Skip to content

Instantly share code, notes, and snippets.

@ebisawa
Created September 12, 2011 08:34
Show Gist options
  • Save ebisawa/1210836 to your computer and use it in GitHub Desktop.
Save ebisawa/1210836 to your computer and use it in GitHub Desktop.
PhpRewriter
class PhpTokenizer
attr_accessor :putline
def initialize(io)
@io = io
reinit
end
def reinit
@io.rewind
@line = nil
@tokens = []
@putline = false
@replaces = []
end
def nextline
line = @io.readline
line.toutf8
end
def set_replace(ostr, nstr)
@replaces << [ ostr, nstr ]
end
def do_replace
@replaces.each do |ary|
ostr, nstr = ary
if @line.sub!(ostr.to_s, nstr.to_s) != nil
@replaces.delete(ary)
end
end
end
def get_token
loop do
t = get_token2
return nil if t == nil
case t
when '/*'
# comment
t = get_token2 while t != '*/'
next
when /^\/\//
@tokens = []
next
end
return t if t != ''
end
end
def get_token2
loop do
while @tokens.size == 0
if @line != nil && @putline == true
do_replace
puts @line
end
@line = nextline
raise "EOF" if @line == nil
@tokens = @line.split(/('[^']*')|("[^"]*")|(\/\*)|(\*\/)|\s+|(=>)|([,\.\(\)])/)
end
return @tokens.shift
end
end
def unget_token(t)
@tokens.unshift(t)
end
end
class PhpRewriter
def initialize(io)
@pam = PhpTokenizer.new(io)
end
def hn(hash, key)
(hash == nil) ? nil : hash[key]
end
def set_replace(pam, ov, nv)
case ov
when Array
if ov.size == nv.size
ov.each_with_index do |o, i|
if o != nv[i]
pam.set_replace(o, nv[i])
end
end
end
when Hash
raise '?'
else
pam.set_replace(ov, nv)
end
end
def parse_value(pam, ov, nv)
key = pam.get_token
key = parse_array(pam, ov, nv) if key == 'array'
loop do
n = pam.get_token
case n
when ','
# simple value
return key
when '.', '+', '-', '*', '/', '%'
# concat
m = parse_value(pam, ov, nv)
return "#{key} #{n} #{m}"
when '=>'
# hash
if nv != nil && nv[key] != nil && nv[key].class != Hash
set_replace(pam, ov[key], nv[key])
end
v = parse_value(pam, hn(ov, key), hn(nv, key))
m = pam.get_token
pam.unget_token(m) if m != ','
return { key => v }
when '('
# call function
m = parse_value(pam, ov, nv)
l = pam.get_token
raise "unexpected token: #{l}" if l != ')'
pam.unget_token("#{key}(#{m})")
return parse_value(pam, ov, nv)
when ')'
pam.unget_token(n)
return key
else
pam.unget_token(n)
return key
end
end
end
def parse_array(pam, ov, nv)
t = pam.get_token
raise "unexpected token: #{t}" if t != '('
a = []; h = {}
loop do
t = pam.get_token
break if t == ')'
pam.unget_token(t)
v = parse_value(pam, ov, nv)
if v.class == Hash
h.merge!(v)
else
a << v
end
end
if a.size > 0 && h.size > 0
pp h; pp a
raise "bug?"
end
return (a.size > 0) ? a : h
end
def pmain(pam, ov, nv)
loop do
t = pam.get_token
case t
when '<?php', '?>', '=', '=>', ',', ';'
# nop
when 'array'
return parse_array(pam, ov, nv)
end
end
end
def parse
@pam.reinit
pmain(@pam, nil, nil)
end
def rewrite(ov, nv)
@pam.reinit
@pam.putline = true
pmain(@pam, ov, nv)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment