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 naive_interpreter
23 intrude import toolcontext
24 intrude import modelbuilder
25 intrude import standard
::file
27 redef interface Object
28 # We redefine exit to start a new thread before killing the one that called exit.
29 redef fun exit
(exit_value
: Int)
31 var dictionary
= new PepperDictionary
32 dictionary
["exit"] = exit_value
33 dictionary
["exit_thread"] = "A new thread has been made available for Nit."
35 app
.post_dictionary dictionary
36 exit_thread exit_value
42 redef fun realpath
do return self
44 # file_exists looks in the 'files' HashMap.
45 redef fun file_exists
: Bool
47 if sys
.files
.has_key
(self) then return true
53 # We add two HashMap for temporary file storage.
54 # 'lib' stores the lib files.
55 var lib
= new HashMap[String, String]
56 # 'files' stores the "file(s)" you want to interpret + the lib files.
57 var files
= new HashMap[String, String]
60 redef class ToolContext
61 # We don't need 'the compute_nit_dir'.
62 redef fun compute_nit_dir
: nullable String
68 # We have to redef some IFStream methods because we don't use NativeFiles anymore.
71 # Looks in the 'files' HashMap.
72 redef init open
(path
: String)
75 var file
= sys
.files
[path
]
76 prepare_buffer
(file
.length
)
97 redef class ModelBuilder
98 # We don't use paths as the interpreter, so just return the argument.
99 redef fun module_absolute_path
(path
: String): String do return path
101 # We don't use paths as the interpreter, so we don't use location or lookpaths args (see the default implementation).
102 redef fun search_module_in_paths
(location
: nullable Location, name
: String, lookpaths
: Collection[String]): nullable ModulePath
104 var candidate
: nullable String = null
105 var try_file
= "{name}.nit"
106 if try_file
.file_exists
then
107 if candidate
== null then
109 else if candidate
!= try_file
then
110 # try to disambiguate conflicting modules
111 var abs_candidate
= module_absolute_path
(candidate
)
112 var abs_try_file
= module_absolute_path
(try_file
)
113 if abs_candidate
!= abs_try_file
then
114 toolcontext
.error
(location
, "Error: conflicting module file for {name}: {candidate} {try_file}")
118 if candidate
== null then return null
119 return identify_file
(candidate
)
126 # In handle_dictionary we search for the 'operation' key in dictionaries,
127 # 'load' means that we are loading the Nit library,
128 # 'interpret' launches the interpreter code.
129 redef fun handle_dictionary
(dictionary
: PepperDictionary)
131 var d
= dictionary
.copy
132 var operation
= d
["operation"]
134 # If operation = 'intepret' we want to interpret some Nit code, so we execute the same code as in nit.nit.
135 if operation
== "interpret" then
136 var args
= d
["args"].to_s
.split
(' ')
137 # Create a tool context to handle options and paths
138 var toolcontext
= new ToolContext
139 toolcontext
.tooldescription
= "Usage: nit [OPTION]... <file.nit>...\nInterprets and debbugs Nit programs."
140 # Add an option "-o" to enable compatibilit with the tests.sh script
141 var opt
= new OptionString("compatibility (does noting)", "-o")
142 toolcontext
.option_context
.add_option
(opt
)
143 var opt_mixins
= new OptionArray("Additionals module to min-in", "-m")
144 toolcontext
.option_context
.add_option
(opt_mixins
)
145 # We do not add other options, so process them now!
146 toolcontext
.process_options
(args
)
148 # We need a model to collect stufs
149 var model
= new Model
150 # An a model builder to parse files
151 var modelbuilder
= new ModelBuilder(model
, toolcontext
.as(not null))
153 var arguments
= toolcontext
.option_context
.rest
154 var progname
= arguments
.first
155 sys
.files
[progname
] = d
["content"].to_s
157 # Here we load an process all modules passed on the command line
158 var mmodules
= modelbuilder
.parse
([progname
])
159 mmodules
.add_all modelbuilder
.parse
(opt_mixins
.value
)
160 modelbuilder
.run_phases
162 if toolcontext
.opt_only_metamodel
.value
then exit
(0)
164 var mainmodule
: nullable MModule
166 # Here we launch the interpreter on the main module
167 if mmodules
.length
== 1 then
168 mainmodule
= mmodules
.first
170 mainmodule
= new MModule(model
, null, mmodules
.first
.name
, mmodules
.first
.location
)
171 mainmodule
.set_imported_mmodules
(mmodules
)
174 var self_mm
= mainmodule
.as(not null)
175 var self_args
= arguments
.as(not null)
177 if toolcontext
.opt_debugger_autorun
.value
then
178 modelbuilder
.run_debugger_autorun
(self_mm
, self_args
)
179 else if toolcontext
.opt_debugger_mode
.value
then
180 modelbuilder
.run_debugger
(self_mm
, self_args
)
182 modelbuilder
.run_naive_interpreter
(self_mm
, self_args
)
184 # If operation = 'load', we are loading lib files, so we store them into HashMaps and send a response to JS.
185 else if operation
== "load" then
186 var filename
= d
["filename"]
187 var content
= d
["content"]
188 if filename
isa String and content
isa String then
189 sys
.lib
[filename
] = content
190 sys
.files
[filename
] = content
192 var response
= new PepperDictionary
193 response
["operation"] = "load_response"
194 response
["files_number"] = sys
.lib
.length
.to_s
195 post_dictionary response
200 redef fun app
do return once
new Pnacl_nit
201 app
.initialize
# Needed to correctly set up Nit control over the Pepper API.
202 app
.run
# Wait for dictionaries.