class Racc::Grammar::DefinitionEnv
def _add(target, x)
def _add(target, x) case x when Sym @delayed.each do |rule| rule.replace x, target if rule.target == x end @grammar.symboltable.delete x else x.each_rule do |r| r.target = target @grammar.add r end end flush_delayed end
def _added?(sym)
def _added?(sym) @grammar.added?(sym) or @delayed.detect {|r| r.target == sym } end
def _defmetasyntax(type, id, action, &block)
def _defmetasyntax(type, id, action, &block) if action idbase = "#{type}@#{id}-#{@seqs[type] += 1}" target = _wrap(idbase, "#{idbase}-core", action) _register("#{idbase}-core", &block) else target = _register("#{type}@#{id}", &block) end @grammar.intern(target) end
def _delayed_add(rule)
def _delayed_add(rule) @delayed.push rule end
def _intern(x)
def _intern(x) case x when Symbol, String @grammar.intern(x) when Racc::Sym x else raise TypeError, "wrong type #{x.class} (expected Symbol/String/Racc::Sym)" end end
def _register(target_name)
def _register(target_name) target = target_name.intern unless _added?(@grammar.intern(target)) yield(target).each_rule do |rule| rule.target = @grammar.intern(target) _delayed_add rule end end target end
def _wrap(target_name, sym, block)
def _wrap(target_name, sym, block) target = target_name.intern _delayed_add Rule.new(@grammar.intern(target), [@grammar.intern(sym.intern)], UserAction.proc(block)) target end
def action(&block)
def action(&block) id = "@#{@seqs["action"] += 1}".intern _delayed_add Rule.new(@grammar.intern(id), [], UserAction.proc(block)) id end
def flush_delayed
def flush_delayed return if @delayed.empty? @delayed.each do |rule| @grammar.add rule end @delayed.clear end
def grammar
def grammar flush_delayed @grammar.each do |rule| if rule.specified_prec rule.specified_prec = @grammar.intern(rule.specified_prec) end end @grammar.init @grammar end
def initialize
def initialize @grammar = Grammar.new @seqs = Hash.new(0) @delayed = [] end
def many(sym, &block)
def many(sym, &block) _defmetasyntax("many", _intern(sym), block) {|target| seq() { [] }\ | seq(target, sym) {|list, x| list.push x; list } } end
def many1(sym, &block)
def many1(sym, &block) _defmetasyntax("many1", _intern(sym), block) {|target| seq(sym) {|x| [x] }\ | seq(target, sym) {|list, x| list.push x; list } } end
def method_missing(mid, *args, &block)
def method_missing(mid, *args, &block) unless mid.to_s[-1,1] == '=' super # raises NoMethodError end target = @grammar.intern(mid.to_s.chop.intern) unless args.size == 1 raise ArgumentError, "too many arguments for #{mid} (#{args.size} for 1)" end _add target, args.first end
def null(&block)
def null(&block) seq(&block) end
def option(sym, default = nil, &block)
def option(sym, default = nil, &block) _defmetasyntax("option", _intern(sym), block) {|target| seq() { default } | seq(sym) } end
def precedence_table(&block)
def precedence_table(&block) env = PrecedenceDefinitionEnv.new(@grammar) env.instance_eval(&block) @grammar.end_precedence_declaration env.reverse end
def separated_by(sep, sym, &block)
def separated_by(sep, sym, &block) option(separated_by1(sep, sym), [], &block) end
def separated_by1(sep, sym, &block)
def separated_by1(sep, sym, &block) _defmetasyntax("separated_by1", _intern(sym), block) {|target| seq(sym) {|x| [x] }\ | seq(target, sep, sym) {|list, _, x| list.push x; list } } end
def seq(*list, &block)
def seq(*list, &block) Rule.new(nil, list.map {|x| _intern(x) }, UserAction.proc(block)) end