forked from kanaka/mal
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstep3_env.pas
More file actions
173 lines (160 loc) Β· 4.25 KB
/
step3_env.pas
File metadata and controls
173 lines (160 loc) Β· 4.25 KB
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
program Mal;
{$H+} // Use AnsiString
Uses sysutils,
CMem,
fgl,
mal_readline,
mal_types,
mal_func,
reader,
printer,
mal_env;
var
Repl_Env : TEnv;
Line : string;
// read
function READ(const Str: string) : TMal;
begin
READ := read_str(Str);
end;
// eval
// Forward declation since eval_ast call it
function EVAL(Ast: TMal; Env: TEnv) : TMal; forward;
function eval_ast(Ast: TMal; Env: TEnv) : TMal;
var
OldArr, NewArr : TMalArray;
OldDict, NewDict : TMalDict;
I : longint;
begin
if Ast is TMalSymbol then
begin
eval_ast := Env.Get((Ast as TMalSymbol));
end
else if Ast is TMalList then
begin
OldArr := (Ast as TMalList).Val;
SetLength(NewArr, Length(OldArr));
for I := 0 to Length(OldArr)-1 do
begin
NewArr[I] := EVAL(OldArr[I], Env);
end;
if Ast is TMalVector then
eval_ast := TMalVector.Create(NewArr)
else
eval_ast := TMalList.Create(NewArr);
end
else if Ast is TMalHashMap then
begin
OldDict := (Ast as TMalHashMap).Val;
NewDict := TMalDict.Create;
I := 0;
while I < OldDict.Count do
begin
NewDict[OldDict.Keys[I]] := EVAL(OldDict[OldDict.Keys[I]], Env);
I := I + 1;
end;
eval_ast := TMalHashMap.Create(NewDict);
end
else
eval_ast := Ast;
end;
function EVAL(Ast: TMal; Env: TEnv) : TMal;
var
Arr : TMalArray;
Arr1 : TMalArray;
A0Sym : string;
LetEnv : TEnv;
I : longint;
Fn : TMalCallable;
begin
if Ast.ClassType <> TMalList then
Exit(eval_ast(Ast, Env));
// Apply list
Arr := (Ast as TMalList).Val;
if Length(Arr) = 0 then
Exit(Ast);
if Arr[0] is TMalSymbol then
A0Sym := (Arr[0] as TMalSymbol).Val
else
A0Sym := '__<*fn*>__';
case A0Sym of
'def!':
EVAL := Env.Add((Arr[1] as TMalSymbol), EVAL(Arr[2], ENV));
'let*':
begin
LetEnv := TEnv.Create(Env);
Arr1 := (Arr[1] as TMalList).Val;
I := 0;
while I < Length(Arr1) do
begin
LetEnv.Add((Arr1[I] as TMalSymbol), EVAL(Arr1[I+1], LetEnv));
Inc(I,2);
end;
EVAL := EVAL(Arr[2], LetEnv);
end;
else
begin
Arr := (eval_ast(Ast, Env) as TMalList).Val;
if Arr[0] is TMalFunc then
begin
Fn := (Arr[0] as TMalFunc).Val;
EVAL := Fn(copy(Arr, 1, Length(Arr)-1));
end
else
raise Exception.Create('invalid apply');
end;
end;
end;
// print
function PRINT(Exp: TMal) : string;
begin
PRINT := pr_str(Exp, True);
end;
// repl
function REP(Str: string) : string;
begin
REP := PRINT(EVAL(READ(Str), Repl_Env));
end;
function add(Args: TMalArray) : TMal;
begin
add := TMalInt.Create((Args[0] as TMalInt).Val +
(Args[1] as TMalInt).Val);
end;
function subtract(Args: TMalArray) : TMal;
begin
subtract := TMalInt.Create((Args[0] as TMalInt).Val -
(Args[1] as TMalInt).Val);
end;
function multiply(Args: TMalArray) : TMal;
begin
multiply := TMalInt.Create((Args[0] as TMalInt).Val *
(Args[1] as TMalInt).Val);
end;
function divide(Args: TMalArray) : TMal;
begin
divide := TMalInt.Create((Args[0] as TMalInt).Val div
(Args[1] as TMalInt).Val);
end;
begin
Repl_Env := TEnv.Create;
Repl_Env.Add(TMalSymbol.Create('+'), TMalFunc.Create(@add));
Repl_Env.Add(TMalSymbol.Create('-'), TMalFunc.Create(@subtract));
Repl_Env.Add(TMalSymbol.Create('*'), TMalFunc.Create(@multiply));
Repl_Env.Add(TMalSymbol.Create('/'), TMalFunc.Create(@divide));
while True do
begin
try
Line := _readline('user> ');
if Line = '' then continue;
WriteLn(REP(Line))
except
On E : MalEOF do Halt(0);
On E : Exception do
begin
WriteLn('Error: ' + E.message);
WriteLn('Backtrace:');
WriteLn(GetBacktrace(E));
end;
end;
end;
end.