module NestedContexts class NestedContext attr :starter attr :ender attr :linenum def initialize(starter,ender,linenum) @starter,@ender,@linenum=starter,ender,linenum end alias dflt_initialize initialize def matches?(tok) @ender==tok end def see stack,msg; end end class ListContext < NestedContext end class ListImmedContext < ListContext def initialize(starter,linenum) assert '{['[starter] super(starter, starter.tr('{[','}]') ,linenum) end end class ParenContext < NestedContext def initialize(linenum) super('(', ')' ,linenum) end end class BlockContext < NestedContext def initialize(linenum) super('{','}',linenum) end end class BlockParamListContext < ListContext def initialize(linenum) super('|','|',linenum) end end class ParamListContext < ListContext def initialize(linenum) super('(', ')',linenum) end end class ImplicitContext < ListContext end class ParamListContextNoParen < ImplicitContext def initialize(linenum) dflt_initialize(nil,nil,linenum) end end class KwParamListContext < ImplicitContext def initialize(starter,linenum) dflt_initialize(starter,nil,linenum) end end class AssignmentRhsContext < ImplicitContext def initialize(linenum) dflt_initialize(nil,nil,linenum) end end class WantsEndContext < NestedContext def initialize(starter,linenum) super(starter,'end',linenum) end def see stack,msg msg==:rescue ? stack.push_rescue_sm : super end end class StringContext < NestedContext #not used yet def initialize(starter,linenum) super(starter, starter[-1,1].tr!('{[(','}])'),linenum) end end class HereStringContext < StringContext #not used yet def initialize(ender,linenum) dflt_initialize("\n",ender,linenum) end end class TopLevelContext < NestedContext def initialize dflt_initialize('','',1) end end class RescueSMContext < NestedContext #normal progression: rescue => arrow => then EVENTS=[:rescue,:arrow,:then,:semi,:colon] LEGAL_SUCCESSORS={nil=> [:rescue], :rescue => [:arrow,:then,:semi,:colon],:arrow => [:then,:semi,:colon],:then => [nil]} #note on :semi and :colon events: in arrow state (and only then), # (unescaped) newline, semicolon, and (unaccompanied) colon # also trigger the :then event. otherwise, they are ignored. attr :state def initialize linenum dflt_initialize("rescue","then",linenum) @state=nil @state=:rescue end def see(stack,msg) case msg when :rescue: WantsEndContext===stack.last or BlockContext===stack.last or ParenContext===stack.last or raise 'syntax error: rescue not expected at this time' when :arrow: #local var defined in this state when :then,:semi,:colon: msg=:then RescueSMContext===stack.pop or raise 'syntax error: then not expected at this time' #pop self off owning context stack else super end LEGAL_SUCCESSORS[@state].include? msg or raise "rescue syntax error: #{msg} unexpected in #@state" @state=msg end end class ForSMContext < NestedContext #normal progression: for => in EVENTS=[:for,:in] LEGAL_SUCCESSORS={nil=> :for, :for => :in,:in => nil} #note on :semi and :colon events: in :in state (and only then), # (unescaped) newline, semicolon, and (unaccompanied) colon # also trigger the :then event. otherwise, they are ignored. attr :state def initialize linenum dflt_initialize("for","in",linenum) @state=:for end def see(stack,msg) case msg when :for: WantsEndContext===stack.last or raise 'syntax error: for not expected at this time' #local var defined in this state when :in: ForSMContext===stack.pop or raise 'syntax error: in not expected at this time' stack.push ExpectDoOrNlContext.new("for",/(do|;|:|\n)/,@linenum) #pop self off owning context stack and push ExpectDoOrNlContext else super end LEGAL_SUCCESSORS[@state] == msg or raise 'for syntax error: #{msg} unexpected in #@state' @state=msg end end class ExpectDoOrNlContext < NestedContext end class TernaryContext < NestedContext def initialize(linenum) dflt_initialize('?',':',linenum) end end end