mochiscript 0.4.0.pre10 → 0.4.0.pre12

Sign up to get free protection for your applications and to get access to all the features.
data/lib/mochiscript.rb CHANGED
@@ -1,1054 +1,2 @@
1
- require 'v8'
2
- require 'json'
3
-
4
- module Mochiscript
5
- VERSION = "0.4.0-pre10".sub("-", '.')
6
- class Context
7
- def initialize
8
- @ctx = V8::Context.new
9
- @ctx['_$m_adapter'] = Adapter.new
10
- @ctx.eval(Parser::JAVASCRIPT)
11
- end
12
-
13
- def parse(str)
14
- @ctx.eval_js("$m.parse(#{str.to_json})")
15
- end
16
-
17
- def eval_ms(str)
18
- @ctx.eval_js(parse(str))
19
- end
20
-
21
- protected
22
-
23
- def method_missing(name, *args, &block)
24
- @ctx.send(name, *args, &block)
25
- end
26
- end
27
-
28
- class Adapter
29
- def out(arg)
30
- print arg
31
- end
32
-
33
- def outs(arg)
34
- puts arg
35
- end
36
- end
37
-
38
- class Parser
39
- JAVASCRIPT = <<'FINISH'
40
- var $m = { ROOT: this, ADAPTER: _$m_adapter };
41
- var JS2 = $m;
42
- (function () {
43
-
44
- // CLASS HELPERS
45
- (function (undefined, $m) {
46
-
47
- var OO = function (klass, par) {
48
- this.klass = klass;
49
- this.par = par;
50
-
51
- this.members = {};
52
- this.staticMembers = {};
53
- this.children = [];
54
- this.included = [];
55
-
56
- if (this.par) this.par.OO.children.push(klass);
57
- };
58
-
59
- OO.prototype = {
60
- forbiddenMembers: {
61
- 'prototype': undefined,
62
- 'OO': undefined
63
- },
64
-
65
- include: function(module) {
66
- this.included.push(module);
67
- var members = module.OO.members;
68
- for (var name in members) {
69
- if (members.hasOwnProperty(name)) {
70
- this.addMember(name, members[name]);
71
- }
72
- }
73
-
74
- var staticMembers = module.OO.staticMembers;
75
- for (var name in staticMembers) {
76
- if (staticMembers.hasOwnProperty(name)) {
77
- this.addStaticMember(name, staticMembers[name]);
78
- }
79
- }
80
-
81
- if (typeof staticMembers['included'] == 'function') {
82
- staticMembers['included'](this.klass);
83
- }
84
- },
85
-
86
- createNamespace: function(name) {
87
- var splitted = name.split('.');
88
- var klassName = splitted.pop();
89
- var root = $m.ROOT;
90
-
91
- while (splitted.length > 0) {
92
- var name = splitted.shift();
93
- if (!root[name]) root[name] = $m.Class.extend({});
94
- root = root[name];
95
- }
96
-
97
- return [ root, klassName ];
98
- },
99
-
100
- makeSuper: function(newMethod, oldMethod) {
101
- if (!oldMethod) return newMethod;
102
-
103
- return function() {
104
- this.$super = oldMethod;
105
- return newMethod.apply(this, arguments);
106
- };
107
- },
108
-
109
- addMember: function(name, member) {
110
- if (this.forbiddenMembers.hasOwnProperty(name)) return;
111
-
112
- var proto = this.klass.prototype;
113
- if (typeof proto[name] == 'function' && !(proto[name] instanceof RegExp)) {
114
- member = this.makeSuper(member, proto[name]);
115
- }
116
-
117
- proto[name] = member;
118
- this.members[name] = member;
119
- },
120
-
121
- addStaticMember: function(name, member) {
122
- if (this.forbiddenMembers.hasOwnProperty(name)) return;
123
-
124
- if (typeof this.klass[name] == 'function') {
125
- if (!this.klass.hasOwnProperty(name)) {
126
- member = this.makeSuper(member, this.klass[name]);
127
- }
128
- }
129
-
130
- this.klass[name] = member;
131
- this.staticMembers[name] = member;
132
- }
133
- };
134
-
135
- $m.Class = function() { this.initialize.apply(this, arguments); };
136
- $m.Class.OO = new OO($m.Class);
137
- $m.Class.prototype = {
138
- initialize: function () {},
139
- oo: $m.Class.OO
140
- };
141
-
142
- var namedClasses = {};
143
- $m.getClass = function(name) {
144
- return namedClasses[name];
145
- };
146
-
147
- var noInit = false;
148
- $m.Class.extend = function(name, klassDef) {
149
- var klass = function() { if (!noInit) this.initialize.apply(this, arguments); };
150
- klass.OO = new OO(klass, this);
151
-
152
- if (typeof name != 'string') {
153
- klassDef = name;
154
- } else {
155
- namedClasses[name] = klass;
156
- var namespace = this.OO.createNamespace(name);
157
- namespace[0][namespace[1]] = klass;
158
- }
159
-
160
- // create instance of this as prototype for new this
161
- noInit = true;
162
- var proto = new this();
163
- noInit = false;
164
-
165
- klass.prototype = proto;
166
- var oo = klass.OO;
167
- proto.OO = oo;
168
-
169
- for (var name in this) {
170
- oo.addStaticMember(name, this[name]);
171
- }
172
-
173
- if (typeof klassDef == 'function') {
174
- klassDef(klass, oo);
175
- } else {
176
- for (var name in klassDef) {
177
- oo.addMember(name, klassDef[name]);
178
- }
179
- }
180
-
181
- return klass;
182
- };
183
-
184
- $m.Module = $m.Class;
185
-
186
- var assert = {
187
- 'eq': function(expected, actual) { if (expected != actual) $m.outs("Expected "+expected+", but got "+actual+".") },
188
- 'isFalse': function(val) { if (val) $m.outs("Expected false, but got "+JSON.stringify(val)+".") },
189
- 'isTrue': function(val) { if (!val) $m.outs("Expected true, but got " +val+".") }
190
- };
191
-
192
- $m.test = function(message, callback) {
193
- if (!callback) callback = message;
194
- callback(assert);
195
- };
196
-
197
- function addListener(type, listener) {
198
- var events = this.__$events || (this.__$events = {});
199
- this.emit('newListener', type, listener);
200
- if (!events[type]) events[type] = [];
201
- events[type].push(listener);
202
- }
203
-
204
- $m.EventEmitter = $m.Module.extend({
205
- emit: function () {
206
- // TODO optimize
207
- var type = arguments[0];
208
- var events = this.__$events || (this.__$events = {});
209
- var handlers = events[type];
210
-
211
- if (!handlers) return false;
212
-
213
- var args = [];
214
- for (var i=1,len=arguments.length; i<len; i++) args[i-1] = arguments[i];
215
- for (var i=0,len=handlers.length; i<len; i++) handlers[i].apply(this, args);
216
- },
217
-
218
- addListener: addListener,
219
- on: addListener
220
- });
221
-
222
- $m.out = function () {
223
- for(var i=0,_c1=arguments,_l1=_c1.length,arg;(arg=_c1[i])||(i<_l1);i++){
224
- $m.ADAPTER.out(arg);
225
- if (i < arguments.length-1) {
226
- $m.ADAPTER.out(',');
227
- }
228
- }
229
- };
230
-
231
- $m.outs = function () {
232
- for(var _i1=0,_c1=arguments,_l1=_c1.length,arg;(arg=_c1[_i1])||(_i1<_l1);_i1++){
233
- $m.ADAPTER.outs(arg);
234
- }
235
- };
236
-
237
-
238
- return $m;
239
- })(undefined, $m);
240
-
241
-
242
- var IDENT = "[\\$\\w]+";
243
- var TOKENS = [
244
- [ "SPACE", "\\s+" ],
245
-
246
- [ "STATIC", "static\\b" ],
247
- [ "MODULE", "module\\b", 'ModuleParser' ],
248
- [ "CLASS", "class\\b", 'ClassParser' ],
249
- [ "FUNCTION", "function\\b" ],
250
- [ "INCLUDE", "include\\b" ],
251
- [ "VAR", "var\\b" ],
252
- [ "PRIVATE", "private\\b" ],
253
- [ "EXTENDS", "extends\\b" ],
254
- [ "FOREACH", "foreach\\b", 'ForeachParser' ],
255
-
256
- [ "SHORTHAND_FUNCTION", "#(?:{|\\()", 'ShorthandFunctionParser' ],
257
- [ "ISTRING_START", "%{", 'IStringParser' ],
258
- [ "HEREDOC", "<<[A-Z][0-9A-Z]*", 'HereDocParser' ],
259
-
260
- [ "DSTRING", "\"(?:\\\\.|[^\"])*\"" ],
261
- [ "SSTRING", "\'(?:\\\\.|[^\'])*\'" ],
262
-
263
- [ "SEMICOLON", ";" ],
264
- [ "OPERATOR", "\\+|\\-|\\++" ],
265
- [ "EQUALS", "=" ],
266
-
267
- [ "COMMENT", "\\/\\/|\\/\\*", "CommentParser" ],
268
- [ "REGEX", "/", 'RegexParser' ],
269
-
270
- [ "LBRACE", "\\(" ],
271
- [ "RBRACE", "\\)" ],
272
- [ "LCURLY", "\\{" ],
273
- [ "RCURLY", "\\}" ],
274
-
275
- [ "IDENT", IDENT ],
276
- [ "WHATEVER", "." ]
277
- ];
278
-
279
- var $c = $m.ROOT;
280
- var TYPES = {};
281
- var REGEXES = [];
282
- var MAIN_REGEX = null;
283
-
284
- for(var i=0,_c1=TOKENS,_l1=_c1.length,t;(t=_c1[i])||(i<_l1);i++){
285
- TYPES[t[0]] = i;
286
- REGEXES.push("(" + t[1] + ")");
287
- }
288
-
289
- var EXTRA_REGEX_STRINGS = {
290
- ARGS: "\\(\s*(?:" + IDENT + ")?(?:\\s*,\\s*" + IDENT + ")*\s*\\)",
291
- CLASSNAME: "[\\$\\w\\.]+"
292
- };
293
-
294
- var MAIN_REGEX = new RegExp("^" + REGEXES.join('|'));
295
-
296
- JS2.Class.extend('Tokens', function(KLASS, OO){
297
- OO.addMember("initialize",function (str) {
298
- this.orig = str;
299
- this.str = str;
300
- this.iterator = 0;
301
- this.consumed = 0;
302
- });
303
-
304
- OO.addMember("peek",function () {
305
- if (this._peek) return this._peek;
306
-
307
- var m = this.str.match(MAIN_REGEX);
308
- if (!m) return null;
309
-
310
- for(var i=0,_c1=TOKENS,_l1=_c1.length,ele;(ele=_c1[i])||(i<_l1);i++){
311
- if (m[i+1]) return this._peek = [ i, m[i+1], ele[2] ];
312
- }
313
- });
314
-
315
- OO.addStaticMember("regex",function (str) {
316
- var regexStr = str.replace(/\*\*/g, "\\s*").replace(/\s+/g, "\\s+").replace(/\>\</g, ">\\s*<").replace(/\<(\w+)\>/g, function($1,$2,$3){
317
- return "(" + (EXTRA_REGEX_STRINGS[$2] || TOKENS[TYPES[$2]][1]) + ")";
318
- });
319
-
320
- return new RegExp("^" + regexStr);
321
- });
322
-
323
- OO.addMember("consume",function (n) {
324
- this.str = this.str.substr(n, this.str.length-n);
325
- this._peek = null;
326
- this.consumed += n;
327
- });
328
-
329
- OO.addMember("length",function () {
330
- return this.str.length;
331
- });
332
-
333
- OO.addMember("lookback",function (n) {
334
- var starting = this.consumed;
335
- while (this.orig.charAt(starting).match(/\s/)) starting--;
336
- return this.orig.substr(starting-1-n, n);
337
- });
338
-
339
- OO.addMember("lookahead",function (n) {
340
- var starting = this.consumed;
341
- while (this.orig.charAt(starting).match(/\s/)) starting++;
342
- return this.orig.substr(starting, n);
343
- });
344
-
345
-
346
- OO.addMember("any",function () {
347
- return this.str.length > 0;
348
- });
349
-
350
- OO.addMember("match",function (regex) {
351
- return this.str.match(regex);
352
- });
353
- });
354
- var Tokens = $c.Tokens;
355
-
356
-
357
- $m.parse = function (str) {
358
- var parser = new $c.RootParser();
359
- parser.parse(new $c.Tokens(str));
360
- return parser.toString();
361
- };
362
-
363
- JS2.Class.extend('RootParser', function(KLASS, OO){
364
- OO.addMember("handlers",{});
365
-
366
- OO.addMember("initialize",function () {
367
- this.out = [];
368
- this.finished = false;
369
- });
370
-
371
- OO.addMember("parse",function (tokens) {
372
- var len = tokens.length();
373
- if (this.startParse(tokens) === false || this.parseTokens(tokens) === false || this.endParse(tokens) === false) return false
374
- return len != tokens.length();
375
- });
376
-
377
- OO.addMember("parseTokens",function (tokens) {
378
- var sanity = 100;
379
- var origLen = tokens.length();
380
-
381
- while (tokens.any()) {
382
- var token = tokens.peek();
383
- if (!token) break;
384
-
385
- // has a parser class associated with this token
386
- var handlerClass = this.getHandler(token) || token[2];
387
- if (handlerClass) {
388
- var handler = new $c[handlerClass];
389
- if (handler.parse(tokens) !== false) {
390
- this.out.push(handler);
391
- tokens.lastHandler = handler;
392
- } else {
393
- this.handleToken(token, tokens);
394
- }
395
- }
396
-
397
- // no parser class, use "this" to just consume it
398
- else {
399
- this.handleToken(token, tokens);
400
- }
401
-
402
- if (this.finished) break;
403
-
404
- if (origLen == tokens.length() && sanity-- == 0) {
405
- throw "parse error";
406
- } else {
407
- sanity = 100;
408
- }
409
- }
410
- });
411
-
412
- OO.addMember("startParse",function () { });
413
- OO.addMember("endParse",function () { });
414
-
415
- OO.addMember("handleToken",function (token, tokens) {
416
- this.out.push(token[1]);
417
- tokens.consume(token[1].length);
418
- });
419
-
420
- OO.addMember("toString",function () {
421
- var ret = [];
422
- for(var _i1=0,_c1=this.out,_l1=_c1.length,ele;(ele=_c1[_i1])||(_i1<_l1);_i1++){
423
- ret.push(ele.toString());
424
- }
425
- return ret.join("");
426
- });
427
-
428
- // intercepts parser class for special cases
429
- OO.addMember("getHandler",function (token) {
430
- return null;
431
- });
432
-
433
- OO.addMember("chop",function () {
434
- this.out.pop();
435
- });
436
- });
437
-
438
- var RootParser = $c.RootParser;
439
-
440
- RootParser.extend('ClassParser', function(KLASS, OO){
441
- // private closure
442
-
443
- var REGEX = Tokens.regex("<CLASS> <CLASSNAME><LCURLY>");
444
- var EXTENDS = Tokens.regex("<CLASS> <CLASSNAME><EXTENDS><CLASSNAME><LCURLY>");
445
-
446
-
447
- OO.addMember("parse",function (tokens) {
448
- var m = tokens.match(REGEX) || tokens.match(EXTENDS);
449
- var name = m[2];
450
- var extending = m[4] || "$m.Class";
451
-
452
- tokens.consume(m[0].length-1);
453
-
454
- var content = new $c.ClassContentParser();
455
- content.parse(tokens);
456
-
457
- this.out = [ "var ", name, " = " + extending + ".extend(function(KLASS, OO)", content, ");" ];
458
- });
459
- });
460
-
461
- RootParser.extend('ModuleParser', function(KLASS, OO){
462
- // private closure
463
-
464
- var REGEX = Tokens.regex("<MODULE> <CLASSNAME><LCURLY>");
465
-
466
-
467
- OO.addMember("parse",function (tokens) {
468
- var m = tokens.match(REGEX);
469
- if (!m) return false;
470
- var name = m[2];
471
- tokens.consume(m[0].length-1);
472
-
473
- var content = new $c.ClassContentParser();
474
- content.parse(tokens);
475
-
476
- this.out = [ "var ", name, " = $m.Module.extend(function(KLASS, OO)", content, ");" ];
477
- });
478
- });
479
-
480
- RootParser.extend('CurlyParser', function(KLASS, OO){
481
- OO.addMember("initialize",function (chop) {
482
- this.chop = chop;
483
- this.$super();
484
- });
485
-
486
- OO.addMember("handleToken",function (token, tokens) {
487
- if (this.curly === undefined) this.curly = 0;
488
- if (token[0] == TYPES.RCURLY) {
489
- this.curly--;
490
- } else if (token[0] == TYPES.LCURLY) {
491
- this.curly++;
492
- }
493
-
494
- this.$super(token, tokens);
495
- if (this.curly == 0) this.finished = true;
496
- });
497
-
498
- OO.addMember("endParse",function (tokens) {
499
- if (this.chop) {
500
- this.out.pop();
501
- this.out.shift();
502
- }
503
- });
504
- });
505
-
506
- var CurlyParser = $c.CurlyParser;
507
-
508
- CurlyParser.extend('ClassContentParser', function(KLASS, OO){
509
- OO.addMember("getHandler",function (token) {
510
- switch(token[0]) {
511
- case TYPES.STATIC: return "StaticParser";
512
- case TYPES.VAR: return "MemberParser";
513
- case TYPES.FUNCTION: return "MethodParser";
514
- case TYPES.PRIVATE: return "PrivateParser";
515
- case TYPES.INCLUDE: return "IncludeParser";
516
- }
517
- });
518
-
519
- });
520
-
521
- RootParser.extend('LineParser', function(KLASS, OO){
522
- OO.addMember("handleToken",function (token, tokens) {
523
- this.$super(token, tokens);
524
- if (token[0] == TYPES.SEMICOLON) {
525
- this.finished = true;
526
- }
527
- });
528
- });
529
-
530
- CurlyParser.extend('PrivateParser', function(KLASS, OO){
531
- // private closure
532
-
533
- var REGEX = Tokens.regex("<PRIVATE>\\s*");
534
-
535
-
536
- OO.addMember("startParse",function (tokens) {
537
- var m = tokens.match(REGEX);
538
- tokens.consume(m[0].length);
539
- });
540
-
541
- OO.addMember("endParse",function (tokens) {
542
- this.out.pop();
543
- this.out.shift();
544
- });
545
- });
546
-
547
-
548
- RootParser.extend('IStringParser', function(KLASS, OO){
549
- // private closure
550
-
551
- var BEGIN = Tokens.regex("<ISTRING_START>");
552
-
553
-
554
- OO.addMember("parse",function (tokens) {
555
- var m = tokens.match(BEGIN);
556
- tokens.consume(m[0].length);
557
- this.out.push('"');
558
-
559
- while (1) {
560
- var m = tokens.match(/^((?:\\.|.)*?)(#\{|})/);
561
- var str = m[1];
562
- var len = m[0].length;
563
- str.replace(/"/, '\\"');
564
-
565
- if (m[2] == '#{') {
566
- this.out.push(str+'"+(');
567
- tokens.consume(len-1);
568
- this.parseMiddle(tokens);
569
- this.out.push(')+"');
570
- }
571
-
572
- else if (m[2] == '}') {
573
- this.out.push(str);
574
- this.out.push('"');
575
- tokens.consume(len);
576
- return;
577
- }
578
- }
579
- });
580
-
581
- OO.addMember("parseMiddle",function (tokens) {
582
- var parser = new CurlyParser(true);
583
- parser.parse(tokens);
584
- this.out.push(parser);
585
- });
586
- });
587
-
588
- RootParser.extend('StaticParser', function(KLASS, OO){
589
- // private closure
590
-
591
- var VAR_REGEX = Tokens.regex("(<STATIC>(\\s+))<VAR>");
592
- var FUNCT_REGEX = Tokens.regex("(<STATIC>(\\s+))<FUNCTION>");
593
-
594
-
595
- OO.addMember("parseTokens",function (tokens) {
596
- var varMatch = tokens.match(VAR_REGEX);
597
- if (varMatch) {
598
- tokens.consume(varMatch[1].length);
599
- var parser = new MemberParser();
600
- parser.isStatic = true;
601
- parser.parse(tokens);
602
- this.out.push(parser);
603
- }
604
-
605
- else {
606
- var functMatch = tokens.match(FUNCT_REGEX);
607
- tokens.consume(functMatch[1].length);
608
-
609
- var parser = new MethodParser();
610
- parser.isStatic = true;
611
- parser.parse(tokens);
612
- this.out.push(parser);
613
- }
614
- });
615
- });
616
-
617
- RootParser.extend('MemberParser', function(KLASS, OO){
618
- // private closure
619
-
620
- var REGEX = Tokens.regex("var <IDENT>\\s*=\\s*?");
621
-
622
-
623
- OO.addMember("parse",function (tokens) {
624
- var m = tokens.str.match(REGEX);
625
- this.name = m[1];
626
- tokens.consume(m[0].length);
627
-
628
- var parser = new $c.LineParser();
629
- parser.parse(tokens);
630
- parser.chop();
631
- var addMethod = this.isStatic ? 'addStaticMember' : 'addMember';
632
-
633
- this.out = [ "OO." + addMethod + "(", JSON.stringify(this.name), ",", parser, ");" ];
634
- });
635
- });
636
-
637
-
638
-
639
- RootParser.extend('IncludeParser', function(KLASS, OO){
640
- // private closure
641
-
642
- var REGEX = Tokens.regex("<INCLUDE> <CLASSNAME><SEMICOLON>");
643
-
644
-
645
- OO.addMember("parse",function (tokens) {
646
- var m = tokens.match(REGEX);
647
- tokens.consume(m[0].length);
648
- this.out = [ 'OO.include(', m[2], ');' ];
649
- });
650
- });
651
-
652
- RootParser.extend('HereDocParser', function(KLASS, OO){
653
- // private closure
654
-
655
- var REGEX = Tokens.regex("<HEREDOC>");
656
-
657
-
658
- OO.addMember("parse",function (tokens) {
659
- var beginning = tokens.match(/^<<(\w+)\s*([;\)])*\n/);
660
- tokens.consume(beginning[0].length);
661
-
662
- var spacing = tokens.match(/^(\s*)/);
663
- var regexSub = new RegExp("^" + (spacing[0] || ''), "mg");
664
-
665
-
666
- var strMatch = tokens.match(new RegExp("^([\\s\\S]*?)\\n\\s*" + beginning[1] + "\\s*\\n"));
667
- var toParse = strMatch[1] || '';
668
-
669
- toParse = toParse.replace(regexSub, '');
670
- toParse = toParse.replace("\n", "\\n");
671
-
672
- var string = $m.parse('%{' + toParse + '}');
673
- tokens.consume(strMatch[0] ? strMatch[0].length : 0);
674
-
675
- this.out = [ string, beginning[2] || ';' ];
676
- });
677
- });
678
-
679
- RootParser.extend('MethodParser', function(KLASS, OO){
680
- // private closure
681
-
682
- var REGEX = Tokens.regex("<FUNCTION> <IDENT><ARGS><SPACE>");
683
-
684
-
685
- OO.addMember("parse",function (tokens) {
686
- var m = tokens.str.match(REGEX);
687
- tokens.consume(m[0].length);
688
- var name = m[2];
689
- var args = m[3];
690
-
691
- var body = new CurlyParser();
692
- body.parse(tokens);
693
-
694
- var addMethod = this.isStatic ? 'addStaticMember' : 'addMember';
695
-
696
-
697
- this.out = [ 'OO.' + addMethod + '(', JSON.stringify(name), ', function', args, body, ');' ];
698
- });
699
- });
700
-
701
- RootParser.extend('ShorthandFunctionParser', function(KLASS, OO){
702
- // private closure
703
-
704
- var ARGS_REGEX = Tokens.regex("<ARGS>\\s*");
705
-
706
-
707
- OO.addMember("parse",function (tokens) {
708
- tokens.consume(1);
709
- var argsMatch = tokens.match(ARGS_REGEX);
710
- var args = null;
711
-
712
- if (argsMatch) {
713
- args = argsMatch[0];
714
- tokens.consume(argsMatch[0].length);
715
- } else {
716
- args = "($1,$2,$3)";
717
- }
718
-
719
- var body = new CurlyParser();
720
- body.parse(tokens);
721
- var semi = tokens.match(/^\s*[,;\)]/) ? '' : ';';
722
-
723
- this.out = [ 'function', args, body, semi ];
724
- });
725
- });
726
-
727
- RootParser.extend('CommentParser', function(KLASS, OO){
728
- OO.addMember("parse",function (tokens) {
729
- var m = tokens.match(/^\/\/.*?\n/);
730
- if (m) {
731
- tokens.consume(m[0].length);
732
- this.out = [ m[0] ];
733
- return;
734
- }
735
-
736
- var m2 = tokens.match(/^\/\*[\s\S]*?\*\//);
737
- if (m2) {
738
- tokens.consume(m2[0].length);
739
- this.out = [ m2[0] ];
740
- return;
741
- }
742
-
743
- return false;
744
- });
745
- });
746
-
747
- RootParser.extend('RegexParser', function(KLASS, OO){
748
- // private closure
749
-
750
- var REGEX = /^\/(\\.|[^\/])+\/[imgy]{0,4}/;
751
- var DIVIDE = /(\}|\)|\+\+|\-\-|[\w\$])$/;
752
-
753
-
754
- OO.addMember("parseTokens",function (tokens) {
755
- var back = tokens.lookback(2);
756
- if (back.match(DIVIDE)) {
757
- tokens.consume(1);
758
- this.out.push("/");
759
- }
760
-
761
- else {
762
- var m = tokens.match(REGEX);
763
- if (m) {
764
- this.out.push(m[0]);
765
- tokens.consume(m[0].length);
766
- } else {
767
- return false;
768
- }
769
- }
770
- });
771
-
772
- });
773
-
774
- CurlyParser.extend('ForeachParser', function(KLASS, OO){
775
- // private closure
776
-
777
- var REGEX = Tokens.regex("<FOREACH><LBRACE><VAR> <IDENT>(?:**:**<IDENT>)? in (.*?)**<RBRACE>**{");
778
-
779
-
780
- OO.addMember("startParse",function (tokens) {
781
- var m = tokens.match(REGEX);
782
- namespace = tokens.iterator++;
783
-
784
- this.item = m[4];
785
- this.iterator = m[5] || "_i_" + namespace;
786
- this.list = m[6];
787
-
788
- // TODO ugly, revisit this later
789
- tokens.consume(m[0].length-1);
790
- var declare = [ this.iterator + "=0", this.item + "=null", "_list_" + namespace + "=" + this.list, "_len_" + namespace + "=_list_" + namespace + ".length" ].join(',');
791
-
792
- var bool = "(" + this.item + "=" + "_list_" + namespace + "[" + this.iterator + "])||" + this.iterator + "<_len_" + namespace;
793
-
794
- this.out = [ "for (", declare, ";", bool, ';', this.iterator + "++)" ];
795
- });
796
-
797
- OO.addMember("endParse",function (tokens) {
798
- tokens.iterator--;
799
- });
800
-
801
- });
802
-
803
-
804
- JS2.Class.extend('JSML', function(KLASS, OO){
805
- OO.addStaticMember("process",function (txt) {
806
- return new KLASS(txt);
807
- });
808
-
809
- OO.addMember("initialize",function (txt) {
810
- var lines = txt.split(/\n/);
811
- this.root = new JS2.JSMLElement();
812
- this.stack = [ this.root ];
813
-
814
- for(var _i1=0,_c1=lines,_l1=_c1.length,l;(l=_c1[_i1])||(_i1<_l1);_i1++){
815
- if (l.match(/^\s*$/)) continue;
816
- this.processLine(l);
817
- }
818
-
819
- var toEval = 'function process() { var out = [];\n' + this.flatten().join('') + '\n return out.join("");\n}';
820
- eval(toEval);
821
-
822
- this.result = function(bound) {
823
- bound = bound || {};
824
- return process.call(bound);
825
- };
826
- });
827
-
828
- OO.addMember("flatten",function () {
829
- return this.root.flatten();
830
- });
831
-
832
- OO.addMember("processLine",function (line) {
833
- if (line.match(/^\s*$/)) return;
834
-
835
- var ele = new JS2.JSMLElement(line);
836
- var scope = this.getScope();
837
-
838
- if (ele.scope == scope) {
839
- this.stack.pop();
840
- this.getLast().push(ele);
841
- this.stack.push(ele);
842
- } else if (ele.scope > scope) {
843
- this.getLast().push(ele);
844
- this.stack.push(ele);
845
- } else if (ele.scope < scope) {
846
- var diff = scope - ele.scope + 1;
847
- while(diff-- > 0) {
848
- this.stack.pop();
849
- }
850
- this.getLast().push(ele);
851
- this.stack.push(ele);
852
- }
853
- });
854
-
855
-
856
- OO.addMember("getScope",function () {
857
- return this.stack.length - 1;
858
- });
859
-
860
- OO.addMember("getLast",function () {
861
- return this.stack[this.stack.length-1];
862
- });
863
-
864
- });
865
-
866
- JS2.Class.extend('JSMLElement', function(KLASS, OO){
867
- OO.addMember("SCOPE_REGEX",/^(\s*)(.*)$/);
868
- OO.addMember("SPLIT_REGEX",/^((?:\.|\#|\%)[^=\s\{]*)?(\{.*\})?(=|-)?(?:\s*)(.*)$/);
869
- OO.addMember("TOKEN_REGEX",/(\%|\#|\.)([\w][\w\-]*)/g);
870
- OO.addMember("JS_REGEX",/^(-|=)(.*)$/g);
871
- OO.addMember("SCOPE_OFFSET",1);
872
- OO.addMember("SELF_CLOSING",{ area: null, basefont: null, br: null, hr: null, input: null, img: null, link: null, meta: null });
873
-
874
- OO.addMember("initialize",function (line) {
875
- this.children = [];
876
-
877
- if (line == null) {
878
- this.scope = this.SCOPE_OFFSET;
879
- return;
880
- }
881
-
882
- var spaceMatch = line.match(this.SCOPE_REGEX);
883
- this.scope = spaceMatch[1].length / 2 + this.SCOPE_OFFSET;
884
-
885
- this.classes = [];
886
- this.nodeID = null;
887
-
888
- this.parse(spaceMatch[2]);
889
- });
890
-
891
- OO.addMember("push",function (child) {
892
- this.children.push(child);
893
- });
894
-
895
- OO.addMember("parse",function (line) {
896
- this.attributes;
897
- this.line = line;
898
- var self = this;
899
-
900
- var splitted = line.match(this.SPLIT_REGEX);
901
- var tokens = splitted[1];
902
- var attrs = splitted[2];
903
- var jsType = splitted[3];
904
- var content = splitted[4];
905
-
906
- if (tokens) {
907
- tokens.replace(this.TOKEN_REGEX, function(match, type, name){
908
- switch(type) {
909
- case '%': self.nodeType = name; break;
910
- case '.': self.classes.push(name); break;
911
- case '#': self.nodeID = name; break;
912
- }
913
- return '';
914
- });
915
- }
916
-
917
- if (jsType == '=') {
918
- this.jsEQ = content;
919
- } else if (jsType == '-') {
920
- this.jsExec = content;
921
- } else {
922
- this.content = content;
923
- }
924
-
925
- if (attrs) {
926
- this.attributes = attrs;
927
- }
928
-
929
- if (!this.nodeType && (this.classes.length || this.nodeID)) {
930
- this.nodeType = 'div';
931
- }
932
-
933
- if (this.SELF_CLOSING.hasOwnProperty(this.nodeType) && this.children.length == 0) {
934
- this.selfClose = '/';
935
- } else {
936
- this.selfClose = '';
937
- }
938
- });
939
-
940
- OO.addMember("flatten",function () {
941
- var out = [];
942
-
943
- for(var _i1=0,_c1=this.children,_l1=_c1.length,c;(c=_c1[_i1])||(_i1<_l1);_i1++){
944
- var arr = c.flatten();
945
- for(var _i2=0,_c2=arr,_l2=_c2.length,item;(item=_c2[_i2])||(_i2<_l2);_i2++){
946
- out.push(item);
947
- }
948
- }
949
-
950
- if (this.nodeType) {
951
- this.handleJsEQ(out);
952
- this.handleContent(out);
953
- out.unshift('out.push("<' + this.nodeType + '"+JS2.JSMLElement.parseAttributes(' + (this.attributes || "{}") + ', ' + JSON.stringify(this.classes || []) + ', ' + JSON.stringify(this.id || null) + ')+"' + this.selfClose + '>");\n');
954
- if (this.selfClose == '') {
955
- out.push('out.push(' + JSON.stringify("</"+(this.nodeType)+">") + ');\n');
956
- }
957
- } else {
958
- this.handleJsExec(out);
959
- this.handleJsEQ(out);
960
- this.handleContent(out);
961
- }
962
-
963
- return out;
964
- });
965
-
966
- OO.addMember("handleJsEQ",function (out) {
967
- if (this.jsEQ) {
968
- this.jsEQ = this.jsEQ.replace(/;\s*$/, '');
969
- out.unshift('out.push(' + this.jsEQ + ');\n');
970
- }
971
- });
972
-
973
- OO.addMember("handleContent",function (out) {
974
- if (this.content != null && this.content.length > 0) {
975
- out.unshift('out.push(' + JSON.stringify(this.content) + ');\n');
976
- }
977
- });
978
-
979
-
980
- OO.addMember("handleJsExec",function (out) {
981
- if (this.jsExec) {
982
- out.unshift(this.jsExec);
983
- if (this.jsExec.match(/\{\s*$/)) {
984
- out.push("}\n");
985
- }
986
- }
987
- });
988
-
989
- OO.addStaticMember("parseAttributes",function (hash, classes, id) {
990
- var out = [];
991
- classes = classes || [];
992
- if (hash['class']) classes.push(hash['class']);
993
- if (classes.length) hash['class'] = classes.join(" ");
994
-
995
- for (var k in hash) {
996
- if (hash.hasOwnProperty(k)) {
997
- out.push(k + '=' + JSON.stringify(hash[k]));
998
- }
999
- }
1000
- return (out.length ? ' ' : '') + out.join(' ');
1001
- });
1002
- });
1003
-
1004
-
1005
- JS2.Class.extend('CLI', function(KLASS, OO){
1006
- // private closure
1007
-
1008
- var COMMANDS = {
1009
- help: 'help',
1010
- render: 'render',
1011
- compile: 'compile',
1012
- watch: 'watch'
1013
- };
1014
-
1015
-
1016
- OO.addMember("run",function (args) {
1017
- var opts = this.parseOpts(args);
1018
- var options = opts[0];
1019
- var command = opts[1];
1020
- var files = opts[2];
1021
- });
1022
-
1023
- OO.addMember("parseOpts",function (args) {
1024
- var files = [];
1025
- var options = {};
1026
- var command = null;
1027
-
1028
- var endedArgs = false;
1029
-
1030
- for(var i=0,_c1=args,_l1=_c1.length,arg;(arg=_c1[i])||(i<_l1);i++){
1031
- if (endedArgs) {
1032
- files.push(arg);
1033
- }
1034
-
1035
- else if (COMMANDS[arg]) {
1036
- command = arg;
1037
- endedArgs = true;
1038
- }
1039
-
1040
- else {
1041
- var setting = arg.match(/^(\w+)(?:=(.*))?$/);
1042
- if (setting) options[setting[0]] = setting[1] || 'true';
1043
- }
1044
- }
1045
-
1046
- return [ options, command, files ];
1047
- });
1048
- });
1049
-
1050
-
1051
- })();
1052
- FINISH
1053
- end
1054
- end
1
+ require File.dirname(__FILE__) + '/mochiscript/core'
2
+ require File.dirname(__FILE__) + '/mochiscript/rails/engine' if defined?(::Rails)