Modified the generated Makefile for some options,
[nit.git] / lib / pnacl.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 # Targets the PNaCl platform
18 #
19 # To use this module and compile for PNaCl, you must install the
20 # NaCl SDK (This file is based on Pepper 33).
21 # If NACL_SDK_ROOT is not set in your PATH, you have to work in
22 # 'nacl_sdk/pepper_your_pepper_version/getting_started/your_project_folder'.
23 #
24 # Provides PNaCl support for Nit
25 module pnacl is platform
26 `{
27 #include <unistd.h>
28 #include <stddef.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include "ppapi/c/pp_errors.h"
32 #include "ppapi/c/ppp.h"
33 #include "ppapi/c/ppp_instance.h"
34 #include "ppapi/c/pp_bool.h"
35 #include "ppapi/c/ppb_var.h"
36 #include "ppapi/c/ppb_messaging.h"
37 #include "ppapi/c/ppp_messaging.h"
38 #include "ppapi/c/ppb_var_dictionary.h"
39 #include "ppapi/c/ppb_var_array.h"
40
41 extern int nit_main(int, char**);
42
43 const PPB_Messaging* g_varMessagingInterface;
44 const PPB_Var* g_varInterface;
45 const PPB_VarDictionary* g_varDictionaryInterface;
46 const PPB_VarArray* g_varArrayInterface;
47
48 PP_Instance g_instance;
49 PnaclApp app;
50
51 /* Posts a string message to JS. */
52 void PostMessage(char* message) {
53 /* Create PP_Var containing the message body. */
54 struct PP_Var varString = g_varInterface->VarFromUtf8(message, strlen(message));
55
56 /* Post message to the JavaScript layer. */
57 g_varMessagingInterface->PostMessage(g_instance, varString);
58 }
59
60 /* Posts a Dictionary (JS like object) to JS. */
61 void PostDictionary(struct PP_Var dictionary) {
62 g_varMessagingInterface->PostMessage(g_instance, dictionary);
63 }
64
65 /* Posts a Variable (aka PepperVar) to JS.
66 Should only be used for testing, conventional conversation is made
67 with Strings or Dictionaries. */
68 void PostVar(struct PP_Var v) {
69 g_varMessagingInterface->PostMessage(g_instance, v);
70 }
71
72 static PP_Bool Instance_DidCreate(PP_Instance instance, uint32_t argc, const char* argn[], const char* argv[]) {
73 g_instance = instance;
74 nit_main(0, NULL);
75 return PP_TRUE;
76 }
77
78 static void Instance_DidDestroy(PP_Instance instance) {
79 // TODO
80 }
81
82 static void Instance_DidChangeView(PP_Instance pp_instance, PP_Resource view) {
83 // TODO
84 }
85
86 static void Instance_DidChangeFocus(PP_Instance pp_instance, PP_Bool has_focus) {
87 // TODO
88 }
89
90 static PP_Bool Instance_HandleDocumentLoad(PP_Instance pp_instance, PP_Resource pp_url_loader) {
91 // TODO
92 return PP_FALSE;
93 }
94
95 /* char* to PP_Var. */
96 static struct PP_Var CStrToVar(const char* str) {
97 if (g_varInterface != NULL) {
98 return g_varInterface->VarFromUtf8(str, strlen(str));
99 }
100 return PP_MakeUndefined();
101 }
102
103 /* Called when JS sends something, is set to accept Strings or Dictionaries,
104 returns an error if received object is not a String or Dictionary. */
105 void Messaging_HandleMessage(PP_Instance instance, struct PP_Var varMessage) {
106 if(varMessage.type == PP_VARTYPE_DICTIONARY) {
107 PnaclApp_handle_dictionary(app, &varMessage);
108 }
109 else if(varMessage.type == PP_VARTYPE_STRING) {
110 uint32_t len;
111 char* message = (char*)g_varInterface->VarToUtf8(varMessage, &len);
112 PnaclApp_handle_message(app, NativeString_to_s_with_length(message, len));
113 }
114 else {
115 struct PP_Var errorMessage = CStrToVar("TypeError : only accepts JS objects or Strings");
116 g_varMessagingInterface->PostMessage(g_instance, errorMessage);
117 }
118 }
119
120 /* Entry point */
121 PP_EXPORT int32_t PPP_InitializeModule(PP_Module module_id, PPB_GetInterface get_browser_interface) {
122 /* Initializing global pointers */
123 g_varMessagingInterface = (const PPB_Messaging*) get_browser_interface(PPB_MESSAGING_INTERFACE);
124 g_varInterface = (const PPB_Var*) get_browser_interface(PPB_VAR_INTERFACE);
125 g_varDictionaryInterface = (const PPB_VarDictionary*) get_browser_interface(PPB_VAR_DICTIONARY_INTERFACE);
126 g_varArrayInterface = (const PPB_VarArray*) get_browser_interface(PPB_VAR_ARRAY_INTERFACE);
127 return PP_OK;
128 }
129
130 PP_EXPORT void PPP_ShutdownModule() {
131 // TODO
132 }
133
134 PP_EXPORT const void* PPP_GetInterface(const char* interface_name) {
135 if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0)
136 {
137 static PPP_Instance instance_interface = {
138 &Instance_DidCreate,
139 &Instance_DidDestroy,
140 &Instance_DidChangeView,
141 &Instance_DidChangeFocus,
142 &Instance_HandleDocumentLoad
143 };
144 return &instance_interface;
145 }
146 else if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0) {
147 static PPP_Messaging messaging_interface = {
148 &Messaging_HandleMessage
149 };
150 return &messaging_interface;
151 }
152 return NULL;
153 }
154
155 // Hack poll
156 int poll(void *fds, int nfds, int timeout) { return 0; }
157 `}
158
159 # Nit class representing a Pepper C API PP_Var typed as a Dictionary.
160 extern class PepperDictionary `{ struct PP_Var* `}
161
162 new `{
163 struct PP_Var* recv = malloc( sizeof( struct PP_Var ) );
164 *recv = g_varDictionaryInterface->Create();
165 return recv;
166 `}
167
168 # Get fonction using PepperVars.
169 #
170 # Returns the value that is associated with 'key'.
171 # If 'key' is not a String typed PepperVar, or doesn't exist in the Dictionary, an undefined PepperVar is returned.
172 fun native_get(key: PepperVar): PepperVar `{
173 struct PP_Var* value = malloc( sizeof ( struct PP_Var ) );
174 *value = g_varDictionaryInterface->Get(*recv, *key);
175 return value;
176 `}
177
178 # Returns the value associated with 'key'.
179 #
180 # 'key' must be a String.
181 # If 'key' is not a String or doesn't exist in the Dictionary, 'null' is returned.
182 fun [](key: nullable Pepperable): nullable Pepperable
183 do
184 var native_key = key.to_pepper
185 var native_value = native_get(native_key)
186 return native_value.to_nit
187 end
188
189 # Set function using PepperVars.
190 #
191 # Sets the value associated with the specified key.
192 # 'key' must be a String typed PepperVar.
193 # If 'key' hasn't existed in the Dictionary, it is added and associated with 'value'.
194 # Otherwise, the previous value is replaced with 'value'.
195 # Returns a Boolean indicating whether the operation succeeds.
196 fun native_set(key: PepperVar, value: PepperVar): Bool `{
197 PP_Bool b;
198 b = g_varDictionaryInterface->Set(*recv, *key, *value);
199 return b;
200 `}
201
202 # Sets the value associated with the specified key.
203 #
204 # 'key' must be a String.
205 # If 'key' hasn't existed in the Dictionary, it is added and associated with 'value'.
206 # Otherwise, the previous value is replaced with 'value'.
207 # Returns a Boolean indicating whether the operation succeeds.
208 fun []=(key: nullable Pepperable, value: nullable Pepperable): Bool
209 do
210 var native_key = key.to_pepper
211 var native_value = value.to_pepper
212 return native_set(native_key, native_value)
213 end
214
215 # Deletes the specified key and its associated value, if the key exists.
216 #
217 # Takes a String typed PepperVar.
218 fun native_delete(key: PepperVar) `{
219 g_varDictionaryInterface->Delete(*recv, *key);
220 `}
221
222 # Deletes the specified key and its associated value, if the key exists.
223 #
224 # Takes a String.
225 fun delete(key: String)
226 do
227 var native_key = key.to_pepper
228 native_delete native_key
229 end
230
231 # Checks whether a key exists.
232 #
233 # Takes a String typed PepperVar.
234 fun native_has_key(key: PepperVar): Bool `{
235 PP_Bool b;
236 b = g_varDictionaryInterface->HasKey(*recv, *key);
237 return b;
238 `}
239
240 # Checks whether a key exists.
241 #
242 # Takes a String.
243 fun has_key(key: String): Bool
244 do
245 var native_key = key.to_pepper
246 return native_has_key(native_key)
247 end
248
249 # Gets all the keys in a dictionary.
250 #
251 # Returns a PepperArray which contains all the keys of the Dictionary. The elements are string vars.
252 fun get_keys: PepperArray `{
253 struct PP_Var* array = malloc( sizeof( struct PP_Var ) );
254 *array = g_varDictionaryInterface->GetKeys(*recv);
255 return array;
256 `}
257
258 # Use this function to copy a dictionary.
259 fun copy: PepperDictionary `{
260 struct PP_Var* varDictionary = malloc( sizeof( struct PP_Var ) );
261 *varDictionary = g_varDictionaryInterface->Create();
262 *varDictionary = *recv;
263 return varDictionary;
264 `}
265 end
266
267 # Nit class representing a Pepper C API PP_Var typed as an Array.
268 extern class PepperArray `{ struct PP_Var* `}
269
270 new `{
271 struct PP_Var* recv = malloc( sizeof( struct PP_Var ) );
272 *recv = g_varArrayInterface->Create();
273 return recv;
274 `}
275
276 # Returns the element at the specified position as a PepperVar.
277 #
278 # If 'index' is larger than or equal to the array length, an undefined PepperVar is returned.
279 fun native_get(index: Int): PepperVar `{
280 struct PP_Var* value = malloc( sizeof( struct PP_Var ) );
281 *value = g_varArrayInterface->Get(*recv, index);
282 return value;
283 `}
284
285 # Returns the element at the specified position.
286 #
287 # If 'index' is larger than or equal to the array length, 'null' is returned.
288 fun [](index: Int): nullable Pepperable
289 do
290 var native_value = native_get(index)
291 return native_value.to_nit
292 end
293
294 # Returns an int containing the length of the PepperArray.
295 fun length: Int `{
296 int length = g_varArrayInterface->GetLength(*recv);
297 return length;
298 `}
299
300 # Takes a PepperVar for the 'value' param.
301 #
302 # Sets the value of an element in the array at indicated index.
303 # If 'index' is larger than or equal to the array length, the length is updated to be 'index' + 1.
304 # Any position in the array that hasn't been set before is set to undefined, i.e., PepperVar of C type PP_VARTYPE_UNDEFINED.
305 # Returns a Boolean indicating whether the operation succeeds.
306 fun native_set(index: Int, value: PepperVar): Bool `{
307 PP_Bool b;
308 b = g_varArrayInterface->Set(*recv, index, *value);
309 return b;
310 `}
311
312 # Sets the value of an element in the array at indicated index.
313 #
314 # If 'index' is larger than or equal to the array length, the length is updated to be 'index' + 1.
315 # Any position in the array that hasn't been set before is set to undefined, i.e., PepperVar of C type PP_VARTYPE_UNDEFINED.
316 # Returns a Boolean indicating whether the operation succeeds.
317 fun []=(index: Int, value: nullable Pepperable): Bool
318 do
319 var native_value = value.to_pepper
320 return native_set(index, native_value)
321 end
322
323 # Sets the array length.
324 #
325 # If 'length' is smaller than its current value, the array is truncated to the new length.
326 # Any elements that no longer fit are removed and the references to them will be released.
327 # If 'length' is larger than its current value, undefined PepperVars are appended to increase the array to the specified length.
328 # Returns a Boolean indicating whether the operation succeeds.
329 fun length=(length: Int): Bool `{
330 PP_Bool b;
331 b = g_varArrayInterface->SetLength(*recv, length);
332 return b;
333 `}
334 end
335
336 # Nit class representing a Pepper C API PP_Var.
337 extern class PepperVar `{ struct PP_Var* `}
338
339 new `{
340 return malloc( sizeof( struct PP_Var ) );
341 `}
342
343 # Converts PepperVar to standard types.
344 #
345 # Actually supports bools, ints, floats, strings. To be used with 'isa'.
346 fun to_nit: nullable Pepperable
347 do
348 if isa_null then return null
349 if isa_bool then return as_bool
350 if isa_int then return as_int
351 if isa_float then return as_float
352 if isa_string then return as_string
353 if is_undefined then return null
354
355 return null
356 end
357
358 private fun isa_null: Bool `{ return recv->type == PP_VARTYPE_NULL; `}
359 private fun isa_bool: Bool `{ return recv->type == PP_VARTYPE_BOOL; `}
360 private fun isa_int: Bool `{ return recv->type == PP_VARTYPE_INT32; `}
361 private fun isa_float: Bool `{ return recv->type == PP_VARTYPE_DOUBLE; `}
362 private fun isa_string: Bool `{ return recv->type == PP_VARTYPE_STRING; `}
363 private fun is_undefined: Bool `{ return recv->type == PP_VARTYPE_UNDEFINED; `}
364
365 private fun as_bool: Bool `{ return recv->value.as_bool; `}
366 private fun as_int: Int `{ return recv->value.as_int; `}
367 private fun as_float: Float `{ return recv->value.as_double; `}
368 private fun as_string: String import NativeString.to_s_with_length `{
369 uint32_t len;
370 char* str = (char*)g_varInterface->VarToUtf8(*recv, &len);
371 return NativeString_to_s_with_length(str, len);
372 `}
373 end
374
375 # Provides a method to convert in PepperVars.
376 interface Pepperable
377 fun to_pepper: PepperVar is abstract
378 end
379
380 redef class Int
381 super Pepperable
382
383 # Converts a Int into a PepperVar with Int type.
384 redef fun to_pepper `{
385 struct PP_Var* var = malloc( sizeof( struct PP_Var ) );
386 *var = PP_MakeInt32(recv);
387 return var;
388 `}
389 end
390
391 redef class Float
392 super Pepperable
393
394 # Converts a Float into a PepperVar with Float type.
395 redef fun to_pepper `{
396 struct PP_Var* var = malloc( sizeof( struct PP_Var ) );
397 *var = PP_MakeDouble(recv);
398 return var;
399 `}
400 end
401
402 redef class Bool
403 super Pepperable
404
405 # Converts a Bool into a PepperVar with Bool type.
406 redef fun to_pepper `{
407 struct PP_Var* var = malloc( sizeof( struct PP_Var ) );
408 *var = PP_MakeBool(recv);
409 return var;
410 `}
411 end
412
413 redef class String
414 super Pepperable
415
416 # Converts a String into a PepperVar with String type.
417 redef fun to_pepper: PepperVar import String.to_cstring, String.length `{
418 char *str = String_to_cstring(recv);
419 struct PP_Var* var = malloc( sizeof( struct PP_Var ) );
420 *var = g_varInterface->VarFromUtf8(str, String_length(recv));
421 return var;
422 `}
423 end
424
425 # Class that provides the tools to interact with PNaCl.
426 class PnaclApp
427
428 # Sets everything up to work, need to be called at first.
429 fun initialize import PnaclApp.handle_message, PnaclApp.handle_dictionary, NativeString.to_s_with_length `{
430 app = recv;
431 `}
432
433 # Posts a message to JS.
434 fun post_message(message: String) import String.to_cstring `{
435 char* str = String_to_cstring(message);
436 PostMessage(str);
437 `}
438
439 # Posts a dictionary to JS.
440 fun post_dictionary(dictionary: PepperDictionary) `{
441 PostDictionary(*dictionary);
442 `}
443
444 # Posts a PepperVar to JS.
445 #
446 # Should be used for testing, not recommanded for conventional conversation.
447 private fun post_var(v: PepperVar) `{
448 PostVar(*v);
449 `}
450
451 # Is called when a message is received from JS.
452 #
453 # Is set to be redefined in your application to handle like you want.
454 fun handle_message(message: String)
455 do
456 # To be Implemented by user.
457 end
458
459 # Is called when a Dictionary is received from JS.
460 #
461 # Is set to be redefined in your application to handle like you want.
462 # The dictionary is freed after this method returns.
463 fun handle_dictionary(dictionary: PepperDictionary)
464 do
465 # To be Implemented by user.
466 end
467 end