class DSL - ripper: Ruby Standard Library Documentation

# class DSL

Simple `DSL` implementation for `Ripper` code generation

input: /*% ripper: stmts_add!(stmts_new!, void_stmt!) %*/ output:

    VALUE v1, v2;
    v1 = dispatch0(stmts_new);
    v2 = dispatch0(void_stmt);
    $$ = dispatch2(stmts_add, v1, v2);

- The code must be a single line.

- The code is basically Ruby code, even if it appears like in C and the result will be processed as C. e.g., comments need to be in Ruby style.

### Constants

NAME_PATTERN
NOT_REF_PATTERN
TAG_PATTERN

### Attributes

events[R]

### Public Class Methods

comma_split(str) click to toggle source

    # File ripper/tools/dsl.rb, line 29
    def self.comma_split(str)
      str or return []
      str.scan(/(([^(,)]+|\((?:,|\g<0>)*\))+)/).map(&:first)
    end

const_missing(name) click to toggle source

    # File ripper/tools/dsl.rb, line 178
    def self.const_missing(name)
      name
    end

line?(line, lineno = nil, indent: nil) click to toggle source

    # File ripper/tools/dsl.rb, line 23
    def self.line?(line, lineno = nil, indent: nil)
      if %r<(?<space>\s*)/\*% *ripper(?:\[(?<option>.*?)\])?: *(?<code>.*?) *%\*/> =~ line
        new(code, comma_split(option), lineno, indent: indent || space)
      end
    end

new(code, options, lineno = nil, indent: "\t\t\t") click to toggle source

    # File ripper/tools/dsl.rb, line 108
    def initialize(code, options, lineno = nil, indent: "\t\t\t")
      @lineno = lineno
      @indent = indent
      @events = {}
      @error = options.include?("error")
      if options.include?("final")
        @final = "p->result"
      else
        @final = (options.grep(/\A\$#{NAME_PATTERN}\z/o)[0] || "p->s_lvalue")
      end

      bind = dsl_binding
      @var_table = Var::Table.new {|arg| "get_value(#{arg})"}
      code = code.gsub(%r[\G#{NOT_REF_PATTERN}\K(\$|\$:|@)#{TAG_PATTERN}?#{NAME_PATTERN}]o) {
        if (arg = $&) == "$:$"
          '"p->s_lvalue"'
        elsif arg.start_with?("$:")
          "(#{@var_table[arg]}=@var_table[#{arg.dump}])"
        else
          arg.dump
        end
      }
      @last_value = bind.eval(code)
    rescue SyntaxError
      $stderr.puts "error on line #{@lineno}" if @lineno
      raise
    end

### Public Instance Methods

add_event(event, args) click to toggle source

    # File ripper/tools/dsl.rb, line 157
    def add_event(event, args)
      event = event.to_s.sub(/!\z/, "")
      @events[event] = args.size
      vars = []
      args.each do |arg|
        arg = @var_table.add {arg} unless Var === arg
        vars << arg
      end
      @var_table.add {"dispatch#{ args.size }(#{ [event, *vars].join(",") })"}
    end

dsl_binding(p = "p") click to toggle source

    # File ripper/tools/dsl.rb, line 136
    def dsl_binding(p = "p")
      # struct parser_params *p
      binding
    end

generate() click to toggle source

    # File ripper/tools/dsl.rb, line 147
    def generate
      s = "#@final=#@last_value;"
      s << "ripper_error(p);" if @error
      unless @var_table.empty?
        vars = @var_table.map {|_, v| "#{v.var}=#{v.value}"}.join(", ")
        s = "VALUE #{ vars }; #{ s }"
      end
      "#{@indent}{#{s}}"
    end

method_missing(event, *args) click to toggle source

    # File ripper/tools/dsl.rb, line 168
    def method_missing(event, *args)
      if event.to_s =~ /!\z/
        add_event(event, args)
      elsif args.empty? and (/\Aid[A-Z_]/ =~ event or @var_table.defined?(event))
        event
      else
        "#{ event }(#{ args.map(&:to_s).join(", ") })"
      end
    end

to_s() click to toggle source

    # File ripper/tools/dsl.rb, line 36
    def to_s
      if empty?
        "rb_ary_new()"
      else
        "rb_ary_new_from_args(#{size}, #{map(&:to_s).join(', ')})"
      end
    end