🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

ruby_parser

Package Overview
Dependencies
Maintainers
1
Versions
80
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ruby_parser - rubygems Package Compare versions

Comparing version
1.0.0
to
2.0.0
bin/ruby_parse

Sorry, the diff of this file is not supported yet

+1051
require 'stringio'
require 'racc/parser'
require 'sexp'
require 'strscan'
# WHY do I have to do this?!?
class Regexp
ONCE = 0 # 16 # ?
ENC_NONE = /x/n.options
ENC_EUC = /x/e.options
ENC_SJIS = /x/s.options
ENC_UTF8 = /x/u.options
end
# I hate ruby 1.9 string changes
class Fixnum
def ord
self
end
end unless "a"[0] == "a"
class RPStringScanner < StringScanner
# if ENV['TALLY'] then
# alias :old_getch :getch
# def getch
# warn({:getch => caller[0]}.inspect)
# old_getch
# end
# end
def current_line # HAHA fuck you (HACK)
string[0..pos][/\A.*__LINE__/m].split(/\n/).size
end
def lineno
string[0...pos].count("\n") + 1
end
# TODO: once we get rid of these, we can make things like
# TODO: current_line and lineno much more accurate and easy to do
def unread c # TODO: remove this entirely - we should not need it
return if c.nil? # UGH
warn({:unread => caller[0]}.inspect) if ENV['TALLY']
string[pos, 0] = c
end
def unread_many str # TODO: remove this entirely - we should not need it
warn({:unread_many => caller[0]}.inspect) if ENV['TALLY']
string[pos, 0] = str
end
def begin_of_line?
pos == 0 or string[pos-1] == ?\n
end
def was_begin_of_line # TODO: kill me
pos <= 2 or string[pos-2] == ?\n
end
if ENV['DEBUG'] then
alias :old_getch :getch
def getch
c = self.old_getch
p :getch => [c, caller.first]
c
end
alias :old_scan :scan
def scan re
s = old_scan re
p :scan => [s, caller.first] if s
s
end
end
# TODO:
# def last_line(src)
# if n = src.rindex("\n")
# src[(n+1) .. -1]
# else
# src
# end
# end
# private :last_line
# def next_words_on_error
# if n = @src.rest.index("\n")
# @src.rest[0 .. (n-1)]
# else
# @src.rest
# end
# end
# def prev_words_on_error(ev)
# pre = @pre
# if ev and /#{Regexp.quote(ev)}$/ =~ pre
# pre = $`
# end
# last_line(pre)
# end
# def on_error(et, ev, values)
# lines_of_rest = @src.rest.to_a.length
# prev_words = prev_words_on_error(ev)
# at = 4 + prev_words.length
# message = <<-MSG
# RD syntax error: line #{@blockp.line_index - lines_of_rest}:
# ...#{prev_words} #{(ev||'')} #{next_words_on_error()} ...
# MSG
# message << " " * at + "^" * (ev ? ev.length : 0) + "\n"
# raise ParseError, message
# end
end
class RubyParser < Racc::Parser
VERSION = '2.0.0'
attr_accessor :lexer, :in_def, :in_single, :file
attr_reader :env, :comments
def append_to_block head, tail # FIX: wtf is this?!? switch to block_append
return head if tail.nil?
return tail if head.nil?
head = s(:block, head) unless head.node_type == :block
head << tail
head
end
def arg_add(node1, node2) # TODO: nuke
return s(:arglist, node2) unless node1
node1[0] = :arglist if node1[0] == :array
return node1 << node2 if node1[0] == :arglist
return s(:arglist, node1, node2)
end
def arg_blk_pass node1, node2 # TODO: nuke
node1 = s(:arglist, node1) unless [:arglist, :array].include? node1.first
node1 << node2 if node2
node1
end
def arg_concat node1, node2 # TODO: nuke
raise "huh" unless node2
node1 << s(:splat, node2).compact
node1
end
def args arg, optarg, rest_arg, block_arg
arg ||= s(:args)
result = arg
if optarg then
optarg[1..-1].each do |lasgn| # FIX clean sexp iter
raise "wtf? #{lasgn.inspect}" unless lasgn[0] == :lasgn
result << lasgn[1]
end
end
result << rest_arg if rest_arg
result << :"&#{block_arg.last}" if block_arg
result << optarg if optarg # TODO? huh - processed above as well
result
end
def aryset receiver, index
index[0] = :arglist if index[0] == :array
s(:attrasgn, receiver, :"[]=", index)
end
def assignable(lhs, value = nil)
id = lhs.to_sym
id = id.to_sym if Sexp === id
raise SyntaxError, "Can't change the value of #{id}" if
id.to_s =~ /^(?:self|nil|true|false|__LINE__|__FILE__)$/
result = case id.to_s
when /^@@/ then
asgn = in_def || in_single > 0
s((asgn ? :cvasgn : :cvdecl), id)
when /^@/ then
s(:iasgn, id)
when /^\$/ then
s(:gasgn, id)
when /^[A-Z]/ then
s(:cdecl, id)
else
case self.env[id]
when :lvar then
s(:lasgn, id)
when :dvar, nil then
if self.env.current[id] == :dvar then
s(:lasgn, id)
elsif self.env[id] == :dvar then
self.env.use(id)
s(:lasgn, id)
elsif ! self.env.dynamic? then
s(:lasgn, id)
else
s(:lasgn, id)
end
else
raise "wtf? unknown type: #{self.env[id]}"
end
end
self.env[id] ||= :lvar
result << value if value
return result
end
def block_append(head, tail, strip_tail_block=false)
return head unless tail
return tail unless head
case head[0]
when :lit, :str then
return tail
end
line = [head.line, tail.line].compact.min
head = remove_begin(head)
head = s(:block, head) unless head[0] == :block
if strip_tail_block and Sexp === tail and tail[0] == :block then
head.push(*tail.values)
else
head << tail
end
head.line = line
head
end
def cond node
return nil if node.nil?
node = value_expr node
case node.first
when :dregex then
return s(:match2, node, s(:gvar, "$_".to_sym))
when :regex then
return s(:match, node)
when :lit then
if Regexp === node.last then
return s(:match, node)
else
return node
end
when :and then
return s(:and, cond(node[1]), cond(node[2]))
when :or then
return s(:or, cond(node[1]), cond(node[2]))
when :dot2 then
label = "flip#{node.hash}"
env[label] = :lvar
return s(:flip2, node[1], node[2])
when :dot3 then
label = "flip#{node.hash}"
env[label] = :lvar
return s(:flip3, node[1], node[2])
else
return node
end
end
##
# for pure ruby systems only
def do_parse
_racc_do_parse_rb(_racc_setup, false)
end if ENV['PURE_RUBY']
def get_match_node lhs, rhs # TODO: rename to new_match
if lhs then
case lhs[0]
when :dregx, :dregx_once then
return s(:match2, lhs, rhs).line(lhs.line)
when :lit then
return s(:match2, lhs, rhs).line(lhs.line) if Regexp === lhs.last
end
end
if rhs then
case rhs[0]
when :dregx, :dregx_once then
return s(:match3, rhs, lhs).line(lhs.line)
when :lit then
return s(:match3, rhs, lhs).line(lhs.line) if Regexp === rhs.last
end
end
return s(:call, lhs, :"=~", s(:arglist, rhs)).line(lhs.line)
end
def gettable(id)
raise "no: #{id.inspect}" if Sexp === id
id = id.to_sym if Sexp === id # HACK
id = id.to_sym if String === id # HACK
return s(:self) if id == :self
return s(:nil) if id == :nil
return s(:true) if id == :true
return s(:false) if id == :false
return s(:str, self.file) if id == :"__FILE__"
return s(:lit, lexer.src.current_line) if id == :"__LINE__"
result = case id.to_s
when /^@@/ then
s(:cvar, id)
when /^@/ then
s(:ivar, id)
when /^\$/ then
s(:gvar, id)
when /^[A-Z]/ then
s(:const, id)
else
type = env[id]
if type then
s(type, id)
elsif env.dynamic? and :dvar == env[id] then
s(:lvar, id)
else
s(:call, nil, id, s(:arglist))
end
end
return result if result
raise "identifier #{id.inspect} is not valid"
end
def initialize
super
self.lexer = RubyLexer.new
self.lexer.parser = self
@env = Environment.new
@comments = []
self.reset
end
def list_append list, item # TODO: nuke me *sigh*
return s(:array, item) unless list
list = s(:array, list) unless Sexp === list && list.first == :array
list << item
end
def list_prepend item, list # TODO: nuke me *sigh*
list = s(:array, list) unless Sexp === list && list[0] == :array
list.insert 1, item
list
end
def literal_concat head, tail
return tail unless head
return head unless tail
htype, ttype = head[0], tail[0]
head = s(:dstr, '', head) if htype == :evstr
case ttype
when :str then
if htype == :str
head[-1] << tail[-1]
elsif htype == :dstr and head.size == 2 then
head[-1] << tail[-1]
else
head << tail
end
when :dstr then
if htype == :str then
tail[1] = head[-1] + tail[1]
head = tail
else
tail[0] = :array
tail[1] = s(:str, tail[1])
tail.delete_at 1 if tail[1] == s(:str, '')
head.push(*tail[1..-1])
end
when :evstr then
head[0] = :dstr if htype == :str
if head.size == 2 and tail.size > 1 and tail[1][0] == :str then
head[-1] << tail[1][-1]
head[0] = :str if head.size == 2 # HACK ?
else
head.push(tail)
end
else
x = [head, tail]
raise "unknown type: #{x.inspect}"
end
return head
end
def logop(type, left, right) # TODO: rename logical_op
left = value_expr left
if left and left[0] == type and not left.paren then
node, second = left, nil
while (second = node[2]) && second[0] == type and not second.paren do
node = second
end
node[2] = s(type, second, right)
return left
end
return s(type, left, right)
end
def new_aref val
val[2] ||= s(:arglist)
val[2][0] = :arglist if val[2][0] == :array # REFACTOR
if val[0].node_type == :self then
result = new_call nil, :"[]", val[2]
else
result = new_call val[0], :"[]", val[2]
end
result
end
def new_body val
result = val[0]
if val[1] then
result = s(:rescue)
result << val[0] if val[0]
resbody = val[1]
while resbody do
result << resbody
resbody = resbody.resbody(true)
end
result << val[2] if val[2]
result.line = (val[0] || val[1]).line
elsif not val[2].nil? then
warning("else without rescue is useless")
result = block_append(result, val[2])
end
result = s(:ensure, result, val[3]).compact if val[3]
return result
end
def new_call recv, meth, args = nil
result = s(:call, recv, meth)
result.line = recv.line if recv
args ||= s(:arglist)
args[0] = :arglist if args.first == :array
args = s(:arglist, args) unless args.first == :arglist
result << args
result
end
def new_case expr, body
result = s(:case, expr)
line = (expr || body).line
while body and body.node_type == :when
result << body
body = body.delete_at 3
end
# else
body = nil if body == s(:block)
result << body
result.line = line
result
end
def new_class val
line, path, superclass, body = val[1], val[2], val[3], val[5]
scope = s(:scope, body).compact
result = s(:class, path, superclass, scope)
result.line = line
result.comments = self.comments.pop
result
end
def new_compstmt val
result = void_stmts(val[0])
result = remove_begin(result) if result
result
end
def new_defn val
line, name, args, body = val[2], val[1], val[3], val[4]
body ||= s(:nil)
body ||= s(:block)
body = s(:block, body) unless body.first == :block
result = s(:defn, name.to_sym, args, s(:scope, body))
result.line = line
result.comments = self.comments.pop
result
end
def new_defs val
recv, name, args, body = val[1], val[4], val[6], val[7]
body ||= s(:block)
body = s(:block, body) unless body.first == :block
result = s(:defs, recv, name.to_sym, args, s(:scope, body))
result.line = recv.line
result.comments = self.comments.pop
result
end
def new_for expr, var, body
result = s(:for, expr, var).line(var.line)
result << body if body
result
end
def new_if c, t, f
l = [c.line, t && t.line, f && f.line].compact.min
c = cond c
c, t, f = c.last, f, t if c[0] == :not
s(:if, c, t, f).line(l)
end
def new_iter call, args, body
result = s(:iter)
result << call if call
result << args
result << body if body
result
end
def new_masgn lhs, rhs, wrap = false
rhs = value_expr(rhs)
rhs = lhs[1] ? s(:to_ary, rhs) : s(:array, rhs) if wrap
lhs.delete_at 1 if lhs[1].nil?
lhs << rhs
lhs
end
def new_module val
line, path, body = val[1], val[2], val[4]
body = s(:scope, body).compact
result = s(:module, path, body)
result.line = line
result.comments = self.comments.pop
result
end
def new_op_asgn val
lhs, asgn_op, arg = val[0], val[1].to_sym, val[2]
name = lhs.value
arg = remove_begin(arg)
result = case asgn_op # REFACTOR
when :"||" then
lhs << arg
s(:op_asgn_or, self.gettable(name), lhs)
when :"&&" then
lhs << arg
s(:op_asgn_and, self.gettable(name), lhs)
else
# TODO: why [2] ?
lhs[2] = new_call(self.gettable(name), asgn_op,
s(:arglist, arg))
lhs
end
result.line = lhs.line
result
end
def new_regexp val
node = val[1] || s(:str, '')
options = val[2]
o, k = 0, nil
options.split(//).each do |c| # FIX: this has a better home
v = {
'x' => Regexp::EXTENDED,
'i' => Regexp::IGNORECASE,
'm' => Regexp::MULTILINE,
'o' => Regexp::ONCE,
'n' => Regexp::ENC_NONE,
'e' => Regexp::ENC_EUC,
's' => Regexp::ENC_SJIS,
'u' => Regexp::ENC_UTF8,
}[c]
raise "unknown regexp option: #{c}" unless v
o += v
k = c if c =~ /[esu]/
end
case node[0]
when :str then
node[0] = :lit
node[1] = if k then
Regexp.new(node[1], o, k)
else
Regexp.new(node[1], o)
end
when :dstr then
if options =~ /o/ then
node[0] = :dregx_once
else
node[0] = :dregx
end
node << o if o and o != 0
else
node = s(:dregx, '', node);
node[0] = :dregx_once if options =~ /o/
node << o if o and o != 0
end
node
end
def new_sclass val
recv, in_def, in_single, body = val[3], val[4], val[6], val[7]
scope = s(:scope, body).compact
result = s(:sclass, recv, scope)
result.line = val[2]
self.in_def = in_def
self.in_single = in_single
result
end
def new_super args
if args && args.node_type == :block_pass then
s(:super, args)
else
args ||= s(:arglist)
s(:super, *args[1..-1])
end
end
def new_undef n, m = nil
if m then
block_append(n, s(:undef, m))
else
s(:undef, n)
end
end
def new_until block, expr, pre
expr = (expr.first == :not ? expr.last : s(:not, expr)).line(expr.line)
new_while block, expr, pre
end
def new_while block, expr, pre
line = [block && block.line, expr.line].compact.min
block, pre = block.last, false if block && block[0] == :begin
expr = cond expr
result = if expr.first == :not then
s(:until, expr.last, block, pre)
else
s(:while, expr, block, pre)
end
result.line = line
result
end
def new_xstring str
if str then
case str[0]
when :str
str[0] = :xstr
when :dstr
str[0] = :dxstr
else
str = s(:dxstr, '', str)
end
str
else
s(:xstr, '')
end
end
def new_yield args = nil
raise SyntaxError, "Block argument should not be given." if
args && args.node_type == :block_pass
args ||= s(:arglist)
args = s(:arglist, args) unless [:arglist, :array].include? args.first
return s(:yield, *args[1..-1])
end
def next_token
if self.lexer.advance then
return self.lexer.token, self.lexer.yacc_value
else
return [false, '$end']
end
end
def node_assign(lhs, rhs) # TODO: rename new_assign
return nil unless lhs
rhs = value_expr rhs
case lhs[0]
when :gasgn, :iasgn, :lasgn, :dasgn, :dasgn_curr,
:masgn, :cdecl, :cvdecl, :cvasgn then
lhs << rhs
when :attrasgn, :call then
args = lhs.pop unless Symbol === lhs.last
lhs << arg_add(args, rhs)
when :const then
lhs[0] = :cdecl
lhs << rhs
else
raise "unknown lhs #{lhs.inspect}"
end
lhs
end
def process(str, file = "(string)")
raise "bad val: #{str.inspect}" unless String === str
self.file = file
self.lexer.src = str
@yydebug = ENV.has_key? 'DEBUG'
do_parse
end
alias :parse :process
def remove_begin node
oldnode = node
if node and :begin == node[0] and node.size == 2 then
node = node[-1]
node.line = oldnode.line
end
node
end
def reset
lexer.reset
self.in_def = false
self.in_single = 0
self.env.reset
self.comments.clear
end
def ret_args node
if node then
raise SyntaxError, "block argument should not be given" if
node[0] == :block_pass
node = node.last if node[0] == :array && node.size == 2
# HACK matz wraps ONE of the FOUR splats in a newline to
# distinguish. I use paren for now. ugh
node = s(:svalue, node) if node[0] == :splat and not node.paren
end
node
end
def s(*args)
result = Sexp.new(*args)
result.line ||= lexer.lineno if lexer.src # otherwise...
result.file = self.file
result
end
def value_expr oldnode # HACK
node = remove_begin oldnode
node.line = oldnode.line if oldnode
node[2] = value_expr(node[2]) if node and node[0] == :if
node
end
def void_stmts node
return nil unless node
return node unless node[0] == :block
node[1..-1] = node[1..-1].map { |n| remove_begin(n) }
node
end
def warning s
# do nothing for now
end
alias :old_yyerror :yyerror
def yyerror msg
# for now do nothing with the msg
old_yyerror
end
end
class Keyword
class KWtable
attr_accessor :name, :state, :id0, :id1
def initialize(name, id=[], state=nil)
@name = name
@id0, @id1 = id
@state = state
end
end
##
# :expr_beg = ignore newline, +/- is a sign.
# :expr_end = newline significant, +/- is a operator.
# :expr_arg = newline significant, +/- is a operator.
# :expr_cmdarg = newline significant, +/- is a operator.
# :expr_endarg = newline significant, +/- is a operator.
# :expr_mid = newline significant, +/- is a operator.
# :expr_fname = ignore newline, no reserved words.
# :expr_dot = right after . or ::, no reserved words.
# :expr_class = immediate after class, no here document.
wordlist = [
["end", [:kEND, :kEND ], :expr_end ],
["else", [:kELSE, :kELSE ], :expr_beg ],
["case", [:kCASE, :kCASE ], :expr_beg ],
["ensure", [:kENSURE, :kENSURE ], :expr_beg ],
["module", [:kMODULE, :kMODULE ], :expr_beg ],
["elsif", [:kELSIF, :kELSIF ], :expr_beg ],
["def", [:kDEF, :kDEF ], :expr_fname ],
["rescue", [:kRESCUE, :kRESCUE_MOD ], :expr_mid ],
["not", [:kNOT, :kNOT ], :expr_beg ],
["then", [:kTHEN, :kTHEN ], :expr_beg ],
["yield", [:kYIELD, :kYIELD ], :expr_arg ],
["for", [:kFOR, :kFOR ], :expr_beg ],
["self", [:kSELF, :kSELF ], :expr_end ],
["false", [:kFALSE, :kFALSE ], :expr_end ],
["retry", [:kRETRY, :kRETRY ], :expr_end ],
["return", [:kRETURN, :kRETURN ], :expr_mid ],
["true", [:kTRUE, :kTRUE ], :expr_end ],
["if", [:kIF, :kIF_MOD ], :expr_beg ],
["defined?", [:kDEFINED, :kDEFINED ], :expr_arg ],
["super", [:kSUPER, :kSUPER ], :expr_arg ],
["undef", [:kUNDEF, :kUNDEF ], :expr_fname ],
["break", [:kBREAK, :kBREAK ], :expr_mid ],
["in", [:kIN, :kIN ], :expr_beg ],
["do", [:kDO, :kDO ], :expr_beg ],
["nil", [:kNIL, :kNIL ], :expr_end ],
["until", [:kUNTIL, :kUNTIL_MOD ], :expr_beg ],
["unless", [:kUNLESS, :kUNLESS_MOD ], :expr_beg ],
["or", [:kOR, :kOR ], :expr_beg ],
["next", [:kNEXT, :kNEXT ], :expr_mid ],
["when", [:kWHEN, :kWHEN ], :expr_beg ],
["redo", [:kREDO, :kREDO ], :expr_end ],
["and", [:kAND, :kAND ], :expr_beg ],
["begin", [:kBEGIN, :kBEGIN ], :expr_beg ],
["__LINE__", [:k__LINE__, :k__LINE__ ], :expr_end ],
["class", [:kCLASS, :kCLASS ], :expr_class ],
["__FILE__", [:k__FILE__, :k__FILE__ ], :expr_end ],
["END", [:klEND, :klEND ], :expr_end ],
["BEGIN", [:klBEGIN, :klBEGIN ], :expr_end ],
["while", [:kWHILE, :kWHILE_MOD ], :expr_beg ],
["alias", [:kALIAS, :kALIAS ], :expr_fname ],
].map { |args| KWtable.new(*args) }
WORDLIST = Hash[*wordlist.map { |o| [o.name, o] }.flatten]
def self.keyword str
WORDLIST[str]
end
end
class Environment
attr_reader :env, :dyn
def [] k
self.all[k]
end
def []= k, v
raise "no" if v == true
self.current[k] = v
end
def all
idx = @dyn.index false
@env[0..idx].reverse.inject { |env, scope| env.merge scope }
end
def current
@env.first
end
def dynamic
idx = @dyn.index false
@env[0...idx].reverse.inject { |env, scope| env.merge scope } || {}
end
def dynamic?
@dyn[0] != false
end
def extend dyn = false
@dyn.unshift dyn
@env.unshift({})
@use.unshift({})
end
def initialize dyn = false
@dyn = []
@env = []
@use = []
self.reset
end
def reset
@dyn.clear
@env.clear
@use.clear
self.extend
end
def unextend
@dyn.shift
@env.shift
@use.shift
raise "You went too far unextending env" if @env.empty?
end
def use id
@env.each_with_index do |env, i|
if env[id] then
@use[i][id] = true
end
end
end
def used? id
idx = @dyn.index false # REFACTOR
u = @use[0...idx].reverse.inject { |env, scope| env.merge scope } || {}
u[id]
end
end
class StackState
attr_reader :stack
def initialize(name)
@name = name
@stack = [false]
end
def inspect
"StackState(#{@name}, #{@stack.inspect})"
end
def is_in_state
@stack.last
end
def lexpop
raise if @stack.size == 0
a = @stack.pop
b = @stack.pop
@stack.push(a || b)
end
def pop
r = @stack.pop
@stack.push false if @stack.size == 0
r
end
def push val
@stack.push val
end
end
############################################################
# HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK
class Symbol
def is_argument # TODO: phase this out
return self == :expr_arg || self == :expr_cmdarg
end
end
class Sexp
attr_writer :paren
attr_accessor :comments
attr_accessor :file
def line(n=nil)
if n then
@line = n
self
else
@line ||= nil
end
end
def line= n
@line = n
end
def node_type
first
end
def paren
@paren ||= false
end
def value
raise "multi item sexp" if size > 2
last
end
def to_sym
self.value.to_sym
end
def values
self[1..-1]
end
alias :real_inspect :inspect
def inspect # :nodoc:
sexp_str = self.map {|x|x.inspect}.join(', ')
if line && ENV['VERBOSE'] then
"s(#{sexp_str}).line(#{line})"
else
"s(#{sexp_str})"
end
end
end
# END HACK
############################################################
require 'test/unit'
require 'ruby_parser_extras'
class TestStackState < Test::Unit::TestCase
def test_stack_state
s = StackState.new :test
s.push true
s.push false
s.lexpop
assert_equal [false, true], s.stack
end
def test_is_in_state
s = StackState.new :test
assert_equal false, s.is_in_state
s.push false
assert_equal false, s.is_in_state
s.push true
assert_equal true, s.is_in_state
s.push false
assert_equal false, s.is_in_state
end
def test_lexpop
s = StackState.new :test
assert_equal [false], s.stack
s.push true
s.push false
assert_equal [false, true, false], s.stack
s.lexpop
assert_equal [false, true], s.stack
end
def test_pop
s = StackState.new :test
assert_equal [false], s.stack
s.push true
assert_equal [false, true], s.stack
assert_equal true, s.pop
assert_equal [false], s.stack
end
def test_push
s = StackState.new :test
assert_equal [false], s.stack
s.push true
s.push false
assert_equal [false, true, false], s.stack
end
end
class TestEnvironment < Test::Unit::TestCase
def deny t
assert ! t
end
def setup
@env = Environment.new
@env[:blah] = 42
assert_equal 42, @env[:blah]
end
def test_use
@env.use :blah
expected = [{ :blah => true }]
assert_equal expected, @env.instance_variable_get(:"@use")
end
def test_use_scoped
@env.use :blah
@env.extend
expected = [{}, { :blah => true }]
assert_equal expected, @env.instance_variable_get(:"@use")
end
def test_used_eh
@env.extend :dynamic
@env[:x] = :dvar
@env.use :x
assert_equal true, @env.used?(:x)
end
def test_used_eh_none
assert_equal nil, @env.used?(:x)
end
def test_used_eh_scoped
self.test_used_eh
@env.extend :dynamic
assert_equal true, @env.used?(:x)
end
def test_var_scope_dynamic
@env.extend :dynamic
assert_equal 42, @env[:blah]
@env.unextend
assert_equal 42, @env[:blah]
end
def test_var_scope_static
@env.extend
assert_equal nil, @env[:blah]
@env.unextend
assert_equal 42, @env[:blah]
end
def test_dynamic
expected1 = {}
expected2 = { :x => 42 }
assert_equal expected1, @env.dynamic
begin
@env.extend :dynamic
assert_equal expected1, @env.dynamic
@env[:x] = 42
assert_equal expected2, @env.dynamic
begin
@env.extend :dynamic
assert_equal expected2, @env.dynamic
@env.unextend
end
assert_equal expected2, @env.dynamic
@env.unextend
end
assert_equal expected1, @env.dynamic
end
def test_all_dynamic
expected = { :blah => 42 }
@env.extend :dynamic
assert_equal expected, @env.all
@env.unextend
assert_equal expected, @env.all
end
def test_all_static
@env.extend
expected = { }
assert_equal expected, @env.all
@env.unextend
expected = { :blah => 42 }
assert_equal expected, @env.all
end
def test_dynamic_eh
assert_equal false, @env.dynamic?
@env.extend :dynamic
assert_equal true, @env.dynamic?
@env.extend
assert_equal false, @env.dynamic?
end
def test_all_static_deeper
expected0 = { :blah => 42 }
expected1 = { :blah => 42, :blah2 => 24 }
expected2 = { :blah => 27 }
@env.extend :dynamic
@env[:blah2] = 24
assert_equal expected1, @env.all
@env.extend
@env[:blah] = 27
assert_equal expected2, @env.all
@env.unextend
assert_equal expected1, @env.all
@env.unextend
assert_equal expected0, @env.all
end
end
+108
-0

@@ -0,1 +1,109 @@

== 2.0.0 / 2008-10-22
* 1 major enhancement
* Brought on the AWESOME! 4x faster! no known lexing/parsing bugs!
* 71 minor enhancements
* 1.9: Added Fixnum#ord.
* 1.9: Added missing Regexp constants and did it so it'd work on 1.9.
* Added #store_comment and #comments
* Added StringScanner #begin_of_line?
* Added a bunch of tests for regexp escape chars, #parse_string, #read_escape, ? numbers, ? whitespace.
* Added a hack for rubinius' r2l eval bug.
* Added a new token type tSTRING that bypasses tSTRING_BEG/END entirely. Only does non-interpolated strings and then falls back to the old way. MUCH cleaner tho.
* Added bin/ruby_parse
* Added compare rule to Rakefile.
* Added coverage files/dirs to clean rule.
* Added file and line numbers to all sexp nodes. Column/ranges to come.
* Added lex_state change for lvars at the end of yylex.
* Added lexed comments to defn/defs/class/module nodes.
* Added stats gathering for yylex. Reordered yylex for avg data
* Added tSYMBOL token type and parser rule to speed up symbol lexing.
* Added tally output for getch, unread, and unread_many.
* Added tests for ambigous uminus/uplus, backtick in cmdarg, square and curly brackets, numeric gvars, eos edge cases, string quoting %<> and %%%.
* All cases throughout yylex now return directly if they match, no passthroughs.
* All lexer cases now slurp entire token in one swoop.
* All zarrays are now just empty arrays.
* Changed s(:block_arg, :blah) to :"&blah" in args sexp.
* Cleaned up lexer error handling. Now just raises all over.
* Cleaned up read_escape and regx_options
* Cleaned up tokadd_string (for some definition of cleaned).
* Converted single quoted strings to new tSTRING token type.
* Coverage is currently 94.4% on lexer.
* Done what I can to clean up heredoc lexing... still sucks.
* Flattened resbodies in rescue node. Fixed .autotest file.
* Folded lex_keywords back in now that it screams.
* Found very last instanceof ILiteralNode in the code. haha!
* Got the tests subclassing PTTC and cleaned up a lot. YAY
* Handle yield(*ary) properly
* MASSIVELY cleaned out =begin/=end comment processor.
* Massive overhaul on Keyword class. All hail the mighty Hash!
* Massively cleaned up ident= edge cases and fixed a stupid bug from jruby.
* Merged @/@@ scanner together, going to try to do the same everywhere.
* Refactored fix_arg_lex_state, common across the lexer.
* Refactored new_fcall into new_call.
* Refactored some code to get better profile numbers.
* Refactored some more #fix_arg_lex_state.
* Refactored tail of yylex into its own method.
* Removed Module#kill
* Removed Token, replaced with Sexp.
* Removed all parse_number and parse_quote tests.
* Removed argspush, argscat. YAY!
* Removed as many token_buffer.split(//)'s as possible. 1 to go.
* Removed begins from compstmts
* Removed buffer arg for tokadd_string.
* Removed crufty (?) solo '@' token... wtf was that anyhow?
* Removed most jruby/stringio cruft from StringScanner.
* Removed one unread_many... 2 to go. They're harder.
* Removed store_comment, now done directly.
* Removed token_buffer. Now I just use token ivar.
* Removed use of s() from lexer. Changed the way line numbers are gathered.
* Renamed *qwords to *awords.
* Renamed StringScanner to RPStringScanner (a subclass) to fix namespace trashing.
* Renamed parse to process and aliased to parse.
* Renamed token_buffer to string_buffer since that arcane shit still needs it.
* Resolved the rest of the lexing issues I brought up w/ ruby-core.
* Revamped tokadd_escape.
* Rewrote Keyword and KWtable.
* Rewrote RubyLexer using StringScanner.
* Rewrote tokadd_escape. 79 lines down to 21.
* Split out lib/ruby_parser_extras.rb so lexer is standalone.
* Started to clean up the parser and make it as skinny as possible
* Stripped out as much code as possible.
* Stripped yylex of some dead code.
* Switched from StringIO to StringScanner.
* Updated rakefile for new hoe.
* Uses pure ruby racc if ENV['PURE_RUBY'], otherwise use c.
* Wrote a ton of lexer tests. Coverage is as close to 100% as possible.
* Wrote args to clean up the big nasty args processing grammar section.
* lex_strterm is now a plain array, removed RubyLexer#s(...).
* yield and super now flatten args.
* 21+ bug fixes:
* I'm sure this list is missing a lot:
* Fixed 2 bugs both involving attrasgn (and ilk) esp when lhs is an array.
* Fixed a bug in the lexer for strings with single digit hex escapes.
* Fixed a bug parsing: a (args) { expr }... the space caused a different route to be followed and all hell broke loose.
* Fixed a bug with x\n=beginvar not putting begin back.
* Fixed attrasgn to have arglists, not arrays.
* Fixed bug in defn/defs with block fixing.
* Fixed class/module's name slot if colon2/3.
* Fixed dstr with empty interpolation body.
* Fixed for 1.9 string/char changes.
* Fixed lexer BS wrt determining token type of words.
* Fixed lexer BS wrt pass through values and lexing words. SO STUPID.
* Fixed lexing of floats.
* Fixed lexing of identifiers followed by equals. I hope.
* Fixed masgn with splat on lhs
* Fixed new_super to deal with block_pass correctly.
* Fixed parser's treatment of :colon2 and :colon3.
* Fixed regexp scanning of escaped numbers, ANY number is valid, not just octs.
* Fixed string scanning of escaped octs, allowing 1-3 chars.
* Fixed unescape for \n
* Fixed: omg this is stupid. '()' was returning bare nil
* Fixed: remove_begin now goes to the end, not sure why it didn't before.
== 1.0.0 / 2007-12-20

@@ -2,0 +110,0 @@

+3
-0

@@ -6,5 +6,8 @@ .autotest

Rakefile
bin/ruby_parse
lib/ruby_lexer.rb
lib/ruby_parser.y
lib/ruby_parser_extras.rb
test/test_ruby_lexer.rb
test/test_ruby_parser.rb
test/test_ruby_parser_extras.rb
+126
-28

@@ -5,13 +5,16 @@ # -*- ruby -*-

require 'hoe'
require './lib/ruby_lexer.rb'
hoe = Hoe.new('ruby_parser', RubyParser::VERSION) do |p|
p.rubyforge_name = 'parsetree'
p.author = 'Ryan Davis'
p.email = 'ryand-ruby@zenspider.com'
p.summary = p.paragraphs_of('README.txt', 2).join("\n\n")
p.description = p.paragraphs_of('README.txt', 2..6).join("\n\n")
p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[-1]
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
p.extra_deps << 'ParseTree'
Hoe.add_include_dirs("../../ParseTree/dev/lib",
"../../ParseTree/dev/test",
"../../RubyInline/dev/lib",
"../../sexp_processor/dev/lib")
require './lib/ruby_parser_extras.rb'
hoe = Hoe.new('ruby_parser', RubyParser::VERSION) do |parser|
parser.rubyforge_name = 'parsetree'
parser.developer('Ryan Davis', 'ryand-ruby@zenspider.com')
parser.extra_deps << 'ParseTree'
parser.extra_deps << ['sexp_processor', '>= 3.0.0']
end

@@ -21,13 +24,6 @@

module Rake::TaskManager
def all_tasks
@tasks
end
[:default, :multi, :test].each do |t|
task t => :parser
end
Rake.application.all_tasks["default"].prerequisites.clear
task :default => :parser
task :test => :parser
path = "pkg/ruby_parser-#{RubyParser::VERSION}"

@@ -40,20 +36,122 @@ task path => :parser do

desc "build the parser"
task :parser => ["lib/ruby_parser.rb"]
rule '.rb' => '.y' do |t|
sh "racc -g -o #{t.name} #{t.source}"
# -v = verbose
# -t = debugging parser ~4% reduction in speed -- keep for now
# -l = no-line-convert
sh "racc -v -t -l -o #{t.name} #{t.source}"
end
task :clean do
rm_f(Dir["**/*~"] +
Dir["**/*.diff"] +
Dir["lib/ruby_parser.rb"] +
Dir["lib/*.output"])
rm_rf(Dir["**/*~"] +
Dir["**/*.diff"] +
Dir["coverage.info"] +
Dir["coverage"] +
Dir["lib/ruby_parser.rb"] +
Dir["lib/*.output"])
end
# require 'rcov/rcovtask'
# Rcov::RcovTask.new do |t|
# t.test_files = FileList['test/test_ruby_lexer.rb']
# end
def next_num(glob)
num = Dir[glob].max[/\d+/].to_i + 1
end
begin
require 'rcov/rcovtask'
Rcov::RcovTask.new do |t|
pattern = ENV['PATTERN'] || 'test/test_ruby_*.rb'
t.test_files = FileList[pattern]
t.verbose = true
t.rcov_opts << "--threshold 80"
t.rcov_opts << "--no-color"
end
rescue LoadError
# skip
end
desc "Compares PT to RP and deletes all files that match"
task :compare do
files = Dir["unit/**/*.rb"]
puts "Parsing #{files.size} files"
files.each do |file|
puts file
system "./cmp.rb -q #{file} && rm #{file}"
end
system 'find -d unit -type d -empty -exec rmdir {} \;'
end
desc "Compares PT to RP and stops on first failure"
task :find_bug do
files = Dir["unit/**/*.rb"]
puts "Parsing #{files.size} files"
files.each do |file|
puts file
sh "./cmp.rb -q #{file}"
end
end
task :sort do
sh 'grepsort "^ +def" lib/ruby_lexer.rb'
sh 'grepsort "^ +def (test|util)" test/test_ruby_lexer.rb'
end
task :rcov_info => :parser do
pattern = ENV['PATTERN'] || "test/test_*.rb"
ruby "-Ilib -S rcov --text-report --save coverage.info #{pattern}"
end
task :rcov_overlay do
rcov, eol = Marshal.load(File.read("coverage.info")).last[ENV["FILE"]], 1
puts rcov[:lines].zip(rcov[:coverage]).map { |line, coverage|
bol, eol = eol, eol + line.length
[bol, eol, "#ffcccc"] unless coverage
}.compact.inspect
end
task :loc do
loc1 = `wc -l ../1.0.0/lib/ruby_lexer.rb`[/\d+/]
flog1 = `flog -s ../1.0.0/lib/ruby_lexer.rb`[/\d+\.\d+/]
loc2 = `cat lib/ruby_lexer.rb lib/ruby_parser_extras.rb | wc -l`[/\d+/]
flog2 = `flog -s lib/ruby_lexer.rb lib/ruby_parser_extras.rb`[/\d+\.\d+/]
loc1, loc2, flog1, flog2 = loc1.to_i, loc2.to_i, flog1.to_f, flog2.to_f
puts "1.0.0: loc = #{loc1} flog = #{flog1}"
puts "dev : loc = #{loc2} flog = #{flog2}"
puts "delta: loc = #{loc2-loc1} flog = #{flog2-flog1}"
end
desc "Validate against all normal files in unit dir"
task :validate do
sh "./cmp.rb unit/*.rb"
end
def run_and_log cmd, prefix
files = ENV['FILES'] || 'unit/*.rb'
p, x = prefix, "txt"
n = Dir["#{p}.*.#{x}"].map { |s| s[/\d+/].to_i }.max + 1 rescue 1
f = "#{p}.#{n}.#{x}"
sh "#{cmd} #{Hoe::RUBY_FLAGS} bin/ruby_parse -q -g #{files} &> #{f}"
puts File.read(f)
end
desc "Benchmark against all normal files in unit dir"
task :benchmark do
run_and_log "ruby", "benchmark"
end
desc "Profile against all normal files in unit dir"
task :profile do
run_and_log "zenprofile", "profile"
end
desc "what was that command again?"
task :huh? do
puts "ruby #{Hoe::RUBY_FLAGS} bin/ruby_parse -q -g ..."
end
# vim: syntax=Ruby
+1
-1

@@ -15,2 +15,3 @@ ruby_parser

* Pure ruby, no compiles.
* Includes preceding comment data for defn/defs/class/module nodes!
* Incredibly simple interface.

@@ -24,3 +25,2 @@ * Output is 100% equivalent to ParseTree.

* Known Issue: dasgn_curr decls can be out of order from ParseTree's.
* TODO: Add comment nodes.

@@ -27,0 +27,0 @@ == SYNOPSIS:

#!/usr/local/bin/ruby
require 'test/unit'
require 'ruby_lexer'
require "test/unit"
require "ruby_lexer"

@@ -12,5 +12,6 @@ class TestRubyLexer < Test::Unit::TestCase

def setup
@lex = RubyLexer.new
@lex.src = StringIO.new("blah blah")
@lex.lex_state = :expr_beg # HACK ? I have no idea actually
p = RubyParser.new
@lex = p.lexer
@lex.src = "blah blah"
@lex.lex_state = :expr_beg
end

@@ -24,60 +25,243 @@

def test_is_next_identchar
assert @lex.is_next_identchar
@lex.src = StringIO.new(" ")
deny @lex.is_next_identchar
@lex.src = StringIO.new("-")
deny @lex.is_next_identchar
def test_read_escape
util_escape "\\", "\\"
util_escape "\n", "n"
util_escape "\t", "t"
util_escape "\r", "r"
util_escape "\f", "f"
util_escape "\13", "v"
util_escape "\0", "0"
util_escape "\07", "a"
util_escape "\007", "a"
util_escape "\033", "e"
util_escape "\377", "377"
util_escape "\377", "xff"
util_escape "\010", "b"
util_escape " ", "s"
util_escape "q", "q" # plain vanilla escape
end
def test_is_next_no_case # TODO: worst name evah
@lex.src = StringIO.new("123 456")
assert @lex.is_next_no_case("123")
pos = @lex.src.pos
deny @lex.is_next_no_case("begin")
assert_equal " 456", @lex.src.read_all, "must put back contents"
def test_read_escape_c
util_escape "\030", "C-x"
util_escape "\030", "cx"
util_escape "\230", 'C-\M-x'
util_escape "\230", 'c\M-x'
util_escape "\177", "C-?"
util_escape "\177", "c?"
end
def test_number_token
node = @lex.number_token("42", false, "\0")
assert_equal :tINTEGER, node
assert_equal 42, @lex.yacc_value
def test_read_escape_errors
util_escape_bad ""
util_escape_bad "M"
util_escape_bad "M-"
util_escape_bad "Mx"
util_escape_bad "Cx"
util_escape_bad "C"
util_escape_bad "C-"
util_escape_bad "c"
end
def test_parse_number
@lex.src = StringIO.new '42'
node = @lex.parse_number('1')
assert_equal :tINTEGER, node
assert_equal 142, @lex.yacc_value
def test_read_escape_m
util_escape "\370", "M-x"
util_escape "\230", 'M-\C-x'
util_escape "\230", 'M-\cx'
end
def test_parse_quote
@lex.src = StringIO.new 'blah)'
node = @lex.parse_quote('(')
assert_equal :tSTRING_BEG, node
assert_equal s(:strterm, RubyLexer::STR_DQUOTE, ")", "("), @lex.lex_strterm
assert_equal ["%)"], @lex.yacc_value.args # FIX double check this
def test_yylex_ambiguous_uminus
util_lex_token("m -3",
:tIDENTIFIER, "m",
:tUMINUS_NUM, "-",
:tINTEGER, 3)
# TODO: verify warning
end
def test_yylex_integer
util_lex_token "42", :tINTEGER, 42
def test_yylex_ambiguous_uplus
util_lex_token("m +3",
:tIDENTIFIER, "m",
:tINTEGER, 3)
# TODO: verify warning
end
def test_yylex_integer_eh_a
util_lex_token('?a',
:tINTEGER, 97)
def test_yylex_and
util_lex_token "&", :tAMPER, "&"
end
def test_yylex_integer_eh_escape_M_escape_C
util_lex_token('?\M-\C-a',
:tINTEGER, 129)
def test_yylex_and2
util_lex_token "&&", :tANDOP, "&&"
end
def test_yylex_float
util_lex_token "1.0", :tFLOAT, 1.0
def test_yylex_and2_equals
util_lex_token "&&=", :tOP_ASGN, "&&"
end
def test_yylex_and_arg
@lex.lex_state = :expr_arg
util_lex_token(" &y",
:tAMPER, "&",
:tIDENTIFIER, "y")
end
def test_yylex_and_equals
util_lex_token "&=", :tOP_ASGN, "&"
end
def test_yylex_and_expr
@lex.lex_state = :expr_arg
util_lex_token("x & y",
:tIDENTIFIER, "x",
:tAMPER2, "&",
:tIDENTIFIER, "y")
end
def test_yylex_and_meth
util_lex_fname "&", :tAMPER2
end
def test_yylex_assoc
util_lex_token "=>", :tASSOC, "=>"
end
def test_yylex_back_ref
util_lex_token("[$&, $`, $', $+]",
:tLBRACK, "[",
:tBACK_REF, :"&", :tCOMMA, ",",
:tBACK_REF, :"`", :tCOMMA, ",",
:tBACK_REF, :"'", :tCOMMA, ",",
:tBACK_REF, :"+",
:tRBRACK, "]")
end
def test_yylex_backslash
util_lex_token("1 \\\n+ 2",
:tINTEGER, 1,
:tPLUS, "+",
:tINTEGER, 2)
end
def test_yylex_backslash_bad
util_bad_token("1 \\ + 2",
:tINTEGER, 1)
end
def test_yylex_backtick
util_lex_token("`ls`",
:tXSTRING_BEG, "`",
:tSTRING_CONTENT, "ls",
:tSTRING_END, "`")
end
def test_yylex_backtick_cmdarg
@lex.lex_state = :expr_dot
util_lex_token("\n`", :tBACK_REF2, "`") # \n ensures expr_cmd
assert_equal :expr_cmdarg, @lex.lex_state
end
def test_yylex_backtick_dot
@lex.lex_state = :expr_dot
util_lex_token("a.`(3)",
:tIDENTIFIER, "a",
:tDOT, ".",
:tBACK_REF2, "`",
:tLPAREN2, "(",
:tINTEGER, 3,
:tRPAREN, ")")
end
def test_yylex_backtick_method
@lex.lex_state = :expr_fname
util_lex_token("`", :tBACK_REF2, "`")
assert_equal :expr_end, @lex.lex_state
end
def test_yylex_bad_char
util_bad_token(" \010 ")
end
def test_yylex_bang
util_lex_token "!", :tBANG, "!"
end
def test_yylex_bang_equals
util_lex_token "!=", :tNEQ, "!="
end
def test_yylex_bang_tilde
util_lex_token "!~", :tNMATCH, "!~"
end
def test_yylex_carat
util_lex_token "^", :tCARET, "^"
end
def test_yylex_carat_equals
util_lex_token "^=", :tOP_ASGN, "^"
end
def test_yylex_colon2
util_lex_token("A::B",
:tCONSTANT, "A",
:tCOLON2, "::",
:tCONSTANT, "B")
end
def test_yylex_colon3
util_lex_token("::Array",
:tCOLON3, "::",
:tCONSTANT, "Array")
end
def test_yylex_comma
util_lex_token ",", :tCOMMA, ","
end
def test_yylex_comment
util_lex_token("1 # one\n# two\n2",
:tINTEGER, 1,
:tNL, nil,
:tINTEGER, 2)
assert_equal "# one\n# two\n", @lex.comments
end
def test_yylex_comment_begin
util_lex_token("=begin\nblah\nblah\n=end\n42",
:tINTEGER, 42)
assert_equal "=begin\nblah\nblah\n=end\n", @lex.comments
end
def test_yylex_comment_begin_bad
util_bad_token("=begin\nblah\nblah\n")
assert_equal "", @lex.comments
end
def test_yylex_comment_begin_not_comment
util_lex_token("beginfoo = 5\np x \\\n=beginfoo",
:tIDENTIFIER, "beginfoo",
:tEQL, "=",
:tINTEGER, 5,
:tNL, nil,
:tIDENTIFIER, "p",
:tIDENTIFIER, "x",
:tEQL, "=",
:tIDENTIFIER, "beginfoo")
end
def test_yylex_comment_begin_space
util_lex_token("=begin blah\nblah\n=end\n")
assert_equal "=begin blah\nblah\n=end\n", @lex.comments
end
def test_yylex_comment_eos
util_lex_token("# comment")
end
def test_yylex_constant
util_lex_token("ArgumentError",
:tCONSTANT, t("ArgumentError"))
:tCONSTANT, "ArgumentError")
end

@@ -87,315 +271,1471 @@

util_lex_token("ArgumentError;",
:tCONSTANT, t("ArgumentError"),
";", t(";"))
:tCONSTANT, "ArgumentError",
:tSEMI, ";")
end
def test_yylex_cvar
util_lex_token "@@blah", :tCVAR, "@@blah"
end
def test_yylex_cvar_bad
assert_raises SyntaxError do
util_lex_token "@@1"
end
end
def test_yylex_def_bad_name
@lex.lex_state = :expr_fname
util_bad_token("def [ ", :kDEF, "def")
end
def test_yylex_div
util_lex_token("a / 2",
:tIDENTIFIER, "a",
:tDIVIDE, "/",
:tINTEGER, 2)
end
def test_yylex_div_equals
util_lex_token("a /= 2",
:tIDENTIFIER, "a",
:tOP_ASGN, "/",
:tINTEGER, 2)
end
def test_yylex_do
util_lex_token("x do 42 end",
:tIDENTIFIER, "x",
:kDO, "do",
:tINTEGER, 42,
:kEND, "end")
end
def test_yylex_do_block
@lex.lex_state = :expr_endarg
@lex.cmdarg.push true
util_lex_token("x.y do 42 end",
:tIDENTIFIER, "x",
:tDOT, ".",
:tIDENTIFIER, "y",
:kDO_BLOCK, "do",
:tINTEGER, 42,
:kEND, "end")
end
def test_yylex_do_block2
@lex.lex_state = :expr_endarg
util_lex_token("do 42 end",
:kDO_BLOCK, "do",
:tINTEGER, 42,
:kEND, "end")
end
def test_yylex_do_cond
@lex.cond.push true
util_lex_token("x do 42 end",
:tIDENTIFIER, "x",
:kDO_COND, "do",
:tINTEGER, 42,
:kEND, "end")
end
def test_yylex_dollar
util_lex_token("$", "$", "$") # FIX: wtf is this?!?
end
def test_yylex_dot # HINT message sends
util_lex_token ".", :tDOT, "."
end
def test_yylex_dot2
util_lex_token "..", :tDOT2, ".."
end
def test_yylex_dot3
util_lex_token "...", :tDOT3, "..."
end
def test_yylex_equals
util_lex_token "=", :tEQL, "=" # FIX: this sucks
end
def test_yylex_equals2
util_lex_token "==", :tEQ, "=="
end
def test_yylex_equals3
util_lex_token "===", :tEQQ, "==="
end
def test_yylex_equals_tilde
util_lex_token "=~", :tMATCH, "=~"
end
def test_yylex_float
util_lex_token "1.0", :tFLOAT, 1.0
end
def test_yylex_float_bad_no_underscores
util_bad_token "1__0.0"
end
def test_yylex_float_bad_no_zero_leading
util_bad_token ".0"
end
def test_yylex_float_bad_trailing_underscore
util_bad_token "123_.0"
end
def test_yylex_float_call
util_lex_token("1.0.to_s",
:tFLOAT, 1.0,
:tDOT, ".",
:tIDENTIFIER, "to_s")
end
def test_yylex_float_dot_E
util_lex_token "1.0E10", :tFLOAT, 1.0e10
end
def test_yylex_float_dot_E_neg
util_lex_token("-1.0E10",
:tUMINUS_NUM, "-",
:tFLOAT, 1.0e10)
end
def test_yylex_float_dot_e
util_lex_token "1.0e10", :tFLOAT, 1.0e10
end
def test_yylex_float_dot_e_neg
util_lex_token("-1.0e10",
:tUMINUS_NUM, "-",
:tFLOAT, 1.0e10)
end
def test_yylex_float_e
util_lex_token "1e10", :tFLOAT, 1e10
end
def test_yylex_float_e_bad_double_e
util_bad_token "1e2e3"
end
def test_yylex_float_e_bad_trailing_underscore
util_bad_token "123_e10"
end
def test_yylex_float_e_minus
util_lex_token "1e-10", :tFLOAT, 1e-10
end
def test_yylex_float_e_neg
util_lex_token("-1e10",
:tUMINUS_NUM, "-",
:tFLOAT, 1e10)
end
def test_yylex_float_e_neg_minus
util_lex_token("-1e-10",
:tUMINUS_NUM, "-",
:tFLOAT, 1e-10)
end
def test_yylex_float_e_neg_plus
util_lex_token("-1e+10",
:tUMINUS_NUM, "-",
:tFLOAT, 1e10)
end
def test_yylex_float_e_plus
util_lex_token "1e+10", :tFLOAT, 1e10
end
def test_yylex_float_e_zero
util_lex_token "0e0", :tFLOAT, 0e0
end
def test_yylex_float_neg
util_lex_token("-1.0",
:tUMINUS_NUM, "-",
:tFLOAT, 1.0)
end
def test_yylex_ge
util_lex_token("a >= 2",
:tIDENTIFIER, "a",
:tGEQ, ">=",
:tINTEGER, 2)
end
def test_yylex_global
util_lex_token("$blah", :tGVAR, "$blah")
end
def test_yylex_global_backref
@lex.lex_state = :expr_fname
util_lex_token("$`", :tGVAR, "$`")
end
def test_yylex_global_dash_nothing
util_lex_token("$- ", :tGVAR, "$-")
end
def test_yylex_global_dash_something
util_lex_token("$-x", :tGVAR, "$-x")
end
def test_yylex_global_number
@lex.lex_state = :expr_fname
util_lex_token("$1", :tGVAR, "$1")
end
def test_yylex_global_number_big
@lex.lex_state = :expr_fname
util_lex_token("$1234", :tGVAR, "$1234")
end
def test_yylex_global_other
util_lex_token("[$~, $*, $$, $?, $!, $@, $/, $\\, $;, $,, $., $=, $:, $<, $>, $\"]",
:tLBRACK, "[",
:tGVAR, "$~", :tCOMMA, ",",
:tGVAR, "$*", :tCOMMA, ",",
:tGVAR, "$$", :tCOMMA, ",",
:tGVAR, "$\?", :tCOMMA, ",",
:tGVAR, "$!", :tCOMMA, ",",
:tGVAR, "$@", :tCOMMA, ",",
:tGVAR, "$/", :tCOMMA, ",",
:tGVAR, "$\\", :tCOMMA, ",",
:tGVAR, "$;", :tCOMMA, ",",
:tGVAR, "$,", :tCOMMA, ",",
:tGVAR, "$.", :tCOMMA, ",",
:tGVAR, "$=", :tCOMMA, ",",
:tGVAR, "$:", :tCOMMA, ",",
:tGVAR, "$<", :tCOMMA, ",",
:tGVAR, "$>", :tCOMMA, ",",
:tGVAR, "$\"",
:tRBRACK, "]")
end
def test_yylex_global_underscore
util_lex_token("$_",
:tGVAR, "$_")
end
def test_yylex_global_wierd
util_lex_token("$__blah",
:tGVAR, "$__blah")
end
def test_yylex_global_zero
util_lex_token("$0", :tGVAR, "$0")
end
def test_yylex_gt
util_lex_token("a > 2",
:tIDENTIFIER, "a",
:tGT, ">",
:tINTEGER, 2)
end
def test_yylex_heredoc_backtick
util_lex_token("a = <<`EOF`\n blah blah\nEOF\n",
:tIDENTIFIER, "a",
:tEQL, "=",
:tXSTRING_BEG, "`",
:tSTRING_CONTENT, " blah blah\n",
:tSTRING_END, "EOF",
:tNL, nil)
end
def test_yylex_heredoc_double
util_lex_token("a = <<\"EOF\"\n blah blah\nEOF\n",
:tIDENTIFIER, "a",
:tEQL, "=",
:tSTRING_BEG, "\"",
:tSTRING_CONTENT, " blah blah\n",
:tSTRING_END, "EOF",
:tNL, nil)
end
def test_yylex_heredoc_double_dash
util_lex_token("a = <<-\"EOF\"\n blah blah\n EOF\n",
:tIDENTIFIER, "a",
:tEQL, "=",
:tSTRING_BEG, "\"",
:tSTRING_CONTENT, " blah blah\n",
:tSTRING_END, "EOF",
:tNL, nil)
end
def test_yylex_heredoc_double_eos
util_bad_token("a = <<\"EOF\"\nblah",
:tIDENTIFIER, "a",
:tEQL, "=",
:tSTRING_BEG, "\"")
end
def test_yylex_heredoc_double_eos_nl
util_bad_token("a = <<\"EOF\"\nblah\n",
:tIDENTIFIER, "a",
:tEQL, "=",
:tSTRING_BEG, "\"")
end
def test_yylex_heredoc_double_interp
util_lex_token("a = <<\"EOF\"\n#x a \#@a b \#$b c \#{3} \nEOF\n",
:tIDENTIFIER, "a",
:tEQL, "=",
:tSTRING_BEG, "\"",
:tSTRING_CONTENT, "#x a ",
:tSTRING_DVAR, "\#@",
:tSTRING_CONTENT, "@a b ", # HUH?
:tSTRING_DVAR, "\#$",
:tSTRING_CONTENT, "$b c ", # HUH?
:tSTRING_DBEG, "\#{",
:tSTRING_CONTENT, "3} \n", # HUH?
:tSTRING_END, "EOF",
:tNL, nil)
end
def test_yylex_heredoc_none
util_lex_token("a = <<EOF\nblah\nblah\nEOF",
:tIDENTIFIER, "a",
:tEQL, "=",
:tSTRING_BEG, "\"",
:tSTRING_CONTENT, "blah\nblah\n",
:tSTRING_CONTENT, "",
:tSTRING_END, "EOF",
:tNL, nil)
end
def test_yylex_heredoc_none_bad_eos
util_bad_token("a = <<EOF",
:tIDENTIFIER, "a",
:tEQL, "=",
:tSTRING_BEG, "\"")
end
def test_yylex_heredoc_none_dash
util_lex_token("a = <<-EOF\nblah\nblah\n EOF",
:tIDENTIFIER, "a",
:tEQL, "=",
:tSTRING_BEG, "\"",
:tSTRING_CONTENT, "blah\nblah\n",
:tSTRING_CONTENT, "",
:tSTRING_END, "EOF",
:tNL, nil)
end
def test_yylex_heredoc_single
util_lex_token("a = <<'EOF'\n blah blah\nEOF\n",
:tIDENTIFIER, "a",
:tEQL, "=",
:tSTRING_BEG, "\"",
:tSTRING_CONTENT, " blah blah\n",
:tSTRING_END, "EOF",
:tNL, nil)
end
def test_yylex_heredoc_single_bad_eos_body
util_bad_token("a = <<'EOF'\nblah",
:tIDENTIFIER, "a",
:tEQL, "=",
:tSTRING_BEG, "\"")
end
def test_yylex_heredoc_single_bad_eos_empty
util_bad_token("a = <<''\n",
:tIDENTIFIER, "a",
:tEQL, "=",
:tSTRING_BEG, "\"")
end
def test_yylex_heredoc_single_bad_eos_term
util_bad_token("a = <<'EOF",
:tIDENTIFIER, "a",
:tEQL, "=",
:tSTRING_BEG, "\"")
end
def test_yylex_heredoc_single_bad_eos_term_nl
util_bad_token("a = <<'EOF\ns = 'blah blah'",
:tIDENTIFIER, "a",
:tEQL, "=",
:tSTRING_BEG, "\"")
end
def test_yylex_heredoc_single_dash
util_lex_token("a = <<-'EOF'\n blah blah\n EOF\n",
:tIDENTIFIER, "a",
:tEQL, "=",
:tSTRING_BEG, "\"",
:tSTRING_CONTENT, " blah blah\n",
:tSTRING_END, "EOF",
:tNL, nil)
end
def test_yylex_identifier
util_lex_token("identifier",
:tIDENTIFIER, t("identifier"))
util_lex_token("identifier", :tIDENTIFIER, "identifier")
end
def test_yylex_identifier_bang
util_lex_token("identifier!", :tFID, "identifier!")
end
def test_yylex_identifier_cmp
util_lex_fname "<=>", :tCMP
end
def test_yylex_identifier_def
util_lex_fname "identifier", :tIDENTIFIER, :expr_end
end
def test_yylex_identifier_eh
util_lex_token("identifier?", :tFID, "identifier?")
end
def test_yylex_identifier_equals_arrow
@lex.lex_state = :expr_fname
util_lex_token(":blah==>",
:tSYMBOL, "blah=",
:tASSOC, "=>")
end
def test_yylex_identifier_equals_caret
util_lex_fname "^", :tCARET
end
def test_yylex_identifier_equals_def
util_lex_fname "identifier=", :tIDENTIFIER, :expr_end
end
def test_yylex_identifier_equals_def2
util_lex_fname "==", :tEQ
end
def test_yylex_identifier_equals_expr
@lex.lex_state = :expr_dot
util_lex_token("y = arg",
:tIDENTIFIER, "y",
:tEQL, "=",
:tIDENTIFIER, "arg")
assert_equal :expr_arg, @lex.lex_state
end
def test_yylex_identifier_equals_or
util_lex_fname "|", :tPIPE
end
def test_yylex_identifier_equals_slash
util_lex_fname "/", :tDIVIDE
end
def test_yylex_identifier_equals_tilde
@lex.lex_state = :expr_fname # can only set via parser's defs
util_lex_token("identifier=~",
:tIDENTIFIER, "identifier",
:tMATCH, "=~")
end
def test_yylex_identifier_gt
util_lex_fname ">", :tGT
end
def test_yylex_identifier_le
util_lex_fname "<=", :tLEQ
end
def test_yylex_identifier_lt
util_lex_fname "<", :tLT
end
def test_yylex_identifier_tilde
util_lex_fname "~", :tTILDE
end
def test_yylex_index
util_lex_fname "[]", :tAREF
end
def test_yylex_index_equals
util_lex_fname "[]=", :tASET
end
def test_yylex_integer
util_lex_token "42", :tINTEGER, 42
end
def test_yylex_integer_bin
util_lex_token "0b101010", :tINTEGER, 42
end
def test_yylex_integer_bin_bad_none
util_bad_token "0b "
end
def test_yylex_integer_bin_bad_underscores
util_bad_token "0b10__01"
end
def test_yylex_integer_dec
util_lex_token "42", :tINTEGER, 42
end
def test_yylex_integer_dec_bad_underscores
util_bad_token "42__24"
end
def test_yylex_integer_dec_d
util_lex_token "0d42", :tINTEGER, 42
end
def test_yylex_integer_dec_d_bad_none
util_bad_token "0d"
end
def test_yylex_integer_dec_d_bad_underscores
util_bad_token "0d42__24"
end
def test_yylex_integer_eh_a
util_lex_token '?a', :tINTEGER, 97
end
def test_yylex_integer_eh_escape_M_escape_C
util_lex_token '?\M-\C-a', :tINTEGER, 129
end
def test_yylex_integer_hex
util_lex_token "0x2a", :tINTEGER, 42
end
def test_yylex_integer_hex_bad_none
util_bad_token "0x "
end
def test_yylex_integer_hex_bad_underscores
util_bad_token "0xab__cd"
end
def test_yylex_integer_oct
util_lex_token "052", :tINTEGER, 42
end
def test_yylex_integer_oct_bad_range
util_bad_token "08"
end
def test_yylex_integer_oct_bad_underscores
util_bad_token "01__23"
end
def test_yylex_integer_oct_o
util_lex_token "0o52", :tINTEGER, 42
end
def test_yylex_integer_oct_o_bad_range
util_bad_token "0o8"
end
def test_yylex_integer_oct_o_bad_underscores
util_bad_token "0o1__23"
end
def test_yylex_integer_oct_o_not_bad_none
util_lex_token "0o ", :tINTEGER, 0
end
def test_yylex_integer_trailing
util_lex_token("1.to_s",
:tINTEGER, 1,
:tDOT, '.',
:tIDENTIFIER, 'to_s')
end
def test_yylex_integer_underscore
util_lex_token "4_2", :tINTEGER, 42
end
def test_yylex_integer_underscore_bad
util_bad_token "4__2"
end
def test_yylex_integer_zero
util_lex_token "0", :tINTEGER, 0
end
def test_yylex_ivar
util_lex_token "@blah", :tIVAR, "@blah"
end
def test_yylex_ivar_bad
util_bad_token "@1"
end
def test_yylex_keyword_expr
@lex.lex_state = :expr_endarg
util_lex_token("if", :kIF_MOD, "if")
assert_equal :expr_beg, @lex.lex_state
end
def test_yylex_lt
util_lex_token "<", :tLT, "<"
end
def test_yylex_lt2
util_lex_token("a <\< b",
:tIDENTIFIER, "a",
:tLSHFT, "<\<",
:tIDENTIFIER, "b")
end
def test_yylex_lt2_equals
util_lex_token("a <\<= b",
:tIDENTIFIER, "a",
:tOP_ASGN, "<\<",
:tIDENTIFIER, "b")
end
def test_yylex_lt_equals
util_lex_token "<=", :tLEQ, "<="
end
def test_yylex_minus
util_lex_token("1 - 2",
:tINTEGER, 1,
:tMINUS, "-",
:tINTEGER, 2)
end
def test_yylex_minus_equals
util_lex_token "-=", :tOP_ASGN, "-"
end
def test_yylex_minus_method
@lex.lex_state = :expr_fname
util_lex_token "-", :tMINUS, "-"
end
def test_yylex_minus_unary_method
@lex.lex_state = :expr_fname
util_lex_token "-@", :tUMINUS, "-@"
end
def test_yylex_minus_unary_number
util_lex_token("-42",
:tUMINUS_NUM, "-",
:tINTEGER, 42)
end
def test_yylex_nth_ref
util_lex_token('[$1, $2, $3, $4, $5, $6, $7, $8, $9]',
:tLBRACK, "[",
:tNTH_REF, 1, :tCOMMA, ",",
:tNTH_REF, 2, :tCOMMA, ",",
:tNTH_REF, 3, :tCOMMA, ",",
:tNTH_REF, 4, :tCOMMA, ",",
:tNTH_REF, 5, :tCOMMA, ",",
:tNTH_REF, 6, :tCOMMA, ",",
:tNTH_REF, 7, :tCOMMA, ",",
:tNTH_REF, 8, :tCOMMA, ",",
:tNTH_REF, 9,
:tRBRACK, "]")
end
def test_yylex_open_bracket
util_lex_token("(", :tLPAREN, "(")
end
def test_yylex_open_bracket_cmdarg
@lex.lex_state = :expr_cmdarg
util_lex_token(" (", :tLPAREN_ARG, "(")
end
def test_yylex_open_bracket_exprarg
@lex.lex_state = :expr_arg
util_lex_token(" (", :tLPAREN2, "(")
end
def test_yylex_open_curly_bracket
util_lex_token("{",
:tLBRACE, "{")
end
def test_yylex_open_curly_bracket_arg
@lex.lex_state = :expr_arg
util_lex_token("m { 3 }",
:tIDENTIFIER, "m",
:tLCURLY, "{",
:tINTEGER, 3,
:tRCURLY, "}")
end
def test_yylex_open_curly_bracket_block
@lex.lex_state = :expr_endarg # seen m(3)
util_lex_token("{ 4 }",
:tLBRACE_ARG, "{",
:tINTEGER, 4,
:tRCURLY, "}")
end
def test_yylex_open_square_bracket_arg
@lex.lex_state = :expr_arg
util_lex_token("m [ 3 ]",
:tIDENTIFIER, "m",
:tLBRACK, "[",
:tINTEGER, 3,
:tRBRACK, "]")
end
def test_yylex_open_square_bracket_ary
util_lex_token("[1, 2, 3]",
:tLBRACK, "[",
:tINTEGER, 1,
:tCOMMA, ",",
:tINTEGER, 2,
:tCOMMA, ",",
:tINTEGER, 3,
:tRBRACK, "]")
end
def test_yylex_open_square_bracket_meth
util_lex_token("m[3]",
:tIDENTIFIER, "m",
"[", "[",
:tINTEGER, 3,
:tRBRACK, "]")
end
def test_yylex_or
util_lex_token "|", :tPIPE, "|"
end
def test_yylex_or2
util_lex_token "||", :tOROP, "||"
end
def test_yylex_or2_equals
util_lex_token "||=", :tOP_ASGN, "||"
end
def test_yylex_or_equals
util_lex_token "|=", :tOP_ASGN, "|"
end
def test_yylex_percent
util_lex_token("a % 2",
:tIDENTIFIER, "a",
:tPERCENT, "%",
:tINTEGER, 2)
end
def test_yylex_percent_equals
util_lex_token("a %= 2",
:tIDENTIFIER, "a",
:tOP_ASGN, "%",
:tINTEGER, 2)
end
def test_yylex_plus
util_lex_token("1 + 1", # TODO lex_state?
:tINTEGER, 1,
:tPLUS, "+",
:tINTEGER, 1)
end
def test_yylex_plus_equals
util_lex_token "+=", :tOP_ASGN, "+"
end
def test_yylex_plus_method
@lex.lex_state = :expr_fname
util_lex_token "+", :tPLUS, "+"
end
def test_yylex_plus_unary_method
@lex.lex_state = :expr_fname
util_lex_token "+@", :tUPLUS, "+@"
end
def test_yylex_plus_unary_number
util_lex_token("+42",
:tINTEGER, 42)
end
def test_yylex_question
util_lex_token "?*", :tINTEGER, 42
end
def test_yylex_question_bad_eos
util_bad_token "?"
end
def test_yylex_question_ws
util_lex_token "? ", :tEH, "?"
util_lex_token "?\n", :tEH, "?"
util_lex_token "?\t", :tEH, "?"
util_lex_token "?\v", :tEH, "?"
util_lex_token "?\r", :tEH, "?"
util_lex_token "?\f", :tEH, "?"
end
def test_yylex_question_ws_backslashed
@lex.lex_state = :expr_beg
util_lex_token "?\\ ", :tINTEGER, 32
@lex.lex_state = :expr_beg
util_lex_token "?\\n", :tINTEGER, 10
@lex.lex_state = :expr_beg
util_lex_token "?\\t", :tINTEGER, 9
@lex.lex_state = :expr_beg
util_lex_token "?\\v", :tINTEGER, 11
@lex.lex_state = :expr_beg
util_lex_token "?\\r", :tINTEGER, 13
@lex.lex_state = :expr_beg
util_lex_token "?\\f", :tINTEGER, 12
end
def test_yylex_rbracket
util_lex_token "]", :tRBRACK, "]"
end
def test_yylex_rcurly
util_lex_token "}", :tRCURLY, "}"
end
def test_yylex_regexp
util_lex_token("/regexp/",
:tREGEXP_BEG, t("/"),
:tSTRING_CONTENT, s(:str, "regexp"),
:tREGEXP_BEG, "/",
:tSTRING_CONTENT, "regexp",
:tREGEXP_END, "")
end
def test_yylex_regexp_nm
util_lex_token("/.*/nm",
:tREGEXP_BEG, t("/"),
:tSTRING_CONTENT, s(:str, ".*"),
:tREGEXP_END, "nm")
def test_yylex_regexp_ambiguous
util_lex_token("method /regexp/",
:tIDENTIFIER, "method",
:tREGEXP_BEG, "/",
:tSTRING_CONTENT, "regexp",
:tREGEXP_END, "")
end
def test_yylex_regexp_escapes
util_lex_token('/re\tge\nxp/',
:tREGEXP_BEG, t("/"),
:tSTRING_CONTENT, s(:str, "re\\tge\\nxp"),
def test_yylex_regexp_bad
util_bad_token("/.*/xyz",
:tREGEXP_BEG, "/",
:tSTRING_CONTENT, ".*")
end
def test_yylex_regexp_escape_C
util_lex_token('/regex\\C-x/',
:tREGEXP_BEG, "/",
:tSTRING_CONTENT, "regex\\C-x",
:tREGEXP_END, "")
end
def test_yylex_regexp_escape_oct
util_lex_token('/re\tge\101xp/',
:tREGEXP_BEG, t("/"),
:tSTRING_CONTENT, s(:str, "re\\tge\\101xp"),
def test_yylex_regexp_escape_C_M
util_lex_token('/regex\\C-\\M-x/',
:tREGEXP_BEG, "/",
:tSTRING_CONTENT, "regex\\C-\\M-x",
:tREGEXP_END, "")
end
def test_yylex_regexp_escape_C_M_craaaazy
util_lex_token("/regex\\C-\\\n\\M-x/",
:tREGEXP_BEG, "/",
:tSTRING_CONTENT, "regex\\C-\\M-x",
:tREGEXP_END, "")
end
def test_yylex_regexp_escape_C_bad_dash
util_bad_token '/regex\\Cx/', :tREGEXP_BEG, "/"
end
def test_yylex_regexp_escape_C_bad_dash_eos
util_bad_token '/regex\\C-/', :tREGEXP_BEG, "/"
end
def test_yylex_regexp_escape_C_bad_dash_eos2
util_bad_token '/regex\\C-', :tREGEXP_BEG, "/"
end
def test_yylex_regexp_escape_C_bad_eos
util_bad_token '/regex\\C/', :tREGEXP_BEG, "/"
end
def test_yylex_regexp_escape_C_bad_eos2
util_bad_token '/regex\\c', :tREGEXP_BEG, "/"
end
def test_yylex_regexp_escape_M
util_lex_token('/regex\\M-x/',
:tREGEXP_BEG, "/",
:tSTRING_CONTENT, "regex\\M-x",
:tREGEXP_END, "")
end
def test_yylex_regexp_escape_M_C
util_lex_token('/regex\\M-\\C-x/',
:tREGEXP_BEG, "/",
:tSTRING_CONTENT, "regex\\M-\\C-x",
:tREGEXP_END, "")
end
def test_yylex_regexp_escape_M_bad_dash
util_bad_token '/regex\\Mx/', :tREGEXP_BEG, "/"
end
def test_yylex_regexp_escape_M_bad_dash_eos
util_bad_token '/regex\\M-/', :tREGEXP_BEG, "/"
end
def test_yylex_regexp_escape_M_bad_dash_eos2
util_bad_token '/regex\\M-', :tREGEXP_BEG, "/"
end
def test_yylex_regexp_escape_M_bad_eos
util_bad_token '/regex\\M/', :tREGEXP_BEG, "/"
end
def test_yylex_regexp_escape_backslash_slash
util_lex_token('/\\//',
:tREGEXP_BEG, "/",
:tSTRING_CONTENT, '\\/',
:tREGEXP_END, "")
end
def test_yylex_regexp_escape_backslash_terminator
util_lex_token('%r%blah\\%blah%',
:tREGEXP_BEG, "%r\000", # FIX ?!?
:tSTRING_CONTENT, "blah\\%blah",
:tREGEXP_END, "")
end
def test_yylex_regexp_escape_backslash_terminator_meta1
util_lex_token('%r{blah\\}blah}',
:tREGEXP_BEG, "%r{", # FIX ?!?
:tSTRING_CONTENT, "blah\\}blah",
:tREGEXP_END, "")
end
def test_yylex_regexp_escape_backslash_terminator_meta2
util_lex_token('%r/blah\\/blah/',
:tREGEXP_BEG, "%r\000", # FIX ?!?
:tSTRING_CONTENT, "blah\\/blah",
:tREGEXP_END, "")
end
def test_yylex_regexp_escape_backslash_terminator_meta3
util_lex_token('%r/blah\\%blah/',
:tREGEXP_BEG, "%r\000", # FIX ?!?
:tSTRING_CONTENT, "blah\\%blah",
:tREGEXP_END, "")
end
def test_yylex_regexp_escape_bad_eos
util_bad_token '/regex\\', :tREGEXP_BEG, "/"
end
def test_yylex_regexp_escape_bs
util_lex_token('/regex\\\\regex/',
:tREGEXP_BEG, "/",
:tSTRING_CONTENT, "regex\\\\regex",
:tREGEXP_END, "")
end
def test_yylex_regexp_escape_c
util_lex_token('/regex\\cxxx/',
:tREGEXP_BEG, "/",
:tSTRING_CONTENT, "regex\\cxxx",
:tREGEXP_END, "")
end
def test_yylex_regexp_escape_c_backslash
util_lex_token('/regex\\c\\n/',
:tREGEXP_BEG, "/",
:tSTRING_CONTENT, "regex\\c\\n",
:tREGEXP_END, "")
end
def test_yylex_regexp_escape_chars
util_lex_token('/re\\tge\\nxp/',
:tREGEXP_BEG, "/",
:tSTRING_CONTENT, "re\\tge\\nxp",
:tREGEXP_END, "")
end
def test_yylex_regexp_escape_double_backslash
regexp = '/[\\/\\\\]$/'
util_lex_token(regexp,
:tREGEXP_BEG, "/",
:tSTRING_CONTENT, regexp[1..-2],
:tREGEXP_END, "")
end
def test_yylex_regexp_escape_hex
util_lex_token('/re\tge\x61xp/',
:tREGEXP_BEG, t("/"),
:tSTRING_CONTENT, s(:str, "re\\tge\\x61xp"),
util_lex_token('/regex\\x61xp/',
:tREGEXP_BEG, "/",
:tSTRING_CONTENT, "regex\\x61xp",
:tREGEXP_END, "")
end
def test_yylex_regexp_escape_hex_one
util_lex_token('/^[\\xd\\xa]{2}/on',
:tREGEXP_BEG, '/',
:tSTRING_CONTENT, '^[\\xd\\xa]{2}',
:tREGEXP_END, 'on')
end
def test_yylex_regexp_escape_hex_bad
util_bad_token '/regex\\xzxp/', :tREGEXP_BEG, "/"
end
def test_yylex_regexp_escape_oct1
util_lex_token('/regex\\0xp/',
:tREGEXP_BEG, "/",
:tSTRING_CONTENT, "regex\\0xp",
:tREGEXP_END, "")
end
def test_yylex_regexp_escape_oct2
util_lex_token('/regex\\07xp/',
:tREGEXP_BEG, "/",
:tSTRING_CONTENT, "regex\\07xp",
:tREGEXP_END, "")
end
def test_yylex_regexp_escape_oct3
util_lex_token('/regex\\10142/',
:tREGEXP_BEG, "/",
:tSTRING_CONTENT, "regex\\10142",
:tREGEXP_END, "")
end
def test_yylex_regexp_escape_return
util_lex_token("/regex\\\nregex/",
:tREGEXP_BEG, "/",
:tSTRING_CONTENT, "regexregex",
:tREGEXP_END, "")
end
def test_yylex_regexp_nm
util_lex_token("/.*/nm",
:tREGEXP_BEG, "/",
:tSTRING_CONTENT, ".*",
:tREGEXP_END, "nm")
end
def test_yylex_rparen
util_lex_token ")", :tRPAREN, ")"
end
def test_yylex_rshft
util_lex_token("a >> 2",
:tIDENTIFIER, "a",
:tRSHFT, ">>",
:tINTEGER, 2)
end
def test_yylex_rshft_equals
util_lex_token("a >>= 2",
:tIDENTIFIER, "a",
:tOP_ASGN, ">>",
:tINTEGER, 2)
end
def test_yylex_star
util_lex_token("a * ",
:tIDENTIFIER, "a",
:tSTAR2, "*")
assert_equal :expr_beg, @lex.lex_state
end
def test_yylex_star2
util_lex_token("a ** ",
:tIDENTIFIER, "a",
:tPOW, "**")
assert_equal :expr_beg, @lex.lex_state
end
def test_yylex_star2_equals
util_lex_token("a **= ",
:tIDENTIFIER, "a",
:tOP_ASGN, "**")
assert_equal :expr_beg, @lex.lex_state
end
def test_yylex_star_arg
@lex.lex_state = :expr_arg
util_lex_token(" *a",
:tSTAR, "*",
:tIDENTIFIER, "a")
assert_equal :expr_arg, @lex.lex_state
end
def test_yylex_star_arg_beg
@lex.lex_state = :expr_beg
util_lex_token("*a",
:tSTAR, "*",
:tIDENTIFIER, "a")
assert_equal :expr_arg, @lex.lex_state
end
def test_yylex_star_arg_beg_fname
@lex.lex_state = :expr_fname
util_lex_token("*a",
:tSTAR2, "*",
:tIDENTIFIER, "a")
assert_equal :expr_arg, @lex.lex_state
end
def test_yylex_star_equals
util_lex_token("a *= ",
:tIDENTIFIER, "a",
:tOP_ASGN, "*")
assert_equal :expr_beg, @lex.lex_state
end
def test_yylex_string_bad_eos
util_bad_token('%',
:tSTRING_BEG, '%')
end
def test_yylex_string_bad_eos_quote
util_bad_token('%{nest',
:tSTRING_BEG, '%}')
end
def test_yylex_string_double
util_lex_token('"string"',
:tSTRING_BEG, t('"'),
:tSTRING_CONTENT, s(:str, "string"),
:tSTRING_END, t('"'))
:tSTRING, "string")
end
def test_yylex_string_double_escapes
util_lex_token('"s\tri\ng"',
:tSTRING_BEG, t('"'),
:tSTRING_CONTENT, s(:str, "s\tri\ng"),
:tSTRING_END, t('"'))
def test_yylex_string_double_escape_M
util_lex_token('"\\M-g"',
:tSTRING, "\347")
end
def test_yylex_string_double_escape_M
util_lex_token('"\M-g"',
:tSTRING_BEG, t('"'),
:tSTRING_CONTENT, s(:str, "\347"),
:tSTRING_END, t('"'))
def test_yylex_string_escape_x_single
util_lex_token('"\\x0"',
:tSTRING, "\000")
end
def test_yylex_string_double_escape_octal
util_lex_token('"n = \101\102\103"',
:tSTRING_BEG, t('"'),
:tSTRING_CONTENT, s(:str, "n = ABC"),
:tSTRING_END, t('"'))
def test_yylex_string_double_escape_chars
util_lex_token('"s\\tri\\ng"',
:tSTRING, "s\tri\ng")
end
def test_yylex_string_double_escape_hex
util_lex_token('"n = \x61\x62\x63"',
:tSTRING_BEG, t('"'),
:tSTRING_CONTENT, s(:str, "n = abc"),
:tSTRING_END, t('"'))
util_lex_token('"n = \\x61\\x62\\x63"',
:tSTRING, "n = abc")
end
def test_yylex_string_single
util_lex_token("'string'",
:tSTRING_BEG, t("'"),
:tSTRING_CONTENT, s(:str, "string"),
:tSTRING_END, t("'"))
def test_yylex_string_double_escape_bs1
util_lex_token('"a\\a\\a"',
:tSTRING, "a\a\a")
end
def test_yylex_string_pct_Q
util_lex_token("%Q[string]",
:tSTRING_BEG, t("%Q["),
:tSTRING_CONTENT, s(:str, "string"),
:tSTRING_END, t("]"))
def test_yylex_string_double_escape_bs2
util_lex_token('"a\\\\a"',
:tSTRING, "a\\a")
end
def test_yylex_string_single_escapes
util_lex_token("'s\\tri\\ng'",
:tSTRING_BEG, t("'"),
:tSTRING_CONTENT, s(:str, "s\\tri\\ng"),
:tSTRING_END, t("'"))
def test_yylex_string_double_escape_octal
util_lex_token('"n = \\101\\102\\103"',
:tSTRING, "n = ABC")
end
def test_yylex_global
util_lex_token("$blah",
:tGVAR, t("$blah"))
def test_yylex_string_double_interp
util_lex_token("\"blah #x a \#@a b \#$b c \#{3} # \"",
:tSTRING_BEG, "\"",
:tSTRING_CONTENT, "blah #x a ",
:tSTRING_DVAR, nil,
:tSTRING_CONTENT, "@a b ",
:tSTRING_DVAR, nil,
:tSTRING_CONTENT, "$b c ",
:tSTRING_DBEG, nil,
:tSTRING_CONTENT, "3} # ",
:tSTRING_END, "\"")
end
def test_yylex_global_wierd
util_lex_token("$__blah",
:tGVAR, t("$__blah"))
def test_yylex_string_double_nested_curlies
util_lex_token('%{nest{one{two}one}nest}',
:tSTRING_BEG, '%}',
:tSTRING_CONTENT, "nest{one{two}one}nest",
:tSTRING_END, '}')
end
def test_yylex_global_dollar_underscore
util_lex_token("$_",
:tGVAR, t("$_"))
def test_yylex_string_double_no_interp
util_lex_token("\"# blah\"", # pound first
:tSTRING, "# blah")
util_lex_token("\"blah # blah\"", # pound not first
:tSTRING, "blah # blah")
end
def test_yylex_symbol
util_lex_token(":symbol",
:tSYMBEG, t(":"),
:tIDENTIFIER, t("symbol"))
def test_yylex_string_pct_Q
util_lex_token("%Q[s1 s2]",
:tSTRING_BEG, "%Q[",
:tSTRING_CONTENT, "s1 s2",
:tSTRING_END, "]")
end
def test_yylex_comment_begin
util_lex_token("=begin\nblah\nblah\n=end\n42",
:tINTEGER, 42)
def test_yylex_string_pct_W
util_lex_token("%W[s1 s2\ns3]", # TODO: add interpolation to these
:tWORDS_BEG, "%W[",
:tSTRING_CONTENT, "s1",
:tSPACE, nil,
:tSTRING_CONTENT, "s2",
:tSPACE, nil,
:tSTRING_CONTENT, "s3",
:tSPACE, nil,
:tSTRING_END, nil)
end
def util_lex_token input, *args
@lex.src = StringIO.new input
def test_yylex_string_pct_W_bs_nl
util_lex_token("%W[s1 \\\ns2]", # TODO: add interpolation to these
:tWORDS_BEG, "%W[",
:tSTRING_CONTENT, "s1",
:tSPACE, nil,
:tSTRING_CONTENT, "\ns2",
:tSPACE, nil,
:tSTRING_END, nil)
end
until args.empty? do
token = args.shift
value = args.shift
assert @lex.advance, "no more tokens"
assert_equal [token, value], [@lex.token, @lex.yacc_value]
end
def test_yylex_string_pct_angle
util_lex_token("%<blah>",
:tSTRING_BEG, "%>",
:tSTRING_CONTENT, "blah",
:tSTRING_END, ">")
end
deny @lex.advance, "must be empty, but had #{[@lex.token, @lex.yacc_value].inspect}"
def test_yylex_string_pct_other
util_lex_token("%%blah%",
:tSTRING_BEG, "%%",
:tSTRING_CONTENT, "blah",
:tSTRING_END, "%")
end
end
class TestStackState < Test::Unit::TestCase
def test_stack_state
s = StackState.new :test
s.push true
s.push false
s.lexpop
assert_equal [false, true], s.stack
def test_yylex_string_pct_w
util_bad_token("%w[s1 s2 ",
:tAWORDS_BEG, "%w[",
:tSTRING_CONTENT, "s1",
:tSPACE, nil,
:tSTRING_CONTENT, "s2",
:tSPACE, nil)
end
def test_is_in_state
s = StackState.new :test
assert_equal false, s.is_in_state
s.push false
assert_equal false, s.is_in_state
s.push true
assert_equal true, s.is_in_state
s.push false
assert_equal false, s.is_in_state
def test_yylex_string_pct_w_bs_nl
util_lex_token("%w[s1 \\\ns2]",
:tAWORDS_BEG, "%w[",
:tSTRING_CONTENT, "s1",
:tSPACE, nil,
:tSTRING_CONTENT, "\ns2",
:tSPACE, nil,
:tSTRING_END, nil)
end
def test_lexpop
s = StackState.new :test
assert_equal [false], s.stack
s.push true
s.push false
assert_equal [false, true, false], s.stack
s.lexpop
assert_equal [false, true], s.stack
def test_yylex_string_pct_w_bs_sp
util_lex_token("%w[s\\ 1 s\\ 2]",
:tAWORDS_BEG, "%w[",
:tSTRING_CONTENT, "s 1",
:tSPACE, nil,
:tSTRING_CONTENT, "s 2",
:tSPACE, nil,
:tSTRING_END, nil)
end
def test_pop
s = StackState.new :test
assert_equal [false], s.stack
s.push true
assert_equal [false, true], s.stack
assert_equal true, s.pop
assert_equal [false], s.stack
def test_yylex_string_single
util_lex_token("'string'",
:tSTRING, "string")
end
def test_push
s = StackState.new :test
assert_equal [false], s.stack
s.push true
s.push false
assert_equal [false, true, false], s.stack
def test_yylex_string_single_escape_chars
util_lex_token("'s\\tri\\ng'",
:tSTRING, "s\\tri\\ng")
end
end
class TestEnvironment < Test::Unit::TestCase
def deny t
assert ! t
def test_yylex_string_single_nl
util_lex_token("'blah\\\nblah'",
:tSTRING, "blah\\\nblah")
end
def setup
@env = Environment.new
@env[:blah] = 42
assert_equal 42, @env[:blah]
def test_yylex_symbol
util_lex_token(":symbol",
:tSYMBOL, "symbol")
end
def test_use
@env.use :blah
expected = [{ :blah => true }]
assert_equal expected, @env.instance_variable_get(:"@use")
def test_yylex_symbol_bad_zero
util_bad_token(":\"blah\0\"",
:tSYMBEG, ":")
end
def test_use_scoped
@env.use :blah
@env.extend
expected = [{}, { :blah => true }]
assert_equal expected, @env.instance_variable_get(:"@use")
def test_yylex_symbol_double
util_lex_token(":\"symbol\"",
:tSYMBEG, ":",
:tSTRING_CONTENT, "symbol",
:tSTRING_END, '"')
end
def test_used_eh
@env.extend :dynamic
@env[:x] = :dvar
@env.use :x
assert_equal true, @env.used?(:x)
def test_yylex_symbol_single
util_lex_token(":'symbol'",
:tSYMBEG, ":",
:tSTRING_CONTENT, "symbol",
:tSTRING_END, "'")
end
def test_used_eh_none
assert_equal nil, @env.used?(:x)
def test_yylex_ternary
util_lex_token("a ? b : c",
:tIDENTIFIER, "a",
:tEH, "?",
:tIDENTIFIER, "b",
:tCOLON, ":",
:tIDENTIFIER, "c")
util_lex_token("a ?bb : c", # GAH! MATZ!!!
:tIDENTIFIER, "a",
:tEH, "?",
:tIDENTIFIER, "bb",
:tCOLON, ":",
:tIDENTIFIER, "c")
util_lex_token("42 ?", # 42 forces expr_end
:tINTEGER, 42,
:tEH, "?")
end
def test_used_eh_scoped
self.test_used_eh
@env.extend :dynamic
assert_equal true, @env.used?(:x)
def test_yylex_tilde
util_lex_token "~", :tTILDE, "~"
end
def test_var_scope_dynamic
@env.extend :dynamic
assert_equal 42, @env[:blah]
@env.unextend
assert_equal 42, @env[:blah]
def test_yylex_tilde_unary
@lex.lex_state = :expr_fname
util_lex_token "~@", :tTILDE, "~"
end
def test_var_scope_static
@env.extend
assert_equal nil, @env[:blah]
@env.unextend
assert_equal 42, @env[:blah]
def test_yylex_uminus
util_lex_token("-blah",
:tUMINUS, "-",
:tIDENTIFIER, "blah")
end
def test_dynamic
expected1 = {}
expected2 = { :x => 42 }
def test_yylex_underscore
util_lex_token("_var", :tIDENTIFIER, "_var")
end
assert_equal expected1, @env.dynamic
begin
@env.extend :dynamic
assert_equal expected1, @env.dynamic
def test_yylex_underscore_end
@lex.src = "__END__\n"
deny @lex.advance
end
@env[:x] = 42
assert_equal expected2, @env.dynamic
def test_yylex_uplus
util_lex_token("+blah",
:tUPLUS, "+",
:tIDENTIFIER, "blah")
end
begin
@env.extend :dynamic
assert_equal expected2, @env.dynamic
@env.unextend
end
def test_zbug_float_in_decl
util_lex_token("def initialize(u = ",
:kDEF, "def",
:tIDENTIFIER, "initialize",
:tLPAREN2, "(",
:tIDENTIFIER, "u",
:tEQL, "=")
assert_equal expected2, @env.dynamic
@env.unextend
end
assert_equal expected1, @env.dynamic
assert_equal :expr_beg, @lex.lex_state
util_lex_token("0.0, s = 0.0",
:tFLOAT, 0.0,
:tCOMMA, ',',
:tIDENTIFIER, "s",
:tEQL, "=",
:tFLOAT, 0.0)
end
def test_all_dynamic
expected = { :blah => 42 }
def test_zbug_id_equals
util_lex_token("a =",
:tIDENTIFIER, "a",
:tEQL, "=")
@env.extend :dynamic
assert_equal expected, @env.all
@env.unextend
assert_equal expected, @env.all
assert_equal :expr_beg, @lex.lex_state
util_lex_token("0.0",
:tFLOAT, 0.0)
end
def test_all_static
@env.extend
expected = { }
assert_equal expected, @env.all
def test_zbug_no_spaces_in_decl
util_lex_token("def initialize(u=",
:kDEF, "def",
:tIDENTIFIER, "initialize",
:tLPAREN2, "(",
:tIDENTIFIER, "u",
:tEQL, "=")
@env.unextend
expected = { :blah => 42 }
assert_equal expected, @env.all
assert_equal :expr_beg, @lex.lex_state
util_lex_token("0.0,s=0.0",
:tFLOAT, 0.0,
:tCOMMA, ",",
:tIDENTIFIER, "s",
:tEQL, "=",
:tFLOAT, 0.0)
end
def test_dynamic_eh
assert_equal false, @env.dynamic?
@env.extend :dynamic
assert_equal true, @env.dynamic?
@env.extend
assert_equal false, @env.dynamic?
############################################################
def util_bad_token s, *args
assert_raises SyntaxError do
util_lex_token s, *args
end
end
def test_all_static_deeper
expected0 = { :blah => 42 }
expected1 = { :blah => 42, :blah2 => 24 }
expected2 = { :blah => 27 }
def util_escape expected, input
@lex.src = input
assert_equal expected, @lex.read_escape
end
@env.extend :dynamic
@env[:blah2] = 24
assert_equal expected1, @env.all
def util_escape_bad input
@lex.src = input
assert_raises SyntaxError do
@lex.read_escape
end
end
@env.extend
@env[:blah] = 27
assert_equal expected2, @env.all
def util_lex_fname name, type, end_state = :expr_arg
@lex.lex_state = :expr_fname # can only set via parser's defs
@env.unextend
assert_equal expected1, @env.all
util_lex_token("def #{name} ", :kDEF, "def", type, name)
@env.unextend
assert_equal expected0, @env.all
assert_equal end_state, @lex.lex_state
end
def util_lex_token input, *args
@lex.src = input
until args.empty? do
token = args.shift
value = args.shift
assert @lex.advance, "no more tokens"
assert_equal [token, value], [@lex.token, @lex.yacc_value]
end
deny @lex.advance, "must be empty, but had #{[@lex.token, @lex.yacc_value].inspect}"
end
end

@@ -11,56 +11,26 @@ #!/usr/local/bin/ruby

class TestRubyParser < Test::Unit::TestCase # ParseTreeTestCase
class RubyParser
def process input
parse input
end
end
# Regular ParseTreeTestCase tests
eval ParseTreeTestCase.testcases.map { |node, data|
next if node.to_s =~ /bmethod|dmethod/
next if Array === data['Ruby'] # runtime only crap
"def test_#{node}
rb = #{data['Ruby'].inspect}
pt = #{data['ParseTree'].inspect}
class RubyParserTestCase < ParseTreeTestCase
def self.previous key
"Ruby"
end
assert_not_nil rb, \"Ruby for #{node} undefined\"
assert_not_nil pt, \"ParseTree for #{node} undefined\"
def self.generate_test klass, node, data, input_name, output_name
return if node.to_s =~ /bmethod|dmethod/
return if Array === data['Ruby']
assert_equal Sexp.from_array(pt), @processor.parse(rb)
end"
}.compact.join("\n")
output_name = "ParseTree"
# Scour the world and compare against ParseTree
if ENV['ZOMGPONIES'] or File.exist? 'zomgponies' then
require 'parse_tree'
super
end
end
base = "/usr/lib/ruby"
base = "unit"
class TestRubyParser < RubyParserTestCase
alias :refute_nil :assert_not_nil unless defined? Mini
files = Dir[File.join(base, "**/*.rb")]
# these files/patterns cause parse_tree_show to bus error (or just suck):
files.reject! { |f| f =~ /environments.environment|rss.maker.base|rails_generator|ferret.browser|rubinius.spec.core.module.(constants|name|remove_const)_spec|tkextlib.tcllib.tablelist/ }
# these are rejected for dasgn_curr ordering failures... I'll fix them later.
# (or mri parse errors--I should have separated them out)
files.reject! { |f| f =~ /lib.flog|lib.autotest.notify|lib.analyzer.tools.rails.stat|flog.lib.flog|rakelib.struct.generator|rubinius.kernel.core.array|lib.rbosa.rb|src.rbosa.rb|spec.spec.mocks.mock.spec.rb|dsl.shared.behaviour.spec.rb|spec.spec.dsl.behaviour.spec|lib.hpricot.parse.rb|resolve.rb|parsers.parse.f95|rubinius.shotgun.lib.primitives.ltm|rubinius.lib.bin.compile|rubinius.kernel.core.object|rubinius.kernel.core.file|rubinius.compiler2.garnet.bindingagent|ruby_to_c_test_r2ctestcase|lib.more.like.this|resolv\.rb|test.r2ctestcase/ }
warn "Generating #{files.size} tests from #{base}"
eval files.map { |file|
name = file[base.size..-1].gsub(/\W+/, '_')
loc = `wc -l #{file}`.strip.to_i
"def test#{name}_#{loc}
file = #{file.inspect}
rb = File.read(file)
pt = ParseTree.new.parse_tree_for_string rb
assert_not_nil pt, \"ParseTree for #{name} undefined\"
rp = @processor.parse rb
assert_equal Sexp.from_array(pt).first, rp, \"RP different from PT\"
File.unlink #{file.inspect}
end"
}.compact.join("\n")
end
def setup

@@ -74,2 +44,18 @@ super

def test_attrasgn_array_lhs
rb = '[1, 2, 3, 4][from .. to] = ["a", "b", "c"]'
pt = s(:attrasgn,
s(:array, s(:lit, 1), s(:lit, 2), s(:lit, 3), s(:lit, 4)),
:[]=,
s(:arglist,
s(:dot2,
s(:call, nil, :from, s(:arglist)),
s(:call, nil, :to, s(:arglist))),
s(:array, s(:str, "a"), s(:str, "b"), s(:str, "c"))))
result = @processor.parse(rb)
assert_equal pt, result
end
def test_block_append

@@ -82,2 +68,9 @@ head = s(:args)

def test_block_append_begin_begin
head = s(:begin, s(:args))
tail = s(:begin, s(:args))
expected = s(:block, s(:args), s(:begin, s(:args)))
assert_equal expected, @processor.block_append(head, tail)
end
def test_block_append_block

@@ -90,18 +83,2 @@ head = s(:block, s(:args))

def test_block_append_tail_block
head = s(:vcall, :f1)
tail = s(:block, s(:undef, s(:lit, :x)), s(:undef, s(:lit, :y)))
expected = s(:block,
s(:vcall, :f1),
s(:block, s(:undef, s(:lit, :x)), s(:undef, s(:lit, :y))))
assert_equal expected, @processor.block_append(head, tail)
end
def test_block_append_begin_begin
head = s(:begin, s(:args))
tail = s(:begin, s(:args))
expected = s(:block, s(:args), s(:begin, s(:args)))
assert_equal expected, @processor.block_append(head, tail)
end
def test_block_append_nil_head

@@ -121,5 +98,14 @@ head = nil

def test_block_append_tail_block
head = s(:call, nil, :f1, s(:arglist))
tail = s(:block, s(:undef, s(:lit, :x)), s(:undef, s(:lit, :y)))
expected = s(:block,
s(:call, nil, :f1, s(:arglist)),
s(:block, s(:undef, s(:lit, :x)), s(:undef, s(:lit, :y))))
assert_equal expected, @processor.block_append(head, tail)
end
def test_call_env
@processor.env[:a] = :lvar
expected = s(:call, s(:lvar, :a), :happy)
expected = s(:call, s(:lvar, :a), :happy, s(:arglist))

@@ -129,7 +115,68 @@ assert_equal expected, @processor.parse('a.happy')

def test_dasgn_icky2
rb = "a do\n v = nil\n begin\n yield\n rescue Exception => v\n break\n end\nend"
pt = s(:iter,
s(:call, nil, :a, s(:arglist)),
nil,
s(:block,
s(:lasgn, :v, s(:nil)),
s(:rescue,
s(:yield),
s(:resbody,
s(:array, s(:const, :Exception), s(:lasgn, :v, s(:gvar, :$!))),
s(:break)))))
assert_equal pt, @processor.parse(rb)
end
def test_class_comments
rb = "# blah 1\n# blah 2\n\nclass X\n # blah 3\n def blah\n # blah 4\n end\nend"
pt = s(:class, :X, nil,
s(:scope,
s(:defn, :blah, s(:args), s(:scope, s(:block, s(:nil))))))
actual = @processor.parse(rb)
assert_equal pt, actual
assert_equal "# blah 1\n# blah 2\n\n", actual.comments
assert_equal "# blah 3\n", actual.scope.defn.comments
end
def test_module_comments
rb = "# blah 1\n \n # blah 2\n\nmodule X\n # blah 3\n def blah\n # blah 4\n end\nend"
pt = s(:module, :X,
s(:scope,
s(:defn, :blah, s(:args), s(:scope, s(:block, s(:nil))))))
actual = @processor.parse(rb)
assert_equal pt, actual
assert_equal "# blah 1\n\n# blah 2\n\n", actual.comments
assert_equal "# blah 3\n", actual.scope.defn.comments
end
def test_defn_comments
rb = "# blah 1\n# blah 2\n\ndef blah\nend"
pt = s(:defn, :blah, s(:args), s(:scope, s(:block, s(:nil))))
actual = @processor.parse(rb)
assert_equal pt, actual
assert_equal "# blah 1\n# blah 2\n\n", actual.comments
end
def test_defs_comments
rb = "# blah 1\n# blah 2\n\ndef self.blah\nend"
pt = s(:defs, s(:self), :blah, s(:args), s(:scope, s(:block)))
actual = @processor.parse(rb)
assert_equal pt, actual
assert_equal "# blah 1\n# blah 2\n\n", actual.comments
end
def test_do_bug # TODO: rename
rb = "a 1\na.b do |c|\n # do nothing\nend"
pt = s(:block,
s(:fcall, :a, s(:array, s(:lit, 1))),
s(:iter, s(:call, s(:vcall, :a), :b), s(:dasgn_curr, :c)))
s(:call, nil, :a, s(:arglist, s(:lit, 1))),
s(:iter,
s(:call, s(:call, nil, :a, s(:arglist)), :b, s(:arglist)),
s(:lasgn, :c)))

@@ -139,2 +186,37 @@ assert_equal pt, @processor.parse(rb)

def test_dstr_evstr
rb = "\"#\{'a'}#\{b}\""
pt = s(:dstr, "a", s(:evstr, s(:call, nil, :b, s(:arglist))))
assert_equal pt, @processor.parse(rb)
end
def test_dstr_str
rb = "\"#\{'a'} b\""
pt = s(:str, "a b")
assert_equal pt, @processor.parse(rb)
end
def test_empty
rb = ""
pt = nil
assert_equal pt, @processor.parse(rb)
end
def test_evstr_evstr
rb = "\"#\{a}#\{b}\""
pt = s(:dstr, "", s(:evstr, s(:call, nil, :a, s(:arglist))), s(:evstr, s(:call, nil, :b, s(:arglist))))
assert_equal pt, @processor.parse(rb)
end
def test_evstr_str
rb = "\"#\{a} b\""
pt = s(:dstr, "", s(:evstr, s(:call, nil, :a, s(:arglist))), s(:str, " b"))
assert_equal pt, @processor.parse(rb)
end
def test_lasgn_env

@@ -144,3 +226,3 @@ rb = 'a = 42'

expected_env = { :a => :lvar }
assert_equal pt, @processor.parse(rb)

@@ -150,2 +232,82 @@ assert_equal expected_env, @processor.env.all

def test_list_append
a = s(:lit, 1)
b = s(:lit, 2)
c = s(:lit, 3)
result = @processor.list_append(s(:array, b.dup), c.dup)
assert_equal s(:array, b, c), result
result = @processor.list_append(b.dup, c.dup)
assert_equal s(:array, b, c), result
result = @processor.list_append(result, a.dup)
assert_equal s(:array, b, c, a), result
lhs, rhs = s(:array, s(:lit, :iter)), s(:when, s(:const, :BRANCHING), nil)
expected = s(:array, s(:lit, :iter), s(:when, s(:const, :BRANCHING), nil))
assert_equal expected, @processor.list_append(lhs, rhs)
end
def test_list_prepend
a = s(:lit, 1)
b = s(:lit, 2)
c = s(:lit, 3)
result = @processor.list_prepend(b.dup, s(:array, c.dup))
assert_equal s(:array, b, c), result
result = @processor.list_prepend(b.dup, c.dup)
assert_equal s(:array, b, c), result
result = @processor.list_prepend(a.dup, result)
assert_equal s(:array, a, b, c), result
end
def test_literal_concat_dstr_dstr
lhs = s(:dstr, "Failed to download spec ",
s(:evstr, s(:call, nil, :spec_name, s(:arglist))),
s(:str, " from "),
s(:evstr, s(:call, nil, :source_uri, s(:arglist))),
s(:str, ":\n"))
rhs = s(:dstr, "\t",
s(:evstr, s(:call, s(:ivar, :@fetch_error), :message)))
expected = s(:dstr, "Failed to download spec ",
s(:evstr, s(:call, nil, :spec_name, s(:arglist))),
s(:str, " from "),
s(:evstr, s(:call, nil, :source_uri, s(:arglist))),
s(:str, ":\n"),
s(:str, "\t"),
s(:evstr, s(:call, s(:ivar, :@fetch_error), :message)))
assert_equal expected, @processor.literal_concat(lhs, rhs)
end
def test_literal_concat_dstr_evstr
lhs, rhs = s(:dstr, "a"), s(:evstr, s(:call, nil, :b, s(:arglist)))
expected = s(:dstr, "a", s(:evstr, s(:call, nil, :b, s(:arglist))))
assert_equal expected, @processor.literal_concat(lhs, rhs)
end
def test_literal_concat_evstr_evstr
lhs, rhs = s(:evstr, s(:lit, 1)), s(:evstr, s(:lit, 2))
expected = s(:dstr, "", s(:evstr, s(:lit, 1)), s(:evstr, s(:lit, 2)))
assert_equal expected, @processor.literal_concat(lhs, rhs)
end
def test_literal_concat_str_evstr
lhs, rhs = s(:str, ""), s(:evstr, s(:str, "blah"))
assert_equal s(:str, "blah"), @processor.literal_concat(lhs, rhs)
end
def test_logop_12

@@ -159,6 +321,14 @@ lhs = s(:lit, 1)

def test_logop_12_3
lhs = s(:and, s(:lit, 1), s(:lit, 2))
rhs = s(:lit, 3)
exp = s(:and, s(:lit, 1), s(:and, s(:lit, 2), s(:lit, 3)))
def test_logop_1234_5
lhs = s(:and, s(:lit, 1), s(:and, s(:lit, 2), s(:and, s(:lit, 3), s(:lit, 4))))
rhs = s(:lit, 5)
exp = s(:and,
s(:lit, 1),
s(:and,
s(:lit, 2),
s(:and,
s(:lit, 3),
s(:and,
s(:lit, 4),
s(:lit, 5)))))

@@ -182,14 +352,6 @@ assert_equal exp, @processor.logop(:and, lhs, rhs)

def test_logop_1234_5
lhs = s(:and, s(:lit, 1), s(:and, s(:lit, 2), s(:and, s(:lit, 3), s(:lit, 4))))
rhs = s(:lit, 5)
exp = s(:and,
s(:lit, 1),
s(:and,
s(:lit, 2),
s(:and,
s(:lit, 3),
s(:and,
s(:lit, 4),
s(:lit, 5)))))
def test_logop_12_3
lhs = s(:and, s(:lit, 1), s(:lit, 2))
rhs = s(:lit, 3)
exp = s(:and, s(:lit, 1), s(:and, s(:lit, 2), s(:lit, 3)))

@@ -200,7 +362,7 @@ assert_equal exp, @processor.logop(:and, lhs, rhs)

def test_logop_nested_mix
lhs = s(:or, s(:vcall, :a), s(:vcall, :b))
rhs = s(:and, s(:vcall, :c), s(:vcall, :d))
lhs = s(:or, s(:call, nil, :a, s(:arglist)), s(:call, nil, :b, s(:arglist)))
rhs = s(:and, s(:call, nil, :c, s(:arglist)), s(:call, nil, :d, s(:arglist)))
exp = s(:or,
s(:or, s(:vcall, :a), s(:vcall, :b)),
s(:and, s(:vcall, :c), s(:vcall, :d)))
s(:or, s(:call, nil, :a, s(:arglist)), s(:call, nil, :b, s(:arglist))),
s(:and, s(:call, nil, :c, s(:arglist)), s(:call, nil, :d, s(:arglist))))

@@ -213,44 +375,12 @@ lhs.paren = true

def test_literal_concat_str_evstr
lhs, rhs = s(:str, ""), s(:evstr, s(:str, "blah"))
def test_str_evstr
rb = "\"a #\{b}\""
pt = s(:dstr, "a ", s(:evstr, s(:call, nil, :b, s(:arglist))))
assert_equal s(:str, "blah"), @processor.literal_concat(lhs, rhs)
assert_equal pt, @processor.parse(rb)
end
def test_literal_concat_evstr_evstr
lhs, rhs = s(:evstr, s(:lit, 1)), s(:evstr, s(:lit, 2))
expected = s(:dstr, "", s(:evstr, s(:lit, 1)), s(:evstr, s(:lit, 2)))
assert_equal expected, @processor.literal_concat(lhs, rhs)
end
def test_literal_concat_dstr_evstr
lhs, rhs = s(:dstr, "a"), s(:evstr, s(:vcall, :b))
expected = s(:dstr, "a", s(:evstr, s(:vcall, :b)))
assert_equal expected, @processor.literal_concat(lhs, rhs)
end
def test_literal_concat_dstr_dstr
lhs = s(:dstr, "Failed to download spec ",
s(:evstr, s(:vcall, :spec_name)),
s(:str, " from "),
s(:evstr, s(:vcall, :source_uri)),
s(:str, ":\n"))
rhs = s(:dstr, "\t",
s(:evstr, s(:call, s(:ivar, :@fetch_error), :message)))
expected = s(:dstr, "Failed to download spec ",
s(:evstr, s(:vcall, :spec_name)),
s(:str, " from "),
s(:evstr, s(:vcall, :source_uri)),
s(:str, ":\n"),
s(:str, "\t"),
s(:evstr, s(:call, s(:ivar, :@fetch_error), :message)))
assert_equal expected, @processor.literal_concat(lhs, rhs)
end
def test_str_pct_Q_nested
rb = "%Q[before [#\{nest}] after]"
pt = s(:dstr, "before [", s(:evstr, s(:vcall, :nest)), s(:str, "] after"))
pt = s(:dstr, "before [", s(:evstr, s(:call, nil, :nest, s(:arglist))), s(:str, "] after"))

@@ -274,67 +404,79 @@ assert_equal pt, @processor.parse(rb)

def test_dstr_str
rb = "\"#\{'a'} b\""
pt = s(:str, "a b")
STARTING_LINE = {
"begin_def" => 2,
"block_stmt_after" => 2,
"block_stmt_after_mri_verbose_flag" => 2,
"block_stmt_before" => 2,
"block_stmt_before_mri_verbose_flag" => 2,
"block_stmt_both" => 2,
"block_stmt_both_mri_verbose_flag" => 2,
"case_nested_inner_no_expr" => 2,
"case_no_expr" => 2,
"case_splat" => 2,
"cvasgn" => 2,
"defn_args_none" => 2,
"defn_zarray" => 2,
"structure_unused_literal_wwtt" => 3, # yes, 3... odd test
"super_0" => 2,
"super_1" => 2,
"super_1_array" => 2,
"super_n" => 2,
"super_multi" => 2,
"undef_block_1" => 2,
"undef_block_2" => 2,
"undef_block_3" => 2,
"undef_block_wtf" => 2,
"zsuper" => 2,
}
assert_equal pt, @processor.parse(rb)
def after_process_hook klass, node, data, input_name, output_name
expected = STARTING_LINE[node] || 1
assert_equal expected, @result.line, "should have proper line number"
end
def test_str_evstr
rb = "\"a #\{b}\""
pt = s(:dstr, "a ", s(:evstr, s(:vcall, :b)))
def test_position_info
rb = "a = 42\np a"
pt = s(:block,
s(:lasgn, :a, s(:lit, 42)),
s(:call, nil, :p, s(:arglist, s(:lvar, :a))))
assert_equal pt, @processor.parse(rb)
end
result = @processor.parse(rb, "blah.rb")
def test_dstr_evstr
rb = "\"#\{'a'}#\{b}\""
pt = s(:dstr, "a", s(:evstr, s(:vcall, :b)))
assert_equal pt, result
assert_equal pt, @processor.parse(rb)
end
assert_equal 1, result.line, "block should have line number"
assert_equal 1, result.lasgn.line, "lasgn should have line number"
assert_equal 2, result.call.line, "call should have line number"
def test_evstr_str
rb = "\"#\{a} b\""
pt = s(:dstr, "", s(:evstr, s(:vcall, :a)), s(:str, " b"))
expected = "blah.rb"
assert_equal pt, @processor.parse(rb)
end
assert_equal expected, result.file
assert_equal expected, result.lasgn.file
assert_equal expected, result.call.file
def test_evstr_evstr
rb = "\"#\{a}#\{b}\""
pt = s(:dstr, "", s(:evstr, s(:vcall, :a)), s(:evstr, s(:vcall, :b)))
assert_equal pt, @processor.parse(rb)
assert_same result.file, result.lasgn.file
assert_same result.file, result.call.file
end
def test_position_info2
rb = "def x(y)\n p(y)\n y *= 2\n return y;\nend" # TODO: remove () & ;
pt = s(:defn, :x, s(:args, :y),
s(:scope,
s(:block,
s(:call, nil, :p, s(:arglist, s(:lvar, :y))),
s(:lasgn, :y,
s(:call, s(:lvar, :y), :*, s(:arglist, s(:lit, 2)))),
s(:return, s(:lvar, :y)))))
def test_dasgn_icky2
rb = "a do\n v = nil\n begin\n yield\n rescue Exception => v\n break\n end\nend"
pt = s(:iter,
s(:fcall, :a),
nil,
s(:block,
s(:dasgn_curr, :v, s(:nil)),
s(:begin,
s(:rescue,
s(:yield),
s(:resbody,
s(:array, s(:const, :Exception)),
s(:block, s(:dasgn_curr, :v, s(:gvar, :$!)), s(:break)))))))
result = @processor.parse(rb)
assert_equal pt, @processor.parse(rb)
end
assert_equal pt, result
def test_list_append
lhs, rhs = s(:array, s(:lit, :iter)), s(:when, s(:const, :BRANCHING), nil)
expected = s(:array, s(:lit, :iter), s(:when, s(:const, :BRANCHING), nil))
body = result.scope.block
assert_equal expected, @processor.list_append(lhs, rhs)
assert_equal 1, result.line, "defn should have line number"
assert_equal 2, body.call.line, "call should have line number"
assert_equal 3, body.lasgn.line, "lasgn should have line number"
assert_equal 4, body.return.line, "return should have line number"
end
end
__END__
# blah18.rb
assert_equal("sub", $_)

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet