1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
%x mu emu com raw
%{
function strip(start, end) {
return yytext = yytext.substr(start, yyleng-end);
}
%}
LEFT_STRIP "~"
RIGHT_STRIP "~"
LOOKAHEAD [=~}\s\/.)|]
LITERAL_LOOKAHEAD [~}\s)]
/*
ID is the inverse of control characters.
Control characters ranges:
[\s] Whitespace
[!"#%-,\./] !, ", #, %, &, ', (, ), *, +, ,, ., /, Exceptions in range: $, -
[;->@] ;, <, =, >, @, Exceptions in range: :, ?
[\[-\^`] [, \, ], ^, `, Exceptions in range: _
[\{-~] {, |, }, ~
*/
ID [^\s!"#%-,\.\/;->@\[-\^`\{-~]+/{LOOKAHEAD}
%%
[^\x00]*?/("{{") {
if(yytext.slice(-2) === "\\\\") {
strip(0,1);
this.begin("mu");
} else if(yytext.slice(-1) === "\\") {
strip(0,1);
this.begin("emu");
} else {
this.begin("mu");
}
if(yytext) return 'CONTENT';
}
[^\x00]+ return 'CONTENT';
// marks CONTENT up to the next mustache or escaped mustache
<emu>[^\x00]{2,}?/("{{"|"\\{{"|"\\\\{{"|<<EOF>>) {
this.popState();
return 'CONTENT';
}
// nested raw block will create stacked 'raw' condition
<raw>"{{{{"/[^/] this.begin('raw'); return 'CONTENT';
<raw>"{{{{/"[^\s!"#%-,\.\/;->@\[-\^`\{-~]+/[=}\s\/.]"}}}}" {
this.popState();
// Should be using `this.topState()` below, but it currently
// returns the second top instead of the first top. Opened an
// issue about it at https://github.com/zaach/jison/issues/291
if (this.conditionStack[this.conditionStack.length-1] === 'raw') {
return 'CONTENT';
} else {
yytext = yytext.substr(5, yyleng-9);
return 'END_RAW_BLOCK';
}
}
<raw>[^\x00]*?/("{{{{") { return 'CONTENT'; }
<com>[\s\S]*?"--"{RIGHT_STRIP}?"}}" {
this.popState();
return 'COMMENT';
}
<mu>"(" return 'OPEN_SEXPR';
<mu>")" return 'CLOSE_SEXPR';
<mu>"{{{{" { return 'OPEN_RAW_BLOCK'; }
<mu>"}}}}" {
this.popState();
this.begin('raw');
return 'CLOSE_RAW_BLOCK';
}
<mu>"{{"{LEFT_STRIP}?">" return 'OPEN_PARTIAL';
<mu>"{{"{LEFT_STRIP}?"#>" return 'OPEN_PARTIAL_BLOCK';
<mu>"{{"{LEFT_STRIP}?"#" return 'OPEN_BLOCK';
<mu>"{{"{LEFT_STRIP}?"/" return 'OPEN_ENDBLOCK';
<mu>"{{"{LEFT_STRIP}?"^"\s*{RIGHT_STRIP}?"}}" this.popState(); return 'INVERSE';
<mu>"{{"{LEFT_STRIP}?\s*"else"\s*{RIGHT_STRIP}?"}}" this.popState(); return 'INVERSE';
<mu>"{{"{LEFT_STRIP}?"^" return 'OPEN_INVERSE';
<mu>"{{"{LEFT_STRIP}?\s*"else" return 'OPEN_INVERSE_CHAIN';
<mu>"{{"{LEFT_STRIP}?"{" return 'OPEN_UNESCAPED';
<mu>"{{"{LEFT_STRIP}?"&" return 'OPEN';
<mu>"{{"{LEFT_STRIP}?"!--" {
this.unput(yytext);
this.popState();
this.begin('com');
}
<mu>"{{"{LEFT_STRIP}?"!"[\s\S]*?"}}" {
this.popState();
return 'COMMENT';
}
<mu>"{{"{LEFT_STRIP}? return 'OPEN';
<mu>"=" return 'EQUALS';
<mu>".." return 'ID';
<mu>"."/{LOOKAHEAD} return 'ID';
<mu>[\/.] return 'SEP';
<mu>\s+ // ignore whitespace
<mu>"}"{RIGHT_STRIP}?"}}" this.popState(); return 'CLOSE_UNESCAPED';
<mu>{RIGHT_STRIP}?"}}" this.popState(); return 'CLOSE';
<mu>'"'("\\"["]|[^"])*'"' yytext = strip(1,2).replace(/\\"/g,'"'); return 'STRING';
<mu>"'"("\\"[']|[^'])*"'" yytext = strip(1,2).replace(/\\'/g,"'"); return 'STRING';
<mu>"@" return 'DATA';
<mu>"true"/{LITERAL_LOOKAHEAD} return 'BOOLEAN';
<mu>"false"/{LITERAL_LOOKAHEAD} return 'BOOLEAN';
<mu>"undefined"/{LITERAL_LOOKAHEAD} return 'UNDEFINED';
<mu>"null"/{LITERAL_LOOKAHEAD} return 'NULL';
<mu>\-?[0-9]+(?:\.[0-9]+)?/{LITERAL_LOOKAHEAD} return 'NUMBER';
<mu>"as"\s+"|" return 'OPEN_BLOCK_PARAMS';
<mu>"|" return 'CLOSE_BLOCK_PARAMS';
<mu>{ID} return 'ID';
<mu>'['[^\]]*']' return 'ID';
<mu>. return 'INVALID';
<INITIAL,mu><<EOF>> return 'EOF';
|