emncd.html 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>NCD in Javascript</title>
  5. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  6. </head>
  7. <body>
  8. <script src="emncd.js"></script>
  9. <script>
  10. var cfunc_emncd_start = Module.cwrap('emncd_start', 'null', ['string']);
  11. var cfunc_emncd_stop = Module.cwrap('emncd_stop', 'null', []);
  12. function on_start ()
  13. {
  14. var code = document.getElementById('codetext').value;
  15. var loglevel = 0;
  16. for (i = 0; i <= 5; i++) {
  17. if (document.getElementById('loglevel' + i).checked) {
  18. loglevel = i;
  19. }
  20. }
  21. cfunc_emncd_start(code, loglevel);
  22. }
  23. function on_stop ()
  24. {
  25. cfunc_emncd_stop();
  26. }
  27. function load_example (num)
  28. {
  29. document.getElementById('codetext').value = document.getElementById('example' + num).value;
  30. }
  31. </script>
  32. This is a quick port of my <a href="http://code.google.com/p/badvpn/wiki/NCD">NCD programming language</a>
  33. to Javascript using the <a href="https://github.com/kripken/emscripten">Emscripten</a> compiler.
  34. <br />
  35. Please open the Javascript console so you can see the output (Chrome: CTRL+Shift+J. Firefox: CTRL+Shift+K).
  36. <br />
  37. <textarea id="example1" style="display:none;">
  38. process hello {
  39. println("hello, world");
  40. exit("0");
  41. }
  42. </textarea>
  43. <textarea id="example2" style="display:none;">
  44. process foo {
  45. println("Starting up, please wait...");
  46. rprintln("Goodbye World!");
  47. sleep("500", "300"); # sleeps 500ms on init and 300ms on deinit
  48. println("Hello World!");
  49. rprintln("Shutting down, please wait...");
  50. }
  51. </textarea>
  52. <textarea id="example3" style="display:none;">
  53. process hello {
  54. var("0") ctr;
  55. blocker() blk;
  56. blk->up();
  57. blk->use();
  58. num_modulo(ctr, "3") m_three;
  59. num_modulo(ctr, "5") m_five;
  60. num_equal(m_three, "0") d_three;
  61. num_equal(m_five, "0") d_five;
  62. and(d_three, d_five) d_three_five;
  63. If (d_three_five) {
  64. var("fizzbuzz") text;
  65. } Elif (d_three) {
  66. var("fizz") text;
  67. } Elif (d_five) {
  68. var("buzz") text;
  69. } else {
  70. var(ctr) text;
  71. } branch;
  72. println(branch.text);
  73. num_add(ctr, "1") i;
  74. num_modulo(i, "20") i;
  75. ctr->set(i);
  76. sleep("100", "0");
  77. blk->downup();
  78. }
  79. </textarea>
  80. <textarea id="example4" style="display:none;">
  81. process main {
  82. var({"0", "1", "3", "2", "2", "3", "1", "1", "6", "end"}) list;
  83. value(["1":"one", "2":"two", "3":"three"]) map;
  84. call("replace", {"_caller.list", "_caller.map"}) replace;
  85. to_string(replace.result) str;
  86. println(str);
  87. exit("0");
  88. }
  89. template replace {
  90. alias(_arg0) list;
  91. alias(_arg1) map;
  92. value({}) new_list;
  93. Foreach (list As elem) {
  94. map->try_get(elem) y;
  95. If (y.exists) {
  96. new_list->insert(new_list.length, y);
  97. } Else {
  98. new_list->insert(new_list.length, elem);
  99. };
  100. };
  101. alias("new_list") result;
  102. }
  103. </textarea>
  104. <textarea id="example5" style="display:none;">
  105. process hello {
  106. println("Hello, NCD in Javascript!");
  107. println("Will now wait 2 seconds.");
  108. rprintln("Goodbye.");
  109. sleep("2000", "3000");
  110. rprintln("Waiting 3 seconds before dying.");
  111. call("func", {"FirstArg", "SecondArg"});
  112. var({"one", "two", "three"}) list;
  113. to_string(list) str;
  114. println(str);
  115. Foreach (list As elem) {
  116. println("start ", elem);
  117. rprintln("stop ", elem);
  118. };
  119. println("We're finished. Press \"Request termination\" to unwind us.");
  120. rprintln("Terminating...");
  121. }
  122. template func {
  123. println("func here, my args are: ", _arg0, " ", _arg1);
  124. rprintln("func going away");
  125. }
  126. </textarea>
  127. <textarea id="example6" style="display:none;">
  128. process main {
  129. # Turing machine specification.
  130. var("B") blank;
  131. var([
  132. {"0", "0"}:{"0", "0", "right"},
  133. {"0", "1"}:{"1", "x", "right"},
  134. {"1", "1"}:{"1", "1", "right"},
  135. {"1", "0"}:{"2", "0", "right"},
  136. {"2", "0"}:{"2", "0", "right"},
  137. {"2", "1"}:{"3", "1", "right"},
  138. {"3", "1"}:{"3", "1", "right"},
  139. {"3", "0"}:{"4", "1", "left"},
  140. {"3", "B"}:{"4", "1", "left"},
  141. {"4", "1"}:{"4", "1", "left"},
  142. {"4", "0"}:{"5", "0", "left"},
  143. {"5", "0"}:{"5", "0", "left"},
  144. {"5", "1"}:{"6", "1", "left"},
  145. {"5", "x"}:{"h", "x", "stay"},
  146. {"6", "1"}:{"6", "1", "left"},
  147. {"6", "x"}:{"0", "x", "right"},
  148. {"6", "0"}:{"0", "0", "right"}
  149. ]) rules;
  150. var("0") initial_state;
  151. var({}) initial_tape_left;
  152. var({
  153. "1", "1", "1", "1", "0", "0", "1", "1", "1", "1"
  154. }) initial_tape_right;
  155. # Perform the computation, stopping when no rule matches.
  156. call("turing", {blank, rules, initial_state, initial_tape_left, initial_tape_right}) results;
  157. # Print results.
  158. to_string(results.tape_left) tape_left;
  159. to_string(results.tape_right) tape_right;
  160. to_string({results.side, results.pos}) head_pos;
  161. to_string(results.state) head_state;
  162. println("Tape L: ", tape_left);
  163. println("Tape R: ", tape_right);
  164. println("Head position: ", head_pos);
  165. println("Head state: ", head_state);
  166. exit("0");
  167. }
  168. template turing {
  169. alias("_arg0") blank;
  170. value(_arg1) rules;
  171. alias("_arg2") initial_state;
  172. alias("_arg3") initial_tape_left;
  173. alias("_arg4") initial_tape_right;
  174. # Head state.
  175. var(initial_state) state;
  176. # Tape. Positions go like this: ... L2 L1 L0 R0 R1 R2 ...
  177. value(initial_tape_left) tape_left;
  178. value(initial_tape_right) tape_right;
  179. # Make sure each side of the tape has at least one symbol so we can flip easily.
  180. tape_left->insert(tape_left.length, blank);
  181. tape_right->insert(tape_right.length, blank);
  182. # Head position.
  183. var("right") side;
  184. var("0") pos;
  185. # Enter loop.
  186. blocker() loop_blk;
  187. loop_blk->up();
  188. loop_blk->use();
  189. # Get symbol under head.
  190. concat("tape_", side) tape_name;
  191. alias(tape_name) cur_tape;
  192. cur_tape->get(pos) symbol;
  193. # Look for a matching rule.
  194. rules->try_get({state, symbol}) rule;
  195. If (rule.exists) {
  196. # Extract directions from rule.
  197. rule->get("0") new_state;
  198. rule->get("1") new_symbol;
  199. rule->get("2") move;
  200. # Change head state.
  201. state->set(new_state);
  202. # Replace symbol under head.
  203. cur_tape->remove(pos);
  204. cur_tape->insert(pos, new_symbol);
  205. # Branch based on how we move.
  206. strcmp(move, side) is_outside;
  207. strcmp(move, "stay") is_stay;
  208. strcmp(pos, "0") is_zero;
  209. If (is_outside) {
  210. # Increment position.
  211. num_add(pos, "1") new_pos;
  212. pos->set(new_pos);
  213. # If the new position is out of range, extend tape.
  214. strcmp(pos, cur_tape.length) need_extend;
  215. If (need_extend) {
  216. cur_tape->insert(pos, blank);
  217. };
  218. } elif (is_stay) {
  219. # Nop.
  220. getargs();
  221. } elif (is_zero) {
  222. # Flip side, leave pos at zero.
  223. side->set(move);
  224. } else {
  225. # Decrement position.
  226. num_subtract(pos, "1") new_pos;
  227. pos->set(new_pos);
  228. };
  229. # Continue loop.
  230. loop_blk->downup();
  231. };
  232. }
  233. </textarea>
  234. Examples:
  235. <button onclick="load_example(1)">Hello World</button>
  236. <button onclick="load_example(2)">Sleep</button>
  237. <button onclick="load_example(3)">FizzBuzz</button>
  238. <button onclick="load_example(4)">Replace</button>
  239. <button onclick="load_example(5)">Foreach, call</button>
  240. <button onclick="load_example(6)">Turing Machine</button>
  241. <br />
  242. <textarea rows=30 cols=80 id="codetext">
  243. process hello {
  244. println("hello, world");
  245. exit("0");
  246. }
  247. </textarea>
  248. <br />
  249. Loglevel:
  250. <input type="radio" name="loglevel" id="loglevel0"> None
  251. <input type="radio" name="loglevel" id="loglevel1"> Error
  252. <input type="radio" name="loglevel" id="loglevel2" checked> Warning
  253. <input type="radio" name="loglevel" id="loglevel3"> Notice
  254. <input type="radio" name="loglevel" id="loglevel4"> Info
  255. <input type="radio" name="loglevel" id="loglevel5"> Debug <br />
  256. <button onclick="on_start()">Start NCD</button>
  257. <button onclick="on_stop()">Request termination</button>
  258. <br />
  259. Note: if you get the interpreter stuck and unable to terminate, just refresh the page
  260. </body>
  261. </html>