|
@ -7,407 +7,408 @@ require "./printer" |
|
|
require "./reader" |
|
|
require "./reader" |
|
|
|
|
|
|
|
|
module Crisp |
|
|
module Crisp |
|
|
|
|
|
extend self |
|
|
|
|
|
|
|
|
|
|
|
macro calc_op(op) |
|
|
|
|
|
-> (args : Array(Crisp::Type)) { |
|
|
|
|
|
x, y = args[0].unwrap, args[1].unwrap |
|
|
|
|
|
eval_error "invalid arguments for binary operator {{op.id}}" unless x.is_a?(Int32) && y.is_a?(Int32) |
|
|
|
|
|
Crisp::Type.new(x {{op.id}} y) |
|
|
|
|
|
} |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
macro calc_op(op) |
|
|
|
|
|
-> (args : Array(Crisp::Type)) { |
|
|
|
|
|
x, y = args[0].unwrap, args[1].unwrap |
|
|
|
|
|
eval_error "invalid arguments for binary operator {{op.id}}" unless x.is_a?(Int32) && y.is_a?(Int32) |
|
|
|
|
|
Crisp::Type.new(x {{op.id}} y) |
|
|
|
|
|
} |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
def self.list(args) |
|
|
|
|
|
args.to_crisp_value |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def list(args) |
|
|
|
|
|
args.to_crisp_value |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.list?(args) |
|
|
|
|
|
args.first.unwrap.is_a? Crisp::List |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def list?(args) |
|
|
|
|
|
args.first.unwrap.is_a? Crisp::List |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.empty?(args) |
|
|
|
|
|
a = args.first.unwrap |
|
|
|
|
|
a.is_a?(Array) ? a.empty? : false |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def empty?(args) |
|
|
|
|
|
a = args.first.unwrap |
|
|
|
|
|
a.is_a?(Array) ? a.empty? : false |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.count(args) |
|
|
|
|
|
a = args.first.unwrap |
|
|
|
|
|
case a |
|
|
|
|
|
when Array |
|
|
|
|
|
a.size as Int32 |
|
|
|
|
|
when Nil |
|
|
|
|
|
0 |
|
|
|
|
|
else |
|
|
|
|
|
eval_error "invalid argument for function 'count'" |
|
|
|
|
|
|
|
|
def count(args) |
|
|
|
|
|
a = args.first.unwrap |
|
|
|
|
|
case a |
|
|
|
|
|
when Array |
|
|
|
|
|
a.size as Int32 |
|
|
|
|
|
when Nil |
|
|
|
|
|
0 |
|
|
|
|
|
else |
|
|
|
|
|
eval_error "invalid argument for function 'count'" |
|
|
|
|
|
end |
|
|
end |
|
|
end |
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
def self.pr_str_(args) |
|
|
|
|
|
args.map{|a| pr_str(a)}.join(" ") |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def pr_str_(args) |
|
|
|
|
|
args.map{|a| pr_str(a)}.join(" ") |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.str(args) |
|
|
|
|
|
args.map{|a| pr_str(a, false)}.join |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def str(args) |
|
|
|
|
|
args.map{|a| pr_str(a, false)}.join |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.prn(args) |
|
|
|
|
|
puts self.pr_str_(args) |
|
|
|
|
|
nil |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def prn(args) |
|
|
|
|
|
puts self.pr_str_(args) |
|
|
|
|
|
nil |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.println(args) |
|
|
|
|
|
puts args.map{|a| pr_str(a, false)}.join(" ") |
|
|
|
|
|
nil |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def println(args) |
|
|
|
|
|
puts args.map{|a| pr_str(a, false)}.join(" ") |
|
|
|
|
|
nil |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.read_string(args) |
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
eval_error "argument of read-str must be string" unless head.is_a? String |
|
|
|
|
|
read_str head |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def read_string(args) |
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
eval_error "argument of read-str must be string" unless head.is_a? String |
|
|
|
|
|
read_str head |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.slurp(args) |
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
eval_error "argument of slurp must be string" unless head.is_a? String |
|
|
|
|
|
begin |
|
|
|
|
|
File.read head |
|
|
|
|
|
rescue e : Errno |
|
|
|
|
|
eval_error "no such file" |
|
|
|
|
|
|
|
|
def slurp(args) |
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
eval_error "argument of slurp must be string" unless head.is_a? String |
|
|
|
|
|
begin |
|
|
|
|
|
File.read head |
|
|
|
|
|
rescue e : Errno |
|
|
|
|
|
eval_error "no such file" |
|
|
|
|
|
end |
|
|
end |
|
|
end |
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
def self.cons(args) |
|
|
|
|
|
head, tail = args[0] as Crisp::Type, args[1].unwrap |
|
|
|
|
|
eval_error "2nd arg of cons must be list" unless tail.is_a? Array |
|
|
|
|
|
([head] + tail).to_crisp_value |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def cons(args) |
|
|
|
|
|
head, tail = args[0] as Crisp::Type, args[1].unwrap |
|
|
|
|
|
eval_error "2nd arg of cons must be list" unless tail.is_a? Array |
|
|
|
|
|
([head] + tail).to_crisp_value |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.concat(args) |
|
|
|
|
|
args.each_with_object(Crisp::List.new) do |arg, list| |
|
|
|
|
|
a = arg.unwrap |
|
|
|
|
|
eval_error "arguments of concat must be list" unless a.is_a?(Array) |
|
|
|
|
|
a.each{|e| list << e} |
|
|
|
|
|
|
|
|
def concat(args) |
|
|
|
|
|
args.each_with_object(Crisp::List.new) do |arg, list| |
|
|
|
|
|
a = arg.unwrap |
|
|
|
|
|
eval_error "arguments of concat must be list" unless a.is_a?(Array) |
|
|
|
|
|
a.each{|e| list << e} |
|
|
|
|
|
end |
|
|
end |
|
|
end |
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
def self.nth(args) |
|
|
|
|
|
a0, a1 = args[0].unwrap, args[1].unwrap |
|
|
|
|
|
eval_error "1st argument of nth must be list or vector" unless a0.is_a? Array |
|
|
|
|
|
eval_error "2nd argument of nth must be integer" unless a1.is_a? Int32 |
|
|
|
|
|
a0[a1] |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def nth(args) |
|
|
|
|
|
a0, a1 = args[0].unwrap, args[1].unwrap |
|
|
|
|
|
eval_error "1st argument of nth must be list or vector" unless a0.is_a? Array |
|
|
|
|
|
eval_error "2nd argument of nth must be integer" unless a1.is_a? Int32 |
|
|
|
|
|
a0[a1] |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.first(args) |
|
|
|
|
|
a0 = args[0].unwrap |
|
|
|
|
|
|
|
|
def first(args) |
|
|
|
|
|
a0 = args[0].unwrap |
|
|
|
|
|
|
|
|
return nil if a0.nil? |
|
|
|
|
|
eval_error "1st argument of first must be list or vector or nil" unless a0.is_a? Array |
|
|
|
|
|
a0.empty? ? nil : a0.first |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
return nil if a0.nil? |
|
|
|
|
|
eval_error "1st argument of first must be list or vector or nil" unless a0.is_a? Array |
|
|
|
|
|
a0.empty? ? nil : a0.first |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.rest(args) |
|
|
|
|
|
a0 = args[0].unwrap |
|
|
|
|
|
|
|
|
def rest(args) |
|
|
|
|
|
a0 = args[0].unwrap |
|
|
|
|
|
|
|
|
return Crisp::List.new if a0.nil? |
|
|
|
|
|
eval_error "1st argument of first must be list or vector or nil" unless a0.is_a? Array |
|
|
|
|
|
return Crisp::List.new if a0.empty? |
|
|
|
|
|
a0[1..-1].to_crisp_value |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
return Crisp::List.new if a0.nil? |
|
|
|
|
|
eval_error "1st argument of first must be list or vector or nil" unless a0.is_a? Array |
|
|
|
|
|
return Crisp::List.new if a0.empty? |
|
|
|
|
|
a0[1..-1].to_crisp_value |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.apply(args) |
|
|
|
|
|
eval_error "apply must take at least 2 arguments" unless args.size >= 2 |
|
|
|
|
|
|
|
|
def apply(args) |
|
|
|
|
|
eval_error "apply must take at least 2 arguments" unless args.size >= 2 |
|
|
|
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
last = args.last.unwrap |
|
|
|
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
last = args.last.unwrap |
|
|
|
|
|
|
|
|
eval_error "last argument of apply must be list or vector" unless last.is_a? Array |
|
|
|
|
|
|
|
|
eval_error "last argument of apply must be list or vector" unless last.is_a? Array |
|
|
|
|
|
|
|
|
case head |
|
|
|
|
|
when Crisp::Closure |
|
|
|
|
|
head.fn.call(args[1..-2] + last) |
|
|
|
|
|
when Crisp::Func |
|
|
|
|
|
head.call(args[1..-2] + last) |
|
|
|
|
|
else |
|
|
|
|
|
eval_error "1st argument of apply must be function or closure" |
|
|
|
|
|
|
|
|
case head |
|
|
|
|
|
when Crisp::Closure |
|
|
|
|
|
head.fn.call(args[1..-2] + last) |
|
|
|
|
|
when Crisp::Func |
|
|
|
|
|
head.call(args[1..-2] + last) |
|
|
|
|
|
else |
|
|
|
|
|
eval_error "1st argument of apply must be function or closure" |
|
|
|
|
|
end |
|
|
end |
|
|
end |
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
def self.map(args) |
|
|
|
|
|
func = args.first.unwrap |
|
|
|
|
|
list = args[1].unwrap |
|
|
|
|
|
|
|
|
def map(args) |
|
|
|
|
|
func = args.first.unwrap |
|
|
|
|
|
list = args[1].unwrap |
|
|
|
|
|
|
|
|
eval_error "2nd argument of map must be list or vector" unless list.is_a? Array |
|
|
|
|
|
|
|
|
eval_error "2nd argument of map must be list or vector" unless list.is_a? Array |
|
|
|
|
|
|
|
|
f = case func |
|
|
|
|
|
when Crisp::Closure then func.fn |
|
|
|
|
|
when Crisp::Func then func |
|
|
|
|
|
else eval_error "1st argument of map must be function" |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
f = case func |
|
|
|
|
|
when Crisp::Closure then func.fn |
|
|
|
|
|
when Crisp::Func then func |
|
|
|
|
|
else eval_error "1st argument of map must be function" |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
list.each_with_object(Crisp::List.new) do |elem, mapped| |
|
|
|
|
|
mapped << f.call([elem]) |
|
|
|
|
|
|
|
|
list.each_with_object(Crisp::List.new) do |elem, mapped| |
|
|
|
|
|
mapped << f.call([elem]) |
|
|
|
|
|
end |
|
|
end |
|
|
end |
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
def self.nil?(args) |
|
|
|
|
|
args.first.unwrap.nil? |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
def self.true?(args) |
|
|
|
|
|
a = args.first.unwrap |
|
|
|
|
|
a.is_a?(Bool) && a |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
def self.false?(args) |
|
|
|
|
|
a = args.first.unwrap |
|
|
|
|
|
a.is_a?(Bool) && !a |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
def self.symbol?(args) |
|
|
|
|
|
args.first.unwrap.is_a?(Crisp::Symbol) |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def nil?(args) |
|
|
|
|
|
args.first.unwrap.nil? |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.symbol(args) |
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
eval_error "1st argument of symbol function must be string" unless head.is_a? String |
|
|
|
|
|
Crisp::Symbol.new head |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def true?(args) |
|
|
|
|
|
a = args.first.unwrap |
|
|
|
|
|
a.is_a?(Bool) && a |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.keyword(args) |
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
eval_error "1st argument of symbol function must be string" unless head.is_a? String |
|
|
|
|
|
"\u029e" + head |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def false?(args) |
|
|
|
|
|
a = args.first.unwrap |
|
|
|
|
|
a.is_a?(Bool) && !a |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.keyword?(args) |
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
head.is_a?(String) && !head.empty? && head[0] == '\u029e' |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def symbol?(args) |
|
|
|
|
|
args.first.unwrap.is_a?(Crisp::Symbol) |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.vector(args) |
|
|
|
|
|
args.to_crisp_value(Crisp::Vector) |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def symbol(args) |
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
eval_error "1st argument of symbol function must be string" unless head.is_a? String |
|
|
|
|
|
Crisp::Symbol.new head |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.vector?(args) |
|
|
|
|
|
args.first.unwrap.is_a? Crisp::Vector |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def keyword(args) |
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
eval_error "1st argument of symbol function must be string" unless head.is_a? String |
|
|
|
|
|
"\u029e" + head |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.hash_map(args) |
|
|
|
|
|
eval_error "hash-map must take even number of arguments" unless args.size.even? |
|
|
|
|
|
map = Crisp::HashMap.new |
|
|
|
|
|
args.each_slice(2) do |kv| |
|
|
|
|
|
k = kv[0].unwrap |
|
|
|
|
|
eval_error "key must be string" unless k.is_a? String |
|
|
|
|
|
map[k] = kv[1] |
|
|
|
|
|
|
|
|
def keyword?(args) |
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
head.is_a?(String) && !head.empty? && head[0] == '\u029e' |
|
|
end |
|
|
end |
|
|
map |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
def self.map?(args) |
|
|
|
|
|
args.first.unwrap.is_a? Crisp::HashMap |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def vector(args) |
|
|
|
|
|
args.to_crisp_value(Crisp::Vector) |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.assoc(args) |
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
eval_error "1st argument of assoc must be hashmap" unless head.is_a? Crisp::HashMap |
|
|
|
|
|
eval_error "assoc must take a list and even number of arguments" unless (args.size - 1).even? |
|
|
|
|
|
|
|
|
def vector?(args) |
|
|
|
|
|
args.first.unwrap.is_a? Crisp::Vector |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
map = Crisp::HashMap.new |
|
|
|
|
|
head.each{|k, v| map[k] = v} |
|
|
|
|
|
|
|
|
def hash_map(args) |
|
|
|
|
|
eval_error "hash-map must take even number of arguments" unless args.size.even? |
|
|
|
|
|
map = Crisp::HashMap.new |
|
|
|
|
|
args.each_slice(2) do |kv| |
|
|
|
|
|
k = kv[0].unwrap |
|
|
|
|
|
eval_error "key must be string" unless k.is_a? String |
|
|
|
|
|
map[k] = kv[1] |
|
|
|
|
|
end |
|
|
|
|
|
map |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
args[1..-1].each_slice(2) do |kv| |
|
|
|
|
|
k = kv[0].unwrap |
|
|
|
|
|
eval_error "key must be string" unless k.is_a? String |
|
|
|
|
|
map[k] = kv[1] |
|
|
|
|
|
|
|
|
def map?(args) |
|
|
|
|
|
args.first.unwrap.is_a? Crisp::HashMap |
|
|
end |
|
|
end |
|
|
|
|
|
|
|
|
map |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def assoc(args) |
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
eval_error "1st argument of assoc must be hashmap" unless head.is_a? Crisp::HashMap |
|
|
|
|
|
eval_error "assoc must take a list and even number of arguments" unless (args.size - 1).even? |
|
|
|
|
|
|
|
|
def self.dissoc(args) |
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
eval_error "1st argument of assoc must be hashmap" unless head.is_a? Crisp::HashMap |
|
|
|
|
|
|
|
|
map = Crisp::HashMap.new |
|
|
|
|
|
head.each{|k, v| map[k] = v} |
|
|
|
|
|
|
|
|
map = Crisp::HashMap.new |
|
|
|
|
|
head.each{|k,v| map[k] = v} |
|
|
|
|
|
|
|
|
args[1..-1].each_slice(2) do |kv| |
|
|
|
|
|
k = kv[0].unwrap |
|
|
|
|
|
eval_error "key must be string" unless k.is_a? String |
|
|
|
|
|
map[k] = kv[1] |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
args[1..-1].each do |arg| |
|
|
|
|
|
key = arg.unwrap |
|
|
|
|
|
eval_error "key must be string" unless key.is_a? String |
|
|
|
|
|
map.delete key |
|
|
|
|
|
|
|
|
map |
|
|
end |
|
|
end |
|
|
|
|
|
|
|
|
map |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def dissoc(args) |
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
eval_error "1st argument of assoc must be hashmap" unless head.is_a? Crisp::HashMap |
|
|
|
|
|
|
|
|
def self.get(args) |
|
|
|
|
|
a0, a1 = args[0].unwrap, args[1].unwrap |
|
|
|
|
|
return nil unless a0.is_a? Crisp::HashMap |
|
|
|
|
|
eval_error "2nd argument of get must be string" unless a1.is_a? String |
|
|
|
|
|
|
|
|
map = Crisp::HashMap.new |
|
|
|
|
|
head.each{|k,v| map[k] = v} |
|
|
|
|
|
|
|
|
# a0[a1]? isn't available because type ofa0[a1] is infered NoReturn |
|
|
|
|
|
a0.has_key?(a1) ? a0[a1] : nil |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
args[1..-1].each do |arg| |
|
|
|
|
|
key = arg.unwrap |
|
|
|
|
|
eval_error "key must be string" unless key.is_a? String |
|
|
|
|
|
map.delete key |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.contains?(args) |
|
|
|
|
|
a0, a1 = args[0].unwrap, args[1].unwrap |
|
|
|
|
|
eval_error "1st argument of get must be hashmap" unless a0.is_a? Crisp::HashMap |
|
|
|
|
|
eval_error "2nd argument of get must be string" unless a1.is_a? String |
|
|
|
|
|
a0.has_key? a1 |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
map |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.keys(args) |
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
eval_error "1st argument of assoc must be hashmap" unless head.is_a? Crisp::HashMap |
|
|
|
|
|
head.keys.each_with_object(Crisp::List.new){|e,l| l << Crisp::Type.new(e)} |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def get(args) |
|
|
|
|
|
a0, a1 = args[0].unwrap, args[1].unwrap |
|
|
|
|
|
return nil unless a0.is_a? Crisp::HashMap |
|
|
|
|
|
eval_error "2nd argument of get must be string" unless a1.is_a? String |
|
|
|
|
|
|
|
|
def self.vals(args) |
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
eval_error "1st argument of assoc must be hashmap" unless head.is_a? Crisp::HashMap |
|
|
|
|
|
head.values.to_crisp_value |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
# a0[a1]? isn't available because type ofa0[a1] is infered NoReturn |
|
|
|
|
|
a0.has_key?(a1) ? a0[a1] : nil |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.sequential?(args) |
|
|
|
|
|
args.first.unwrap.is_a? Array |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def contains?(args) |
|
|
|
|
|
a0, a1 = args[0].unwrap, args[1].unwrap |
|
|
|
|
|
eval_error "1st argument of get must be hashmap" unless a0.is_a? Crisp::HashMap |
|
|
|
|
|
eval_error "2nd argument of get must be string" unless a1.is_a? String |
|
|
|
|
|
a0.has_key? a1 |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.readline(args) |
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
eval_error "1st argument of readline must be string" unless head.is_a? b">String |
|
|
|
|
|
Readline.readline head |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def keys(args) |
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
eval_error "1st argument of assoc must be hashmap" unless head.is_a? ">Crisp::HashMap |
|
|
|
|
|
head.keys.each_with_object(Crisp::List.new){|e,l| l << Crisp::Type.new(e)} |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.meta(args) |
|
|
|
|
|
m = args.first.meta |
|
|
|
|
|
m.nil? ? nil : m |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def vals(args) |
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
eval_error "1st argument of assoc must be hashmap" unless head.is_a? Crisp::HashMap |
|
|
|
|
|
head.values.to_crisp_value |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.with_meta(args) |
|
|
|
|
|
t = args.first.dup |
|
|
|
|
|
t.meta = args[1] |
|
|
|
|
|
t |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def sequential?(args) |
|
|
|
|
|
args.first.unwrap.is_a? Array |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.atom(args) |
|
|
|
|
|
Crisp::Atom.new args.first |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def readline(args) |
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
eval_error "1st argument of readline must be string" unless head.is_a? String |
|
|
|
|
|
Readline.readline head |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.atom?(args) |
|
|
|
|
|
args.first.unwrap.is_a? Crisp::Atom |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def meta(args) |
|
|
|
|
|
m = args.first.meta |
|
|
|
|
|
m.nil? ? nil : m |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.deref(args) |
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
eval_error "1st argument of deref must be atom" unless head.is_a? Crisp::Atom |
|
|
|
|
|
head.val |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def with_meta(args) |
|
|
|
|
|
t = args.first.dup |
|
|
|
|
|
t.meta = args[1] |
|
|
|
|
|
t |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.reset!(args) |
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
eval_error "1st argument of reset! must be atom" unless head.is_a? Crisp::Atom |
|
|
|
|
|
head.val = args[1] |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def atom(args) |
|
|
|
|
|
Crisp::Atom.new args.first |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
def atom?(args) |
|
|
|
|
|
args.first.unwrap.is_a? Crisp::Atom |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def self.swap!(args) |
|
|
|
|
|
atom = args.first.unwrap |
|
|
|
|
|
eval_error "1st argument of swap! must be atom" unless atom.is_a? Crisp::Atom |
|
|
|
|
|
|
|
|
def deref(args) |
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
eval_error "1st argument of deref must be atom" unless head.is_a? Crisp::Atom |
|
|
|
|
|
head.val |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
a = [atom.val] + args[2..-1] |
|
|
|
|
|
|
|
|
def reset!(args) |
|
|
|
|
|
head = args.first.unwrap |
|
|
|
|
|
eval_error "1st argument of reset! must be atom" unless head.is_a? Crisp::Atom |
|
|
|
|
|
head.val = args[1] |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
func = args[1].unwrap |
|
|
|
|
|
case func |
|
|
|
|
|
when Crisp::Func |
|
|
|
|
|
atom.val = func.call a |
|
|
|
|
|
when Crisp::Closure |
|
|
|
|
|
atom.val = func.fn.call a |
|
|
|
|
|
else |
|
|
|
|
|
eval_error "2nd argumetn of swap! must be function" |
|
|
|
|
|
|
|
|
def swap!(args) |
|
|
|
|
|
atom = args.first.unwrap |
|
|
|
|
|
eval_error "1st argument of swap! must be atom" unless atom.is_a? Crisp::Atom |
|
|
|
|
|
|
|
|
|
|
|
a = [atom.val] + args[2..-1] |
|
|
|
|
|
|
|
|
|
|
|
func = args[1].unwrap |
|
|
|
|
|
case func |
|
|
|
|
|
when Crisp::Func |
|
|
|
|
|
atom.val = func.call a |
|
|
|
|
|
when Crisp::Closure |
|
|
|
|
|
atom.val = func.fn.call a |
|
|
|
|
|
else |
|
|
|
|
|
eval_error "2nd argumetn of swap! must be function" |
|
|
|
|
|
end |
|
|
end |
|
|
end |
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
def self.conj(args) |
|
|
|
|
|
seq = args.first.unwrap |
|
|
|
|
|
case seq |
|
|
|
|
|
when Crisp::List |
|
|
|
|
|
(args[1..-1].reverse + seq).to_crisp_value |
|
|
|
|
|
when Crisp::Vector |
|
|
|
|
|
(seq + args[1..-1]).to_crisp_value(Crisp::Vector) |
|
|
|
|
|
else |
|
|
|
|
|
eval_error "1st argument of conj must be list or vector" |
|
|
|
|
|
|
|
|
def conj(args) |
|
|
|
|
|
seq = args.first.unwrap |
|
|
|
|
|
case seq |
|
|
|
|
|
when Crisp::List |
|
|
|
|
|
(args[1..-1].reverse + seq).to_crisp_value |
|
|
|
|
|
when Crisp::Vector |
|
|
|
|
|
(seq + args[1..-1]).to_crisp_value(Crisp::Vector) |
|
|
|
|
|
else |
|
|
|
|
|
eval_error "1st argument of conj must be list or vector" |
|
|
|
|
|
end |
|
|
end |
|
|
end |
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
def self.time_ms(args) |
|
|
|
|
|
(Time.now.to_i.to_i32) * 1000 |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
def time_ms(args) |
|
|
|
|
|
(Time.now.to_i.to_i32) * 1000 |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
# Note: |
|
|
|
|
|
# Simply using ->self.some_func doesn't work |
|
|
|
|
|
macro func(name) |
|
|
|
|
|
-> (args : Array(Crisp::Type)) { Crisp::Type.new self.{{name.id}}(args) } |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
# Note: |
|
|
|
|
|
# Simply using ->self.some_func doesn't work |
|
|
|
|
|
macro func(name) |
|
|
|
|
|
-> (args : Array(Crisp::Type)) { Crisp::Type.new self.{{name.id}}(args) } |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
macro rel_op(op) |
|
|
|
|
|
-> (args : Array(Crisp::Type)) { Crisp::Type.new (args[0] {{op.id}} args[1]) } |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
macro rel_op(op) |
|
|
|
|
|
-> (args : Array(Crisp::Type)) { Crisp::Type.new (args[0] {{op.id}} args[1]) } |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
o">NS = { |
|
|
|
|
|
"+" => calc_op(:+) |
|
|
|
|
|
"-" => calc_op(:-) |
|
|
|
|
|
"*" => calc_op(:*) |
|
|
|
|
|
"/" => calc_op(:/) |
|
|
|
|
|
"list" => func(:list) |
|
|
|
|
|
"list?" => func(:list?) |
|
|
|
|
|
"empty?" => func(:empty?) |
|
|
|
|
|
"count" => func(:count) |
|
|
|
|
|
"=" => rel_op(:==) |
|
|
|
|
|
"<" => rel_op(:<) |
|
|
|
|
|
">" => rel_op(:>) |
|
|
|
|
|
"<=" => rel_op(:<=) |
|
|
|
|
|
">=" => rel_op(:>=) |
|
|
|
|
|
"pr-str" => func(:pr_str_) |
|
|
|
|
|
"str" => func(:str) |
|
|
|
|
|
"prn" => func(:prn) |
|
|
|
|
|
"println" => func(:println) |
|
|
|
|
|
"read-string" => func(:read_string) |
|
|
|
|
|
"slurp" => func(:slurp) |
|
|
|
|
|
"cons" => func(:cons) |
|
|
|
|
|
"concat" => func(:concat) |
|
|
|
|
|
"nth" => func(:nth) |
|
|
|
|
|
"first" => func(:first) |
|
|
|
|
|
"rest" => func(:rest) |
|
|
|
|
|
"throw" => -> (args : Array(Crisp::Type)) { raise Crisp::RuntimeException.new args[0] } |
|
|
|
|
|
"apply" => func(:apply) |
|
|
|
|
|
"map" => func(:map) |
|
|
|
|
|
"nil?" => func(:nil?) |
|
|
|
|
|
"true?" => func(:true?) |
|
|
|
|
|
"false?" => func(:false?) |
|
|
|
|
|
"symbol?" => func(:symbol?) |
|
|
|
|
|
"symbol" => func(:symbol) |
|
|
|
|
|
"keyword" => func(:keyword) |
|
|
|
|
|
"keyword?" => func(:keyword?) |
|
|
|
|
|
"vector" => func(:vector) |
|
|
|
|
|
"vector?" => func(:vector?) |
|
|
|
|
|
"hash-map" => func(:hash_map) |
|
|
|
|
|
"map?" => func(:map?) |
|
|
|
|
|
"assoc" => func(:assoc) |
|
|
|
|
|
"dissoc" => func(:dissoc) |
|
|
|
|
|
"get" => func(:get) |
|
|
|
|
|
"contains?" => func(:contains?) |
|
|
|
|
|
"keys" => func(:keys) |
|
|
|
|
|
"vals" => func(:vals) |
|
|
|
|
|
"sequential?" => func(:sequential?) |
|
|
|
|
|
"readline" => func(:readline) |
|
|
|
|
|
"meta" => func(:meta) |
|
|
|
|
|
"with-meta" => func(:with_meta) |
|
|
|
|
|
"atom" => func(:atom) |
|
|
|
|
|
"atom?" => func(:atom?) |
|
|
|
|
|
"deref" => func(:deref) |
|
|
|
|
|
"deref" => func(:deref) |
|
|
|
|
|
"reset!" => func(:reset!) |
|
|
|
|
|
"swap!" => func(:swap!) |
|
|
|
|
|
"conj" => func(:conj) |
|
|
|
|
|
"time-ms" => func(:time_ms) |
|
|
|
|
|
} of String => Crisp::Func |
|
|
|
|
|
|
|
|
NameSpace = { |
|
|
|
|
|
"+" => calc_op(:+) |
|
|
|
|
|
"-" => calc_op(:-) |
|
|
|
|
|
"*" => calc_op(:*) |
|
|
|
|
|
"/" => calc_op(:/) |
|
|
|
|
|
"list" => func(:list) |
|
|
|
|
|
"list?" => func(:list?) |
|
|
|
|
|
"empty?" => func(:empty?) |
|
|
|
|
|
"count" => func(:count) |
|
|
|
|
|
"=" => rel_op(:==) |
|
|
|
|
|
"<" => rel_op(:<) |
|
|
|
|
|
">" => rel_op(:>) |
|
|
|
|
|
"<=" => rel_op(:<=) |
|
|
|
|
|
">=" => rel_op(:>=) |
|
|
|
|
|
"pr-str" => func(:pr_str_) |
|
|
|
|
|
"str" => func(:str) |
|
|
|
|
|
"prn" => func(:prn) |
|
|
|
|
|
"println" => func(:println) |
|
|
|
|
|
"read-string" => func(:read_string) |
|
|
|
|
|
"slurp" => func(:slurp) |
|
|
|
|
|
"cons" => func(:cons) |
|
|
|
|
|
"concat" => func(:concat) |
|
|
|
|
|
"nth" => func(:nth) |
|
|
|
|
|
"first" => func(:first) |
|
|
|
|
|
"rest" => func(:rest) |
|
|
|
|
|
"throw" => -> (args : Array(Crisp::Type)) { raise Crisp::RuntimeException.new args[0] } |
|
|
|
|
|
"apply" => func(:apply) |
|
|
|
|
|
"map" => func(:map) |
|
|
|
|
|
"nil?" => func(:nil?) |
|
|
|
|
|
"true?" => func(:true?) |
|
|
|
|
|
"false?" => func(:false?) |
|
|
|
|
|
"symbol?" => func(:symbol?) |
|
|
|
|
|
"symbol" => func(:symbol) |
|
|
|
|
|
"keyword" => func(:keyword) |
|
|
|
|
|
"keyword?" => func(:keyword?) |
|
|
|
|
|
"vector" => func(:vector) |
|
|
|
|
|
"vector?" => func(:vector?) |
|
|
|
|
|
"hash-map" => func(:hash_map) |
|
|
|
|
|
"map?" => func(:map?) |
|
|
|
|
|
"assoc" => func(:assoc) |
|
|
|
|
|
"dissoc" => func(:dissoc) |
|
|
|
|
|
"get" => func(:get) |
|
|
|
|
|
"contains?" => func(:contains?) |
|
|
|
|
|
"keys" => func(:keys) |
|
|
|
|
|
"vals" => func(:vals) |
|
|
|
|
|
"sequential?" => func(:sequential?) |
|
|
|
|
|
"readline" => func(:readline) |
|
|
|
|
|
"meta" => func(:meta) |
|
|
|
|
|
"with-meta" => func(:with_meta) |
|
|
|
|
|
"atom" => func(:atom) |
|
|
|
|
|
"atom?" => func(:atom?) |
|
|
|
|
|
"deref" => func(:deref) |
|
|
|
|
|
"deref" => func(:deref) |
|
|
|
|
|
"reset!" => func(:reset!) |
|
|
|
|
|
"swap!" => func(:swap!) |
|
|
|
|
|
"conj" => func(:conj) |
|
|
|
|
|
"time-ms" => func(:time_ms) |
|
|
|
|
|
} of String => Crisp::Func |
|
|
|
|
|
|
|
|
end |
|
|
end |