Sha256: 09d6eb94eb3653c47857e21c6709a36f50b219387271da948bdc6bc215d9df01

Contents?: true

Size: 1.47 KB

Versions: 2

Compression:

Stored size: 1.47 KB

Contents

require "bundler/setup"
require "lisp/version"
require "lisp/repl"

module Lisp
  def self.eval(string)
    execute(parse(tokenize(string)))
  end

  def self.tokenize(string)
    string.gsub("("," ( ").gsub(")"," ) ").split
  end

  def self.parse(tokens, tree = [])
    raise "unexpected: eof" if tokens.size.zero?

    case token = tokens.shift
    when "("
      while tokens[0] != ")" do
        tree.push parse(tokens)
      end
      tokens.shift
      tree
    when ")"
      raise "unexpected: )"
    else
      evaluator(token)
    end
  end

  def self.evaluator(token)
    case token
    when /\d/
      token.to_f
    else
      token.to_sym
    end
  end

  def self.execute(exp, scope = global)
    return scope[exp] if     exp.is_a? Symbol
    return exp        unless exp.is_a? Array

    case exp[0]
    when :define
      _, var, exp = exp
      scope[var] = execute(exp, scope)
    when :lambda
      _, params, exp = exp
      lambda { |*args| execute(exp, scope.merge(Hash[params.zip(args)])) }
    when :if
      _, test, conseq, alt = exp
      exp = execute(test, scope) ? conseq : alt
      execute(exp, scope)
    else
      func, *args = exp.map { |exp| execute(exp, scope) }
      func.call(*args)
    end
  end

  def self.global
    @scope ||= begin
      operators = [:==, :"!=", :"<", :"<=", :">", :">=", :+, :-, :*, :/]
      operators.inject({}) do |scope, operator|
        scope.merge(operator => lambda { |*args| args.inject(&operator) })
      end
    end
  end
end

Version data entries

2 entries across 2 versions & 1 rubygems

Version Path
lisp-1.0.6 lib/lisp.rb
lisp-1.0.4 lib/lisp.rb