Class: Malady::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/malady/parser.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(filename) ⇒ Parser

Returns a new instance of Parser.



5
6
7
8
# File 'lib/malady/parser.rb', line 5

def initialize(filename)
  @filename = filename
  @line = 0
end

Instance Attribute Details

#filenameObject (readonly)

Returns the value of attribute filename.



3
4
5
# File 'lib/malady/parser.rb', line 3

def filename
  @filename
end

Instance Method Details

#apply(fn, args) ⇒ Object



86
87
88
89
90
91
92
# File 'lib/malady/parser.rb', line 86

def apply(fn, args)
  if builtins.values.include? fn
    fn.new(@filename, @line, *args)
  else
    Malady::AST::FunctionCallNode.new(@filename, @line, fn, args)
  end
end

#builtinsObject



94
95
96
97
98
99
100
101
102
# File 'lib/malady/parser.rb', line 94

def builtins
  {
    '+' => Malady::AST::AddNode,
    '-' => Malady::AST::MinusNode,
    '/' => Malady::AST::DivideNode,
    '*' => Malady::AST::MultiplyNode,
    '<' => Malady::AST::LessThanNode,
  }
end

#on_error(t, val, vstack) ⇒ Object

Raises:

  • (ParseError)


109
110
111
112
# File 'lib/malady/parser.rb', line 109

def on_error(t, val, vstack)
    raise ParseError, sprintf("\nparse error on value %s (%s) #{@filename}:#{@line}",
        val.inspect, token_to_str(t) || '?')
end

#parse(sexp) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/malady/parser.rb', line 16

def parse(sexp)
  type, *rest = sexp
  if type == :list
    symbol = rest.first
    case symbol[1]
    when 'def!'
      parse_def(sexp)
    when 'let*'
      parse_let(sexp)
    when 'if'
      parse_if(sexp)
    when 'fn*'
      parse_fn(sexp)
    else
      fn, *args = parse_sexp(sexp)
      apply(fn, args)
    end
  else
    parse_sexp(sexp)
  end
end

#parse_def(sexp) ⇒ Object



58
59
60
61
62
63
# File 'lib/malady/parser.rb', line 58

def parse_def(sexp)
  # [:list, [:symbol, 'def!'], [:symbol, 'blah'], sexp]
  name = sexp[2][1]
  value = sexp[3]
  Malady::AST::AssignNode.new(@filename, @line, name, parse(value))
end

#parse_fn(sexp) ⇒ Object



79
80
81
82
83
84
# File 'lib/malady/parser.rb', line 79

def parse_fn(sexp)
  # [:list, [:symbol, 'fn*'], [:list, [:symbol, 'x']], body]
  _, _, (_, *arguments), body = sexp
  arguments = arguments.map(&:last)
  Malady::AST::FnNode.new(@filename, @line, arguments, parse(body))
end

#parse_if(sexp) ⇒ Object



73
74
75
76
77
# File 'lib/malady/parser.rb', line 73

def parse_if(sexp)
  # [:list, [:symbol, 'if'], condition, then_branch, else_branch]
  _, _, condition, then_branch, else_branch = sexp
  Malady::AST::IfNode.new(@filename, @line, parse(condition), parse(then_branch), parse(else_branch))
end

#parse_let(sexp) ⇒ Object



65
66
67
68
69
70
71
# File 'lib/malady/parser.rb', line 65

def parse_let(sexp)
  # [:list, [:symbol, 'let'], [:list, [:symbol, 'c'], sexp], sexp]
  bindings = sexp[2][1..-1].each_slice(2).to_a
  body = sexp[3]
  parsed_bindings = bindings.map { |s, val| [s[1], parse(val)] }
  Malady::AST::LetNode.new(@filename, @line, parsed_bindings, parse(body))
end

#parse_sexp(sexp) ⇒ Object



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/malady/parser.rb', line 38

def parse_sexp(sexp)
  type, *rest = sexp
  case type
  when :boolean
    boolean = sexp.last
    if boolean == :true
      Malady::AST::TrueBooleanNode.new(@filename, @line)
    else
      Malady::AST::FalseBooleanNode.new(@filename, @line)
    end
  when :symbol
    name = sexp.last
    builtins.fetch(name, Malady::AST::SymbolNode.new(@filename, @line, name))
  when :integer
    Malady::AST::IntegerNode.new @filename, @line, sexp[1]
  when :list
    rest.map { |sexp| parse(sexp) }
  end
end

#parse_string(string) ⇒ Object



10
11
12
13
14
# File 'lib/malady/parser.rb', line 10

def parse_string(string)
  sexp = Reader.read_str(string)
  program_body = [parse(sexp)]
  Malady::AST::Program.new @filename, @line, program_body
end

#pre_exeObject

the following methods are needed to conform with RBX’s parser interface



105
106
107
# File 'lib/malady/parser.rb', line 105

def pre_exe
  []
end