@@ -0,0 +1,478 @@
1+---
2+navhome: /docs
3+title: C#
4+sort: 12
5+next: true
6+---
7+
8+# C#
9+
10+From [Julien Beasley](https://github.com/zass30/Nock5KCSharp):
11+
12+```
13+using System;
14+using System.Collections.Generic;
15+using System.Linq;
16+using System.Text;
17+using System.Text.RegularExpressions;
18+
19+namespace NockInterpreter
20+{
21+ class Interpreter
22+ {
23+ static Dictionary<string, Noun> memocache = new Dictionary<string, Noun>();
24+
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+ }
33+
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;
46+
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+ }
149+
150+ public static Noun Nock(string program)
151+ {
152+ Noun noun = Noun.CreateNoun(program);
153+ return Nock(noun);
154+ }
155+
156+ public static Noun Nock(Noun n1, Noun n2)
157+ {
158+ Noun noun = Noun.CreateNoun(n1, n2);
159+ return Nock(noun);
160+ }
161+
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;
169+
170+ if (cell.n1.ToString() == cell.n2.ToString())
171+ return Noun.CreateNoun("0");
172+ else
173+ return Noun.CreateNoun("1");
174+ }
175+ }
176+
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+ }
188+
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+ }
196+
197+ private static Noun fas(Noun n1, Noun n2)
198+ {
199+ Noun noun = Noun.CreateNoun(n1, n2);
200+ return fas(noun);
201+ }
202+
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+ }
252+
253+ class Noun
254+ {
255+ public Noun n1;
256+ public Noun n2;
257+
258+ // takes a program, returns a pair of nouns, stringified.
259+ public static Tuple<string, string> SplitCell(string program)
260+ {
261+
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));
280+
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+ }
295+
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, [
304+
305+ // stack count must always be nonzero
306+ // first and last elements must be [ and ]
307+
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+ }
348+
349+ // We should end with stack count of zero
350+ if (i == 0)
351+ return true;
352+ else
353+ return false;
354+ }
355+
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+ }
372+
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+ }
383+
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+ }
394+
395+ public static bool IsAtom(Noun noun)
396+ {
397+ return IsAtom(noun.ToString());
398+ }
399+
400+ public static bool IsCell(Noun noun)
401+ {
402+ return IsCell(noun.ToString());
403+ }
404+
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+ }
412+
413+ public static Noun CreateNoun(Noun n1, Noun n2)
414+ {
415+ return CreateNoun("[" + n1.ToString() + " " + n2.ToString() + "]");
416+ }
417+
418+ public static Noun CreateNoun(string p1, Noun n2)
419+ {
420+ return CreateNoun("[" + p1 + " " + n2.ToString() + "]");
421+ }
422+
423+ public static Noun CreateNoun(Noun n1, string p2)
424+ {
425+ return CreateNoun("[" + n1.ToString() + " " + p2 + "]");
426+ }
427+
428+ public static Noun CreateNoun(string p1, string p2)
429+ {
430+ return CreateNoun("[" + p1 + " " + p2 + "]");
431+ }
432+ }
433+
434+ class Atom : Noun
435+ {
436+ public int value;
437+
438+ public override string ToString()
439+ {
440+ return value.ToString();
441+ }
442+
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+ }
457+
458+ class Cell : Noun
459+ {
460+ public override string ToString()
461+ {
462+ return "[" + n1.ToString() + " " + n2.ToString() + "]";
463+ }
464+
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+ }
477+}
478+```