@@ -2,36 +2,173 @@ import { toNumber, stripQuotes } from '../util/index'
22import Cache from '../cache'
33
44const cache = new Cache ( 1000 )
5- const filterTokenRE = / [ ^ \s ' " ] + | ' [ ^ ' ] * ' | " [ ^ " ] * " / g
65const reservedArgRE = / ^ i n $ | ^ - ? \d + /
76
87/**
98 * Parser state
109 */
1110
12- var str , dir
13- var c , prev , i , l , lastFilterIndex
14- var inSingle , inDouble , curly , square , paren
11+ var str , dir , len
12+ var index
13+ var chr
14+ var state
15+ var startState = 0
16+ var filterState = 1
17+ var filterNameState = 2
18+ var filterArgState = 3
19+
20+ var doubleChr = 0x22
21+ var singleChr = 0x27
22+ var pipeChr = 0x7C
23+ var escapeChr = 0x5C
24+ var spaceChr = 0x20
25+
26+ var expStartChr = { 0x5B : 1 , 0x7B : 1 , 0x28 : 1 }
27+ var expChrPair = { 0x5B : 0x5D , 0x7B : 0x7D , 0x28 : 0x29 }
28+
29+ function peek ( ) {
30+ return str . charCodeAt ( index + 1 )
31+ }
32+
33+ function next ( ) {
34+ return str . charCodeAt ( ++ index )
35+ }
36+
37+ function eof ( ) {
38+ return index >= len
39+ }
40+
41+ function eatSpace ( ) {
42+ while ( peek ( ) === spaceChr ) {
43+ next ( )
44+ }
45+ }
46+
47+ function isStringStart ( chr ) {
48+ return chr === doubleChr || chr === singleChr
49+ }
50+
51+ function isExpStart ( chr ) {
52+ return expStartChr [ chr ]
53+ }
54+
55+ function isExpEnd ( start , chr ) {
56+ return expChrPair [ start ] === chr
57+ }
58+
59+ function parseString ( ) {
60+ var stringQuote = next ( )
61+ var chr
62+ while ( ! eof ( ) ) {
63+ chr = next ( )
64+ // escape char
65+ if ( chr === escapeChr ) {
66+ next ( )
67+ } else if ( chr === stringQuote ) {
68+ break
69+ }
70+ }
71+ }
72+
73+ function parseSpecialExp ( chr ) {
74+ var inExp = 0
75+ var startChr = chr
76+
77+ while ( ! eof ( ) ) {
78+ chr = peek ( )
79+ if ( isStringStart ( chr ) ) {
80+ parseString ( )
81+ continue
82+ }
83+
84+ if ( startChr === chr ) {
85+ inExp ++
86+ }
87+ if ( isExpEnd ( startChr , chr ) ) {
88+ inExp --
89+ }
90+
91+ next ( )
92+
93+ if ( inExp === 0 ) {
94+ break
95+ }
96+ }
97+ }
1598
1699/**
17- * Push a filter to the current directive object
100+ * syntax:
101+ * expression | filterName [arg arg [| filterName arg arg]]
18102 */
19103
20- function pushFilter ( ) {
21- var exp = str . slice ( lastFilterIndex , i ) . trim ( )
22- var filter
23- if ( exp ) {
24- filter = { }
25- var tokens = exp . match ( filterTokenRE )
26- filter . name = tokens [ 0 ]
27- if ( tokens . length > 1 ) {
28- filter . args = tokens . slice ( 1 ) . map ( processFilterArg )
104+ function parseExpression ( ) {
105+ var start = index
106+ while ( ! eof ( ) ) {
107+ chr = peek ( )
108+ if ( isStringStart ( chr ) ) {
109+ parseString ( )
110+ } else if ( isExpStart ( chr ) ) {
111+ parseSpecialExp ( chr )
112+ } else if ( chr === pipeChr ) {
113+ next ( )
114+ chr = peek ( )
115+ if ( chr === pipeChr ) {
116+ next ( )
117+ } else {
118+ if ( state === startState || state === filterArgState ) {
119+ state = filterState
120+ }
121+ break
122+ }
123+ } else if ( chr === spaceChr && ( state === filterNameState || state === filterArgState ) ) {
124+ eatSpace ( )
125+ break
126+ } else {
127+ if ( state === filterState ) {
128+ state = filterNameState
129+ }
130+ next ( )
29131 }
30132 }
31- if ( filter ) {
32- ( dir . filters = dir . filters || [ ] ) . push ( filter )
133+
134+ return str . slice ( start + 1 , index ) || null
135+ }
136+
137+ function parseFilterList ( ) {
138+ var filters = [ ]
139+ while ( ! eof ( ) ) {
140+ filters . push ( parseFilter ( ) )
33141 }
34- lastFilterIndex = i + 1
142+ return filters
143+ }
144+
145+ function parseFilter ( ) {
146+ var filter = { }
147+ var args
148+
149+ state = filterState
150+ filter . name = parseExpression ( ) . trim ( )
151+
152+ state = filterArgState
153+ args = parseFilterArguments ( )
154+
155+ if ( args . length ) {
156+ filter . args = args
157+ }
158+ return filter
159+ }
160+
161+ function parseFilterArguments ( ) {
162+ var args = [ ]
163+ while ( ! eof ( ) && state !== filterState ) {
164+ var arg = parseExpression ( )
165+ if ( ! arg ) {
166+ break
167+ }
168+ args . push ( processFilterArg ( arg ) )
169+ }
170+
171+ return args
35172}
36173
37174/**
@@ -83,51 +220,22 @@ export function parseDirective (s) {
83220
84221 // reset parser state
85222 str = s
86- inSingle = inDouble = false
87- curly = square = paren = 0
88- lastFilterIndex = 0
89223 dir = { }
224+ len = str . length
225+ index = - 1
226+ chr = ''
227+ state = startState
90228
91- for ( i = 0 , l = str . length ; i < l ; i ++ ) {
92- prev = c
93- c = str . charCodeAt ( i )
94- if ( inSingle ) {
95- // check single quote
96- if ( c === 0x27 && prev !== 0x5C ) inSingle = ! inSingle
97- } else if ( inDouble ) {
98- // check double quote
99- if ( c === 0x22 && prev !== 0x5C ) inDouble = ! inDouble
100- } else if (
101- c === 0x7C && // pipe
102- str . charCodeAt ( i + 1 ) !== 0x7C &&
103- str . charCodeAt ( i - 1 ) !== 0x7C
104- ) {
105- if ( dir . expression == null ) {
106- // first filter, end of expression
107- lastFilterIndex = i + 1
108- dir . expression = str . slice ( 0 , i ) . trim ( )
109- } else {
110- // already has filter
111- pushFilter ( )
112- }
113- } else {
114- switch ( c ) {
115- case 0x22 : inDouble = true ; break // "
116- case 0x27 : inSingle = true ; break // '
117- case 0x28 : paren ++ ; break // (
118- case 0x29 : paren -- ; break // )
119- case 0x5B : square ++ ; break // [
120- case 0x5D : square -- ; break // ]
121- case 0x7B : curly ++ ; break // {
122- case 0x7D : curly -- ; break // }
123- }
124- }
125- }
229+ var filters
126230
127- if ( dir . expression == null ) {
128- dir . expression = str . slice ( 0 , i ) . trim ( )
129- } else if ( lastFilterIndex !== 0 ) {
130- pushFilter ( )
231+ if ( str . indexOf ( '|' ) < 0 ) {
232+ dir . expression = str . trim ( )
233+ } else {
234+ dir . expression = parseExpression ( ) . trim ( )
235+ filters = parseFilterList ( )
236+ if ( filters . length ) {
237+ dir . filters = filters
238+ }
131239 }
132240
133241 cache . put ( s , dir )
0 commit comments