--- metal/metal_class.php 2001/07/09 19:31:14 1.54 +++ metal/metal_class.php 2001/12/08 04:24:32 1.74 @@ -6,7 +6,7 @@ if(!defined("METAL_CLASS_INCLUDED")) /* * metal_class.php * - * @(#) $Header: /opt2/mlemos/cvs/metal/metal/metal_class.php,v 1.54 2001/07/09 19:31:14 mlemos Exp $ + * @(#) $Header: /opt2/mlemos/cvs/metal/metal/metal_class.php,v 1.74 2001/12/08 04:24:32 mlemos Exp $ * */ @@ -182,6 +182,8 @@ class metal_class_class extends metal_ba $function["type"]=$this->classes[$class_parent]["functions"][$name]["type"]; if(IsSet($this->classes[$class_parent]["functions"][$name]["Arguments"])) $function["Arguments"]=$this->classes[$class_parent]["functions"][$name]["Arguments"]; + if(IsSet($this->classes[$class_parent]["functions"][$name]["protected"])) + $function["protected"]=$this->classes[$class_parent]["functions"][$name]["protected"]; break; } if(!IsSet($this->classes[$class_parent]["parent"])) @@ -224,24 +226,24 @@ class metal_class_class extends metal_ba return(0); } break; - case "private": + case "protected": if(!IsSet($name)) { - $compiler->SetElementError($attributes->file,$function_element_path,"it was defined the class function private status before specifying its name"); + $compiler->SetElementError($attributes->file,$function_element_path,"it was defined the class function protected status before specifying its name"); return(0); } if($index && IsSet($this->classes[$parent]["functions"][$name])) { - $compiler->SetElementError($attributes->file,$function_element_path,"it was attempted to redefine the class private status of a inherited subclass function"); + $compiler->SetElementError($attributes->file,$function_element_path,"it was attempted to redefine the class protected status of a inherited subclass function"); return(0); } - if(IsSet($function["private"])) + if(IsSet($function["protected"])) { - $compiler->SetElementError($attributes->file,$function_element_path,"it was defined the class function private status more than once"); + $compiler->SetElementError($attributes->file,$function_element_path,"it was defined the class function protected status more than once"); return(0); } - $function["private"]=1; + $function["protected"]=1; break; case "argument": if(!IsSet($name)) @@ -309,10 +311,15 @@ class metal_class_class extends metal_ba $compiler->SetElementError($attributes->file,$argument_element_path,"it was defined the class function argument defaultvalue more than once"); return(0); } - if(IsSet($argument["reference"])) + if(IsSet($argument["parameter"])) { - $compiler->SetElementError($attributes->file,$argument_element_path,"it was defined a defaultvalue for a class function argument to be passed by reference"); - return(0); + switch($argument["parameter"]) + { + case "out": + case "inout": + $compiler->SetElementError($attributes->file,$argument_element_path,"it was defined a defaultvalue for a class function argument to be passed as ".$argument["parameter"]); + return(0); + } } if(!IsSet($argument["type"])) { @@ -323,18 +330,26 @@ class metal_class_class extends metal_ba || !$compiler->ConvertData(&$attributes,$argument["type"],$argument["defaultvalue"],&$argument["converteddefaultvalue"])) return(0); break; - case "reference": - if(IsSet($argument["reference"])) + case "in": + case "out": + case "inout": + if(IsSet($argument["parameter"])) { - $compiler->SetElementError($attributes->file,$argument_element_path,"it was defined the class function argument reference more than once"); + $compiler->SetElementError($attributes->file,$argument_element_path,"class function argument is already defined as ".$argument["parameter"]); return(0); } - if(IsSet($argument["defaultvalue"])) + switch($data["Tag"]) { - $compiler->SetElementError($attributes->file,$argument_element_path,"it was defined a defaultvalue for a class function argument to be passed by reference"); - return(0); + case "out": + case "inout": + if(IsSet($argument["defaultvalue"])) + { + $compiler->SetElementError($attributes->file,$argument_element_path,"it was defined a defaultvalue for a ".$data["Tag"]." class function argument"); + return(0); + } + break; } - $argument["reference"]=1; + $argument["parameter"]=$data["Tag"]; break; case "documentation": if(!$this->GetDocumentation(&$argument,&$compiler,&$code,&$attributes,$argument_element_path)) @@ -361,6 +376,8 @@ class metal_class_class extends metal_ba $compiler->SetElementError($attributes->file,$function_element_path,"it was not defined the class function argument type"); return(0); } + if(!IsSet($argument["parameter"])) + $argument["parameter"]="in"; $function["Arguments"][$argument_name]=$argument; break; case "do": @@ -438,7 +455,11 @@ class metal_class_class extends metal_ba } if($index && IsSet($this->classes[$parent]["variables"][$name])) + { $variable["type"]=$this->classes[$parent]["variables"][$name]["type"]; + if(IsSet($this->classes[$parent]["variables"][$name]["protected"])) + $variable["protected"]=$this->classes[$parent]["variables"][$name]["protected"]; + } break; case "type": if(!IsSet($name)) @@ -474,24 +495,24 @@ class metal_class_class extends metal_ba return(0); } break; - case "private": + case "protected": if(!IsSet($name)) { - $compiler->SetElementError($attributes->file,$variable_element_path,"it was defined the class variable private status before specifying its name"); + $compiler->SetElementError($attributes->file,$variable_element_path,"it was defined the class variable protected status before specifying its name"); return(0); } $class=$parent; if($this->InheritedVariableClass(&$class,$name)) { - $compiler->SetElementError($attributes->file,$variable_element_path,"it was attempted to redefine the private status of a inherited subclass variable"); + $compiler->SetElementError($attributes->file,$variable_element_path,"it was attempted to redefine the protected status of a inherited subclass variable"); return(0); } - if(IsSet($variable["private"])) + if(IsSet($variable["protected"])) { - $compiler->SetElementError($attributes->file,$variable_element_path,"it was defined the class variable private status more than once"); + $compiler->SetElementError($attributes->file,$variable_element_path,"it was defined the class variable protected status more than once"); return(0); } - $variable["private"]=1; + $variable["protected"]=1; break; case "value": $class=$parent; @@ -544,10 +565,13 @@ class metal_class_class extends metal_ba } $this->classes[$index]["variables"][$name]=$variable; break; + case "abstract": + $this->classes[$index][$data["Tag"]]=1; + break; case "file": case "basepath": case "tag": - case "comment": + case "version": case "copyright": case "title": case "author": @@ -584,7 +608,15 @@ class metal_class_class extends metal_ba } } if($index) + { + if(IsSet($this->classes[$index]["abstract"]) + && !IsSet($this->classes[$parent]["abstract"])) + { + $compiler->SetElementError($attributes->file,$attributes->path,"it was defined the abstract attribute for a subclass of a class that is not abstract"); + return(0); + } $this->classes[$index]["parent"]=$parent; + } if(!IsSet($this->classes[$index]["tag"])) $this->classes[$index]["tag"]="CLASS_".strtoupper(ereg_replace("[^A-Za-z0-9]","_",$this->classes[$index]["file"])); return(1); @@ -626,6 +658,53 @@ class metal_class_class extends metal_ba return(1); } + Function GenerateFunction(&$compiler,$class,$name) + { + if(!IsSet($this->classes[$class]["functions"][$name]["do"]["code"])) + { + $this->classes[$class]["functions"][$name]["do"]["code"]=array(); + $function_name=$this->classes[$class]["function_name"]; + $return_type=$this->classes[$class]["return_type"]; + $return_value_set=$this->classes[$class]["return_value_set"]; + $this->classes[$class]["function_name"]=$name; + $this->classes[$class]["return_type"]=$this->classes[$class]["functions"][$name]["type"]; + $this->classes[$class]["return_value_set"]=0; + $action_context=new metal_execution_context_class; + $action_context->file=$this->classes[$class]["functions"][$name]["do"]["file"]; + $action_context->path=$this->classes[$class]["functions"][$name]["do"]["path"]; + $action_context->result=array(); + $functions=array( + "instancevariable", + "instancecall", + "functionargument", + "return" + ); + if(!$compiler->AddContextFunctions(&$action_context,$this->object_name,&$functions,&$level) + || !$compiler->StartScope(&$action_context,&$scope,"method")) + return(0); + $current_subclass=$this->current_subclass; + $this->current_subclass=$class; + if(!$compiler->GetOutputData($this->classes[$class]["functions"][$name]["do"]["file"],$this->classes[$class]["functions"][$name]["do"]["path"],&$this->classes[$class]["functions"][$name]["do"]["code"],"it were not defined valid class function do statements",1) + || !$compiler->GetScopeVariables(&$context,$scope,&$this->classes[$class]["functions"][$name]["variables"])) + return(0); + $this->current_subclass=$current_subclass; + $success=$compiler->EndScope(&$action_context,$scope); + if(!$compiler->RemoveContextFunctions(&$action_context,$this->object_name,$level) + || !$success) + return(0); + if(strcmp($this->classes[$class]["functions"][$name]["type"],"VOID") + && $this->classes[$class]["return_value_set"]==0) + { + $compiler->SetElementError($this->classes[$class]["functions"][$name]["do"]["file"],$this->classes[$class]["functions"][$name]["do"]["path"],"it was not set the class function return value"); + return(0); + } + $this->classes[$class]["function_name"]=$function_name; + $this->classes[$class]["return_type"]=$return_type; + $this->classes[$class]["return_value_set"]=$return_value_set; + } + return(1); + } + Function InheritedFunctionClass(&$class,$function) { for(;;$class=$this->classes[$class]["parent"]) @@ -758,307 +837,6 @@ class metal_class_class extends metal_ba return(1); } - Function GenerateFunction(&$compiler,$class,$name) - { - if(!IsSet($this->classes[$class]["functions"][$name]["do"]["code"])) - { - $this->classes[$class]["functions"][$name]["do"]["code"]=array(); - $function_name=$this->classes[$class]["function_name"]; - $return_type=$this->classes[$class]["return_type"]; - $return_value_set=$this->classes[$class]["return_value_set"]; - $this->classes[$class]["function_name"]=$name; - $this->classes[$class]["return_type"]=$this->classes[$class]["functions"][$name]["type"]; - $this->classes[$class]["return_value_set"]=0; - $action_context=new metal_execution_context_class; - $action_context->file=$this->classes[$class]["functions"][$name]["do"]["file"]; - $action_context->path=$this->classes[$class]["functions"][$name]["do"]["path"]; - $action_context->result=array(); - $functions=array( - "instancevariable", - "instancecall", - "functionargument", - "return" - ); - if(!$compiler->AddContextFunctions(&$action_context,$this->object_name,&$functions,&$level)) - return(0); - $current_subsclass=$this->current_subclass; - $this->current_subclass=$class; - if(!$compiler->GetOutputData($this->classes[$class]["functions"][$name]["do"]["file"],$this->classes[$class]["functions"][$name]["do"]["path"],&$this->classes[$class]["functions"][$name]["do"]["code"],"it were not defined valid class function do statements",1)) - return(0); - $this->current_subclass=$current_subsclass; - if(!$compiler->RemoveContextFunctions(&$action_context,$this->object_name,$level)) - return(0); - if(strcmp($this->classes[$class]["functions"][$name]["type"],"VOID") - && $this->classes[$class]["return_value_set"]==0) - { - $compiler->SetElementError($this->classes[$class]["functions"][$name]["do"]["file"],$this->classes[$class]["functions"][$name]["do"]["path"],"it was not set the class function return value"); - return(0); - } - $this->classes[$class]["function_name"]=$function_name; - $this->classes[$class]["return_type"]=$return_type; - $this->classes[$class]["return_value_set"]=$return_value_set; - } - return(1); - } - - Function GenerateComment($comment,&$result) - { - for($line=$comment;strcmp($line,"");) - { - $line=strtok($line,"\r\n"); - $result[]=array( - "Data"=>" * $line", - "Type"=>"COMMAND" - ); - $line=strtok(""); - } - } - - Function GenerateVariables(&$result,$class,$private) - { - for($output_variable=0,Reset($this->classes[$class]["variables"]),$function=0;$functionclasses[$class]["variables"]);$function++,Next($this->classes[$class]["variables"])) - { - $name=Key($this->classes[$class]["variables"]); - if(($private - && IsSet($this->classes[$class]["variables"][$name]["private"])) - || (!$private - && !IsSet($this->classes[$class]["variables"][$name]["private"]))) - { - if($output_variable==0) - { - if(!$private) - { - $result[]=array( - "Data"=>"", - "Type"=>"COMMAND" - ); - } - $result[]=array( - "Data"=>"/*", - "Type"=>"COMMAND" - ); - $result[]=array( - "Data"=>" * ".($private ? "Private variables" : "Public variables"), - "Type"=>"COMMAND" - ); - $result[]=array( - "Data"=>" *", - "Type"=>"COMMAND" - ); - $result[]=array( - "Data"=>" */", - "Type"=>"COMMAND" - ); - } - $value=(IsSet($this->classes[$class]["variables"][$name]["value"]) ? "=".$this->classes[$class]["variables"][$name]["convertedvalue"] : ""); - $result[]=array( - "Data"=>"var \$$name$value;", - "Type"=>"COMMAND" - ); - $output_variable++; - } - } - } - - Function GenerateFunctions(&$compiler,&$result,$class,$private) - { - for($output_function=0,Reset($this->classes[$class]["functions"]),$function=0;$functionclasses[$class]["functions"]);$function++,Next($this->classes[$class]["functions"])) - { - $name=Key($this->classes[$class]["functions"]); - if(($private - && IsSet($this->classes[$class]["functions"][$name]["private"])) - || (!$private - && !IsSet($this->classes[$class]["functions"][$name]["private"]))) - { - $result[]=array( - "Data"=>"", - "Type"=>"COMMAND" - ); - if($output_function==0) - { - $result[]=array( - "Data"=>"/*", - "Type"=>"COMMAND" - ); - $result[]=array( - "Data"=>" * ".($private ? "Private functions" : "Public functions"), - "Type"=>"COMMAND" - ); - $result[]=array( - "Data"=>" *", - "Type"=>"COMMAND" - ); - $result[]=array( - "Data"=>" */", - "Type"=>"COMMAND" - ); - } - if(!$this->GenerateFunction(&$compiler,$class,$name)) - return(0); - $argument_list=""; - if(IsSet($this->classes[$class]["functions"][$name]["Arguments"])) - { - $arguments=$this->classes[$class]["functions"][$name]["Arguments"]; - for(Reset($arguments),$argument=0;$argument0) - $argument_list.=","; - $argument_list.=(IsSet($arguments[Key($arguments)]["reference"]) ? "&" : "")."\$".Key($arguments); - } - } - $result[]=array( - "Data"=>"Function $name($argument_list)", - "Type"=>"COMMAND" - ); - $result[]=array( - "Data"=>"{", - "Type"=>"COMMAND" - ); - $result[]=array( - "Data"=>1, - "Type"=>"INDENT" - ); - for($part=0;$partclasses[$class]["functions"][$name]["do"]["code"]);$part++) - { - if(strcmp($this->classes[$class]["functions"][$name]["do"]["code"][$part]["Type"],"INITIALIZATION")) - $result[]=$this->classes[$class]["functions"][$name]["do"]["code"][$part]; - else - $initialization_result[]=$this->classes[$class]["functions"][$name]["do"]["code"][$part]; - } - $result[]=array( - "Data"=>1, - "Type"=>"OUTDENT" - ); - $result[]=array( - "Data"=>"}", - "Type"=>"COMMAND" - ); - $output_function++; - } - } - } - - Function GenerateClass(&$compiler,&$result,&$initialization_result,$class) - { - $result=array(); - $result[]=array( - "Data"=>0, - "Type"=>"RESETINDENT" - ); - if(strcmp($this->classes[$class]["file"],"")) - { - $result[]=array( - "Data"=>"if(!defined(\"".$this->classes[$class]["tag"]."\"))", - "Type"=>"COMMAND" - ); - $result[]=array( - "Data"=>"{", - "Type"=>"COMMAND" - ); - $result[]=array( - "Data"=>1, - "Type"=>"INDENT" - ); - $result[]=array( - "Data"=>"define(\"".$this->classes[$class]["tag"]."\",1);", - "Type"=>"COMMAND" - ); - $result[]=array( - "Data"=>1, - "Type"=>"OUTDENT" - ); - } - $result[]=array( - "Data"=>"", - "Type"=>"COMMAND" - ); - if(IsSet($this->classes[$class]["comment"]) - || IsSet($this->classes[$class]["copyright"])) - { - $result[]=array( - "Data"=>"/*", - "Type"=>"COMMAND" - ); - $result[]=array( - "Data"=>" *", - "Type"=>"COMMAND" - ); - if(IsSet($this->classes[$class]["copyright"])) - { - $this->GenerateComment($this->classes[$class]["copyright"],&$result); - if(IsSet($this->classes[$class]["comment"])) - { - $result[]=array( - "Data"=>" *", - "Type"=>"COMMAND" - ); - } - } - if(IsSet($this->classes[$class]["comment"])) - $this->GenerateComment($this->classes[$class]["comment"],&$result); - $result[]=array( - "Data"=>" *", - "Type"=>"COMMAND" - ); - $result[]=array( - "Data"=>" */", - "Type"=>"COMMAND" - ); - $result[]=array( - "Data"=>"", - "Type"=>"COMMAND" - ); - } - $result[]=array( - "Data"=>"class ".$this->classes[$class]["name"].(IsSet($this->classes[$class]["parent"]) ? " extends ".$this->classes[$this->classes[$class]["parent"]]["name"] : ""), - "Type"=>"COMMAND" - ); - $result[]=array( - "Data"=>"{", - "Type"=>"COMMAND" - ); - $result[]=array( - "Data"=>1, - "Type"=>"INDENT" - ); - $this->GenerateVariables(&$result,$class,1); - $this->GenerateVariables(&$result,$class,0); - if(count($this->classes[$class]["variables"]) - && count($this->classes[$class]["functions"])) - { - $result[]=array( - "Data"=>"", - "Type"=>"COMMAND" - ); - } - $this->GenerateFunctions(&$compiler,&$result,$class,1); - $this->GenerateFunctions(&$compiler,&$result,$class,0); - $result[]=array( - "Data"=>1, - "Type"=>"OUTDENT" - ); - $result[]=array( - "Data"=>"};", - "Type"=>"COMMAND" - ); - $result[]=array( - "Data"=>"", - "Type"=>"COMMAND" - ); - if(strcmp($this->classes[$class]["file"],"")) - { - $result[]=array( - "Data"=>"}", - "Type"=>"COMMAND" - ); - } - $result[]=array( - "Data"=>0, - "Type"=>"RESTOREINDENT" - ); - return(1); - } - Function GetSubclassArgument(&$compiler,$file,$path,&$values) { if(IsSet($value["subclass"])) @@ -1119,6 +897,52 @@ class metal_class_class extends metal_ba return(1); } + Function IterateVariables(&$compiler,&$context,$class,&$variables,$protected,$public,$inherited) + { + for($class_variable=0,Reset($this->classes[$class]["variables"]);$class_variableclasses[$class]["variables"]);Next($this->classes[$class]["variables"]),$class_variable++) + { + $this->current_class=$class; + $this->current_variable=Key($this->classes[$class]["variables"]); + if(!IsSet($variables[$this->current_variable]) + && (($public + && !IsSet($this->classes[$class]["variables"][$this->current_variable]["protected"])) + || ($protected + && IsSet($this->classes[$class]["variables"][$this->current_variable]["protected"])))) + { + if(!$compiler->GetOutputData($context->file,$context->path,&$context->result,"it was not defined valid action for the class variables",1)) + return(0); + $variables[$this->current_variable]=$class; + } + } + if($inherited + && IsSet($this->classes[$class]["parent"])) + return($this->IterateVariables($compiler,$context,$this->classes[$class]["parent"],&$variables,$protected,$public,$inherited)); + return(1); + } + + Function IterateFunctions(&$compiler,&$context,$class,&$functions,$protected,$public,$inherited) + { + for($class_function=0,Reset($this->classes[$class]["functions"]);$class_functionclasses[$class]["functions"]);Next($this->classes[$class]["functions"]),$class_function++) + { + $this->current_class=$class; + $this->current_function=Key($this->classes[$class]["functions"]); + if(!IsSet($functions[$this->current_function]) + && (($public + && !IsSet($this->classes[$class]["functions"][$this->current_function]["protected"])) + || ($protected + && IsSet($this->classes[$class]["functions"][$this->current_function]["protected"])))) + { + if(!$compiler->GetOutputData($context->file,$context->path,&$context->result,"it was not defined valid action for the class functions",1)) + return(0); + $functions[$this->current_function]=$class; + } + } + if($inherited + && IsSet($this->classes[$class]["parent"])) + return($this->IterateFunctions($compiler,$context,$this->classes[$class]["parent"],&$functions,$protected,$public,$inherited)); + return(1); + } + Function Execute(&$compiler,&$code,$function,&$context,&$arguments_code,&$arguments) { switch($compiler->language["name"]) @@ -1126,10 +950,13 @@ class metal_class_class extends metal_ba case "Java": switch($function) { -/* case "output": + case "functionargument": + case "return": + case "instancevariable": + case "instancecall": + case "call": break; -*/ default: $compiler->SetElementError($context->file,$context->path,"$function function of the class class is not implemented for the language ".$compiler->language["name"]); return(0); @@ -1183,6 +1010,11 @@ class metal_class_class extends metal_ba } } $subclass=(IsSet($load["subclass"]) ? $load["subclass"] : 0); + if(IsSet($this->classes[$subclass]["abstract"])) + { + $compiler->SetElementError($context->file,$context->path,"an abstract class can not be loaded"); + return(0); + } $relative_path=$compiler->RelativePath($this->classes[$subclass]["basepath"],$this->classes[$subclass]["file"]); $context->result[]=array( "Data"=>array( @@ -1292,6 +1124,11 @@ class metal_class_class extends metal_ba } } $subclass=(IsSet($new["subclass"]) ? $new["subclass"] : 0); + if(IsSet($this->classes[$subclass]["abstract"])) + { + $compiler->SetElementError($context->file,$context->path,"an abstract class can not be instanciated"); + return(0); + } $context->result[]=array( "Data"=>array( "Object"=>$this->object_name, @@ -1323,36 +1160,80 @@ class metal_class_class extends metal_ba break; case "instancecall": case "call": - $call=array(); - if(!$this->Call(&$compiler,&$arguments_code,&$arguments,&$call,$function) - || !$this->Call(&$compiler,&$code,&$context,&$call,$function)) + $message=array(); + if(!$this->Call(&$compiler,&$arguments_code,&$arguments,&$message,$function) + || !$this->Call(&$compiler,&$code,&$context,&$message,$function)) return(0); if((strcmp($function,"instancecall") - && !IsSet($call[$argument="object"])) - || !IsSet($call[$argument="function"])) + && !IsSet($message[$argument="object"])) + || !IsSet($message[$argument="function"])) { $compiler->SetElementError($context->file,$context->path,"it was not defined the class $function $argument argument"); return(0); } - $argument_list=""; - $class=$subclass=(IsSet($call["subclass"]) ? $call["subclass"] : $this->current_subclass); - $this->InheritedFunctionClass(&$class,$call["function"]); - if(IsSet($this->classes[$class]["functions"][$call["function"]]["Arguments"])) + $message["class"]=$subclass=(IsSet($message["subclass"]) ? $message["subclass"] : $this->current_subclass); + if(IsSet($this->classes[$subclass]["abstract"]) + && !strcmp($function,"call")) + { + $compiler->SetElementError($context->file,$context->path,"an abstract class can not be called"); + return(0); + } + $this->InheritedFunctionClass(&$message["class"],$message["function"]); + $message["argumentlist"]=array(); + if(IsSet($this->classes[$message["class"]]["functions"][$message["function"]]["Arguments"])) { - $arguments=$this->classes[$class]["functions"][$call["function"]]["Arguments"]; + $arguments=$this->classes[$message["class"]]["functions"][$message["function"]]["Arguments"]; for(Reset($arguments),$argument=0;$argumentfile=$argument_context["file"]; $evaluate_context->path=$argument_context["path"]; - $reference=IsSet($argument_context["reference"]); - if(!$compiler->GetValidExpression(&$evaluate_context,$argument_context["type"],$reference ? "BOTH" : "NOTLEFT","it was not specified a valid class function $function argument ".$argument_context["type"]." ".($reference ? "reference" : "value")." expression",0) + switch($this->classes[$message["class"]]["functions"][$message["function"]]["Arguments"][$argument_name]["parameter"]) + { + case "in": + $side="NOTLEFT"; + $error="it was not specified a valid class function $function argument ".$argument_context["type"]." input expression"; + break; + case "out": + $side="NOTRIGHT"; + $error="it was not specified a valid class function $function argument ".$argument_context["type"]." output expression"; + break; + case "inout": + $side="BOTH"; + $error="it was not specified a valid class function $function argument ".$argument_context["type"]." input/output expression"; + break; + } + if(!$compiler->GetValidExpression(&$evaluate_context,"ANY",$side,$error,0) || !$compiler->GetExpressionValue(&$context,&$evaluate_context->result,&$argument_value,&$expression_type)) return(0); + if($expression_type=="UNDEFINED" + && $side=="NOTRIGHT") + { + $variable=array( + "DeclarationFile"=>$evaluate_context->file, + "DeclarationPath"=>$evaluate_context->path.",0" + ); + if(!$compiler->QueryVariable(&$context,&$variable)) + return(0); + if($variable["Declared"]) + { + $variable["Type"]=$argument_context["type"]; + if(!$compiler->DeclareVariable(&$context,&$variable)) + return(0); + if(!$compiler->GetValidExpression(&$evaluate_context,$argument_context["type"],$side,$error,0) + || !$compiler->GetExpressionValue(&$context,&$evaluate_context->result,&$argument_value,&$expression_type)) + return(0); + } + } + if($expression_type!=$argument_context["type"]) + { + $compiler->SetElementError($evaluate_context->file,$evaluate_context->path,"it was specified an expression of type \"$expression_type\" where it was expected a ".$argument_context["type"]." expression for class $function ".$argument_name." argument"); + return(0); + } } else { @@ -1363,30 +1244,11 @@ class metal_class_class extends metal_ba } $argument_value=$arguments[$argument_name]["converteddefaultvalue"]; } - if($argument>0) - $argument_list.=","; - $argument_list.=$argument_value; + $message["argumentlist"][]=$argument_value; } } - $statement=(strcmp($function,"instancecall") ? $call["object"] : "\$this")."->".$call["function"]."($argument_list)"; - if(strcmp($this->classes[$class]["functions"][$call["function"]]["type"],"VOID")) - { - $context->result[]=array( - "Data"=>array( - "Value"=>$statement, - "Type"=>$this->classes[$class]["functions"][$call["function"]]["type"], - "Side"=>"RIGHT" - ), - "Type"=>"EXPRESSION" - ); - } - else - { - $context->result[]=array( - "Data"=>$statement.";", - "Type"=>"COMMAND" - ); - } + if(!$this->language_bindings->Execute(&$compiler,&$context,&$this,$function,&$message)) + return(0); break; case "return": if(!$this->GetClassScope(&$compiler,&$arguments_code,&$arguments,&$class,0,$tags)) @@ -1405,36 +1267,31 @@ class metal_class_class extends metal_ba if(!$compiler->GetValidExpression(&$evaluate_context,$this->classes[$class]["return_type"],"NOTLEFT","it was not specified a valid class function return ".$this->classes[$class]["return_type"]." expression",1) || !$compiler->GetExpressionValue(&$context,&$evaluate_context->result,&$return_value,&$expression_type)) return(0); - $context->result[]=array( - "Data"=>"return $return_value;", - "Type"=>"COMMAND" + $message=array( + "value"=>$return_value ); + if(!$this->language_bindings->Execute(&$compiler,&$context,&$this,"return",&$message)) + return(0); $this->classes[$class]["return_value_set"]=1; break; case "instancevariable": - if(!$this->GetClassScope(&$compiler,&$arguments_code,&$arguments,&$class,0,$tags)) + $message=array(); + if(!$this->GetClassScope(&$compiler,&$arguments_code,&$arguments,&$message["class"],0,$tags)) return(0); - if(!strcmp($this->classes[$class]["return_type"],"")) + if(!strcmp($this->classes[$message["class"]]["return_type"],"")) { $compiler->SetElementError($context->file,$context->path,"the instance variable is being accessed from outside a class function"); return(0); } - if(!$compiler->GetValidName($context->file,$context->path,&$name,"it was not specified a valid class variable name")) + if(!$compiler->GetValidName($context->file,$context->path,&$message["name"],"it was not specified a valid class variable name")) return(0); - - if(!$this->InheritedVariableClass(&$class,$name)) + if(!$this->InheritedVariableClass(&$message["class"],$message["name"])) { - $compiler->SetElementError($context->file,$context->path,"it was not specified a defined class variable name (\"$name\")"); + $compiler->SetElementError($context->file,$context->path,"it was not specified a defined class variable name (\"".$message["name"]."\")"); return(0); } - $context->result[]=array( - "Data"=>array( - "Value"=>"\$"."this->$name", - "Type"=>$this->classes[$class]["variables"][$name]["type"], - "Side"=>"BOTH" - ), - "Type"=>"EXPRESSION" - ); + if(!$this->language_bindings->Execute(&$compiler,&$context,&$this,"instancevariable",&$message)) + return(0); break; case "objectvariable": $object_variable=array(); @@ -1482,14 +1339,19 @@ class metal_class_class extends metal_ba if(!$compiler->GetValidName($context->file,$context->path,&$name,"it was not specified a valid class variable name")) return(0); $subclass=(IsSet($object_variable["subclass"]) ? $object_variable["subclass"] : 0); + if(IsSet($this->classes[$subclass]["abstract"])) + { + $compiler->SetElementError($context->file,$context->path,"abstract class variables can not be accessed"); + return(0); + } if(!$this->InheritedVariableClass(&$subclass,$name)) { $compiler->SetElementError($context->file,$context->path,"it was not specified a defined class variable name (\"$name\")"); return(0); } - if(IsSet($this->classes[$subclass]["variables"][$name]["private"])) + if(IsSet($this->classes[$subclass]["variables"][$name]["protected"])) { - $compiler->SetElementError($context->file,$context->path,"it was attempted to access an object private variable (\"$name\") from outside the class scope"); + $compiler->SetElementError($context->file,$context->path,"it was attempted to access an object protected variable (\"$name\") from outside the class scope"); return(0); } $context->result[]=array( @@ -1502,40 +1364,44 @@ class metal_class_class extends metal_ba ); break; case "functionargument": - if(!$this->GetClassScope(&$compiler,&$arguments_code,&$arguments,&$class,0,$tags)) + $message=array(); + if(!$this->GetClassScope(&$compiler,&$arguments_code,&$arguments,&$message["class"],0,$tags)) return(0); - if(!strcmp($this->classes[$class]["function_name"],"")) + if(!strcmp($this->classes[$message["class"]]["function_name"],"")) { $compiler->SetElementError($context->file,$context->path,"the function argument function is being from called outside a class function"); return(0); } - if(!$compiler->GetValidName($context->file,$context->path,&$name,"it was not specified a valid class function argument name")) + if(!$compiler->GetValidName($context->file,$context->path,&$message["name"],"it was not specified a valid class function argument name")) return(0); - if(!IsSet($this->classes[$class]["functions"][$this->classes[$class]["function_name"]]["Arguments"][$name])) + if(!IsSet($this->classes[$message["class"]]["functions"][$this->classes[$message["class"]]["function_name"]]["Arguments"][$message["name"]])) { - $compiler->SetElementError($context->file,$context->path,"it was specified an unknown class function argument (\"$name\")"); + $compiler->SetElementError($context->file,$context->path,"it was specified an unknown class function argument (\"".$message["name"]."\")"); return(0); } - $argument=$this->classes[$class]["functions"][$this->classes[$class]["function_name"]]["Arguments"][$name]; - $context->result[]=array( - "Data"=>array( - "Value"=>"\$".$name, - "Type"=>$argument["type"], - "Side"=>"BOTH" - ), - "Type"=>"EXPRESSION" - ); + if(!$this->language_bindings->Execute(&$compiler,&$context,&$this,"functionargument",&$message)) + return(0); break; case "output": if(!$this->GetClassScope(&$compiler,&$arguments_code,&$arguments,&$class,0,$tags)) return(0); + if(IsSet($this->classes[$class]["abstract"])) + { + $compiler->SetElementError($context->file,$context->path,"abstract classes can not be generated"); + return(0); + } if(!strcmp($this->classes[$class]["file"],"")) { $compiler->SetElementError($context->file,$context->path,"it was not specified the class output file"); return(0); } - if(!$this->GenerateClass(&$compiler,&$result,&$initialization_result,$class) - || !$compiler->GenerateOutput(&$context,&$result,&$output,"",0) + $message=array( + "class"=>$class, + "result"=>array(), + "initialization"=>array() + ); + if(!$this->language_bindings->Execute(&$compiler,&$context,&$this,"output",&$message) + || !$compiler->GenerateOutput(&$context,&$message["result"],&$output,"",0) || !$compiler->CreateContextOutputDirectory(dirname($this->classes[$class]["file"]),&$context,"it was not possible to create the directory for the class output file \"".dirname($this->classes[$class]["file"])."\"")) return(0); if(!($output_file=@fopen($this->classes[$class]["file"],"w"))) @@ -1574,7 +1440,7 @@ class metal_class_class extends metal_ba case "file": case "basepath": case "tag": - case "comment": + case "version": case "copyright": case "title": case "author": @@ -1599,6 +1465,18 @@ class metal_class_class extends metal_ba ); } break; + case "subclass": + $context->result[]=array( + "Data"=>(!strcmp($function,"getproperty") ? (IsSet($this->classes[$class]["parent"]) ? "1" : "0") : "1"), + "Type"=>"DATA" + ); + break; + case "abstract": + $context->result[]=array( + "Data"=>(!strcmp($function,"getproperty") ? (IsSet($this->classes[$class]["abstract"]) ? "1" : "0") : "1"), + "Type"=>"DATA" + ); + break; default: $compiler->SetElementError($context->file,$context->path,"\"$property\" is not a supported class property"); return(0); @@ -1629,8 +1507,16 @@ class metal_class_class extends metal_ba $compiler->SetElementError($context->file,$element_path,"it was defined the class data type \"".$data["Tag"]."\" more than once"); return(0); } - if(!$compiler->GetValidData($context->file,$element_path,&$this->classes[$class]["types"][$data["Tag"]],"it was not specified a valid class data type option")) + if(!$compiler->GetValidData($context->file,$element_path,&$type,"it was not specified a valid class data type option")) return(0); + $type_name=$data["Tag"]; + $this->classes[$class]["types"][$type_name]=$type; + $parent=$class; + while(IsSet($this->classes[$parent]["parent"])) + { + $parent=$this->classes[$parent]["parent"]; + $this->classes[$parent]["types"][$type_name]=$type; + } break; default: $compiler->SetElementError($context->file,$element_path,"it was not defined a valid class data type"); @@ -1650,22 +1536,23 @@ class metal_class_class extends metal_ba if(IsSet($tags["idiom"]) && !$compiler->GetValidName($tags["idiom"]->file,$tags["idiom"]->path,&$idiom,"it was not specified a valid class documentation idiom tag")) return(0); - $private=$public=1; - if(IsSet($tags["private"])) + $protected=$public=1; + $inherited=0; + if(IsSet($tags["protected"])) { - if(!$compiler->GetValidData($tags["private"]->file,$tags["private"]->path,&$value,"it was not specified a valid class function public value")) + if(!$compiler->GetValidData($tags["protected"]->file,$tags["protected"]->path,&$value,"it was not specified a valid class function public value")) return(0); switch($value) { case "1": case "": - $private=1; + $protected=1; break; case "0": - $private=0; + $protected=0; break; default: - $compiler->SetElementError($tags["private"]->file,$tags["private"]->path,"it was not specified a valid class function private value"); + $compiler->SetElementError($tags["protected"]->file,$tags["protected"]->path,"it was not specified a valid class function protected value"); return(0); } } @@ -1687,37 +1574,42 @@ class metal_class_class extends metal_ba return(0); } } + if(IsSet($tags["inherited"])) + { + if(!$compiler->GetValidData($tags["inherited"]->file,$tags["inherited"]->path,&$value,"it was not specified a valid class function inherited value")) + return(0); + switch($value) + { + case "1": + case "": + $inherited=1; + break; + case "0": + $inherited=0; + break; + default: + $compiler->SetElementError($tags["inherited"]->file,$tags["inherited"]->path,"it was not specified a valid class function inherited value"); + return(0); + } + } $functions=array( "functionname", "functiontype", "functiontypename", "functionistype", + "functionhasarguments", "forallarguments" ); if(!$compiler->AddContextFunctions(&$context,$this->object_name,&$functions,&$level)) return(0); $current_class=$this->current_class; $current_function=$this->current_function; - for($class_function=0,Reset($this->classes[$class]["functions"]);$class_functionclasses[$class]["functions"]);Next($this->classes[$class]["functions"]),$class_function++) - { - $this->current_class=$class; - $this->current_function=Key($this->classes[$class]["functions"]); - if(($public - && !IsSet($this->classes[$class]["functions"][$this->current_function]["private"])) - || ($private - && IsSet($this->classes[$class]["functions"][$this->current_function]["private"]))) - { - if(!$compiler->GetOutputData($context->file,$context->path,&$context->result,"it was not defined valid action for the class functions",1)) - { - $this->current_class=$current_class; - $this->current_function=$current_function; - return(0); - } - } - } + $functions=array(); + $success=$this->IterateFunctions($compiler,$context,$class,$functions,$protected,$public,$inherited); $this->current_class=$current_class; $this->current_function=$current_function; - if(!$compiler->RemoveContextFunctions(&$context,$this->object_name,$level)) + if(!$compiler->RemoveContextFunctions(&$context,$this->object_name,$level) + || !$success) return(0); break; case "forallvariables": @@ -1726,22 +1618,23 @@ class metal_class_class extends metal_ba if(IsSet($tags["idiom"]) && !$compiler->GetValidName($tags["idiom"]->file,$tags["idiom"]->path,&$idiom,"it was not specified a valid class documentation idiom tag")) return(0); - $private=$public=1; - if(IsSet($tags["private"])) + $protected=$public=1; + $inherited=0; + if(IsSet($tags["protected"])) { - if(!$compiler->GetValidData($tags["private"]->file,$tags["private"]->path,&$value,"it was not specified a valid class variable public value")) + if(!$compiler->GetValidData($tags["protected"]->file,$tags["protected"]->path,&$value,"it was not specified a valid class variable public value")) return(0); switch($value) { case "1": case "": - $private=1; + $protected=1; break; case "0": - $private=0; + $protected=0; break; default: - $compiler->SetElementError($tags["private"]->file,$tags["private"]->path,"it was not specified a valid class variable private value"); + $compiler->SetElementError($tags["protected"]->file,$tags["protected"]->path,"it was not specified a valid class variable protected value"); return(0); } } @@ -1763,6 +1656,24 @@ class metal_class_class extends metal_ba return(0); } } + if(IsSet($tags["inherited"])) + { + if(!$compiler->GetValidData($tags["inherited"]->file,$tags["inherited"]->path,&$value,"it was not specified a valid class variable inherited value")) + return(0); + switch($value) + { + case "1": + case "": + $inherited=1; + break; + case "0": + $inherited=0; + break; + default: + $compiler->SetElementError($tags["inherited"]->file,$tags["inherited"]->path,"it was not specified a valid class variable inherited value"); + return(0); + } + } $functions=array( "variablename", "variabletype", @@ -1775,26 +1686,12 @@ class metal_class_class extends metal_ba return(0); $current_class=$this->current_class; $current_variable=$this->current_variable; - for($class_variable=0,Reset($this->classes[$class]["variables"]);$class_variableclasses[$class]["variables"]);Next($this->classes[$class]["variables"]),$class_variable++) - { - $this->current_class=$class; - $this->current_variable=Key($this->classes[$class]["variables"]); - if(($public - && !IsSet($this->classes[$class]["variables"][$this->current_variable]["private"])) - || ($private - && IsSet($this->classes[$class]["variables"][$this->current_variable]["private"]))) - { - if(!$compiler->GetOutputData($context->file,$context->path,&$context->result,"it was not defined valid action for the class variables",1)) - { - $this->current_class=$current_class; - $this->current_variable=$current_variable; - return(0); - } - } - } + $variables=array(); + $success=$this->IterateVariables($compiler,$context,$class,$variables,$protected,$public,$inherited); $this->current_class=$current_class; $this->current_variable=$current_variable; - if(!$compiler->RemoveContextFunctions(&$context,$this->object_name,$level)) + if(!$compiler->RemoveContextFunctions(&$context,$this->object_name,$level) + || !$success) return(0); break; case "forallarguments": @@ -1815,7 +1712,7 @@ class metal_class_class extends metal_ba "argumentname", "argumenttype", "argumenttypename", - "referenceargument", + "argumentparameter", "lastargument" ); if(!$compiler->AddContextFunctions(&$context,$this->object_name,&$functions,&$level)) @@ -1839,6 +1736,29 @@ class metal_class_class extends metal_ba if(!$compiler->RemoveContextFunctions(&$context,$this->object_name,$level)) return(0); break; + case "forallparentclasses": + if(!$this->GetClassScope(&$compiler,&$arguments_code,&$arguments,&$class,1,$tags)) + return(0); + if(IsSet($tags["idiom"]) + && !$compiler->GetValidName($tags["idiom"]->file,$tags["idiom"]->path,&$idiom,"it was not specified a valid class documentation idiom tag")) + return(0); + $functions=array(); + if(!$compiler->AddContextFunctions(&$context,$this->object_name,&$functions,&$level)) + return(0); + $current_class=$this->current_class; + $this->current_class=$class; + $success=1; + while(IsSet($this->classes[$this->current_class]["parent"])) + { + $this->current_class=$this->classes[$this->current_class]["parent"]; + if(!($success=$compiler->GetOutputData($context->file,$context->path,&$context->result,"it was not defined valid action for the class parentclasses",0))) + break; + } + $this->current_class=$current_class; + if(!$compiler->RemoveContextFunctions(&$context,$this->object_name,$level) + || !$success) + return(0); + break; case "getdocumentation": case "defineddocumentation": if(!$this->GetClassScope(&$compiler,&$arguments_code,&$arguments,&$class,1,$tags)) @@ -1852,8 +1772,33 @@ class metal_class_class extends metal_ba return(0); if(!$compiler->GetValidName($context->file,$context->path,&$tag,"it was not specified a valid class documentation tag")) return(0); + $inherited=0; + if(IsSet($tags["inherited"])) + { + if(!$compiler->GetValidData($tags["inherited"]->file,$tags["inherited"]->path,&$value,"it was not specified a valid class function inherited value")) + return(0); + switch($value) + { + case "1": + case "": + $inherited=1; + break; + case "0": + $inherited=0; + break; + default: + $compiler->SetElementError($tags["inherited"]->file,$tags["inherited"]->path,"it was not specified a valid class function inherited value"); + return(0); + } + } if(strcmp($this->current_argument,"")) { + if($inherited) + { + while(!IsSet($this->classes[$class]["functions"][$this->current_function]["Arguments"][$this->current_argument]["documentation"][$idiom][$tag]) + && IsSet($this->classes[$class]["parent"])) + $class=$this->classes[$class]["parent"]; + } if(strcmp($function,"defineddocumentation")) { if(!IsSet($this->classes[$class]["functions"][$this->current_function]["Arguments"][$this->current_argument]["documentation"][$idiom][$tag])) @@ -1876,6 +1821,12 @@ class metal_class_class extends metal_ba { if(strcmp($this->current_function,"")) { + if($inherited) + { + while(!IsSet($this->classes[$class]["functions"][$this->current_function]["documentation"][$idiom][$tag]) + && IsSet($this->classes[$class]["parent"])) + $class=$this->classes[$class]["parent"]; + } if(strcmp($function,"defineddocumentation")) { if(!IsSet($this->classes[$class]["functions"][$this->current_function]["documentation"][$idiom][$tag])) @@ -1898,6 +1849,12 @@ class metal_class_class extends metal_ba { if(strcmp($this->current_variable,"")) { + if($inherited) + { + while(!IsSet($this->classes[$class]["variables"][$this->current_variable]["documentation"][$idiom][$tag]) + && IsSet($this->classes[$class]["parent"])) + $class=$this->classes[$class]["parent"]; + } if(strcmp($function,"defineddocumentation")) { if(!IsSet($this->classes[$class]["variables"][$this->current_variable]["documentation"][$idiom][$tag])) @@ -1943,6 +1900,7 @@ class metal_class_class extends metal_ba case "functiontype": case "functiontypename": case "functionistype": + case "functionhasarguments": if(!strcmp($this->current_function,"")) { $compiler->SetElementError($context->file,$context->path,"it was requested the $function of function outside a function definition scope"); @@ -1981,6 +1939,9 @@ class metal_class_class extends metal_ba } $value=(strcmp($type,$this->classes[$this->current_class]["functions"][$this->current_function]["type"]) ? "0" : "1"); break; + case "functionhasarguments": + $value=(IsSet($this->classes[$this->current_class]["functions"][$this->current_function]["Arguments"]) ? "1" : "0"); + break; } $context->result[]=array( "Data"=>$value, @@ -1990,7 +1951,7 @@ class metal_class_class extends metal_ba case "argumentname": case "argumenttype": case "argumenttypename": - case "referenceargument": + case "argumentparameter": case "lastargument": if(!strcmp($this->current_argument,"")) { @@ -2010,8 +1971,8 @@ class metal_class_class extends metal_ba if(IsSet($this->classes[$this->current_class]["types"][$value])) $value=$this->classes[$this->current_class]["types"][$value]; break; - case "referenceargument": - $value=(IsSet($this->classes[$this->current_class]["functions"][$this->current_function]["Arguments"][$this->current_argument]["reference"]) ? "1" : "0"); + case "argumentparameter": + $value=$this->classes[$this->current_class]["functions"][$this->current_function]["Arguments"][$this->current_argument]["parameter"]; break; case "lastargument": $value=($this->current_argument_number+1==count($this->classes[$this->current_class]["functions"][$this->current_function]["Arguments"]) ? "1" : "0"); @@ -2071,6 +2032,57 @@ class metal_class_class extends metal_ba "Type"=>"DATA" ); break; + case "examplecode": + if(!$this->GetClassScope(&$compiler,&$arguments_code,&$arguments,&$class,1,$tags)) + return(0); + $result=array(); + if(!$compiler->GetOutputData($context->file,$context->path,&$result,"invalid example code",1)) + return(0); + $initialization=1; + if(IsSet($tags["initialization"])) + { + if(!$compiler->GetValidData($tags["initialization"]->file,$tags["initialization"]->path,&$value,"it was not specified a valid class example code initialization value")) + return(0); + switch($value) + { + case "1": + case "": + $initialization=1; + break; + case "0": + $initialization=0; + break; + default: + $compiler->SetElementError($tags["initialization"]->file,$tags["initialization"]->path,"it was not specified a valid class example code initialization value"); + return(0); + } + } + if($initialization) + { + if(!$compiler->GenerateOutput(&$context,&$result,&$output,"",0)) + return(0); + } + else + { + for($stripped=array(),$part=0;$partGenerateOutput(&$context,&$stripped,&$output,"",0)) + return(0); + } + $context->result[]=array( + "Data"=>$output, + "Type"=>"DATA" + ); + break; default: $compiler->SetElementError($context->file,$context->path,$function." is not a supported class object function"); return(0); @@ -2086,9 +2098,13 @@ class metal_class_class extends metal_ba return(0); } $class=$this->subclasses[$object_context]; - for($parent=$class;$parent!=0;) + if(IsSet($this->classes[$class]["abstract"])) + { + $compiler->SetElementError($context->file,$context->path,"abstract class functions arguments can not be accessed"); + return(0); + } + for($parent=$class;$parent!=0 && !IsSet($this->classes[$parent=$this->classes[$parent]["parent"]]["abstract"]);) { - $parent=$this->classes[$parent]["parent"]; $context->result[]=array( "Data"=>array( "Object"=>$this->object_name, @@ -2133,10 +2149,17 @@ class metal_class_class extends metal_ba } else { - if(!$this->GenerateClass(&$compiler,&$result,&$context->result,$class)) + $message=array( + "class"=>$class, + "result"=>array(), + "initialization"=>array() + ); + if(!$this->language_bindings->Execute(&$compiler,&$context,&$this,"output",&$message)) return(0); - for($part=0;$partresult[]=$result[$part]; + for($part=0;$partresult[]=$message["initialization"][$part]; + for($part=0;$partresult[]=$message["result"][$part]; } return(1); }