You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
172 lines
7.6 KiB
172 lines
7.6 KiB
/* description: Parses expressions. */ |
|
|
|
%options case-insensitive |
|
|
|
/* lexical grammar */ |
|
%lex |
|
%% |
|
\s+ /* skip whitespace */ |
|
|
|
(\-(webkit|moz)\-)?calc\b return 'CALC'; |
|
|
|
[a-z][a-z0-9-]*\s*\((?:(?:\"(?:\\.|[^\"\\])*\"|\'(?:\\.|[^\'\\])*\')|\([^)]*\)|[^\(\)]*)*\) return 'FUNCTION'; |
|
|
|
"*" return 'MUL'; |
|
"/" return 'DIV'; |
|
"+" return 'ADD'; |
|
"-" return 'SUB'; |
|
|
|
([0-9]+("."[0-9]+)?|"."[0-9]+)em\b return 'LENGTH'; // em |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)ex\b return 'LENGTH'; // ex |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)ch\b return 'LENGTH'; // ch |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)rem\b return 'LENGTH'; // rem |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)vw\b return 'LENGTH'; // vw |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)vh\b return 'LENGTH'; // vh |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)vmin\b return 'LENGTH'; // vmin |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)vmax\b return 'LENGTH'; // vmax |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)vm\b return 'LENGTH'; // vm (non-standard name) |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)px\b return 'LENGTH'; // px |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)mm\b return 'LENGTH'; // mm |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)cm\b return 'LENGTH'; // cm |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)in\b return 'LENGTH'; // in |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)pt\b return 'LENGTH'; // pt |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)pc\b return 'LENGTH'; // pc |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)Q\b return 'LENGTH'; // Q |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)fr\b return 'LENGTH'; // fr |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)deg\b return 'ANGLE'; // deg |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)grad\b return 'ANGLE'; // grad |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)turn\b return 'ANGLE'; // turn |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)rad\b return 'ANGLE'; // rad |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)s\b return 'TIME'; // s |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)ms\b return 'TIME'; // ms |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)Hz\b return 'FREQ'; // Hz |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)kHz\b return 'FREQ'; // kHz |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)dpi\b return 'RES'; // dpi |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)dpcm\b return 'RES'; // dpcm |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)dppx\b return 'RES'; // dppm |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)\% return 'PERCENTAGE'; |
|
([0-9]+("."[0-9]+)?|"."[0-9]+)\b return 'NUMBER'; |
|
|
|
"(" return 'LPAREN'; |
|
")" return 'RPAREN'; |
|
|
|
#\{([\s\S]*?)\} return 'UNKNOWN'; // scss interpolation |
|
@\{([\s\S]*?)\} return 'UNKNOWN'; // less interpolation |
|
|
|
\S[^\s()*/+-]* return 'UNKNOWN'; |
|
|
|
<<EOF>> return 'EOF'; |
|
|
|
/lex |
|
|
|
%left ADD SUB |
|
%left MUL DIV |
|
%left UPREC |
|
|
|
|
|
%start expression |
|
|
|
%% |
|
|
|
expression |
|
: math_expression EOF { return $1; } |
|
; |
|
|
|
math_expression |
|
: CALC LPAREN math_expression RPAREN { |
|
$$ = $3; |
|
$$.source.start = { index: @1.range[0] }; |
|
$$.source.end = { index: @4.range[1] }; |
|
} |
|
| math_expression ADD math_expression { |
|
$$ = { |
|
type: 'MathExpression', operator: $2, left: $1, right: $3, |
|
source: { |
|
start: $1.source.start, end: $3.source.end, |
|
operator: { start: { index: @2.range[0] }, end: { index: @2.range[1] } } |
|
} |
|
}; |
|
} |
|
| math_expression SUB math_expression { |
|
$$ = { |
|
type: 'MathExpression', operator: $2, left: $1, right: $3, |
|
source: { |
|
start: $1.source.start, end: $3.source.end, |
|
operator: { start: { index: @2.range[0] }, end: { index: @2.range[1] } } |
|
} |
|
}; |
|
} |
|
| math_expression MUL math_expression { |
|
$$ = { |
|
type: 'MathExpression', operator: $2, left: $1, right: $3, |
|
source: { |
|
start: $1.source.start, end: $3.source.end, |
|
operator: { start: { index: @2.range[0] }, end: { index: @2.range[1] } } |
|
} |
|
}; |
|
} |
|
| math_expression DIV math_expression { |
|
$$ = { |
|
type: 'MathExpression', operator: $2, left: $1, right: $3, |
|
source: { |
|
start: $1.source.start, end: $3.source.end, |
|
operator: { start: { index: @2.range[0] }, end: { index: @2.range[1] } } |
|
} |
|
}; |
|
} |
|
| SUB math_expression %prec UPREC { |
|
if (@1.range[1] !== $2.source.start.index) { |
|
throw new Error('Unexpected spaces was found between sign and value'); |
|
} |
|
if (typeof $2.value !== 'number') { |
|
throw new Error('Unexpected sign'); |
|
} |
|
if ($2.sign) { |
|
throw new Error('Unexpected continuous sign'); |
|
} |
|
$$ = $2; |
|
$$.sign = '-' |
|
$$.value = -$2.value; |
|
$$.source.start.index = @1.range[0]; |
|
} |
|
| ADD math_expression %prec UPREC { |
|
if (@1.range[1] !== $2.source.start.index) { |
|
throw new Error('Unexpected spaces was found between sign and value'); |
|
} |
|
if (typeof $2.value !== 'number') { |
|
throw new Error('Unexpected sign'); |
|
} |
|
if ($2.sign) { |
|
throw new Error('Unexpected continuous sign'); |
|
} |
|
$$ = $2; |
|
$$.sign = '+' |
|
$$.source.start.index = @1.range[0]; |
|
} |
|
| LPAREN math_expression RPAREN { |
|
$$ = $2; |
|
$$.source.start = { index: @1.range[0] }; |
|
$$.source.end = { index: @3.range[1] }; |
|
} |
|
| function { $$ = $1; } |
|
| css_value { $$ = $1; } |
|
| value { $$ = $1; } |
|
; |
|
|
|
value |
|
: NUMBER { $$ = { type: 'Value', value: parseFloat($1), source: { start: { index: @1.range[0] }, end: { index: @1.range[1] } } }; } |
|
; |
|
|
|
function |
|
: FUNCTION { $$ = { type: 'Function', value: $1, source: { start: { index: @1.range[0] }, end: { index: @1.range[1] } } }; } |
|
; |
|
|
|
css_value |
|
: LENGTH { $$ = { type: 'LengthValue', value: parseFloat($1), unit: /[a-z]+/i.exec($1)[0], source: { start: { index: @1.range[0] }, end: { index: @1.range[1] } } }; } |
|
| ANGLE { $$ = { type: 'AngleValue', value: parseFloat($1), unit: /[a-z]+/i.exec($1)[0], source: { start: { index: @1.range[0] }, end: { index: @1.range[1] } } }; } |
|
| TIME { $$ = { type: 'TimeValue', value: parseFloat($1), unit: /[a-z]+/i.exec($1)[0], source: { start: { index: @1.range[0] }, end: { index: @1.range[1] } } }; } |
|
| FREQ { $$ = { type: 'FrequencyValue', value: parseFloat($1), unit: /[a-z]+/i.exec($1)[0], source: { start: { index: @1.range[0] }, end: { index: @1.range[1] } } }; } |
|
| RES { $$ = { type: 'ResolutionValue', value: parseFloat($1), unit: /[a-z]+/i.exec($1)[0], source: { start: { index: @1.range[0] }, end: { index: @1.range[1] } } }; } |
|
| PERCENTAGE { $$ = { type: 'PercentageValue', value: parseFloat($1), unit: '%', source: { start: { index: @1.range[0] }, end: { index: @1.range[1] } } }; } |
|
| UNKNOWN { $$ = { type: 'UnknownValue', value: $1, unit: '', source: { start: { index: @1.range[0] }, end: { index: @1.range[1] } } }; } |
|
;
|
|
|