Class: Iode::Interpreter
- Inherits:
-
Object
- Object
- Iode::Interpreter
- Defined in:
- lib/iode/interpreter.rb
Overview
Iode interpreter, providing the central #eval function.
Instance Method Summary collapse
-
#apply(fn, args) ⇒ Object
Apply a function to its arguments.
-
#car(list) ⇒ Object
Get the head (car) of a list.
-
#cdr(list) ⇒ Array
Get the tail (cdr) of a list.
-
#eval(sexp) ⇒ Object
Given an iode data structure, execute it.
-
#initialize(scope = Scope.new) ⇒ Interpreter
constructor
Create a new Interpreter with a given Scope.
-
#lambda(argnames, *sexps) ⇒ Lambda
Create a new lambda.
-
#macro(argnames, *sexps) ⇒ Macro
Create a new macro.
-
#progn(*sexps) ⇒ Object
Create an explicit progn block.
Constructor Details
#initialize(scope = Scope.new) ⇒ Interpreter
Create a new Interpreter with a given Scope.
24 25 26 |
# File 'lib/iode/interpreter.rb', line 24 def initialize(scope = Scope.new) @env = scope end |
Instance Method Details
#apply(fn, args) ⇒ Object
Apply a function to its arguments.
117 118 119 120 121 122 123 |
# File 'lib/iode/interpreter.rb', line 117 def apply(fn, args) if fn.respond_to?(:call) fn.call(*args) else raise "Cannot apply non-function `#{fn}`" end end |
#car(list) ⇒ Object
Get the head (car) of a list.
35 36 37 38 |
# File 'lib/iode/interpreter.rb', line 35 def car(list) v, *_ = list v end |
#cdr(list) ⇒ Array
Get the tail (cdr) of a list.
47 48 49 50 |
# File 'lib/iode/interpreter.rb', line 47 def cdr(list) _, *v = list v end |
#eval(sexp) ⇒ Object
Given an iode data structure, execute it.
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/iode/interpreter.rb', line 132 def eval(sexp) case sexp when Array case car(sexp) when nil nil when :quote car(cdr(sexp)) when :quasiquote car(cdr(sexp)) when :if if eval(car(cdr(sexp))) eval(car(cdr(cdr(sexp)))) else eval(car(cdr(cdr(cdr(sexp))))) end when :progn progn(*cdr(sexp)) when :set! @env[car(cdr(sexp))] = eval(car(cdr(cdr(sexp)))) when :def @env.define(car(cdr(sexp)), eval(car(cdr(cdr(sexp))))) when :lambda lambda(car(cdr(sexp)), *cdr(cdr(sexp))) when :macro macro(car(cdr(sexp)), *cdr(cdr(sexp))) when :apply eval([car(cdr(sexp)), *car(cdr(cdr(sexp)))]) else callee = eval(car(sexp)) case callee when Macro eval(apply(callee, cdr(sexp))) else apply(callee, cdr(sexp).map(&method(:eval))) end end when Symbol @env[sexp] else sexp end end |
#lambda(argnames, *sexps) ⇒ Lambda
Create a new lambda.
These lambdas act as closures in their environment.
78 79 80 81 82 83 84 |
# File 'lib/iode/interpreter.rb', line 78 def lambda(argnames, *sexps) Lambda.new do |*args| Interpreter.new( @env.push_scope(Hash[argnames.zip(args)]) ).progn(*sexps) end end |
#macro(argnames, *sexps) ⇒ Macro
Create a new macro.
Macros are acually just a special case of lambda and also close their environment and can be passed as arguments.
99 100 101 102 103 104 105 |
# File 'lib/iode/interpreter.rb', line 99 def macro(argnames, *sexps) Macro.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.
62 63 64 |
# File 'lib/iode/interpreter.rb', line 62 def progn(*sexps) sexps.inject(nil){|_,s| eval(s)} end |