diff --git a/src/astbuilder.nit b/src/astbuilder.nit index d0602eea2e..9c93bd0241 100644 --- a/src/astbuilder.nit +++ b/src/astbuilder.nit @@ -42,6 +42,12 @@ class ASTBuilder return new AIntegerExpr.make(value, mmodule.int_type) end + # Make a self expression + fun make_self: ASelfExpr + do + return new ASelfExpr + end + # Make a new instantiation fun make_new(callsite: CallSite, args: nullable Array[AExpr]): ANewExpr do diff --git a/src/contracts.nit b/src/contracts.nit index 132be36277..d4fc9c9e3b 100644 --- a/src/contracts.nit +++ b/src/contracts.nit @@ -70,7 +70,9 @@ redef class AModule # Entry point to generate the entire contract infrastructure. # Once this method is called we must call the `do_weaving_contracts` method (see it for more information). fun do_contracts(toolcontext: ToolContext) do - var ast_builder = new ASTBuilder(mmodule.as(not null)) + var mmodule = self.mmodule + if mmodule == null then return # Skip errir + var ast_builder = new ASTBuilder(mmodule) # var contract_visitor = new ContractsVisitor(toolcontext, toolcontext.modelbuilder.identified_modules.first, self, ast_builder) contract_visitor.enter_visit(self) diff --git a/src/examples/module_fictive.nit b/src/examples/module_fictive.nit new file mode 100644 index 0000000000..39c8c45e83 --- /dev/null +++ b/src/examples/module_fictive.nit @@ -0,0 +1,61 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Sample program that show how to build (and run) a synthetic program from the AST builder +import nitc::astprinter +import nitc::interpreter +import nitc::astbuilder + +# 3 god classes +var tc = new ToolContext +tc.keep_going = true +var model = new Model +var mb = new ModelBuilder(model, tc) + +# load the code module. While implicit in source code, we need to retrieve it for synthetic code +var acore = mb.load_module("core") +var mcore = acore.mmodule +assert mcore != null +# Loading does not perform the analysis, so force the analysis now +mb.run_phases + +# A synthetic main module +var mmodule = new MModule(model, null, "m0", model.no_location) +mmodule.set_imported_mmodules([mcore]) # Close the module hierarchy +mmodule.set_visibility_for(mcore, public_visibility) # Important, or else `_name` methods will fail + +# Refine Sys in the main module +var mclass = mmodule.sys_type +assert mclass != null +var mclassdef = new MClassDef(mmodule, mclass, model.no_location) +mclassdef.add_in_hierarchy # Close the classdef hierarchy + +# Redefine Sys::main +var nmeth = mb.create_method_from_name("main", mclassdef, false) + +# Body is `self.print(42)` +var ab = new ASTBuilder(mmodule, mclass) +var narg = ab.make_int(42) +var nrecv = ab.make_self +var mprint = mb.try_get_mproperty_by_name2(null, mmodule, mclass, "print") +assert mprint isa MMethod +var callsite = ab.create_callsite(mprint, false) +var ncall = ab.make_call(nrecv, callsite, [narg]) +nmeth.n_block.add(ncall) + +nmeth.dump_tree(false, false) +ncall.print_tree + +var interpreter = new NaiveInterpreter(mb, mmodule, new Array[String]) +interpreter.start(mmodule) diff --git a/src/examples/module_injected.nit b/src/examples/module_injected.nit new file mode 100644 index 0000000000..2bb66cabf4 --- /dev/null +++ b/src/examples/module_injected.nit @@ -0,0 +1,42 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Sample program that show how to load (and run) a program from a String +module module_injected + +import nitc::parser_util +import nitc::astprinter +import nitc::interpreter + +# 3 god classes +var tc = new ToolContext +tc.keep_going = true +var model = new Model +var mb = new ModelBuilder(model, tc) + +# Parse the module +var amodule = tc.parse_module("print 42") +# Add it to the model through the model builder +var mmodule = mb.load_rt_module(null, amodule, "-") +assert mmodule != null +# Do the semantic analysis +mb.run_phases + +amodule.dump_tree +var main_method = amodule.n_classdefs.last.n_propdefs.first +main_method.print_tree +assert main_method isa AMethPropdef + +var interpreter = new NaiveInterpreter(mb, mmodule, new Array[String]) +interpreter.start(mmodule) diff --git a/src/ffi/header_dependency.nit b/src/ffi/header_dependency.nit index 84bbb298b4..dd596b24fe 100644 --- a/src/ffi/header_dependency.nit +++ b/src/ffi/header_dependency.nit @@ -68,6 +68,7 @@ private class HeaderDependancyPhase redef fun process_nmodule(nmodule) do var mmodule = nmodule.mmodule + if mmodule == null then return # Skip error mmodule.compute_header_dependencies(self) end end diff --git a/src/nit.nit b/src/nit.nit index 6441b1a1f9..1f44fa2bfe 100644 --- a/src/nit.nit +++ b/src/nit.nit @@ -50,7 +50,6 @@ var mmodules: Array[MModule] if opt_eval.value then var amodule = toolcontext.parse_module(progname) - toolcontext.check_errors var parent = null if opt_loop.value then @@ -62,13 +61,14 @@ if opt_eval.value then end modelbuilder.load_rt_module(parent, amodule, "-") + toolcontext.check_errors mmodules = [amodule.mmodule.as(not null)] else if progname == "-" then var content = stdin.read_all var amodule = toolcontext.parse_module(content) - toolcontext.check_errors modelbuilder.load_rt_module(null, amodule, "-") + toolcontext.check_errors mmodules = [amodule.mmodule.as(not null)] else mmodules = modelbuilder.parse([progname]) diff --git a/src/parser/parser_nodes.nit b/src/parser/parser_nodes.nit index f19547d159..120ea68cdf 100644 --- a/src/parser/parser_nodes.nit +++ b/src/parser/parser_nodes.nit @@ -26,6 +26,11 @@ abstract class ANode # However, manual instantiated nodes may need more care. var location: Location is writable, noinit + fun has_location: Bool + do + return isset self._location + end + # The location of the important part of the node (identifier or whatever) fun hot_location: Location do return location @@ -235,7 +240,11 @@ class ASTDump redef fun display(n) do - return "{n.class_name} {n.dump_info(self)} @{n.location}" + if n.has_location then + return "{n.class_name} {n.dump_info(self)} @{n.location}" + else + return "{n.class_name} {n.dump_info(self)}" + end end # `s` as yellow @@ -382,7 +391,13 @@ abstract class Token redef fun is_structural do return true - redef fun dump_info(v) do return " {text.escape_to_c}" + redef fun dump_info(v) do + if has_location then + return " {text.escape_to_c}" + else + return "" + end + end # Loose tokens that precede `self`. # diff --git a/src/toolcontext.nit b/src/toolcontext.nit index 0797723308..19045e95d9 100644 --- a/src/toolcontext.nit +++ b/src/toolcontext.nit @@ -416,6 +416,8 @@ class ToolContext opt_stub_man.hidden = true opt_bash_completion.hidden = true opt_set_dummy_tool.hidden = true + + nit_dir = locate_nit_dir end # Name, usage and synopsis of the tool. @@ -503,6 +505,10 @@ The Nit language documentation and the source code of its tools and libraries ma end nit_dir = locate_nit_dir + if nit_dir == null then + fatal_error(null, "Fatal Error: cannot locate a valid base Nit directory. It is quite unexpected. Try to set the environment variable `NIT_DIR` or to use the `--nit-dir` option.") + abort + end if option_context.rest.is_empty and not accept_no_arguments then print tooldescription @@ -577,7 +583,7 @@ The Nit language documentation and the source code of its tools and libraries ma # # The result is returned without being assigned to `nit_dir`. # This function is automatically called by `process_options` - fun locate_nit_dir: String + fun locate_nit_dir: nullable String do # the option has precedence var res = opt_nit_dir.value @@ -617,8 +623,7 @@ The Nit language documentation and the source code of its tools and libraries ma if check_nit_dir(res) then return res.simplify_path end - fatal_error(null, "Fatal Error: cannot locate a valid base Nit directory. It is quite unexpected. Try to set the environment variable `NIT_DIR` or to use the `--nit-dir` option.") - abort + return null end private fun check_nit_dir(res: String): Bool diff --git a/tests/nitcg.skip b/tests/nitcg.skip index 3c378aa029..e61d597669 100644 --- a/tests/nitcg.skip +++ b/tests/nitcg.skip @@ -11,3 +11,5 @@ get_mclasses ^nit test_astbuilder test_astprinter +module_fictive +module_injected diff --git a/tests/niti.skip b/tests/niti.skip index 551351b0d6..340b280e0b 100644 --- a/tests/niti.skip +++ b/tests/niti.skip @@ -48,3 +48,5 @@ nitpm nitdoc test_astbuilder test_astprinter +module_fictive +module_injected diff --git a/tests/sav/module_fictive.res b/tests/sav/module_fictive.res new file mode 100644 index 0000000000..8edc936ff3 --- /dev/null +++ b/tests/sav/module_fictive.res @@ -0,0 +1,11 @@ +AMethPropdef @ +|--APublicVisibility +|--AIdMethid +|--ASignature +`--ABlockExpr + `--ACallExpr call=Sys.file$Sys$print(object: Object) + |--ASelfExpr + `--AListExprs + `--AIntegerExpr :Int +self.print(42) +42 diff --git a/tests/sav/module_injected.res b/tests/sav/module_injected.res new file mode 100644 index 0000000000..bc55b36d31 --- /dev/null +++ b/tests/sav/module_injected.res @@ -0,0 +1,14 @@ +1 print 42 +AModule @1,1--8 +`--AMainClassdef @1,1--8 + `--AMainMethPropdef @1,1--8 + `--ABlockExpr @1,1--8 + `--ACallExpr call=Sys.file$Sys$print(object: Object) @1,1--8 + |--AImplicitSelfExpr :Sys @1,1 + |--AQid @1,1--5 + | `--TId print @1,1--5 + `--AListExprs @1,7--8 + `--AIntegerExpr :Int @1,7--8 + `--TInteger 42 @1,7--8 +print(42) +42