contrib/objcwrapper: revamp the AST visitor
authorAlexis Laferrière <alexis.laf@xymus.net>
Fri, 21 Aug 2015 15:29:19 +0000 (11:29 -0400)
committerAlexis Laferrière <alexis.laf@xymus.net>
Fri, 21 Aug 2015 19:05:27 +0000 (15:05 -0400)
Signed-off-by: Alexis Laferrière <alexis.laf@xymus.net>

contrib/objcwrapper/src/objc_visitor.nit
contrib/objcwrapper/src/objcwrapper.nit

index d4056d4..3d51935 100644 (file)
@@ -18,564 +18,187 @@ module objc_visitor
 import objc_model
 import objc_parser
 
-class Interpretor
+# AST visitor building `model` from the parsed class headers
+class ObjcVisitor
        super Visitor
 
-       var is_variable = false
-       var is_method = false
-       var is_parameter_name = false
-       var class_objc: nullable ObjcClass = null
-       var method_objc: ObjcMethod is noinit
-       var attribute_objc: ObjcAttribute is noinit
-       var param: Param is noinit
+       # `ObjcModel` in construction
        var model = new ObjcModel
 
+       # `ObjcClass` in construction, if any
+       private var objc_class: nullable ObjcClass = null
+
        redef fun visit(n) do n.accept_objc(self)
 end
 
 redef class Node
-       fun accept_objc(v: Interpretor) do visit_children(v)
+       private fun accept_objc(v: ObjcVisitor) do visit_children(v)
 end
 
-redef class Nlines
-       redef fun accept_objc(v) do
-       end
-end
+# ---
+# Main nodes
 
+# Class declaration
 redef class Nlines_interface
-       redef fun accept_objc(v) do
+       redef fun accept_objc(v)
+       do
                var interface_block = n_interface_block
-               var inheritance_block = n_inheritance
-               v.class_objc = null
-               if interface_block != null then
-                       for class_objc in v.model.classes do
-                               if class_objc.name == n_class.text then
-                                       v.class_objc = class_objc
-                               end
-                       end
-                       if v.class_objc == null then
-                               v.class_objc = new ObjcClass(n_class.text)
-                               v.model.classes.add(v.class_objc)
+               if interface_block == null then return
+
+               # If reopening a class, continue with the exisitng one
+               var c = null
+               for objc_class in v.model.classes do
+                       if objc_class.name == n_class.text then
+                               c = objc_class
                        end
-                       if inheritance_block != null then v.enter_visit(inheritance_block)
-                       v.enter_visit(interface_block)
                end
-       end
-end
-
-redef class Ninheritance_add
-       redef fun accept_objc(v) do
-               var additional = n_additional
-               v.enter_visit(n_classe)
-               if additional != null then v.enter_visit(additional)
-       end
-end
-
-redef class Nclasse_class
-       redef fun accept_objc(v) do
-               v.class_objc.super_names.add(n_class.text)
-       end
-end
-
-redef class Nadditional_add
-       redef fun accept_objc(v) do
-               v.enter_visit(n_classe)
-       end
-end
-
-redef class Ninterface_block_instance
-       redef fun accept_objc(v) do
-               v.enter_visit(n_instance_declaration)
-       end
-end
 
-redef class Ninstance_declaration_signature
-       redef fun accept_objc(v) do
-               v.enter_visit(n_signature_block)
-       end
-end
-
-redef class Ninstance_declaration_property
-       redef fun accept_objc(v) do
-               v.enter_visit(n_property_declaration)
-       end
-end
-
-redef class Nproperty_declaration_property
-       redef fun accept_objc(v) do
-               v.enter_visit(n_property)
-       end
-end
-
-redef class Nsignature_block_signature
-       redef fun accept_objc(v) do
-               if n_signature.children.to_s.has("signature_named") or n_signature.children.to_s.has("signature_single") then
-                       v.method_objc = new ObjcMethod
-
-                       v.enter_visit(n_scope)
-                       v.is_method = true
-                       var signature_return_type = n_signature_return_type
-                       if signature_return_type != null then v.enter_visit(signature_return_type)
-                       v.is_method = false
-                       v.enter_visit(n_signature)
-
-                       v.class_objc.methods.add(v.method_objc)
+               # New class
+               if c == null then
+                       c = new ObjcClass(n_class.text)
+                       v.model.classes.add c
                end
-       end
-end
-
-redef class Nscope_instance
-       redef fun accept_objc(v) do
-               v.method_objc.scope = '-'
-       end
-end
-
-redef class Nscope_class
-       redef fun accept_objc(v) do
-               v.method_objc.scope = '+'
-       end
-end
+               v.objc_class = c
 
-redef class Nsignature_return_type_return
-       redef fun accept_objc(v) do
-               v.enter_visit(n_type)
-       end
-end
-
-redef class Nsignature_named
-       redef fun accept_objc(v) do
-               v.param = new Param
-
-               v.enter_visit(n_left)
-               v.is_parameter_name = true
-               v.enter_visit(n_right)
-               v.is_parameter_name = false
-               v.enter_visit(n_signature_type)
-
-               v.method_objc.params.add(v.param)
-       end
-end
-
-redef class Nsignature_single
-       redef fun accept_objc(v) do
-               v.param = new Param
-               v.param.is_single = true
-               v.enter_visit(n_term)
-               v.method_objc.params.add(v.param)
-       end
-end
-
-redef class Nsignature_type_anonymous
-       redef fun accept_objc(v) do
-               v.enter_visit(n_type)
-               v.method_objc.is_commented = true
-       end
-end
-
-redef class Nsignature_type_table
-       redef fun accept_objc(v) do
-               v.enter_visit(n_type)
-               v.param.is_table = true
-       end
-end
-
-redef class Nsignature_type_pointer
-       redef fun accept_objc(v) do
-               v.enter_visit(n_type)
-               v.param.is_pointer = true
-       end
-end
-
-redef class Nsignature_type_unsigned
-       redef fun accept_objc(v) do
-               v.method_objc.is_commented = true
-               v.param.is_pointer = true
-       end
-end
-
-redef class Nsignature_type_protocol
-       redef fun accept_objc(v) do
-               v.enter_visit(n_type)
-               v.method_objc.is_commented = true
-       end
-end
+               # Visit superclass declarations
+               var inheritance_block = n_inheritance
+               if inheritance_block != null then v.enter_visit(inheritance_block)
 
-redef class Nsignature_type_normal
-       redef fun accept_objc(v) do
-               v.enter_visit(n_type)
+               # Visit main body
+               v.enter_visit(interface_block)
        end
 end
 
-redef class Nterm_private
-       redef fun accept_objc(v) do
-               if v.is_parameter_name then
-                       v.param.variable_name = n_private.text
-               else if v.is_variable then
-                       v.attribute_objc.name = n_private.text
-               else
-                       v.param.name = n_private.text
-               end
-       end
-end
+# Method or function declaration
+redef class Nsignature_block_signature
+       redef fun accept_objc(v)
+       do
+               var method = new ObjcMethod
+               method.return_type = n_signature_return_type.to_type
+               method.scope = if n_scope.is_class_property then '-' else '+'
+
+               for n_param in n_parameter.children do
+                       var param = n_param.to_param
+                       if param == null then
+
+                               # Unsupported parameter format
+                               method.is_commented = true
+
+                               # Use a placeholder for easier debugging
+                               param = new Param
+                               param.name = "UNKNOWN"
+                               param.return_type = "UNKNOWN"
+                               param.variable_name = "UNKNOWN"
+                       end
 
-redef class Nterm_class
-       redef fun accept_objc(v) do
-               if v.is_parameter_name then
-                       v.param.variable_name = n_class.text
-               else if v.is_variable then
-                       v.attribute_objc.name = n_class.text
-               else
-                       v.param.name = n_class.text
+                       method.params.add param
                end
-       end
-end
 
-redef class Nterm_var
-       redef fun accept_objc(v) do
-               if v.is_parameter_name then
-                       v.param.variable_name = n_id.text
-               else if v.is_variable then
-                       v.attribute_objc.name = n_id.text
-               else
-                       v.param.name = n_id.text
-               end
+               v.objc_class.methods.add method
        end
 end
 
+# Class variable/attribute declaration (inside alternative node)
 redef class Nproperty_property
-       redef fun accept_objc(v) do
-               var protocol = n_protocols
-               if protocol == null then
-                       v.is_variable = true
-                       v.attribute_objc = new ObjcAttribute
-                       v.enter_visit(n_left)
-                       v.enter_visit(n_type)
-                       v.class_objc.attributes.add(v.attribute_objc)
-                       v.is_variable = false
-               end
-       end
-end
+       redef fun accept_objc(v)
+       do
+               var attr = new ObjcAttribute
+               attr.return_type = n_type.to_type
+               attr.name = n_left.collect_text
 
-redef class Ntype_type
-       redef fun accept_objc(v) do
-               v.enter_visit(n_data_type)
+               v.objc_class.attributes.add attr
        end
 end
 
-redef class Ndata_type_more
-       redef fun accept_objc(v) do
-               v.enter_visit(n_more_type)
-       end
-end
-
-redef class Ndata_type_otype
-       redef fun accept_objc(v) do
-               if v.is_variable then
-                       v.attribute_objc.return_type = n_class.text
-               else if v.is_method then
-                       v.method_objc.return_type = n_class.text
-               else
-                       v.param.return_type = n_class.text
-               end
-       end
-end
-
-redef class Nmore_type_stype
-       redef fun accept_objc(v) do
-               v.enter_visit(n_specific_type)
-       end
-end
-
-redef class Nmore_type_ptype
-       redef fun accept_objc(v) do
-               v.enter_visit(n_primitive_type)
-       end
-end
-
-redef class Nspecific_type_i
-       redef fun accept_objc(v) do
-               if v.is_variable then
-                       v.attribute_objc.return_type = "id"
-               else if v.is_method then
-                       v.method_objc.return_type = "id"
-               else
-                       v.param.return_type = "id"
-               end
-       end
-end
-
-redef class Nspecific_type_b
-       redef fun accept_objc(v) do
-               if v.is_variable then
-                       v.attribute_objc.return_type = "Bool"
-               else if v.is_method then
-                       v.method_objc.return_type = "Bool"
-               else
-                       v.param.return_type = "Bool"
-               end
-       end
-end
-
-redef class Nspecific_type_val
-       redef fun accept_objc(v) do
-               if v.is_variable then
-                       v.attribute_objc.return_type = "va_list"
-               else if v.is_method then
-                       v.method_objc.return_type = "va_list"
-               else
-                       v.param.return_type = "va_list"
-               end
-       end
-end
-
-redef class Nspecific_type_v
-       redef fun accept_objc(v) do
-               if v.is_variable then
-                       v.attribute_objc.return_type = "void"
-               else if v.is_method then
-                       v.method_objc.return_type = "void"
-               else
-                       v.param.return_type = "void"
-               end
-       end
-end
-
-redef class Nprimitive_type_ui8
-       redef fun accept_objc(v) do
-               if v.is_variable then
-                       v.attribute_objc.return_type = "uint8_t"
-               else if v.is_method then
-                       v.method_objc.return_type = "uint8_t"
-               else
-                       v.param.return_type = "uint8_t"
-               end
-       end
-end
-
-redef class Nprimitive_type_ui16
-       redef fun accept_objc(v) do
-               if v.is_variable then
-                       v.attribute_objc.return_type = "uint16_t"
-               else if v.is_method then
-                       v.method_objc.return_type = "uint16_t"
-               else
-                       v.param.return_type = "uint16_t"
-               end
-       end
-end
-
-redef class Nprimitive_type_ui32
-       redef fun accept_objc(v) do
-               if v.is_variable then
-                       v.attribute_objc.return_type = "uint32_t"
-               else if v.is_method then
-                       v.method_objc.return_type = "uint32_t"
-               else
-                       v.param.return_type = "uint32_t"
-               end
-       end
-end
-
-redef class Nprimitive_type_ui64
-       redef fun accept_objc(v) do
-               if v.is_variable then
-                       v.attribute_objc.return_type = "uint64_t"
-               else if v.is_method then
-                       v.method_objc.return_type = "uint64_t"
-               else
-                       v.param.return_type = "uint64_t"
-               end
-       end
-end
-
-redef class Nprimitive_type_i8
-       redef fun accept_objc(v) do
-               if v.is_variable then
-                       v.attribute_objc.return_type = "int8_t"
-               else if v.is_method then
-                       v.method_objc.return_type = "int8_t"
-               else
-                       v.param.return_type = "int8_t"
-               end
-       end
-end
-
-redef class Nprimitive_type_i16
-       redef fun accept_objc(v) do
-               if v.is_variable then
-                       v.attribute_objc.return_type = "int16_t"
-               else if v.is_method then
-                       v.method_objc.return_type = "int16_t"
-               else
-                       v.param.return_type = "int16_t"
-               end
-       end
-end
-
-redef class Nprimitive_type_i32
-       redef fun accept_objc(v) do
-               if v.is_variable then
-                       v.attribute_objc.return_type = "int32_t"
-               else if v.is_method then
-                       v.method_objc.return_type = "int32_t"
-               else
-                       v.param.return_type = "int32_t"
-               end
+# Class variable/attribute declaration (outside with @property)
+redef class Nproperty_declaration_property
+       redef fun accept_objc(v)
+       do
+               # TODO property attribute readonly, copy, etc.
+               super
        end
 end
 
-redef class Nprimitive_type_i64
-       redef fun accept_objc(v) do
-               if v.is_variable then
-                       v.attribute_objc.return_type = "int64_t"
-               else if v.is_method then
-                       v.method_objc.return_type = "int64_t"
-               else
-                       v.param.return_type = "int64_t"
-               end
-       end
-end
+# ---
+# Support nodes
 
-redef class Nprimitive_type_uc
-       redef fun accept_objc(v) do
-               if v.is_variable then
-                       v.attribute_objc.return_type = "unichar"
-               else if v.is_method then
-                       v.method_objc.return_type = "unichar"
-               else
-                       v.param.return_type = "unichar"
-               end
+redef class NProd
+       # Append all tokens under this node in a `String`
+       private fun collect_text: String
+       do
+               var buf = new FlatBuffer
+               for node in depth do if node isa NToken then buf.append node.text
+               return buf.to_s
        end
 end
 
-redef class Nprimitive_type_c
-       redef fun accept_objc(v) do
-               if v.is_variable then
-                       v.attribute_objc.return_type = "char"
-               else if v.is_method then
-                       v.method_objc.return_type = "char"
-               else
-                       v.param.return_type = "char"
-               end
-       end
+redef class Nlines
+       # Do not visit other lines, they are only to be eaten
+       redef fun accept_objc(v) do end
 end
 
-redef class Nprimitive_type_s
-       redef fun accept_objc(v) do
-               if v.is_variable then
-                       v.attribute_objc.return_type = "short"
-               else if v.is_method then
-                       v.method_objc.return_type = "short"
-               else
-                       v.param.return_type = "short"
-               end
-       end
+redef class Nscope
+       # Does this mark a class property (+)? Otherwise it's an instance property (-).
+       private fun is_class_property: Bool do return false
 end
 
-redef class Nprimitive_type_si
-       redef fun accept_objc(v) do
-               if v.is_variable then
-                       v.attribute_objc.return_type = "short int"
-               else if v.is_method then
-                       v.method_objc.return_type = "short int"
-               else
-                       v.param.return_type = "short int"
-               end
-       end
+redef class Nscope_class
+       redef fun is_class_property do return true
 end
 
-redef class Nprimitive_type_i
-       redef fun accept_objc(v) do
-               if v.is_variable then
-                       v.attribute_objc.return_type = "int"
-               else if v.is_method then
-                       v.method_objc.return_type = "int"
-               else
-                       v.param.return_type = "int"
-               end
-       end
+redef class Nsignature_return_type
+       # Get type from this node TODO return an ObjcType
+       private fun to_type: String do return collect_text
 end
 
-redef class Nprimitive_type_l
-       redef fun accept_objc(v) do
-               if v.is_variable then
-                       v.attribute_objc.return_type = "long"
-               else if v.is_method then
-                       v.method_objc.return_type = "long"
-               else
-                       v.param.return_type = "long"
-               end
-       end
+redef class Nsignature_return_type_return
+       redef fun to_type do return n_type.to_type
 end
 
-redef class Nprimitive_type_li
-       redef fun accept_objc(v) do
-               if v.is_variable then
-                       v.attribute_objc.return_type = "long int"
-               else if v.is_method then
-                       v.method_objc.return_type = "long int"
-               else
-                       v.param.return_type = "long int"
-               end
-       end
+redef class Nparameter
+       # Return null if type is not yet unsupported
+       private fun to_param: nullable Param do return null
 end
 
-redef class Nprimitive_type_ll
-       redef fun accept_objc(v) do
-               if v.is_variable then
-                       v.attribute_objc.return_type = "long long"
-               else if v.is_method then
-                       v.method_objc.return_type = "long long"
-               else
-                       v.param.return_type = "long long"
-               end
+# Parameters with both a public and an internal name
+redef class Nparameter_named
+       redef fun to_param
+       do
+               var param = new Param
+               param.variable_name = n_right.collect_text
+               param.name = n_left.collect_text
+               param.return_type = n_parameter_type.to_type
+               return param
        end
 end
 
-redef class Nprimitive_type_lli
-       redef fun accept_objc(v) do
-               if v.is_variable then
-                       v.attribute_objc.return_type = "long long int"
-               else if v.is_method then
-                       v.method_objc.return_type = "long long int"
-               else
-                       v.param.return_type = "long long int"
-               end
+# Usually the name of a method without parameters
+redef class Nparameter_single
+       redef fun to_param
+       do
+               var param = new Param
+               param.name = n_term.collect_text
+               param.is_single = true
+               return param
        end
 end
 
-redef class Nprimitive_type_f
-       redef fun accept_objc(v) do
-               if v.is_variable then
-                       v.attribute_objc.return_type = "float"
-               else if v.is_method then
-                       v.method_objc.return_type = "float"
-               else
-                       v.param.return_type = "float"
+redef class Nparameter_type
+       # Get type from this node TODO return an ObjcType
+       private fun to_type: String
+       do
+               # FIXME taking the first token skips pointers
+               for child in children do
+                       if child isa Ntype then
+                               return child.to_type
+                       end
                end
-       end
-end
 
-redef class Nprimitive_type_d
-       redef fun accept_objc(v) do
-               if v.is_variable then
-                       v.attribute_objc.return_type = "double"
-               else if v.is_method then
-                       v.method_objc.return_type = "double"
-               else
-                       v.param.return_type = "double"
-               end
+               return collect_text
        end
 end
 
-redef class Nprimitive_type_ld
-       redef fun accept_objc(v) do
-               if v.is_variable then
-                       v.attribute_objc.return_type = "long double"
-               else if v.is_method then
-                       v.method_objc.return_type = "long double"
-               else
-                       v.param.return_type = "long double"
-               end
-       end
+redef class Ntype
+       # Get type from this node TODO return an ObjcType
+       private fun to_type: String do return collect_text
 end
index d697cf5..46a6f70 100644 (file)
@@ -40,7 +40,7 @@ Options:"""
        exit 1
 end
 
-var v = new Interpretor
+var v = new ObjcVisitor
 var g = new CodeGenerator
 
 for arg in opts.rest do