opal 0.5.5 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (257) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +40 -9
  3. data/CHANGELOG.md +349 -0
  4. data/Gemfile +7 -8
  5. data/README.md +25 -3
  6. data/Rakefile +4 -2
  7. data/bin/opal +1 -1
  8. data/examples/rack/Gemfile +3 -0
  9. data/examples/rack/app/application.rb +13 -0
  10. data/examples/rack/app/user.rb +21 -0
  11. data/examples/rack/config.ru +7 -0
  12. data/examples/rack/index.html.erb +10 -0
  13. data/examples/sinatra/Gemfile +4 -0
  14. data/examples/sinatra/app/application.rb +7 -0
  15. data/examples/sinatra/config.ru +21 -0
  16. data/lib/mspec/opal/rake_task.rb +29 -8
  17. data/lib/mspec/opal/runner.rb +5 -4
  18. data/lib/opal.rb +1 -0
  19. data/lib/opal/builder.rb +0 -28
  20. data/lib/opal/cli.rb +0 -14
  21. data/lib/opal/compiler.rb +12 -11
  22. data/lib/opal/fragment.rb +8 -1
  23. data/lib/opal/nodes/array.rb +1 -1
  24. data/lib/opal/nodes/base.rb +4 -0
  25. data/lib/opal/nodes/call.rb +6 -2
  26. data/lib/opal/nodes/call_special.rb +1 -1
  27. data/lib/opal/nodes/class.rb +2 -2
  28. data/lib/opal/nodes/constants.rb +3 -1
  29. data/lib/opal/nodes/helpers.rb +23 -14
  30. data/lib/opal/nodes/if.rb +16 -9
  31. data/lib/opal/nodes/literal.rb +37 -5
  32. data/lib/opal/nodes/logic.rb +7 -1
  33. data/lib/opal/nodes/module.rb +2 -2
  34. data/lib/opal/nodes/scope.rb +13 -2
  35. data/lib/opal/nodes/top.rb +9 -0
  36. data/lib/opal/nodes/variables.rb +5 -2
  37. data/lib/opal/parser.rb +306 -71
  38. data/lib/opal/parser/grammar.rb +2667 -2775
  39. data/lib/opal/parser/grammar.y +177 -233
  40. data/lib/opal/parser/lexer.rb +511 -427
  41. data/lib/opal/parser/sexp.rb +15 -3
  42. data/lib/opal/source_map.rb +8 -4
  43. data/lib/opal/sprockets.rb +4 -0
  44. data/lib/opal/sprockets/cache_key_fix.rb +17 -0
  45. data/lib/opal/sprockets/environment.rb +21 -0
  46. data/lib/opal/sprockets/erb.rb +30 -0
  47. data/lib/opal/sprockets/processor.rb +127 -0
  48. data/lib/opal/sprockets/server.rb +166 -0
  49. data/lib/opal/util.rb +29 -0
  50. data/lib/opal/version.rb +1 -1
  51. data/opal.gemspec +1 -1
  52. data/opal/corelib/array.rb +106 -187
  53. data/opal/corelib/array/inheritance.rb +113 -0
  54. data/opal/corelib/basic_object.rb +6 -2
  55. data/opal/corelib/boolean.rb +4 -0
  56. data/opal/corelib/class.rb +2 -0
  57. data/opal/corelib/complex.rb +3 -0
  58. data/opal/corelib/enumerable.rb +75 -8
  59. data/opal/corelib/enumerator.rb +2 -0
  60. data/opal/corelib/error.rb +23 -23
  61. data/opal/corelib/hash.rb +5 -5
  62. data/opal/corelib/helpers.rb +51 -16
  63. data/opal/corelib/io.rb +7 -24
  64. data/opal/corelib/kernel.rb +23 -11
  65. data/opal/corelib/module.rb +44 -47
  66. data/opal/corelib/nil_class.rb +4 -0
  67. data/opal/corelib/numeric.rb +101 -15
  68. data/opal/corelib/range.rb +2 -0
  69. data/opal/corelib/rational.rb +3 -0
  70. data/opal/corelib/regexp.rb +36 -17
  71. data/opal/corelib/runtime.js +22 -7
  72. data/opal/corelib/string.rb +213 -110
  73. data/opal/corelib/string/inheritance.rb +78 -0
  74. data/opal/corelib/struct.rb +8 -0
  75. data/opal/corelib/time.rb +54 -42
  76. data/opal/corelib/variables.rb +24 -0
  77. data/opal/opal.rb +5 -27
  78. data/spec/cli/compiler_spec.rb +136 -0
  79. data/spec/cli/dependency_resolver_spec.rb +40 -0
  80. data/spec/cli/lexer_spec.rb +110 -0
  81. data/spec/cli/parser/alias_spec.rb +26 -0
  82. data/spec/cli/parser/and_spec.rb +13 -0
  83. data/spec/cli/parser/attrasgn_spec.rb +28 -0
  84. data/spec/cli/parser/begin_spec.rb +42 -0
  85. data/spec/cli/parser/block_spec.rb +12 -0
  86. data/spec/cli/parser/break_spec.rb +17 -0
  87. data/spec/cli/parser/call_spec.rb +139 -0
  88. data/spec/cli/parser/class_spec.rb +35 -0
  89. data/spec/cli/parser/comments_spec.rb +11 -0
  90. data/spec/cli/parser/def_spec.rb +61 -0
  91. data/spec/cli/parser/if_spec.rb +26 -0
  92. data/spec/cli/parser/iter_spec.rb +59 -0
  93. data/spec/cli/parser/lambda_spec.rb +64 -0
  94. data/spec/cli/parser/literal_spec.rb +113 -0
  95. data/spec/cli/parser/masgn_spec.rb +37 -0
  96. data/spec/cli/parser/module_spec.rb +27 -0
  97. data/spec/cli/parser/not_spec.rb +27 -0
  98. data/spec/cli/parser/op_asgn1_spec.rb +23 -0
  99. data/spec/cli/parser/op_asgn2_spec.rb +23 -0
  100. data/spec/cli/parser/or_spec.rb +13 -0
  101. data/spec/cli/parser/return_spec.rb +17 -0
  102. data/spec/cli/parser/sclass_spec.rb +21 -0
  103. data/spec/cli/parser/string_spec.rb +269 -0
  104. data/spec/cli/parser/super_spec.rb +20 -0
  105. data/spec/cli/parser/undef_spec.rb +15 -0
  106. data/spec/cli/parser/unless_spec.rb +13 -0
  107. data/spec/cli/parser/variables_spec.rb +92 -0
  108. data/spec/cli/parser/while_spec.rb +15 -0
  109. data/spec/cli/parser/yield_spec.rb +20 -0
  110. data/spec/cli/spec_helper.rb +31 -11
  111. data/spec/opal/core/array/set_range_to_array_spec.rb +7 -0
  112. data/spec/opal/core/date_spec.rb +122 -0
  113. data/spec/opal/core/language/predefined_spec.rb +1 -1
  114. data/spec/opal/core/runtime/operator_call_spec.rb +13 -0
  115. data/spec/opal/core/runtime/truthy_spec.rb +23 -0
  116. data/spec/opal/filters/bugs/array.rb +96 -87
  117. data/spec/opal/filters/bugs/basic_object.rb +9 -0
  118. data/spec/opal/filters/bugs/class.rb +16 -0
  119. data/spec/opal/filters/bugs/enumerable.rb +54 -0
  120. data/spec/opal/filters/bugs/language.rb +37 -3
  121. data/spec/opal/filters/bugs/math.rb +93 -0
  122. data/spec/opal/filters/bugs/nil.rb +7 -0
  123. data/spec/opal/filters/bugs/numeric.rb +19 -0
  124. data/spec/opal/filters/bugs/opal.rb +12 -0
  125. data/spec/opal/filters/bugs/regexp.rb +0 -2
  126. data/spec/opal/filters/bugs/string.rb +317 -19
  127. data/spec/opal/filters/bugs/struct.rb +29 -0
  128. data/spec/opal/filters/bugs/time.rb +130 -9
  129. data/spec/opal/filters/unsupported/encoding.rb +52 -4
  130. data/spec/opal/filters/unsupported/enumerator.rb +0 -3
  131. data/spec/opal/filters/unsupported/integer_size.rb +7 -0
  132. data/spec/opal/filters/unsupported/method_added.rb +10 -0
  133. data/spec/opal/filters/unsupported/mutable_strings.rb +299 -1
  134. data/spec/opal/filters/unsupported/private_constants.rb +30 -0
  135. data/spec/opal/filters/unsupported/private_methods.rb +16 -0
  136. data/spec/opal/filters/unsupported/random.rb +4 -0
  137. data/spec/opal/filters/unsupported/tainted.rb +53 -0
  138. data/spec/opal/filters/unsupported/trusted.rb +5 -0
  139. data/spec/opal/rubyspecs +167 -234
  140. data/spec/opal/spec_helper.rb +3 -0
  141. data/spec/opal/stdlib/promise/error_spec.rb +15 -0
  142. data/spec/opal/stdlib/promise/rescue_spec.rb +35 -0
  143. data/spec/opal/stdlib/promise/then_spec.rb +54 -0
  144. data/spec/opal/stdlib/promise/trace_spec.rb +35 -0
  145. data/spec/opal/stdlib/promise/value_spec.rb +15 -0
  146. data/spec/opal/stdlib/promise/when_spec.rb +34 -0
  147. data/stdlib/base64.rb +152 -0
  148. data/stdlib/date.rb +82 -49
  149. data/{opal/corelib → stdlib}/encoding.rb +3 -1
  150. data/stdlib/erb.rb +0 -1
  151. data/stdlib/json.rb +10 -26
  152. data/stdlib/math.rb +370 -0
  153. data/stdlib/native.rb +40 -33
  154. data/stdlib/opal-parser.rb +7 -4
  155. data/stdlib/promise.rb +292 -0
  156. data/stdlib/strscan.rb +1 -1
  157. data/stdlib/template.rb +1 -3
  158. data/stdlib/time.rb +9 -0
  159. metadata +143 -204
  160. data/doc/compiler.md +0 -42
  161. data/doc/compiler_options.md +0 -5
  162. data/doc/examples/node_http_server.rb +0 -49
  163. data/doc/external_libraries.md +0 -9
  164. data/doc/generated_javascript.md +0 -272
  165. data/doc/home.md +0 -17
  166. data/doc/method_missing.md +0 -58
  167. data/doc/static_applications.md +0 -60
  168. data/doc/using_ruby_from_javascript.md +0 -18
  169. data/doc/using_sprockets.md +0 -65
  170. data/spec/opal/core/numeric/abs_spec.rb +0 -12
  171. data/spec/opal/core/numeric/downto_spec.rb +0 -19
  172. data/spec/opal/core/numeric/equal_value_spec.rb +0 -9
  173. data/spec/opal/core/numeric/even_spec.rb +0 -21
  174. data/spec/opal/core/numeric/magnitude_spec.rb +0 -12
  175. data/spec/opal/core/numeric/odd_spec.rb +0 -21
  176. data/spec/opal/core/string/chop_spec.rb +0 -10
  177. data/spec/opal/core/string/chr_spec.rb +0 -13
  178. data/spec/opal/core/string/clone_spec.rb +0 -8
  179. data/spec/opal/core/string/comparison_spec.rb +0 -13
  180. data/spec/opal/core/string/dup_spec.rb +0 -8
  181. data/spec/opal/core/string/element_reference_spec.rb +0 -96
  182. data/spec/opal/core/string/fixtures/classes.rb +0 -49
  183. data/spec/opal/core/string/format_spec.rb +0 -9
  184. data/spec/opal/core/string/freeze_spec.rb +0 -15
  185. data/spec/opal/core/string/gsub_spec.rb +0 -31
  186. data/spec/opal/core/string/lines_spec.rb +0 -9
  187. data/spec/opal/core/string/ljust_spec.rb +0 -32
  188. data/spec/opal/core/string/lstrip_spec.rb +0 -7
  189. data/spec/opal/core/string/match_spec.rb +0 -49
  190. data/spec/opal/core/string/next_spec.rb +0 -10
  191. data/spec/opal/core/string/ord_spec.rb +0 -9
  192. data/spec/opal/core/string/partition_spec.rb +0 -10
  193. data/spec/opal/core/string/rindex_spec.rb +0 -50
  194. data/spec/opal/core/string/rjust_spec.rb +0 -32
  195. data/spec/opal/core/string/rstrip_spec.rb +0 -7
  196. data/spec/opal/core/string/scan_spec.rb +0 -66
  197. data/spec/opal/core/string/slice_spec.rb +0 -74
  198. data/spec/opal/core/string/split_spec.rb +0 -5
  199. data/spec/opal/core/string/strip_spec.rb +0 -6
  200. data/spec/opal/core/string/sub_spec.rb +0 -38
  201. data/spec/opal/core/string/succ_spec.rb +0 -10
  202. data/spec/opal/core/string/sum_spec.rb +0 -5
  203. data/spec/opal/core/string/to_f_spec.rb +0 -14
  204. data/spec/opal/core/string/to_i_spec.rb +0 -25
  205. data/spec/opal/core/string/tr_s_spec.rb +0 -31
  206. data/spec/opal/core/string/tr_spec.rb +0 -31
  207. data/spec/opal/filters/bugs/parser.rb +0 -10
  208. data/spec/opal/filters/unsupported/immutable_strings.rb +0 -24
  209. data/spec/opal/filters/unsupported/string_subclasses.rb +0 -8
  210. data/spec/opal/parser/alias_spec.rb +0 -26
  211. data/spec/opal/parser/and_spec.rb +0 -13
  212. data/spec/opal/parser/array_spec.rb +0 -22
  213. data/spec/opal/parser/attrasgn_spec.rb +0 -28
  214. data/spec/opal/parser/begin_spec.rb +0 -42
  215. data/spec/opal/parser/block_spec.rb +0 -12
  216. data/spec/opal/parser/break_spec.rb +0 -17
  217. data/spec/opal/parser/call_spec.rb +0 -131
  218. data/spec/opal/parser/class_spec.rb +0 -35
  219. data/spec/opal/parser/const_spec.rb +0 -13
  220. data/spec/opal/parser/cvar_spec.rb +0 -11
  221. data/spec/opal/parser/def_spec.rb +0 -61
  222. data/spec/opal/parser/false_spec.rb +0 -17
  223. data/spec/opal/parser/file_spec.rb +0 -7
  224. data/spec/opal/parser/gvar_spec.rb +0 -13
  225. data/spec/opal/parser/hash_spec.rb +0 -17
  226. data/spec/opal/parser/heredoc_spec.rb +0 -30
  227. data/spec/opal/parser/iasgn_spec.rb +0 -9
  228. data/spec/opal/parser/if_spec.rb +0 -26
  229. data/spec/opal/parser/int_spec.rb +0 -13
  230. data/spec/opal/parser/iter_spec.rb +0 -59
  231. data/spec/opal/parser/ivar_spec.rb +0 -9
  232. data/spec/opal/parser/lambda_spec.rb +0 -64
  233. data/spec/opal/parser/lasgn_spec.rb +0 -8
  234. data/spec/opal/parser/line_spec.rb +0 -8
  235. data/spec/opal/parser/lvar_spec.rb +0 -38
  236. data/spec/opal/parser/masgn_spec.rb +0 -37
  237. data/spec/opal/parser/module_spec.rb +0 -27
  238. data/spec/opal/parser/nil_spec.rb +0 -17
  239. data/spec/opal/parser/not_spec.rb +0 -27
  240. data/spec/opal/parser/nth_ref_spec.rb +0 -13
  241. data/spec/opal/parser/op_asgn1_spec.rb +0 -23
  242. data/spec/opal/parser/op_asgn2_spec.rb +0 -23
  243. data/spec/opal/parser/or_spec.rb +0 -13
  244. data/spec/opal/parser/parse_spec.rb +0 -66
  245. data/spec/opal/parser/regexp_spec.rb +0 -16
  246. data/spec/opal/parser/return_spec.rb +0 -17
  247. data/spec/opal/parser/sclass_spec.rb +0 -21
  248. data/spec/opal/parser/self_spec.rb +0 -17
  249. data/spec/opal/parser/str_spec.rb +0 -107
  250. data/spec/opal/parser/string_spec.rb +0 -8
  251. data/spec/opal/parser/super_spec.rb +0 -20
  252. data/spec/opal/parser/true_spec.rb +0 -17
  253. data/spec/opal/parser/undef_spec.rb +0 -15
  254. data/spec/opal/parser/unless_spec.rb +0 -13
  255. data/spec/opal/parser/while_spec.rb +0 -15
  256. data/spec/opal/parser/xstr_spec.rb +0 -116
  257. data/spec/opal/parser/yield_spec.rb +0 -20
@@ -4,21 +4,51 @@ require 'opal/parser/keywords'
4
4
  module Opal
5
5
  class Lexer
6
6
 
7
- attr_reader :line, :scope_line, :scope
8
-
9
- attr_accessor :lex_state, :strterm, :scanner
7
+ STR_FUNC_ESCAPE = 0x01
8
+ STR_FUNC_EXPAND = 0x02
9
+ STR_FUNC_REGEXP = 0x04
10
+ STR_FUNC_QWORDS = 0x08
11
+ STR_FUNC_SYMBOL = 0x10
12
+ STR_FUNC_INDENT = 0x20
13
+ STR_FUNC_XQUOTE = 0x40
14
+
15
+ STR_SQUOTE = 0x00
16
+ STR_DQUOTE = STR_FUNC_EXPAND
17
+ STR_XQUOTE = STR_FUNC_EXPAND | STR_FUNC_XQUOTE
18
+ STR_REGEXP = STR_FUNC_REGEXP | STR_FUNC_ESCAPE | STR_FUNC_EXPAND
19
+ STR_SWORD = STR_FUNC_QWORDS
20
+ STR_DWORD = STR_FUNC_QWORDS | STR_FUNC_EXPAND
21
+ STR_SSYM = STR_FUNC_SYMBOL
22
+ STR_DSYM = STR_FUNC_SYMBOL | STR_FUNC_EXPAND
23
+
24
+ attr_reader :line
25
+ attr_reader :scope
26
+ attr_reader :eof_content
27
+
28
+ attr_accessor :lex_state
29
+ attr_accessor :strterm
30
+ attr_accessor :scanner
31
+ attr_accessor :yylval
32
+ attr_accessor :parser
10
33
 
11
34
  def initialize(source, file)
12
35
  @lex_state = :expr_beg
13
36
  @cond = 0
14
37
  @cmdarg = 0
15
38
  @line = 1
39
+ @tok_line = 1
40
+ @column = 0
41
+ @tok_column = 0
16
42
  @file = file
17
43
 
18
44
  @scanner = StringScanner.new(source)
19
45
  @scanner_stack = [@scanner]
20
46
  end
21
47
 
48
+ def has_local?(local)
49
+ parser.scope.has_local?(local.to_sym)
50
+ end
51
+
22
52
  def cond_push(n)
23
53
  @cond = (@cond << 1) | (n & 1)
24
54
  end
@@ -75,153 +105,258 @@ module Opal
75
105
  @scanner.check(/\s/)
76
106
  end
77
107
 
108
+ def set_arg_state
109
+ @lex_state = after_operator? ? :expr_arg : :expr_beg
110
+ end
111
+
78
112
  def scan(regexp)
79
- @scanner.scan regexp
113
+ if result = @scanner.scan(regexp)
114
+ @column += result.length
115
+ @yylval += @scanner.matched
116
+ end
117
+
118
+ result
119
+ end
120
+
121
+ def skip(regexp)
122
+ if result = @scanner.scan(regexp)
123
+ @column += result.length
124
+ @tok_column = @column
125
+ end
126
+
127
+ result
80
128
  end
81
129
 
82
130
  def check(regexp)
83
131
  @scanner.check regexp
84
132
  end
85
133
 
134
+ def pushback(n)
135
+ @scanner.pos -= n
136
+ end
137
+
86
138
  def matched
87
139
  @scanner.matched
88
140
  end
89
141
 
90
- def next_token
91
- self.yylex
142
+ def line=(line)
143
+ @column = @tok_column = 0
144
+ @line = @tok_line = line
92
145
  end
93
146
 
94
- def strterm_expand?(strterm)
95
- type = strterm[:type]
147
+ def next_token
148
+ token = self.yylex
149
+ value = self.yylval
150
+ location = [@tok_line, @tok_column]
96
151
 
97
- [:dquote, :dsym, :dword, :heredoc, :xquote, :regexp].include? type
152
+ # once location is stored, ensure next token starts in correct place
153
+ @tok_column = @column
154
+ @tok_line = @line
155
+
156
+ [token, [value, location]]
98
157
  end
99
158
 
100
- def new_strterm(type, start, finish)
101
- { :type => type, :beg => start, :end => finish }
159
+ def new_strterm(func, term, paren)
160
+ { :type => :string, :func => func, :term => term, :paren => paren }
102
161
  end
103
162
 
104
- def new_strterm2(type, start, finish)
105
- term = new_strterm(type, start, finish)
163
+ def new_strterm2(func, term, paren)
164
+ term = new_strterm(func, term, paren)
106
165
  term.merge({ :balance => true, :nesting => 0 })
107
166
  end
108
167
 
168
+ def new_op_asgn(value)
169
+ self.yylval = value
170
+ :tOP_ASGN
171
+ end
172
+
109
173
  def process_numeric
110
174
  @lex_state = :expr_end
111
- scanner = @scanner
112
175
 
113
176
  if scan(/0b?(0|1|_)+/)
114
- return [:tINTEGER, scanner.matched.to_i(2)]
177
+ self.yylval = scanner.matched.to_i(2)
178
+ return :tINTEGER
115
179
  elsif scan(/0o?([0-7]|_)+/)
116
- return [:tINTEGER, scanner.matched.to_i(8)]
180
+ self.yylval = scanner.matched.to_i(8)
181
+ return :tINTEGER
117
182
  elsif scan(/[\d_]+\.[\d_]+\b|[\d_]+(\.[\d_]+)?[eE][-+]?[\d_]+\b/)
118
- return [:tFLOAT, scanner.matched.gsub(/_/, '').to_f]
183
+ self.yylval = scanner.matched.gsub(/_/, '').to_f
184
+ return :tFLOAT
119
185
  elsif scan(/[\d_]+\b/)
120
- return [:tINTEGER, scanner.matched.gsub(/_/, '').to_i]
186
+ self.yylval = scanner.matched.gsub(/_/, '').to_i
187
+ return :tINTEGER
121
188
  elsif scan(/0(x|X)(\d|[a-f]|[A-F]|_)+/)
122
- return [:tINTEGER, scanner.matched.to_i(16)]
189
+ self.yylval = scanner.matched.to_i(16)
190
+ return :tINTEGER
123
191
  else
124
192
  raise "Lexing error on numeric type: `#{scanner.peek 5}`"
125
193
  end
126
194
  end
127
195
 
128
- def next_string_token
129
- str_parse = self.strterm
130
- scanner = @scanner
131
- space = false
196
+ def read_escape
197
+ if scan(/\\/)
198
+ "\\"
199
+ elsif scan(/n/)
200
+ "\n"
201
+ elsif scan(/t/)
202
+ "\t"
203
+ elsif scan(/r/)
204
+ "\r"
205
+ elsif scan(/f/)
206
+ "\f"
207
+ elsif scan(/v/)
208
+ "\v"
209
+ elsif scan(/a/)
210
+ "\a"
211
+ elsif scan(/e/)
212
+ "\e"
213
+ elsif scan(/s/)
214
+ " "
215
+ elsif scan(/[0-7]{1,3}/)
216
+ (matched.to_i(8) % 0x100).chr
217
+ elsif scan(/x([0-9a-fA-F]{1,2})/)
218
+ scanner[1].to_i(16).chr
219
+ elsif scan(/u([0-9a-zA-Z]{1,4})/)
220
+ if defined?(::Encoding)
221
+ scanner[1].to_i(16).chr(Encoding::UTF_8)
222
+ else
223
+ # FIXME: no encoding on 1.8
224
+ ""
225
+ end
226
+ else
227
+ # escaped char doesnt need escaping, so just return it
228
+ scan(/./)
229
+ end
230
+ end
132
231
 
133
- expand = strterm_expand?(str_parse)
232
+ def peek_variable_name
233
+ if check(/[@$]/)
234
+ :tSTRING_DVAR
235
+ elsif scan(/\{/)
236
+ :tSTRING_DBEG
237
+ end
238
+ end
134
239
 
135
- words = ['w', 'W'].include? str_parse[:beg]
240
+ def here_document(str_parse)
241
+ eos_regx = /[ \t]*#{Regexp.escape(str_parse[:term])}(\r*\n|$)/
242
+ expand = true
136
243
 
137
- space = true if ['w', 'W'].include?(str_parse[:beg]) and scan(/\s+/)
244
+ if check(eos_regx)
245
+ scan(/[ \t]*#{Regexp.escape(str_parse[:term])}/)
246
+
247
+ if str_parse[:scanner]
248
+ @scanner_stack << str_parse[:scanner]
249
+ @scanner = str_parse[:scanner]
250
+ end
251
+
252
+ return :tSTRING_END
253
+ end
138
254
 
139
- # if not end of string, so we must be parsing contents
140
255
  str_buffer = []
141
256
 
142
- if str_parse[:type] == :heredoc
143
- eos_regx = /[ \t]*#{Regexp.escape(str_parse[:end])}(\r*\n|$)/
257
+ if scan(/#/)
258
+ if tok = peek_variable_name
259
+ return tok
260
+ end
144
261
 
145
- if check(eos_regx)
146
- scan(/[ \t]*#{Regexp.escape(str_parse[:end])}/)
147
- self.strterm = nil
262
+ str_buffer << '#'
263
+ end
148
264
 
149
- if str_parse[:scanner]
150
- @scanner_stack << str_parse[:scanner]
151
- @scanner = str_parse[:scanner]
152
- end
265
+ until check(eos_regx) && scanner.bol?
266
+ if scanner.eos?
267
+ raise "reached EOF while in heredoc"
268
+ end
153
269
 
154
- @lex_state = :expr_end
155
- return :tSTRING_END, scanner.matched
270
+ if scan(/\n/)
271
+ str_buffer << scanner.matched
272
+ elsif expand && check(/#(?=[\$\@\{])/)
273
+ break
274
+ elsif scan(/\\/)
275
+ str_buffer << self.read_escape
276
+ else
277
+ reg = Regexp.new("[^\#\0\\\\\n]+|.")
278
+
279
+ scan reg
280
+ str_buffer << scanner.matched
156
281
  end
157
282
  end
158
283
 
159
- # see if we can read end of string/xstring/regexp markers
160
- # if scan /#{str_parse[:end]}/
161
- if scan Regexp.new(Regexp.escape(str_parse[:end]))
162
- if words && !str_parse[:done_last_space]#&& space
284
+ complete_str = str_buffer.join ''
285
+ @line += complete_str.count("\n")
286
+
287
+ self.yylval = complete_str
288
+ return :tSTRING_CONTENT
289
+ end
290
+
291
+ def parse_string
292
+ str_parse = self.strterm
293
+ func = str_parse[:func]
294
+
295
+ space = false
296
+
297
+ qwords = (func & STR_FUNC_QWORDS) != 0
298
+ expand = (func & STR_FUNC_EXPAND) != 0
299
+ regexp = (func & STR_FUNC_REGEXP) != 0
300
+
301
+ space = true if qwords and scan(/\s+/)
302
+
303
+ # if not end of string, so we must be parsing contents
304
+ str_buffer = []
305
+
306
+ if scan Regexp.new(Regexp.escape(str_parse[:term]))
307
+ if qwords && !str_parse[:done_last_space]#&& space
163
308
  str_parse[:done_last_space] = true
164
- scanner.pos -= 1
165
- return :tSPACE, ' '
309
+ pushback(1)
310
+ self.yylval = ' '
311
+ return :tSPACE
166
312
  end
167
- self.strterm = nil
168
313
 
169
314
  if str_parse[:balance]
170
315
  if str_parse[:nesting] == 0
171
- @lex_state = :expr_end
172
316
 
173
- if str_parse[:type] == :regexp
174
- result = scan(/\w+/)
175
- return :tREGEXP_END, result
317
+ if regexp
318
+ self.yylval = scan(/\w+/)
319
+ return :tREGEXP_END
176
320
  end
177
- return :tSTRING_END, scanner.matched
321
+ return :tSTRING_END
178
322
  else
179
323
  str_buffer << scanner.matched
180
324
  str_parse[:nesting] -= 1
181
325
  self.strterm = str_parse
182
326
  end
183
-
184
- elsif ['"', "'"].include? str_parse[:beg]
327
+ elsif regexp
185
328
  @lex_state = :expr_end
186
- return :tSTRING_END, scanner.matched
187
-
188
- elsif str_parse[:beg] == '`'
189
- @lex_state = :expr_end
190
- return :tSTRING_END, scanner.matched
191
-
192
- elsif str_parse[:beg] == '/' || str_parse[:type] == :regexp
193
- result = scan(/\w+/)
194
- @lex_state = :expr_end
195
- return :tREGEXP_END, result
196
-
329
+ self.yylval = scan(/\w+/)
330
+ return :tREGEXP_END
197
331
  else
198
332
  if str_parse[:scanner]
199
333
  @scanner_stack << str_parse[:scanner]
200
334
  @scanner = str_parse[:scanner]
201
335
  end
202
336
 
203
- @lex_state = :expr_end
204
- return :tSTRING_END, scanner.matched
337
+ return :tSTRING_END
205
338
  end
206
339
  end
207
340
 
208
- return :tSPACE, ' ' if space
341
+ if space
342
+ self.yylval = ' '
343
+ return :tSPACE
344
+ end
209
345
 
210
- if str_parse[:balance] and scan Regexp.new(Regexp.escape(str_parse[:beg]))
346
+ if str_parse[:balance] and scan Regexp.new(Regexp.escape(str_parse[:paren]))
211
347
  str_buffer << scanner.matched
212
348
  str_parse[:nesting] += 1
213
349
  elsif check(/#[@$]/)
214
350
  scan(/#/)
215
351
  if expand
216
- return :tSTRING_DVAR, scanner.matched
352
+ return :tSTRING_DVAR
217
353
  else
218
354
  str_buffer << scanner.matched
219
355
  end
220
356
 
221
357
  elsif scan(/#\{/)
222
358
  if expand
223
- # we are into ruby code, so stop parsing content (for now)
224
- return :tSTRING_DBEG, scanner.matched
359
+ return :tSTRING_DBEG
225
360
  else
226
361
  str_buffer << scanner.matched
227
362
  end
@@ -231,80 +366,25 @@ module Opal
231
366
  str_buffer << '#'
232
367
  end
233
368
 
234
- if str_parse[:type] == :heredoc
235
- add_heredoc_content str_buffer, str_parse
236
- else
237
- add_string_content str_buffer, str_parse
238
- end
369
+ add_string_content str_buffer, str_parse
239
370
 
240
371
  complete_str = str_buffer.join ''
241
372
  @line += complete_str.count("\n")
242
- return :tSTRING_CONTENT, complete_str
243
- end
244
-
245
- def add_heredoc_content(str_buffer, str_parse)
246
- scanner = @scanner
247
-
248
- eos_regx = /[ \t]*#{Regexp.escape(str_parse[:end])}(\r*\n|$)/
249
- expand = true
250
-
251
- until scanner.eos?
252
- c = nil
253
- handled = true
254
373
 
255
- if scan(/\n/)
256
- c = scanner.matched
257
- elsif check(eos_regx) && scanner.bol?
258
- break # eos!
259
- elsif expand && check(/#(?=[\$\@\{])/)
260
- break
261
- elsif scan(/\\/)
262
- if str_parse[:type] == :regexp
263
- if scan(/(.)/)
264
- c = "\\" + scanner.matched
265
- end
266
- else
267
- c = if scan(/n/)
268
- "\n"
269
- elsif scan(/r/)
270
- "\r"
271
- elsif scan(/\n/)
272
- "\n"
273
- elsif scan(/t/)
274
- "\t"
275
- else
276
- # escaped char doesnt need escaping, so just return it
277
- scan(/./)
278
- scanner.matched
279
- end
280
- end
281
- else
282
- handled = false
283
- end
284
-
285
- unless handled
286
- reg = Regexp.new("[^#{Regexp.escape str_parse[:end]}\#\0\\\\\n]+|.")
287
-
288
- scan reg
289
- c = scanner.matched
290
- end
291
-
292
- c ||= scanner.matched
293
- str_buffer << c
294
- end
295
-
296
- raise "reached EOF while in string" if scanner.eos?
374
+ self.yylval = complete_str
375
+ return :tSTRING_CONTENT
297
376
  end
298
377
 
299
378
  def add_string_content(str_buffer, str_parse)
300
- scanner = @scanner
301
- # regexp for end of string/regexp
302
- # end_str_re = /#{str_parse[:end]}/
303
- end_str_re = Regexp.new(Regexp.escape(str_parse[:end]))
379
+ func = str_parse[:func]
304
380
 
305
- expand = strterm_expand?(str_parse)
381
+ end_str_re = Regexp.new(Regexp.escape(str_parse[:term]))
306
382
 
307
- words = ['W', 'w'].include? str_parse[:beg]
383
+ qwords = (func & STR_FUNC_QWORDS) != 0
384
+ expand = (func & STR_FUNC_EXPAND) != 0
385
+ regexp = (func & STR_FUNC_REGEXP) != 0
386
+ escape = (func & STR_FUNC_ESCAPE) != 0
387
+ xquote = (func == STR_XQUOTE)
308
388
 
309
389
  until scanner.eos?
310
390
  c = nil
@@ -323,51 +403,60 @@ module Opal
323
403
  break
324
404
  end
325
405
 
326
- elsif str_parse[:balance] and scan Regexp.new(Regexp.escape(str_parse[:beg]))
406
+ elsif str_parse[:balance] and scan Regexp.new(Regexp.escape(str_parse[:paren]))
327
407
  str_parse[:nesting] += 1
328
408
  c = scanner.matched
329
409
 
330
- elsif words && scan(/\s/)
331
- scanner.pos -= 1
410
+ elsif qwords && scan(/\s/)
411
+ pushback(1)
332
412
  break
333
-
334
413
  elsif expand && check(/#(?=[\$\@\{])/)
335
414
  break
336
-
337
- #elsif scan(/\\\\/)
338
- #c = scanner.matched
339
-
415
+ elsif qwords and scan(/\s/)
416
+ pushback(1)
417
+ break
340
418
  elsif scan(/\\/)
341
- if str_parse[:type] == :regexp
419
+ if xquote # opal - treat xstrings as dquotes? forces us to double escape
420
+ c = "\\" + scan(/./)
421
+ elsif qwords and scan(/\n/)
422
+ str_buffer << "\n"
423
+ next
424
+ elsif expand and scan(/\n/)
425
+ next
426
+ elsif qwords and scan(/\s/)
427
+ c = ' '
428
+ elsif regexp
342
429
  if scan(/(.)/)
343
430
  c = "\\" + scanner.matched
344
431
  end
345
- else
346
- c = if scan(/n/)
347
- "\n"
348
- elsif scan(/r/)
349
- "\r"
350
- elsif scan(/\n/)
351
- "\n"
352
- elsif scan(/t/)
353
- "\t"
432
+ elsif expand
433
+ c = self.read_escape
434
+ elsif scan(/\n/)
435
+ # nothing..
436
+ elsif scan(/\\/)
437
+ if escape
438
+ c = "\\\\"
439
+ else
440
+ c = scanner.matched
441
+ end
442
+ else # \\
443
+ unless scan(end_str_re)
444
+ str_buffer << "\\"
354
445
  else
355
- # escaped char doesnt need escaping, so just return it
356
- scan(/./)
357
- scanner.matched
358
- end
446
+ #c = scanner.matched
447
+ end
359
448
  end
360
449
  else
361
450
  handled = false
362
451
  end
363
452
 
364
453
  unless handled
365
- reg = if words
366
- Regexp.new("[^#{Regexp.escape str_parse[:end]}\#\0\n\ \\\\]+|.")
454
+ reg = if qwords
455
+ Regexp.new("[^#{Regexp.escape str_parse[:term]}\#\0\n\ \\\\]+|.")
367
456
  elsif str_parse[:balance]
368
- Regexp.new("[^#{Regexp.escape str_parse[:end]}#{Regexp.escape str_parse[:beg]}\#\0\\\\]+|.")
457
+ Regexp.new("[^#{Regexp.escape str_parse[:term]}#{Regexp.escape str_parse[:paren]}\#\0\\\\]+|.")
369
458
  else
370
- Regexp.new("[^#{Regexp.escape str_parse[:end]}\#\0\\\\]+|.")
459
+ Regexp.new("[^#{Regexp.escape str_parse[:term]}\#\0\\\\]+|.")
371
460
  end
372
461
 
373
462
  scan reg
@@ -382,36 +471,39 @@ module Opal
382
471
  end
383
472
 
384
473
  def heredoc_identifier
385
- if @scanner.scan(/(-?)['"]?(\w+)['"]?/)
474
+ if scan(/(-?)['"]?(\w+)['"]?/)
386
475
  heredoc = @scanner[2]
387
- self.strterm = new_strterm(:heredoc, heredoc, heredoc)
476
+ self.strterm = new_strterm(STR_DQUOTE, heredoc, heredoc)
477
+ self.strterm[:type] = :heredoc
388
478
 
389
479
  # if ruby code at end of line after heredoc, we have to store it to
390
480
  # parse after heredoc is finished parsing
391
- end_of_line = @scanner.scan(/.*\n/)
481
+ end_of_line = scan(/.*\n/)
392
482
  self.strterm[:scanner] = StringScanner.new(end_of_line) if end_of_line != "\n"
393
483
 
394
- return :tSTRING_BEG, heredoc
484
+ self.line += 1
485
+ self.yylval = heredoc
486
+ return :tSTRING_BEG
395
487
  end
396
488
  end
397
489
 
398
490
  def process_identifier(matched, cmd_start)
399
- scanner = @scanner
400
- matched = scanner.matched
491
+ last_state = @lex_state
401
492
 
402
- if scanner.peek(2) != '::' && scan(/:/)
493
+ if !check(/::/) and scan(/:/)
403
494
  @lex_state = :expr_beg
404
- return :tLABEL, "#{matched}"
495
+ self.yylval = matched
496
+ return :tLABEL
405
497
  end
406
498
 
407
499
  if matched == 'defined?'
408
500
  if after_operator?
409
501
  @lex_state = :expr_end
410
- return :tIDENTIFIER, matched
502
+ return :tIDENTIFIER
411
503
  end
412
504
 
413
505
  @lex_state = :expr_arg
414
- return :kDEFINED, 'defined?'
506
+ return :kDEFINED
415
507
  end
416
508
 
417
509
  if matched.end_with? '?', '!'
@@ -435,7 +527,8 @@ module Opal
435
527
  @lex_state = kw.state
436
528
 
437
529
  if old_state == :expr_fname
438
- return [kw.id[0], kw.name]
530
+ self.yylval = kw.name
531
+ return kw.id[0]
439
532
  end
440
533
 
441
534
  if @lex_state == :expr_beg
@@ -445,34 +538,36 @@ module Opal
445
538
  if matched == "do"
446
539
  if after_operator?
447
540
  @lex_state = :expr_end
448
- return :tIDENTIFIER, matched
541
+ return :tIDENTIFIER
449
542
  end
450
543
 
451
544
  if @start_of_lambda
452
545
  @start_of_lambda = false
453
546
  @lex_state = :expr_beg
454
- return [:kDO_LAMBDA, scanner.matched]
547
+ return :kDO_LAMBDA
455
548
  elsif cond?
456
549
  @lex_state = :expr_beg
457
- return :kDO_COND, matched
550
+ return :kDO_COND
458
551
  elsif cmdarg? && @lex_state != :expr_cmdarg
459
552
  @lex_state = :expr_beg
460
- return :kDO_BLOCK, matched
553
+ return :kDO_BLOCK
461
554
  elsif @lex_state == :expr_endarg
462
- return :kDO_BLOCK, matched
555
+ return :kDO_BLOCK
463
556
  else
464
557
  @lex_state = :expr_beg
465
- return :kDO, matched
558
+ return :kDO
466
559
  end
467
560
  else
468
561
  if old_state == :expr_beg or old_state == :expr_value
469
- return [kw.id[0], matched]
562
+ self.yylval = matched
563
+ return kw.id[0]
470
564
  else
471
565
  if kw.id[0] != kw.id[1]
472
566
  @lex_state = :expr_beg
473
567
  end
474
568
 
475
- return [kw.id[1], matched]
569
+ self.yylval = matched
570
+ return kw.id[1]
476
571
  end
477
572
  end
478
573
  end
@@ -483,123 +578,116 @@ module Opal
483
578
  @lex_state = :expr_end
484
579
  end
485
580
 
486
- return [matched =~ /^[A-Z]/ ? :tCONSTANT : :tIDENTIFIER, matched]
581
+ if ![:expr_dot, :expr_fname].include?(last_state) and has_local?(matched)
582
+ @lex_state = :expr_end
583
+ end
584
+
585
+ return matched =~ /^[A-Z]/ ? :tCONSTANT : :tIDENTIFIER
487
586
  end
488
587
 
489
588
  def yylex
589
+ @yylval = ''
490
590
  @space_seen = false
491
591
  cmd_start = false
492
592
  c = ''
493
593
 
494
594
  if self.strterm
495
- return next_string_token
595
+ if self.strterm[:type] == :heredoc
596
+ token = here_document(self.strterm)
597
+ else
598
+ token = parse_string
599
+ end
600
+
601
+ if token == :tSTRING_END or token == :tREGEXP_END
602
+ self.strterm = nil
603
+ @lex_state = :expr_end
604
+ end
605
+
606
+ return token
496
607
  end
497
608
 
498
609
  while true
499
- if scan(/\ |\t|\r/)
610
+ if skip(/\ |\t|\r/)
500
611
  @space_seen = true
501
612
  next
502
613
 
503
- elsif scan(/(\n|#)/)
614
+ elsif skip(/(\n|#)/)
504
615
  c = scanner.matched
505
- if c == '#' then scan(/(.*)/) else @line += 1; end
616
+ if c == '#'
617
+ skip(/(.*)/)
618
+ else
619
+ self.line += 1
620
+ end
621
+
622
+ skip(/(\n+)/)
506
623
 
507
- scan(/(\n+)/)
508
- @line += scanner.matched.length if scanner.matched
624
+ if scanner.matched
625
+ self.line += scanner.matched.length
626
+ end
509
627
 
510
628
  next if [:expr_beg, :expr_dot].include? @lex_state
511
629
 
512
- if scan(/([\ \t\r\f\v]*)\./)
630
+ if skip(/([\ \t\r\f\v]*)\./)
513
631
  @space_seen = true unless scanner[1].empty?
514
- scanner.pos = scanner.pos - 1
632
+ pushback(1)
515
633
 
516
634
  next unless check(/\.\./)
517
635
  end
518
636
 
519
637
  cmd_start = true
520
638
  @lex_state = :expr_beg
521
- return :tNL, '\\n'
639
+ self.yylval = '\\n'
640
+ return :tNL
522
641
 
523
642
  elsif scan(/\;/)
524
643
  @lex_state = :expr_beg
525
- return :tSEMI, ';'
644
+ return :tSEMI
526
645
 
527
- elsif scan(/\*/)
528
- if scan(/\*/)
529
- if scan(/\=/)
530
- @lex_state = :expr_beg
531
- return :tOP_ASGN, '**'
532
- end
533
-
534
- if @lex_state == :expr_fname or @lex_state == :expr_dot
535
- @lex_state = :expr_arg
536
- else
537
- @lex_state = :expr_beg
538
- end
539
-
540
- return :tPOW, '**'
541
-
542
- else
543
- if scan(/\=/)
544
- @lex_state = :expr_beg
545
- return :tOP_ASGN, '*'
546
- end
547
- end
548
-
549
- if scan(/\*\=/)
646
+ elsif check(/\*/)
647
+ if scan(/\*\*\=/)
550
648
  @lex_state = :expr_beg
551
- return :tOP_ASGN, '**'
552
- end
553
-
554
- if scan(/\*/)
555
- if after_operator?
556
- @lex_state = :expr_arg
557
- else
558
- @lex_state = :expr_beg
559
- end
560
-
561
- return :tPOW, '**'
562
- end
563
-
564
- if scan(/\=/)
649
+ return new_op_asgn('**')
650
+ elsif scan(/\*\*/)
651
+ self.set_arg_state
652
+ return :tPOW
653
+ elsif scan(/\*\=/)
565
654
  @lex_state = :expr_beg
566
- return :tOP_ASGN, '*'
655
+ return new_op_asgn('*')
567
656
  else
568
- result = '*'
569
- if @lex_state == :expr_fname or @lex_state == :expr_dot
657
+ scan(/\*/)
658
+
659
+ if after_operator?
570
660
  @lex_state = :expr_arg
571
- return :tSTAR2, result
661
+ return :tSTAR2
572
662
  elsif @space_seen && check(/\S/)
573
663
  @lex_state = :expr_beg
574
- return :tSTAR, result
664
+ return :tSTAR
575
665
  elsif [:expr_beg, :expr_mid].include? @lex_state
576
666
  @lex_state = :expr_beg
577
- return :tSTAR, result
667
+ return :tSTAR
578
668
  else
579
669
  @lex_state = :expr_beg
580
- return :tSTAR2, result
670
+ return :tSTAR2
581
671
  end
582
672
  end
583
673
 
584
674
  elsif scan(/\!/)
585
- c = scan(/./)
586
675
  if after_operator?
587
676
  @lex_state = :expr_arg
588
- if c == "@"
677
+ if scan(/@/)
589
678
  return :tBANG, '!'
590
679
  end
591
680
  else
592
681
  @lex_state = :expr_beg
593
682
  end
594
683
 
595
- if c == '='
596
- return :tNEQ, '!='
597
- elsif c == '~'
598
- return :tNMATCH, '!~'
684
+ if scan(/\=/)
685
+ return :tNEQ
686
+ elsif scan(/\~/)
687
+ return :tNMATCH
599
688
  end
600
689
 
601
- scanner.pos = scanner.pos - 1
602
- return :tBANG, '!'
690
+ return :tBANG
603
691
 
604
692
  elsif scan(/\=/)
605
693
  if @lex_state == :expr_beg and !@space_seen
@@ -614,7 +702,7 @@ module Opal
614
702
 
615
703
  if scan(/\=end/) and space?
616
704
  @line += line_count
617
- return next_token
705
+ return yylex
618
706
  end
619
707
 
620
708
  if scan(/\n/)
@@ -627,53 +715,49 @@ module Opal
627
715
  end
628
716
  end
629
717
 
630
- @lex_state = if after_operator?
631
- :expr_arg
632
- else
633
- :expr_beg
634
- end
718
+ self.set_arg_state
635
719
 
636
720
  if scan(/\=/)
637
721
  if scan(/\=/)
638
- return :tEQQ, '==='
722
+ return :tEQQ
639
723
  end
640
724
 
641
- return :tEQ, '=='
725
+ return :tEQ
642
726
  end
643
727
 
644
728
  if scan(/\~/)
645
- return :tMATCH, '=~'
729
+ return :tMATCH
646
730
  elsif scan(/\>/)
647
- return :tASSOC, '=>'
731
+ return :tASSOC
648
732
  end
649
733
 
650
- return :tEQL, '='
734
+ return :tEQL
651
735
 
652
736
  elsif scan(/\"/)
653
- self.strterm = new_strterm(:dquote, '"', '"')
654
- return :tSTRING_BEG, scanner.matched
737
+ self.strterm = new_strterm(STR_DQUOTE, '"', "\0")
738
+ return :tSTRING_BEG
655
739
 
656
740
  elsif scan(/\'/)
657
- self.strterm = new_strterm(:squote, "'", "'")
658
- return :tSTRING_BEG, scanner.matched
741
+ self.strterm = new_strterm(STR_SQUOTE, "'", "\0")
742
+ return :tSTRING_BEG
659
743
 
660
744
  elsif scan(/\`/)
661
- self.strterm = new_strterm(:xquote, '`', '`')
662
- return :tXSTRING_BEG, scanner.matched
745
+ self.strterm = new_strterm(STR_XQUOTE, "`", "\0")
746
+ return :tXSTRING_BEG
663
747
 
664
748
  elsif scan(/\&/)
665
749
  if scan(/\&/)
666
750
  @lex_state = :expr_beg
667
751
 
668
752
  if scan(/\=/)
669
- return :tOP_ASGN, '&&'
753
+ return new_op_asgn('&&')
670
754
  end
671
755
 
672
- return :tANDOP, '&&'
756
+ return :tANDOP
673
757
 
674
758
  elsif scan(/\=/)
675
759
  @lex_state = :expr_beg
676
- return :tOP_ASGN, '&'
760
+ return new_op_asgn('&')
677
761
  end
678
762
 
679
763
  if spcarg?
@@ -686,95 +770,93 @@ module Opal
686
770
  result = :tAMPER2
687
771
  end
688
772
 
689
- @lex_state = after_operator? ? :expr_arg : :expr_beg
690
- return result, '&'
773
+ self.set_arg_state
774
+ return result
691
775
 
692
776
  elsif scan(/\|/)
693
777
  if scan(/\|/)
694
778
  @lex_state = :expr_beg
695
779
  if scan(/\=/)
696
- return :tOP_ASGN, '||'
780
+ return new_op_asgn('||')
697
781
  end
698
782
 
699
- return :tOROP, '||'
783
+ return :tOROP
700
784
 
701
785
  elsif scan(/\=/)
702
- return :tOP_ASGN, '|'
786
+ return new_op_asgn('|')
703
787
  end
704
788
 
705
- @lex_state = after_operator?() ? :expr_arg : :expr_beg
706
- return :tPIPE, '|'
789
+ self.set_arg_state
790
+ return :tPIPE
707
791
 
708
792
  elsif scan(/\%[QqWwixr]/)
709
793
  str_type = scanner.matched[1, 1]
710
- paren = scan(/./)
711
-
712
- term = case paren
713
- when '(' then ')'
714
- when '[' then ']'
715
- when '{' then '}'
716
- else paren
717
- end
718
-
719
- case str_type
720
- when 'Q'
721
- self.strterm = new_strterm2(:dquote, paren, term)
722
- return :tSTRING_BEG, scanner.matched
723
- when 'q'
724
- self.strterm = new_strterm2(:squote, paren, term)
725
- return :tSTRING_BEG, scanner.matched
726
- when 'W'
727
- self.strterm = new_strterm(:dword, 'W', term)
728
- scan(/\s*/)
729
- return :tWORDS_BEG, scanner.matched
730
- when 'w', 'i'
731
- self.strterm = new_strterm(:sword, 'w', term)
732
- scan(/\s*/)
733
- return :tAWORDS_BEG, scanner.matched
734
- when 'x'
735
- self.strterm = new_strterm2(:xquote, paren, term)
736
- return :tXSTRING_BEG, scanner.matched
737
- when 'r'
738
- self.strterm = new_strterm2(:regexp, paren, term)
739
- return :tREGEXP_BEG, scanner.matched
794
+ paren = term = scan(/./)
795
+
796
+ case term
797
+ when '(' then term = ')'
798
+ when '[' then term = ']'
799
+ when '{' then term = '}'
800
+ when '<' then term = '>'
801
+ else paren = "\0"
740
802
  end
741
803
 
804
+ token, func = case str_type
805
+ when 'Q'
806
+ [:tSTRING_BEG, STR_DQUOTE]
807
+ when 'q'
808
+ [:tSTRING_BEG, STR_SQUOTE]
809
+ when 'W'
810
+ skip(/\s*/)
811
+ [:tWORDS_BEG, STR_DWORD]
812
+ when 'w', 'i'
813
+ skip(/\s*/)
814
+ [:tAWORDS_BEG, STR_SWORD]
815
+ when 'x'
816
+ [:tXSTRING_BEG, STR_XQUOTE]
817
+ when 'r'
818
+ [:tREGEXP_BEG, STR_REGEXP]
819
+ end
820
+
821
+ self.strterm = new_strterm2(func, term, paren)
822
+ return token
823
+
742
824
  elsif scan(/\//)
743
- if [:expr_beg, :expr_mid].include? @lex_state
744
- self.strterm = new_strterm(:regexp, '/', '/')
745
- return :tREGEXP_BEG, scanner.matched
825
+ if beg?
826
+ self.strterm = new_strterm(STR_REGEXP, '/', '/')
827
+ return :tREGEXP_BEG
746
828
  elsif scan(/\=/)
747
829
  @lex_state = :expr_beg
748
- return :tOP_ASGN, '/'
749
- elsif @lex_state == :expr_fname or @lex_state == :expr_dot
830
+ return new_op_asgn('/')
831
+ elsif after_operator?
750
832
  @lex_state = :expr_arg
751
- elsif @lex_state == :expr_cmdarg || @lex_state == :expr_arg
833
+ elsif arg?
752
834
  if !check(/\s/) && @space_seen
753
- self.strterm = new_strterm(:regexp, '/', '/')
754
- return :tREGEXP_BEG, scanner.matched
835
+ self.strterm = new_strterm(STR_REGEXP, '/', '/')
836
+ return :tREGEXP_BEG
755
837
  end
756
838
  else
757
839
  @lex_state = :expr_beg
758
840
  end
759
841
 
760
- return :tDIVIDE, '/'
842
+ return :tDIVIDE
761
843
 
762
844
  elsif scan(/\%/)
763
845
  if scan(/\=/)
764
846
  @lex_state = :expr_beg
765
- return :tOP_ASGN, '%'
847
+ return new_op_asgn('%')
766
848
  elsif check(/[^\s]/)
767
849
  if @lex_state == :expr_beg or (@lex_state == :expr_arg && @space_seen)
768
850
  start_word = scan(/./)
769
851
  end_word = { '(' => ')', '[' => ']', '{' => '}' }[start_word] || start_word
770
- self.strterm = new_strterm2(:dquote, start_word, end_word)
771
- return :tSTRING_BEG, scanner.matched
852
+ self.strterm = new_strterm2(STR_DQUOTE, end_word, start_word)
853
+ return :tSTRING_BEG
772
854
  end
773
855
  end
774
856
 
775
- @lex_state = after_operator? ? :expr_arg : :expr_beg
857
+ self.set_arg_state
776
858
 
777
- return :tPERCENT, '%'
859
+ return :tPERCENT
778
860
 
779
861
  elsif scan(/\\/)
780
862
  if scan(/\r?\n/)
@@ -786,9 +868,9 @@ module Opal
786
868
 
787
869
  elsif scan(/\(/)
788
870
  result = scanner.matched
789
- if [:expr_beg, :expr_mid].include? @lex_state
871
+ if beg?
790
872
  result = :tLPAREN
791
- elsif @space_seen && [:expr_arg, :expr_cmdarg].include?(@lex_state)
873
+ elsif @space_seen && arg?
792
874
  result = :tLPAREN_ARG
793
875
  else
794
876
  result = :tLPAREN2
@@ -798,125 +880,123 @@ module Opal
798
880
  cond_push 0
799
881
  cmdarg_push 0
800
882
 
801
- return result, scanner.matched
883
+ return result
802
884
 
803
885
  elsif scan(/\)/)
804
886
  cond_lexpop
805
887
  cmdarg_lexpop
806
888
  @lex_state = :expr_end
807
- return :tRPAREN, scanner.matched
889
+ return :tRPAREN
808
890
 
809
891
  elsif scan(/\[/)
810
892
  result = scanner.matched
811
893
 
812
- if [:expr_fname, :expr_dot].include? @lex_state
894
+ if after_operator?
813
895
  @lex_state = :expr_arg
814
896
  if scan(/\]=/)
815
- return :tASET, '[]='
897
+ return :tASET
816
898
  elsif scan(/\]/)
817
- return :tAREF, '[]'
899
+ return :tAREF
818
900
  else
819
901
  raise "Unexpected '[' token"
820
902
  end
821
- elsif [:expr_beg, :expr_mid].include?(@lex_state) || @space_seen
822
- @lex_state = :expr_beg
823
- cond_push 0
824
- cmdarg_push 0
825
- return :tLBRACK, scanner.matched
903
+ elsif beg?
904
+ result = :tLBRACK
905
+ elsif arg? && @space_seen
906
+ result = :tLBRACK
826
907
  else
827
- @lex_state = :expr_beg
828
- cond_push 0
829
- cmdarg_push 0
830
- return :tLBRACK2, scanner.matched
908
+ result = :tLBRACK2
831
909
  end
832
910
 
911
+ @lex_state = :expr_beg
912
+ cond_push 0
913
+ cmdarg_push 0
914
+ return result
915
+
833
916
  elsif scan(/\]/)
834
917
  cond_lexpop
835
918
  cmdarg_lexpop
836
919
  @lex_state = :expr_end
837
- return :tRBRACK, scanner.matched
920
+ return :tRBRACK
838
921
 
839
922
  elsif scan(/\}/)
840
923
  cond_lexpop
841
924
  cmdarg_lexpop
842
925
  @lex_state = :expr_end
843
926
 
844
- return :tRCURLY, scanner.matched
927
+ return :tRCURLY
845
928
 
846
929
  elsif scan(/\.\.\./)
847
930
  @lex_state = :expr_beg
848
- return :tDOT3, scanner.matched
931
+ return :tDOT3
849
932
 
850
933
  elsif scan(/\.\./)
851
934
  @lex_state = :expr_beg
852
- return :tDOT2, scanner.matched
935
+ return :tDOT2
853
936
 
854
937
  elsif scan(/\./)
855
938
  @lex_state = :expr_dot unless @lex_state == :expr_fname
856
- return :tDOT, scanner.matched
939
+ return :tDOT
857
940
 
858
941
  elsif scan(/\:\:/)
859
- if [:expr_beg, :expr_mid, :expr_class].include? @lex_state
942
+ if beg?
860
943
  @lex_state = :expr_beg
861
- return :tCOLON3, scanner.matched
862
- elsif @space_seen && @lex_state == :expr_arg
944
+ return :tCOLON3
945
+ elsif spcarg?
863
946
  @lex_state = :expr_beg
864
- return :tCOLON3, scanner.matched
947
+ return :tCOLON3
865
948
  end
866
949
 
867
950
  @lex_state = :expr_dot
868
- return :tCOLON2, scanner.matched
951
+ return :tCOLON2
869
952
 
870
953
  elsif scan(/\:/)
871
954
  if end? || check(/\s/)
872
955
  unless check(/\w/)
873
956
  @lex_state = :expr_beg
874
- return :tCOLON, ':'
957
+ return :tCOLON
875
958
  end
876
959
 
877
960
  @lex_state = :expr_fname
878
- return :tSYMBEG, ':'
961
+ return :tSYMBEG
879
962
  end
880
963
 
881
964
  if scan(/\'/)
882
- self.strterm = new_strterm(:ssym, "'", "'")
965
+ self.strterm = new_strterm(STR_SSYM, "'", "\0")
883
966
  elsif scan(/\"/)
884
- self.strterm = new_strterm(:dsym, '"', '"')
967
+ self.strterm = new_strterm(STR_DSYM, '"', "\0")
885
968
  end
886
969
 
887
970
  @lex_state = :expr_fname
888
- return :tSYMBEG, ':'
971
+ return :tSYMBEG
889
972
 
890
973
  elsif scan(/\^\=/)
891
974
  @lex_state = :expr_beg
892
- return :tOP_ASGN, '^'
893
- elsif scan(/\^/)
894
- if @lex_state == :expr_fname or @lex_state == :expr_dot
895
- @lex_state = :expr_arg
896
- return :tCARET, scanner.matched
897
- end
975
+ return new_op_asgn('^')
898
976
 
899
- @lex_state = :expr_beg
900
- return :tCARET, scanner.matched
977
+ elsif scan(/\^/)
978
+ self.set_arg_state
979
+ return :tCARET
901
980
 
902
981
  elsif check(/\</)
903
982
  if scan(/\<\<\=/)
904
983
  @lex_state = :expr_beg
905
- return :tOP_ASGN, '<<'
984
+ return new_op_asgn('<<')
985
+
906
986
  elsif scan(/\<\</)
907
- if @lex_state == :expr_fname or @lex_state == :expr_dot
987
+ if after_operator?
908
988
  @lex_state = :expr_arg
909
- return :tLSHFT, '<<'
910
- elsif ![:expr_dot, :expr_class].include?(@lex_state) && !end? && (!arg? || @space_seen)
989
+ return :tLSHFT
990
+ elsif !after_operator? && !end? && (!arg? || @space_seen)
911
991
  if token = heredoc_identifier
912
992
  return token
913
993
  end
914
994
 
915
995
  @lex_state = :expr_beg
916
- return :tLSHFT, '<<'
996
+ return :tLSHFT
917
997
  end
918
998
  @lex_state = :expr_beg
919
- return :tLSHFT, '<<'
999
+ return :tLSHFT
920
1000
  elsif scan(/\<\=\>/)
921
1001
  if after_operator?
922
1002
  @lex_state = :expr_arg
@@ -928,54 +1008,38 @@ module Opal
928
1008
  @lex_state = :expr_beg
929
1009
  end
930
1010
 
931
- return :tCMP, '<=>'
1011
+ return :tCMP
932
1012
  elsif scan(/\<\=/)
933
- if @lex_state == :expr_fname or @lex_state == :expr_dot
934
- @lex_state = :expr_arg
935
- else
936
- @lex_state = :expr_beg
937
- end
938
- return :tLEQ, '<='
1013
+ self.set_arg_state
1014
+ return :tLEQ
1015
+
939
1016
  elsif scan(/\</)
940
- if @lex_state == :expr_fname or @lex_state == :expr_dot
941
- @lex_state = :expr_arg
942
- else
943
- @lex_state = :expr_beg
944
- end
945
- return :tLT, '<'
1017
+ self.set_arg_state
1018
+ return :tLT
946
1019
  end
947
1020
 
948
1021
  elsif check(/\>/)
949
1022
  if scan(/\>\>\=/)
950
- return :tOP_ASGN, '>>'
1023
+ return new_op_asgn('>>')
1024
+
951
1025
  elsif scan(/\>\>/)
952
- if @lex_state == :expr_fname or @lex_state == :expr_dot
953
- @lex_state = :expr_arg
954
- else
955
- @lex_state = :expr_beg
956
- end
957
- return :tRSHFT, '>>'
1026
+ self.set_arg_state
1027
+ return :tRSHFT
1028
+
958
1029
  elsif scan(/\>\=/)
959
- if @lex_state == :expr_fname or @lex_state == :expr_dot
960
- @lex_state = :expr_end
961
- else
962
- @lex_state = :expr_beg
963
- end
964
- return :tGEQ, scanner.matched
1030
+ self.set_arg_state
1031
+ return :tGEQ
1032
+
965
1033
  elsif scan(/\>/)
966
- if @lex_state == :expr_fname or @lex_state == :expr_dot
967
- @lex_state = :expr_arg
968
- else
969
- @lex_state = :expr_beg
970
- end
971
- return :tGT, '>'
1034
+ self.set_arg_state
1035
+ return :tGT
972
1036
  end
973
1037
 
974
1038
  elsif scan(/->/)
975
1039
  # FIXME: # should be :expr_arg, but '(' breaks it...
976
1040
  @lex_state = :expr_end
977
1041
  @start_of_lambda = true
978
- return [:tLAMBDA, scanner.matched]
1042
+ return :tLAMBDA
979
1043
 
980
1044
  elsif scan(/[+-]/)
981
1045
  matched = scanner.matched
@@ -987,103 +1051,122 @@ module Opal
987
1051
 
988
1052
  if beg?
989
1053
  @lex_state = :expr_mid
990
- return [utype, matched]
1054
+ self.yylval = matched
1055
+ return utype
991
1056
  elsif after_operator?
992
1057
  @lex_state = :expr_arg
993
- return [:tIDENTIFIER, matched + '@'] if scan(/@/)
994
- return [sign, matched]
1058
+ if scan(/@/)
1059
+ self.yylval = matched + '@'
1060
+ return :tIDENTIFIER
1061
+ end
1062
+
1063
+ self.yylval = matched
1064
+ return sign
995
1065
  end
996
1066
 
997
1067
  if scan(/\=/)
998
1068
  @lex_state = :expr_beg
999
- return [:tOP_ASGN, matched]
1069
+ return new_op_asgn(matched)
1000
1070
  end
1001
1071
 
1002
- if arg?
1003
- if !space? && @space_seen
1004
- @lex_state = :expr_mid
1005
- return [utype, matched]
1006
- end
1072
+ if spcarg?
1073
+ @lex_state = :expr_mid
1074
+ self.yylval = matched
1075
+ return utype
1007
1076
  end
1008
1077
 
1009
1078
  @lex_state = :expr_beg
1010
- return [sign, sign]
1079
+ self.yylval = matched
1080
+ return sign
1011
1081
 
1012
1082
  elsif scan(/\?/)
1013
1083
  if end?
1014
1084
  @lex_state = :expr_beg
1015
- return :tEH, scanner.matched
1085
+ return :tEH
1016
1086
  end
1017
1087
 
1018
- unless check(/\ |\t|\r|\s/)
1088
+ if check(/\ |\t|\r|\s/)
1089
+ @lex_state = :expr_beg
1090
+ return :tEH
1091
+ elsif scan(/\\/)
1019
1092
  @lex_state = :expr_end
1020
- return :tSTRING, scan(/./)
1093
+ self.yylval = self.read_escape
1094
+ return :tSTRING
1021
1095
  end
1022
1096
 
1023
- @lex_state = :expr_beg
1024
- return :tEH, scanner.matched
1097
+ @lex_state = :expr_end
1098
+ self.yylval = scan(/./)
1099
+ return :tSTRING
1025
1100
 
1026
1101
  elsif scan(/\~/)
1027
- if @lex_state == :expr_fname
1028
- @lex_state = :expr_end
1029
- return :tTILDE, '~'
1030
- end
1031
- @lex_state = :expr_beg
1032
- return :tTILDE, '~'
1102
+ self.set_arg_state
1103
+ return :tTILDE
1033
1104
 
1034
1105
  elsif check(/\$/)
1035
1106
  if scan(/\$([1-9]\d*)/)
1036
1107
  @lex_state = :expr_end
1037
- return :tNTH_REF, scanner.matched.sub('$', '')
1108
+ self.yylval = scanner.matched.sub('$', '')
1109
+ return :tNTH_REF
1038
1110
 
1039
1111
  elsif scan(/(\$_)(\w+)/)
1040
1112
  @lex_state = :expr_end
1041
- return :tGVAR, scanner.matched
1113
+ return :tGVAR
1042
1114
 
1043
1115
  elsif scan(/\$[\+\'\`\&!@\"~*$?\/\\:;=.,<>_]/)
1044
1116
  @lex_state = :expr_end
1045
- return :tGVAR, scanner.matched
1117
+ return :tGVAR
1046
1118
  elsif scan(/\$\w+/)
1047
1119
  @lex_state = :expr_end
1048
- return :tGVAR, scanner.matched
1120
+ return :tGVAR
1049
1121
  else
1050
1122
  raise "Bad gvar name: #{scanner.peek(5).inspect}"
1051
1123
  end
1052
1124
 
1053
1125
  elsif scan(/\$\w+/)
1054
1126
  @lex_state = :expr_end
1055
- return :tGVAR, scanner.matched
1127
+ return :tGVAR
1056
1128
 
1057
1129
  elsif scan(/\@\@\w*/)
1058
1130
  @lex_state = :expr_end
1059
- return :tCVAR, scanner.matched
1131
+ return :tCVAR
1060
1132
 
1061
1133
  elsif scan(/\@\w*/)
1062
1134
  @lex_state = :expr_end
1063
- return :tIVAR, scanner.matched
1135
+ return :tIVAR
1064
1136
 
1065
1137
  elsif scan(/\,/)
1066
1138
  @lex_state = :expr_beg
1067
- return :tCOMMA, scanner.matched
1139
+ return :tCOMMA
1068
1140
 
1069
1141
  elsif scan(/\{/)
1070
1142
  if @start_of_lambda
1071
1143
  @start_of_lambda = false
1072
1144
  @lex_state = :expr_beg
1073
- return [:tLAMBEG, scanner.matched]
1145
+ return :tLAMBEG
1074
1146
 
1075
- elsif [:expr_end, :expr_arg, :expr_cmdarg].include? @lex_state
1147
+ elsif arg? or @lex_state == :expr_end
1076
1148
  result = :tLCURLY
1077
1149
  elsif @lex_state == :expr_endarg
1078
1150
  result = :LBRACE_ARG
1079
1151
  else
1080
- result = '{'
1152
+ result = :tLBRACE
1081
1153
  end
1082
1154
 
1083
1155
  @lex_state = :expr_beg
1084
1156
  cond_push 0
1085
1157
  cmdarg_push 0
1086
- return result, scanner.matched
1158
+ return result
1159
+
1160
+ elsif scanner.bol? and skip(/\__END__(\n|$)/)
1161
+ while true
1162
+ if scanner.eos?
1163
+ @eof_content = self.yylval
1164
+ return false
1165
+ end
1166
+
1167
+ scan(/(.*)/)
1168
+ scan(/\n/)
1169
+ end
1087
1170
 
1088
1171
  elsif check(/[0-9]/)
1089
1172
  return process_numeric
@@ -1094,11 +1177,12 @@ module Opal
1094
1177
 
1095
1178
  if scanner.eos?
1096
1179
  if @scanner_stack.size == 1 # our main scanner, we cant pop this
1097
- return [false, false]
1180
+ self.yylval = false
1181
+ return false
1098
1182
  else # we were probably parsing a heredoc, so pop that parser and continue
1099
1183
  @scanner_stack.pop
1100
1184
  @scanner = @scanner_stack.last
1101
- return next_token
1185
+ return yylex
1102
1186
  end
1103
1187
  end
1104
1188