class Lucio

Public Class Methods

new(lexicon = Lexicon.new) click to toggle source
# File lib/lucio/lucio.rb, line 2
def initialize(lexicon = Lexicon.new)
  @lexicon = lexicon
  @lexicon.add_function :+    , lambda{|items| items.reduce(0, :+)}
  @lexicon.add_function :*    , lambda{|items| items.reduce(1, :*)}
  @lexicon.add_function :-    , lambda{|items| case when items.size == 0; 0; else; head, tail = Lucio.behead(items); tail.empty? ? (head * -1) : tail.inject(head) {|subtraction, item| subtraction -= item}; end}
  @lexicon.add_function :/    , lambda{|items| case when items.size == 0; raise 'expects at least 1 arguments, given 0'; when items.size == 1; 1.0 / items[0]; else items.reduce{|result, item| result = result / item.to_f}; end}
  @lexicon.add_function :true , lambda{ true }
  @lexicon.add_function :false, lambda{ false }
  @lexicon.add_function :eql? , lambda{|items| items.map{|item| item == items[0]}.reduce{|memo, item| memo && item}}
  @lexicon.add_macro    :let  , lambda{|lexicon, items| lexicon.add_function(items[0].to_sym, lambda{(items[1].kind_of? Array) ? evaluate_tree(items[1]) : items[1]})}
  @lexicon.add_macro    :if   , lambda{|lexicon, items| evaluate_tree(items[0]) ? evaluate_tree(items[1]) : evaluate_tree(items[2]) }
end

Private Class Methods

behead(list) click to toggle source
# File lib/lucio/lucio.rb, line 53
def self.behead(list)
  [list[0], list.drop(1)]
end

Public Instance Methods

eval(source_code) click to toggle source
# File lib/lucio/lucio.rb, line 15
def eval(source_code)
  tree = Sparse.new.parse(source_code)
  ret = nil
  tree.each {|list| ret = evaluate_tree list}
  ret
end

Private Instance Methods

evaluate_tree(tree) click to toggle source
# File lib/lucio/lucio.rb, line 23
def evaluate_tree(tree)
  unless tree.empty?
    operator, list = Lucio.behead tree
    
    if operator.kind_of?(Symbol) || operator.kind_of?(Array)
      instruction = @lexicon.get operator

      if instruction
        if instruction[:type] == :function
          list.map! {|item| (item.kind_of? Array) ? item = evaluate_tree(item) : item}
          list.map! {|item| (item.kind_of? Symbol) ? item = @lexicon.get(item)[:code].call : item}

          instruction[:code].call list

          elsif instruction[:type] == :macro
          instruction[:code].call @lexicon, list

        end

      else
        raise UnboundSymbolException.new "Unbound symbol #{operator.to_s}"

      end
    else
      operator
    end

  end
end