Browse Source

Crisp::Type -> Crisp::Expr

master
rhysd 9 years ago
parent
commit
0c01804b7b
8 changed files with 55 additions and 55 deletions
  1. +2
    -2
      spec/crisp/interpreter_spec.cr
  2. +8
    -8
      src/crisp/core.cr
  3. +4
    -4
      src/crisp/env.cr
  4. +12
    -12
      src/crisp/evaluator.cr
  5. +6
    -6
      src/crisp/interpreter.cr
  6. +3
    -3
      src/crisp/printer.cr
  7. +6
    -6
      src/crisp/reader.cr
  8. +14
    -14
      src/crisp/types.cr

+ 2
- 2
spec/crisp/interpreter_spec.cr View File

@ -5,7 +5,7 @@ describe "Crisp::Interpreter" do
it "takes arguments as string value" do it "takes arguments as string value" do
i = Crisp::Interpreter.new %w(foo bar baz) i = Crisp::Interpreter.new %w(foo bar baz)
result = i.eval_string("*ARGV*") result = i.eval_string("*ARGV*")
result.should be_a(Crisp::Type)
result.should be_a(Crisp::Expr)
unwrapped = result.unwrap unwrapped = result.unwrap
unwrapped.should be_a(Crisp::List) unwrapped.should be_a(Crisp::List)
if unwrapped.is_a? Crisp::List if unwrapped.is_a? Crisp::List
@ -27,7 +27,7 @@ describe "Crisp::Interpreter" do
it "evaluates string of Crisp expression" do it "evaluates string of Crisp expression" do
i = Crisp::Interpreter.new i = Crisp::Interpreter.new
result = i.eval_string "(+ 1 2)" result = i.eval_string "(+ 1 2)"
result.should be_a(Crisp::Type)
result.should be_a(Crisp::Expr)
unwrapped = result.unwrap unwrapped = result.unwrap
unwrapped.should be_a(Int32) unwrapped.should be_a(Int32)
unwrapped.should eq(3) unwrapped.should eq(3)

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

@ -10,10 +10,10 @@ module Crisp
extend self extend self
macro calc_op(op) macro calc_op(op)
-> (args : Array(Crisp::Type)) {
-> (args : Array(Crisp::Expr)) {
x, y = args[0].unwrap, args[1].unwrap x, y = args[0].unwrap, args[1].unwrap
Crisp.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)
Crisp::Expr.new(x {{op.id}} y)
} }
end end
@ -77,7 +77,7 @@ module Crisp
end end
def cons(args) def cons(args)
head, tail = args[0] as Crisp::Type, args[1].unwrap
head, tail = args[0] as Crisp::Expr, args[1].unwrap
Crisp.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 ([head] + tail).to_crisp_value
end end
@ -245,7 +245,7 @@ module Crisp
return nil unless a0.is_a? Crisp::HashMap return nil unless a0.is_a? Crisp::HashMap
Crisp.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[a1]? isn't available because type of a0[a1] is inferred NoReturn
a0.has_key?(a1) ? a0[a1] : nil a0.has_key?(a1) ? a0[a1] : nil
end end
@ -259,7 +259,7 @@ module Crisp
def keys(args) def keys(args)
head = args.first.unwrap head = args.first.unwrap
Crisp.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)}
head.keys.each_with_object(Crisp::List.new){|e,l| l << Crisp::Expr.new(e)}
end end
def vals(args) def vals(args)
@ -345,11 +345,11 @@ module Crisp
# Note: # Note:
# Simply using ->self.some_func doesn't work # Simply using ->self.some_func doesn't work
macro func(name) macro func(name)
-> (args : Array(Crisp::Type)) { Crisp::Type.new self.{{name.id}}(args) }
-> (args : Array(Crisp::Expr)) { Crisp::Expr.new self.{{name.id}}(args) }
end end
macro rel_op(op) macro rel_op(op)
-> (args : Array(Crisp::Type)) { Crisp::Type.new (args[0] {{op.id}} args[1]) }
-> (args : Array(Crisp::Expr)) { Crisp::Expr.new (args[0] {{op.id}} args[1]) }
end end
NameSpace = { NameSpace = {
@ -377,7 +377,7 @@ module Crisp
"nth" => func(:nth) "nth" => func(:nth)
"first" => func(:first) "first" => func(:first)
"rest" => func(:rest) "rest" => func(:rest)
"throw" => -> (args : Array(Crisp::Type)) { raise Crisp::RuntimeException.new args[0] }
"throw" => -> (args : Array(Crisp::Expr)) { raise Crisp::RuntimeException.new args[0] }
"apply" => func(:apply) "apply" => func(:apply)
"map" => func(:map) "map" => func(:map)
"nil?" => func(:nil?) "nil?" => func(:nil?)

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

@ -7,11 +7,11 @@ module Crisp
property data property data
def initialize(@outer = nil) def initialize(@outer = nil)
@data = {} of String => Crisp::Type
@data = {} of String => Crisp::Expr
end end
def initialize(@outer, binds, exprs : Array(Crisp::Type))
@data = {} of String => Crisp::Type
def initialize(@outer, binds, exprs : Array(Crisp::Expr))
@data = {} of String => Crisp::Expr
Crisp.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
@ -27,7 +27,7 @@ module Crisp
Crisp.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 var_args = Crisp::List.new
exprs[idx..-1].each{|e| var_args << e} if idx < exprs.size exprs[idx..-1].each{|e| var_args << e} if idx < exprs.size
@data[next_param.str] = Crisp::Type.new var_args
@data[next_param.str] = Crisp::Expr.new var_args
break break
end end

+ 12
- 12
src/crisp/evaluator.cr View File

@ -12,18 +12,18 @@ module Crisp
class Evaluator class Evaluator
def func_of(env, binds, body) def func_of(env, binds, body)
-> (args : Array(Crisp::Type)) {
-> (args : Array(Crisp::Expr)) {
new_env = Crisp::Env.new(env, binds, args) new_env = Crisp::Env.new(env, binds, args)
eval(body, new_env) eval(body, new_env)
} as Crisp::Func } as Crisp::Func
end end
def eval_ast(ast, env) 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::Expr} if ast.is_a? Array
val = ast.unwrap val = ast.unwrap
Crisp::Type.new case val
Crisp::Expr.new case val
when Crisp::Symbol when Crisp::Symbol
if e = env.get(val.str) if e = env.get(val.str)
e e
@ -51,7 +51,7 @@ module Crisp
list = ast.unwrap list = ast.unwrap
unless pair?(list) unless pair?(list)
return Crisp::Type.new(
return Crisp::Expr.new(
Crisp::List.new << gen_type(Crisp::Symbol, "quote") << ast Crisp::List.new << gen_type(Crisp::Symbol, "quote") << ast
) )
end end
@ -64,13 +64,13 @@ module Crisp
list[1] list[1]
# (("splice-unquote" ...) ...) # (("splice-unquote" ...) ...)
when pair?(head) && (arg0 = head.first.unwrap).is_a?(Crisp::Symbol) && arg0.str == "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(
tail = Crisp::Expr.new list[1..-1].to_crisp_value
Crisp::Expr.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(
tail = Crisp::Expr.new list[1..-1].to_crisp_value
Crisp::Expr.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
@ -148,7 +148,7 @@ module Crisp
return invoke_list(list, env) unless head.is_a? Crisp::Symbol return invoke_list(list, env) unless head.is_a? Crisp::Symbol
return Crisp::Type.new case head.str
return Crisp::Expr.new case head.str
when "def!" when "def!"
Crisp.eval_error "wrong number of argument for 'def!'" unless list.size == 3 Crisp.eval_error "wrong number of argument for 'def!'" unless list.size == 3
a1 = list[1].unwrap a1 = list[1].unwrap
@ -173,7 +173,7 @@ module Crisp
next # TCO next # TCO
when "do" when "do"
if list.empty? if list.empty?
ast = Crisp::Type.new nil
ast = Crisp::Expr.new nil
next next
end end
@ -182,7 +182,7 @@ module Crisp
next # TCO next # TCO
when "if" when "if"
ast = unless eval(list[1], env).unwrap ast = unless eval(list[1], env).unwrap
list.size >= 4 ? list[3] : Crisp::Type.new(nil)
list.size >= 4 ? list[3] : Crisp::Expr.new(nil)
else else
list[2] list[2]
end end
@ -219,7 +219,7 @@ module Crisp
new_env = Crisp::Env.new(env, [catch_list[1]], [e.thrown]) new_env = Crisp::Env.new(env, [catch_list[1]], [e.thrown])
eval(catch_list[2], new_env) eval(catch_list[2], new_env)
rescue e rescue e
new_env = Crisp::Env.new(env, [catch_list[1]], [Crisp::Type.new e.message])
new_env = Crisp::Env.new(env, [catch_list[1]], [Crisp::Expr.new e.message])
eval(catch_list[2], new_env) eval(catch_list[2], new_env)
end end
else else

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

@ -17,8 +17,8 @@ module Crisp
@evaluator = Evaluator.new @evaluator = Evaluator.new
@env = Crisp::Env.new @env = Crisp::Env.new
Crisp::NameSpace.each{|k,v| @env.set(k, Crisp::Type.new(v))}
@env.set("eval", Crisp::Type.new -> (args: Array(Crisp::Type)){ @evaluator.eval(args[0], @env) })
Crisp::NameSpace.each{|k,v| @env.set(k, Crisp::Expr.new(v))}
@env.set("eval", Crisp::Expr.new -> (args: Array(Crisp::Expr)){ @evaluator.eval(args[0], @env) })
eval_string "(def! not (fn* (a) (if a false true)))" eval_string "(def! not (fn* (a) (if a false true)))"
eval_string "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))" eval_string "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))"
@ -30,11 +30,11 @@ module Crisp
if args if args
args.each do |a| args.each do |a|
argv << Crisp::Type.new a
argv << Crisp::Expr.new a
end end
end end
@env.set("*ARGV*", Crisp::Type.new argv)
@env.set("*ARGV*", Crisp::Expr.new argv)
end end
def read(str) def read(str)
@ -49,12 +49,12 @@ module Crisp
@evaluator.eval(read(str), @env) @evaluator.eval(read(str), @env)
end end
def eval(t : Crisp::Type)
def eval(t : Crisp::Expr)
@evaluator.eval(t, @env) @evaluator.eval(t, @env)
end end
def eval(val) def eval(val)
@evaluator.eval(Crisp::Type.new val, @env)
@evaluator.eval(Crisp::Expr.new val, @env)
end end
def run(filename = nil) def run(filename = nil)

+ 3
- 3
src/crisp/printer.cr View File

@ -29,12 +29,12 @@ module Crisp
when Crisp::Atom when Crisp::Atom
"(atom #{print(value.val)})" "(atom #{print(value.val)})"
else else
raise "invalid CrispType: #{value.to_s}"
raise "invalid CrispExpr: #{value.to_s}"
end end
end end
def print(t : Crisp::Type)
print(t.unwrap) + (t.macro? ? " (macro)" : "")
def print(e : Crisp::Expr)
print(e.unwrap) + (e.macro? ? " (macro)" : "")
end end
end end
end end

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

@ -49,15 +49,15 @@ module Crisp
end end
def read_list def read_list
Crisp::Type.new read_sequence(Crisp::List.new, '(', ')')
Crisp::Expr.new read_sequence(Crisp::List.new, '(', ')')
end end
def read_vector def read_vector
Crisp::Type.new read_sequence(Crisp::Vector.new, '[', ']')
Crisp::Expr.new read_sequence(Crisp::Vector.new, '[', ']')
end end
def read_hashmap def read_hashmap
types = read_sequence([] of Crisp::Type, '{', '}')
types = read_sequence([] of Crisp::Expr, '{', '}')
Crisp.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 map = Crisp::HashMap.new
@ -72,14 +72,14 @@ module Crisp
end end
end end
Crisp::Type.new map
Crisp::Expr.new map
end end
def read_atom def read_atom
token = self.next token = self.next
Crisp.parse_error "expected Atom but got EOF" unless token Crisp.parse_error "expected Atom but got EOF" unless token
Crisp::Type.new case
Crisp::Expr.new case
when token =~ /^-?\d+$/ then token.to_i when token =~ /^-?\d+$/ then token.to_i
when token == "true" then true when token == "true" then true
when token == "false" then false when token == "false" then false
@ -100,7 +100,7 @@ module Crisp
Crisp.parse_error "unexpected EOF" unless token Crisp.parse_error "unexpected EOF" unless token
Crisp.parse_error "unexpected comment" if token[0] == ';' Crisp.parse_error "unexpected comment" if token[0] == ';'
Crisp::Type.new case token
Crisp::Expr.new case token
when "(" then read_list when "(" then read_list
when ")" then Crisp.parse_error "unexpected ')'" when ")" then Crisp.parse_error "unexpected ')'"
when "[" then read_vector when "[" then read_vector

+ 14
- 14
src/crisp/types.cr View File

@ -13,13 +13,13 @@ module Crisp
end end
end end
class List < Array(Type)
class List < Array(Expr)
end end
class Vector < Array(Type)
class Vector < Array(Expr)
end end
class HashMap < Hash(String, Type)
class HashMap < Hash(String, Expr)
end end
class Atom class Atom
@ -38,21 +38,21 @@ module Crisp
end end
end end
class Type
alias Func = (Array(Type) -> Type)
alias ValueType = Nil | Bool | Int32 | String | Symbol | List | Vector | HashMap | Func | Closure | Atom
class Expr
alias Func = (Array(Expr) -> Expr)
alias ValueExpr = Nil | Bool | Int32 | String | Symbol | List | Vector | HashMap | Func | Closure | Atom
is_macro :: Bool is_macro :: Bool
meta :: Type
meta :: Expr
property :is_macro, :meta property :is_macro, :meta
def initialize(@val : ValueType)
def initialize(@val : ValueExpr)
@is_macro = false @is_macro = false
@meta = nil @meta = nil
end end
def initialize(other : Type)
def initialize(other : Expr)
@val = other.unwrap @val = other.unwrap
@is_macro = other.is_macro @is_macro = other.is_macro
@meta = other.meta @meta = other.meta
@ -71,19 +71,19 @@ module Crisp
end end
def dup def dup
Type.new(@val).tap do |t|
Expr.new(@val).tap do |t|
t.is_macro = @is_macro t.is_macro = @is_macro
t.meta = @meta t.meta = @meta
end end
end end
def ==(other : Type)
def ==(other : Expr)
@val == other.unwrap @val == other.unwrap
end end
macro rel_op(*ops) macro rel_op(*ops)
{% for op in ops %} {% for op in ops %}
def {{op.id}}(other : Crisp::Type)
def {{op.id}}(other : Crisp::Expr)
l, r = @val, other.unwrap l, r = @val, other.unwrap
{% for t in [Int32, String] %} {% for t in [Int32, String] %}
if l.is_a?({{t}}) && r.is_a?({{t}}) if l.is_a?({{t}}) && r.is_a?({{t}})
@ -101,11 +101,11 @@ module Crisp
rel_op :<, :>, :<=, :>= rel_op :<, :>, :<=, :>=
end end
alias Func = Type::Func
alias Func = Expr::Func
end end
macro gen_type(t, *args) macro gen_type(t, *args)
Crisp::Type.new {{t.id}}.new({{*args}})
Crisp::Expr.new {{t.id}}.new({{*args}})
end end
class Array class Array

Loading…
Cancel
Save