handlebars 0.0.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/.gitignore +1 -1
  2. data/.gitmodules +3 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +1 -1
  5. data/README.mdown +44 -0
  6. data/Rakefile +3 -0
  7. data/handlebars.gemspec +19 -13
  8. data/lib/handlebars.rb +4 -3
  9. data/lib/handlebars/context.rb +37 -0
  10. data/lib/handlebars/version.rb +1 -1
  11. data/spec/handlebars_spec.rb +40 -0
  12. data/spike.rb +17 -0
  13. data/vendor/handlebars/.gitignore +6 -0
  14. data/vendor/handlebars/.jshintrc +50 -0
  15. data/vendor/handlebars/.npmignore +11 -0
  16. data/vendor/handlebars/Gemfile +5 -0
  17. data/vendor/handlebars/LICENSE +20 -0
  18. data/vendor/handlebars/README.markdown +315 -0
  19. data/vendor/handlebars/Rakefile +116 -0
  20. data/vendor/handlebars/bench/benchwarmer.js +149 -0
  21. data/vendor/handlebars/bench/handlebars.js +163 -0
  22. data/vendor/handlebars/bin/handlebars +139 -0
  23. data/vendor/handlebars/lib/handlebars.js +14 -0
  24. data/vendor/handlebars/lib/handlebars/base.js +101 -0
  25. data/vendor/handlebars/lib/handlebars/compiler/ast.js +103 -0
  26. data/vendor/handlebars/lib/handlebars/compiler/base.js +27 -0
  27. data/vendor/handlebars/lib/handlebars/compiler/compiler.js +808 -0
  28. data/vendor/handlebars/lib/handlebars/compiler/index.js +7 -0
  29. data/vendor/handlebars/lib/handlebars/compiler/printer.js +137 -0
  30. data/vendor/handlebars/lib/handlebars/compiler/visitor.js +13 -0
  31. data/vendor/handlebars/lib/handlebars/runtime.js +68 -0
  32. data/vendor/handlebars/lib/handlebars/utils.js +68 -0
  33. data/vendor/handlebars/package.json +25 -0
  34. data/vendor/handlebars/spec/acceptance_spec.rb +101 -0
  35. data/vendor/handlebars/spec/parser_spec.rb +264 -0
  36. data/vendor/handlebars/spec/qunit_spec.js +1067 -0
  37. data/vendor/handlebars/spec/spec_helper.rb +157 -0
  38. data/vendor/handlebars/spec/tokenizer_spec.rb +254 -0
  39. data/vendor/handlebars/src/handlebars.l +42 -0
  40. data/vendor/handlebars/src/handlebars.yy +99 -0
  41. metadata +93 -77
  42. data/README.md +0 -39
  43. data/lib/handlebars/generator.rb +0 -4
  44. data/lib/handlebars/parser.rb +0 -240
  45. data/spec/generator_spec.rb +0 -5
  46. data/spec/parser_spec.rb +0 -163
  47. data/spec/spec_helper.rb +0 -17
@@ -0,0 +1,157 @@
1
+ require "v8"
2
+
3
+ # Monkey patches due to bugs in RubyRacer
4
+ class V8::JSError
5
+ def initialize(try, to)
6
+ @to = to
7
+ begin
8
+ super(initialize_unsafe(try))
9
+ rescue Exception => e
10
+ # Original code does not make an Array here
11
+ @boundaries = [Boundary.new(:rbframes => e.backtrace)]
12
+ @value = e
13
+ super("BUG! please report. JSError#initialize failed!: #{e.message}")
14
+ end
15
+ end
16
+
17
+ def parse_js_frames(try)
18
+ raw = @to.rb(try.StackTrace())
19
+ if raw && !raw.empty?
20
+ raw.split("\n")[1..-1].tap do |frames|
21
+ # Original code uses strip!, and the frames are not guaranteed to be strippable
22
+ frames.each {|frame| frame.strip.chomp!(",")}
23
+ end
24
+ else
25
+ []
26
+ end
27
+ end
28
+ end
29
+
30
+ module Handlebars
31
+ module Spec
32
+ def self.js_backtrace(context)
33
+ begin
34
+ context.eval("throw")
35
+ rescue V8::JSError => e
36
+ return e.backtrace(:javascript)
37
+ end
38
+ end
39
+
40
+ def self.remove_exports(string)
41
+ match = string.match(%r{\A(.*?)^// BEGIN\(BROWSER\)\n(.*)\n^// END\(BROWSER\)(.*?)\Z}m)
42
+ prelines = match ? match[1].count("\n") + 1 : 0
43
+ ret = match ? match[2] : string
44
+ ("\n" * prelines) + ret
45
+ end
46
+
47
+ def self.load_helpers(context)
48
+ context["exports"] = nil
49
+
50
+ context["p"] = proc do |val|
51
+ p val if ENV["DEBUG_JS"]
52
+ end
53
+
54
+ context["puts"] = proc do |val|
55
+ puts val if ENV["DEBUG_JS"]
56
+ end
57
+
58
+ context["puts_node"] = proc do |val|
59
+ puts context["Handlebars"]["PrintVisitor"].new.accept(val)
60
+ puts
61
+ end
62
+
63
+ context["puts_caller"] = proc do
64
+ puts "BACKTRACE:"
65
+ puts Handlebars::Spec.js_backtrace(context)
66
+ puts
67
+ end
68
+ end
69
+
70
+ def self.js_load(context, file)
71
+ str = File.read(file)
72
+ context.eval(remove_exports(str), file)
73
+ end
74
+
75
+ CONTEXT = V8::Context.new
76
+ CONTEXT.instance_eval do |context|
77
+ Handlebars::Spec.load_helpers(context);
78
+
79
+ Handlebars::Spec.js_load(context, 'lib/handlebars/base.js');
80
+ Handlebars::Spec.js_load(context, 'lib/handlebars/utils.js');
81
+ Handlebars::Spec.js_load(context, 'lib/handlebars/runtime.js');
82
+
83
+ context["CompilerContext"] = {}
84
+ CompilerContext = context["CompilerContext"]
85
+ CompilerContext["compile"] = proc do |*args|
86
+ template, options = args[0], args[1] || nil
87
+ templateSpec = COMPILE_CONTEXT["Handlebars"]["precompile"].call(template, options);
88
+ context["Handlebars"]["template"].call(context.eval("(#{templateSpec})"));
89
+ end
90
+ CompilerContext["compileWithPartial"] = proc do |*args|
91
+ template, options = args[0], args[1] || nil
92
+ FULL_CONTEXT["Handlebars"]["compile"].call(template, options);
93
+ end
94
+ end
95
+
96
+ COMPILE_CONTEXT = V8::Context.new
97
+ COMPILE_CONTEXT.instance_eval do |context|
98
+ Handlebars::Spec.load_helpers(context);
99
+
100
+ Handlebars::Spec.js_load(context, 'lib/handlebars/base.js');
101
+ Handlebars::Spec.js_load(context, 'lib/handlebars/utils.js');
102
+ Handlebars::Spec.js_load(context, 'lib/handlebars/compiler/parser.js');
103
+ Handlebars::Spec.js_load(context, 'lib/handlebars/compiler/base.js');
104
+ Handlebars::Spec.js_load(context, 'lib/handlebars/compiler/ast.js');
105
+ Handlebars::Spec.js_load(context, 'lib/handlebars/compiler/visitor.js');
106
+ Handlebars::Spec.js_load(context, 'lib/handlebars/compiler/printer.js');
107
+ Handlebars::Spec.js_load(context, 'lib/handlebars/compiler/compiler.js');
108
+
109
+ context["Handlebars"]["logger"]["level"] = ENV["DEBUG_JS"] ? context["Handlebars"]["logger"][ENV["DEBUG_JS"]] : 4
110
+
111
+ context["Handlebars"]["logger"]["log"] = proc do |level, str|
112
+ logger_level = context["Handlebars"]["logger"]["level"].to_i
113
+
114
+ if logger_level <= level
115
+ puts str
116
+ end
117
+ end
118
+ end
119
+
120
+ FULL_CONTEXT = V8::Context.new
121
+ FULL_CONTEXT.instance_eval do |context|
122
+ Handlebars::Spec.load_helpers(context);
123
+
124
+ Handlebars::Spec.js_load(context, 'lib/handlebars/base.js');
125
+ Handlebars::Spec.js_load(context, 'lib/handlebars/utils.js');
126
+ Handlebars::Spec.js_load(context, 'lib/handlebars/compiler/parser.js');
127
+ Handlebars::Spec.js_load(context, 'lib/handlebars/compiler/base.js');
128
+ Handlebars::Spec.js_load(context, 'lib/handlebars/compiler/ast.js');
129
+ Handlebars::Spec.js_load(context, 'lib/handlebars/compiler/visitor.js');
130
+ Handlebars::Spec.js_load(context, 'lib/handlebars/compiler/printer.js');
131
+ Handlebars::Spec.js_load(context, 'lib/handlebars/compiler/compiler.js');
132
+ Handlebars::Spec.js_load(context, 'lib/handlebars/runtime.js');
133
+
134
+ context["Handlebars"]["logger"]["level"] = ENV["DEBUG_JS"] ? context["Handlebars"]["logger"][ENV["DEBUG_JS"]] : 4
135
+
136
+ context["Handlebars"]["logger"]["log"] = proc do |level, str|
137
+ logger_level = context["Handlebars"]["logger"]["level"].to_i
138
+
139
+ if logger_level <= level
140
+ puts str
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
146
+
147
+
148
+ require "test/unit/assertions"
149
+
150
+ RSpec.configure do |config|
151
+ config.include Test::Unit::Assertions
152
+
153
+ # Each is required to allow classes to mark themselves as compiler tests
154
+ config.before(:each) do
155
+ @context = @compiles ? Handlebars::Spec::COMPILE_CONTEXT : Handlebars::Spec::CONTEXT
156
+ end
157
+ end
@@ -0,0 +1,254 @@
1
+ require "spec_helper"
2
+ require "timeout"
3
+
4
+ describe "Tokenizer" do
5
+ let(:parser) { @context["handlebars"] }
6
+ let(:lexer) { @context["handlebars"]["lexer"] }
7
+
8
+ before(:all) do
9
+ @compiles = true
10
+ end
11
+ Token = Struct.new(:name, :text)
12
+
13
+ def tokenize(string)
14
+ lexer.setInput(string)
15
+ out = []
16
+
17
+ while token = lexer.lex
18
+ # p token
19
+ result = parser.terminals_[token] || token
20
+ # p result
21
+ break if !result || result == "EOF" || result == "INVALID"
22
+ out << Token.new(result, lexer.yytext)
23
+ end
24
+
25
+ out
26
+ end
27
+
28
+ RSpec::Matchers.define :match_tokens do |tokens|
29
+ match do |result|
30
+ result.map(&:name).should == tokens
31
+ end
32
+ end
33
+
34
+ RSpec::Matchers.define :be_token do |name, string|
35
+ match do |token|
36
+ token.name.should == name
37
+ token.text.should == string
38
+ end
39
+ end
40
+
41
+ it "tokenizes a simple mustache as 'OPEN ID CLOSE'" do
42
+ result = tokenize("{{foo}}")
43
+ result.should match_tokens(%w(OPEN ID CLOSE))
44
+ result[1].should be_token("ID", "foo")
45
+ end
46
+
47
+ it "supports escaping delimiters" do
48
+ result = tokenize("{{foo}} \\{{bar}} {{baz}}")
49
+ result.should match_tokens(%w(OPEN ID CLOSE CONTENT CONTENT OPEN ID CLOSE))
50
+
51
+ result[4].should be_token("CONTENT", "{{bar}} ")
52
+ end
53
+
54
+ it "supports escaping a triple stash" do
55
+ result = tokenize("{{foo}} \\{{{bar}}} {{baz}}")
56
+ result.should match_tokens(%w(OPEN ID CLOSE CONTENT CONTENT OPEN ID CLOSE))
57
+
58
+ result[4].should be_token("CONTENT", "{{{bar}}} ")
59
+ end
60
+
61
+ it "tokenizes a simple path" do
62
+ result = tokenize("{{foo/bar}}")
63
+ result.should match_tokens(%w(OPEN ID SEP ID CLOSE))
64
+ end
65
+
66
+ it "allows dot notation" do
67
+ result = tokenize("{{foo.bar}}")
68
+ result.should match_tokens(%w(OPEN ID SEP ID CLOSE))
69
+
70
+ tokenize("{{foo.bar.baz}}").should match_tokens(%w(OPEN ID SEP ID SEP ID CLOSE))
71
+ end
72
+
73
+ it "allows path literals with []" do
74
+ result = tokenize("{{foo.[bar]}}")
75
+ result.should match_tokens(%w(OPEN ID SEP ID CLOSE))
76
+ end
77
+
78
+ it "allows multiple path literals on a line with []" do
79
+ result = tokenize("{{foo.[bar]}}{{foo.[baz]}}")
80
+ result.should match_tokens(%w(OPEN ID SEP ID CLOSE OPEN ID SEP ID CLOSE))
81
+ end
82
+
83
+ it "tokenizes {{.}} as OPEN ID CLOSE" do
84
+ result = tokenize("{{.}}")
85
+ result.should match_tokens(%w(OPEN ID CLOSE))
86
+ end
87
+
88
+ it "tokenizes a path as 'OPEN (ID SEP)* ID CLOSE'" do
89
+ result = tokenize("{{../foo/bar}}")
90
+ result.should match_tokens(%w(OPEN ID SEP ID SEP ID CLOSE))
91
+ result[1].should be_token("ID", "..")
92
+ end
93
+
94
+ it "tokenizes a path with .. as a parent path" do
95
+ result = tokenize("{{../foo.bar}}")
96
+ result.should match_tokens(%w(OPEN ID SEP ID SEP ID CLOSE))
97
+ result[1].should be_token("ID", "..")
98
+ end
99
+
100
+ it "tokenizes a path with this/foo as OPEN ID SEP ID CLOSE" do
101
+ result = tokenize("{{this/foo}}")
102
+ result.should match_tokens(%w(OPEN ID SEP ID CLOSE))
103
+ result[1].should be_token("ID", "this")
104
+ result[3].should be_token("ID", "foo")
105
+ end
106
+
107
+ it "tokenizes a simple mustache with spaces as 'OPEN ID CLOSE'" do
108
+ result = tokenize("{{ foo }}")
109
+ result.should match_tokens(%w(OPEN ID CLOSE))
110
+ result[1].should be_token("ID", "foo")
111
+ end
112
+
113
+ it "tokenizes a simple mustache with line breaks as 'OPEN ID ID CLOSE'" do
114
+ result = tokenize("{{ foo \n bar }}")
115
+ result.should match_tokens(%w(OPEN ID ID CLOSE))
116
+ result[1].should be_token("ID", "foo")
117
+ end
118
+
119
+ it "tokenizes raw content as 'CONTENT'" do
120
+ result = tokenize("foo {{ bar }} baz")
121
+ result.should match_tokens(%w(CONTENT OPEN ID CLOSE CONTENT))
122
+ result[0].should be_token("CONTENT", "foo ")
123
+ result[4].should be_token("CONTENT", " baz")
124
+ end
125
+
126
+ it "tokenizes a partial as 'OPEN_PARTIAL ID CLOSE'" do
127
+ result = tokenize("{{> foo}}")
128
+ result.should match_tokens(%w(OPEN_PARTIAL ID CLOSE))
129
+ end
130
+
131
+ it "tokenizes a partial with context as 'OPEN_PARTIAL ID ID CLOSE'" do
132
+ result = tokenize("{{> foo bar }}")
133
+ result.should match_tokens(%w(OPEN_PARTIAL ID ID CLOSE))
134
+ end
135
+
136
+ it "tokenizes a partial without spaces as 'OPEN_PARTIAL ID CLOSE'" do
137
+ result = tokenize("{{>foo}}")
138
+ result.should match_tokens(%w(OPEN_PARTIAL ID CLOSE))
139
+ end
140
+
141
+ it "tokenizes a partial space at the end as 'OPEN_PARTIAL ID CLOSE'" do
142
+ result = tokenize("{{>foo }}")
143
+ result.should match_tokens(%w(OPEN_PARTIAL ID CLOSE))
144
+ end
145
+
146
+ it "tokenizes a comment as 'COMMENT'" do
147
+ result = tokenize("foo {{! this is a comment }} bar {{ baz }}")
148
+ result.should match_tokens(%w(CONTENT COMMENT CONTENT OPEN ID CLOSE))
149
+ result[1].should be_token("COMMENT", " this is a comment ")
150
+ end
151
+
152
+ it "tokenizes open and closing blocks as 'OPEN_BLOCK ID CLOSE ... OPEN_ENDBLOCK ID CLOSE'" do
153
+ result = tokenize("{{#foo}}content{{/foo}}")
154
+ result.should match_tokens(%w(OPEN_BLOCK ID CLOSE CONTENT OPEN_ENDBLOCK ID CLOSE))
155
+ end
156
+
157
+ it "tokenizes inverse sections as 'OPEN_INVERSE CLOSE'" do
158
+ tokenize("{{^}}").should match_tokens(%w(OPEN_INVERSE CLOSE))
159
+ tokenize("{{else}}").should match_tokens(%w(OPEN_INVERSE CLOSE))
160
+ tokenize("{{ else }}").should match_tokens(%w(OPEN_INVERSE CLOSE))
161
+ end
162
+
163
+ it "tokenizes inverse sections with ID as 'OPEN_INVERSE ID CLOSE'" do
164
+ result = tokenize("{{^foo}}")
165
+ result.should match_tokens(%w(OPEN_INVERSE ID CLOSE))
166
+ result[1].should be_token("ID", "foo")
167
+ end
168
+
169
+ it "tokenizes inverse sections with ID and spaces as 'OPEN_INVERSE ID CLOSE'" do
170
+ result = tokenize("{{^ foo }}")
171
+ result.should match_tokens(%w(OPEN_INVERSE ID CLOSE))
172
+ result[1].should be_token("ID", "foo")
173
+ end
174
+
175
+ it "tokenizes mustaches with params as 'OPEN ID ID ID CLOSE'" do
176
+ result = tokenize("{{ foo bar baz }}")
177
+ result.should match_tokens(%w(OPEN ID ID ID CLOSE))
178
+ result[1].should be_token("ID", "foo")
179
+ result[2].should be_token("ID", "bar")
180
+ result[3].should be_token("ID", "baz")
181
+ end
182
+
183
+ it "tokenizes mustaches with String params as 'OPEN ID ID STRING CLOSE'" do
184
+ result = tokenize("{{ foo bar \"baz\" }}")
185
+ result.should match_tokens(%w(OPEN ID ID STRING CLOSE))
186
+ result[3].should be_token("STRING", "baz")
187
+ end
188
+
189
+ it "tokenizes String params with spaces inside as 'STRING'" do
190
+ result = tokenize("{{ foo bar \"baz bat\" }}")
191
+ result.should match_tokens(%w(OPEN ID ID STRING CLOSE))
192
+ result[3].should be_token("STRING", "baz bat")
193
+ end
194
+
195
+ it "tokenizes String params with escapes quotes as 'STRING'" do
196
+ result = tokenize(%|{{ foo "bar\\"baz" }}|)
197
+ result.should match_tokens(%w(OPEN ID STRING CLOSE))
198
+ result[2].should be_token("STRING", %{bar"baz})
199
+ end
200
+
201
+ it "tokenizes numbers" do
202
+ result = tokenize(%|{{ foo 1 }}|)
203
+ result.should match_tokens(%w(OPEN ID INTEGER CLOSE))
204
+ result[2].should be_token("INTEGER", "1")
205
+ end
206
+
207
+ it "tokenizes booleans" do
208
+ result = tokenize(%|{{ foo true }}|)
209
+ result.should match_tokens(%w(OPEN ID BOOLEAN CLOSE))
210
+ result[2].should be_token("BOOLEAN", "true")
211
+
212
+ result = tokenize(%|{{ foo false }}|)
213
+ result.should match_tokens(%w(OPEN ID BOOLEAN CLOSE))
214
+ result[2].should be_token("BOOLEAN", "false")
215
+ end
216
+
217
+ it "tokenizes hash arguments" do
218
+ result = tokenize("{{ foo bar=baz }}")
219
+ result.should match_tokens %w(OPEN ID ID EQUALS ID CLOSE)
220
+
221
+ result = tokenize("{{ foo bar baz=bat }}")
222
+ result.should match_tokens %w(OPEN ID ID ID EQUALS ID CLOSE)
223
+
224
+ result = tokenize("{{ foo bar baz=1 }}")
225
+ result.should match_tokens %w(OPEN ID ID ID EQUALS INTEGER CLOSE)
226
+
227
+ result = tokenize("{{ foo bar baz=true }}")
228
+ result.should match_tokens %w(OPEN ID ID ID EQUALS BOOLEAN CLOSE)
229
+
230
+ result = tokenize("{{ foo bar baz=false }}")
231
+ result.should match_tokens %w(OPEN ID ID ID EQUALS BOOLEAN CLOSE)
232
+
233
+ result = tokenize("{{ foo bar\n baz=bat }}")
234
+ result.should match_tokens %w(OPEN ID ID ID EQUALS ID CLOSE)
235
+
236
+ result = tokenize("{{ foo bar baz=\"bat\" }}")
237
+ result.should match_tokens %w(OPEN ID ID ID EQUALS STRING CLOSE)
238
+
239
+ result = tokenize("{{ foo bar baz=\"bat\" bam=wot }}")
240
+ result.should match_tokens %w(OPEN ID ID ID EQUALS STRING ID EQUALS ID CLOSE)
241
+
242
+ result = tokenize("{{foo omg bar=baz bat=\"bam\"}}")
243
+ result.should match_tokens %w(OPEN ID ID ID EQUALS ID ID EQUALS STRING CLOSE)
244
+ result[2].should be_token("ID", "omg")
245
+ end
246
+
247
+ it "does not time out in a mustache with a single } followed by EOF" do
248
+ Timeout.timeout(1) { tokenize("{{foo}").should match_tokens(%w(OPEN ID)) }
249
+ end
250
+
251
+ it "does not time out in a mustache when invalid ID characters are used" do
252
+ Timeout.timeout(1) { tokenize("{{foo & }}").should match_tokens(%w(OPEN ID)) }
253
+ end
254
+ end
@@ -0,0 +1,42 @@
1
+
2
+ %x mu emu
3
+
4
+ %%
5
+
6
+ [^\x00]*?/("{{") {
7
+ if(yytext.slice(-1) !== "\\") this.begin("mu");
8
+ if(yytext.slice(-1) === "\\") yytext = yytext.substr(0,yyleng-1), this.begin("emu");
9
+ if(yytext) return 'CONTENT';
10
+ }
11
+
12
+ [^\x00]+ { return 'CONTENT'; }
13
+
14
+ <emu>[^\x00]{2,}?/("{{") { this.popState(); return 'CONTENT'; }
15
+
16
+ <mu>"{{>" { return 'OPEN_PARTIAL'; }
17
+ <mu>"{{#" { return 'OPEN_BLOCK'; }
18
+ <mu>"{{/" { return 'OPEN_ENDBLOCK'; }
19
+ <mu>"{{^" { return 'OPEN_INVERSE'; }
20
+ <mu>"{{"\s*"else" { return 'OPEN_INVERSE'; }
21
+ <mu>"{{{" { return 'OPEN_UNESCAPED'; }
22
+ <mu>"{{&" { return 'OPEN_UNESCAPED'; }
23
+ <mu>"{{!"[\s\S]*?"}}" { yytext = yytext.substr(3,yyleng-5); this.popState(); return 'COMMENT'; }
24
+ <mu>"{{" { return 'OPEN'; }
25
+
26
+ <mu>"=" { return 'EQUALS'; }
27
+ <mu>"."/[} ] { return 'ID'; }
28
+ <mu>".." { return 'ID'; }
29
+ <mu>[\/.] { return 'SEP'; }
30
+ <mu>\s+ { /*ignore whitespace*/ }
31
+ <mu>"}}}" { this.popState(); return 'CLOSE'; }
32
+ <mu>"}}" { this.popState(); return 'CLOSE'; }
33
+ <mu>'"'("\\"["]|[^"])*'"' { yytext = yytext.substr(1,yyleng-2).replace(/\\"/g,'"'); return 'STRING'; }
34
+ <mu>"true"/[}\s] { return 'BOOLEAN'; }
35
+ <mu>"false"/[}\s] { return 'BOOLEAN'; }
36
+ <mu>[0-9]+/[}\s] { return 'INTEGER'; }
37
+ <mu>[a-zA-Z0-9_$-]+/[=}\s\/.] { return 'ID'; }
38
+ <mu>'['[^\]]*']' { yytext = yytext.substr(1, yyleng-2); return 'ID'; }
39
+ <mu>. { return 'INVALID'; }
40
+
41
+ <INITIAL,mu><<EOF>> { return 'EOF'; }
42
+