Module: Lisp

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

Constant Summary collapse

VERSION =
"1.0.2"

Class Method Summary collapse

Class Method Details

.eval(string) ⇒ Object



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

def self.eval(string)
  execute(parse(tokenize(string)))
end

.evaluator(token) ⇒ Object



31
32
33
34
35
36
37
38
# File 'lib/lisp.rb', line 31

def self.evaluator(token)
  case token
  when /\d/
    token.to_f
  else
    token.to_sym
  end
end

.execute(exp, scope = global) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/lisp.rb', line 40

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

  case exp[0]
  when :define
    _, var, exp = exp
    scope[var] = execute(exp, scope)
  when :lambda
    _, params, exp = exp
    lambda { |*args| execute(exp, scope.merge(Hash[params.zip(args)])) }
  when :if
    _, test, conseq, alt = exp
    exp = execute(test, scope) ? conseq : alt
    execute(exp, scope)
  else
    func, *args = exp.map { |exp| execute(exp, scope) }
    func.call(*args)
  end
end

.globalObject



61
62
63
64
65
66
67
68
# File 'lib/lisp.rb', line 61

def self.global
  @scope ||= begin
    operators = [:==, :"!=", :"<", :"<=", :">", :">=", :+, :-, :*, :/]
    operators.inject({}) do |scope, operator|
      scope.merge(operator => lambda { |*args| args.inject(&operator) })
    end
  end
end

.inputObject



19
20
21
# File 'lib/lisp/repl.rb', line 19

def self.input
  Coolline.new
end

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



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/lisp.rb', line 14

def self.parse(tokens, tree = [])
  raise "unexpected: eof" if tokens.size.zero?
  token = tokens.shift
  case token
  when "("
    while tokens[0] != ")" do
      tree.push parse(tokens)
    end
    tokens.shift
    tree
  when ")"
    raise "unexpected: )"
  else
    evaluator(token)
  end
end

.replObject



5
6
7
8
9
10
11
12
13
14
15
16
17
# File 'lib/lisp/repl.rb', line 5

def self.repl
  trap("SIGINT") { throw :exit }
  puts "ctrl-c to exit"
  catch(:exit) do
    loop do
      puts begin
        eval input.readline
      rescue Exception => e
        e.message
      end
    end
  end
end

.tokenize(string) ⇒ Object



10
11
12
# File 'lib/lisp.rb', line 10

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