Added sources files.
[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 naive_interpreter
21 import debugger
22 import pnacl
23 intrude import toolcontext
24 intrude import modelbuilder
25 intrude import standard::file
26
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)
30 do
31 var dictionary = new PepperDictionary
32 dictionary["exit"] = exit_value
33 dictionary["exit_thread"] = "A new thread has been made available for Nit."
34 create_thread
35 app.post_dictionary dictionary
36 exit_thread exit_value
37 end
38 end
39
40 #hack realpath.
41 redef class String
42 redef fun realpath do return self
43
44 # file_exists looks in the 'files' HashMap.
45 redef fun file_exists: Bool
46 do
47 if sys.files.has_key(self) then return true
48 return false
49 end
50 end
51
52 redef class Sys
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]
58 end
59
60 redef class ToolContext
61 # We don't need 'the compute_nit_dir'.
62 redef fun compute_nit_dir: nullable String
63 do
64 return "/pnacl"
65 end
66 end
67
68 # We have to redef some IFStream methods because we don't use NativeFiles anymore.
69 redef class IFStream
70
71 # Looks in the 'files' HashMap.
72 redef init open(path: String)
73 do
74 self.path = path
75 var file = sys.files[path]
76 prepare_buffer(file.length)
77 _buffer.append(file)
78 end
79
80 redef fun close
81 do
82 end_reached = true
83 end
84
85 redef fun fill_buffer
86 do
87 _buffer.clear
88 end_reached = true
89 end
90
91 redef fun reopen
92 do
93 _buffer_pos = 0
94 end
95 end
96
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
100
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
103 do
104 var candidate: nullable String = null
105 var try_file = "{name}.nit"
106 if try_file.file_exists then
107 if candidate == null then
108 candidate = try_file
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}")
115 end
116 end
117 end
118 if candidate == null then return null
119 return identify_file(candidate)
120 end
121 end
122
123 class Pnacl_nit
124 super PnaclApp
125
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)
130 do
131 var d = dictionary.copy
132 var operation = d["operation"]
133
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)
147
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))
152
153 var arguments = toolcontext.option_context.rest
154 var progname = arguments.first
155 sys.files[progname] = d["content"].to_s
156
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
161
162 if toolcontext.opt_only_metamodel.value then exit(0)
163
164 var mainmodule: nullable MModule
165
166 # Here we launch the interpreter on the main module
167 if mmodules.length == 1 then
168 mainmodule = mmodules.first
169 else
170 mainmodule = new MModule(model, null, mmodules.first.name, mmodules.first.location)
171 mainmodule.set_imported_mmodules(mmodules)
172 end
173
174 var self_mm = mainmodule.as(not null)
175 var self_args = arguments.as(not null)
176
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)
181 else
182 modelbuilder.run_naive_interpreter(self_mm, self_args)
183 end
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
191 end
192 var response = new PepperDictionary
193 response["operation"] = "load_response"
194 response["files_number"] = sys.lib.length.to_s
195 post_dictionary response
196 end
197 end
198 end
199
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.