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