Skip to content

Commit

Permalink
Improve the usability of ASTBuilder
Browse files Browse the repository at this point in the history
This fix small bugs and add a full example of a synthetic module that prints 42
  • Loading branch information
privat authored Aug 22, 2024
2 parents 5fa8f4c + b277a63 commit d18ebf9
Show file tree
Hide file tree
Showing 12 changed files with 169 additions and 8 deletions.
6 changes: 6 additions & 0 deletions src/astbuilder.nit
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion src/contracts.nit
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
61 changes: 61 additions & 0 deletions src/examples/module_fictive.nit
Original file line number Diff line number Diff line change
@@ -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)
42 changes: 42 additions & 0 deletions src/examples/module_injected.nit
Original file line number Diff line number Diff line change
@@ -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)
1 change: 1 addition & 0 deletions src/ffi/header_dependency.nit
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 2 additions & 2 deletions src/nit.nit
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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])
Expand Down
19 changes: 17 additions & 2 deletions src/parser/parser_nodes.nit
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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`.
#
Expand Down
11 changes: 8 additions & 3 deletions src/toolcontext.nit
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions tests/nitcg.skip
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ get_mclasses
^nit
test_astbuilder
test_astprinter
module_fictive
module_injected
2 changes: 2 additions & 0 deletions tests/niti.skip
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,5 @@ nitpm
nitdoc
test_astbuilder
test_astprinter
module_fictive
module_injected
11 changes: 11 additions & 0 deletions tests/sav/module_fictive.res
Original file line number Diff line number Diff line change
@@ -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
14 changes: 14 additions & 0 deletions tests/sav/module_injected.res
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit d18ebf9

Please sign in to comment.