/
githubmirror
/
amphtml
Обзор
Документация
Войти
/
githubmirror
/
amphtml
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
extensions/amp-bind/0.1/bind-expr-impl.jison
385 строк
8 KB
Jake Fried
Bind expressions: allow escaped quotes in strings (#27270)
24 мар 2020, 00:44
Не верифицирован
24 мар 2020, 00:44
dbf2b91
Код
Авторство
О чём код?
%lex %% \s+ /* skip whitespace */ "null" return 'NULL' "true" return 'TRUE' "false" return 'FALSE' [0-9]+("."[0-9]+)?\b return 'NUMBER' [a-zA-Z_][a-zA-Z0-9_]* return 'NAME' \'([^\'\\]|\\.)*\' return 'STRING' \"([^\"\\]|\\.)*\" return 'STRING' '=>' return '=>' "+" return '+' "-" return '-' "*" return '*' "/" return '/' "&&" return '&&' "||" return '||' "!=" return '!=' "==" return '==' "<=" return '<=' "<" return '<' ">=" return '>=' ">" return '>' "!" return '!' "?" return '?' ":" return ':' "%" return '%' "[" return '[' "]" return ']' "{" return '{' "}" return '}' "(" return '(' ")" return ')' "," return ',' \. return '.' . return 'INVALID' <<EOF>> return 'EOF' /lex %token NAME %token STRING %token NUMBER %token TRUE FALSE %token NULL %token EOF /* * Operator precedence. * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence */ %nonassoc '=>' %left ',' %right '?' ':' %left '||' %left '&&' %left '==' '!=' %left '<' '<=' '>' '>=' %left '+' '-' %left '*' '/' '%' %right '!' UMINUS UPLUS %left '.' '[' ']' %left '(' ')' %% /* BNF grammar. */ result: expr EOF {return $1;} | EOF {return '';} ; /* Don't bother creating AST nodes for direct references in `expr`. */ expr: operation {$$ = $1;} | invocation {$$ = $1;} | member_access {$$ = $1;} | '(' expr ')' {$$ = $2;} | variable {$$ = $1;} | literal {$$ = $1;} ; operation: '!' expr %{ $$ = new AstNode(AstNodeType.NOT, [$2]); %} | '-' expr %prec UMINUS %{ $$ = new AstNode(AstNodeType.UNARY_MINUS, [$2]); %} | '+' expr %prec UPLUS %{ $$ = new AstNode(AstNodeType.UNARY_PLUS, [$2]); %} | expr '+' expr %{ $$ = new AstNode(AstNodeType.PLUS, [$1, $3]); %} | expr '-' expr %{ $$ = new AstNode(AstNodeType.MINUS, [$1, $3]); %} | expr '*' expr %{ $$ = new AstNode(AstNodeType.MULTIPLY, [$1, $3]); %} | expr '/' expr %{ $$ = new AstNode(AstNodeType.DIVIDE, [$1, $3]); %} | expr '%' expr %{ $$ = new AstNode(AstNodeType.MODULO, [$1, $3]); %} | expr '&&' expr %{ $$ = new AstNode(AstNodeType.LOGICAL_AND, [$1, $3]); %} | expr '||' expr %{ $$ = new AstNode(AstNodeType.LOGICAL_OR, [$1, $3]); %} | expr '<=' expr %{ $$ = new AstNode(AstNodeType.LESS_OR_EQUAL, [$1, $3]); %} | expr '<' expr %{ $$ = new AstNode(AstNodeType.LESS, [$1, $3]); %} | expr '>=' expr %{ $$ = new AstNode(AstNodeType.GREATER_OR_EQUAL, [$1, $3]); %} | expr '>' expr %{ $$ = new AstNode(AstNodeType.GREATER, [$1, $3]); %} | expr '!=' expr %{ $$ = new AstNode(AstNodeType.NOT_EQUAL, [$1, $3]); %} | expr '==' expr %{ $$ = new AstNode(AstNodeType.EQUAL, [$1, $3]); %} | expr '?' expr ':' expr %{ $$ = new AstNode(AstNodeType.TERNARY, [$1, $3, $5]); %} ; /* * Constrain the use of arrow functions to function invocations. */ invocation: NAME args %{ $$ = new AstNode(AstNodeType.INVOCATION, [undefined, $args], $NAME); %} | expr '.' NAME args %{ $$ = new AstNode(AstNodeType.INVOCATION, [$expr, $args], $NAME); %} | expr '.' NAME '(' arrow_function ')' %{ { const array = new AstNode(AstNodeType.ARRAY, [$arrow_function]); $$ = new AstNode(AstNodeType.INVOCATION, [$expr, array], $NAME); } %} | expr '.' NAME '(' arrow_function ',' expr ')' %{ { const array = new AstNode(AstNodeType.ARRAY, [$arrow_function, $expr2]); $$ = new AstNode(AstNodeType.INVOCATION, [$expr1, array], $NAME); } %} ; arrow_function: '(' ')' '=>' expr %{ $$ = new AstNode(AstNodeType.ARROW_FUNCTION, [undefined, $expr]); %} | NAME '=>' expr %{ const param = new AstNode(AstNodeType.LITERAL, null, [$NAME]); $$ = new AstNode(AstNodeType.ARROW_FUNCTION, [param, $expr]); %} | '(' params ')' '=>' expr %{ $$ = new AstNode(AstNodeType.ARROW_FUNCTION, [$params, $expr]); %} ; /* * Must be multiple parameters, unfortunately. A single parameter like '(x)' * causes a reduce/reduce conflict with a parenthetical expr with one variable. * This can be solved but requires a custom lexer, e.g. * http://coffeescript.org/v1/annotated-source/lexer.html#section-32 */ params: NAME ',' NAME %{ $$ = new AstNode(AstNodeType.LITERAL, null, [$1, $3]); %} | params ',' NAME %{ $$ = $params; $$.value.push($NAME); %} ; args: '(' ')' %{ $$ = new AstNode(AstNodeType.ARGS, []); %} | '(' array ')' %{ $$ = new AstNode(AstNodeType.ARGS, [$2]); %} ; member_access: expr member %{ $$ = new AstNode(AstNodeType.MEMBER_ACCESS, [$1, $2]); %} ; member: '.' NAME %{ $$ = new AstNode(AstNodeType.MEMBER, null, $2); %} | '[' expr ']' %{ $$ = new AstNode(AstNodeType.MEMBER, [$2]); %} ; variable: NAME %{ $$ = new AstNode(AstNodeType.VARIABLE, null, $1); %} ; literal: primitive %{ $$ = $1; %} | object_literal %{ $$ = $1; %} | array_literal %{ $$ = $1; %} ; primitive: STRING %{ const raw = yytext.substr(1, yyleng - 2); // Since we accept escaped quotation marks, unescape them here. // Note: We can't use $1 directly because of https://github.com/zaach/jison/issues/380. const unescaped = raw.replace(/\\('|")/g, "$" + "1"); // Use JSON.parse() to process special chars e.g. '\n'. // JSON doesn't recognize single-quotes, so use double-quote in // leading/trailing chars and escape double-quote in the string. const parsed = tryParseJson(`"${unescaped.replace(/"/g, '\\"')}"`); this.$ = new AstNode(AstNodeType.LITERAL, null, parsed || unescaped); %} | NUMBER %{ $$ = new AstNode(AstNodeType.LITERAL, null, Number(yytext)); %} | TRUE %{ $$ = new AstNode(AstNodeType.LITERAL, null, true); %} | FALSE %{ $$ = new AstNode(AstNodeType.LITERAL, null, false); %} | NULL %{ $$ = new AstNode(AstNodeType.LITERAL, null, null); %} ; array_literal: '[' ']' %{ $$ = new AstNode(AstNodeType.ARRAY_LITERAL, []); %} | '[' array ']' %{ $$ = new AstNode(AstNodeType.ARRAY_LITERAL, [$2]); %} | '[' array ',' ']' %{ $$ = new AstNode(AstNodeType.ARRAY_LITERAL, [$2]); %} ; array: expr %{ $$ = new AstNode(AstNodeType.ARRAY, [$1]); %} | array ',' expr %{ $$ = $1; $$.args.push($3); %} ; object_literal: '{' '}' %{ $$ = new AstNode(AstNodeType.OBJECT_LITERAL, []); %} | '{' object '}' %{ $$ = new AstNode(AstNodeType.OBJECT_LITERAL, [$object]); %} | '{' object ',' '}' %{ $$ = new AstNode(AstNodeType.OBJECT_LITERAL, [$object]); %} ; object: key_value %{ $$ = new AstNode(AstNodeType.OBJECT, [$key_value]); %} | object ',' key_value %{ $$ = $object; $$.args.push($key_value); %} ; key_value: key ':' expr %{ $$ = new AstNode(AstNodeType.KEY_VALUE, [$key, $expr]); %} ; key: NAME %{ $$ = new AstNode(AstNodeType.LITERAL, null, $NAME); %} | primitive %{ $$ = $primitive; %} | '[' expr ']' /* Computed property name. */ %{ $$ = $expr; %} ;