Created
April 5, 2012 02:06
-
-
Save dcluna/2307427 to your computer and use it in GitHub Desktop.
Lisp in Ruby
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class Risp | |
| @@envs = [] | |
| def initialize | |
| define_environment({}) | |
| end | |
| def eval(arg) | |
| if arg.is_a? Symbol # accessor | |
| @env[arg] | |
| elsif !arg.is_a? Array # atom - is not a list | |
| arg | |
| elsif is_quote? arg # [:quote, <other-stuff>] | |
| arg[1..-1] # 'quote' uses the list as-is (prevents evaluation) | |
| elsif is_if? arg # [:] | |
| body = eval(arg[1]) ? arg[2] : arg[3] # if 1 then do 2; else do 3 | |
| eval body | |
| elsif is_set? arg | |
| @env[arg[1]] = eval arg[2] | |
| elsif is_lambda? arg # [:lambda, [<bindings, as symbols>], <body> ] | |
| instance_eval "lambda {|#{arg[1].join ","}| eval arg[2]}" # cool trick bro | |
| else | |
| puts 'Command not recognized' | |
| end | |
| end | |
| private | |
| def define_environment(old_bindings) | |
| @env = old_bindings | |
| @@envs.push @env | |
| end | |
| def is_quote?(elem) | |
| elem.first == :quote | |
| end | |
| def is_if?(elem) | |
| elem.first == :if && elem.length >= 3 | |
| end | |
| def is_set?(elem) | |
| elem[0] == :set! && elem[1].is_a?(Symbol) && elem.length == 3 | |
| end | |
| def is_lambda?(elem) | |
| elem.first == :lambda && | |
| elem[1].is_a?(Array) && elem[1].all? {|binding| binding.is_a? Symbol } | |
| end | |
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| def eval_sexp(sexp) | |
| return sexp unless sexp.instance_of? Array | |
| command = sexp.first | |
| args = sexp.drop 1 | |
| if command.instance_of?(Symbol) # send msg to objects | |
| args.map! { |arg| eval_sexp arg } | |
| call_command command, :arguments => args | |
| else | |
| sexp.map { |arg| eval_sexp arg } | |
| end | |
| end | |
| private | |
| def call_command(command,params) | |
| args = params[:arguments] | |
| return command.call(args) if command.instance_of? Proc | |
| if args.length > 2 | |
| argument = args.drop(1).first | |
| other_arguments = args.drop(2) | |
| partial_result = args.first.send(command,argument) | |
| call_command command, :arguments => [partial_result,other_arguments].flatten | |
| elsif args.length == 2 | |
| return args.first.send(command,args[1]) | |
| else | |
| return args.first.send(command) | |
| end | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment