on c674887 help sign in
476 lines 20 kB history raw
1---
2navhome: '/docs/'
3next: True
4sort: 12
5title: 'C\#'
6---
8# C
10From [Julien Beasley](https://github.com/zass30/Nock5KCSharp):
12 using System;
13 using System.Collections.Generic;
14 using System.Linq;
15 using System.Text;
16 using System.Text.RegularExpressions;
18 namespace NockInterpreter
19 {
20 class Interpreter
21 {
22 static Dictionary<string, Noun> memocache = new Dictionary<string, Noun>();
24 public static Noun Nock(Noun noun)
25 {
26 Start:
27 Noun cache_noun;
28 if (memocache.TryGetValue(noun.ToString(), out cache_noun))
29 {
30 return cache_noun;
31 }
33 if (Atom.IsAtom(noun))
34 throw new Exception("Infinite loop nocking an atom: " + noun.ToString());
35 else
36 {
37 Noun subject = noun.n1;
38 if (Noun.IsCell(noun.n2))
39 {
40 Cell formula = (Cell)noun.n2;
41 if (Noun.IsAtom(formula.n1)) // we have lines 25-37 of spec
42 {
43 Atom op = (Atom)formula.n1;
44 Noun operands = formula.n2;
46 switch (op.value)
47 {
48 case 0: // 25 :: *[a 0 b] /[b a]
49 memocache[noun.ToString()] = fas(operands, subject);
50 return memocache[noun.ToString()];
51 case 1: // 26 :: *[a 1 b] b
52 memocache[noun.ToString()] = operands;
53 return memocache[noun.ToString()];
54 case 2: // 27 :: *[a 2 b c] *[*[a b] *[a c]]
55 if (Noun.IsCell(operands))
56 {
57 Noun a = Nock(subject, operands.n1);
58 Noun b = Nock(subject, operands.n2);
59 noun = Noun.CreateNoun(a, b);
60 goto Start;
61 // return Nock(Nock(subject, operands.n1), Nock(subject, operands.n2));
62 }
63 throw new Exception("Atom after operand 2: " + operands.ToString());
64 case 3: // 28 :: *[a 3 b] ?*[a b]
65 memocache[noun.ToString()] = wut(Nock(subject, operands));
66 return memocache[noun.ToString()];
67 case 4: // 29 :: *[a 4 b] +*[a b]
68 memocache[noun.ToString()] = lus(Nock(subject, operands));
69 return memocache[noun.ToString()];
70 case 5: // 30 :: *[a 5 b] =*[a b]
71 memocache[noun.ToString()] = tis(Nock(subject, operands));
72 return memocache[noun.ToString()];
73 case 6: // 32 :: *[a 6 b c d] *[a 2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]
74 if (Noun.IsCell(operands) && Noun.IsCell(operands.n2))
75 {
76 Noun b = operands.n1;
77 Noun c = operands.n2.n1;
78 Noun d = operands.n2.n2;
79 noun = Noun.CreateNoun("[" + subject + " 2 [0 1] 2 [1 " + c + " " + d + "] [1 0] 2 [1 2 3] [1 0] 4 4 " + b + "]");
80 goto Start;
81 // return Nock(Noun.CreateNoun("[" + subject + " 2 [0 1] 2 [1 " + c + " " + d + "] [1 0] 2 [1 2 3] [1 0] 4 4 " + b + "]"));
82 }
83 throw new Exception("Unhandled pattern for operand 6");
84 case 7: // 33 :: *[a 7 b c] *[a 2 b 1 c]
85 if (Noun.IsCell(operands))
86 {
87 Noun b = operands.n1;
88 Noun c = operands.n2;
89 noun = Noun.CreateNoun("[" + subject + " 2 " + b + " 1 " + c + "]");
90 goto Start;
91 // return Nock(Noun.CreateNoun("[" + subject + " 2 " + b + " 1 " + c + "]"));
92 }
93 throw new Exception("Atom after operand 7: " + operands.ToString());
94 case 8: // 34 :: *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
95 if (Noun.IsCell(operands))
96 {
97 Noun b = operands.n1;
98 Noun c = operands.n2;
99 noun = Noun.CreateNoun("[" + subject + " 7 [[7 [0 1] " + b + "] 0 1] " + c + "]");
100 goto Start;
101 // return Nock(Noun.CreateNoun("[" + subject + " 7 [[7 [0 1] " + b + "] 0 1] " + c + "]"));
102 }
103 throw new Exception("Atom after operand 8: " + operands.ToString());
104 case 9: // 35 :: *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
105 if (Noun.IsCell(operands))
106 {
107 Noun b = operands.n1;
108 Noun c = operands.n2;
109 noun = Noun.CreateNoun("[" + subject + " 7 " + c + " 2 [0 1] 0 " + b + "]");
110 goto Start;
111 // return Nock(Noun.CreateNoun("[" + subject + " 7 " + c + " 2 [0 1] 0 " + b + "]"));
112 }
113 throw new Exception("Atom after operand 9: " + operands.ToString());
114 case 10:
115 if (Noun.IsCell(operands))
116 {
117 if (Noun.IsCell(operands.n1)) // 36 :: *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
118 {
119 Noun b = operands.n1.n1;
120 Noun c = operands.n1.n2;
121 Noun d = operands.n2;
122 noun = Noun.CreateNoun("[" + subject + " 8 " + c + " 7 [0 3] " + d + "]");
123 goto Start;
124 // return Nock(Noun.CreateNoun("[" + subject + " 8 " + c + " 7 [0 3] " + d + "]"));
125 }
126 else // 37 :: *[a 10 b c] *[a c]
127 {
128 Noun c = operands.n2;
129 noun = Noun.CreateNoun(subject, c);
130 goto Start;
131 // return Nock(subject, c);
132 }
133 }
134 throw new Exception("Atom after operand 10: " + operands.ToString());
135 default:
136 throw new Exception("Unknown operand: " + op.value);
137 }
138 }
139 else // 23 :: *[a [b c] d] [*[a b c] *[a d]]
140 {
141 memocache[noun.ToString()] = Noun.CreateNoun(Nock(subject, formula.n1), Nock(subject, formula.n2));
142 return memocache[noun.ToString()];
143 }
144 }
145 }
146 throw new Exception("Unhandled pattern");
147 }
149 public static Noun Nock(string program)
150 {
151 Noun noun = Noun.CreateNoun(program);
152 return Nock(noun);
153 }
155 public static Noun Nock(Noun n1, Noun n2)
156 {
157 Noun noun = Noun.CreateNoun(n1, n2);
158 return Nock(noun);
159 }
161 private static Noun tis(Noun noun)
162 {
163 if (Noun.IsAtom(noun.ToString()))
164 throw new Exception("Infinite loop tising an atom: " + noun.ToString());
165 else
166 {
167 Cell cell = (Cell)noun;
169 if (cell.n1.ToString() == cell.n2.ToString())
170 return Noun.CreateNoun("0");
171 else
172 return Noun.CreateNoun("1");
173 }
174 }
176 private static Noun lus(Noun noun)
177 {
178 if (Noun.IsAtom(noun.ToString()))
179 {
180 Atom a = (Atom)noun;
181 int v = a.value + 1;
182 return Noun.CreateNoun(v.ToString());
183 }
184 else
185 throw new Exception("Infinite loop lusing a cell: " + noun.ToString());
186 }
188 private static Noun wut(Noun noun)
189 {
190 if (Noun.IsAtom(noun.ToString()))
191 return Noun.CreateNoun("1");
192 else
193 return Noun.CreateNoun("0");
194 }
196 private static Noun fas(Noun n1, Noun n2)
197 {
198 Noun noun = Noun.CreateNoun(n1, n2);
199 return fas(noun);
200 }
202 private static Noun fas(Noun noun)
203 {
204 if (Noun.IsAtom(noun.ToString()))
205 throw new Exception("Infinite loop fasing an atom: " + noun.ToString());
206 else
207 {
208 Cell c = (Cell)noun;
209 // If n1 isn't an atom, I assume we throw? This isn't defined in the spec. Confirmed by John B by email. This spins forever.
210 if (Noun.IsCell(c.n1.ToString()))
211 throw new Exception("Axis must be an atom: " + c.ToString());
212 else
213 {
214 Atom a = (Atom)c.n1;
215 if (a.value == 1)
216 return c.n2;
217 else if (a.value >= 2)
218 {
219 if (!Noun.IsCell(c.n2.ToString()))
220 {
221 throw new Exception("Only a cell can have an axis of 2 or 3: " + c.n2.ToString());
222 }
223 else
224 {
225 Cell c2 = (Cell)c.n2;
226 if (a.value == 2)
227 return c2.n1;
228 else if (a.value == 3)
229 return c2.n2;
230 else if (a.value % 2 == 0)
231 {
232 int half = a.value / 2;
233 return fas(Noun.CreateNoun("2", fas(Noun.CreateNoun(half.ToString(), c2))));
234 }
235 else if (a.value % 2 == 1)
236 {
237 int half = a.value / 2;
238 return fas(Noun.CreateNoun("3", fas(Noun.CreateNoun(half.ToString(), c2))));
239 }
240 else
241 {
242 throw new Exception("Infinite loop somewhere in fasing: " + c.n2.ToString());
243 }
244 }
245 }
246 }
247 throw new Exception("Infinite loop somewhere in fasing: " + c.n2.ToString());
248 }
249 }
250 }
252 class Noun
253 {
254 public Noun n1;
255 public Noun n2;
257 // takes a program, returns a pair of nouns, stringified.
258 public static Tuple<string, string> SplitCell(string program)
259 {
261 int stackCount = 0;
262 int i = 0;
263 // split the string right after the first space
264 foreach (char c in program)
265 {
266 if (IsValidChar(c))
267 {
268 if (c == '[')
269 stackCount++;
270 else if (c == ']')
271 stackCount--;
272 else if (c == ' ')
273 {
274 // if we see a space, and our stack count is at 1, then we've found our split point
275 if (stackCount == 1)
276 {
277 string a = program.Substring(1, i - 1);
278 string b = program.Substring(i + 1, program.Length - (i + 2));
280 // to implement proper bracket closing, surround b with brackets if it isn't a cell and isn't an atom
281 if (!IsCell(b) && !IsAtom(b))
282 b = "[" + b + "]";
283 Tuple<string, string> tuple = new Tuple<string, string>(a, b);
284 return tuple;
285 }
286 }
287 }
288 else
289 throw new Exception("Invalid char in cell: " + c);
290 i++;
291 }
292 throw new Exception("Invalid cell: " + program);
293 }
295 public static bool IsCell(string program)
296 {
297 // check if cell is valid, as above but make sure no space after bracket
298 // valid tokens are: space, int, [, ]
299 // from [ => [, int
300 // from int => space, ], int
301 // from ] => space, ]
302 // from space => int, [
304 // stack count must always be nonzero
305 // first and last elements must be [ and ]
307 int i = 0; // i is the stack count for brackets.
308 int counter = 0;
309 char s = '\0'; // s is the last seen character
310 // split the string right after the first space
311 foreach (char c in program)
312 {
313 if (s == '\0')
314 {
315 if (c != '[')
316 return false;
317 }
318 else if (s == '[')
319 {
320 if (!(c == '[' || IsInt(c)))
321 return false;
322 }
323 else if (IsInt(s))
324 {
325 if (!(IsInt(c) || c == ' ' || c == ']'))
326 return false;
327 }
328 else if (s == ']')
329 {
330 if (!(c == ']' || c == ' '))
331 return false;
332 }
333 else if (s == ' ')
334 {
335 if (!(c == '[' || IsInt(c)))
336 return false;
337 }
338 s = c;
339 counter++;
340 if (c == '[')
341 i++;
342 else if (c == ']')
343 i--;
344 if (i <= 0 && counter != program.Length) // stack count can't be zero unless it's the last character
345 return false;
346 }
348 // We should end with stack count of zero
349 if (i == 0)
350 return true;
351 else
352 return false;
353 }
355 public static bool IsInt(char c)
356 {
357 if (c == '0' ||
358 c == '1' ||
359 c == '2' ||
360 c == '3' ||
361 c == '4' ||
362 c == '5' ||
363 c == '6' ||
364 c == '7' ||
365 c == '8' ||
366 c == '9')
367 return true;
368 else
369 return false;
370 }
372 public static bool IsValidChar(char c)
373 {
374 if (c == ' ' ||
375 c == '[' ||
376 c == ']' ||
377 IsInt(c))
378 return true;
379 else
380 return false;
381 }
383 public static bool IsAtom(string program)
384 {
385 int i = 0;
386 if (int.TryParse(program, out i))
387 {
388 if (i >= 0)
389 return true;
390 }
391 return false;
392 }
394 public static bool IsAtom(Noun noun)
395 {
396 return IsAtom(noun.ToString());
397 }
399 public static bool IsCell(Noun noun)
400 {
401 return IsCell(noun.ToString());
402 }
404 public static Noun CreateNoun(string program)
405 {
406 if (IsAtom(program))
407 return new Atom(program);
408 else
409 return new Cell(program);
410 }
412 public static Noun CreateNoun(Noun n1, Noun n2)
413 {
414 return CreateNoun("[" + n1.ToString() + " " + n2.ToString() + "]");
415 }
417 public static Noun CreateNoun(string p1, Noun n2)
418 {
419 return CreateNoun("[" + p1 + " " + n2.ToString() + "]");
420 }
422 public static Noun CreateNoun(Noun n1, string p2)
423 {
424 return CreateNoun("[" + n1.ToString() + " " + p2 + "]");
425 }
427 public static Noun CreateNoun(string p1, string p2)
428 {
429 return CreateNoun("[" + p1 + " " + p2 + "]");
430 }
431 }
433 class Atom : Noun
434 {
435 public int value;
437 public override string ToString()
438 {
439 return value.ToString();
440 }
442 public Atom(string program)
443 {
444 if (IsAtom(program))
445 {
446 int i = 0;
447 bool result = int.TryParse(program, out i);
448 value = i;
449 }
450 else
451 throw new ArgumentException("Invalid Atom: " + program);
452 n1 = null;
453 n2 = null;
454 }
455 }
457 class Cell : Noun
458 {
459 public override string ToString()
460 {
461 return "[" + n1.ToString() + " " + n2.ToString() + "]";
462 }
464 public Cell(string program)
465 {
466 if (IsCell(program))
467 {
468 Tuple<string, string> split = SplitCell(program);
469 n1 = CreateNoun(split.Item1);
470 n2 = CreateNoun(split.Item2);
471 }
472 else
473 throw new ArgumentException("Invalid Cell: " + program);
474 }
475 }
476 }