Bug #6929 » 0001-Documentation-for-Ripper.patch
| ext/ripper/extconf.rb | ||
|---|---|---|
|
require 'mkmf'
|
||
|
require 'rbconfig'
|
||
|
def main
|
||
|
def main # :nodoc:
|
||
|
unless find_executable('bison')
|
||
|
unless File.exist?('ripper.c') or File.exist?("#{$srcdir}/ripper.c")
|
||
|
raise 'missing bison; abort'
|
||
| ext/ripper/lib/ripper.rb | ||
|---|---|---|
|
require 'ripper/lexer'
|
||
|
require 'ripper/filter'
|
||
|
require 'ripper/sexp'
|
||
|
# Ripper is a Ruby script parser.
|
||
|
#
|
||
|
# You can get information from the parser with event-based style.
|
||
|
# Information such as abstract syntax trees or simple lexical analysis of the
|
||
|
# Ruby program.
|
||
|
#
|
||
|
# == Usage
|
||
|
#
|
||
|
# Ripper provides an easy interface for parsing your program into a symbolic
|
||
|
# expression tree (or S-expression).
|
||
|
#
|
||
|
# Understanding the output of the parser may come as a challenge, it's
|
||
|
# recommended you use PP to format the output for legibility.
|
||
|
#
|
||
|
# require 'ripper'
|
||
|
# require 'pp'
|
||
|
#
|
||
|
# pp Ripper.sexp('def hello(world); "Hello, #{world}!"; end')
|
||
|
# #=> [:program,
|
||
|
# [[:def,
|
||
|
# [:@ident, "hello", [1, 4]],
|
||
|
# [:paren,
|
||
|
# [:params, [[:@ident, "world", [1, 10]]], nil, nil, nil, nil, nil, nil]],
|
||
|
# [:bodystmt,
|
||
|
# [[:void_stmt],
|
||
|
# [:string_literal,
|
||
|
# [:string_content,
|
||
|
# [:@tstring_content, "Hello, ", [1, 19]],
|
||
|
# [:string_embexpr, [[:var_ref, [:@ident, "world", [1, 28]]]]],
|
||
|
# [:@tstring_content, "!", [1, 34]]]]],
|
||
|
# nil,
|
||
|
# nil,
|
||
|
# nil]]]]
|
||
|
#
|
||
|
# You can see in the example above, the expression starts with +:program+.
|
||
|
#
|
||
|
# From here, a method definition at +:def+, followed by the method's identifier
|
||
|
# <code>:@ident</code>. After the method's identifier comes the parentheses
|
||
|
# +:paren+ and the method parameters under +:params+.
|
||
|
#
|
||
|
# Next is the method body, starting at +:bodystmt+ (+stmt+ meaning statement),
|
||
|
# which contains the full definition of the method.
|
||
|
#
|
||
|
# In our case, we're simply returning a String, so next we have the
|
||
|
# +:void_stmt+ followed by a +:string_literal+.
|
||
|
#
|
||
|
# Within our +:string_literal+ you'll notice two <code>@tstring_content</code>,
|
||
|
# this is the literal part for <code>Hello, </code> and <code>!</code>. Between
|
||
|
# the two <code>@tstring_content</code> statements is a +:string_embexpr+,
|
||
|
# where _embexpr_ is an embedded expression. Our expression consists of a local
|
||
|
# variable, or +var_ref+, with the identifier (<code>@ident</code>) of +world+.
|
||
|
#
|
||
|
# == Resources
|
||
|
#
|
||
|
# * {Ruby Inside}[http://www.rubyinside.com/using-ripper-to-see-how-ruby-is-parsing-your-code-5270.html]
|
||
|
#
|
||
|
# == Requirements
|
||
|
#
|
||
|
# * ruby 1.9 (support CVS HEAD only)
|
||
|
# * bison 1.28 or later (Other yaccs do not work)
|
||
|
#
|
||
|
# == License
|
||
|
#
|
||
|
# Ruby License.
|
||
|
#
|
||
|
# Minero Aoki
|
||
|
# aamine@loveruby.net
|
||
|
# http://i.loveruby.net
|
||
|
class Ripper; end
|
||
| ext/ripper/lib/ripper/core.rb | ||
|---|---|---|
|
class Ripper
|
||
|
# Parses Ruby program read from _src_.
|
||
|
# _src_ must be a String or a IO or a object which has #gets method.
|
||
|
# Parses the given Ruby program read from +src+.
|
||
|
# +src+ must be a String or an IO or a object with a #gets method.
|
||
|
def Ripper.parse(src, filename = '(ripper)', lineno = 1)
|
||
|
new(src, filename, lineno).parse
|
||
|
end
|
||
| ... | ... | |
|
end
|
||
|
# This method is called when weak warning is produced by the parser.
|
||
|
# _fmt_ and _args_ is printf style.
|
||
|
# +fmt+ and +args+ is printf style.
|
||
|
def warn(fmt, *args)
|
||
|
end
|
||
|
# This method is called when strong warning is produced by the parser.
|
||
|
# _fmt_ and _args_ is printf style.
|
||
|
# +fmt+ and +args+ is printf style.
|
||
|
def warning(fmt, *args)
|
||
|
end
|
||
| ext/ripper/lib/ripper/filter.rb | ||
|---|---|---|
|
class Ripper
|
||
|
# This class handles only scanner events,
|
||
|
# and they are dispatched in the `right' order (same with input).
|
||
|
# which are dispatched in the 'right' order (same with input).
|
||
|
class Filter
|
||
|
# Creates a new Ripper::Filter instance, passes parameters +src+,
|
||
|
# +filename+, and +lineno+ to Ripper::Lexer.new
|
||
|
#
|
||
|
# The lexer is for internal use only.
|
||
|
def initialize(src, filename = '-', lineno = 1)
|
||
|
@__lexer = Lexer.new(src, filename, lineno)
|
||
|
@__line = nil
|
||
| ... | ... | |
|
@__col
|
||
|
end
|
||
|
# Starts parsing. _init_ is a data accumulator.
|
||
|
# It is passed to the next event handler (as of Enumerable#inject).
|
||
|
# Starts the parser.
|
||
|
# +init+ is a data accumulator and is passed to the next event handler (as
|
||
|
# of Enumerable#inject).
|
||
|
def parse(init = nil)
|
||
|
data = init
|
||
|
@__lexer.lex.each do |pos, event, tok|
|
||
| ... | ... | |
|
private
|
||
|
# This method is called when some event handler have not defined.
|
||
|
# _event_ is :on_XXX, _token_ is scanned token, _data_ is a data
|
||
|
# accumulator. The return value of this method is passed to the
|
||
|
# next event handler (as of Enumerable#inject).
|
||
|
# This method is called when some event handler is undefined.
|
||
|
# +event+ is :on_XXX, +token+ is the scanned token, and +data+ is a data
|
||
|
# accumulator.
|
||
|
#
|
||
|
# The return value of this method is passed to the next event handler (as
|
||
|
# of Enumerable#inject).
|
||
|
def on_default(event, token, data)
|
||
|
data
|
||
|
end
|
||
| ext/ripper/lib/ripper/lexer.rb | ||
|---|---|---|
|
class Ripper
|
||
|
# Tokenizes Ruby program and returns an Array of String.
|
||
|
# Tokenizes the Ruby program and returns an Array of String.
|
||
|
def Ripper.tokenize(src, filename = '-', lineno = 1)
|
||
|
Lexer.new(src, filename, lineno).tokenize
|
||
|
end
|
||
|
# Tokenizes Ruby program and returns an Array of Array,
|
||
|
# which is formatted like [[lineno, column], type, token].
|
||
|
# Tokenizes the Ruby program and returns an Array of an Array,
|
||
|
# which is formatted like <code>[[lineno, column], type, token]</code>.
|
||
|
#
|
||
|
# require 'ripper'
|
||
|
# require 'pp'
|
||
| ... | ... | |
|
class TokenPattern #:nodoc:
|
||
|
class Error < ::StandardError; end
|
||
|
class CompileError < Error; end
|
||
|
class MatchError < Error; end
|
||
|
class Error < ::StandardError # :nodoc:
|
||
|
end
|
||
|
class CompileError < Error # :nodoc:
|
||
|
end
|
||
|
class MatchError < Error # :nodoc:
|
||
|
end
|
||
|
class << self
|
||
|
alias compile new
|
||
| ... | ... | |
|
MAP[tok] or raise CompileError, "unknown token: #{tok}"
|
||
|
end
|
||
|
class MatchData
|
||
|
class MatchData # :nodoc:
|
||
|
def initialize(tokens, match)
|
||
|
@tokens = tokens
|
||
|
@match = match
|
||
| ext/ripper/lib/ripper/sexp.rb | ||
|---|---|---|
|
# [EXPERIMENTAL]
|
||
|
# Parses +src+ and create S-exp tree.
|
||
|
# Returns more readable tree rather than Ripper.sexp_raw.
|
||
|
# This method is for mainly developer use.
|
||
|
# This method is mainly for developer use.
|
||
|
#
|
||
|
# require 'ripper'
|
||
|
# require 'pp'
|
||
| ... | ... | |
|
# [EXPERIMENTAL]
|
||
|
# Parses +src+ and create S-exp tree.
|
||
|
# This method is for mainly developer use.
|
||
|
# This method is mainly for developer use.
|
||
|
#
|
||
|
# require 'ripper'
|
||
|
# require 'pp'
|
||
| ext/ripper/tools/generate.rb | ||
|---|---|---|
|
require 'optparse'
|
||
|
def main
|
||
|
def main # :nodoc:
|
||
|
mode = nil
|
||
|
ids1src = nil
|
||
|
ids2src = nil
|
||
| ... | ... | |
|
end
|
||
|
end
|
||
|
def usage(msg)
|
||
|
def usage(msg) # :nodoc:
|
||
|
$stderr.puts msg
|
||
|
$stderr.puts @parser.help
|
||
|
exit false
|
||
|
end
|
||
|
def generate_eventids1(ids)
|
||
|
def generate_eventids1(ids) # :nodoc:
|
||
|
buf = ""
|
||
|
ids.each do |id, arity|
|
||
|
buf << %Q[static ID ripper_id_#{id};\n]
|
||
| ... | ... | |
|
buf
|
||
|
end
|
||
|
def generate_eventids2_table(ids)
|
||
|
def generate_eventids2_table(ids) # :nodoc:
|
||
|
buf = ""
|
||
|
buf << %Q[static void\n]
|
||
|
buf << %Q[ripper_init_eventids2_table(VALUE self)\n]
|
||
| ... | ... | |
|
buf
|
||
|
end
|
||
|
def read_ids1(path)
|
||
|
def read_ids1(path) # :nodoc:
|
||
|
strip_locations(read_ids1_with_locations(path))
|
||
|
end
|
||
|
def strip_locations(h)
|
||
|
def strip_locations(h) # :nodoc:
|
||
|
h.map {|event, list| [event, list.first[1]] }\
|
||
|
.sort_by {|event, arity| event.to_s }
|
||
|
end
|
||
|
def check_arity(h)
|
||
|
def check_arity(h) # :nodoc:
|
||
|
invalid = false
|
||
|
h.each do |event, list|
|
||
|
unless list.map {|line, arity| arity }.uniq.size == 1
|
||
| ... | ... | |
|
abort if invalid
|
||
|
end
|
||
|
def read_ids1_with_locations(path)
|
||
|
def read_ids1_with_locations(path) # :nodoc:
|
||
|
h = {}
|
||
|
File.open(path) {|f|
|
||
|
f.each do |line|
|
||
| ... | ... | |
|
h
|
||
|
end
|
||
|
def read_ids2(path)
|
||
|
def read_ids2(path) # :nodoc:
|
||
|
File.open(path) {|f|
|
||
|
return f.read.scan(/ripper_id_(\w+)/).flatten.uniq.sort
|
||
|
}
|
||
| ext/ripper/tools/preproc.rb | ||
|---|---|---|
|
require 'optparse'
|
||
|
def main
|
||
|
def main # :nodoc:
|
||
|
output = nil
|
||
|
parser = OptionParser.new
|
||
|
parser.banner = "Usage: #{File.basename($0)} [--output=PATH] <parse.y>"
|
||
| ... | ... | |
|
end
|
||
|
end
|
||
|
def prelude(f, out)
|
||
|
def prelude(f, out) # :nodoc:
|
||
|
while line = f.gets
|
||
|
case line
|
||
|
when %r</\*%%%\*/>
|
||
| ... | ... | |
|
end
|
||
|
end
|
||
|
def grammar(f, out)
|
||
|
def grammar(f, out) # :nodoc:
|
||
|
while line = f.gets
|
||
|
case line
|
||
|
when %r</\*%%%\*/>
|
||
| ... | ... | |
|
end
|
||
|
end
|
||
|
def usercode(f, out)
|
||
|
def usercode(f, out) # :nodoc:
|
||
|
while line = f.gets
|
||
|
out << line
|
||
|
end
|
||