Sha256: 4db6768c4b17b58c0bf91a893fe55324ba6c04317c2dbd80a10df1c86494952a

Contents?: true

Size: 1.97 KB

Versions: 1

Compression:

Stored size: 1.97 KB

Contents

$:.unshift File.dirname(__FILE__)

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
      atom token
    end
  end

  def self.atom token
    case token
    when /\d/
      token.to_f % 1 > 0 ? token.to_f : token.to_i
    else
      token.to_sym
    end
  end

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

    case expression[0]
    when :define
      _, var, expression = expression
      scope[var]         = execute expression, scope
    when :lambda
      _, params, expression = expression
      lambda { |*args| execute expression, scope.merge(Hash[params.zip(args)]) }
    when :if
      _, test, consequent, alternative = expression
      expression                       = if execute test, scope then consequent else alternative end
      execute expression, scope
    when :set!
      _, var, expression                     = expression
      if scope.has_key?(var) then scope[var] = execute expression, scope else raise "#{var} is undefined" end
    when :begin
      _, *expression = expression
      expression.map { |expression| execute expression }.last
    else
      function, *args = expression.map { |expression| execute expression, scope }
      function.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

1 entries across 1 versions & 1 rubygems

Version Path
lisp-1.4.0 lib/lisp.rb