Browse Source

fix code style and missing module specification

master
rhysd 9 years ago
parent
commit
ebd767a57d
6 changed files with 165 additions and 166 deletions
  1. +36
    -36
      src/crisp/core.cr
  2. +5
    -5
      src/crisp/env.cr
  3. +2
    -2
      src/crisp/error.cr
  4. +93
    -93
      src/crisp/interpreter.cr
  5. +18
    -19
      src/crisp/printer.cr
  6. +11
    -11
      src/crisp/reader.cr

+ 36
- 36
src/crisp/core.cr View File

@ -12,7 +12,7 @@ module Crisp
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.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
@ -38,7 +38,7 @@ module Crisp
when Nil
0
else
eval_error "invalid argument for function 'count'"
Crisp.eval_error "invalid argument for function 'count'"
end
end
@ -62,38 +62,38 @@ module Crisp
def read_string(args)
head = args.first.unwrap
eval_error "argument of read-str must be string" unless head.is_a? String
Crisp.eval_error "argument of read-str must be string" unless head.is_a? String
read_str head
end
def slurp(args)
head = args.first.unwrap
eval_error "argument of slurp must be string" unless head.is_a? String
Crisp.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"
Crisp.eval_error "no such file"
end
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
Crisp.eval_error "2nd arg of cons must be list" unless tail.is_a? Array
([head] + tail).to_crisp_value
end
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)
Crisp.eval_error "arguments of concat must be list" unless a.is_a?(Array)
a.each{|e| list << e}
end
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
Crisp.eval_error "1st argument of nth must be list or vector" unless a0.is_a? Array
Crisp.eval_error "2nd argument of nth must be integer" unless a1.is_a? Int32
a0[a1]
end
@ -101,7 +101,7 @@ module Crisp
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
Crisp.eval_error "1st argument of first must be list or vector or nil" unless a0.is_a? Array
a0.empty? ? nil : a0.first
end
@ -109,18 +109,18 @@ module Crisp
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
Crisp.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 apply(args)
eval_error "apply must take at least 2 arguments" unless args.size >= 2
Crisp.eval_error "apply must take at least 2 arguments" unless args.size >= 2
head = args.first.unwrap
last = args.last.unwrap
eval_error "last argument of apply must be list or vector" unless last.is_a? Array
Crisp.eval_error "last argument of apply must be list or vector" unless last.is_a? Array
case head
when Crisp::Closure
@ -128,7 +128,7 @@ module Crisp
when Crisp::Func
head.call(args[1..-2] + last)
else
eval_error "1st argument of apply must be function or closure"
Crisp.eval_error "1st argument of apply must be function or closure"
end
end
@ -136,12 +136,12 @@ module Crisp
func = args.first.unwrap
list = args[1].unwrap
eval_error "2nd argument of map must be list or vector" unless list.is_a? Array
Crisp.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"
else Crisp.eval_error "1st argument of map must be function"
end
list.each_with_object(Crisp::List.new) do |elem, mapped|
@ -169,13 +169,13 @@ module Crisp
def symbol(args)
head = args.first.unwrap
eval_error "1st argument of symbol function must be string" unless head.is_a? String
Crisp.eval_error "1st argument of symbol function must be string" unless head.is_a? String
Crisp::Symbol.new head
end
def keyword(args)
head = args.first.unwrap
eval_error "1st argument of symbol function must be string" unless head.is_a? String
Crisp.eval_error "1st argument of symbol function must be string" unless head.is_a? String
"\u029e" + head
end
@ -193,11 +193,11 @@ module Crisp
end
def hash_map(args)
eval_error "hash-map must take even number of arguments" unless args.size.even?
Crisp.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
Crisp.eval_error "key must be string" unless k.is_a? String
map[k] = kv[1]
end
map
@ -209,15 +209,15 @@ module Crisp
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?
Crisp.eval_error "1st argument of assoc must be hashmap" unless head.is_a? Crisp::HashMap
Crisp.eval_error "assoc must take a list and even number of arguments" unless (args.size - 1).even?
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
Crisp.eval_error "key must be string" unless k.is_a? String
map[k] = kv[1]
end
@ -226,14 +226,14 @@ module Crisp
def dissoc(args)
head = args.first.unwrap
eval_error "1st argument of assoc must be hashmap" unless head.is_a? Crisp::HashMap
Crisp.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}
args[1..-1].each do |arg|
key = arg.unwrap
eval_error "key must be string" unless key.is_a? String
Crisp.eval_error "key must be string" unless key.is_a? String
map.delete key
end
@ -243,7 +243,7 @@ module Crisp
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
Crisp.eval_error "2nd argument of get must be string" unless a1.is_a? String
# a0[a1]? isn't available because type ofa0[a1] is infered NoReturn
a0.has_key?(a1) ? a0[a1] : nil
@ -251,20 +251,20 @@ module Crisp
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
Crisp.eval_error "1st argument of get must be hashmap" unless a0.is_a? Crisp::HashMap
Crisp.eval_error "2nd argument of get must be string" unless a1.is_a? String
a0.has_key? a1
end
def keys(args)
head = args.first.unwrap
eval_error "1st argument of assoc must be hashmap" unless head.is_a? Crisp::HashMap
Crisp.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 vals(args)
head = args.first.unwrap
eval_error "1st argument of assoc must be hashmap" unless head.is_a? Crisp::HashMap
Crisp.eval_error "1st argument of assoc must be hashmap" unless head.is_a? Crisp::HashMap
head.values.to_crisp_value
end
@ -274,7 +274,7 @@ module Crisp
def readline(args)
head = args.first.unwrap
eval_error "1st argument of readline must be string" unless head.is_a? String
Crisp.eval_error "1st argument of readline must be string" unless head.is_a? String
Readline.readline head
end
@ -299,19 +299,19 @@ module Crisp
def deref(args)
head = args.first.unwrap
eval_error "1st argument of deref must be atom" unless head.is_a? Crisp::Atom
Crisp.eval_error "1st argument of deref must be atom" unless head.is_a? Crisp::Atom
head.val
end
def reset!(args)
head = args.first.unwrap
eval_error "1st argument of reset! must be atom" unless head.is_a? Crisp::Atom
Crisp.eval_error "1st argument of reset! must be atom" unless head.is_a? Crisp::Atom
head.val = args[1]
end
def swap!(args)
atom = args.first.unwrap
eval_error "1st argument of swap! must be atom" unless atom.is_a? Crisp::Atom
Crisp.eval_error "1st argument of swap! must be atom" unless atom.is_a? Crisp::Atom
a = [atom.val] + args[2..-1]
@ -322,7 +322,7 @@ module Crisp
when Crisp::Closure
atom.val = func.fn.call a
else
eval_error "2nd argumetn of swap! must be function"
Crisp.eval_error "2nd argumetn of swap! must be function"
end
end
@ -334,7 +334,7 @@ module Crisp
when Crisp::Vector
(seq + args[1..-1]).to_crisp_value(Crisp::Vector)
else
eval_error "1st argument of conj must be list or vector"
Crisp.eval_error "1st argument of conj must be list or vector"
end
end

+ 5
- 5
src/crisp/env.cr View File

@ -13,18 +13,18 @@ module Crisp
def initialize(@outer, binds, exprs : Array(Crisp::Type))
@data = {} of String => Crisp::Type
eval_error "binds must be list or vector" unless binds.is_a? Array
Crisp.eval_error "binds must be list or vector" unless binds.is_a? Array
# Note:
# Array#zip() can't be used because overload resolution failed
(0...binds.size).each do |idx|
sym = binds[idx].unwrap
eval_error "bind name must be symbol" unless sym.is_a? Crisp::Symbol
Crisp.eval_error "bind name must be symbol" unless sym.is_a? Crisp::Symbol
if sym.str == "&"
eval_error "missing variable parameter name" if binds.size == idx
Crisp.eval_error "missing variable parameter name" if binds.size == idx
next_param = binds[idx+1].unwrap
eval_error "bind name must be symbol" unless next_param.is_a? Crisp::Symbol
Crisp.eval_error "bind name must be symbol" unless next_param.is_a? Crisp::Symbol
var_args = Crisp::List.new
exprs[idx..-1].each{|e| var_args << e} if idx < exprs.size
@data[next_param.str] = Crisp::Type.new var_args
@ -59,7 +59,7 @@ module Crisp
def get(key)
e = find key
eval_error "'#{key}' not found" unless e
Crisp.eval_error "'#{key}' not found" unless e
e.data[key]
end
end

+ 2
- 2
src/crisp/error.cr View File

@ -14,11 +14,11 @@ module Crisp
end
end
def self.eval_error(msg)
def eval_error(msg)
raise Crisp::EvalException.new msg
end
def self.parse_error(msg)
def parse_error(msg)
raise Crisp::ParseException.new msg
end
end

+ 93
- 93
src/crisp/interpreter.cr View File

@ -40,90 +40,90 @@ module Crisp
end
def func_of(env, binds, body)
-> (args : Array(Crisp::Type)) {
new_env = Crisp::Env.new(env, binds, args)
eval(body, new_env)
} as Crisp::Func
-> (args : Array(Crisp::Type)) {
new_env = Crisp::Env.new(env, binds, args)
eval(body, new_env)
} as Crisp::Func
end
def eval_ast(ast, env)
return ast.map{|n| eval(n, env) as Crisp::Type} if ast.is_a? Array
return ast.map{|n| eval(n, env) as Crisp::Type} if ast.is_a? Array
val = ast.unwrap
val = ast.unwrap
Crisp::Type.new case val
when Crisp::Symbol
Crisp::Type.new case val
when Crisp::Symbol
if e = env.get(val.str)
e
else
eval_error "'#{val.str}' not found"
Crisp.eval_error "'#{val.str}' not found"
end
when Crisp::List
when Crisp::List
val.each_with_object(Crisp::List.new){|n, l| l << eval(n, env)}
when Crisp::Vector
when Crisp::Vector
val.each_with_object(Crisp::Vector.new){|n, l| l << eval(n, env)}
when Crisp::HashMap
when Crisp::HashMap
new_map = Crisp::HashMap.new
val.each{|k, v| new_map[k] = eval(v, env)}
new_map
else
else
val
end
end
end
def read(str)
read_str str
read_str str
end
macro pair?(list)
{{list}}.is_a?(Array) && !{{list}}.empty?
{{list}}.is_a?(Array) && !{{list}}.empty?
end
def quasiquote(ast)
list = ast.unwrap
list = ast.unwrap
unless pair?(list)
return Crisp::Type.new(
Crisp::List.new << gen_type(Crisp::Symbol, "quote") << ast
)
end
unless pair?(list)
return Crisp::Type.new(
Crisp::List.new << gen_type(Crisp::Symbol, "quote") << ast
)
end
head = list.first.unwrap
head = list.first.unwrap
case
# ("unquote" ...)
when head.is_a?(Crisp::Symbol) && head.str == "unquote"
case
# ("unquote" ...)
when head.is_a?(Crisp::Symbol) && head.str == "unquote"
list[1]
# (("splice-unquote" ...) ...)
when pair?(head) && (arg0 = head.first.unwrap).is_a?(Crisp::Symbol) && arg0.str == "splice-unquote"
# (("splice-unquote" ...) ...)
when pair?(head) && (arg0 = head.first.unwrap).is_a?(Crisp::Symbol) && arg0.str == "splice-unquote"
tail = Crisp::Type.new list[1..-1].to_crisp_value
Crisp::Type.new(
Crisp::List.new << gen_type(Crisp::Symbol, "concat") << head[1] << quasiquote(tail)
Crisp::List.new << gen_type(Crisp::Symbol, "concat") << head[1] << quasiquote(tail)
)
else
else
tail = Crisp::Type.new list[1..-1].to_crisp_value
Crisp::Type.new(
Crisp::List.new << gen_type(Crisp::Symbol, "cons") << quasiquote(list.first) << quasiquote(tail)
Crisp::List.new << gen_type(Crisp::Symbol, "cons") << quasiquote(list.first) << quasiquote(tail)
)
end
end
end
def macro_call?(ast, env)
list = ast.unwrap
return false unless list.is_a? Crisp::List
return false if list.empty?
list = ast.unwrap
return false unless list.is_a? Crisp::List
return false if list.empty?
sym = list.first.unwrap
return false unless sym.is_a? Crisp::Symbol
sym = list.first.unwrap
return false unless sym.is_a? Crisp::Symbol
func = env.find(sym.str).try(&.data[sym.str])
return false unless func && func.macro?
func = env.find(sym.str).try(&.data[sym.str])
return false unless func && func.macro?
true
true
end
def macroexpand(ast, env)
while macro_call?(ast, env)
while macro_call?(ast, env)
# Already checked in macro_call?
list = ast.unwrap as Crisp::List
@ -132,41 +132,41 @@ module Crisp
case func
when Crisp::Func
ast = func.call(list[1..-1])
ast = func.call(list[1..-1])
when Crisp::Closure
ast = func.fn.call(list[1..-1])
ast = func.fn.call(list[1..-1])
else
eval_error "macro '#{func_sym.str}' must be function: #{ast}"
end
Crisp.eval_error "macro '#{func_sym.str}' must be function: #{ast}"
end
end
ast
ast
end
macro invoke_list(l, env)
f = eval({{l}}.first, {{env}}).unwrap
args = eval_ast({{l}}[1..-1], {{env}}) as Array
f = eval({{l}}.first, {{env}}).unwrap
args = eval_ast({{l}}[1..-1], {{env}}) as Array
case f
when Crisp::Closure
case f
when Crisp::Closure
ast = f.ast
{{env}} = Crisp::Env.new(f.env, f.params, args)
next # TCO
when Crisp::Func
when Crisp::Func
return f.call args
else
eval_error "expected function as the first argument: #{f}"
end
else
Crisp.eval_error "expected function as the first argument: #{f}"
end
end
def debug(ast)
puts print(ast).colorize.red
puts print(ast).colorize.red
end
def eval(ast, env)
# 'next' in 'do...end' has a bug in crystal 0.7.1
# https://github.com/manastech/crystal/issues/659
while true
# 'next' in 'do...end' has a bug in crystal 0.7.1
# https://github.com/manastech/crystal/issues/659
while true
return eval_ast(ast, env) unless ast.unwrap.is_a? Crisp::List
ast = macroexpand(ast, env)
@ -181,63 +181,63 @@ module Crisp
return invoke_list(list, env) unless head.is_a? Crisp::Symbol
return Crisp::Type.new case head.str
when "def!"
eval_error "wrong number of argument for 'def!'" unless list.size == 3
when "def!"
Crisp.eval_error "wrong number of argument for 'def!'" unless list.size == 3
a1 = list[1].unwrap
eval_error "1st argument of 'def!' must be symbol: #{a1}" unless a1.is_a? Crisp::Symbol
Crisp.eval_error "1st argument of 'def!' must be symbol: #{a1}" unless a1.is_a? Crisp::Symbol
env.set(a1.str, eval(list[2], env))
when "let*"
eval_error "wrong number of argument for 'def!'" unless list.size == 3
when "let*"
Crisp.eval_error "wrong number of argument for 'def!'" unless list.size == 3
bindings = list[1].unwrap
eval_error "1st argument of 'let*' must be list or vector" unless bindings.is_a? Array
eval_error "size of binding list must be even" unless bindings.size.even?
Crisp.eval_error "1st argument of 'let*' must be list or vector" unless bindings.is_a? Array
Crisp.eval_error "size of binding list must be even" unless bindings.size.even?
new_env = Crisp::Env.new env
bindings.each_slice(2) do |binding|
key, value = binding
name = key.unwrap
eval_error "name of binding must be specified as symbol #{name}" unless name.is_a? Crisp::Symbol
new_env.set(name.str, eval(value, new_env))
key, value = binding
name = key.unwrap
class="n">Crisp class="o">.eval_error "name of binding must be specified as symbol #{name}" unless name.is_a? Crisp::Symbol
new_env.set(name.str, eval(value, new_env))
end
ast, env = list[2], new_env
next # TCO
when "do"
when "do"
if list.empty?
ast = Crisp::Type.new nil
next
ast = Crisp::Type.new nil
next
end
eval_ast(list[1..-2].to_crisp_value, env)
ast = list.last
next # TCO
when "if"
when "if"
ast = unless eval(list[1], env).unwrap
list.size >= 4 ? list[3] : Crisp::Type.new(nil)
list.size >= 4 ? list[3] : Crisp::Type.new(nil)
else
list[2]
list[2]
end
next # TCO
when "fn*"
when "fn*"
params = list[1].unwrap
unless params.is_a? Array
eval_error "'fn*' parameters must be list or vector: #{params}"
class="n">Crisp class="o">.eval_error "'fn*' parameters must be list or vector: #{params}"
end
Crisp::Closure.new(list[2], params, env, func_of(env, params, list[2]))
when "quote"
when "quote"
list[1]
when "quasiquote"
when "quasiquote"
ast = quasiquote list[1]
next # TCO
when "defmacro!"
eval_error "wrong number of argument for 'defmacro!'" unless list.size == 3
when "defmacro!"
Crisp.eval_error "wrong number of argument for 'defmacro!'" unless list.size == 3
a1 = list[1].unwrap
eval_error "1st argument of 'defmacro!' must be symbol: #{a1}" unless a1.is_a? Crisp::Symbol
Crisp.eval_error "1st argument of 'defmacro!' must be symbol: #{a1}" unless a1.is_a? Crisp::Symbol
env.set(a1.str, eval(list[2], env).tap{|n| n.is_macro = true})
when "macroexpand"
when "macroexpand"
macroexpand(list[1], env)
when "try*"
when "try*"
catch_list = list[2].unwrap
return eval(list[1], env) unless catch_list.is_a? Crisp::List
@ -246,22 +246,22 @@ module Crisp
return eval(list[1], env) unless catch_head.str == "catch*"
begin
eval(list[1], env)
eval(list[1], env)
rescue e : Crisp::RuntimeException
new_env = Crisp::Env.new(env, [catch_list[1]], [e.thrown])
eval(catch_list[2], new_env)
new_env = Crisp::Env.new(env, [catch_list[1]], [e.thrown])
eval(catch_list[2], new_env)
rescue e
new_env = Crisp::Env.new(env, [catch_list[1]], [Crisp::Type.new e.message])
eval(catch_list[2], new_env)
new_env = Crisp::Env.new(env, [catch_list[1]], [Crisp::Type.new e.message])
eval(catch_list[2], new_env)
end
else
else
invoke_list(list, env)
end
end
end
end
end
def print(result)
@printer.print(result)
@printer.print(result)
end
def eval_string(str)

+ 18
- 19
src/crisp/printer.cr View File

@ -6,36 +6,35 @@ module Crisp
end
def print(value)
case value
when Nil then "nil"
when Bool then value.to_s
when Int32 then value.to_s
when Crisp::List then "(#{value.map{|v| print(v) as String}.join(" ")})"
when Crisp::Vector then "[#{value.map{|v| print(v) as String}.join(" ")}]"
when Crisp::Symbol then value.str.to_s
when Crisp::Func then "<function>"
when Crisp::Closure then "<closure>"
when Crisp::HashMap
# step1_read_print.cr requires specifying type
case value
when Nil then "nil"
when Bool then value.to_s
when Int32 then value.to_s
when Crisp::List then "(#{value.map{|v| print(v) as String}.join(" ")})"
when Crisp::Vector then "[#{value.map{|v| print(v) as String}.join(" ")}]"
when Crisp::Symbol then value.str.to_s
when Crisp::Func then "<function>"
when Crisp::Closure then "<closure>"
when Crisp::HashMap
"{#{value.map{|k, v| "#{print(k)} #{print(v)}"}.join(" ")}}"
when String
when String
case
when value.empty?()
@print_readably ? value.inspect : value
@print_readably ? value.inspect : value
when value[0] == '\u029e'
":#{value[1..-1]}"
":#{value[1..-1]}"
else
@print_readably ? value.inspect : value
@print_readably ? value.inspect : value
end
when Crisp::Atom
when Crisp::Atom
"(atom #{print(value.val)})"
else
else
raise "invalid CrispType: #{value.to_s}"
end
end
end
def print(t : Crisp::Type)
print(t.unwrap) + (t.macro? ? " (macro)" : "")
print(t.unwrap) + (t.macro? ? " (macro)" : "")
end
end
end

+ 11
- 11
src/crisp/reader.cr View File

@ -32,12 +32,12 @@ module Crisp
def read_sequence(init, open, close)
token = self.next
parse_error "expected '#{open}', got EOF" unless token
parse_error "expected '#{open}', got #{token}" unless token[0] == open
Crisp.parse_error "expected '#{open}', got EOF" unless token
Crisp.parse_error "expected '#{open}', got #{token}" unless token[0] == open
loop do
token = peek
parse_error "expected '#{close}', got EOF" unless token
Crisp.parse_error "expected '#{close}', got EOF" unless token
break if token[0] == close
init << read_form
@ -59,7 +59,7 @@ module Crisp
def read_hashmap
types = read_sequence([] of Crisp::Type, '{', '}')
parse_error "odd number of elements for hash-map: #{types.size}" if types.size.odd?
Crisp.parse_error "odd number of elements for hash-map: #{types.size}" if types.size.odd?
map = Crisp::HashMap.new
types.each_slice(2) do |kv|
@ -68,7 +68,7 @@ module Crisp
when String
map[k] = v
else
parse_error("key of hash-map must be string or keyword")
Crisp.parse_error("key of hash-map must be string or keyword")
end
end
@ -77,7 +77,7 @@ module Crisp
def read_atom
token = self.next
parse_error "expected Atom but got EOF" unless token
Crisp.parse_error "expected Atom but got EOF" unless token
Crisp::Type.new case
when token =~ /^-?\d+$/ then token.to_i
@ -97,16 +97,16 @@ module Crisp
def read_form
token = peek
parse_error "unexpected EOF" unless token
parse_error "unexpected comment" if token[0] == ';'
Crisp.parse_error "unexpected EOF" unless token
Crisp.parse_error "unexpected comment" if token[0] == ';'
Crisp::Type.new case token
when "(" then read_list
when ")" then parse_error "unexpected ')'"
when ")" then Crisp.parse_error "unexpected ')'"
when "[" then read_vector
when "]" then parse_error "unexpected ']'"
when "]" then Crisp.parse_error "unexpected ']'"
when "{" then read_hashmap
when "}" then parse_error "unexpected '}'"
when "}" then Crisp.parse_error "unexpected '}'"
when "'" then self.next; list_of("quote")
when "`" then self.next; list_of("quasiquote")
when "~" then self.next; list_of("unquote")

Loading…
Cancel
Save