nitmetrics: refactor self usage metrics computation
[nit.git] / src / naive_interpreter.nit
index 18a4389..95a66a4 100644 (file)
@@ -21,6 +21,17 @@ import literal
 import typing
 import auto_super_init
 
+redef class ToolContext
+       # --discover-call-trace
+       var opt_discover_call_trace: OptionBool = new OptionBool("Trace calls of the first invocation of a method", "--discover-call-trace")
+
+       redef init
+       do
+               super
+               self.option_context.add_option(self.opt_discover_call_trace)
+       end
+end
+
 redef class ModelBuilder
        # Execute the program from the entry point (Sys::main) of the `mainmodule'
        # `arguments' are the command-line arguments in order
@@ -266,11 +277,28 @@ private class NaiveInterpreter
                exit(1)
        end
 
+       # Debug on the current node
+       fun debug(message: String)
+       do
+               if frames.is_empty then
+                       print message
+               else
+                       self.frame.current_node.debug(message)
+               end
+       end
+
+       # Store known method, used to trace methods as thez are reached
+       var discover_call_trace: Set[MMethodDef] = new HashSet[MMethodDef]
+
        # Execute `mpropdef' for a `args' (where args[0] is the receiver).
        # Return a falue if `mpropdef' is a function, or null if it is a procedure.
        # The call is direct/static. There is no message-seding/late-bindng.
        fun call(mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
        do
+               if self.modelbuilder.toolcontext.opt_discover_call_trace.value and not self.discover_call_trace.has(mpropdef) then
+                       self.discover_call_trace.add mpropdef
+                       self.debug("Discovered {mpropdef}")
+               end
                var vararg_rank = mpropdef.msignature.vararg_rank
                if vararg_rank >= 0 then
                        assert args.length >= mpropdef.msignature.arity + 1 # because of self
@@ -701,7 +729,9 @@ redef class AInternMethPropdef
                                return v.int_instance(recv <=> args[1].val.as(Char))
                        end
                else if cname == "Float" then
-                       if pname == "+" then
+                       if pname == "unary -" then
+                               return v.float_instance(-args[0].to_f)
+                       else if pname == "+" then
                                return v.float_instance(args[0].to_f + args[1].to_f)
                        else if pname == "-" then
                                return v.float_instance(args[0].to_f - args[1].to_f)
@@ -849,6 +879,16 @@ redef class AExternMethPropdef
                                var res = sys.system(recvval.to_s)
                                return v.int_instance(res)
                        end
+               else if cname == "Int" then
+                       if pname == "rand" then
+                               return v.int_instance(args[0].to_i.rand)
+                       end
+               else if cname == "Float" then
+                       if pname == "cos" then
+                               return v.float_instance(args[0].to_f.cos)
+                       else if pname == "sin" then
+                               return v.float_instance(args[0].to_f.sin)
+                       end
                else if pname == "native_argc" then
                        return v.int_instance(v.arguments.length)
                else if pname == "native_argv" then
@@ -856,6 +896,10 @@ redef class AExternMethPropdef
                        return v.native_string_instance(txt)
                else if pname == "get_time" then
                        return v.int_instance(get_time)
+               else if pname == "atan2" then
+                       return v.float_instance(atan2(args[1].to_f, args[2].to_f))
+               else if pname == "pi" then
+                       return v.float_instance(pi)
                else if pname == "lexer_goto" then
                        return v.int_instance(lexer_goto(args[1].to_i, args[2].to_i))
                else if pname == "lexer_accept" then