classdef core
methods(Static)
function ret = throw(obj)
- ret = types.nil;
- throw(types.MalException(obj));
+ ret = type_utils.nil;
+ if exist('OCTAVE_VERSION', 'builtin') ~= 0
+ % Until Octave has MException objects, we need to
+ % store the error object globally to be able to pass
+ % it to the error handler.
+ global error_object;
+ error_object = obj;
+ exc = struct('identifier', 'MalException:object',...
+ 'message', 'MalException');
+ rethrow(exc);
+ else
+ throw(types.MalException(obj));
+ end
end
function str = pr_str(varargin)
strs = cellfun(@(s) printer.pr_str(s,true), varargin, ...
'UniformOutput', false);
fprintf('%s\n', strjoin(strs, ' '));
- ret = types.nil;
+ ret = type_utils.nil;
end
function ret = println(varargin)
strs = cellfun(@(s) printer.pr_str(s,false), varargin, ...
'UniformOutput', false);
fprintf('%s\n', strjoin(strs, ' '));
- ret = types.nil;
+ ret = type_utils.nil;
+ end
+
+ function ret = time_ms()
+ secs = now-repmat(datenum('1970-1-1 00:00:00'),size(now));
+ 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);
+ if exist('OCTAVE_VERSION', 'builtin') ~= 0
+ new_hm.data.remove(ks);
+ else
+ remove(new_hm.data, ks);
+ end
+ end
+
+ function ret = get(hm, key)
+ if isa(hm, 'types.Nil')
+ ret = type_utils.nil;
+ elseif hm.data.isKey(key)
+ ret = hm.data(key);
+ else
+ ret = type_utils.nil;
+ 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;
+ if isa(seq, 'types.Nil')
+ ret = type_utils.nil;
+ elseif length(seq) < 1
+ ret = type_utils.nil;
+ else
+ ret = seq.get(1);
+ end
+ end
+
+ function ret = rest(seq)
+ if isa(seq, 'types.Nil')
+ ret = types.List();
else
- ret = seq{1};
+ cella = seq.data(2:end);
+ ret = types.List(cella{:});
end
end
throw(MException('Range:nth', ...
'nth: index out of range'))
end
- ret = seq{idx+1};
+ ret = seq.get(idx+1);
end
function ret = apply(varargin)
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
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 ret = conj(varargin)
+ seq = varargin{1};
+ args = varargin(2:end);
+ if type_utils.list_Q(seq)
+ cella = [fliplr(args), seq.data];
+ ret = types.List(cella{:});
+ else
+ cella = [seq.data, args];
+ ret = types.Vector(cella{:});
+ end
+ end
+
+ function new_obj = with_meta(obj, meta)
+ new_obj = clone(obj);
+ new_obj.meta = meta;
+ end
+
+ function meta = meta(obj)
+ switch class(obj)
+ case {'types.List', 'types.Vector',
+ 'types.HashMap', 'types.Function'}
+ meta = obj.meta;
+ otherwise
+ meta = type_utils.nil;
+ end
+ end
+
+ function ret = reset_BANG(atm, val)
+ atm.val = val;
+ ret = val;
+ end
+
+ function ret = swap_BANG(atm, f, varargin)
+ args = [{atm.val} varargin];
+ if isa(f, 'types.Function')
+ f = f.fn;
+ end
+ atm.val = f(args{:});
+ ret = atm.val;
end
function n = ns()
- n = containers.Map();
- n('=') = @types.equal;
- n('throw') = @core.throw;
+ if exist('OCTAVE_VERSION', 'builtin') ~= 0
+ n = Dict();
+ else
+ n = containers.Map();
+ end
+ n('=') = @(a,b) type_utils.equal(a,b);
+ n('throw') = @(a) core.throw(a);
n('nil?') = @(a) isa(a, 'types.Nil');
n('true?') = @(a) isa(a, 'logical') && a == true;
n('false?') = @(a) isa(a, 'logical') && a == false;
n('symbol') = @(a) types.Symbol(a);
n('symbol?') = @(a) isa(a, 'types.Symbol');
+ n('keyword') = @(a) type_utils.keyword(a);
+ n('keyword?') = @(a) type_utils.keyword_Q(a);
- n('pr-str') = @core.pr_str;
- n('str') = @core.do_str;
- n('prn') = @core.prn;
- n('println') = @core.println;
- n('read-string') = @reader.read_str;
+ n('pr-str') = @(varargin) core.pr_str(varargin{:});
+ n('str') = @(varargin) core.do_str(varargin{:});
+ n('prn') = @(varargin) core.prn(varargin{:});
+ n('println') = @(varargin) core.println(varargin{:});
+ n('read-string') = @(a) reader.read_str(a);
n('readline') = @(p) input(p, 's');
- n('slurp') = @fileread;
+ n('slurp') = @(a) fileread(a);
n('<') = @(a,b) a<b;
n('<=') = @(a,b) a<=b;
n('-') = @(a,b) a-b;
n('*') = @(a,b) a*b;
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?') = @(a) type_utils.list_Q(a);
+ n('vector') = @(varargin) types.Vector(varargin{:});
+ n('vector?') = @(a) type_utils.vector_Q(a);
+ n('hash-map') = @(varargin) types.HashMap(varargin{:});
+ n('map?') = @(a) type_utils.hash_map_Q(a);
+ n('assoc') = @(varargin) core.assoc(varargin{:});
+ n('dissoc') = @(varargin) core.dissoc(varargin{:});
+ n('get') = @(a,b) core.get(a,b);
+ n('contains?') = @(a,b) a.data.isKey(b);
+ n('keys') = @(a) core.keys(a);
+ n('vals') = @(a) core.vals(a);
- n('cons') = @(a,b) [{a}, b];
- n('concat') = @core.concat;
- n('nth') = @core.nth;
- n('first') = @core.first;
- n('rest') = @(a) a(2:end);
+ n('sequential?') = @(a) type_utils.sequential_Q(a);
+ n('cons') = @(a,b) core.cons(a,b);
+ n('concat') = @(varargin) core.concat(varargin{:});
+ n('nth') = @(a,b) core.nth(a,b);
+ n('first') = @(a) core.first(a);
+ n('rest') = @(a) core.rest(a);
n('empty?') = @(a) length(a) == 0;
- n('count') = @(a) length(a);
- n('apply') = @core.apply;
- n('map') = @core.map;
+ % workaround Octave always giving length(a) of 1
+ n('count') = @(a) 0 + length(a);
+ n('apply') = @(varargin) core.apply(varargin{:});
+ n('map') = @(varargin) core.map(varargin{:});
+ n('conj') = @(varargin) core.conj(varargin{:});
+
+ n('with-meta') = @(a,b) core.with_meta(a,b);
+ n('meta') = @(a) core.meta(a);
+ n('atom') = @(a) types.Atom(a);
+ n('atom?') = @(a) isa(a, 'types.Atom');
+ n('deref') = @(a) a.val;
+ n('reset!') = @(a,b) core.reset_BANG(a,b);
+ n('swap!') = @(varargin) core.swap_BANG(varargin{:});
end
end
end