1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2014 Johan Kayser <kayser.johan@gmail.com>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # A version of the naive Nit interpreter for PNaCl.
20 import nitc
::interpreter
::naive_interpreter
21 import nitc
::interpreter
::debugger
23 intrude import nitc
::toolcontext
24 intrude import nitc
::loader
25 intrude import core
::file
27 # We redefine exit to start a new thread before killing the one that called exit.
28 redef fun exit
(exit_value
: Int)
30 var dictionary
= new PepperDictionary
31 dictionary
["exit"] = exit_value
32 dictionary
["exit_thread"] = "A new thread has been made available for Nit."
34 app
.post_dictionary dictionary
35 exit_thread exit_value
40 redef fun realpath
do return self
42 # file_exists looks in the 'files' HashMap.
43 redef fun file_exists
: Bool
45 if sys
.files
.has_key
(self) then return true
51 # We add two HashMap for temporary file storage.
52 # 'lib' stores the lib files.
53 var lib
= new HashMap[String, String]
54 # 'files' stores the "file(s)" you want to interpret + the lib files.
55 var files
= new HashMap[String, String]
58 redef class ToolContext
59 # We don't need 'the compute_nit_dir'.
60 redef fun compute_nit_dir
66 # We have to redef some FileReader methods because we don't use NativeFiles anymore.
67 redef class FileReader
69 # Looks in the 'files' HashMap.
70 redef init open
(path
: String)
73 var file
= sys
.files
[path
]
74 prepare_buffer
(file
.length
)
75 path
.copy_to_native
(_buffer
, file
.length
, 0, 0)
95 redef class ModelBuilder
96 # We don't use paths as the interpreter, so just return the argument.
97 redef fun module_absolute_path
(path
: String): String do return path
99 # We don't use paths as the interpreter, so we don't use location or lookpaths args (see the default implementation).
100 redef fun search_module_in_paths
(location
: nullable Location, name
: String, lookpaths
: Collection[String]): nullable ModulePath
102 var candidate
: nullable String = null
103 var try_file
= "{name}.nit"
104 if try_file
.file_exists
then
105 if candidate
== null then
107 else if candidate
!= try_file
then
108 # try to disambiguate conflicting modules
109 var abs_candidate
= module_absolute_path
(candidate
)
110 var abs_try_file
= module_absolute_path
(try_file
)
111 if abs_candidate
!= abs_try_file
then
112 toolcontext
.error
(location
, "Error: conflicting module file for {name}: {candidate} {try_file}")
116 if candidate
== null then return null
117 return identify_file
(candidate
)
124 # In handle_dictionary we search for the 'operation' key in dictionaries,
125 # 'load' means that we are loading the Nit library,
126 # 'interpret' launches the interpreter code.
127 redef fun handle_dictionary
(dictionary
: PepperDictionary)
129 var d
= dictionary
.copy
130 var operation
= d
["operation"]
132 # If operation = 'intepret' we want to interpret some Nit code, so we execute the same code as in nit.nit.
133 if operation
== "interpret" then
134 var args
= d
["args"].to_s
.split
(' ')
135 # Create a tool context to handle options and paths
136 var toolcontext
= new ToolContext
137 toolcontext
.tooldescription
= "Usage: nit [OPTION]... <file.nit>...\nInterprets and debbugs Nit programs."
138 # Add an option "-o" to enable compatibilit with the tests.sh script
139 var opt
= new OptionString("compatibility (does noting)", "-o")
140 toolcontext
.option_context
.add_option
(opt
)
141 var opt_mixins
= new OptionArray("Additionals module to min-in", "-m")
142 toolcontext
.option_context
.add_option
(opt_mixins
)
143 # We do not add other options, so process them now!
144 toolcontext
.process_options
(args
)
146 # We need a model to collect stufs
147 var model
= new Model
148 # An a model builder to parse files
149 var modelbuilder
= new ModelBuilder(model
, toolcontext
)
151 var arguments
= toolcontext
.option_context
.rest
152 var progname
= arguments
.first
153 sys
.files
[progname
] = d
["content"].to_s
155 # Here we load an process all modules passed on the command line
156 var mmodules
= modelbuilder
.parse
([progname
])
157 mmodules
.add_all modelbuilder
.parse
(opt_mixins
.value
)
158 modelbuilder
.run_phases
160 if toolcontext
.opt_only_metamodel
.value
then exit
(0)
162 var mainmodule
: nullable MModule
164 # Here we launch the interpreter on the main module
165 if mmodules
.length
== 1 then
166 mainmodule
= mmodules
.first
168 mainmodule
= new MModule(model
, null, mmodules
.first
.name
, mmodules
.first
.location
)
169 mainmodule
.set_imported_mmodules
(mmodules
)
172 var self_mm
= mainmodule
173 var self_args
= arguments
175 if toolcontext
.opt_debugger_autorun
.value
then
176 modelbuilder
.run_debugger_autorun
(self_mm
, self_args
)
177 else if toolcontext
.opt_debugger_mode
.value
then
178 modelbuilder
.run_debugger
(self_mm
, self_args
)
180 modelbuilder
.run_naive_interpreter
(self_mm
, self_args
)
182 # If operation = 'load', we are loading lib files, so we store them into HashMaps and send a response to JS.
183 else if operation
== "load" then
184 var filename
= d
["filename"]
185 var content
= d
["content"]
186 if filename
isa String and content
isa String then
187 sys
.lib
[filename
] = content
188 sys
.files
[filename
] = content
190 var response
= new PepperDictionary
191 response
["operation"] = "load_response"
192 response
["files_number"] = sys
.lib
.length
.to_s
193 post_dictionary response
198 redef fun app
do return once
new Pnacl_nit
199 app
.initialize
# Needed to correctly set up Nit control over the Pepper API.
200 app
.run
# Wait for dictionaries.