class RedParse::ListInNode::StringNode
Constants
- CHAROPT2NUM
- CHARSETFLAG2NUM
- DOWNSHIFT_STRING_TYPE
- DQ_ESC
- DQ_EVEN
- DQ_ODD
- ESCAPABLES
- EVEN_BSS
- EVEN_NUM_BSLASHES
- LETTER2ENCODING
- SQ_ESC
- SQ_EVEN
- SQ_ODD
Attributes
char[R]
modifiers[R]
type[R]
Public Class Methods
new(token)
click to toggle source
Calls superclass method
RedParse::ListInNode::Node::new
# File lib/redparse/node.rb, line 3531 def initialize(token) if HerePlaceholderToken===token str=token.string @char=token.quote else str=token @char=str.char end @modifiers=str.modifiers #if str.modifiers super( *with_string_data(str) ) @open=token.open @close=token.close @offset=token.offset @bs_handler=str.bs_handler if /[\[{]/===@char @parses_like=split_into_words(str) end return =begin #this should have been taken care of by with_string_data first=shift delete_if{|x| ''==x } unshift(first) #escape translation now done later on map!{|strfrag| if String===strfrag str.translate_escapes strfrag else strfrag end } =end end
Public Instance Methods
Regexp_new(src,opts,lang)
click to toggle source
# File lib/redparse/node.rb, line 4015 def Regexp_new(src,opts,lang) src.encode!(LETTER2ENCODING[lang]) Regexp.new(src,opts) end
depthwalk(*args,&callback)
click to toggle source
Calls superclass method
RedParse::ListInNode::Node#depthwalk
# File lib/redparse/node.rb, line 3673 def depthwalk(*args,&callback) return @parses_like.depthwalk(*args,&callback) if defined? @parses_like super end
endline=(endline)
click to toggle source
Calls superclass method
# File lib/redparse/node.rb, line 3740 def endline= endline each{|frag| frag.endline||=endline if frag.respond_to? :endline } super end
escapable(open=@open,close=@close)
click to toggle source
# File lib/redparse/node.rb, line 3632 def escapable open=@open,close=@close unless escapable=ESCAPABLES[open] maybe_crunch='\\#' if %r{\A["`/\{]\Z} === @char and open[1] != ?q and open != "'" #" #crunch (#) might need to be escaped too, depending on what @char is quotes=open[-1,1] quotes+=close unless quotes==close escapable=ESCAPABLES[open]= /[#{Regexp.quote(quotes)}#{maybe_crunch}]/ end escapable end
image()
click to toggle source
# File lib/redparse/node.rb, line 3666 def image; '(#@char)' end
initialize_ivars()
click to toggle source
# File lib/redparse/node.rb, line 3570 def initialize_ivars @char||='"' @open||='"' @close||='"' @bs_handler||=:dquote_esc_seq @modifiers||=nil if /[\[{]/===@char @parses_like||=split_into_words(str) end end
old_cat_initialize(*tokens)
click to toggle source
# File lib/redparse/node.rb, line 3598 def old_cat_initialize(*tokens) #not needed anymore? token=tokens.shift tokens.size==1 or fail "string node must be made from a single string token" newdata=with_string_data(*tokens) case token when HereDocNode token.list_to_append=newdata when StringNode #do nothing else fail "non-string token class used to construct string node" end replace token.data # size%2==1 and last<<newdata.shift if size==1 and String===first and String===newdata.first first << newdata.shift end concat newdata @implicit_match=false end
parsetree(o)
click to toggle source
# File lib/redparse/node.rb, line 3859 def parsetree(o) if size==1 val=translate_escapes first type=case @char when '"',"'"; :str when '/' numopts=0 charset=0 RubyLexer::CharHandler.each_char(@modifiers){|ch| if ch==?o type=:dregx_once elsif numopt=CHAROPT2NUM[ch].nonzero? numopts|=numopt elsif set=CHARSETFLAG2NUM[ch].nonzero? charset=set else fail end } val=Regexp.new val,numopts|charset :lit when '[','{' return @parses_like.parsetree(o) =begin double_chunks=val.split(/([^\\]|\A)(?:\s|\v)/,-1) chunks=[] (0..double_chunks.size).step(2){|i| chunks << double_chunks[i,2].to_s.gsub(/\\(\s|\v)/){$1} } # last=chunks # last.last.empty? and last.pop if last and !last.empty? words=chunks#.flatten words.shift if words.first.empty? unless words.empty? words.pop if words.last.empty? unless words.empty? return [:zarray] if words.empty? return words.map{|word| [:str,word]}.unshift(:array) =end when '`'; :xstr else raise "dunno what to do with #@char<StringToken" end result=[type,val] else saw_string=false vals=[] each{|elem| case elem when String was_esc_nl= (elem=="\\\n") #ick elem=translate_escapes elem if saw_string vals.push [:str, elem] if !elem.empty? or was_esc_nl else saw_string=true vals.push elem end when NopNode vals.push [:evstr] when Node #,VarNameToken res=elem.parsetree(o) if res.first==:str and @char != '{' vals.push res elsif res.first==:dstr and @char != '{' vals.push [:str, res[1]], *res[2..-1] else vals.push [:evstr, res] end else fail "#{elem.class} not expected here" end } while vals.size>1 and vals[1].first==:str vals[0]+=vals.delete_at(1).last end #vals.pop if vals.last==[:str, ""] type=case @char when '"'; :dstr when '/' type=:dregx numopts=charset=0 RubyLexer::CharHandler.each_char(@modifiers){|ch| if ch==?o type=:dregx_once elsif numopt=CHAROPT2NUM[ch].nonzero? numopts|=numopt elsif set=CHARSETFLAG2NUM[ch].nonzero? charset=set end } regex_options= numopts|charset unless numopts|charset==0 val=/#{val}/ type when '{' return @parses_like.parsetree(o) =begin vals[0]=vals[0].sub(/\A(\s|\v)+/,'') if /\A(\s|\v)/===vals.first merged=Array.new(vals) result=[] merged.each{|i| if String===i next if /\A(?:\s|\v)+\Z/===i double_chunks=i.split(/([^\\]|\A)(?:\s|\v)/,-1) chunks=[] (0..double_chunks.size).step(2){|ii| chunks << double_chunks[ii,2].to_s.gsub(/\\(\s|\v)/){$1} } words=chunks.map{|word| [:str,word]} if !result.empty? and frag=words.shift and !frag.last.empty? result[-1]+=frag end result.push( *words ) else result.push [:str,""] if result.empty? if i.first==:evstr and i.size>1 and i.last.first==:str if String===result.last[-1] result.last[-1]+=i.last.last else result.last[0]=:dstr result.last.push(i.last) end else result.last[0]=:dstr result.last.push(i) end end } return result.unshift(:array) =end when '`'; :dxstr else raise "dunno what to do with #@char<StringToken" end if vals.size==1 if :dregx==type or :dregx_once==type lang=@modifiers.tr_s("^nesuNESU","") lang=lang[-1,1] unless lang.empty? lang.downcase! regex_options=nil vals=[Regexp_new( vals.first,numopts,lang )] end type=DOWNSHIFT_STRING_TYPE[type] end result= vals.unshift(type) result.push regex_options if regex_options end result=[:match, result] if defined? @implicit_match and @implicit_match return result end
special_conditions!()
click to toggle source
# File lib/redparse/node.rb, line 3678 def special_conditions! @implicit_match= @char=="/" end
split_into_words(strtok)
click to toggle source
# File lib/redparse/node.rb, line 3772 def split_into_words strtok @offset=strtok.offset return unless /[{\[]/===@char result=ArrayLiteralNode[] result << StringNode['',{:@char=>'"',:@open=>@open,:@close=>@close,:@bs_handler=>@bs_handler}] proxy=dup proxy[0]=proxy[0][/\A(?:\s|\v)+(.*)\Z/m,1] if /\A(?:\s|\v)/===proxy[0] # first[/\A(?:\s|\v)+/]='' if /\A(?:\s|\v)/===first #uh-oh, changes first proxy.each{|x| if String===x # x=x[/\A(?:\s|\v)+(.*)\Z/,1] if /\A[\s\v]/===x if false #split on ws preceded by an even # of backslashes or a non-backslash, non-ws char #this ignores backslashed ws #save the thing that preceded the ws, it goes back on the token preceding split double_chunks=x.split(/( #{EVEN_BSS} | (?:[^\\\s\v]|\A|#{EVEN_BSS}\\[\s\v]) )(?:\s|\v)+/xo,-1) chunks=[] (0..double_chunks.size).step(2){|i| chunks << #strtok.translate_escapes \ double_chunks[i,2].to_s #.gsub(/\\([\s\v\\])/){$1} } else #split on ws, then ignore ws preceded by an odd number of esc's #esc is \ in squote word array, \ or \c or \C- or \M- in dquote chunks_and_ws=x.split(/([\s\v]+)/,-1) start=chunks_and_ws.size; start-=1 if start&1==1 chunks=[] i=start+2; while (i-=2)>=0 ch=chunks_and_ws[i]||"" if i<chunks_and_ws.size and ch.match(@char=="[" ? /#{SQ_ODD}\Z/omx : /#{DQ_ODD}\Z/omx) ch<< chunks_and_ws[i+1][0,1] if chunks_and_ws[i+1].size==1 ch<< chunks.shift end end chunks.unshift ch end end chunk1= chunks.shift if chunk1.empty? #do nothing more elsif String===result.last.last result.last.last << chunk1 else result.last.push chunk1 end # result.last.last.empty? and result.last.pop result.concat chunks.map{|chunk| StringNode[chunk,{:@char=>'"',:@open=>@open,:@close=>@close,:@bs_handler=>@bs_handler}] } else #result.last << x unless String===result.last.last result.push StringNode["",{:@char=>'"',:@open=>@open,:@close=>@close,:@bs_handler=>@bs_handler}] end result.last.push x # result.push StringNode["",x,{:@char=>'"',:@open=>@open,:@close=>@close,:@bs_handler=>@bs_handler}] end } result.shift if StringNode&-{:size=>1, :first=>''}===result.first result.pop if StringNode&-{:size=>1, :first=>''}===result.last return result end
to_lisp()
click to toggle source
# File lib/redparse/node.rb, line 3748 def to_lisp return %{"#{first}"} if size<=1 and @char=='"' huh end
translate_escapes(str)
click to toggle source
# File lib/redparse/node.rb, line 3581 def translate_escapes(str) rl=RubyLexer.new("(string escape translation hack...)",'') result=str.dup seq=result.to_sequence rl.instance_eval{@file=seq} i=0 #ugly ugly ugly... all so I can call @bs_handler while i<result.size and bs_at=result.index(/\\./m,i) seq.pos=$~.end(0)-1 ch=rl.send(@bs_handler,"\\",@open[-1,1],@close) result[bs_at...seq.pos]=ch i=bs_at+ch.size end return result end
unparse(o=default_unparse_options)
click to toggle source
# File lib/redparse/node.rb, line 3624 def unparse o=default_unparse_options o[:linenum]+=@open.count("\n") result=[@open,unparse_interior(o),@close,@modifiers].join o[:linenum]+=@close.count("\n") result<<" " if /\r\z/===result return result end
unparse_interior(o,open=@open,close=@close,escape=nil)
click to toggle source
# File lib/redparse/node.rb, line 3644 def unparse_interior o,open=@open,close=@close,escape=nil escapable=escapable(open,close) result=map{|substr| case substr when String #hack: this is needed for here documents only, because their #delimiter is changing. substr.gsub!(escape){|ch| ch[0...-1]+"\\"+ch[-1,1]} if escape o[:linenum]+=substr.count("\n") if o[:linenum] substr when NopNode '#{}' else ['#{',substr.unparse(o),'}'] end } result end
walk(*args,&callback)
click to toggle source
Calls superclass method
RedParse::ListInNode::Node#walk
# File lib/redparse/node.rb, line 3668 def walk(*args,&callback) @parses_like.walk(*args,&callback) if defined? @parses_like super end
with_string_data(token)
click to toggle source
# File lib/redparse/node.rb, line 3685 def with_string_data(token) # token=tokens.first # data=tokens.inject([]){|sum,token| # data=elems=token.string.elems data= #elems= case token when StringToken; token.elems when HerePlaceholderToken; token.string.elems else raise "unknown string token type: #{token}:#{token.class}" end # sum.size%2==1 and sum.last<<elems.shift # sum+elems # } # endline=@endline 1.step(data.length-1,2){|i| tokens=data[i].ident.dup #replace trailing } with EoiToken (tokens.size-1).downto(0){|j| tok=tokens[j] break(tokens[j..-1]=[EoiToken.new('',nil,tokens[j].offset)]) if tok.ident=='}' } #remove leading { tokens.each_with_index{|tok,j| break(tokens.delete_at j) if tok.ident=='{' } if tokens.size==1 and VarNameToken===tokens.first data[i]=VarNode.new tokens.first data[i].startline=data[i].endline=token.endline data[i].offset=tokens.first.offset else #parse the token list in the string inclusion parser=Thread.current[:$RedParse_parser] klass=parser.class data[i]=klass.new(tokens, "(string inclusion)",1,[],:rubyversion=>parser.rubyversion,:cache_mode=>:none).parse end } #if data # was_nul_header= (String===data.first and data.first.empty?) #and o[:quirks] last=data.size-1 #remove (most) empty string fragments last.downto(1){|frag_i| frag=data[frag_i] String===frag or next next unless frag.empty? next if frag_i==last #and o[:quirks] next if data[frag_i-1].endline != data[frag_i+1].endline #and o[:quirks] #prev and next inclusions on different lines data.slice!(frag_i) } # data.unshift '' if was_nul_header return data end