-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathStandardLibrary.cs
150 lines (127 loc) · 4.78 KB
/
StandardLibrary.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Lisp {
public class StandardLibrary {
/// <summary>
/// This creates a new context and populates it with the 7 core callables, and the "defun" macro
/// </summary>
public static Context NewContext() {
var context = new Context();
context.Variables["quote"] = new Quote();
context.Variables["atom"] = new Atom();
context.Variables["eq"] = new Eq();
context.Variables["car"] = new Car();
context.Variables["cdr"] = new Cdr();
context.Variables["cons"] = new Cons();
context.Variables["cond"] = new Cond();
context.Variables["defun"] = new Defun();
return context;
}
}
public class Quote : Macro {
/// <summary>
/// Return the argument unevaluated
/// </summary>
public override LispObject Call(Context context, List<LispObject> args) {
if (args.Count != 1) {
throw new LispException("quote expects exactly one argument");
}
return args[0];
}
}
public class Eq : Function {
/// <summary>
/// Return whether or not both arguments are symbols and have the same value
/// </summary>
public override LispObject Call(Context context, List<LispObject> args) {
if (args.Count != 2) {
throw new LispException("eq expects exactly two arguments");
}
var one = args[0] as Symbol;
var two = args[1] as Symbol;
if (one == null && two == null) {
return LispObject.T;
}
return LispObject.FromBool(one != null && two != null && one.Value == two.Value);
}
}
public class Atom : Function {
/// <summary>
/// Return true if the argument is not a list
/// </summary>
public override LispObject Call(Context context, List<LispObject> args) {
if (args.Count != 1) {
throw new LispException("atom expects exactly one argument");
}
return LispObject.FromBool((args[0] as Cell) == null);
}
}
public class Car : Function {
/// <summary>
/// Return return the "car" property of a cons
/// </summary>
public override LispObject Call(Context context, List<LispObject> args) {
if (args.Count != 1) {
throw new LispException("car expects exactly one argument");
}
return (args[0] as Cell).Car;
}
}
public class Cdr : Function {
/// <summary>
/// Return return the "cdr" property of a cons
/// </summary>
public override LispObject Call(Context context, List<LispObject> args) {
if (args.Count != 1) {
throw new LispException("cdr expects exactly one argument");
}
return (args[0] as Cell).Cdr;
}
}
public class Cons : Function {
/// <summary>
/// Create a cell with the car and cdr set from the arguments
/// </summary>
public override LispObject Call(Context context, List<LispObject> args) {
if (args.Count != 2) {
throw new LispException("cons expects exactly two arguments");
}
return new Cell(args[0], args[1]);
}
}
public class Cond : Macro {
/// <summary>
/// Execute a sequence of predicates until one is true, and then execute the associated body
/// </summary>
public override LispObject Call(Context context, List<LispObject> args) {
foreach (Cell arg in args) {
var predicate = arg.Car;
var result = arg.Cadr;
if (LispObject.ToBool(context.Evaluate(predicate))) {
return context.Evaluate(result);
}
}
return null;
}
}
public class Defun : Macro {
/// <summary>
/// Create a lambda and associate it in the current context with the specified name
/// </summary>
public override LispObject Call(Context context, List<LispObject> args) {
if (args.Count != 3) {
throw new LispException("defun expects exactly three arguments");
}
var name = (args[0] as Symbol).Value;
var arguments = ((Cell)args[1]).Select(arg => ((Symbol)arg).Value)
.ToList();
var body = args[2];
var lambda = new Lambda(arguments, body);
context.Variables[name] = lambda;
return lambda;
}
}
}