rubylexer 0.7.1 → 0.7.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (115) hide show
  1. data/COPYING +0 -0
  2. data/History.txt +16 -1
  3. data/Manifest.txt +0 -0
  4. data/README.txt +0 -0
  5. data/Rakefile +1 -1
  6. data/howtouse.txt +0 -0
  7. data/lib/assert.rb +0 -0
  8. data/lib/rubylexer.rb +156 -45
  9. data/lib/rubylexer/0.6.2.rb +0 -0
  10. data/lib/rubylexer/0.6.rb +0 -0
  11. data/lib/rubylexer/0.7.0.rb +0 -0
  12. data/lib/rubylexer/0.7.1.rb +0 -0
  13. data/lib/rubylexer/charhandler.rb +0 -0
  14. data/lib/rubylexer/charset.rb +0 -0
  15. data/lib/rubylexer/context.rb +6 -0
  16. data/lib/rubylexer/rubycode.rb +0 -0
  17. data/lib/rubylexer/rulexer.rb +3 -2
  18. data/lib/rubylexer/symboltable.rb +0 -0
  19. data/lib/rubylexer/token.rb +3 -3
  20. data/lib/rubylexer/tokenprinter.rb +0 -0
  21. data/lib/rubylexer/version.rb +1 -1
  22. data/rubylexer.vpj +39 -29
  23. data/test/code/all_the_gems.rb +0 -0
  24. data/test/code/all_the_raas.rb +0 -0
  25. data/test/code/all_the_rubies.rb +0 -0
  26. data/test/code/deletewarns.rb +0 -0
  27. data/test/code/dumptokens.rb +6 -2
  28. data/test/code/errscan +0 -0
  29. data/test/code/isolate_error.rb +0 -0
  30. data/test/code/lexloop +0 -0
  31. data/test/code/locatetest +0 -0
  32. data/test/code/locatetest.rb +0 -0
  33. data/test/code/regression.rb +0 -2
  34. data/test/code/rubylexervsruby.rb +0 -0
  35. data/test/code/strgen.rb +0 -0
  36. data/test/code/tarball.rb +0 -0
  37. data/test/code/testcases.rb +0 -0
  38. data/test/code/tokentest.rb +0 -0
  39. data/test/code/torment +0 -0
  40. data/test/data/1.rb.broken +0 -0
  41. data/test/data/23.rb +0 -0
  42. data/test/data/__end__.rb +0 -0
  43. data/test/data/__end__2.rb +0 -0
  44. data/test/data/__eof2.rb +0 -0
  45. data/test/data/__eof5.rb +0 -0
  46. data/test/data/__eof6.rb +0 -0
  47. data/test/data/and.rb +0 -0
  48. data/test/data/blockassigntest.rb +0 -0
  49. data/test/data/chunky.plain.rb +0 -0
  50. data/test/data/chunky_bacon.rb +0 -0
  51. data/test/data/chunky_bacon2.rb +0 -0
  52. data/test/data/chunky_bacon3.rb +0 -0
  53. data/test/data/chunky_bacon4.rb +0 -0
  54. data/test/data/cvtesc.rb +0 -0
  55. data/test/data/for.rb +0 -0
  56. data/test/data/format.rb +0 -0
  57. data/test/data/g.rb +0 -0
  58. data/test/data/hd0.rb +0 -0
  59. data/test/data/hdateof.rb +0 -0
  60. data/test/data/hdempty.rb +0 -0
  61. data/test/data/hdr.rb +0 -0
  62. data/test/data/hdr_dos.rb +0 -0
  63. data/test/data/hdr_dos2.rb +0 -0
  64. data/test/data/heart.rb +0 -0
  65. data/test/data/here_escnl.rb +0 -0
  66. data/test/data/here_escnl_dos.rb +0 -0
  67. data/test/data/here_squote.rb +0 -0
  68. data/test/data/heremonsters.rb +0 -0
  69. data/test/data/heremonsters.rb.broken +0 -0
  70. data/test/data/heremonsters.rb.broken.save +0 -0
  71. data/test/data/heremonsters_dos.rb +0 -0
  72. data/test/data/heremonsters_dos.rb.broken +0 -0
  73. data/test/data/if.rb +0 -0
  74. data/test/data/jarh.rb +0 -0
  75. data/test/data/lbrace.rb +0 -0
  76. data/test/data/lbrack.rb +0 -0
  77. data/test/data/make_ws_strdelim.rb +0 -0
  78. data/test/data/maven2_builer_test.rb +0 -0
  79. data/test/data/migration.rb +0 -0
  80. data/test/data/modl.rb +0 -0
  81. data/test/data/modl_dos.rb +0 -0
  82. data/test/data/modl_fails.rb +0 -0
  83. data/test/data/multilinestring.rb +0 -0
  84. data/test/data/newsyntax.rb +0 -0
  85. data/test/data/noeolatend.rb +0 -0
  86. data/test/data/oneliners.rb +1 -1
  87. data/test/data/p-op.rb +0 -0
  88. data/test/data/p.rb +0 -0
  89. data/test/data/pleac.rb.broken +0 -0
  90. data/test/data/pre.rb +0 -0
  91. data/test/data/pre.unix.rb +0 -0
  92. data/test/data/regtest.rb +0 -0
  93. data/test/data/rescue.rb +0 -0
  94. data/test/data/s.rb +0 -0
  95. data/test/data/simple.rb +0 -0
  96. data/test/data/simple_dos.rb +0 -0
  97. data/test/data/stanzas.rb +0 -0
  98. data/test/data/strdelim_crlf.rb +0 -0
  99. data/test/data/strinc.rb +0 -0
  100. data/test/data/stuff.rb +0 -0
  101. data/test/data/stuff2.rb +0 -0
  102. data/test/data/stuff3.rb +0 -0
  103. data/test/data/tkweird.rb +0 -0
  104. data/test/data/tokentest.assert.rb.can +0 -0
  105. data/test/data/unending_stuff.rb +0 -0
  106. data/test/data/untermed_here.rb.broken +0 -0
  107. data/test/data/untermed_string.rb.broken +0 -0
  108. data/test/data/untitled1.rb +0 -0
  109. data/test/data/w.rb +0 -0
  110. data/test/data/whatnot.rb +0 -0
  111. data/test/data/ws_strdelim.rb +0 -0
  112. data/test/data/wsdlDriver.rb +0 -0
  113. data/test/test.sh +0 -0
  114. data/testing.txt +0 -0
  115. metadata +64 -149
data/COPYING CHANGED
File without changes
@@ -1,4 +1,19 @@
1
- === 0.7.1/10-29-2008
1
+ === 0.7.2/10-12-2008
2
+ * 12 Minor Enhancements:
3
+ * a new context for then kw expected
4
+ * disable all backtracking when scanning string interiors
5
+ * ternary flag distinguishes ternary : from other uses
6
+ * EndDefHeaderToken renamed to EndHeaderToken
7
+ * ^ now gets its own scanning method
8
+ * correct # of parens emitted after of kw used as (or like) method
9
+ * more special casing for break return and next
10
+ * abort_noparens! now better if When context on the stack
11
+ * semicolon may now be omitted after module header
12
+ * { and } in BEGIN/END expr masquerade as do and end
13
+ * trying to make 'rake test' work right
14
+ * certain other changes of no importance whatsoever
15
+
16
+ === 0.7.1/8-29-2008
2
17
  * 6 Major Enhancements:
3
18
  * handling of empty string fragments now more closely mirrors ruby; this resolves many warnings
4
19
  * yet more hacks in aid of string inclusions
File without changes
data/README.txt CHANGED
File without changes
data/Rakefile CHANGED
@@ -15,7 +15,7 @@ require 'lib/rubylexer/version.rb'
15
15
  _.email = "rubylexer-owner @at@ inforadical .dot. net"
16
16
  _.url = ["http://rubylexer.rubyforge.org/", "http://rubyforge.org/projects/rubylexer/"]
17
17
  _.extra_deps << ['sequence', '>= 0.2.0']
18
- _.test_globs=["test/{code/*,data/*rb*,results/}"]
18
+ _.test_globs=["test/code/regression.rb"]
19
19
  _.description=desc
20
20
  _.summary=desc[/\A[^.]+\./]
21
21
  _.spec_extras={:bindir=>''}
File without changes
File without changes
@@ -83,7 +83,7 @@ class RubyLexer
83
83
  ?, => :comma,
84
84
  ?; => :semicolon,
85
85
 
86
- ?^ => :biop,
86
+ ?^ => :caret,
87
87
  ?~ => :tilde,
88
88
  ?= => :equals,
89
89
  ?! => :exclam,
@@ -130,6 +130,9 @@ class RubyLexer
130
130
  @in_def_name=false
131
131
  @last_operative_token=nil
132
132
  @last_token_maybe_implicit=nil
133
+ @enable_macro=nil
134
+ @base_file=nil
135
+ @progress_thread=nil
133
136
 
134
137
  @toptable=CharHandler.new(self, :illegal_char, CHARMAPPINGS)
135
138
 
@@ -442,12 +445,12 @@ private
442
445
  end
443
446
 
444
447
  #-----------------------------------
445
- def in_lvar_define_state
448
+ def in_lvar_define_state lasttok=@last_operative_token
446
449
  #@defining_lvar is a hack
447
450
  @defining_lvar or case ctx=@parsestack.last
448
451
  #when ForSMContext; ctx.state==:for
449
452
  when RescueSMContext
450
- @last_operative_token.ident=="=>" and @file.match? /\A[\s\v]*([:;#\n]|then[^a-zA-Z0-9_])/m
453
+ lasttok.ident=="=>" and @file.match? /\A[\s\v]*([:;#\n]|then[^a-zA-Z0-9_])/m
451
454
  #when BlockParamListLhsContext; true
452
455
  end
453
456
  end
@@ -472,7 +475,7 @@ private
472
475
 
473
476
  assert String===name
474
477
 
475
- was_in_lvar_define_state=in_lvar_define_state
478
+ was_in_lvar_define_state=in_lvar_define_state(lasttok)
476
479
  #maybe_local really means 'maybe local or constant'
477
480
  maybe_local=case name
478
481
  when /[^a-z_0-9]$/i #do nothing
@@ -500,8 +503,6 @@ private
500
503
  if /^[a-z_][a-zA-Z_0-9]*$/===name
501
504
  assert !(lasttok===/^(\.|::)$/)
502
505
  localvars[name]=true
503
- else
504
- lexerror tok,"not a valid variable name: #{name}"
505
506
  end
506
507
  return result.unshift(tok)
507
508
  elsif maybe_local
@@ -534,7 +535,6 @@ private
534
535
  if (assignment_coming && !(lasttok===/^(\.|::)$/) or was_in_lvar_define_state)
535
536
  tok=assign_lvar_type! VarNameToken.new(name,pos)
536
537
  if /[^a-z_0-9]$/i===name
537
- lexerror tok,"not a valid variable name: #{name}"
538
538
  elsif /^[a-z_]/===name and !(lasttok===/^(\.|::)$/)
539
539
  localvars[name]=true
540
540
  end
@@ -573,7 +573,7 @@ private
573
573
  !(KeywordToken===oldlast and oldlast===/\A(\.|::)\Z/)
574
574
  x
575
575
  =end
576
- when ?(;
576
+ when ?(
577
577
  maybe_local=false
578
578
  lastid=lasttok&&lasttok.ident
579
579
  case lastid
@@ -595,10 +595,12 @@ private
595
595
  # ignored_tokens(true)
596
596
  # want_parens=false if nextchar==?)
597
597
  # @file.pos=afterparen
598
-
598
+ want_parens=true if /^(return|break|next)$/===@last_operative_token.ident and not(
599
+ KeywordToken===lasttok and /^(.|::)$/===lasttok.ident
600
+ )
599
601
  want_parens ? 1 : 0
600
- when ?},?],?),?;,?^, ?|, ?>, ?,, ?., ?=; 2
601
- when ?+, ?-, ?%, ?/
602
+ when ?},?],?),?;,(?^ unless @enable_macro), ?|, ?>, ?,, ?., ?=; 2
603
+ when ?+, ?-, ?%, ?/, (?^ if @enable_macro)
602
604
  if /^(return|break|next)$/===@last_operative_token.ident and not(
603
605
  KeywordToken===lasttok and /^(.|::)$/===lasttok.ident
604
606
  )
@@ -607,7 +609,7 @@ private
607
609
  (ws_toks.empty? || readahead(2)[/^.[#{WHSPLF}]/o]) ? 2 : 3
608
610
  end
609
611
  when ?*, ?&
610
- lasttok=@last_operative_token
612
+ # lasttok=@last_operative_token
611
613
  if /^(return|break|next)$/===@last_operative_token.ident and not(
612
614
  KeywordToken===lasttok and /^(.|::)$/===lasttok.ident
613
615
  )
@@ -626,7 +628,12 @@ private
626
628
  /^\?([#{WHSPLF}]|[a-z_][a-z_0-9])/io===next3 ? 2 : 3
627
629
  # when ?:,??; (readahead(2)[/^.[#{WHSPLF}]/o]) ? 2 : 3
628
630
  when ?<; (!ws_toks.empty? && readahead(4)[/^<<-?["'`a-zA-Z_0-9]/]) ? 3 : 2
629
- when ?[; ws_toks.empty?&&!(KeywordToken===oldlast and /^(return|break|next)$/===oldlast.ident) ? 2 : 3
631
+ when ?[;
632
+ if ws_toks.empty?
633
+ (KeywordToken===oldlast and /^(return|break|next)$/===oldlast.ident) ? 3 : 2
634
+ else
635
+ 3
636
+ end
630
637
  when ?\\, ?\s, ?\t, ?\n, ?\r, ?\v, ?#; raise 'failure'
631
638
  else raise "unknown char after ident: #{nc=nextchar ? nc.chr : "<<EOF>>"}"
632
639
  end
@@ -704,8 +711,8 @@ private
704
711
  CONTEXT2ENDTOK={
705
712
  AssignmentRhsContext=>AssignmentRhsListEndToken,
706
713
  ParamListContextNoParen=>ImplicitParamListEndToken,
707
- KWParamListContextNoParen=>ImplicitParamListEndToken,
708
- WhenParamListContext=>KwParamListEndToken,
714
+ KWParamListContextNoParen=>ImplicitParamListEndToken, #break,next,return
715
+ WhenParamListContext=>KwParamListEndToken,
709
716
  RescueSMContext=>KwParamListEndToken
710
717
  }
711
718
  def abort_noparens!(str='')
@@ -713,7 +720,8 @@ private
713
720
  result=[]
714
721
  while klass=CONTEXT2ENDTOK[@parsestack.last.class]
715
722
  result << klass.new(input_position-str.length)
716
- break if RescueSMContext===@parsestack.last
723
+ break if RescueSMContext===@parsestack.last #and str==':'
724
+ break if WhenParamListContext===@parsestack.last and str==':'
717
725
  @parsestack.pop
718
726
  end
719
727
  return result
@@ -724,7 +732,7 @@ private
724
732
  AssignmentRhsContext=>AssignmentRhsListEndToken,
725
733
  ParamListContextNoParen=>ImplicitParamListEndToken,
726
734
  KWParamListContextNoParen=>ImplicitParamListEndToken,
727
- WhenParamListContext=>KwParamListEndToken,
735
+ WhenParamListContext=>KwParamListEndToken, #I think this isn't needed...
728
736
  RescueSMContext=>KwParamListEndToken
729
737
  }
730
738
  def abort_noparens_for_rescue!(str='')
@@ -791,6 +799,39 @@ private
791
799
  return result
792
800
  end
793
801
 
802
+ #-----------------------------------
803
+ def enable_macros!
804
+ @enable_macro="macro"
805
+ end
806
+ public :enable_macros!
807
+
808
+
809
+ #-----------------------------------
810
+ @@SPACES=/[\ \t\v\f\v]/
811
+ @@WSTOK=/\r?\n|\r*#@@SPACES+(?:#@@SPACES|\r(?!\n))*|\#[^\n]*\n|\\\r?\n|
812
+ ^=begin[\s\n](?:(?!=end).*\n)*=end[\s\n].*\n/x
813
+ @@WSTOKS=/(?!=begin)#@@WSTOK+/o
814
+ def divide_ws(ws,offset)
815
+ result=[]
816
+ ws.scan(/\G#@@WSTOK/o){|ws|
817
+ incr= $~.begin(0)
818
+ klass=case ws
819
+ when /\A[\#=]/: CommentToken
820
+ when /\n\Z/: EscNlToken
821
+ else WsToken
822
+ end
823
+ result << klass.new(ws,offset+incr)
824
+ }
825
+ result.each_with_index{|ws,i|
826
+ if WsToken===ws
827
+ ws.ident << result.delete(i+1).ident while WsToken===result[i+1]
828
+ end
829
+ }
830
+ return result
831
+ end
832
+
833
+
834
+
794
835
  #-----------------------------------
795
836
  #parse keywords now, to prevent confusion over bare symbols
796
837
  #and match end with corresponding preceding def or class or whatever.
@@ -823,7 +864,33 @@ private
823
864
  result.first.has_end!
824
865
  @parsestack.push WantsEndContext.new(str,@linenum)
825
866
  @localvars_stack.push SymbolTable.new
826
-
867
+ offset=input_position
868
+ @file.scan(/\A(#@@WSTOKS)?(::)?/o)
869
+ md=@file.last_match
870
+ all,ws,dc=*md
871
+ fail if all.empty?
872
+ @moretokens.concat divide_ws(ws,offset) if ws
873
+ @moretokens.push KeywordToken.new('::',offset+md.end(0)-2) if dc
874
+ loop do
875
+ offset=input_position
876
+ @file.scan(/\A(#@@WSTOKS)?([A-Z][a-zA-Z_0-9]*)(::)?/o)
877
+ #this regexp---^ will need to change in order to support utf8 properly.
878
+ md=@file.last_match
879
+ all,ws,name,dc=*md
880
+ if ws
881
+ @moretokens.concat divide_ws(ws,offset)
882
+ incr=ws.size
883
+ else
884
+ incr=0
885
+ end
886
+ @moretokens.push VarNameToken.new(name,offset+incr)
887
+ break unless dc
888
+ @moretokens.push KeywordToken.new('::',offset+md.end(0)-2)
889
+ end
890
+ @moretokens.push EndHeaderToken.new(input_position)
891
+
892
+
893
+
827
894
  when "class"
828
895
  result.first.has_end!
829
896
  @parsestack.push ClassContext.new(str,@linenum)
@@ -832,11 +899,12 @@ private
832
899
  if after_nonid_op?{false} #prefix form
833
900
  result.first.has_end!
834
901
  @parsestack.push WantsEndContext.new(str,@linenum)
835
-
836
-
902
+ @parsestack.push ExpectThenOrNlContext.new(str,@linenum)
837
903
  else #infix form
838
904
  result.unshift(*abort_noparens!(str))
839
905
  end
906
+ when "elsif"
907
+ @parsestack.push ExpectThenOrNlContext.new(str,@linenum)
840
908
  when "begin","case"
841
909
  result.first.has_end!
842
910
  @parsestack.push WantsEndContext.new(str,@linenum)
@@ -868,12 +936,12 @@ private
868
936
  localvars.start_block
869
937
  block_param_list_lookahead
870
938
  end
871
- when "def"
939
+ when "def",@enable_macro
872
940
  result.first.has_end!
873
941
  @parsestack.push ctx=DefContext.new(@linenum)
874
942
  ctx.state=:saw_def
875
943
  safe_recurse { |aa|
876
- set_last_token KeywordToken.new "def" #hack
944
+ set_last_token KeywordToken.new str #hack
877
945
  result.concat ignored_tokens
878
946
 
879
947
  #read an expr like a.b.c or a::b::c
@@ -957,7 +1025,7 @@ private
957
1025
  else
958
1026
  ofs+=listend.to_s.size
959
1027
  end
960
- result.insert end_index+1,EndDefHeaderToken.new(ofs)
1028
+ result.insert end_index+1,EndHeaderToken.new(ofs)
961
1029
  break
962
1030
  end
963
1031
 
@@ -983,7 +1051,7 @@ private
983
1051
  if endofs
984
1052
  result.insert -2,ImplicitParamListEndToken.new(tok.offset)
985
1053
  end
986
- result.insert -2, EndDefHeaderToken.new(tok.offset)
1054
+ result.insert -2, EndHeaderToken.new(tok.offset)
987
1055
  break
988
1056
  else
989
1057
  lexerror(tok, "bizarre token in def name: " +
@@ -1060,6 +1128,11 @@ private
1060
1128
  when "then"
1061
1129
  result.unshift(*abort_noparens!(str))
1062
1130
  @parsestack.last.see self,:then
1131
+
1132
+ if ExpectThenOrNlContext===@parsestack.last
1133
+ @parsestack.pop
1134
+ else #error... does anyone care?
1135
+ end
1063
1136
 
1064
1137
  when "in"
1065
1138
  result.unshift KwParamListEndToken.new( offset)
@@ -1083,7 +1156,7 @@ private
1083
1156
  #END blocks are visible to subsequent code. (Why??)
1084
1157
  #That difference forces a custom parsing.
1085
1158
  if @last_operative_token===/^(\.|::)$/
1086
- result=yield nil #should pass a keyword token here
1159
+ result=yield MethNameToken.new(str) #should pass a methname token here
1087
1160
  else
1088
1161
  safe_recurse{
1089
1162
  old=result.first
@@ -1096,17 +1169,18 @@ private
1096
1169
  getchar=='{' or lexerror(result.first,"expected { after #{str}")
1097
1170
  result.push KeywordToken.new('{',input_position-1)
1098
1171
  result.last.set_infix!
1172
+ result.last.as="do"
1099
1173
  @parsestack.push BeginEndContext.new(str,offset)
1100
1174
  }
1101
1175
  end
1102
1176
 
1103
1177
  when FUNCLIKE_KEYWORDS
1104
- result=yield nil #should be a keyword token
1178
+ result=yield MethNameToken.new(str) #should be a keyword token?
1105
1179
 
1106
1180
  when RUBYKEYWORDS
1107
1181
  #do nothing
1108
1182
 
1109
- else result=yield nil
1183
+ else result=yield MethNameToken.new(str)
1110
1184
 
1111
1185
  end
1112
1186
 
@@ -1307,7 +1381,7 @@ end
1307
1381
  # if !eof? and nextchar.chr[/[iuw\/<|>+\-*&%?:({]/] and
1308
1382
  # !(NewlineToken===@last_operative_token) and
1309
1383
  # !(/^(end|;)$/===@last_operative_token)
1310
- #result<<EndDefHeaderToken.new(result.last.offset+result.last.to_s.size)
1384
+ #result<<EndHeaderToken.new(result.last.offset+result.last.to_s.size)
1311
1385
  set_last_token KeywordToken.new ';'
1312
1386
  result<< get1token
1313
1387
  # end
@@ -1426,10 +1500,18 @@ end
1426
1500
  #-----------------------------------
1427
1501
  def symbol_or_op(ch)
1428
1502
  startpos= input_position
1503
+
1504
+
1429
1505
  qe= colon_quote_expected?(ch)
1430
1506
  lastchar=prevchar
1431
1507
  eat_next_if(ch[0]) or raise "needed: "+ch
1432
1508
 
1509
+ if nextchar==?( and @enable_macro
1510
+ result= OperatorToken.new(':', startpos)
1511
+ result.unary=true
1512
+ return result
1513
+ end
1514
+
1433
1515
  #handle quoted symbols like :"foobar", :"[]"
1434
1516
  qe and return symbol(':')
1435
1517
 
@@ -1437,17 +1519,23 @@ end
1437
1519
  unless eat_next_if(?:)
1438
1520
  #cancel implicit contexts...
1439
1521
  @moretokens.push(*abort_noparens!(':'))
1440
- @moretokens.push KeywordToken.new(':',startpos)
1522
+ @moretokens.push tok=KeywordToken.new(':',startpos)
1441
1523
 
1442
1524
  case @parsestack.last
1443
- when TernaryContext: @parsestack.pop #should be in the context's see handler
1525
+ when TernaryContext:
1526
+ tok.ternary=true
1527
+ @parsestack.pop #should be in the context's see handler
1444
1528
  when ExpectDoOrNlContext: #should be in the context's see handler
1445
1529
  @parsestack.pop
1446
1530
  assert @parsestack.last.starter[/^(while|until|for)$/]
1447
- @moretokens.last.as=";"
1531
+ tok.as=";"
1532
+ when ExpectThenOrNlContext,WhenParamListContext:
1533
+ #should be in the context's see handler
1534
+ @parsestack.pop
1535
+ tok.as="then"
1448
1536
  when RescueSMContext:
1449
- @moretokens.last.as=";"
1450
- else @moretokens.last.as="then"
1537
+ tok.as=";"
1538
+ else fail ": not expected in #{@parsestack.last.class}->#{@parsestack.last.starter}"
1451
1539
  end
1452
1540
 
1453
1541
  #end ternary context, if any
@@ -1503,7 +1591,9 @@ end
1503
1591
  /[A-Z_0-9]$/i===result and klass=VarNameToken
1504
1592
  end
1505
1593
  result
1506
- else error= "unexpected char starting symbol: #{nc.chr}"
1594
+ else
1595
+ error= "unexpected char starting symbol: #{nc.chr}"
1596
+ '_'
1507
1597
  end
1508
1598
  result= lexerror(klass.new(result,start,notbare ? ':' : ''),error)
1509
1599
  if open
@@ -1843,7 +1933,10 @@ end
1843
1933
  then #hack-o-rama: probly cases left out above
1844
1934
  @offset_adjust=@min_offset_adjust
1845
1935
  a= abort_noparens!
1846
- ExpectDoOrNlContext===@parsestack.last and @parsestack.pop
1936
+ case @parsestack.last #these should be in the see:semi handler
1937
+ when ExpectDoOrNlContext: @parsestack.pop
1938
+ when ExpectThenOrNlContext: @parsestack.pop
1939
+ end
1847
1940
  assert !@parsestack.empty?
1848
1941
  @parsestack.last.see self,:semi
1849
1942
 
@@ -2011,7 +2104,7 @@ end
2011
2104
  when /^(#{RUBYOPERATORREX}|#{INNERBOUNDINGWORDS}|do)$/o.token_pat
2012
2105
  #regexs above must match whole string
2013
2106
  #assert(@last_operative_token==$&) #disabled 'cause $& is now always nil :(
2014
- return true
2107
+ return true if OperatorToken===@last_operative_token || KeywordToken===@last_operative_token
2015
2108
  when NewlineToken, nil, #nil means we're still at beginning of file
2016
2109
  /^([({\[]|or|not|and|if|unless|then|elsif|else|class|module|def|
2017
2110
  while|until|begin|for|in|case|when|ensure|defined\?)$
@@ -2065,15 +2158,31 @@ end
2065
2158
  end
2066
2159
 
2067
2160
 
2068
- #-----------------------------------
2069
- def biop(ch) #match /%=?/ (% or %=)
2161
+ #-----------------------------------
2162
+ def caret(ch) #match /^=?/ (^ or ^=) (maybe unary ^ too)
2163
+ if @enable_macro and (@last_token_maybe_implicit and
2164
+ @last_token_maybe_implicit.ident=='(') || unary_op_expected?(ch)
2165
+ result=OperatorToken.new(read(1),input_position)
2166
+ result.unary=true
2167
+ result
2168
+ else
2169
+ biop ch
2170
+ end
2171
+ end
2172
+
2173
+ #-----------------------------------
2174
+ def biop(ch) #match /%=?/ (% or %=)
2070
2175
  assert(ch[/^[%^]$/])
2176
+ oldpos=input_position
2071
2177
  result=getchar
2072
2178
  if eat_next_if(?=)
2073
2179
  result << ?=
2074
2180
  end
2075
- return operator_or_methname_token( result)
2181
+ result= operator_or_methname_token( result)
2182
+ result.offset=oldpos
2183
+ return result
2076
2184
  end
2185
+
2077
2186
  #-----------------------------------
2078
2187
  def tilde(ch) #match ~
2079
2188
  assert(ch=='~')
@@ -2322,10 +2431,8 @@ end
2322
2431
  lexerror kw,"mismatched braces: #{origch}#{ch}\n" +
2323
2432
  "matching brace location", @filename, line
2324
2433
  end
2325
- if BlockContext===ctx
2326
- localvars.end_block
2327
- @moretokens.last.as="end"
2328
- end
2434
+ localvars.end_block if BlockContext===ctx
2435
+ @moretokens.last.as="end" if BlockContext===ctx or BeginEndContext===ctx
2329
2436
  if ParamListContext==ctx.class
2330
2437
  assert ch==')'
2331
2438
  kw.set_callsite! #not needed?
@@ -2372,6 +2479,7 @@ end
2372
2479
  ParamListContext===@parsestack[-2] ||
2373
2480
  ParamListContextNoParen===@parsestack[-2] ||
2374
2481
  WhenParamListContext===@parsestack[-2] ||
2482
+ ListImmedContext===@parsestack[-2] ||
2375
2483
  (RescueSMContext===@parsestack[-2] && @parsestack[-2].state==:rescue) ||
2376
2484
  (DefContext===@parsestack[-2] && !@parsestack[-2].in_body)
2377
2485
  @parsestack.pop
@@ -2394,7 +2502,10 @@ end
2394
2502
  assert @moretokens.empty?
2395
2503
  @moretokens.push(*abort_noparens!)
2396
2504
  @parsestack.last.see self,:semi
2397
- if ExpectDoOrNlContext===@parsestack.last #should be in context's see:semi handler
2505
+ case @parsestack.last #should be in context's see:semi handler
2506
+ when ExpectThenOrNlContext
2507
+ @parsestack.pop
2508
+ when ExpectDoOrNlContext
2398
2509
  @parsestack.pop
2399
2510
  assert @parsestack.last.starter[/^(while|until|for)$/]
2400
2511
  end
@@ -2417,7 +2528,7 @@ end
2417
2528
  #-----------------------------------
2418
2529
  #tokenify_results_of :identifier
2419
2530
  save_offsets_in(*CHARMAPPINGS.values.uniq-[
2420
- :symbol_or_op,:open_brace,:whitespace,:exclam,:backquote
2531
+ :symbol_or_op,:open_brace,:whitespace,:exclam,:backquote,:caret
2421
2532
  ])
2422
2533
  #save_offsets_in :symbol
2423
2534