Commit 88a2c6fc by Tobias Skarhed Committed by Torkel Ödegaard

Graphite: Refactor lexer and parser (#17958)

parent 9b468cae
......@@ -898,7 +898,7 @@ const unicodeLetterTable = [
195101,
];
const identifierStartTable = [];
const identifierStartTable: any[] = [];
for (let i = 0; i < 128; i++) {
identifierStartTable[i] =
......@@ -922,24 +922,28 @@ for (let i = 0; i < 128; i++) {
const identifierPartTable = identifierStartTable;
export function Lexer(this: any, expression) {
this.input = expression;
this.char = 1;
this.from = 1;
}
export class Lexer {
input: any;
char: number;
from: number;
constructor(expression: any) {
this.input = expression;
this.char = 1;
this.from = 1;
}
Lexer.prototype = {
peek: function(i) {
peek(i?: number) {
return this.input.charAt(i || 0);
},
}
skip: function(i) {
skip(i?: number) {
i = i || 1;
this.char += i;
this.input = this.input.slice(i);
},
}
tokenize: function() {
tokenize() {
const list = [];
let token = this.next();
while (token) {
......@@ -947,9 +951,9 @@ Lexer.prototype = {
token = this.next();
}
return list;
},
}
next: function() {
next() {
this.from = this.char;
// Move to the next non-space character.
......@@ -979,9 +983,9 @@ Lexer.prototype = {
// No token could be matched, give up.
return null;
},
}
scanTemplateSequence: function() {
scanTemplateSequence() {
if (this.peek() === '[' && this.peek(1) === '[') {
return {
type: 'templateStart',
......@@ -999,7 +1003,7 @@ Lexer.prototype = {
}
return null;
},
}
/*
* Extract a JavaScript identifier out of the next sequence of
......@@ -1007,7 +1011,7 @@ Lexer.prototype = {
* to Identifier this method can also produce BooleanLiteral
* (true/false) and NullLiteral (null).
*/
scanIdentifier: function() {
scanIdentifier() {
let id = '';
let index = 0;
let type, char;
......@@ -1020,7 +1024,7 @@ Lexer.prototype = {
// Both approach and unicodeLetterTable were borrowed from
// Google's Traceur.
function isUnicodeLetter(code) {
function isUnicodeLetter(code: number) {
for (let i = 0; i < unicodeLetterTable.length; ) {
if (code < unicodeLetterTable[i++]) {
return false;
......@@ -1034,7 +1038,7 @@ Lexer.prototype = {
return false;
}
function isHexDigit(str) {
function isHexDigit(str: string) {
return /^[0-9a-fA-F]$/.test(str);
}
......@@ -1157,7 +1161,7 @@ Lexer.prototype = {
value: id,
pos: this.char,
};
},
}
/*
* Extract a numeric literal out of the next sequence of
......@@ -1168,26 +1172,26 @@ Lexer.prototype = {
* This method's implementation was heavily influenced by the
* scanNumericLiteral function in the Esprima parser's source code.
*/
scanNumericLiteral: function(): any {
scanNumericLiteral(): any {
let index = 0;
let value = '';
const length = this.input.length;
let char = this.peek(index);
let bad;
function isDecimalDigit(str) {
function isDecimalDigit(str: string) {
return /^[0-9]$/.test(str);
}
function isOctalDigit(str) {
function isOctalDigit(str: string) {
return /^[0-7]$/.test(str);
}
function isHexDigit(str) {
function isHexDigit(str: string) {
return /^[0-9a-fA-F]$/.test(str);
}
function isIdentifierStart(ch) {
function isIdentifierStart(ch: string) {
return ch === '$' || ch === '_' || ch === '\\' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
}
......@@ -1369,9 +1373,9 @@ Lexer.prototype = {
pos: this.char,
isMalformed: !isFinite(+value),
};
},
}
isPunctuator: ch1 => {
isPunctuator(ch1: string) {
switch (ch1) {
case '.':
case '(':
......@@ -1383,9 +1387,9 @@ Lexer.prototype = {
}
return false;
},
}
scanPunctuator: function() {
scanPunctuator() {
const ch1 = this.peek();
if (this.isPunctuator(ch1)) {
......@@ -1397,7 +1401,7 @@ Lexer.prototype = {
}
return null;
},
}
/*
* Extract a string out of the next sequence of characters and/or
......@@ -1410,7 +1414,7 @@ Lexer.prototype = {
* var str = "hello\
* world";
*/
scanStringLiteral: function() {
scanStringLiteral() {
/*jshint loopfunc:true */
const quote = this.peek();
......@@ -1451,5 +1455,5 @@ Lexer.prototype = {
quote: quote,
pos: this.char,
};
},
};
}
}
import { Lexer } from './lexer';
export function Parser(this: any, expression) {
this.expression = expression;
this.lexer = new Lexer(expression);
this.tokens = this.lexer.tokenize();
this.index = 0;
}
Parser.prototype = {
getAst: function() {
export class Parser {
expression: any;
lexer: Lexer;
tokens: any;
index: number;
constructor(expression: any) {
this.expression = expression;
this.lexer = new Lexer(expression);
this.tokens = this.lexer.tokenize();
this.index = 0;
}
getAst() {
return this.start();
},
}
start: function() {
start() {
try {
return this.functionCall() || this.metricExpression();
} catch (e) {
......@@ -22,9 +27,9 @@ Parser.prototype = {
pos: e.pos,
};
}
},
}
curlyBraceSegment: function() {
curlyBraceSegment() {
if (this.match('identifier', '{') || this.match('{')) {
let curlySegment = '';
......@@ -51,9 +56,9 @@ Parser.prototype = {
} else {
return null;
}
},
}
metricSegment: function() {
metricSegment() {
const curly = this.curlyBraceSegment();
if (curly) {
return curly;
......@@ -97,14 +102,14 @@ Parser.prototype = {
this.consumeToken();
return node;
},
}
metricExpression: function() {
metricExpression() {
if (!this.match('templateStart') && !this.match('identifier') && !this.match('number') && !this.match('{')) {
return null;
}
const node = {
const node: any = {
type: 'metric',
segments: [],
};
......@@ -123,9 +128,9 @@ Parser.prototype = {
}
return node;
},
}
functionCall: function() {
functionCall() {
if (!this.match('identifier', '(')) {
return null;
}
......@@ -147,9 +152,9 @@ Parser.prototype = {
this.consumeToken();
return node;
},
}
boolExpression: function() {
boolExpression() {
if (!this.match('bool')) {
return null;
}
......@@ -158,9 +163,9 @@ Parser.prototype = {
type: 'bool',
value: this.consumeToken().value === 'true',
};
},
}
functionParameters: function() {
functionParameters(): any {
if (this.match(')') || this.match('')) {
return [];
}
......@@ -179,9 +184,9 @@ Parser.prototype = {
this.consumeToken();
return [param].concat(this.functionParameters());
},
}
seriesRefExpression: function() {
seriesRefExpression() {
if (!this.match('identifier')) {
return null;
}
......@@ -197,9 +202,9 @@ Parser.prototype = {
type: 'series-ref',
value: token.value,
};
},
}
numericLiteral: function() {
numericLiteral() {
if (!this.match('number')) {
return null;
}
......@@ -208,9 +213,9 @@ Parser.prototype = {
type: 'number',
value: parseFloat(this.consumeToken().value),
};
},
}
stringLiteral: function() {
stringLiteral() {
if (!this.match('string')) {
return null;
}
......@@ -224,29 +229,29 @@ Parser.prototype = {
type: 'string',
value: token.value,
};
},
}
errorMark: function(text) {
errorMark(text: string) {
const currentToken = this.tokens[this.index];
const type = currentToken ? currentToken.type : 'end of string';
throw {
message: text + ' instead found ' + type,
pos: currentToken ? currentToken.pos : this.lexer.char,
};
},
}
// returns token value and incre
consumeToken: function() {
consumeToken() {
this.index++;
return this.tokens[this.index - 1];
},
}
matchToken: function(type, index) {
matchToken(type: any, index: number) {
const token = this.tokens[this.index + index];
return (token === undefined && type === '') || (token && token.type === type);
},
}
match: function(token1, token2) {
match(token1: any, token2?: any) {
return this.matchToken(token1, 0) && (!token2 || this.matchToken(token2, 1));
},
};
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment