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