1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 # This program is free software: you can redistribute it and/or modify
15 # it under the terms of the GNU General Public License as published by
16 # the Free Software Foundation, either version 3 of the License, or
17 # (at your option) any later version.
19 # The Nit interactive interpreter
22 import nitc
::interpreter
24 import nitc
::parser_util
26 redef class ToolContext
29 var opt_no_prompt
= new OptionBool("Disable writing a prompt.", "--no-prompt")
32 var opt_source_name
= new OptionString("Set a name for the input source.", "--source-name")
36 option_context
.add_option
(opt_no_prompt
, opt_source_name
)
39 # Parse a full module given as a string
41 # Return a AModule or a AError
42 fun p_module
(string
: String): ANode
44 var source_name
= opt_source_name
.value
or else ""
45 string
= "\n" * last_line
+ string
46 var source
= new SourceFile.from_string
(source_name
, string
)
47 var lexer
= new Lexer(source
)
48 var parser
= new Parser(lexer
)
49 var tree
= parser
.parse
52 if eof
isa AError then
55 return tree
.n_base
.as(not null)
58 # Read an user-line with a given `prompt`
60 # Return `null` if end of file
61 fun readline
(prompt
: String): nullable String do
63 var res
= stdin
.read_line
64 if res
== "" and stdin
.eof
then return null
68 # Add `text` in the history for `readline`.
70 # With the default implementation, the history is dropped
71 fun readline_add_history
(text
: String) do end
73 # The last line number read by `i_parse`
76 # Parse the input of the user as a module
77 fun i_parse
(prompt
: String): nullable ANode
83 if opt_no_prompt
.value
then
85 if s
== "" and stdin
.eof
then s
= null
89 if s
== null then return null
99 if s
.chars
.first
== ':' then
100 var res
= new TString
105 var text
= oldtext
+ s
+ "\n"
107 var n
= p_module
(text
)
109 if n
isa AParserError and (n
.token
isa EOF) then
110 # Unexpected end of file, thus continuing
111 if oldtext
== "" then prompt
= "." * prompt
.length
116 last_line
= n
.location
.file
.line_starts
.length
- 1
117 readline_add_history
(text
.chomp
)
124 # Create a tool context to handle options and paths
125 var toolcontext
= new ToolContext
126 toolcontext
.option_context
.options_before_rest
= true
127 toolcontext
.accept_no_arguments
= true
128 toolcontext
.keep_going
= true
129 toolcontext
.process_options
(args
)
131 # We need a model to collect stufs
132 var model
= new Model
133 # An a model builder to parse files
134 var modelbuilder
= new ModelBuilder(model
, toolcontext
)
136 var arguments
= toolcontext
.option_context
.rest
138 # Our initial program is an empty module
139 var amodule
= toolcontext
.parse_module
("")
140 var mmodule
= modelbuilder
.load_rt_module
(null, amodule
, "input-0")
141 modelbuilder
.run_phases
142 if not toolcontext
.check_errors
then return
143 assert mmodule
!= null
144 var mmodules
= [mmodule
]
145 var mainmodule
= toolcontext
.make_main_module
(mmodules
)
147 # Start and run the interpreter on the empty module
148 var interpreter
= new NaiveInterpreter(modelbuilder
, mainmodule
, arguments
)
149 interpreter
.start
(mainmodule
)
151 # Get the main object and the main method
152 var mainobj
= interpreter
.mainobj
153 assert mainobj
!= null
154 var sys_type
= mainobj
.mtype
.as(MClassType)
155 var mainprop
= mainmodule
.try_get_primitive_method
("main", sys_type
.mclass
)
156 assert mainprop
!= null
160 # Next piece of Nit code
161 var n
= toolcontext
.i_parse
("-->")
166 # Special adhoc command
167 if n
isa TString then
179 print
"{n.location.colored_line("0;31")}: {n.message}"
185 # A syntactically module!
186 amodule
= n
.as(AModule)
188 # Try to load it as a submodule
190 var newmodule
= modelbuilder
.load_rt_module
(mainmodule
, amodule
, "input-{l}")
191 if newmodule
== null then continue
192 modelbuilder
.run_phases
193 if not toolcontext
.check_errors
then
194 toolcontext
.error_count
= 0
197 # Everything is fine, the module is the new main module!
198 mainmodule
= newmodule
199 interpreter
.mainmodule
= mainmodule
201 # Run the main if the AST contains a main
202 if amodule
.n_classdefs
.not_empty
and amodule
.n_classdefs
.last
isa AMainClassdef then
204 interpreter
.catch_count
+= 1
205 interpreter
.send
(mainprop
, [mainobj
])
207 var e
= interpreter
.last_error
211 print
"{en.location}: Runtime error: {e.message}\n{en.location.colored_line("0;31")}"
213 print
"Runtime error: {e.message}"
216 print interpreter
.stack_trace
217 interpreter
.frames
.clear