@@ -19,14 +19,18 @@ const tokenize = require('./tokenize');
1919const flatten = require ( 'flatten' ) ;
2020const indexesOf = require ( 'indexes-of' ) ;
2121const uniq = require ( 'uniq' ) ;
22+ const ParserError = require ( './errors/ParserError' ) ;
2223
2324function sortAscending ( list ) {
2425 return list . sort ( ( a , b ) => a - b ) ;
2526}
2627
2728module . exports = class Parser {
28- constructor ( input ) {
29+ constructor ( input , options ) {
30+ const defaults = { loose : false } ;
31+
2932 this . input = input ;
33+ this . options = Object . assign ( { } , defaults , options ) ;
3034 this . position = 0 ;
3135 // we'll use this to keep track of the paren balance
3236 this . unbalanced = 0 ;
@@ -37,7 +41,8 @@ module.exports = class Parser {
3741 this . root . append ( value ) ;
3842
3943 this . current = value ;
40- this . tokens = tokenize ( input ) ;
44+ this . tokens = tokenize ( input , this . options ) ;
45+ // console.log(this.tokens);
4146 }
4247
4348 parse ( ) {
@@ -106,8 +111,8 @@ module.exports = class Parser {
106111 this . position ++ ;
107112 }
108113
109- error ( message ) {
110- throw new Error ( message ) ; // eslint-disable- line new-cap
114+ error ( message , token ) {
115+ throw new ParserError ( message + ` at line: ${ token [ 2 ] } , column ${ token [ 3 ] } ` ) ;
111116 }
112117
113118 loop ( ) {
@@ -129,7 +134,30 @@ module.exports = class Parser {
129134
130135 operator ( ) {
131136
132- let node = new Operator ( {
137+ // if a +|- operator is followed by a non-word character (. is allowed) and
138+ // is preceded by a non-word character. (5+5)
139+ let char = this . currToken [ 1 ] ,
140+ node ;
141+
142+ if ( char === '+' || char === '-' ) {
143+ if ( this . position > 0 ) {
144+ if ( ! this . options . loose ) {
145+ if ( this . prevToken [ 0 ] !== 'space' ) {
146+ this . error ( 'Syntax Error' , this . currToken ) ;
147+ }
148+ else if ( this . nextToken [ 0 ] !== 'space' ) {
149+ this . error ( 'Syntax Error' , this . currToken ) ;
150+ }
151+ }
152+ }
153+
154+ if ( ( ! this . current . nodes . length || ( this . current . last && this . current . last . type === 'operator' ) ) && this . nextToken [ 0 ] === 'word' ) {
155+ return this . word ( ) ;
156+ }
157+ }
158+
159+
160+ node = new Operator ( {
133161 value : this . currToken [ 1 ] ,
134162 source : {
135163 start : {
@@ -205,7 +233,7 @@ module.exports = class Parser {
205233 }
206234
207235 if ( unbalanced ) {
208- this . error ( 'Expected closing parenthesis.' ) ;
236+ this . error ( 'Expected closing parenthesis' , token ) ;
209237 }
210238
211239 // ok, all parens are balanced. continue on
@@ -300,7 +328,7 @@ module.exports = class Parser {
300328 this . current . unbalanced -- ;
301329
302330 if ( this . current . unbalanced < 0 ) {
303- this . error ( 'Expected opening parenthesis.' ) ;
331+ this . error ( 'Expected opening parenthesis' , token ) ;
304332 }
305333
306334 if ( ! this . current . unbalanced && this . cache ) {
@@ -450,10 +478,6 @@ module.exports = class Parser {
450478 return this . splitWord ( ) ;
451479 }
452480
453- missingParenthesis ( ) {
454- return this . error ( 'Expected opening parenthesis.' ) ;
455- }
456-
457481 newNode ( node ) {
458482 if ( this . spaces ) {
459483 node . raws . before += this . spaces ;
0 commit comments