feat(parser): adds basic expressions to the parser.
Mostly copy pasta from angular.dart. Remove GetterFactory in favor for ClosureMap (which has basically the same implementation).
This commit is contained in:
@ -2,7 +2,8 @@ import {FIELD, int} from 'facade/lang';
|
||||
import {ListWrapper, List} from 'facade/collection';
|
||||
import {Lexer, EOF, Token, $PERIOD} from './lexer';
|
||||
import {ClosureMap} from './closure_map';
|
||||
import {AST, ImplicitReceiver, FieldRead} from './ast';
|
||||
import {AST, ImplicitReceiver, FieldRead, LiteralPrimitive, Expression,
|
||||
Binary, PrefixNot } from './ast';
|
||||
|
||||
var _implicitReceiver = new ImplicitReceiver();
|
||||
|
||||
@ -52,10 +53,115 @@ class _ParseAST {
|
||||
}
|
||||
}
|
||||
|
||||
optionalOperator(op:string):boolean {
|
||||
if (this.next.isOperator(op)) {
|
||||
this.advance();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
parseLogicalOr() {
|
||||
// '||'
|
||||
var result = this.parseLogicalAnd();
|
||||
while (this.optionalOperator('||')) {
|
||||
result = new Binary('||', result, this.parseLogicalAnd());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
parseLogicalAnd() {
|
||||
// '&&'
|
||||
var result = this.parseEquality();
|
||||
while (this.optionalOperator('&&')) {
|
||||
result = new Binary('&&', result, this.parseEquality());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
parseEquality() {
|
||||
// '==','!='
|
||||
var result = this.parseRelational();
|
||||
while (true) {
|
||||
if (this.optionalOperator('==')) {
|
||||
result = new Binary('==', result, this.parseRelational());
|
||||
} else if (this.optionalOperator('!=')) {
|
||||
result = new Binary('!=', result, this.parseRelational());
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parseRelational() {
|
||||
// '<', '>', '<=', '>='
|
||||
var result = this.parseAdditive();
|
||||
while (true) {
|
||||
if (this.optionalOperator('<')) {
|
||||
result = new Binary('<', result, this.parseAdditive());
|
||||
} else if (this.optionalOperator('>')) {
|
||||
result = new Binary('>', result, this.parseAdditive());
|
||||
} else if (this.optionalOperator('<=')) {
|
||||
result = new Binary('<=', result, this.parseAdditive());
|
||||
} else if (this.optionalOperator('>=')) {
|
||||
result = new Binary('>=', result, this.parseAdditive());
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parseAdditive() {
|
||||
// '+', '-'
|
||||
var result = this.parseMultiplicative();
|
||||
while (true) {
|
||||
if (this.optionalOperator('+')) {
|
||||
result = new Binary('+', result, this.parseMultiplicative());
|
||||
} else if (this.optionalOperator('-')) {
|
||||
result = new Binary('-', result, this.parseMultiplicative());
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parseMultiplicative() {
|
||||
// '*', '%', '/', '~/'
|
||||
var result = this.parsePrefix();
|
||||
while (true) {
|
||||
if (this.optionalOperator('*')) {
|
||||
result = new Binary('*', result, this.parsePrefix());
|
||||
} else if (this.optionalOperator('%')) {
|
||||
result = new Binary('%', result, this.parsePrefix());
|
||||
} else if (this.optionalOperator('/')) {
|
||||
result = new Binary('/', result, this.parsePrefix());
|
||||
// TODO(rado): This exists only in Dart, figure out whether to support it.
|
||||
// } else if (this.optionalOperator('~/')) {
|
||||
// result = new BinaryTruncatingDivide(result, this.parsePrefix());
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parsePrefix() {
|
||||
if (this.optionalOperator('+')) {
|
||||
return this.parsePrefix();
|
||||
} else if (this.optionalOperator('-')) {
|
||||
return new Binary('-', new LiteralPrimitive(0), this.parsePrefix());
|
||||
} else if (this.optionalOperator('!')) {
|
||||
return new PrefixNot(this.parsePrefix());
|
||||
} else {
|
||||
return this.parseAccessOrCallMember();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
parseChain():AST {
|
||||
var exprs = [];
|
||||
while (this.index < this.tokens.length) {
|
||||
ListWrapper.push(exprs, this.parseAccess());
|
||||
ListWrapper.push(exprs, this.parseLogicalOr());
|
||||
}
|
||||
return ListWrapper.first(exprs);
|
||||
}
|
||||
@ -68,6 +174,42 @@ class _ParseAST {
|
||||
return result;
|
||||
}
|
||||
|
||||
parseAccessOrCallMember() {
|
||||
var result = this.parsePrimary();
|
||||
// TODO: add missing cases.
|
||||
return result;
|
||||
}
|
||||
|
||||
parsePrimary() {
|
||||
var value;
|
||||
// TODO: add missing cases.
|
||||
|
||||
if (this.next.isKeywordNull() || this.next.isKeywordUndefined()) {
|
||||
this.advance();
|
||||
return new LiteralPrimitive(null);
|
||||
} else if (this.next.isKeywordTrue()) {
|
||||
this.advance();
|
||||
return new LiteralPrimitive(true);
|
||||
} else if (this.next.isKeywordFalse()) {
|
||||
this.advance();
|
||||
return new LiteralPrimitive(false);
|
||||
} else if (this.next.isIdentifier()) {
|
||||
return this.parseAccess();
|
||||
} else if (this.next.isNumber()) {
|
||||
value = this.next.toNumber();
|
||||
this.advance();
|
||||
return new LiteralPrimitive(value);
|
||||
} else if (this.next.isString()) {
|
||||
value = this.next.toString();
|
||||
this.advance();
|
||||
return new LiteralPrimitive(value);
|
||||
} else if (this.index >= this.tokens.length) {
|
||||
throw `Unexpected end of expression: ${this.input}`;
|
||||
} else {
|
||||
throw `Unexpected token ${this.next}`;
|
||||
}
|
||||
}
|
||||
|
||||
parseFieldRead(receiver):AST {
|
||||
var id = this.parseIdentifier();
|
||||
return new FieldRead(receiver, id, this.closureMap.getter(id));
|
||||
@ -78,4 +220,4 @@ class _ParseAST {
|
||||
this.advance();
|
||||
return n.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user