mixin: introduce -D option to redefine functions from the command-line
authorJean Privat <jean@pryen.org>
Fri, 10 Oct 2014 02:09:12 +0000 (22:09 -0400)
committerJean Privat <jean@pryen.org>
Fri, 10 Oct 2014 22:55:09 +0000 (18:55 -0400)
Signed-off-by: Jean Privat <jean@pryen.org>

src/compiler/abstract_compiler.nit
src/interpreter/naive_interpreter.nit
src/mixin.nit
src/model/model.nit
src/rapid_type_analysis.nit

index 082d987..b9987c0 100644 (file)
@@ -1397,6 +1397,19 @@ abstract class AbstractCompilerVisitor
                return res
        end
 
+       fun value_instance(object: Object): RuntimeVariable
+       do
+               if object isa Int then
+                       return int_instance(object)
+               else if object isa Bool then
+                       return bool_instance(object)
+               else if object isa String then
+                       return string_instance(object)
+               else
+                       abort
+               end
+       end
+
        # Generate an array value
        fun array_instance(array: Array[RuntimeVariable], elttype: MType): RuntimeVariable is abstract
 
@@ -1837,6 +1850,7 @@ redef class MMethodDef
        fun compile_inside_to_c(v: VISITOR, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
        do
                var modelbuilder = v.compiler.modelbuilder
+               var val = constant_value
                if modelbuilder.mpropdef2npropdef.has_key(self) then
                        var npropdef = modelbuilder.mpropdef2npropdef[self]
                        var oldnode = v.current_node
@@ -1851,6 +1865,8 @@ redef class MMethodDef
                        self.compile_parameter_check(v, arguments)
                        nclassdef.compile_to_c(v, self, arguments)
                        v.current_node = oldnode
+               else if val != null then
+                       v.ret(v.value_instance(val))
                else
                        abort
                end
index 917606a..01c872d 100644 (file)
@@ -248,6 +248,19 @@ class NaiveInterpreter
                return res
        end
 
+       fun value_instance(object: Object): Instance
+       do
+               if object isa Int then
+                       return int_instance(object)
+               else if object isa Bool then
+                       return bool_instance(object)
+               else if object isa String then
+                       return string_instance(object)
+               else
+                       abort
+               end
+       end
+
        # Return a new native string initialized with `txt`
        fun native_string_instance(txt: String): Instance
        do
@@ -376,6 +389,7 @@ class NaiveInterpreter
 
                # Look for the AST node that implements the property
                var mproperty = mpropdef.mproperty
+               var val = mpropdef.constant_value
                if self.modelbuilder.mpropdef2npropdef.has_key(mpropdef) then
                        var npropdef = self.modelbuilder.mpropdef2npropdef[mpropdef]
                        self.parameter_check(npropdef, mpropdef, args)
@@ -384,6 +398,8 @@ class NaiveInterpreter
                        var nclassdef = self.modelbuilder.mclassdef2nclassdef[mpropdef.mclassdef]
                        self.parameter_check(nclassdef, mpropdef, args)
                        return nclassdef.call(self, mpropdef, args)
+               else if val != null then
+                       return value_instance(val)
                else
                        fatal("Fatal Error: method {mpropdef} not found in the AST")
                        abort
index bdbadf0..94d0c32 100644 (file)
@@ -22,11 +22,13 @@ import modelbuilder
 redef class ToolContext
        # --mixin
        var opt_mixins = new OptionArray("Additionals module to min-in", "-m", "--mixin")
+       # --define
+       var opt_defines = new OptionArray("Define a specific property", "-D", "--define")
 
        redef init
        do
                super
-               option_context.add_option(opt_mixins)
+               option_context.add_option(opt_mixins, opt_defines)
        end
 
        redef fun make_main_module(mmodules)
@@ -39,6 +41,70 @@ redef class ToolContext
 
                var mainmodule = super
 
+               var defines = opt_defines.value
+               if not defines.is_empty then
+                       var location = mainmodule.location
+                       var model = mainmodule.model
+
+                       if mainmodule == mmodules.first then
+                               mainmodule = new MModule(model, null, mainmodule.name + "-d", location)
+                               mainmodule.set_imported_mmodules(mmodules)
+                               mainmodule.is_fictive = true
+                       end
+
+                       var recv = mainmodule.object_type
+                       var mclassdef = new MClassDef(mainmodule, recv, location)
+                       mclassdef.add_in_hierarchy
+
+                       for define in defines do
+                               var spl = define.split_once_on('=')
+                               var name = spl.first
+                               var val = null
+                               if spl.length > 1 then val = spl[1]
+                               var prop = mainmodule.try_get_primitive_method(name, recv.mclass)
+                               if prop == null then
+                                       error(null, "Error: --define: no top-level function `{name}`")
+                                       continue
+                               end
+                               var ret = prop.intro.msignature.return_mtype
+                               var v
+                               if ret == null then
+                                       error(null, "Error: --define: Method `{prop}` is not a function")
+                                       continue
+                               else if ret.to_s == "Bool" then
+                                       if val == null or val == "true" then
+                                               v = true
+                                       else if val == "false" then
+                                               v = false
+                                       else
+                                               error(null, "Error: --define: Method `{prop}` need a Bool.")
+                                               continue
+                                       end
+                               else if ret.to_s == "Int" then
+                                       if val != null and val.is_numeric then
+                                               v = val.to_i
+                                       else
+                                               error(null, "Error: --define: Method `{prop}` need a Int.")
+                                               continue
+                                       end
+                               else if ret.to_s == "String" then
+                                       if val != null then
+                                               v = val
+                                       else
+                                               error(null, "Error: --define: Method `{prop}` need a String.")
+                                               continue
+                                       end
+                               else
+                                       error(null, "Error: --define: Method `{prop}` return an unmanaged type {ret}.")
+                                       continue
+                               end
+                               var pd = new MMethodDef(mclassdef, prop, location)
+                               pd.msignature = prop.intro.msignature
+                               pd.constant_value = v
+                       end
+                       check_errors
+               end
+
                return mainmodule
        end
 end
index eab60f7..f26eb2e 100644 (file)
@@ -1977,6 +1977,16 @@ class MMethodDef
 
        # Is the method definition extern?
        var is_extern = false is writable
+
+       # An optional constant value returned in functions.
+       #
+       # Only some specific primitife value are accepted by engines.
+       # Is used when there is no better implementation available.
+       #
+       # Currently used only for the implementation of the `--define`
+       # command-line option.
+       # SEE: module `mixin`.
+       var constant_value: nullable Object = null is writable
 end
 
 # A local definition of an attribute
index a6adfee..7cbdaf9 100644 (file)
@@ -244,6 +244,9 @@ class RapidTypeAnalysis
                                        if mmethoddef.mproperty.is_root_init and not mmethoddef.is_intro then
                                                self.add_super_send(v.receiver, mmethoddef)
                                        end
+                               else if mmethoddef.constant_value != null then
+                                       # Make the return type live
+                                       v.add_type(mmethoddef.msignature.return_mtype.as(MClassType))
                                else
                                        abort
                                end