diff options
| author | Joel Martin <github@martintribe.org> | 2015-02-09 23:20:23 -0600 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2015-02-10 01:46:17 -0600 |
| commit | 6a572dff25a95f460d1b3c1b259c7a0a1f10c2d0 (patch) | |
| tree | e680af55f0b6b02eaf86fb7a5a384b9b364c6942 | |
| parent | 7f567f36457b937c36345becdb7c1101566dcdf3 (diff) | |
| download | mal-6a572dff25a95f460d1b3c1b259c7a0a1f10c2d0.tar.gz mal-6a572dff25a95f460d1b3c1b259c7a0a1f10c2d0.zip | |
matlab: add keyword, vector, hash-map support.
Switch List to full object like vector and hash-map.
| -rw-r--r-- | matlab/+types/HashMap.m | 47 | ||||
| -rw-r--r-- | matlab/+types/List.m | 60 | ||||
| -rw-r--r-- | matlab/+types/Vector.m | 15 | ||||
| -rw-r--r-- | matlab/Env.m | 6 | ||||
| -rw-r--r-- | matlab/Makefile | 2 | ||||
| -rw-r--r-- | matlab/core.m | 82 | ||||
| -rw-r--r-- | matlab/printer.m | 33 | ||||
| -rw-r--r-- | matlab/reader.m | 53 | ||||
| -rw-r--r-- | matlab/step2_eval.m | 24 | ||||
| -rw-r--r-- | matlab/step3_env.m | 36 | ||||
| -rw-r--r-- | matlab/step4_if_fn_do.m | 51 | ||||
| -rw-r--r-- | matlab/step5_tco.m | 53 | ||||
| -rw-r--r-- | matlab/step6_file.m | 56 | ||||
| -rw-r--r-- | matlab/step7_quote.m | 87 | ||||
| -rw-r--r-- | matlab/step8_macros.m | 104 | ||||
| -rw-r--r-- | matlab/step9_try.m | 112 | ||||
| -rw-r--r-- | matlab/stepA_interop.m | 112 | ||||
| -rw-r--r-- | matlab/types.m | 35 |
18 files changed, 677 insertions, 291 deletions
diff --git a/matlab/+types/HashMap.m b/matlab/+types/HashMap.m new file mode 100644 index 0000000..f48ba81 --- /dev/null +++ b/matlab/+types/HashMap.m @@ -0,0 +1,47 @@ +classdef HashMap < handle + properties + data = containers.Map(); + meta = types.nil; + end + methods + function obj = HashMap(varargin) + if nargin == 0 + obj.data = containers.Map(); + else + obj.data = containers.Map(varargin(1:2:end), ... + varargin(2:2:end)); + end + end + + function len = length(obj) + len = length(obj.data); + end + + function ret = get(obj, key) + ret = obj.data(key); + end + + function ret = set(obj, key, val) + obj.data(key) = val; + ret = val; + end + + function ret = keys(obj) + ret = obj.data.keys(); + end + + function ret = values(obj) + ret = obj.data.values(); + end + + function ret = clone(obj) + ret = types.HashMap(); + if length(obj) > 0 + ret.data = containers.Map(obj.data.keys(), obj.data.values()); + else + ret.data = containers.Map(); + end + ret.meta = obj.meta; + end + end +end diff --git a/matlab/+types/List.m b/matlab/+types/List.m new file mode 100644 index 0000000..fd27cb4 --- /dev/null +++ b/matlab/+types/List.m @@ -0,0 +1,60 @@ +classdef List < handle + properties + data = {} + meta = types.nil; + end + methods + function obj = List(varargin) + obj.data = varargin; + end + + function len = length(obj) + len = length(obj.data); + end + + function ret = get(obj, idx) + ret = obj.data{idx}; + end + + function ret = set(obj, key, val) + obj.data{key} = val; + ret = val; + end + + function ret = append(obj, val) + obj.data{end+1} = val; + ret = val; + end + + function ret = slice(obj, start, last) + if nargin < 3 + last = length(obj.data); + end + ret = types.List(obj.data{start:end}); + end + +% function varargout = subsref(vec, S) +% % This doesn't work for ranges +% [varargout{1:nargout}] = builtin('subsref', vec.data, S); +% +% varargout = cell(1,max(1,nargout)); +% [varargout{:}] = builtin('subsref',vec.data,S); +% +%% switch S.type +%% case '()' +%% varargout = cell(1,numel(vec)); +%% varargout{1} = builtin('subsref', vec.data, S); +%% case '{}' +%% varargout = cell(1,numel(vec)); +%% varargout{1} = builtin('subsref', vec.data, S); +%% case '.' +%% error('Vector property access not yet implemented'); +%% end +% end + +% %function n = numel(varargin) +% % n = 1; +% %end + + end +end diff --git a/matlab/+types/Vector.m b/matlab/+types/Vector.m new file mode 100644 index 0000000..3f854fb --- /dev/null +++ b/matlab/+types/Vector.m @@ -0,0 +1,15 @@ +classdef Vector < types.List + methods + function obj = Vector(varargin) + obj.data = varargin; + end + + function ret = slice(obj, start, last) + if nargin < 3 + last = length(obj.data); + end + ret = types.Vector(obj.data{2:end}); + end + + end +end diff --git a/matlab/Env.m b/matlab/Env.m index 1a7b3fc..0a09db8 100644 --- a/matlab/Env.m +++ b/matlab/Env.m @@ -11,12 +11,12 @@ classdef Env < handle if nargin > 1 env = Env(outer); for i=1:length(binds) - k = binds{i}.name; + k = binds.get(i).name; if strcmp(k, '&') - env.data(binds{i+1}.name) = exprs(i:end); + env.data(binds.get(i+1).name) = exprs.slice(i); break; else - env.data(k) = exprs{i}; + env.data(k) = exprs.get(i); end end end diff --git a/matlab/Makefile b/matlab/Makefile index db69428..445512a 100644 --- a/matlab/Makefile +++ b/matlab/Makefile @@ -1,6 +1,6 @@ SOURCES_BASE = Reader.m types/Symbol.m reader.m printer.m #SOURCES_LISP = env.m core.m stepA_interop.m -SOURCES_LISP = step1_read_print.m +SOURCES_LISP = stepA_interop.m SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) diff --git a/matlab/core.m b/matlab/core.m index ee86ad9..5947c2d 100644 --- a/matlab/core.m +++ b/matlab/core.m @@ -33,28 +33,76 @@ classdef core ret = floor(secs.*repmat(24*3600.0*1000,size(now))); end + function new_hm = assoc(hm, varargin) + new_hm = clone(hm); + for i=1:2:length(varargin) + new_hm.set(varargin{i}, varargin{i+1}); + end + end + + function new_hm = dissoc(hm, varargin) + new_hm = clone(hm); + ks = intersect(hm.keys(),varargin); + remove(new_hm.data, ks); + end + + function ret = get(hm, key) + if hm == types.nil + ret = types.nil; + else + if hm.data.isKey(key) + ret = hm.data(key); + else + ret = types.nil; + end + end + end + + function ret = keys(hm) + ks = hm.keys(); + ret = types.List(ks{:}); + end + + function ret = vals(hm) + vs = hm.values(); + ret = types.List(vs{:}); + end + + function ret = cons(a, seq) + cella = [{a}, seq.data]; + ret = types.List(cella{:}); + end + function ret = concat(varargin) if nargin == 0 - ret = {}; + cella = {}; else - ret = cat(2,varargin{:}); + cells = cellfun(@(x) x.data, varargin, ... + 'UniformOutput', false); + cella = cat(2,cells{:}); end + ret = types.List(cella{:}); end function ret = first(seq) if length(seq) < 1 ret = types.nil; else - ret = seq{1}; + ret = seq.get(1); end end + function ret = rest(seq) + cella = seq.data(2:end); + ret = types.List(cella{:}); + end + function ret = nth(seq, idx) if idx+1 > length(seq) throw(MException('Range:nth', ... 'nth: index out of range')) end - ret = seq{idx+1}; + ret = seq.get(idx+1); end function ret = apply(varargin) @@ -63,7 +111,7 @@ classdef core f = f.fn; end first_args = varargin(2:end-1); - rest_args = varargin{end}; + rest_args = varargin{end}.data; args = [first_args rest_args]; ret = f(args{:}); end @@ -72,7 +120,8 @@ classdef core if isa(f, 'types.Function') f = f.fn; end - ret = cellfun(@(x) f(x), lst, 'UniformOutput', false); + cells = cellfun(@(x) f(x), lst.data, 'UniformOutput', false); + ret = types.List(cells{:}); end function n = ns() @@ -84,6 +133,8 @@ classdef core n('false?') = @(a) isa(a, 'logical') && a == false; n('symbol') = @(a) types.Symbol(a); n('symbol?') = @(a) isa(a, 'types.Symbol'); + n('keyword') = @types.keyword; + n('keyword?') = @types.keyword_Q; n('pr-str') = @core.pr_str; n('str') = @core.do_str; @@ -103,14 +154,25 @@ classdef core n('/') = @(a,b) floor(a/b); n('time-ms') = @core.time_ms; - n('list') = @(varargin) varargin; - n('list?') = @iscell; + n('list') = @(varargin) types.List(varargin{:}); + n('list?') = @types.list_Q; + n('vector') = @(varargin) types.Vector(varargin{:}); + n('vector?') = @types.vector_Q; + n('hash-map') = @(varargin) types.HashMap(varargin{:}); + n('map?') = @types.hash_map_Q; + n('assoc') = @core.assoc; + n('dissoc') = @core.dissoc; + n('get') = @core.get; + n('contains?') = @(a,b) a.data.isKey(b); + n('keys') = @core.keys; + n('vals') = @core.vals; - n('cons') = @(a,b) [{a}, b]; + n('sequential?') = @types.sequential_Q; + n('cons') = @core.cons; n('concat') = @core.concat; n('nth') = @core.nth; n('first') = @core.first; - n('rest') = @(a) a(2:end); + n('rest') = @core.rest; n('empty?') = @(a) length(a) == 0; n('count') = @(a) length(a); n('apply') = @core.apply; diff --git a/matlab/printer.m b/matlab/printer.m index 11e22a8..fa55e06 100644 --- a/matlab/printer.m +++ b/matlab/printer.m @@ -8,18 +8,35 @@ classdef printer case 'double' str = num2str(obj); case 'char' - if print_readably - str = strrep(obj, '\', '\\'); - str = strrep(str, '"', '\"'); - str = strrep(str, char(10), '\n'); - str = strcat('"', str, '"'); + if types.keyword_Q(obj) + str = strcat(':', obj(2:end)); else - str = obj; + if print_readably + str = strrep(obj, '\', '\\'); + str = strrep(str, '"', '\"'); + str = strrep(str, char(10), '\n'); + str = strcat('"', str, '"'); + else + str = obj; + end end - case 'cell' + case 'types.List' strs = cellfun(@(x) printer.pr_str(x, print_readably), ... - obj, 'UniformOutput', false); + obj.data, 'UniformOutput', false); str = strcat('(', strjoin(strs, ' '), ')'); + case 'types.Vector' + strs = cellfun(@(x) printer.pr_str(x, print_readably), ... + obj.data, 'UniformOutput', false); + str = strcat('[', strjoin(strs, ' '), ']'); + case 'types.HashMap' + strs = {}; + ks = obj.keys(); + for i=1:length(ks) + k = ks{i}; + strs{end+1} = printer.pr_str(k, print_readably); + strs{end+1} = printer.pr_str(obj.get(k), print_readably); + end + str = strcat('{', strjoin(strs, ' '), '}'); case 'types.Nil' str = 'nil'; case 'logical' diff --git a/matlab/reader.m b/matlab/reader.m index 0a985e8..7265ab3 100644 --- a/matlab/reader.m +++ b/matlab/reader.m @@ -18,6 +18,8 @@ classdef reader atm = token(2:length(token)-1); atm = strrep(atm, '\"', '"'); atm = strrep(atm, '\n', char(10)); + elseif strcmp(token(1), ':') + atm = types.keyword(token); elseif strcmp(token, 'nil') atm = types.nil; elseif strcmp(token, 'true') @@ -29,45 +31,72 @@ classdef reader end end - function lst = read_list(rdr) - %fprintf('in read_list\n'); - lst = {}; + function seq = read_seq(rdr, start, last) + %fprintf('in read_seq\n'); + seq = {}; token = rdr.next(); - if not(strcmp(token, '(')) - error('expected ''('''); + if not(strcmp(token, start)) + error(strcat('expected ''', start, '''')); end token = rdr.peek(); while true if eq(token, false) - error('expected '')'''); + error(strcat('expected ''', last, '''')); end - if strcmp(token, ')'), break, end - lst{length(lst)+1} = reader.read_form(rdr); + if strcmp(token, last), break, end + seq{end+1} = reader.read_form(rdr); token = rdr.peek(); end rdr.next(); end + function lst = read_list(rdr) + seq = reader.read_seq(rdr, '(', ')'); + lst = types.List(seq{:}); + end + + function vec = read_vector(rdr) + seq = reader.read_seq(rdr, '[', ']'); + vec = types.Vector(seq{:}); + end + + function map = read_hash_map(rdr) + seq = reader.read_seq(rdr, '{', '}'); + map = types.HashMap(seq{:}); + end + function ast = read_form(rdr) %fprintf('in read_form\n'); token = rdr.peek(); switch token case '''' rdr.next(); - ast = {types.Symbol('quote'), reader.read_form(rdr)}; + ast = types.List(types.Symbol('quote'), ... + reader.read_form(rdr)); case '`' rdr.next(); - ast = {types.Symbol('quasiquote'), reader.read_form(rdr)}; + ast = types.List(types.Symbol('quasiquote'), ... + reader.read_form(rdr)); case '~' rdr.next(); - ast = {types.Symbol('unquote'), reader.read_form(rdr)}; + ast = types.List(types.Symbol('unquote'), ... + reader.read_form(rdr)); case '~@' rdr.next(); - ast = {types.Symbol('splice-unquote'), reader.read_form(rdr)}; + ast = types.List(types.Symbol('splice-unquote'), ... + reader.read_form(rdr)); case ')' error('unexpected '')'''); case '(' ast = reader.read_list(rdr); + case ']' + error('unexpected '']'''); + case '[' + ast = reader.read_vector(rdr); + case '}' + error('unexpected ''}'''); + case '{' + ast = reader.read_hash_map(rdr); otherwise ast = reader.read_atom(rdr); end diff --git a/matlab/step2_eval.m b/matlab/step2_eval.m index a388145..34559c0 100644 --- a/matlab/step2_eval.m +++ b/matlab/step2_eval.m @@ -10,10 +10,22 @@ function ret = eval_ast(ast, env) switch class(ast) case 'types.Symbol' ret = env(ast.name); - case 'cell' - ret = {}; + case 'types.List' + ret = types.List(); for i=1:length(ast) - ret{end+1} = EVAL(ast{i}, env); + ret.append(EVAL(ast.get(i), env)); + end + case 'types.Vector' + ret = types.Vector(); + for i=1:length(ast) + ret.append(EVAL(ast.get(i), env)); + end + case 'types.HashMap' + ret = types.HashMap(); + ks = ast.keys(); + for i=1:length(ks) + k = ks{i}; + ret.set(EVAL(k, env), EVAL(ast.get(k), env)); end otherwise ret = ast; @@ -21,15 +33,15 @@ function ret = eval_ast(ast, env) end function ret = EVAL(ast, env) - if ~iscell(ast) + if ~types.list_Q(ast) ret = eval_ast(ast, env); return; end % apply el = eval_ast(ast, env); - f = el{1}; - args = el(2:end); + f = el.get(1); + args = el.data(2:end); ret = f(args{:}); end diff --git a/matlab/step3_env.m b/matlab/step3_env.m index f5b953b..801ad6f 100644 --- a/matlab/step3_env.m +++ b/matlab/step3_env.m @@ -10,10 +10,22 @@ function ret = eval_ast(ast, env) switch class(ast) case 'types.Symbol' ret = env.get(ast); - case 'cell' - ret = {}; + case 'types.List' + ret = types.List(); for i=1:length(ast) - ret{end+1} = EVAL(ast{i}, env); + ret.append(EVAL(ast.get(i), env)); + end + case 'types.Vector' + ret = types.Vector(); + for i=1:length(ast) + ret.append(EVAL(ast.get(i), env)); + end + case 'types.HashMap' + ret = types.HashMap(); + ks = ast.keys(); + for i=1:length(ks) + k = ks{i}; + ret.set(EVAL(k, env), EVAL(ast.get(k), env)); end otherwise ret = ast; @@ -21,30 +33,30 @@ function ret = eval_ast(ast, env) end function ret = EVAL(ast, env) - if ~iscell(ast) + if ~types.list_Q(ast) ret = eval_ast(ast, env); return; end % apply - if isa(ast{1},'types.Symbol') - a1sym = ast{1}.name; + if isa(ast.get(1),'types.Symbol') + a1sym = ast.get(1).name; else a1sym = '_@$fn$@_'; end switch (a1sym) case 'def!' - ret = env.set(ast{2}, EVAL(ast{3}, env)); + ret = env.set(ast.get(2), EVAL(ast.get(3), env)); case 'let*' let_env = Env(env); - for i=1:2:length(ast{2}) - let_env.set(ast{2}{i}, EVAL(ast{2}{i+1}, let_env)); + for i=1:2:length(ast.get(2)) + let_env.set(ast.get(2).get(i), EVAL(ast.get(2).get(i+1), let_env)); end - ret = EVAL(ast{3}, let_env); + ret = EVAL(ast.get(3), let_env); otherwise el = eval_ast(ast, env); - f = el{1}; - args = el(2:end); + f = el.get(1); + args = el.data(2:end); ret = f(args{:}); end end diff --git a/matlab/step4_if_fn_do.m b/matlab/step4_if_fn_do.m index dc9f28b..0e24b28 100644 --- a/matlab/step4_if_fn_do.m +++ b/matlab/step4_if_fn_do.m @@ -10,10 +10,22 @@ function ret = eval_ast(ast, env) switch class(ast) case 'types.Symbol' ret = env.get(ast); - case 'cell' - ret = {}; + case 'types.List' + ret = types.List(); for i=1:length(ast) - ret{end+1} = EVAL(ast{i}, env); + ret.append(EVAL(ast.get(i), env)); + end + case 'types.Vector' + ret = types.Vector(); + for i=1:length(ast) + ret.append(EVAL(ast.get(i), env)); + end + case 'types.HashMap' + ret = types.HashMap(); + ks = ast.keys(); + for i=1:length(ks) + k = ks{i}; + ret.set(EVAL(k, env), EVAL(ast.get(k), env)); end otherwise ret = ast; @@ -21,47 +33,48 @@ function ret = eval_ast(ast, env) end function ret = EVAL(ast, env) - if ~iscell(ast) + if ~types.list_Q(ast) ret = eval_ast(ast, env); return; end % apply - if isa(ast{1},'types.Symbol') - a1sym = ast{1}.name; + if isa(ast.get(1),'types.Symbol') + a1sym = ast.get(1).name; else a1sym = '_@$fn$@_'; end switch (a1sym) case 'def!' - ret = env.set(ast{2}, EVAL(ast{3}, env)); + ret = env.set(ast.get(2), EVAL(ast.get(3), env)); case 'let*' let_env = Env(env); - for i=1:2:length(ast{2}) - let_env.set(ast{2}{i}, EVAL(ast{2}{i+1}, let_env)); + for i=1:2:length(ast.get(2)) + let_env.set(ast.get(2).get(i), EVAL(ast.get(2).get(i+1), let_env)); end - ret = EVAL(ast{3}, let_env); + ret = EVAL(ast.get(3), let_env); case 'do' - el = eval_ast(ast(2:end), env); - ret = el{end}; + el = eval_ast(ast.slice(2), env); + ret = el.get(length(el)); case 'if' - cond = EVAL(ast{2}, env); + cond = EVAL(ast.get(2), env); if strcmp(class(cond), 'types.Nil') || ... (islogical(cond) && cond == false) if length(ast) > 3 - ret = EVAL(ast{4}, env); + ret = EVAL(ast.get(4), env); else - ret = types.nil; + ret = types.nil; end else - ret = EVAL(ast{3}, env); + ret = EVAL(ast.get(3), env); end case 'fn*' - ret = @(varargin) EVAL(ast{3}, Env(env, ast{2}, varargin)); + ret = @(varargin) EVAL(ast.get(3), Env(env, ast.get(2), ... + types.List(varargin{:}))); otherwise el = eval_ast(ast, env); - f = el{1}; - args = el(2:end); + f = el.get(1); + args = el.data(2:end); ret = f(args{:}); end end diff --git a/matlab/step5_tco.m b/matlab/step5_tco.m index 8ffb261..a4385e4 100644 --- a/matlab/step5_tco.m +++ b/matlab/step5_tco.m @@ -10,10 +10,22 @@ function ret = eval_ast(ast, env) switch class(ast) case 'types.Symbol' ret = env.get(ast); - case 'cell' - ret = {}; + case 'types.List' + ret = types.List(); for i=1:length(ast) - ret{end+1} = EVAL(ast{i}, env); + ret.append(EVAL(ast.get(i), env)); + end + case 'types.Vector' + ret = types.Vector(); + for i=1:length(ast) + ret.append(EVAL(ast.get(i), env)); + end + case 'types.HashMap' + ret = types.HashMap(); + ks = ast.keys(); + for i=1:length(ks) + k = ks{i}; + ret.set(EVAL(k, env), EVAL(ast.get(k), env)); end otherwise ret = ast; @@ -22,57 +34,58 @@ end function ret = EVAL(ast, env) while true - if ~iscell(ast) + if ~types.list_Q(ast) ret = eval_ast(ast, env); return; end % apply - if isa(ast{1},'types.Symbol') - a1sym = ast{1}.name; + if isa(ast.get(1),'types.Symbol') + a1sym = ast.get(1).name; else a1sym = '_@$fn$@_'; end switch (a1sym) case 'def!' - ret = env.set(ast{2}, EVAL(ast{3}, env)); + ret = env.set(ast.get(2), EVAL(ast.get(3), env)); return; case 'let*' let_env = Env(env); - for i=1:2:length(ast{2}) - let_env.set(ast{2}{i}, EVAL(ast{2}{i+1}, let_env)); + for i=1:2:length(ast.get(2)) + let_env.set(ast.get(2).get(i), EVAL(ast.get(2).get(i+1), let_env)); end env = let_env; - ast = ast{3}; % TCO + ast = ast.get(3); % TCO case 'do' - el = eval_ast(ast(2:end-1), env); - ast = ast{end}; % TCO + el = eval_ast(ast.slice(2,length(ast)-1), env); + ast = ast.get(length(ast)); % TCO case 'if' - cond = EVAL(ast{2}, env); + cond = EVAL(ast.get(2), env); if strcmp(class(cond), 'types.Nil') || ... (islogical(cond) && cond == false) if length(ast) > 3 - ast = ast{4}; % TCO + ast = ast.get(4); % TCO else ret = types.nil; return; end else - ast = ast{3}; % TCO + ast = ast.get(3); % TCO end case 'fn*' - fn = @(varargin) EVAL(ast{3}, Env(env, ast{2}, varargin)); - ret = types.Function(fn, ast{3}, env, ast{2}); + fn = @(varargin) EVAL(ast.get(3), Env(env, ast.get(2), ... + types.List(varargin{:}))); + ret = types.Function(fn, ast.get(3), env, ast.get(2)); return; otherwise el = eval_ast(ast, env); - f = el{1}; - args = el(2:end); + f = el.get(1); + args = el.slice(2); if isa(f, 'types.Function') env = Env(f.env, f.params, args); ast = f.ast; % TCO else - ret = f(args{:}); + ret = f(args.data{:}); return end end diff --git a/matlab/step6_file.m b/matlab/step6_file.m index 8e50633..cfca152 100644 --- a/matlab/step6_file.m +++ b/matlab/step6_file.m @@ -10,10 +10,22 @@ function ret = eval_ast(ast, env) switch class(ast) case 'types.Symbol' ret = env.get(ast); - case 'cell' - ret = {}; + case 'types.List' + ret = types.List(); for i=1:length(ast) - ret{end+1} = EVAL(ast{i}, env); + ret.append(EVAL(ast.get(i), env)); + end + case 'types.Vector' + ret = types.Vector(); + for i=1:length(ast) + ret.append(EVAL(ast.get(i), env)); + end + case 'types.HashMap' + ret = types.HashMap(); + ks = ast.keys(); + for i=1:length(ks) + k = ks{i}; + ret.set(EVAL(k, env), EVAL(ast.get(k), env)); end otherwise ret = ast; @@ -22,57 +34,58 @@ end function ret = EVAL(ast, env) while true - if ~iscell(ast) + if ~types.list_Q(ast) ret = eval_ast(ast, env); return; end % apply - if isa(ast{1},'types.Symbol') - a1sym = ast{1}.name; + if isa(ast.get(1),'types.Symbol') + a1sym = ast.get(1).name; else a1sym = '_@$fn$@_'; end switch (a1sym) case 'def!' - ret = env.set(ast{2}, EVAL(ast{3}, env)); + ret = env.set(ast.get(2), EVAL(ast.get(3), env)); return; case 'let*' let_env = Env(env); - for i=1:2:length(ast{2}) - let_env.set(ast{2}{i}, EVAL(ast{2}{i+1}, let_env)); + for i=1:2:length(ast.get(2)) + let_env.set(ast.get(2).get(i), EVAL(ast.get(2).get(i+1), let_env)); end env = let_env; - ast = ast{3}; % TCO + ast = ast.get(3); % TCO case 'do' - el = eval_ast(ast(2:end-1), env); - ast = ast{end}; % TCO + el = eval_ast(ast.slice(2,length(ast)-1), env); + ast = ast.get(length(ast)); % TCO case 'if' - cond = EVAL(ast{2}, env); + cond = EVAL(ast.get(2), env); if strcmp(class(cond), 'types.Nil') || ... (islogical(cond) && cond == false) if length(ast) > 3 - ast = ast{4}; % TCO + ast = ast.get(4); % TCO else ret = types.nil; return; end else - ast = ast{3}; % TCO + ast = ast.get(3); % TCO end case 'fn*' - fn = @(varargin) EVAL(ast{3}, Env(env, ast{2}, varargin)); - ret = types.Function(fn, ast{3}, env, ast{2}); + fn = @(varargin) EVAL(ast.get(3), Env(env, ast.get(2), ... + types.List(varargin{:}))); + ret = types.Function(fn, ast.get(3), env, ast.get(2)); return; otherwise el = eval_ast(ast, env); - f = el{1}; - args = el(2:end); + f = el.get(1); + args = el.slice(2); if isa(f, 'types.Function') env = Env(f.env, f.params, args); ast = f.ast; % TCO else - ret = f(args{:}); + ret = f(args.data{:}); return end end @@ -99,7 +112,8 @@ function main(args) repl_env.set(types.Symbol(k), ns(k)); end repl_env.set(types.Symbol('eval'), @(a) EVAL(a, repl_env)); - repl_env.set(types.Symbol('*ARGV*'), args(2:end)); + rest_args = args(2:end); + repl_env.set(types.Symbol('*ARGV*'), types.List(rest_args{:})); % core.mal: defined using the langauge itself rep('(def! not (fn* (a) (if a false true)))', repl_env); diff --git a/matlab/step7_quote.m b/matlab/step7_quote.m index 524d547..cb572a6 100644 --- a/matlab/step7_quote.m +++ b/matlab/step7_quote.m @@ -7,24 +7,25 @@ end % eval function ret = is_pair(ast) - ret = iscell(ast) && length(ast) > 0; + ret = types.sequential_Q(ast) && length(ast) > 0; end function ret = quasiquote(ast) if ~is_pair(ast) - ret = {types.Symbol('quote'), ast}; - elseif isa(ast{1},'types.Symbol') && ... - strcmp(ast{1}.name, 'unquote') - ret = ast{2}; - elseif is_pair(ast{1}) && isa(ast{1}{1},'types.Symbol') && ... - strcmp(ast{1}{1}.name, 'splice-unquote') - ret = {types.Symbol('concat'), ... - ast{1}{2}, ... - quasiquote(ast(2:end))}; + ret = types.List(types.Symbol('quote'), ast); + elseif isa(ast.get(1),'types.Symbol') && ... + strcmp(ast.get(1).name, 'unquote') + ret = ast.get(2); + elseif is_pair(ast.get(1)) && ... + isa(ast.get(1).get(1),'types.Symbol') && ... + strcmp(ast.get(1).get(1).name, 'splice-unquote') + ret = types.List(types.Symbol('concat'), ... + ast.get(1).get(2), ... + quasiquote(ast.slice(2))); else - ret = {types.Symbol('cons'), ... - quasiquote(ast{1}), ... - quasiquote(ast(2:end))}; + ret = types.List(types.Symbol('cons'), ... + quasiquote(ast.get(1)), ... + quasiquote(ast.slice(2))); end end @@ -32,10 +33,22 @@ function ret = eval_ast(ast, env) switch class(ast) case 'types.Symbol' ret = env.get(ast); - case 'cell' - ret = {}; + case 'types.List' + ret = types.List(); for i=1:length(ast) - ret{end+1} = EVAL(ast{i}, env); + ret.append(EVAL(ast.get(i), env)); + end + case 'types.Vector' + ret = types.Vector(); + for i=1:length(ast) + ret.append(EVAL(ast.get(i), env)); + end + case 'types.HashMap' + ret = types.HashMap(); + ks = ast.keys(); + for i=1:length(ks) + k = ks{i}; + ret.set(EVAL(k, env), EVAL(ast.get(k), env)); end otherwise ret = ast; @@ -44,62 +57,63 @@ end function ret = EVAL(ast, env) while true - if ~iscell(ast) + if ~types.list_Q(ast) ret = eval_ast(ast, env); return; end % apply - if isa(ast{1},'types.Symbol') - a1sym = ast{1}.name; + if isa(ast.get(1),'types.Symbol') + a1sym = ast.get(1).name; else a1sym = '_@$fn$@_'; end switch (a1sym) case 'def!' - ret = env.set(ast{2}, EVAL(ast{3}, env)); + ret = env.set(ast.get(2), EVAL(ast.get(3), env)); return; case 'let*' let_env = Env(env); - for i=1:2:length(ast{2}) - let_env.set(ast{2}{i}, EVAL(ast{2}{i+1}, let_env)); + for i=1:2:length(ast.get(2)) + let_env.set(ast.get(2).get(i), EVAL(ast.get(2).get(i+1), let_env)); end env = let_env; - ast = ast{3}; % TCO + ast = ast.get(3); % TCO case 'quote' - ret = ast{2}; + ret = ast.get(2); return; case 'quasiquote' - ast = quasiquote(ast{2}); % TCO + ast = quasiquote(ast.get(2)); % TCO case 'do' - el = eval_ast(ast(2:end-1), env); - ast = ast{end}; % TCO + el = eval_ast(ast.slice(2,length(ast)-1), env); + ast = ast.get(length(ast)); % TCO case 'if' - cond = EVAL(ast{2}, env); + cond = EVAL(ast.get(2), env); if strcmp(class(cond), 'types.Nil') || ... (islogical(cond) && cond == false) if length(ast) > 3 - ast = ast{4}; % TCO + ast = ast.get(4); % TCO else ret = types.nil; return; end else - ast = ast{3}; % TCO + ast = ast.get(3); % TCO end case 'fn*' - fn = @(varargin) EVAL(ast{3}, Env(env, ast{2}, varargin)); - ret = types.Function(fn, ast{3}, env, ast{2}); + fn = @(varargin) EVAL(ast.get(3), Env(env, ast.get(2), ... + types.List(varargin{:}))); + ret = types.Function(fn, ast.get(3), env, ast.get(2)); return; otherwise el = eval_ast(ast, env); - f = el{1}; - args = el(2:end); + f = el.get(1); + args = el.slice(2); if isa(f, 'types.Function') env = Env(f.env, f.params, args); ast = f.ast; % TCO else - ret = f(args{:}); + ret = f(args.data{:}); return end end @@ -126,7 +140,8 @@ function main(args) repl_env.set(types.Symbol(k), ns(k)); end repl_env.set(types.Symbol('eval'), @(a) EVAL(a, repl_env)); - repl_env.set(types.Symbol('*ARGV*'), args(2:end)); + rest_args = args(2:end); + repl_env.set(types.Symbol('*ARGV*'), types.List(rest_args{:})); % core.mal: defined using the langauge itself rep('(def! not (fn* (a) (if a false true)))', repl_env); diff --git a/matlab/step8_macros.m b/matlab/step8_macros.m index a4b45c2..8757c7a 100644 --- a/matlab/step8_macros.m +++ b/matlab/step8_macros.m @@ -7,31 +7,32 @@ end % eval function ret = is_pair(ast) - ret = iscell(ast) && length(ast) > 0; + ret = types.sequential_Q(ast) && length(ast) > 0; end function ret = quasiquote(ast) if ~is_pair(ast) - ret = {types.Symbol('quote'), ast}; - elseif isa(ast{1},'types.Symbol') && ... - strcmp(ast{1}.name, 'unquote') - ret = ast{2}; - elseif is_pair(ast{1}) && isa(ast{1}{1},'types.Symbol') && ... - strcmp(ast{1}{1}.name, 'splice-unquote') - ret = {types.Symbol('concat'), ... - ast{1}{2}, ... - quasiquote(ast(2:end))}; + ret = types.List(types.Symbol('quote'), ast); + elseif isa(ast.get(1),'types.Symbol') && ... + strcmp(ast.get(1).name, 'unquote') + ret = ast.get(2); + elseif is_pair(ast.get(1)) && ... + isa(ast.get(1).get(1),'types.Symbol') && ... + strcmp(ast.get(1).get(1).name, 'splice-unquote') + ret = types.List(types.Symbol('concat'), ... + ast.get(1).get(2), ... + quasiquote(ast.slice(2))); else - ret = {types.Symbol('cons'), ... - quasiquote(ast{1}), ... - quasiquote(ast(2:end))}; + ret = types.List(types.Symbol('cons'), ... + quasiquote(ast.get(1)), ... + quasiquote(ast.slice(2))); end end function ret = is_macro_call(ast, env) - if iscell(ast) && isa(ast{1}, 'types.Symbol') && ... - ~islogical(env.find(ast{1})) - f = env.get(ast{1}); + if types.list_Q(ast) && isa(ast.get(1), 'types.Symbol') && ... + ~islogical(env.find(ast.get(1))) + f = env.get(ast.get(1)); ret = isa(f,'types.Function') && f.is_macro; else ret = false; @@ -40,8 +41,9 @@ end function ret = macroexpand(ast, env) while is_macro_call(ast, env) - mac = env.get(ast{1}); - ast = mac.fn(ast{2:end}); + mac = env.get(ast.get(1)); + args = ast.slice(2); + ast = mac.fn(args.data{:}); end ret = ast; end @@ -50,10 +52,22 @@ function ret = eval_ast(ast, env) switch class(ast) case 'types.Symbol' ret = env.get(ast); - case 'cell' - ret = {}; + case 'types.List' + ret = types.List(); for i=1:length(ast) - ret{end+1} = EVAL(ast{i}, env); + ret.append(EVAL(ast.get(i), env)); + end + case 'types.Vector' + ret = types.Vector(); + for i=1:length(ast) + ret.append(EVAL(ast.get(i), env)); + end + case 'types.HashMap' + ret = types.HashMap(); + ks = ast.keys(); + for i=1:length(ks) + k = ks{i}; + ret.set(EVAL(k, env), EVAL(ast.get(k), env)); end otherwise ret = ast; @@ -62,75 +76,76 @@ end function ret = EVAL(ast, env) while true - if ~iscell(ast) + if ~types.list_Q(ast) ret = eval_ast(ast, env); return; end % apply ast = macroexpand(ast, env); - if ~iscell(ast) + if ~types.list_Q(ast) ret = ast; return; end - if isa(ast{1},'types.Symbol') - a1sym = ast{1}.name; + if isa(ast.get(1),'types.Symbol') + a1sym = ast.get(1).name; else a1sym = '_@$fn$@_'; end switch (a1sym) case 'def!' - ret = env.set(ast{2}, EVAL(ast{3}, env)); + ret = env.set(ast.get(2), EVAL(ast.get(3), env)); return; case 'let*' let_env = Env(env); - for i=1:2:length(ast{2}) - let_env.set(ast{2}{i}, EVAL(ast{2}{i+1}, let_env)); + for i=1:2:length(ast.get(2)) + let_env.set(ast.get(2).get(i), EVAL(ast.get(2).get(i+1), let_env)); end env = let_env; - ast = ast{3}; % TCO + ast = ast.get(3); % TCO case 'quote' - ret = ast{2}; + ret = ast.get(2); return; case 'quasiquote' - ast = quasiquote(ast{2}); % TCO + ast = quasiquote(ast.get(2)); % TCO case 'defmacro!' - ret = env.set(ast{2}, EVAL(ast{3}, env)); + ret = env.set(ast.get(2), EVAL(ast.get(3), env)); ret.is_macro = true; return; case 'macroexpand' - ret = macroexpand(ast{2}, env); + ret = macroexpand(ast.get(2), env); return; case 'do' - el = eval_ast(ast(2:end-1), env); - ast = ast{end}; % TCO + el = eval_ast(ast.slice(2,length(ast)-1), env); + ast = ast.get(length(ast)); % TCO case 'if' - cond = EVAL(ast{2}, env); + cond = EVAL(ast.get(2), env); if strcmp(class(cond), 'types.Nil') || ... (islogical(cond) && cond == false) if length(ast) > 3 - ast = ast{4}; % TCO + ast = ast.get(4); % TCO else ret = types.nil; return; end else - ast = ast{3}; % TCO + ast = ast.get(3); % TCO end case 'fn*' - fn = @(varargin) EVAL(ast{3}, Env(env, ast{2}, varargin)); - ret = types.Function(fn, ast{3}, env, ast{2}); + fn = @(varargin) EVAL(ast.get(3), Env(env, ast.get(2), ... + types.List(varargin{:}))); + ret = types.Function(fn, ast.get(3), env, ast.get(2)); return; otherwise el = eval_ast(ast, env); - f = el{1}; - args = el(2:end); + f = el.get(1); + args = el.slice(2); if isa(f, 'types.Function') env = Env(f.env, f.params, args); ast = f.ast; % TCO else - ret = f(args{:}); + ret = f(args.data{:}); return end end @@ -157,7 +172,8 @@ function main(args) repl_env.set(types.Symbol(k), ns(k)); end repl_env.set(types.Symbol('eval'), @(a) EVAL(a, repl_env)); - repl_env.set(types.Symbol('*ARGV*'), args(2:end)); + rest_args = args(2:end); + repl_env.set(types.Symbol('*ARGV*'), types.List(rest_args{:})); % core.mal: defined using the langauge itself rep('(def! not (fn* (a) (if a false true)))', repl_env); diff --git a/matlab/step9_try.m b/matlab/step9_try.m index 4880aac..a9bf92f 100644 --- a/matlab/step9_try.m +++ b/matlab/step9_try.m @@ -7,31 +7,32 @@ end % eval function ret = is_pair(ast) - ret = iscell(ast) && length(ast) > 0; + ret = types.sequential_Q(ast) && length(ast) > 0; end function ret = quasiquote(ast) if ~is_pair(ast) - ret = {types.Symbol('quote'), ast}; - elseif isa(ast{1},'types.Symbol') && ... - strcmp(ast{1}.name, 'unquote') - ret = ast{2}; - elseif is_pair(ast{1}) && isa(ast{1}{1},'types.Symbol') && ... - strcmp(ast{1}{1}.name, 'splice-unquote') - ret = {types.Symbol('concat'), ... - ast{1}{2}, ... - quasiquote(ast(2:end))}; + ret = types.List(types.Symbol('quote'), ast); + elseif isa(ast.get(1),'types.Symbol') && ... + strcmp(ast.get(1).name, 'unquote') + ret = ast.get(2); + elseif is_pair(ast.get(1)) && ... + isa(ast.get(1).get(1),'types.Symbol') && ... + strcmp(ast.get(1).get(1).name, 'splice-unquote') + ret = types.List(types.Symbol('concat'), ... + ast.get(1).get(2), ... + quasiquote(ast.slice(2))); else - ret = {types.Symbol('cons'), ... - quasiquote(ast{1}), ... - quasiquote(ast(2:end))}; + ret = types.List(types.Symbol('cons'), ... + quasiquote(ast.get(1)), ... + quasiquote(ast.slice(2))); end end function ret = is_macro_call(ast, env) - if iscell(ast) && isa(ast{1}, 'types.Symbol') && ... - ~islogical(env.find(ast{1})) - f = env.get(ast{1}); + if types.list_Q(ast) && isa(ast.get(1), 'types.Symbol') && ... + ~islogical(env.find(ast.get(1))) + f = env.get(ast.get(1)); ret = isa(f,'types.Function') && f.is_macro; else ret = false; @@ -40,8 +41,9 @@ end function ret = macroexpand(ast, env) while is_macro_call(ast, env) - mac = env.get(ast{1}); - ast = mac.fn(ast{2:end}); + mac = env.get(ast.get(1)); + args = ast.slice(2); + ast = mac.fn(args.data{:}); end ret = ast; end @@ -50,10 +52,22 @@ function ret = eval_ast(ast, env) switch class(ast) case 'types.Symbol' ret = env.get(ast); - case 'cell' - ret = {}; + case 'types.List' + ret = types.List(); for i=1:length(ast) - ret{end+1} = EVAL(ast{i}, env); + ret.append(EVAL(ast.get(i), env)); + end + case 'types.Vector' + ret = types.Vector(); + for i=1:length(ast) + ret.append(EVAL(ast.get(i), env)); + end + case 'types.HashMap' + ret = types.HashMap(); + ks = ast.keys(); + for i=1:length(ks) + k = ks{i}; + ret.set(EVAL(k, env), EVAL(ast.get(k), env)); end otherwise ret = ast; @@ -62,92 +76,95 @@ end function ret = EVAL(ast, env) while true - if ~iscell(ast) + if ~types.list_Q(ast) ret = eval_ast(ast, env); return; end % apply ast = macroexpand(ast, env); - if ~iscell(ast) + if ~types.list_Q(ast) ret = ast; return; end - if isa(ast{1},'types.Symbol') - a1sym = ast{1}.name; + if isa(ast.get(1),'types.Symbol') + a1sym = ast.get(1).name; else a1sym = '_@$fn$@_'; end switch (a1sym) case 'def!' - ret = env.set(ast{2}, EVAL(ast{3}, env)); + ret = env.set(ast.get(2), EVAL(ast.get(3), env)); return; case 'let*' let_env = Env(env); - for i=1:2:length(ast{2}) - let_env.set(ast{2}{i}, EVAL(ast{2}{i+1}, let_env)); + for i=1:2:length(ast.get(2)) + let_env.set(ast.get(2).get(i), EVAL(ast.get(2).get(i+1), let_env)); end env = let_env; - ast = ast{3}; % TCO + ast = ast.get(3); % TCO case 'quote' - ret = ast{2}; + ret = ast.get(2); return; case 'quasiquote' - ast = quasiquote(ast{2}); % TCO + ast = quasiquote(ast.get(2)); % TCO case 'defmacro!' - ret = env.set(ast{2}, EVAL(ast{3}, env)); + ret = env.set(ast.get(2), EVAL(ast.get(3), env)); ret.is_macro = true; return; case 'macroexpand' - ret = macroexpand(ast{2}, env); + ret = macroexpand(ast.get(2), env); return; case 'try*' try - ret = EVAL(ast{2}, env); + ret = EVAL(ast.get(2), env); return; catch e - if length(ast) > 2 && strcmp(ast{3}{1}.name, 'catch*') + if length(ast) > 2 && strcmp(ast.get(3).get(1).name, 'catch*') if isa(e, 'types.MalException') exc = e.obj; else exc = e.message; end - ret = EVAL(ast{3}{3}, Env(env, {ast{3}{2}}, {exc})); + catch_env = Env(env, types.List(ast.get(3).get(2)), ... + types.List(exc)); + ret = EVAL(ast.get(3).get(3), catch_env); return; else throw(e); end end case 'do' - el = eval_ast(ast(2:end-1), env); - ast = ast{end}; % TCO + el = eval_ast(ast.slice(2,length(ast)-1), env); + ast = ast.get(length(ast)); % TCO case 'if' - cond = EVAL(ast{2}, env); + cond = EVAL(ast.get(2), env); if strcmp(class(cond), 'types.Nil') || ... (islogical(cond) && cond == false) if length(ast) > 3 - ast = ast{4}; % TCO + ast = ast.get(4); % TCO else ret = types.nil; return; end else - ast = ast{3}; % TCO + ast = ast.get(3); % TCO end case 'fn*' - fn = @(varargin) EVAL(ast{3}, Env(env, ast{2}, varargin)); - ret = types.Function(fn, ast{3}, env, ast{2}); + fn = @(varargin) EVAL(ast.get(3), Env(env, ast.get(2), ... + types.List(varargin{:}))); + ret = types.Function(fn, ast.get(3), env, ast.get(2)); return; otherwise el = eval_ast(ast, env); - f = el{1}; - args = el(2:end); + f = el.get(1); + args = el.slice(2); if isa(f, 'types.Function') env = Env(f.env, f.params, args); ast = f.ast; % TCO else - ret = f(args{:}); + ret = f(args.data{:}); return end end @@ -174,7 +191,8 @@ function main(args) repl_env.set(types.Symbol(k), ns(k)); end repl_env.set(types.Symbol('eval'), @(a) EVAL(a, repl_env)); - repl_env.set(types.Symbol('*ARGV*'), args(2:end)); + rest_args = args(2:end); + repl_env.set(types.Symbol('*ARGV*'), types.List(rest_args{:})); % core.mal: defined using the langauge itself rep('(def! not (fn* (a) (if a false true)))', repl_env); diff --git a/matlab/stepA_interop.m b/matlab/stepA_interop.m index 4972095..f9e3364 100644 --- a/matlab/stepA_interop.m +++ b/matlab/stepA_interop.m @@ -7,31 +7,32 @@ end % eval function ret = is_pair(ast) - ret = iscell(ast) && length(ast) > 0; + ret = types.sequential_Q(ast) && length(ast) > 0; end function ret = quasiquote(ast) if ~is_pair(ast) - ret = {types.Symbol('quote'), ast}; - elseif isa(ast{1},'types.Symbol') && ... - strcmp(ast{1}.name, 'unquote') - ret = ast{2}; - elseif is_pair(ast{1}) && isa(ast{1}{1},'types.Symbol') && ... - strcmp(ast{1}{1}.name, 'splice-unquote') - ret = {types.Symbol('concat'), ... - ast{1}{2}, ... - quasiquote(ast(2:end))}; + ret = types.List(types.Symbol('quote'), ast); + elseif isa(ast.get(1),'types.Symbol') && ... + strcmp(ast.get(1).name, 'unquote') + ret = ast.get(2); + elseif is_pair(ast.get(1)) && ... + isa(ast.get(1).get(1),'types.Symbol') && ... + strcmp(ast.get(1).get(1).name, 'splice-unquote') + ret = types.List(types.Symbol('concat'), ... + ast.get(1).get(2), ... + quasiquote(ast.slice(2))); else - ret = {types.Symbol('cons'), ... - quasiquote(ast{1}), ... - quasiquote(ast(2:end))}; + ret = types.List(types.Symbol('cons'), ... + quasiquote(ast.get(1)), ... + quasiquote(ast.slice(2))); end end function ret = is_macro_call(ast, env) - if iscell(ast) && isa(ast{1}, 'types.Symbol') && ... - ~islogical(env.find(ast{1})) - f = env.get(ast{1}); + if types.list_Q(ast) && isa(ast.get(1), 'types.Symbol') && ... + ~islogical(env.find(ast.get(1))) + f = env.get(ast.get(1)); ret = isa(f,'types.Function') && f.is_macro; else ret = false; @@ -40,8 +41,9 @@ end function ret = macroexpand(ast, env) while is_macro_call(ast, env) - mac = env.get(ast{1}); - ast = mac.fn(ast{2:end}); + mac = env.get(ast.get(1)); + args = ast.slice(2); + ast = mac.fn(args.data{:}); end ret = ast; end @@ -50,10 +52,22 @@ function ret = eval_ast(ast, env) switch class(ast) case 'types.Symbol' ret = env.get(ast); - case 'cell' - ret = {}; + case 'types.List' + ret = types.List(); for i=1:length(ast) - ret{end+1} = EVAL(ast{i}, env); + ret.append(EVAL(ast.get(i), env)); + end + case 'types.Vector' + ret = types.Vector(); + for i=1:length(ast) + ret.append(EVAL(ast.get(i), env)); + end + case 'types.HashMap' + ret = types.HashMap(); + ks = ast.keys(); + for i=1:length(ks) + k = ks{i}; + ret.set(EVAL(k, env), EVAL(ast.get(k), env)); end otherwise ret = ast; @@ -62,92 +76,95 @@ end function ret = EVAL(ast, env) while true - if ~iscell(ast) + if ~types.list_Q(ast) ret = eval_ast(ast, env); return; end % apply ast = macroexpand(ast, env); - if ~iscell(ast) + if ~types.list_Q(ast) ret = ast; return; end - if isa(ast{1},'types.Symbol') - a1sym = ast{1}.name; + if isa(ast.get(1),'types.Symbol') + a1sym = ast.get(1).name; else a1sym = '_@$fn$@_'; end switch (a1sym) case 'def!' - ret = env.set(ast{2}, EVAL(ast{3}, env)); + ret = env.set(ast.get(2), EVAL(ast.get(3), env)); return; case 'let*' let_env = Env(env); - for i=1:2:length(ast{2}) - let_env.set(ast{2}{i}, EVAL(ast{2}{i+1}, let_env)); + for i=1:2:length(ast.get(2)) + let_env.set(ast.get(2).get(i), EVAL(ast.get(2).get(i+1), let_env)); end env = let_env; - ast = ast{3}; % TCO + ast = ast.get(3); % TCO case 'quote' - ret = ast{2}; + ret = ast.get(2); return; case 'quasiquote' - ast = quasiquote(ast{2}); % TCO + ast = quasiquote(ast.get(2)); % TCO case 'defmacro!' - ret = env.set(ast{2}, EVAL(ast{3}, env)); + ret = env.set(ast.get(2), EVAL(ast.get(3), env)); ret.is_macro = true; return; case 'macroexpand' - ret = macroexpand(ast{2}, env); + ret = macroexpand(ast.get(2), env); return; case 'try*' try - ret = EVAL(ast{2}, env); + ret = EVAL(ast.get(2), env); return; catch e - if length(ast) > 2 && strcmp(ast{3}{1}.name, 'catch*') + if length(ast) > 2 && strcmp(ast.get(3).get(1).name, 'catch*') if isa(e, 'types.MalException') exc = e.obj; else exc = e.message; end - ret = EVAL(ast{3}{3}, Env(env, {ast{3}{2}}, {exc})); + catch_env = Env(env, types.List(ast.get(3).get(2)), ... + types.List(exc)); + ret = EVAL(ast.get(3).get(3), catch_env); return; else throw(e); end end case 'do' - el = eval_ast(ast(2:end-1), env); - ast = ast{end}; % TCO + el = eval_ast(ast.slice(2,length(ast)-1), env); + ast = ast.get(length(ast)); % TCO case 'if' - cond = EVAL(ast{2}, env); + cond = EVAL(ast.get(2), env); if strcmp(class(cond), 'types.Nil') || ... (islogical(cond) && cond == false) if length(ast) > 3 - ast = ast{4}; % TCO + ast = ast.get(4); % TCO else ret = types.nil; return; end else - ast = ast{3}; % TCO + ast = ast.get(3); % TCO end case 'fn*' - fn = @(varargin) EVAL(ast{3}, Env(env, ast{2}, varargin)); - ret = types.Function(fn, ast{3}, env, ast{2}); + fn = @(varargin) EVAL(ast.get(3), Env(env, ast.get(2), ... + types.List(varargin{:}))); + ret = types.Function(fn, ast.get(3), env, ast.get(2)); return; otherwise el = eval_ast(ast, env); - f = el{1}; - args = el(2:end); + f = el.get(1); + args = el.slice(2); if isa(f, 'types.Function') env = Env(f.env, f.params, args); ast = f.ast; % TCO else - ret = f(args{:}); + ret = f(args.data{:}); return end end @@ -174,7 +191,8 @@ function main(args) repl_env.set(types.Symbol(k), ns(k)); end repl_env.set(types.Symbol('eval'), @(a) EVAL(a, repl_env)); - repl_env.set(types.Symbol('*ARGV*'), args(2:end)); + rest_args = args(2:end); + repl_env.set(types.Symbol('*ARGV*'), types.List(rest_args{:})); % core.mal: defined using the langauge itself rep('(def! *host-language* "matlab")', repl_env); diff --git a/matlab/types.m b/matlab/types.m index 7263fb2..91f052d 100644 --- a/matlab/types.m +++ b/matlab/types.m @@ -7,17 +7,18 @@ classdef types function ret = equal(a,b) ret = false; ota = class(a); otb = class(b); - if ~(strcmp(ota,otb) || (iscell(a) && iscell(b))) + if ~(strcmp(ota,otb) || ... + (types.sequential_Q(a) && types.sequential_Q(b))) return; end switch (ota) - case 'cell' + case {'types.List', 'types.Vector'} if ~(length(a) == length(b)) - return + return; end for i=1:length(a) - if ~(types.equal(a{i}, b{i})) - return + if ~(types.equal(a.get(i), b.get(i))) + return; end end ret = true; @@ -27,6 +28,30 @@ classdef types ret = a == b; end end + + function ret = sequential_Q(obj) + ret = strcmp(class(obj), 'types.List') || ... + strcmp(class(obj), 'types.Vector'); + end + + function ret = list_Q(obj) + ret = strcmp(class(obj), 'types.List'); + end + function ret = vector_Q(obj) + ret = strcmp(class(obj), 'types.Vector'); + end + function ret = hash_map_Q(obj) + ret = strcmp(class(obj), 'types.HashMap'); + end + + function ret = keyword(str) + ret = strcat(native2unicode(hex2dec('029e'),'UTF-8'), ... + str(2:end)); + end + function ret = keyword_Q(obj) + ret = length(obj) > 1 && ... + strcmp(obj(1), native2unicode(hex2dec('029e'),'UTF-8')); + end end end |
