Class: Iode::Interpreter

Inherits:
Object
  • Object
show all
Includes:
BuiltIns
Defined in:
lib/iode/interpreter.rb

Overview

Iode interpreter, providing the central #eval function.

Instance Method Summary collapse

Methods included from BuiltIns

#caddddr, #cadddr, #caddr, #cadr, #car, #cdddddr, #cddddr, #cdddr, #cddr, #cdr

Constructor Details

#initialize(scope = Scope.new) ⇒ Interpreter

Create a new Interpreter with a given Scope.

Parameters:

  • scope (Scope) (defaults to: Scope.new)

    the initial environment



26
27
28
# File 'lib/iode/interpreter.rb', line 26

def initialize(scope = Scope.new)
  @env = scope
end

Instance Method Details

#apply(fn, args) ⇒ Object

Apply a function to its arguments.

Parameters:

  • fn (Callable)

    a Proc or a Lambda

  • args (Array)

    a list of arguments to apply with

Returns:

  • (Object)

    the function return value



74
75
76
77
78
79
80
# File 'lib/iode/interpreter.rb', line 74

def apply(fn, args)
  if fn.respond_to?(:call)
    fn.call(*args)
  else
    raise "Cannot apply non-function `#{fn}`"
  end
end

#eval(sexp) ⇒ Object

Given an iode data structure, execute it.

Parameters:

  • sexp (Object)

    any valid S-expression in iode

Returns:

  • (Object)

    whatever the expression evaluates to



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/iode/interpreter.rb', line 89

def eval(sexp)
  case sexp
  when Array
    case car(sexp)
    when nil
      nil
    when :quote
      cadr(sexp)
    when :if
      if eval(cadr(sexp))
        eval(caddr(sexp))
      else
        eval(cadddr(sexp))
      end
    when :progn
      progn(*cdr(sexp))
    when :set!
      @env[cadr(sexp)] = eval(caddr(sexp))
    when :lambda
      lambda(cadr(sexp), *cddr(sexp))
    else
      apply(eval(car(sexp)), cdr(sexp).map(&method(:eval)))
    end
  when Symbol
    @env[sexp]
  else
    sexp
  end
end

#lambda(argnames, *sexps) ⇒ Proc

Create a new lambda for Iode.

These lambdas act as closures in their environment.

Parameters:

  • argnames (Array)

    a list of argument names as function inputs

  • *sexps (Object...)

    variadic list of S-Expressions for the body

Returns:

  • (Proc)

    a callable lambda



56
57
58
59
60
61
62
# File 'lib/iode/interpreter.rb', line 56

def lambda(argnames, *sexps)
  Proc.new do |*args|
    Interpreter.new(
      @env.push_scope(Hash[argnames.zip(args)])
    ).progn(*sexps)
  end
end

#progn(*sexps) ⇒ Object

Create an explicit progn block.

A progn encapsulates a list of S-Expressions to be evaluated in sequence. The last evaluated S-Expression becomes the value of the progn.

Parameters:

  • *sexps (Object...)

    a list of S-Expressions to wrap in a progn

Returns:

  • (Object)

    the value of the last S-Expression



40
41
42
# File 'lib/iode/interpreter.rb', line 40

def progn(*sexps)
  sexps.inject(nil){|_,s| eval(s)}
end