ed8151de09b0b30f648d21e0c78b2b0ec30508e4
[nit.git] / contrib / online_ide / sources / nit / pnacl_nit.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2014 Johan Kayser <kayser.johan@gmail.com>
4 #
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
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
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.
16
17 # A version of the naive Nit interpreter for PNaCl.
18 module pnacl_nit
19
20 import interpreter::naive_interpreter
21 import interpreter::debugger
22 import pnacl
23 intrude import toolcontext
24 intrude import loader
25 intrude import core::file
26
27 # We redefine exit to start a new thread before killing the one that called exit.
28 redef fun exit(exit_value: Int)
29 do
30 var dictionary = new PepperDictionary
31 dictionary["exit"] = exit_value
32 dictionary["exit_thread"] = "A new thread has been made available for Nit."
33 create_thread
34 app.post_dictionary dictionary
35 exit_thread exit_value
36 end
37
38 #hack realpath.
39 redef class String
40 redef fun realpath do return self
41
42 # file_exists looks in the 'files' HashMap.
43 redef fun file_exists: Bool
44 do
45 if sys.files.has_key(self) then return true
46 return false
47 end
48 end
49
50 redef class Sys
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]
56 end
57
58 redef class ToolContext
59 # We don't need 'the compute_nit_dir'.
60 redef fun compute_nit_dir
61 do
62 return "/pnacl"
63 end
64 end
65
66 # We have to redef some FileReader methods because we don't use NativeFiles anymore.
67 redef class FileReader
68
69 # Looks in the 'files' HashMap.
70 redef init open(path: String)
71 do
72 self.path = path
73 var file = sys.files[path]
74 prepare_buffer(file.length)
75 path.copy_to_native(_buffer, file.length, 0, 0)
76 end
77
78 redef fun close
79 do
80 end_reached = true
81 end
82
83 redef fun fill_buffer
84 do
85 buffer_reset
86 end_reached = true
87 end
88
89 redef fun reopen
90 do
91 _buffer_pos = 0
92 end
93 end
94
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
98
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
101 do
102 var candidate: nullable String = null
103 var try_file = "{name}.nit"
104 if try_file.file_exists then
105 if candidate == null then
106 candidate = try_file
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}")
113 end
114 end
115 end
116 if candidate == null then return null
117 return identify_file(candidate)
118 end
119 end
120
121 class Pnacl_nit
122 super PnaclApp
123
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)
128 do
129 var d = dictionary.copy
130 var operation = d["operation"]
131
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)
145
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)
150
151 var arguments = toolcontext.option_context.rest
152 var progname = arguments.first
153 sys.files[progname] = d["content"].to_s
154
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
159
160 if toolcontext.opt_only_metamodel.value then exit(0)
161
162 var mainmodule: nullable MModule
163
164 # Here we launch the interpreter on the main module
165 if mmodules.length == 1 then
166 mainmodule = mmodules.first
167 else
168 mainmodule = new MModule(model, null, mmodules.first.name, mmodules.first.location)
169 mainmodule.set_imported_mmodules(mmodules)
170 end
171
172 var self_mm = mainmodule
173 var self_args = arguments
174
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)
179 else
180 modelbuilder.run_naive_interpreter(self_mm, self_args)
181 end
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
189 end
190 var response = new PepperDictionary
191 response["operation"] = "load_response"
192 response["files_number"] = sys.lib.length.to_s
193 post_dictionary response
194 end
195 end
196 end
197
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.