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
::naive_interpreter
22 intrude import nitc
::toolcontext
23 intrude import nitc
::loader
24 intrude import core
::file
26 # We redefine exit to start a new thread before killing the one that called exit.
27 redef fun exit
(exit_value
: Int)
29 var dictionary
= new PepperDictionary
30 dictionary
["exit"] = exit_value
31 dictionary
["exit_thread"] = "A new thread has been made available for Nit."
33 app
.post_dictionary dictionary
34 exit_thread exit_value
39 redef fun realpath
do return self
41 # file_exists looks in the 'files' HashMap.
42 redef fun file_exists
: Bool
44 if sys
.files
.has_key
(self) then return true
50 # We add two HashMap for temporary file storage.
51 # 'lib' stores the lib files.
52 var lib
= new HashMap[String, String]
53 # 'files' stores the "file(s)" you want to interpret + the lib files.
54 var files
= new HashMap[String, String]
57 redef class ToolContext
58 # We don't need 'the locate_nit_dir'.
59 redef fun locate_nit_dir
65 # We have to redef some FileReader methods because we don't use NativeFiles anymore.
66 redef class FileReader
68 # Looks in the 'files' HashMap.
69 redef init open
(path
: String)
72 var file
= sys
.files
[path
]
73 prepare_buffer
(file
.length
)
74 path
.copy_to_native
(_buffer
, file
.length
, 0, 0)
94 redef class ModelBuilder
95 # We don't use paths as the interpreter, so just return the argument.
96 redef fun module_absolute_path
(path
: String): String do return path
98 # We don't use paths as the interpreter, so we don't use location or lookpaths args (see the default implementation).
99 redef fun search_module_in_paths
(location
: nullable Location, name
: String, lookpaths
: Collection[String]): nullable MModule
101 var candidate
: nullable String = null
102 var try_file
= "{name}.nit"
103 if try_file
.file_exists
then
104 if candidate
== null then
106 else if candidate
!= try_file
then
107 # try to disambiguate conflicting modules
108 var abs_candidate
= module_absolute_path
(candidate
)
109 var abs_try_file
= module_absolute_path
(try_file
)
110 if abs_candidate
!= abs_try_file
then
111 toolcontext
.error
(location
, "Error: conflicting module file for {name}: {candidate} {try_file}")
115 if candidate
== null then return null
116 return identify_module
(candidate
)
123 # In handle_dictionary we search for the 'operation' key in dictionaries,
124 # 'load' means that we are loading the Nit library,
125 # 'interpret' launches the interpreter code.
126 redef fun handle_dictionary
(dictionary
: PepperDictionary)
128 var d
= dictionary
.copy
129 var operation
= d
["operation"]
131 # If operation = 'intepret' we want to interpret some Nit code, so we execute the same code as in nit.nit.
132 if operation
== "interpret" then
133 var args
= d
["args"].to_s
.split
(' ')
134 # Create a tool context to handle options and paths
135 var toolcontext
= new ToolContext
136 toolcontext
.tooldescription
= "Usage: nit [OPTION]... <file.nit>...\nInterprets and debbugs Nit programs."
137 # Add an option "-o" to enable compatibilit with the tests.sh script
138 var opt
= new OptionString("compatibility (does noting)", "-o")
139 toolcontext
.option_context
.add_option
(opt
)
140 var opt_mixins
= new OptionArray("Additionals module to min-in", "-m")
141 toolcontext
.option_context
.add_option
(opt_mixins
)
142 # We do not add other options, so process them now!
143 toolcontext
.process_options
(args
)
145 # We need a model to collect stufs
146 var model
= new Model
147 # An a model builder to parse files
148 var modelbuilder
= new ModelBuilder(model
, toolcontext
)
150 var arguments
= toolcontext
.option_context
.rest
151 var progname
= arguments
.first
152 sys
.files
[progname
] = d
["content"].to_s
154 # Here we load an process all modules passed on the command line
155 var mmodules
= modelbuilder
.parse
([progname
])
156 mmodules
.add_all modelbuilder
.parse
(opt_mixins
.value
)
157 modelbuilder
.run_phases
159 if toolcontext
.opt_only_metamodel
.value
then exit
(0)
161 var mainmodule
: nullable MModule
163 # Here we launch the interpreter on the main module
164 if mmodules
.length
== 1 then
165 mainmodule
= mmodules
.first
167 mainmodule
= new MModule(model
, null, mmodules
.first
.name
, mmodules
.first
.location
)
168 mainmodule
.set_imported_mmodules
(mmodules
)
171 var self_mm
= mainmodule
172 var self_args
= arguments
174 modelbuilder
.run_naive_interpreter
(self_mm
, self_args
)
175 # If operation = 'load', we are loading lib files, so we store them into HashMaps and send a response to JS.
176 else if operation
== "load" then
177 var filename
= d
["filename"]
178 var content
= d
["content"]
179 if filename
isa String and content
isa String then
180 sys
.lib
[filename
] = content
181 sys
.files
[filename
] = content
183 var response
= new PepperDictionary
184 response
["operation"] = "load_response"
185 response
["files_number"] = sys
.lib
.length
.to_s
186 post_dictionary response
191 redef fun app
do return once
new Pnacl_nit
192 app
.initialize
# Needed to correctly set up Nit control over the Pepper API.
193 app
.run
# Wait for dictionaries.