Skip to content

Instantly share code, notes, and snippets.

@atton
Forked from tompng/lisp2.rb
Last active December 15, 2015 17:59
Show Gist options
  • Save atton/5300354 to your computer and use it in GitHub Desktop.
Save atton/5300354 to your computer and use it in GitHub Desktop.
require './lisp_base.rb'
LISP do (cons 1,2) end
LISP do (cond true,(cond false,(cons 1,2),(cons 3,4)),(cons 5,6)) end
LISP do (defun :fact,:x,(cond (eq :x,0),1,(mult (sqrt (square :x)),(fact (minus :x,1))))) end
LISP do (defun :abs,:x,(cond (lt :x,0),(minus 0,:x),:x)) end
LISP do
(defun :sqrtrec,:x,:y,:d,
(cond (lt :d,0.0000000001),
:y,
(cond (lt (mult :y,:y),:x),
(sqrtrec :x,(add :y,:d),(mult :d,0.5)),
(sqrtrec :x,(minus :y,:d),(mult :d,0.5))
)
)
)
end
LISP do (defun :sqrt,:x,(sqrtrec :x,:x,:x)) end
LISP do (defun :square,(mult :x,:x)) end
LISP do (fact 5) end
LISP do (defun :x, 3) end # likes to let ...?
LISP do (x) end # can call
# LISP do (defun) end # raise argument error
# LISP do (defun :method) end # raise argument error
LISP do (defun :run, :x, (cond (lt :x,10),"lt 10","ge 10")) end # can define 'run' method
LISP do (run 100) end # can call
LISP do (run 1) end # can call
class LispEvaluator
class Parser < BasicObject
def method_missing name,*args
{name:name,args:args}
end
end
class ChainHash
def initialize hash
@parent = hash
@hash = { }
end
def []= key,value
@hash[key] = value
end
def [] key
@hash[key] || @parent[key]
end
end
def run code, hash
if code.class == Symbol
hash[code]
elsif code.class == Hash
@methods[code[:name]].call hash, *code[:args]
else
code
end
end
def parse &block
@parser.instance_eval(&block)
end
def initialize_embedded_methods
@methods[:defun] = -> (hash, *definitions) {
raise "defun arguments require method_name, *args(optional), code" if definitions.size < 2
method_name = definitions.shift
method_code = definitions.pop
method_args = definitions
@methods[method_name] = -> (hash, *args) {
hash = ChainHash.new hash
method_args.zip(args).each{ |key, code|
hash[key] = run code, hash
}
run method_code, hash
}
true
}
@methods[:cond]=->(hash,a,b,c){
if run a,hash
run b,hash
else
run c,hash
end
}
@methods[:cons]=->(hash,a,b){
[run(a,hash),run(b,hash)]
}
@methods[:eq]=->(hash,a,b){
run(a,hash)==run(b,hash)
}
@methods[:mult]=->(hash,a,b){
run(a,hash)*run(b,hash)
}
@methods[:minus]=->(hash,a,b){
run(a,hash)-run(b,hash)
}
@methods[:add]=->(hash,a,b){
run(a,hash)+run(b,hash)
}
@methods[:lt]=->(hash,a,b){
run(a,hash)<run(b,hash)
}
@methods[:le]=->(hash,a,b){
run(a,hash)>run(b,hash)
}
end
def initialize
@parser = Parser.new
@methods={ }
initialize_embedded_methods
end
end
@lispevaluator = LispEvaluator.new
def LISP(&block)
code = @lispevaluator.parse(&block)
p @lispevaluator.run(code,{})
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment