Merge: lib: expand packages
[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 nitc::naive_interpreter
21 import pnacl
22 intrude import nitc::toolcontext
23 intrude import nitc::loader
24 intrude import core::file
25
26 # We redefine exit to start a new thread before killing the one that called exit.
27 redef fun exit(exit_value: Int)
28 do
29 var dictionary = new PepperDictionary
30 dictionary["exit"] = exit_value
31 dictionary["exit_thread"] = "A new thread has been made available for Nit."
32 create_thread
33 app.post_dictionary dictionary
34 exit_thread exit_value
35 end
36
37 #hack realpath.
38 redef class String
39 redef fun realpath do return self
40
41 # file_exists looks in the 'files' HashMap.
42 redef fun file_exists: Bool
43 do
44 if sys.files.has_key(self) then return true
45 return false
46 end
47 end
48
49 redef class Sys
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]
55 end
56
57 redef class ToolContext
58 # We don't need 'the locate_nit_dir'.
59 redef fun locate_nit_dir
60 do
61 return "/pnacl"
62 end
63 end
64
65 # We have to redef some FileReader methods because we don't use NativeFiles anymore.
66 redef class FileReader
67
68 # Looks in the 'files' HashMap.
69 redef init open(path: String)
70 do
71 self.path = path
72 var file = sys.files[path]
73 prepare_buffer(file.length)
74 path.copy_to_native(_buffer, file.length, 0, 0)
75 end
76
77 redef fun close
78 do
79 end_reached = true
80 end
81
82 redef fun fill_buffer
83 do
84 buffer_reset
85 end_reached = true
86 end
87
88 redef fun reopen
89 do
90 _buffer_pos = 0
91 end
92 end
93
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
97
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
100 do
101 var candidate: nullable String = null
102 var try_file = "{name}.nit"
103 if try_file.file_exists then
104 if candidate == null then
105 candidate = try_file
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}")
112 end
113 end
114 end
115 if candidate == null then return null
116 return identify_module(candidate)
117 end
118 end
119
120 class Pnacl_nit
121 super PnaclApp
122
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)
127 do
128 var d = dictionary.copy
129 var operation = d["operation"]
130
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)
144
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)
149
150 var arguments = toolcontext.option_context.rest
151 var progname = arguments.first
152 sys.files[progname] = d["content"].to_s
153
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
158
159 if toolcontext.opt_only_metamodel.value then exit(0)
160
161 var mainmodule: nullable MModule
162
163 # Here we launch the interpreter on the main module
164 if mmodules.length == 1 then
165 mainmodule = mmodules.first
166 else
167 mainmodule = new MModule(model, null, mmodules.first.name, mmodules.first.location)
168 mainmodule.set_imported_mmodules(mmodules)
169 end
170
171 var self_mm = mainmodule
172 var self_args = arguments
173
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
182 end
183 var response = new PepperDictionary
184 response["operation"] = "load_response"
185 response["files_number"] = sys.lib.length.to_s
186 post_dictionary response
187 end
188 end
189 end
190
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.