Module: Lisp

Defined in:
lib/lisp.rb,
lib/lisp/repl.rb,
lib/lisp/version.rb,
lib/lisp/interpreter.rb

Defined Under Namespace

Classes: REPL

Constant Summary collapse

VERSION =
'1.5.1'.freeze

Class Method Summary collapse

Class Method Details

.eval(string) ⇒ Object



3
4
5
# File 'lib/lisp/interpreter.rb', line 3

def eval string
  execute parse tokenize string
end

.execute(expression, scope = global) ⇒ Object



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/lisp/interpreter.rb', line 28

def execute expression, scope = global
  return scope.fetch(expression) { |var| raise "#{var} is undefined" } 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, scope }.last
  else
    function, *args = expression.map { |expression| execute expression, scope }
    function.call *args
  end
end

.parse(tokens, tree = []) ⇒ Object



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/lisp/interpreter.rb', line 11

def 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

.tokenize(string) ⇒ Object



7
8
9
# File 'lib/lisp/interpreter.rb', line 7

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