matlab: add step8
[jackhill/mal.git] / matlab / step7_quote.m
CommitLineData
c3023f26
JM
1function step7_quote(varargin), main(varargin), end
2
3% read
4function ret = READ(str)
5 ret = reader.read_str(str);
6end
7
8% eval
9function ret = is_pair(ast)
c4033aab 10 ret = iscell(ast) && length(ast) > 0;
c3023f26
JM
11end
12
13function ret = quasiquote(ast)
14 if ~is_pair(ast)
15 ret = {types.Symbol('quote'), ast};
16 elseif isa(ast{1},'types.Symbol') && ...
17 strcmp(ast{1}.name, 'unquote')
18 ret = ast{2};
19 elseif is_pair(ast{1}) && isa(ast{1}{1},'types.Symbol') && ...
20 strcmp(ast{1}{1}.name, 'splice-unquote')
21 ret = {types.Symbol('concat'), ...
22 ast{1}{2}, ...
23 quasiquote(ast(2:end))};
24 else
25 ret = {types.Symbol('cons'), ...
26 quasiquote(ast{1}), ...
27 quasiquote(ast(2:end))};
28 end
29end
30
31function ret = eval_ast(ast, env)
32 switch class(ast)
33 case 'types.Symbol'
34 ret = env.get(ast);
35 case 'cell'
36 ret = {};
37 for i=1:length(ast)
38 ret{end+1} = EVAL(ast{i}, env);
39 end
40 otherwise
41 ret = ast;
42 end
43end
44
45function ret = EVAL(ast, env)
46 while true
47 if ~iscell(ast)
48 ret = eval_ast(ast, env);
49 return;
50 end
51
52 % apply
53 if isa(ast{1},'types.Symbol')
54 a1sym = ast{1}.name;
55 else
56 a1sym = '_@$fn$@_';
57 end
58 switch (a1sym)
59 case 'def!'
60 ret = env.set(ast{2}, EVAL(ast{3}, env));
61 return;
62 case 'let*'
63 let_env = Env(env);
64 for i=1:2:length(ast{2})
65 let_env.set(ast{2}{i}, EVAL(ast{2}{i+1}, let_env));
66 end
67 env = let_env;
68 ast = ast{3}; % TCO
69 case 'quote'
70 ret = ast{2};
71 return;
72 case 'quasiquote'
73 ast = quasiquote(ast{2}); % TCO
74 case 'do'
75 el = eval_ast(ast(2:end-1), env);
76 ast = ast{end}; % TCO
77 case 'if'
78 cond = EVAL(ast{2}, env);
79 if strcmp(class(cond), 'types.Nil') || ...
80 (islogical(cond) && cond == false)
81 if length(ast) > 3
82 ast = ast{4}; % TCO
83 else
84 ret = types.nil;
85 return;
86 end
87 else
88 ast = ast{3}; % TCO
89 end
90 case 'fn*'
91 fn = @(varargin) EVAL(ast{3}, Env(env, ast{2}, varargin));
92 ret = Function(fn, ast{3}, env, ast{2});
93 return;
94 otherwise
95 el = eval_ast(ast, env);
96 f = el{1};
97 args = el(2:end);
98 if isa(f, 'Function')
99 env = Env(f.env, f.params, args);
100 ast = f.ast; % TCO
101 else
102 ret = f(args{:});
103 return
104 end
105 end
106 end
107end
108
109% print
110function ret = PRINT(ast)
111 ret = printer.pr_str(ast, true);
112end
113
114% REPL
115function ret = rep(str, env)
116 ret = PRINT(EVAL(READ(str), env));
117end
118
119function main(args)
120 repl_env = Env(false);
121
122 % core.m: defined using matlab
123 ns = core.ns(); ks = ns.keys();
124 for i=1:length(ks)
125 k = ks{i};
126 repl_env.set(types.Symbol(k), ns(k));
127 end
128 repl_env.set(types.Symbol('eval'), @(a) EVAL(a, repl_env));
129 repl_env.set(types.Symbol('*ARGV*'), args(2:end));
130
131 % core.mal: defined using the langauge itself
132 rep('(def! not (fn* (a) (if a false true)))', repl_env);
133 rep('(def! load-file (fn* (f) (eval (read-string (str "(do " (slurp f) ")")))))"', repl_env);
134
135 if ~isempty(args)
136 rep(strcat('(load-file "', args{1}, '")'), repl_env);
137 quit;
138 end
139
140 %cleanObj = onCleanup(@() disp('*** here1 ***'));
141 while (true)
142 line = input('user> ', 's');
143 if strcmp(strtrim(line),''), continue, end
144 try
145 fprintf('%s\n', rep(line, repl_env));
146 catch err
147 fprintf('Error: %s\n', err.message);
148 fprintf('%s\n', getReport(err, 'extended'));
149 end
150 end
151end