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