-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinterp.pl
180 lines (150 loc) · 5.64 KB
/
interp.pl
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
174
175
176
177
178
179
180
:- ensure_loaded(lexer).
:- ensure_loaded(parser).
:- ensure_loaded(helpers).
:- ensure_loaded(env_helpers).
arity_mismatch(Fun, closure(RealFunName, ArgNames, _), Args) :-
length(ArgNames, Expected),
length(Args, Got),
any_list_concat(["Arity mismatch while calling ", Fun, " (real name ", RealFunName, "). Function expected ", Expected, " arguments, got ", Got, "."], Msg),
writeln(Msg),
throw(arity_mismatch(Fun, Msg)).
evalExpr(integer(N), _, N).
evalExpr(ident(N), Env, Val) :-
getVar(Env, (N, Val)).
evalExpr(ident(I, SubExpr), Env, Val) :-
evalExpr(SubExpr, Env, Sub),
getVar(Env, (I, Arr)),
catch(arr_get(Arr, Sub, Val), "List too short!", throw(("Array", I, Sub, "too short!"))),
!.
evalExpr(call("read", []), Env, Val) :-
read_line_to_string(user_input, Str),
atom_number(Str, X),
evalExpr(integer(X), Env, Val),
!.
evalExpr(call(Fun, ArgExprs), Env, Val) :-
parallelEval(ArgExprs, evalExpr, Env, Args),
getVar(Env, (Fun, closure(RealFunName, ArgNames, Body))),
(same_length(Args, ArgNames); arity_mismatch(Fun, closure(RealFunName, ArgNames, Body), Args)),
!,
callArgs(ArgNames, Args, CallArgs),
createCall(Env, Env1, CallArgs),
createVar(Env1, Env2, (RealFunName, closure(RealFunName, ArgNames, Body))),
evalProg(Body, Env2, Env3),
checkReturnValue(Env3, Val),
destroyCall(Env3, Env),
!.
evalExpr(arith_op(Op, Arg1, Arg2), Env, Val) :-
evalExpr(Arg1, Env, Val1),
evalExpr(Arg2, Env, Val2),
Expr =.. [Op, Val1, Val2],
call(is, Val, Expr).
evalLog(logic_op(and, Arg1, Arg2), Env, Val) :- !,
evalLog(Arg1, Env, Val1),
evalLog(Arg2, Env, Val2),
((Val1 = true, Val2 = true) -> (Val = true, !); Val = false).
evalLog(logic_op(or, Arg1, Arg2), Env, Val) :- !,
evalLog(Arg1, Env, Val1),
evalLog(Arg2, Env, Val2),
((Val1 = true; Val2 = true) -> (Val = true, !); Val = false).
evalLog(logic_op(not, Arg), Env, Val) :-
evalLog(Arg, Env, Val),
((Val = true) -> (Val = false, !); Val = true).
evalLog(rel_op(=, Arg1, Arg2), Env, Val) :- !,
evalExpr(Arg1, Env, Val1),
evalExpr(Arg2, Env, Val2),
(Val1 == Val2 -> (Val = true, !); Val = false).
evalLog(rel_op(<>, Arg1, Arg2), Env, Val) :- !,
evalExpr(Arg1, Env, Val1),
evalExpr(Arg2, Env, Val2),
((\+ Val1 == Val2) -> (Val = true, !); Val = false).
evalLog(rel_op(<=, Arg1, Arg2), Env, Val) :- !,
evalExpr(Arg1, Env, Val1),
evalExpr(Arg2, Env, Val2),
(Val1 =< Val2 -> (Val = true, !); Val = false).
evalLog(rel_op(Op, Arg1, Arg2), Env, Val) :-
evalExpr(Arg1, Env, Val1),
evalExpr(Arg2, Env, Val2),
(call(Op, Val1, Val2) -> (Val = true, !); Val = false).
evalProg([], Env, Env) :- !.
evalProg([S|Ss], Env, EnvOut) :-
evalProg(S, Env, Env1),
!,
(
(didReturnValue(Env1), !, EnvOut = Env1);
evalProg(Ss, Env1, EnvOut)).
evalProg(def(I, arith(Expr)), Mem, MemOut) :-
!,
evalExpr(Expr, Mem, Val),
createVar(Mem, MemOut, (I, Val)).
evalProg(def(I, array(LengthExpr, ArrayExprs)), Mem, MemOut) :-
!,
evalExpr(LengthExpr, Mem, Length),
parallelEval(ArrayExprs, evalExpr, Mem, ArrayVals),
length(Val, Length),
repeatingList(Val, ArrayVals),
createVar(Mem, MemOut, (I, array(Length, Val))).
evalProg(def(I, fun(ArgNames, Body)), Mem, MemOut) :-
createVar(Mem, MemOut, (I, closure(I, ArgNames, Body))).
evalProg(assignment(I, Expr), Mem, MemOut) :-
evalExpr(Expr, Mem, Val),
setVar(Mem, MemOut, (I, Val)).
evalProg(assignment(I, SubExpr, ValExpr), Mem, MemOut) :-
parallelEval([ValExpr, SubExpr], evalExpr, Mem, [Val, Sub]),
getVar(Mem, (I, Arr)),
catch(arr_set(Arr, Sub, Val, NewArr), "List too short!", throw(("Array", I, Sub, "too short!"))),
!,
setVar(Mem, MemOut, (I, NewArr)).
evalProg(if(Cond, Then), Mem, MemOut) :-
evalLog(Cond, Mem, CondVal),
evalIf(CondVal, if(Cond, Then, []), Mem, MemOut).
evalProg(if(Cond, Then, Else), Mem, MemOut) :-
evalLog(Cond, Mem, CondVal),
evalIf(CondVal, if(Cond, Then, Else), Mem, MemOut).
evalProg(while(Cond, Body), Mem, MemOut) :-
evalLog(Cond, Mem, CondVal),
whileEval(CondVal, while(Cond, Body), Mem, MemOut).
evalProg(call("return", [ReturnExpr]), Env, Env1) :-
!,
evalExpr(ReturnExpr, Env, Val),
returnValue(Env, Env1, Val).
evalProg(call("return", _), _, _) :-
throw(arity_mismatch("Return expects exactly one argument!")).
evalProg(call("print", [string(Expr)]), Env, Env) :-
!,
any_list_concat(["[> ", Expr], Msg),
writeln(Msg).
evalProg(call("print", [Expr]), Env, Env) :-
!,
evalExpr(Expr, Env, Val),
any_list_concat(["[> ", Val], Msg),
writeln(Msg).
evalProg(call("env", []), Env, Env) :-
!,
prettyEnv(Env, PrettyEnv),
writeln(PrettyEnv).
evalProg(call(Fun, ArgExprs), Mem, Mem) :-
evalExpr(call(Fun, ArgExprs), Mem, _).
callArgs(Names, Values, CallArgs) :-
zip(Names, Values, CallArgs).
evalIf(true, if(_, Then, _), Mem, MemOut) :-
createNamedScope(Mem, Mem1, "if"),
evalProg(Then, Mem1, Mem2),
destroyScope(Mem2, MemOut).
evalIf(false, if(_, _, Else), Mem, MemOut) :-
createNamedScope(Mem, Mem1, "if"),
evalProg(Else, Mem1, Mem2),
destroyScope(Mem2, MemOut).
whileEval(true, while(Cond, Body), Mem, MemOut) :-
createScope(Mem, Mem1),
evalProg(Body, Mem1, Mem2),
destroyScope(Mem2, Mem3),
evalProg(while(Cond, Body), Mem3, MemOut).
whileEval(false, while(_, _), Mem, Mem).
interp(Ast, Memory) :-
initEnv(Env),
((evalProg(Ast, Env, Memory), !); writeln("Interpreter failed unexpectedly.")).
interp_file(Path, Memory) :-
read_file_to_string(Path, Str, []),
lex(Str, Tokens),
parse(Tokens, Ast),
interp(Ast, Memory).