10From [Julien Beasley](https://github.com/zass30/Nock5KCSharp):
14using System.Collections.Generic;
17using System.Text.RegularExpressions;
19namespace NockInterpreter
23 static Dictionary<string, Noun> memocache = new Dictionary<string, Noun>();
25 public static Noun Nock(Noun noun)
29 if (memocache.TryGetValue(noun.ToString(), out cache_noun))
34 if (Atom.IsAtom(noun))
35 throw new Exception("Infinite loop nocking an atom: " + noun.ToString());
38 Noun subject = noun.n1;
39 if (Noun.IsCell(noun.n2))
41 Cell formula = (Cell)noun.n2;
42 if (Noun.IsAtom(formula.n1)) // we have lines 25-37 of spec
44 Atom op = (Atom)formula.n1;
45 Noun operands = formula.n2;
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))
58 Noun a = Nock(subject, operands.n1);
59 Noun b = Nock(subject, operands.n2);
60 noun = Noun.CreateNoun(a, b);
62 // return Nock(Nock(subject, operands.n1), Nock(subject, operands.n2));
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))
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 + "]");
82 // return Nock(Noun.CreateNoun("[" + subject + " 2 [0 1] 2 [1 " + c + " " + d + "] [1 0] 2 [1 2 3] [1 0] 4 4 " + b + "]"));
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))
90 noun = Noun.CreateNoun("[" + subject + " 2 " + b + " 1 " + c + "]");
92 // return Nock(Noun.CreateNoun("[" + subject + " 2 " + b + " 1 " + c + "]"));
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))
100 noun = Noun.CreateNoun("[" + subject + " 7 [[7 [0 1] " + b + "] 0 1] " + c + "]");
102 // return Nock(Noun.CreateNoun("[" + subject + " 7 [[7 [0 1] " + b + "] 0 1] " + c + "]"));
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))
108 Noun b = operands.n1;
109 Noun c = operands.n2;
110 noun = Noun.CreateNoun("[" + subject + " 7 " + c + " 2 [0 1] 0 " + b + "]");
112 // return Nock(Noun.CreateNoun("[" + subject + " 7 " + c + " 2 [0 1] 0 " + b + "]"));
114 throw new Exception("Atom after operand 9: " + operands.ToString());
116 if (Noun.IsCell(operands))
118 if (Noun.IsCell(operands.n1)) // 36 :: *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
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 + "]");
125 // return Nock(Noun.CreateNoun("[" + subject + " 8 " + c + " 7 [0 3] " + d + "]"));
127 else // 37 :: *[a 10 b c] *[a c]
129 Noun c = operands.n2;
130 noun = Noun.CreateNoun(subject, c);
132 // return Nock(subject, c);
135 throw new Exception("Atom after operand 10: " + operands.ToString());
137 throw new Exception("Unknown operand: " + op.value);
140 else // 23 :: *[a [b c] d] [*[a b c] *[a d]]
142 memocache[noun.ToString()] = Noun.CreateNoun(Nock(subject, formula.n1), Nock(subject, formula.n2));
143 return memocache[noun.ToString()];
147 throw new Exception("Unhandled pattern");
150 public static Noun Nock(string program)
152 Noun noun = Noun.CreateNoun(program);
156 public static Noun Nock(Noun n1, Noun n2)
158 Noun noun = Noun.CreateNoun(n1, n2);
162 private static Noun tis(Noun noun)
164 if (Noun.IsAtom(noun.ToString()))
165 throw new Exception("Infinite loop tising an atom: " + noun.ToString());
168 Cell cell = (Cell)noun;
170 if (cell.n1.ToString() == cell.n2.ToString())
171 return Noun.CreateNoun("0");
173 return Noun.CreateNoun("1");
177 private static Noun lus(Noun noun)
179 if (Noun.IsAtom(noun.ToString()))
183 return Noun.CreateNoun(v.ToString());
186 throw new Exception("Infinite loop lusing a cell: " + noun.ToString());
189 private static Noun wut(Noun noun)
191 if (Noun.IsAtom(noun.ToString()))
192 return Noun.CreateNoun("1");
194 return Noun.CreateNoun("0");
197 private static Noun fas(Noun n1, Noun n2)
199 Noun noun = Noun.CreateNoun(n1, n2);
203 private static Noun fas(Noun noun)
205 if (Noun.IsAtom(noun.ToString()))
206 throw new Exception("Infinite loop fasing an atom: " + noun.ToString());
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());
218 else if (a.value >= 2)
220 if (!Noun.IsCell(c.n2.ToString()))
222 throw new Exception("Only a cell can have an axis of 2 or 3: " + c.n2.ToString());
226 Cell c2 = (Cell)c.n2;
229 else if (a.value == 3)
231 else if (a.value % 2 == 0)
233 int half = a.value / 2;
234 return fas(Noun.CreateNoun("2", fas(Noun.CreateNoun(half.ToString(), c2))));
236 else if (a.value % 2 == 1)
238 int half = a.value / 2;
239 return fas(Noun.CreateNoun("3", fas(Noun.CreateNoun(half.ToString(), c2))));
243 throw new Exception("Infinite loop somewhere in fasing: " + c.n2.ToString());
248 throw new Exception("Infinite loop somewhere in fasing: " + c.n2.ToString());
258 // takes a program, returns a pair of nouns, stringified.
259 public static Tuple<string, string> SplitCell(string program)
264 // split the string right after the first space
265 foreach (char c in program)
275 // if we see a space, and our stack count is at 1, then we've found our split point
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))
284 Tuple<string, string> tuple = new Tuple<string, string>(a, b);
290 throw new Exception("Invalid char in cell: " + c);
293 throw new Exception("Invalid cell: " + program);
296 public static bool IsCell(string program)
298 // check if cell is valid, as above but make sure no space after bracket
299 // valid tokens are: space, 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.
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)
321 if (!(c == '[' || IsInt(c)))
326 if (!(IsInt(c) || c == ' ' || c == ']'))
331 if (!(c == ']' || c == ' '))
336 if (!(c == '[' || IsInt(c)))
345 if (i <= 0 && counter != program.Length) // stack count can't be zero unless it's the last character
349 // We should end with stack count of zero
356 public static bool IsInt(char c)
373 public static bool IsValidChar(char c)
384 public static bool IsAtom(string program)
387 if (int.TryParse(program, out i))
395 public static bool IsAtom(Noun noun)
397 return IsAtom(noun.ToString());
400 public static bool IsCell(Noun noun)
402 return IsCell(noun.ToString());
405 public static Noun CreateNoun(string program)
408 return new Atom(program);
410 return new Cell(program);
413 public static Noun CreateNoun(Noun n1, Noun n2)
415 return CreateNoun("[" + n1.ToString() + " " + n2.ToString() + "]");
418 public static Noun CreateNoun(string p1, Noun n2)
420 return CreateNoun("[" + p1 + " " + n2.ToString() + "]");
423 public static Noun CreateNoun(Noun n1, string p2)
425 return CreateNoun("[" + n1.ToString() + " " + p2 + "]");
428 public static Noun CreateNoun(string p1, string p2)
430 return CreateNoun("[" + p1 + " " + p2 + "]");
438 public override string ToString()
440 return value.ToString();
443 public Atom(string program)
448 bool result = int.TryParse(program, out i);
452 throw new ArgumentException("Invalid Atom: " + program);
460 public override string ToString()
462 return "[" + n1.ToString() + " " + n2.ToString() + "]";
465 public Cell(string program)
469 Tuple<string, string> split = SplitCell(program);
470 n1 = CreateNoun(split.Item1);
471 n2 = CreateNoun(split.Item2);
474 throw new ArgumentException("Invalid Cell: " + program);
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list