niti: fix type in tool description
[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 in "C Header" `{
28 #include "ppapi/c/pp_errors.h"
29 #include "ppapi/c/ppp.h"
30 #include "ppapi/c/ppp_instance.h"
31 #include "ppapi/c/pp_bool.h"
32 #include "ppapi/c/ppb_var.h"
33 #include "ppapi/c/ppb_messaging.h"
34 #include "ppapi/c/ppp_messaging.h"
35 #include "ppapi/c/ppb_var_dictionary.h"
36 #include "ppapi/c/ppb_var_array.h"
37 `}
38
39 `{
40 #include <unistd.h>
41 #include <stddef.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <stdlib.h>
45 #include <pthread.h>
46
47 #define MAX_DICTIONARY_QUEUE_SIZE 200
48 #define MAX_MESSAGE_QUEUE_SIZE 10
49
50 extern int nit_main(int, char**);
51
52 /* A working thread for Nit. */
53 static pthread_t g_nit_thread;
54
55 /* Mutex that guards the queues. */
56 static pthread_mutex_t g_dictionary_queue_mutex;
57 static pthread_mutex_t g_message_queue_mutex;
58
59 /* Condition variables that are signalled when the queues are not empty. */
60 static pthread_cond_t g_dictionary_queue_not_empty_cond;
61 static pthread_cond_t g_message_queue_not_empty_cond;
62
63 /** Circular queues of dictionaries and messages from JavaScript to be handled.
64 *
65 * If g_queue_start < g_queue_end:
66 * all elements in the range [g_queue_start, g_queue_end) are valid.
67 * If g_queue_start > g_queue_end:
68 * all elements in the ranges [0, g_queue_end) and
69 * [g_queue_start, MAX_QUEUE_SIZE) are valid.
70 * If g_queue_start == g_queue_end, and g_queue_size > 0:
71 * all elements in the g_queue are valid.
72 * If g_queue_start == g_queue_end, and g_queue_size == 0:
73 * No elements are valid. */
74 static struct PP_Var g_dictionary_queue[MAX_DICTIONARY_QUEUE_SIZE];
75 static char* g_message_queue[MAX_MESSAGE_QUEUE_SIZE];
76
77 /* The index of the head of the queues. */
78 static int g_dictionary_queue_start = 0;
79 static int g_message_queue_start = 0;
80
81 /* The index of the tail of the queues, non-inclusive. */
82 static int g_dictionary_queue_end = 0;
83 static int g_message_queue_end = 0;
84
85 /* The size of the queues. */
86 static int g_dictionary_queue_size = 0;
87 static int g_message_queue_size = 0;
88
89 /* PNaCl interfaces. */
90 const PPB_Messaging* g_varMessagingInterface;
91 const PPB_Var* g_varInterface;
92 const PPB_VarDictionary* g_varDictionaryInterface;
93 const PPB_VarArray* g_varArrayInterface;
94
95 PP_Instance g_instance;
96 PnaclApp app;
97
98 /* A wrapper to launch the Nit main on a new thread. */
99 void* WrapperNitMain(void* arg) {
100 nit_main(0, NULL);
101 return NULL;
102 }
103
104 /** Return whether the queues are empty.
105 *
106 * NOTE: this function assumes g_queue_mutex lock is held.
107 * @return non-zero if the queue is empty. */
108 static int IsDictionaryQueueEmpty() { return g_dictionary_queue_size == 0; }
109 static int IsMessageQueueEmpty() { return g_message_queue_size == 0; }
110
111 /** Return whether the queues are full.
112 *
113 * NOTE: this function assumes g_queue_mutex lock is held.
114 * @return non-zero if the queue is full. */
115 static int IsDictionaryQueueFull() { return g_dictionary_queue_size == MAX_DICTIONARY_QUEUE_SIZE; }
116 static int IsMessageQueueFull() { return g_message_queue_size == MAX_MESSAGE_QUEUE_SIZE; }
117
118 /* Initialize the queues. */
119 void InitializeQueues() {
120 pthread_mutex_init(&g_dictionary_queue_mutex, NULL);
121 pthread_cond_init(&g_dictionary_queue_not_empty_cond, NULL);
122 pthread_mutex_init(&g_message_queue_mutex, NULL);
123 pthread_cond_init(&g_message_queue_not_empty_cond, NULL);
124 }
125
126 /** Enqueue a dictionary (i.e. add to the end)
127 *
128 * If the queue is full, the dictionary will be dropped.
129 *
130 * NOTE: this function assumes g_dictionary_queue_mutex is _NOT_ held.
131 * @param[in] dictionary, the dictionary to enqueue.
132 * @return non-zero if the dictionary was added to the queue. */
133 int EnqueueDictionary(struct PP_Var dictionary) {
134 pthread_mutex_lock(&g_dictionary_queue_mutex);
135
136 /* We shouldn't block the main thread waiting for the queue to not be full,
137 * so just drop the dictionary. */
138 if (IsDictionaryQueueFull()) {
139 pthread_mutex_unlock(&g_dictionary_queue_mutex);
140 return 0;
141 }
142
143 g_dictionary_queue[g_dictionary_queue_end] = dictionary;
144 g_dictionary_queue_end = (g_dictionary_queue_end + 1) % MAX_DICTIONARY_QUEUE_SIZE;
145 g_dictionary_queue_size++;
146
147 pthread_cond_signal(&g_dictionary_queue_not_empty_cond);
148
149 pthread_mutex_unlock(&g_dictionary_queue_mutex);
150
151 return 1;
152 }
153
154 /** Enqueue a message (i.e. add to the end)
155 *
156 * If the queue is full, the message will be dropped.
157 *
158 * NOTE: this function assumes g_message_queue_mutex is _NOT_ held.
159 * @param[in] message The message to enqueue.
160 * @return non-zero if the message was added to the queue. */
161 int EnqueueMessage(char* message) {
162 pthread_mutex_lock(&g_message_queue_mutex);
163
164 /* We shouldn't block the main thread waiting for the queue to not be full,
165 * so just drop the message. */
166 if (IsMessageQueueFull()) {
167 pthread_mutex_unlock(&g_message_queue_mutex);
168 return 0;
169 }
170
171 g_message_queue[g_message_queue_end] = message;
172 g_message_queue_end = (g_message_queue_end + 1) % MAX_MESSAGE_QUEUE_SIZE;
173 g_message_queue_size++;
174
175 pthread_cond_signal(&g_message_queue_not_empty_cond);
176
177 pthread_mutex_unlock(&g_message_queue_mutex);
178
179 return 1;
180 }
181
182 /** Dequeue a dictionary and return it.
183 *
184 * This function blocks until a dictionary is available. It should not be called
185 * on the main thread.
186 *
187 * NOTE: this function assumes g_dictionary_queue_mutex is _NOT_ held.
188 * @return The dictionary at the head of the queue. */
189 struct PP_Var DequeueDictionary() {
190 struct PP_Var dictionary = g_varDictionaryInterface->Create();
191
192 pthread_mutex_lock(&g_dictionary_queue_mutex);
193
194 while (IsDictionaryQueueEmpty()) {
195 pthread_cond_wait(&g_dictionary_queue_not_empty_cond, &g_dictionary_queue_mutex);
196 }
197
198 dictionary = g_dictionary_queue[g_dictionary_queue_start];
199 g_dictionary_queue_start = (g_dictionary_queue_start + 1) % MAX_DICTIONARY_QUEUE_SIZE;
200 g_dictionary_queue_size--;
201
202 pthread_mutex_unlock(&g_dictionary_queue_mutex);
203
204 return dictionary;
205 }
206
207 /** Dequeue a message and return it.
208 *
209 * This function blocks until a message is available. It should not be called
210 * on the main thread.
211 *
212 * NOTE: this function assumes g_queue_mutex is _NOT_ held.
213 * @return The message at the head of the queue. */
214 char* DequeueMessage() {
215 char* message = NULL;
216
217 pthread_mutex_lock(&g_message_queue_mutex);
218
219 while (IsMessageQueueEmpty()) {
220 pthread_cond_wait(&g_message_queue_not_empty_cond, &g_message_queue_mutex);
221 }
222
223 message = g_message_queue[g_message_queue_start];
224 g_message_queue_start = (g_message_queue_start + 1) % MAX_MESSAGE_QUEUE_SIZE;
225 g_message_queue_size--;
226
227 pthread_mutex_unlock(&g_message_queue_mutex);
228
229 return message;
230 }
231
232 /* Posts a string message to JS. */
233 void PostMessage(char* message) {
234 /* Create PP_Var containing the message body. */
235 struct PP_Var varString = g_varInterface->VarFromUtf8(message, strlen(message));
236
237 /* Post message to the JavaScript layer. */
238 g_varMessagingInterface->PostMessage(g_instance, varString);
239 }
240
241 /* Posts a Dictionary (JS like object) to JS. */
242 void PostDictionary(struct PP_Var dictionary) {
243 g_varMessagingInterface->PostMessage(g_instance, dictionary);
244 }
245
246 /* Posts a Variable (aka PepperVar) to JS.
247 Should only be used for testing, conventional conversation is made
248 with Strings or Dictionaries. */
249 void PostVar(struct PP_Var v) {
250 g_varMessagingInterface->PostMessage(g_instance, v);
251 }
252
253 /* char* to PP_Var. */
254 static struct PP_Var CStrToVar(const char* str) {
255 if (g_varInterface != NULL) {
256 return g_varInterface->VarFromUtf8(str, strlen(str));
257 }
258 return PP_MakeUndefined();
259 }
260
261 static PP_Bool Instance_DidCreate(PP_Instance instance, uint32_t argc, const char* argn[], const char* argv[]) {
262 g_instance = instance;
263
264 /* Initialization of the queues and creation of the thread for Nit. */
265 InitializeQueues();
266 pthread_create(&g_nit_thread, NULL, &WrapperNitMain, NULL);
267
268 return PP_TRUE;
269 }
270
271 static void Instance_DidDestroy(PP_Instance instance) {
272 // TODO
273 }
274
275 static void Instance_DidChangeView(PP_Instance pp_instance, PP_Resource view) {
276 // TODO
277 }
278
279 static void Instance_DidChangeFocus(PP_Instance pp_instance, PP_Bool has_focus) {
280 // TODO
281 }
282
283 static PP_Bool Instance_HandleDocumentLoad(PP_Instance pp_instance, PP_Resource pp_url_loader) {
284 // TODO
285 return PP_FALSE;
286 }
287
288 /* Called when JS sends something, is set to accept Strings or Dictionaries,
289 returns an error if received object is not a String or Dictionary. */
290 void Messaging_HandleMessage(PP_Instance instance, struct PP_Var varMessage) {
291 if(varMessage.type == PP_VARTYPE_DICTIONARY) {
292 if(!EnqueueDictionary(varMessage)) {
293 struct PP_Var errorMessage = CStrToVar("QueueFull : dropped dictionary because the queue was full.");
294 g_varMessagingInterface->PostMessage(g_instance, errorMessage);
295 }
296 }
297 else if(varMessage.type == PP_VARTYPE_STRING) {
298 uint32_t len;
299 char* message = (char*)g_varInterface->VarToUtf8(varMessage, &len);
300 if(!EnqueueMessage(message)) {
301 struct PP_Var errorMessage = CStrToVar("QueueFull : dropped message because the queue was full.");
302 g_varMessagingInterface->PostMessage(g_instance, errorMessage);
303 }
304 }
305 else {
306 struct PP_Var errorMessage = CStrToVar("TypeError : only accepts JS objects or Strings");
307 g_varMessagingInterface->PostMessage(g_instance, errorMessage);
308 }
309 }
310
311 /* This function is called by Nit when using check_dictionary,
312 returns the dictionary at the head of the queue. */
313 void* NitHandleDictionary() {
314 struct PP_Var dictionary = DequeueDictionary();
315 PnaclApp_handle_dictionary(app, &dictionary);
316 return 0;
317 }
318
319 /* This function is called By Nit when waiting for a user input. */
320 char* NitHandleMessage() {
321 return DequeueMessage();
322 }
323
324 /* Entry point */
325 PP_EXPORT int32_t PPP_InitializeModule(PP_Module module_id, PPB_GetInterface get_browser_interface) {
326 /* Initializing global pointers. */
327 g_varMessagingInterface = (const PPB_Messaging*) get_browser_interface(PPB_MESSAGING_INTERFACE);
328 g_varInterface = (const PPB_Var*) get_browser_interface(PPB_VAR_INTERFACE);
329 g_varDictionaryInterface = (const PPB_VarDictionary*) get_browser_interface(PPB_VAR_DICTIONARY_INTERFACE);
330 g_varArrayInterface = (const PPB_VarArray*) get_browser_interface(PPB_VAR_ARRAY_INTERFACE);
331 return PP_OK;
332 }
333
334 PP_EXPORT void PPP_ShutdownModule() {
335 // TODO
336 }
337
338 PP_EXPORT const void* PPP_GetInterface(const char* interface_name) {
339 if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0)
340 {
341 static PPP_Instance instance_interface = {
342 &Instance_DidCreate,
343 &Instance_DidDestroy,
344 &Instance_DidChangeView,
345 &Instance_DidChangeFocus,
346 &Instance_HandleDocumentLoad
347 };
348 return &instance_interface;
349 }
350 else if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0) {
351 static PPP_Messaging messaging_interface = {
352 &Messaging_HandleMessage
353 };
354 return &messaging_interface;
355 }
356 return NULL;
357 }
358
359 /* Hack in order to avoid the problem with file. */
360 int poll(void *fds, int nfds, int timeout) { return 0; }
361 `}
362
363 # Nit class representing a Pepper C API PP_Var typed as a Dictionary.
364 extern class PepperDictionary `{ struct PP_Var* `}
365
366 new `{
367 struct PP_Var* recv = malloc( sizeof( struct PP_Var ) );
368 *recv = g_varDictionaryInterface->Create();
369 return recv;
370 `}
371
372 # Get fonction using PepperVars.
373 #
374 # Returns the value that is associated with 'key'.
375 # If 'key' is not a String typed PepperVar, or doesn't exist in the Dictionary, an undefined PepperVar is returned.
376 fun native_get(key: PepperVar): PepperVar `{
377 struct PP_Var* value = malloc( sizeof ( struct PP_Var ) );
378 *value = g_varDictionaryInterface->Get(*recv, *key);
379 return value;
380 `}
381
382 # Returns the value associated with 'key'.
383 #
384 # 'key' must be a String.
385 # If 'key' is not a String or doesn't exist in the Dictionary, 'null' is returned.
386 fun [](key: nullable Pepperable): nullable Pepperable
387 do
388 var native_key = key.to_pepper
389 var native_value = native_get(native_key)
390 return native_value.to_nit
391 end
392
393 # Set function using PepperVars.
394 #
395 # Sets the value associated with the specified key.
396 # 'key' must be a String typed PepperVar.
397 # If 'key' hasn't existed in the Dictionary, it is added and associated with 'value'.
398 # Otherwise, the previous value is replaced with 'value'.
399 # Returns a Boolean indicating whether the operation succeeds.
400 fun native_set(key: PepperVar, value: PepperVar): Bool `{
401 PP_Bool b;
402 b = g_varDictionaryInterface->Set(*recv, *key, *value);
403 return b;
404 `}
405
406 # Sets the value associated with the specified key.
407 #
408 # 'key' must be a String.
409 # If 'key' hasn't existed in the Dictionary, it is added and associated with 'value'.
410 # Otherwise, the previous value is replaced with 'value'.
411 # Returns a Boolean indicating whether the operation succeeds.
412 fun []=(key: nullable Pepperable, value: nullable Pepperable): Bool
413 do
414 var native_key = key.to_pepper
415 var native_value = value.to_pepper
416 return native_set(native_key, native_value)
417 end
418
419 # Deletes the specified key and its associated value, if the key exists.
420 #
421 # Takes a String typed PepperVar.
422 fun native_delete(key: PepperVar) `{
423 g_varDictionaryInterface->Delete(*recv, *key);
424 `}
425
426 # Deletes the specified key and its associated value, if the key exists.
427 #
428 # Takes a String.
429 fun delete(key: String)
430 do
431 var native_key = key.to_pepper
432 native_delete native_key
433 end
434
435 # Checks whether a key exists.
436 #
437 # Takes a String typed PepperVar.
438 fun native_has_key(key: PepperVar): Bool `{
439 PP_Bool b;
440 b = g_varDictionaryInterface->HasKey(*recv, *key);
441 return b;
442 `}
443
444 # Checks whether a key exists.
445 #
446 # Takes a String.
447 fun has_key(key: String): Bool
448 do
449 var native_key = key.to_pepper
450 return native_has_key(native_key)
451 end
452
453 # Gets all the keys in a dictionary.
454 #
455 # Returns a PepperArray which contains all the keys of the Dictionary. The elements are string vars.
456 fun get_keys: PepperArray `{
457 struct PP_Var* array = malloc( sizeof( struct PP_Var ) );
458 *array = g_varDictionaryInterface->GetKeys(*recv);
459 return array;
460 `}
461
462 # Use this function to copy a dictionary.
463 fun copy: PepperDictionary `{
464 struct PP_Var* varDictionary = malloc( sizeof( struct PP_Var ) );
465 *varDictionary = g_varDictionaryInterface->Create();
466 *varDictionary = *recv;
467 return varDictionary;
468 `}
469 end
470
471 # Nit class representing a Pepper C API PP_Var typed as an Array.
472 extern class PepperArray `{ struct PP_Var* `}
473
474 new `{
475 struct PP_Var* recv = malloc( sizeof( struct PP_Var ) );
476 *recv = g_varArrayInterface->Create();
477 return recv;
478 `}
479
480 # Returns the element at the specified position as a PepperVar.
481 #
482 # If 'index' is larger than or equal to the array length, an undefined PepperVar is returned.
483 fun native_get(index: Int): PepperVar `{
484 struct PP_Var* value = malloc( sizeof( struct PP_Var ) );
485 *value = g_varArrayInterface->Get(*recv, index);
486 return value;
487 `}
488
489 # Returns the element at the specified position.
490 #
491 # If 'index' is larger than or equal to the array length, 'null' is returned.
492 fun [](index: Int): nullable Pepperable
493 do
494 var native_value = native_get(index)
495 return native_value.to_nit
496 end
497
498 # Returns an int containing the length of the PepperArray.
499 fun length: Int `{
500 int length = g_varArrayInterface->GetLength(*recv);
501 return length;
502 `}
503
504 # Takes a PepperVar for the 'value' param.
505 #
506 # Sets the value of an element in the array at indicated index.
507 # If 'index' is larger than or equal to the array length, the length is updated to be 'index' + 1.
508 # Any position in the array that hasn't been set before is set to undefined, i.e., PepperVar of C type PP_VARTYPE_UNDEFINED.
509 # Returns a Boolean indicating whether the operation succeeds.
510 fun native_set(index: Int, value: PepperVar): Bool `{
511 PP_Bool b;
512 b = g_varArrayInterface->Set(*recv, index, *value);
513 return b;
514 `}
515
516 # Sets the value of an element in the array at indicated index.
517 #
518 # If 'index' is larger than or equal to the array length, the length is updated to be 'index' + 1.
519 # Any position in the array that hasn't been set before is set to undefined, i.e., PepperVar of C type PP_VARTYPE_UNDEFINED.
520 # Returns a Boolean indicating whether the operation succeeds.
521 fun []=(index: Int, value: nullable Pepperable): Bool
522 do
523 var native_value = value.to_pepper
524 return native_set(index, native_value)
525 end
526
527 # Sets the array length.
528 #
529 # If 'length' is smaller than its current value, the array is truncated to the new length.
530 # Any elements that no longer fit are removed and the references to them will be released.
531 # If 'length' is larger than its current value, undefined PepperVars are appended to increase the array to the specified length.
532 # Returns a Boolean indicating whether the operation succeeds.
533 fun length=(length: Int): Bool `{
534 PP_Bool b;
535 b = g_varArrayInterface->SetLength(*recv, length);
536 return b;
537 `}
538 end
539
540 # Nit class representing a Pepper C API PP_Var.
541 extern class PepperVar `{ struct PP_Var* `}
542
543 new `{
544 return malloc( sizeof( struct PP_Var ) );
545 `}
546
547 # Converts PepperVar to standard types.
548 #
549 # Actually supports bools, ints, floats, strings. To be used with 'isa'.
550 fun to_nit: nullable Pepperable
551 do
552 if isa_null then return null
553 if isa_bool then return as_bool
554 if isa_int then return as_int
555 if isa_float then return as_float
556 if isa_string then return as_string
557 if is_undefined then return null
558
559 return null
560 end
561
562 private fun isa_null: Bool `{ return recv->type == PP_VARTYPE_NULL; `}
563 private fun isa_bool: Bool `{ return recv->type == PP_VARTYPE_BOOL; `}
564 private fun isa_int: Bool `{ return recv->type == PP_VARTYPE_INT32; `}
565 private fun isa_float: Bool `{ return recv->type == PP_VARTYPE_DOUBLE; `}
566 private fun isa_string: Bool `{ return recv->type == PP_VARTYPE_STRING; `}
567 private fun is_undefined: Bool `{ return recv->type == PP_VARTYPE_UNDEFINED; `}
568
569 private fun as_bool: Bool `{ return recv->value.as_bool; `}
570 private fun as_int: Int `{ return recv->value.as_int; `}
571 private fun as_float: Float `{ return recv->value.as_double; `}
572 private fun as_string: String import NativeString.to_s_with_length `{
573 uint32_t len;
574 char* str = (char*)g_varInterface->VarToUtf8(*recv, &len);
575 return NativeString_to_s_with_length(str, len);
576 `}
577 end
578
579 # Provides a method to convert in PepperVars.
580 interface Pepperable
581 fun to_pepper: PepperVar is abstract
582 end
583
584 redef class Int
585 super Pepperable
586
587 # Converts a Int into a PepperVar with Int type.
588 redef fun to_pepper `{
589 struct PP_Var* var = malloc( sizeof( struct PP_Var ) );
590 *var = PP_MakeInt32(recv);
591 return var;
592 `}
593 end
594
595 redef class Float
596 super Pepperable
597
598 # Converts a Float into a PepperVar with Float type.
599 redef fun to_pepper `{
600 struct PP_Var* var = malloc( sizeof( struct PP_Var ) );
601 *var = PP_MakeDouble(recv);
602 return var;
603 `}
604 end
605
606 redef class Bool
607 super Pepperable
608
609 # Converts a Bool into a PepperVar with Bool type.
610 redef fun to_pepper `{
611 struct PP_Var* var = malloc( sizeof( struct PP_Var ) );
612 *var = PP_MakeBool(recv);
613 return var;
614 `}
615 end
616
617 redef class String
618 super Pepperable
619
620 # Converts a String into a PepperVar with String type.
621 redef fun to_pepper: PepperVar import String.to_cstring, String.length `{
622 char *str = String_to_cstring(recv);
623 struct PP_Var* var = malloc( sizeof( struct PP_Var ) );
624 *var = g_varInterface->VarFromUtf8(str, String_length(recv));
625 return var;
626 `}
627 end
628
629 # A stream for PNaCl, redefines basic input and output methods.
630 class PnaclStream
631 super PollableIStream
632 super OStream
633 super BufferedIStream
634
635 init do prepare_buffer(10)
636
637 redef var end_reached: Bool = false
638
639 redef fun eof do return end_reached
640
641 # Redefintion of 'write' to send messages to the browser.
642 redef fun write(s: Text) do app.post_message s.to_s
643
644 redef fun is_writable: Bool do return true
645
646 # Checks if there is a message in the queue, and if so the message is handled automatically.
647 fun check_message: NativeString `{
648 return NitHandleMessage();
649 `}
650
651 # fill_buffer now checks for a message in the message queue which is filled by user inputs.
652 redef fun fill_buffer
653 do
654 _buffer.clear
655 _buffer_pos = 0
656 _buffer.append check_message.to_s
657 end
658 end
659
660 # For a PNaCl app, Sys uses PnaclStreams.
661 redef class Sys
662 fun pnacl_stdstr: PnaclStream do return once new PnaclStream
663
664 # NaCl input.
665 redef fun stdin do return pnacl_stdstr
666
667 # NaCl output.
668 redef fun stdout do return pnacl_stdstr
669
670 # NaCl output for errors.
671 redef fun stderr do return pnacl_stdstr
672 end
673
674 # Class that provides the tools to interact with PNaCl.
675 class PnaclApp
676
677 # Sets everything up to work, need to be called at first.
678 fun initialize import PnaclApp.handle_message, PnaclApp.handle_dictionary, NativeString.to_s_with_length `{
679 app = recv;
680 `}
681
682 # Posts a message to JS.
683 fun post_message(message: String) import String.to_cstring `{
684 char* str = String_to_cstring(message);
685 PostMessage(str);
686 `}
687
688 # Posts a dictionary to JS.
689 fun post_dictionary(dictionary: PepperDictionary) `{
690 PostDictionary(*dictionary);
691 `}
692
693 # Posts a PepperVar to JS.
694 #
695 # Should be used for testing, not recommanded for conventional conversation.
696 private fun post_var(v: PepperVar) `{
697 PostVar(*v);
698 `}
699
700 # Is called when a message is received from JS.
701 #
702 # Is set to be redefined in your application to handle like you want.
703 fun handle_message(message: String)
704 do
705 # To be Implemented by user.
706 end
707
708 # Is called when a Dictionary is received from JS.
709 #
710 # Is set to be redefined in your application to handle like you want.
711 # The dictionary is freed after this method returns.
712 fun handle_dictionary(dictionary: PepperDictionary)
713 do
714 # To be Implemented by user.
715 end
716
717 # Checks if there is a dictionary in the queue, and if so the dictionary is handled automatically.
718 fun check_dictionary `{
719 NitHandleDictionary();
720 `}
721
722 # Infinite loop on check_dictionary
723 fun run
724 do
725 loop
726 check_dictionary
727 end
728 end
729 end
730
731 # Creates a new thread for Nit.
732 #
733 # This function launches the Nit main on a new thread.
734 # Its purpose is to allow Nit to be still operational after an exit when needed,
735 # because reloading the page may not be an option.
736 #
737 # Should only be used within the 'exit' before stopping the current thread
738 # when the Nit execution causes a crash.
739 #
740 # REQUIRE: g_nit_thread and WrapperNitMain are set.
741 fun create_thread `{
742 pthread_create(&g_nit_thread, NULL, &WrapperNitMain, NULL);
743 `}
744
745 # Calls 'pthread_exit on current thread.
746 fun exit_thread(exit_value: Int) `{
747 pthread_exit((void*) exit_value);
748 `}
749
750 # Redef of exit in order to avoid the module to crash by terminating only the Nit thread.
751 redef fun exit(exit_value: Int)
752 do
753 var dictionary = new PepperDictionary
754 dictionary["exit"] = exit_value
755 app.post_dictionary dictionary
756 exit_thread exit_value
757 end
758
759 fun app: PnaclApp do return once new PnaclApp