summaryrefslogtreecommitdiff
path: root/packages/cocoaint/utils/source/objp_parser.php
diff options
context:
space:
mode:
Diffstat (limited to 'packages/cocoaint/utils/source/objp_parser.php')
-rw-r--r--packages/cocoaint/utils/source/objp_parser.php500
1 files changed, 500 insertions, 0 deletions
diff --git a/packages/cocoaint/utils/source/objp_parser.php b/packages/cocoaint/utils/source/objp_parser.php
new file mode 100644
index 0000000000..c5d1bcd3c1
--- /dev/null
+++ b/packages/cocoaint/utils/source/objp_parser.php
@@ -0,0 +1,500 @@
+<?php
+
+class TObjPParser extends TPasCocoaParser {
+
+ var $trailing_underscore = true;
+
+ // ignore these classes when testing for ivar size
+ var $ignore_class_ivar_comparison = array( "NSNibOutletConnector", "NSNibConnector", "NSNibControlConnector", "NSPredicateEditorRowTemplate", "NSSegmentedCell",
+ "NSSimpleHorizontalTypesetter", "NSInvocation", "NSPointerFunctions", "NSConstantString");
+
+ // These methods require that the last parameter append a trailing underscore (if $trailing_underscore is on)
+ var $trailing_underscore_methods = array("- (void)copy:(id)sender;", "- (void)setNeedsDisplay:(BOOL)flag;","- (void*)QTMovie;","- (QTMovie *)QTMovie;","- (BOOL)load:(NSError **)error;");
+
+ var $ignore_methods = array("observationInfo");
+
+ // Converts an Objective-c method name to Pascal
+ function ConvertObjcMethodName ($method) {
+ $params = explode(":", $method);
+ $name = "";
+ $count = 0;
+
+ if (count($params) > 1) {
+ foreach ($params as $value) {
+ if (eregi("([a-zA-Z0-9]+)$", $value, $captures)) $name .= $captures[1]."_";
+ }
+ } else {
+ if (eregi("([a-zA-Z0-9]+)(;)*$", $params[0], $captures)) $name .= $captures[1]."_";
+ }
+
+ // clean it up
+ if ($this->trailing_underscore) {
+ if (!in_array($method, $this->trailing_underscore_methods)) $name = trim($name, "_");
+ }
+
+ $name = $this->ReplaceObjcType($name);
+
+ return $name;
+ }
+
+ // Converts an Objective-C method to Pascal format
+ function ConvertObjcMethodToPascal ($class, $source, $parts, $protected_keywords, $has_params, $deprecatedmods) {
+
+ //print("$source\n");
+ //print_r($parts);
+
+ // replace "hinted" params comment with hinted type
+ if ($this->replace_hinted_params) {
+
+ // param string
+ if (eregi("(/\*[[:space:]]*(.*)[[:space:]]*\*/)", $parts[4], $captures)) {
+ // ??? change the parameter to the hinted type
+ //$parts[4] = eregi_replace("(/\*.*\*/)", $captures[2], $parts[4]);
+ //$parts[4] = trim($parts[4], " ");
+ }
+
+ // return type
+ if (eregi("(/\*[[:space:]]*(.*)[[:space:]]*\*/)", $parts[2], $captures)) $parts[2] = $this->ReplaceRemoteMessagingModifiers($captures[2], $null);
+
+ //print_r($parts);
+
+ } else { // remove comments from params and return type
+ $parts[4] = eregi_replace("(/\*.*\*/)", "", $parts[4]);
+ $parts[4] = trim($parts[4]);
+
+ $parts[2] = eregi_replace("(/\*.*\*/)", "", $parts[2]);
+ $parts[2] = $this->ReplaceRemoteMessagingModifiers($parts[2], $null);
+ }
+
+ $return_type_clean = $parts[2];
+ $return_type_pointers = preg_replace("![^*]+!e", "", $return_type_clean);
+ $return_type_clean = trim($return_type_clean,"* ");
+
+ // perform preformatting before attempting to protect keywords
+ $parts[2] = $this->FormatObjcType($parts[2], $modifiers);
+ $parts[4] = $this->FormatObjcParams($parts[4], $variable_arguments);
+ //print($parts[4]."\n");
+
+ if ($has_params) {
+ $name = $this->ConvertObjcMethodName($source);
+
+ // merge default protected keywords for the class/category
+ if ($this->default_protected["*"]) $protected_keywords = array_merge($this->default_protected["*"], $protected_keywords);
+ if ($this->default_protected[$class]) $protected_keywords = array_merge($this->default_protected[$class], $protected_keywords);
+
+
+ $param_array = $this->ConvertObjcParamsToPascal($parts[4], $protected_keywords);
+ $params = "(".$param_array["string"].")";
+ $params_with_modifiers = "(".$param_array["string_with_modifiers"].")";
+
+ } else {
+ $params = "";
+ $params_with_modifiers = "";
+ // no parameters -> definitely no underscore normally, but there are some
+ // conflicts...
+ $name = $parts[3];
+ // clean it up
+ if ($this->trailing_underscore) {
+ if (in_array($source, $this->trailing_underscore_methods)) $name = $name . "_";
+ }
+ $param_array = null;
+ $variable_arguments = false;
+ }
+
+ // protect method name from keywords
+ if ($this->IsKeywordReserved($name)) $name .= "_";
+
+ // replace objc type
+ $return_type = $this->ConvertReturnType($return_type_clean,$return_type_pointers);
+
+ $virtual = "";
+ $class_prefix = "";
+
+ // determine the type based on return value
+ if (ereg($this->regex_procedure_type, $return_type_clean.$return_type_pointers)) {
+ $kind = "procedure";
+ } else {
+ $kind = "function";
+ }
+
+ // determine if this is a class method
+ if ($parts[1] == "+") {
+ $class_prefix = "class ";
+
+ // These methods probably return the an allocated instance of the class, a typical convenience method.
+ // ??? Ack! $class may be the category or protocol name
+ //if ($return_type == $this->objc_id) $return_type = $class;
+ }
+
+ // Replace SEL with the string equivalent
+ if ($this->register_selectors) {
+ $params_with_modifiers = str_replace_word("SEL", $this->sel_string, $params_with_modifiers);
+ }
+
+ // make method templates
+ if ($kind != "function") {
+ if ($variable_arguments) $modifier .= " varargs;";
+
+ $method = "$class_prefix$kind $name$params_with_modifiers;$modifier$virtual";
+ $method_template = "[KIND] [PREFIX]$name"."[PARAMS];$modifier";
+ } else {
+ if ($variable_arguments) $return_type = "$return_type; varargs";
+
+ $method = $class_prefix."function $name$params_with_modifiers: $return_type;$modifier$virtual";
+ $method_template = "[KIND] [PREFIX]$name"."[PARAMS]: [RETURN];$modifier";
+ }
+
+ $method_template_procedure = "procedure [PREFIX]$name"."[PARAMS];$modifier";
+ $method_template_function = "function [PREFIX]$name"."[PARAMS]: [RETURN];$modifier";
+
+ // build structure
+ $struct["def"] = $method;
+ $struct["template"] = $method_template;
+ $struct["template_function"] = $method_template_function;
+ $struct["template_procedure"] = $method_template_procedure;
+ $struct["objc_method"] = $this->CopyObjcMethodName($source);
+ $struct["class_prefix"] = $class_prefix;
+ if ($deprecatedmods != "") $struct["deprecated"] = $deprecatedmods.";";
+ //$struct["def_objc"] = eregi("(.*);", $source, $captures[1]);
+ if ($return_type == "void") $return_type = "";
+ $struct["return"] = $return_type;
+
+ if (in_array($return_type, $this->cocoa_classes)) $struct["returns_wrapper"] = true;
+ $struct["param_string_clean"] = trim($params, "()");
+ $struct["param_string_clean_with_modifiers"] = trim($params_with_modifiers, "()");
+ $struct["param_string"] = $params;
+ $struct["param_string_with_modifiers"] = $params_with_modifiers;
+ $struct["param_array"] = $param_array["pairs"];
+ $struct["param_list"] = $param_array["list"];
+ $struct["class"] = $class;
+ $struct["name"] = $name;
+ $struct["kind"] = $kind;
+
+ if ($struct["param_array"] != null) $struct["has_params"] = true;
+
+ // FPC bug work around
+ if (strlen($name) > $this->maximum_method_length) {
+ $struct["can_override"] = false;
+ print(" # WARNING: method $name can't override because the name is too long\n");
+ $this->warning_count ++;
+ }
+
+ return $struct;
+ }
+
+ function InsertPatches ($header) {
+ $path = "$this->root/patches/".$header["name_clean"].".patch";
+ if ($handle = @fopen($path, "r")) {
+ $text = ReadTextFile($path);
+ $this->PrintOutput(0, $text);
+ fclose($handle);
+ }
+ }
+
+ function HeaderContainsPatch ($header) {
+ if ($handle = @fopen("$this->root/patches/".$header["name_clean"].".patch", "r")) {
+ fclose($handle);
+ return true;
+ }
+ }
+
+ function PrintGlobalClassInfo($all_classes, $defined_classes, $anon_classes) {
+ // add all classes as anonymous external classes to a separate unit.
+ // They will be overridden by the actual definitions in the translated
+ // headers part of the main unit, but this way they can appear as record
+ // field types and as callback parameters
+
+ // open the output file if we not printing to terminal
+ if (!$this->show) {
+ $this->output = fopen("$this->root$this->out/AnonClassDefinitions".ucfirst($this->framework).".pas", "w+");
+ }
+
+ $this->PrintOutput(0, "{ Parsed from ".ucfirst($this->framework)." }");
+
+ $date = @date("D M j G:i:s T Y");
+
+ $this->PrintOutput(0, "");
+ // allows parameter names conflicting with field names
+ $this->PrintOutput(0, "{\$mode delphi}");
+ $this->PrintOutput(0, "{\$modeswitch objectivec1}");
+ // enables "external" after the semi-colon
+ $this->PrintOutput(0, "{\$modeswitch cvar}");
+ $this->PrintOutput(0, "");
+
+ $this->PrintOutPut(0,"unit AnonClassDefinitions".ucfirst($this->framework).";");
+ $this->PrintOutput(0, "");
+ $this->PrintOutput(0, "interface");
+ $this->PrintOutput(0, "");
+ $this->PrintOutput(0, "type");
+
+ foreach ($all_classes as $class)
+ $this->PrintOutput(1, $class." = objcclass; external;");
+
+ $this->PrintOutput(0, "");
+ $this->PrintOutput(0, "implementation");
+ $this->PrintOutput(0, "");
+ $this->PrintOutput(0, "end.");
+
+
+ // Now all anonymous external classes that have no real definition to an
+ // include file that is added to the main unit. This way it is possible
+ // to declare variables of these types in user programs without having to
+ // include the unit above will all anonymous classes (should not be used)
+
+ // open the output file if we not printing to terminal
+ if (!$this->show) {
+ $this->output = fopen("$this->root$this->out/$this->framework/AnonIncludeClassDefinitions".ucfirst($this->framework).".inc", "w+");
+ }
+
+ $this->PrintOutput(0, "{ Parsed from ".ucfirst($this->framework)." }");
+
+ $date = @date("D M j G:i:s T Y");
+
+
+ // add all classes as anonymous external classes. They will be overridden
+ // by the actual definitions in the translated headers, but this way they
+ // can appear as record field types and as callback parameters
+ $first = true;
+ foreach ($anon_classes as $class) {
+ if (!in_array($class,$defined_classes)) {
+ if ($first) {
+ $this->PrintOutput(0, "type");
+ $first = false;
+ }
+ $this->PrintOutput(1, $class." = objcclass; external;");
+ }
+ }
+ }
+
+
+ // Prints all classes from the header in Objective-P FPC format
+ function PrintHeader ($header) {
+ global $version;
+ //print_r($header);
+ //print_r($this->dump["categories"]);
+
+ // open the output file if we not printing to terminal
+ if (!$this->show) {
+ if ($this->merge_headers) {
+ $this->output = fopen($header["path_merge"], "w+");
+ } else {
+ $this->output = fopen($header["path"], "w+");
+ }
+ }
+
+ $this->PrintOutput(0, "{ Parsed from ".ucfirst($header["framework"]).".framework ".$header["name"]." }");
+
+ $date = @date("D M j G:i:s T Y");
+ $this->PrintOutput(0, "{ Version: $version - $date }");
+ $this->PrintOutput(0, "");
+
+ $macro = strtoupper(substr($header["name"], 0, (strripos($header["name"], "."))));
+
+ $this->PrintOutput(0, "");
+ $this->PrintOutput(0, "{\$ifdef TYPES}");
+ $this->PrintOutput(0, "{\$ifndef $macro"."_PAS_T}");
+ $this->PrintOutput(0, "{\$define $macro"."_PAS_T}");
+ $this->PrintTypes($header, false);
+ $this->PrintOutput(0, "");
+ $this->PrintOutput(0, "{\$endif}");
+ $this->PrintOutput(0, "{\$endif}");
+
+ $this->PrintOutput(0, "");
+ $this->PrintOutput(0, "{\$ifdef RECORDS}");
+ $this->PrintOutput(0, "{\$ifndef $macro"."_PAS_R}");
+ $this->PrintOutput(0, "{\$define $macro"."_PAS_R}");
+
+ // Records from types
+ $this->PrintRecords($header);
+
+ $this->PrintOutput(0, "");
+ $this->PrintOutput(0, "{\$endif}");
+ $this->PrintOutput(0, "{\$endif}");
+
+ $this->PrintOutput(0, "");
+ $this->PrintOutput(0, "{\$ifdef FUNCTIONS}");
+ $this->PrintOutput(0, "{\$ifndef $macro"."_PAS_F}");
+ $this->PrintOutput(0, "{\$define $macro"."_PAS_F}");
+ $this->PrintFunctions($header);
+ $this->PrintOutput(0, "");
+ $this->PrintOutput(0, "{\$endif}");
+ $this->PrintOutput(0, "{\$endif}");
+
+ $this->PrintOutput(0, "");
+ $this->PrintOutput(0, "{\$ifdef EXTERNAL_SYMBOLS}");
+ $this->PrintOutput(0, "{\$ifndef $macro"."_PAS_S}");
+ $this->PrintOutput(0, "{\$define $macro"."_PAS_S}");
+ $this->PrintExternalSymbols($header);
+ $this->PrintOutput(0, "");
+ $this->PrintOutput(0, "{\$endif}");
+ $this->PrintOutput(0, "{\$endif}");
+
+ // insert user patches
+ if ($this->HeaderContainsPatch($header)) {
+ $this->PrintOutput(0, "");
+ $this->PrintOutput(0, "{\$ifdef USER_PATCHES}");
+ //$this->PrintOutput(0, "{\$ifndef $macro"."_PAS_PATCH}");
+ //$this->PrintOutput(0, "{\$define $macro"."_PAS_PATCH}");
+ $this->InsertPatches($header);
+ $this->PrintOutput(0, "");
+ //$this->PrintOutput(0, "{\$endif}");
+ $this->PrintOutput(0, "{\$endif}");
+ }
+
+ if (($header["classes"]) || ($header["protocols"])) {
+ $this->PrintOutput(0, "");
+ $this->PrintOutput(0, "{\$ifdef FORWARD}");
+
+ if ($header["protocols"]) {
+ foreach ($header["protocols"] as $protocol) $this->PrintOutput(1, $protocol["name"]."$this->protocol_suffix = objcprotocol;");
+ }
+
+ if ($header["classes"]) {
+ foreach ($header["classes"] as $class) {
+ if ($class["name"]) {
+ $this->PrintOutput(1, $class["name"]." = objcclass;");
+ $this->PrintOutput(1, $class["name"].$this->class_pointer_suffix." = ^".$class["name"].";");
+ // for consistency also offer Ptr-name variant
+ $this->PrintOutput(1, $class["name"]."Ptr = ".$class["name"].$this->class_pointer_suffix.";");
+ }
+ }
+ }
+ $this->PrintOutput(0, "");
+ $this->PrintOutput(0, "{\$endif}");
+ }
+
+ if ($header["classes"]) {
+ $this->PrintOutput(0, "");
+ $this->PrintOutput(0, "{\$ifdef CLASSES}");
+ $this->PrintOutput(0, "{\$ifndef $macro"."_PAS_C}");
+ $this->PrintOutput(0, "{\$define $macro"."_PAS_C}");
+
+ foreach ($header["classes"] as $class) {
+ if ($class["name"]) $this->PrintClass($class);
+ }
+
+ if (count($header["categories"]) > 0) {
+ foreach ($header["categories"] as $category) {
+ $this->PrintCategory($class, $category);
+ }
+ }
+
+ $this->PrintOutput(0, "");
+ $this->PrintOutput(0, "{\$endif}");
+ $this->PrintOutput(0, "{\$endif}");
+ }
+
+
+ if ($header["protocols"]) {
+ $this->PrintOutput(0, "{\$ifdef PROTOCOLS}");
+ $this->PrintOutput(0, "{\$ifndef $macro"."_PAS_P}");
+ $this->PrintOutput(0, "{\$define $macro"."_PAS_P}");
+
+
+ foreach ($header["protocols"] as $protocol) {
+ $this->PrintOutput(1, "");
+ $this->PrintOutput(0, "{ ".$protocol["name"]." Protocol }");
+ if ($protocol["comment"]) $this->PrintOutput(0, $protocol["comment"]);
+ $this->PrintOutput(1, $protocol["name"]."$this->protocol_suffix = objcprotocol");
+
+ // print methods
+ if ($protocol["methods"]) {
+ foreach ($protocol["methods"] as $name => $method) {
+ if ($method["comment"]) $this->PrintOutput(2, $method["comment"]);
+ $this->PrintOutput(2, $method["def"]." message '".$method["objc_method"]."';".$method["deprecated"]);
+ }
+ }
+
+ $this->PrintOutput(1, "end; external name '".$protocol["name"]."';");
+ }
+
+ $this->PrintOutput(0, "{\$endif}");
+ $this->PrintOutput(0, "{\$endif}");
+ }
+ }
+
+ function PrintCategory ($class, $category) {
+
+ // declare real category if external
+ if ($category["external"]) {
+ $new_name = " name '".$category["external_name"]."'";
+ }
+
+ $category_name = $category["name"].$this->category_suffix;
+
+ $this->PrintOutput(0, "");
+ $this->PrintOutput(0, "{ $category_name }");
+ if ($category["comment"]) $this->PrintOutput(0, $category["comment"]);
+
+ // print super class or protocol which the class conforms to
+ $this->PrintOutput(1, "$category_name = objccategory(".$category["super"].")");
+
+ // print methods
+ if ($category["methods"]) {
+ foreach ($category["methods"] as $method) {
+ if ($method["comment"]) $this->PrintOutput(2, $method["comment"]);
+ $this->PrintOutput(2, $method["def"]." message '".$method["objc_method"]."';".$method["deprecated"]);
+ }
+ }
+
+ $this->PrintOutput(1, "end; external$new_name;");
+ }
+
+ function PrintClass ($class) {
+
+ $this->PrintOutput(0, "");
+ $this->PrintOutput(0, "{ ".$class["name"]." }");
+
+ if ($class["comment"]) $this->PrintOutput(0, $class["comment"]);
+ //print_r($class["methods"]);
+
+
+ // print super class or protocol which the class conforms to
+ if ($class["adopts"]) {
+ $this->PrintOutput(1, $class["name"]." = objcclass(".$class["super"].", ".$class["adopts"].")");
+ } elseif ($class["super"]) {
+ $this->PrintOutput(1, $class["name"]." = objcclass(".$class["super"].")");
+ }
+
+ // print instance variables
+ if ($class["ivars"]) {
+ $this->PrintOutput(1, "private");
+ foreach ($class["ivars"] as $ivar) {
+ $this->PrintOutput(2, $ivar);
+ }
+ }
+
+ // print alloc method for the class
+ $this->PrintOutput(2, "");
+ $this->PrintOutput(1, "public");
+ $this->PrintOutput(2, "class function alloc: ".$class["name"]."; message 'alloc';");
+
+ // print class-level methods
+ if ($class["methods"]) {
+ $this->PrintOutput(0, "");
+ foreach ($class["methods"] as $method) {
+ if ($method["comment"]) $this->PrintOutput(2, $method["comment"]);
+ $this->PrintOutput(2, $method["def"]." message '".$method["objc_method"]."';".$method["deprecated"]);
+ }
+ }
+
+ // print adopted protocol methods
+ if (count($class["protocols"]) > 0) {
+ $this->PrintOutput(0, "");
+ $this->PrintOutput(2, "{ Adopted Protocols }");
+ //print_r($this->dump["protocols"]);
+
+ foreach ($class["protocols"] as $name) {
+ if ($this->dump["protocols"][$name]) {
+ foreach ($this->dump["protocols"][$name] as $method) {
+ if (!$this->ClassContainsMethod($class, $method)) $this->PrintOutput(2, $method["def"]);
+ }
+ }
+ }
+ }
+
+ $this->PrintOutput(1, "end; external;");
+ }
+
+}
+?> \ No newline at end of file