summaryrefslogtreecommitdiff
path: root/ext/ripper/tools/dsl.rb
blob: 3857ec0702dd6f3b9450b66d63a0fffeec47d243 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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
54
55
56
57
58
59
60
# Simple DSL implementation for Ripper code generation
#
# input: /*% ripper: stmts_add(stmts_new, void_stmt) %*/
# output: $$ = dispatch2(stmts_add, dispatch0(stmts_new), dispatch0(void_stmt))

class DSL
  def initialize(code, options)
    @events = {}
    @error = options.include?("error")
    @brace = options.include?("brace")
    @final = options.include?("final")
    @var_field_1 = options.include?("var_field_1")

    # create $1 == "$1", $2 == "$2", ...
    re, s = "", ""
    1.upto(9) do |n|
      re << "(..)"
      s << "$#{ n }"
    end
    /#{ re }/ =~ s

    # struct parser_params *p
    p = "p"

    @code = eval(code)
  end

  attr_reader :events

  undef lambda
  undef hash
  undef class

  def generate
    s = "$$"
    s = "p->result" if @final
    s = "#{ s } = #@code;"
    s << "ripper_error(p);" if @error
    s = "{#{ s }}" if @brace
    s = "$1 = var_field(p, $1);" + s if @var_field_1
    "\t\t\t#{s}"
  end

  def method_missing(event, *args)
    if event.to_s =~ /!\z/
      event = $`
      @events[event] = args.size
      "dispatch#{ args.size }(#{ [event, *args].join(", ") })"
    elsif args.empty? and /\Aid[A-Z]/ =~ event.to_s
      event
    else
      "#{ event }(#{ args.join(", ") })"
    end
  end

  def self.const_missing(name)
    name
  end
end