asherkin@263: /* vim: set ts=4 sw=4 tw=99 et: asherkin@263: * asherkin@263: * Copyright (C) 2012 David Anderson asherkin@263: * asherkin@263: * This file is part of SourcePawn. asherkin@263: * asherkin@263: * SourcePawn is free software: you can redistribute it and/or modify it under asherkin@263: * the terms of the GNU General Public License as published by the Free asherkin@263: * Software Foundation, either version 3 of the License, or (at your option) asherkin@263: * any later version. asherkin@263: * asherkin@263: * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY asherkin@263: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS asherkin@263: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. asherkin@263: * asherkin@263: * You should have received a copy of the GNU General Public License along with asherkin@263: * SourcePawn. If not, see http://www.gnu.org/licenses/. asherkin@263: */ asherkin@263: #include asherkin@263: #include "../Zone.h" asherkin@263: #include "../FixedArray.h" asherkin@263: #include "../Heap.h" asherkin@263: #include "../Strings.h" asherkin@263: #include "../TypeManager.h" asherkin@263: #include "Parser.h" asherkin@263: #include "../Heap-inl.h" asherkin@263: asherkin@263: using namespace ke; asherkin@263: asherkin@263: Parser::Parser(Zone *zone, CompileContext &cc, const char *stream, size_t length) asherkin@263: : zone_(zone), asherkin@263: cc_(cc), asherkin@263: pool_(zone_->pool()), asherkin@263: scanner_(cc, stream, length), asherkin@263: unbound_(NULL) asherkin@263: { asherkin@263: unbound_ = new (pool_) PoolList(); asherkin@263: imports_ = new (pool_) PoolList(); asherkin@263: } asherkin@263: asherkin@263: bool asherkin@263: Parser::peek(TokenKind kind) asherkin@263: { asherkin@263: return scanner_.peek() == kind; asherkin@263: } asherkin@263: asherkin@263: bool asherkin@263: Parser::match(TokenKind kind) asherkin@263: { asherkin@263: if (!peek(kind)) asherkin@263: return false; asherkin@263: scanner_.scan(); asherkin@263: return true; asherkin@263: } asherkin@263: asherkin@263: bool asherkin@263: Parser::matchSemicolon() asherkin@263: { asherkin@263: return expect(TOK_SEMICOLON); asherkin@263: } asherkin@263: asherkin@263: bool asherkin@263: Parser::expect(TokenKind kind) asherkin@263: { asherkin@263: TokenKind got = scanner_.scan(); asherkin@263: if (got == kind) asherkin@263: return true; asherkin@263: cc_.reportError(scanner_.begin(), Message_WrongToken, TokenNames[kind], TokenNames[got]); asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: bool asherkin@263: Parser::matchName(String **name, TokenKind kind) asherkin@263: { asherkin@263: assert(kind == TOK_NAME || kind == TOK_LABEL); asherkin@263: *name = NULL; asherkin@263: if (!match(kind)) asherkin@263: return false; asherkin@263: *name = zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()); asherkin@263: return true; asherkin@263: } asherkin@263: asherkin@263: String * asherkin@263: Parser::expectName() asherkin@263: { asherkin@263: if (!expect(TOK_NAME)) asherkin@263: return NULL; asherkin@263: return zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()); asherkin@263: } asherkin@263: asherkin@263: Expression * asherkin@263: Parser::primitive() asherkin@263: { asherkin@263: TokenKind kind = scanner_.peek(); asherkin@263: switch (kind) { asherkin@263: case TOK_FLOAT_LITERAL: asherkin@263: { asherkin@263: scanner_.scan(); asherkin@263: double value = Scanner::ParseDouble(scanner_.literal()); asherkin@263: return new (pool_) FloatLiteral(scanner_.begin(), value); asherkin@263: } asherkin@263: asherkin@263: case TOK_HEX_LITERAL: asherkin@263: { asherkin@263: scanner_.scan(); asherkin@263: int value = strtol(scanner_.literal(), NULL, 16); asherkin@263: return new (pool_) IntegerLiteral(scanner_.begin(), value); asherkin@263: } asherkin@263: asherkin@263: case TOK_INTEGER_LITERAL: asherkin@263: { asherkin@263: scanner_.scan(); asherkin@263: int value = atoi(scanner_.literal()); asherkin@263: return new (pool_) IntegerLiteral(scanner_.begin(), value); asherkin@263: } asherkin@263: asherkin@263: case TOK_TRUE: asherkin@263: case TOK_FALSE: asherkin@263: scanner_.scan(); asherkin@263: return new (pool_) BooleanLiteral(scanner_.begin(), kind); asherkin@263: asherkin@263: case TOK_STRING_LITERAL: asherkin@263: { asherkin@263: scanner_.scan(); asherkin@263: Local string(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length())); asherkin@263: return new (pool_) StringLiteral(scanner_.begin(), string); asherkin@263: } asherkin@263: asherkin@263: default: asherkin@263: { asherkin@263: if (kind != TOK_ERROR) asherkin@263: cc_.reportError(scanner_.begin(), Message_ExpectedExpression, TokenNames[kind]); asherkin@263: return NULL; asherkin@263: } asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: Expression * asherkin@263: Parser::fixedArrayLiteral() asherkin@263: { asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: asherkin@263: ExpressionList *list = new (pool_) ExpressionList(); asherkin@263: do { asherkin@263: // { } is an illegal array literal. asherkin@263: if (list->length() > 0 && match(TOK_LBRACE)) asherkin@263: break; asherkin@263: asherkin@263: Expression *expr = NULL; asherkin@263: if (peek(TOK_LBRACE)) asherkin@263: expr = fixedArrayLiteral(); asherkin@263: else asherkin@263: expr = primitive(); asherkin@263: if (!expr) asherkin@263: return NULL; asherkin@263: asherkin@263: if (!list->append(expr)) asherkin@263: return NULL; asherkin@263: asherkin@263: if (!match(TOK_COMMA)) { asherkin@263: if (!expect(TOK_RBRACE)) asherkin@263: return NULL; asherkin@263: break; asherkin@263: } asherkin@263: } while (true); asherkin@263: asherkin@263: return new (pool_) ArrayLiteral(pos, TOK_LBRACE, list); asherkin@263: } asherkin@263: asherkin@263: Expression * asherkin@263: Parser::prefix() asherkin@263: { asherkin@263: switch (scanner_.peek()) { asherkin@263: case TOK_LPAREN: asherkin@263: { asherkin@263: scanner_.scan(); asherkin@263: Expression *expr = expression(); asherkin@263: if (!expr) asherkin@263: return NULL; asherkin@263: if (!expect(TOK_RPAREN)) asherkin@263: return NULL; asherkin@263: return expr; asherkin@263: } asherkin@263: asherkin@263: case TOK_NAME: asherkin@263: { asherkin@263: Local name(zone_, expectName()); asherkin@263: if (!name) asherkin@263: return NULL; asherkin@263: return new (pool_) NameProxy(scanner_.begin(), name); asherkin@263: } asherkin@263: asherkin@263: default: asherkin@263: return primitive(); asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: // Parses only old-style declarations. asherkin@263: bool asherkin@263: Parser::typeAndName(Expression **type, String **namep) asherkin@263: { asherkin@263: if (match(TOK_LABEL)) { asherkin@263: // Old-style declaration: asherkin@263: // new X:type asherkin@263: Local name(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length())); asherkin@263: if (!name) asherkin@263: return false; asherkin@263: asherkin@263: *type = new (pool_) NameProxy(scanner_.begin(), name); asherkin@263: *namep = expectName(); asherkin@263: return !!*namep; asherkin@263: } asherkin@263: asherkin@263: *type = NULL; asherkin@263: *namep = expectName(); asherkin@263: asherkin@263: return !!*namep; asherkin@263: } asherkin@263: asherkin@263: // Parses both old and new style declarations. asherkin@263: bool asherkin@263: Parser::fullTypeAndName(Expression **type, String **namep, DeclKind kind) asherkin@263: { asherkin@263: // decl ::= newdecl | olddecl asherkin@263: // newdecl ::= Type Ident asherkin@263: // olddecl ::= Label? (Ident | "...") asherkin@263: // type ::= Ident asherkin@263: // label ::= Ident ":" asherkin@263: // asherkin@263: if (match(TOK_LABEL)) { asherkin@263: // We something of the form: asherkin@263: // Label Ident asherkin@263: // or: Label "..." asherkin@263: Local name(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length())); asherkin@263: if (!name) asherkin@263: return false; asherkin@263: asherkin@263: *type = new (pool_) NameProxy(scanner_.begin(), name); asherkin@263: if (kind == DeclArg && match(TOK_ELLIPSES)) { asherkin@263: *namep = NULL; asherkin@263: } else { asherkin@263: if ((*namep = expectName()) == NULL) asherkin@263: return false; asherkin@263: } asherkin@263: return true; asherkin@263: } asherkin@263: asherkin@263: Local name(zone_, expectName()); asherkin@263: if (!name) asherkin@263: return false; asherkin@263: asherkin@263: if (peek(TOK_NAME) || (kind == DeclArg && peek(TOK_ELLIPSES))) { asherkin@263: // We got something of the form: asherkin@263: // Ident Ident asherkin@263: *type = new (pool_) NameProxy(scanner_.begin(), name); asherkin@263: if (peek(TOK_NAME)) { asherkin@263: if ((*namep = expectName()) == NULL) asherkin@263: return false; asherkin@263: } else { asherkin@263: *namep = NULL; asherkin@263: } asherkin@263: return true; asherkin@263: } asherkin@263: asherkin@263: // We got something of the form: asherkin@263: // Ident asherkin@263: *type = NULL; asherkin@263: *namep = name; asherkin@263: return true; asherkin@263: } asherkin@263: asherkin@263: Expression * asherkin@263: Parser::call(Expression *callee) asherkin@263: { asherkin@263: ExpressionList *arguments = new (pool_) ExpressionList(); asherkin@263: asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: expect(TOK_LPAREN); asherkin@263: asherkin@263: if (!match(TOK_RPAREN)) { asherkin@263: while (true) { asherkin@263: Expression *expr = expression(); asherkin@263: if (!expr) asherkin@263: return NULL; asherkin@263: asherkin@263: if (!arguments->append(expr)) asherkin@263: return NULL; asherkin@263: asherkin@263: if (!match(TOK_COMMA)) asherkin@263: break; asherkin@263: } asherkin@263: asherkin@263: if (!expect(TOK_RPAREN)) asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: return new (pool_) CallExpression(pos, callee, arguments); asherkin@263: } asherkin@263: asherkin@263: Expression * asherkin@263: Parser::index(Expression *left) asherkin@263: { asherkin@263: expect(TOK_LBRACKET); asherkin@263: asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: Expression *expr = expression(); asherkin@263: if (!expr) asherkin@263: return NULL; asherkin@263: asherkin@263: if (!expect(TOK_RBRACKET)) asherkin@263: return NULL; asherkin@263: asherkin@263: return new (pool_) IndexExpression(pos, left, expr); asherkin@263: } asherkin@263: asherkin@263: Expression * asherkin@263: Parser::field(Expression *left) asherkin@263: { asherkin@263: expect(TOK_DOT); asherkin@263: asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: Local name(zone_, expectName()); asherkin@263: if (!name) asherkin@263: return NULL; asherkin@263: asherkin@263: return new (pool_) FieldExpression(pos, left, name); asherkin@263: } asherkin@263: asherkin@263: Expression * asherkin@263: Parser::primary() asherkin@263: { asherkin@263: Expression *expr = prefix(); asherkin@263: if (!expr) asherkin@263: return NULL; asherkin@263: asherkin@263: for (;;) { asherkin@263: switch (scanner_.peek()) { asherkin@263: case TOK_LPAREN: asherkin@263: if ((expr = call(expr)) == NULL) asherkin@263: return NULL; asherkin@263: break; asherkin@263: asherkin@263: case TOK_LBRACKET: asherkin@263: if ((expr = index(expr)) == NULL) asherkin@263: return NULL; asherkin@263: break; asherkin@263: asherkin@263: case TOK_DOT: asherkin@263: if ((expr = field(expr)) == NULL) asherkin@263: return NULL; asherkin@263: break; asherkin@263: asherkin@263: default: asherkin@263: return expr; asherkin@263: } asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: Expression * asherkin@263: Parser::unary() asherkin@263: { asherkin@263: TokenKind token = scanner_.peek(); asherkin@263: asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: switch (token) { asherkin@263: case TOK_INCREMENT: asherkin@263: case TOK_DECREMENT: asherkin@263: { asherkin@263: scanner_.scan(); asherkin@263: Expression *expr = unary(); asherkin@263: if (!expr) asherkin@263: return NULL; asherkin@263: return new (pool_) IncDecExpression(pos, token, expr, false); asherkin@263: } asherkin@263: asherkin@263: case TOK_MINUS: asherkin@263: case TOK_NOT: asherkin@263: case TOK_TILDE: asherkin@263: { asherkin@263: scanner_.scan(); asherkin@263: Expression *expr = unary(); asherkin@263: if (!expr) asherkin@263: return NULL; asherkin@263: return new (pool_) UnaryExpression(pos, token, expr); asherkin@263: } asherkin@263: asherkin@263: case TOK_SIZEOF: asherkin@263: { asherkin@263: scanner_.scan(); asherkin@263: if (!expect(TOK_LPAREN)) asherkin@263: return NULL; asherkin@263: Expression *expr = unary(); asherkin@263: if (!expr) asherkin@263: return NULL; asherkin@263: if (!expect(TOK_RPAREN)) asherkin@263: return NULL; asherkin@263: return new (pool_) UnaryExpression(pos, token, expr); asherkin@263: } asherkin@263: asherkin@263: case TOK_LABEL: asherkin@263: { asherkin@263: scanner_.scan(); asherkin@263: Local tag(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length())); asherkin@263: if (!tag) asherkin@263: return NULL; asherkin@263: asherkin@263: NameProxy *proxy = new (pool_) NameProxy(scanner_.begin(), tag); asherkin@263: asherkin@263: Expression *expr = unary(); asherkin@263: if (!expr) asherkin@263: return NULL; asherkin@263: asherkin@263: return new (pool_) UnaryExpression(pos, TOK_LABEL, expr, proxy); asherkin@263: } asherkin@263: asherkin@263: default: asherkin@263: break; asherkin@263: } asherkin@263: asherkin@263: Expression *expr = primary(); asherkin@263: asherkin@263: token = scanner_.peek(); asherkin@263: if (token == TOK_INCREMENT || token == TOK_DECREMENT) { asherkin@263: scanner_.scan(); asherkin@263: return new (pool_) IncDecExpression(pos, token, expr, true); asherkin@263: } asherkin@263: asherkin@263: return expr; asherkin@263: } asherkin@263: asherkin@263: Expression * asherkin@263: Parser::multiplication() asherkin@263: { asherkin@263: Expression *left = unary(); asherkin@263: do { asherkin@263: if (!match(TOK_SLASH) && !match(TOK_STAR) && !match(TOK_PERCENT)) asherkin@263: break; asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: TokenKind kind = scanner_.last(); asherkin@263: Expression *right = unary(); asherkin@263: if (!right) asherkin@263: return NULL; asherkin@263: left = new (pool_) BinaryExpression(pos, kind, left, right); asherkin@263: } while (left); asherkin@263: return left; asherkin@263: } asherkin@263: asherkin@263: Expression * asherkin@263: Parser::addition() asherkin@263: { asherkin@263: Expression *left = multiplication(); asherkin@263: while (left) { asherkin@263: if (!match(TOK_PLUS) && !match(TOK_MINUS)) asherkin@263: break; asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: TokenKind kind = scanner_.last(); asherkin@263: Expression *right = multiplication(); asherkin@263: if (!right) asherkin@263: return NULL; asherkin@263: left = new (pool_) BinaryExpression(pos, kind, left, right); asherkin@263: } asherkin@263: return left; asherkin@263: } asherkin@263: asherkin@263: Expression * asherkin@263: Parser::shift() asherkin@263: { asherkin@263: Expression *left = addition(); asherkin@263: while (left) { asherkin@263: if (!match(TOK_SHL) && !match(TOK_SHR) && !match(TOK_USHR)) asherkin@263: break; asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: TokenKind kind = scanner_.last(); asherkin@263: Expression *right = addition(); asherkin@263: if (!right) asherkin@263: return NULL; asherkin@263: left = new (pool_) BinaryExpression(pos, kind, left, right); asherkin@263: } asherkin@263: return left; asherkin@263: } asherkin@263: asherkin@263: Expression * asherkin@263: Parser::bitand_() asherkin@263: { asherkin@263: Expression *left = shift(); asherkin@263: while (left) { asherkin@263: if (!match(TOK_BITAND)) asherkin@263: break; asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: Expression *right = shift(); asherkin@263: if (!right) asherkin@263: return NULL; asherkin@263: left = new (pool_) BinaryExpression(pos, TOK_BITAND, left, right); asherkin@263: } asherkin@263: return left; asherkin@263: } asherkin@263: asherkin@263: Expression * asherkin@263: Parser::bitxor() asherkin@263: { asherkin@263: Expression *left = bitand_(); asherkin@263: while (left) { asherkin@263: if (!match(TOK_BITXOR)) asherkin@263: break; asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: Expression *right = shift(); asherkin@263: if (!right) asherkin@263: return NULL; asherkin@263: left = new (pool_) BinaryExpression(pos, TOK_BITXOR, left, right); asherkin@263: } asherkin@263: return left; asherkin@263: } asherkin@263: asherkin@263: Expression * asherkin@263: Parser::bitor_() asherkin@263: { asherkin@263: Expression *left = bitxor(); asherkin@263: while (left) { asherkin@263: if (!match(TOK_BITOR)) asherkin@263: break; asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: Expression *right = bitxor(); asherkin@263: if (!right) asherkin@263: return NULL; asherkin@263: left = new (pool_) BinaryExpression(pos, TOK_BITOR, left, right); asherkin@263: } asherkin@263: return left; asherkin@263: } asherkin@263: asherkin@263: Expression * asherkin@263: Parser::relational() asherkin@263: { asherkin@263: Expression *left = bitor_(); asherkin@263: while (left) { asherkin@263: TokenKind kind = scanner_.peek(); asherkin@263: if (kind < TOK_LT || kind > TOK_GE) asherkin@263: break; asherkin@263: scanner_.scan(); asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: Expression *right = shift(); asherkin@263: if (!right) asherkin@263: return NULL; asherkin@263: left = new (pool_) BinaryExpression(pos, kind, left, right); asherkin@263: } asherkin@263: return left; asherkin@263: } asherkin@263: asherkin@263: Expression * asherkin@263: Parser::equals() asherkin@263: { asherkin@263: Expression *left = relational(); asherkin@263: while (left) { asherkin@263: if (!match(TOK_EQUALS) && !match(TOK_NOTEQUALS)) asherkin@263: break; asherkin@263: TokenKind kind = scanner_.last(); asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: Expression *right = relational(); asherkin@263: if (!right) asherkin@263: return NULL; asherkin@263: left = new (pool_) BinaryExpression(pos, kind, left, right); asherkin@263: } asherkin@263: return left; asherkin@263: } asherkin@263: asherkin@263: Expression * asherkin@263: Parser::and_() asherkin@263: { asherkin@263: Expression *left = equals(); asherkin@263: while (left) { asherkin@263: if (!match(TOK_AND)) asherkin@263: break; asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: Expression *right = equals(); asherkin@263: if (!right) asherkin@263: return NULL; asherkin@263: left = new (pool_) BinaryExpression(pos, TOK_AND, left, right); asherkin@263: } asherkin@263: return left; asherkin@263: } asherkin@263: asherkin@263: Expression * asherkin@263: Parser::or_() asherkin@263: { asherkin@263: Expression *left = and_(); asherkin@263: while (left) { asherkin@263: if (!match(TOK_OR)) asherkin@263: break; asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: Expression *right = and_(); asherkin@263: if (!right) asherkin@263: return NULL; asherkin@263: left = new (pool_) BinaryExpression(pos, TOK_OR, left, right); asherkin@263: } asherkin@263: return left; asherkin@263: } asherkin@263: asherkin@263: Expression * asherkin@263: Parser::ternary() asherkin@263: { asherkin@263: Expression *cond = or_(); asherkin@263: if (!cond) asherkin@263: return NULL; asherkin@263: asherkin@263: if (!match(TOK_QMARK)) asherkin@263: return cond; asherkin@263: asherkin@263: Expression *left; asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: AutoAllowTags disableTags(scanner_); asherkin@263: { asherkin@263: if ((left = expression()) == NULL) asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: if (!expect(TOK_COLON)) asherkin@263: return NULL; asherkin@263: asherkin@263: Expression *right = expression(); asherkin@263: if (!right) asherkin@263: return NULL; asherkin@263: asherkin@263: return new (pool_) TernaryExpression(pos, cond, left, right); asherkin@263: } asherkin@263: asherkin@263: Expression * asherkin@263: Parser::assignment() asherkin@263: { asherkin@263: Expression *left = ternary(); asherkin@263: while (left) { asherkin@263: TokenKind token = scanner_.peek(); asherkin@263: if (token != TOK_ASSIGN && (token < TOK_ASSIGN_ADD || token > TOK_ASSIGN_SHL)) asherkin@263: break; asherkin@263: scanner_.scan(); asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: Expression *expr = ternary(); asherkin@263: if (!expr) asherkin@263: return NULL; asherkin@263: asherkin@263: left = new (pool_) Assignment(pos, token, left, expr); asherkin@263: } asherkin@263: return left; asherkin@263: } asherkin@263: asherkin@263: Expression * asherkin@263: Parser::expression() asherkin@263: { asherkin@263: return assignment(); asherkin@263: } asherkin@263: asherkin@263: Statement * asherkin@263: Parser::while_() asherkin@263: { asherkin@263: // while ::= "while" "(" expr ")" statement asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: scanner_.scan(); asherkin@263: asherkin@263: if (!expect(TOK_LPAREN)) asherkin@263: return NULL; asherkin@263: asherkin@263: Expression *condition = expression(); asherkin@263: if (!condition) asherkin@263: return NULL; asherkin@263: asherkin@263: if (!expect(TOK_RPAREN)) asherkin@263: return NULL; asherkin@263: asherkin@263: Statement *body; asherkin@263: if (scanner_.peek() == TOK_LBRACE) asherkin@263: body = block(); asherkin@263: else asherkin@263: body = localStatement(); asherkin@263: if (!body) asherkin@263: return NULL; asherkin@263: asherkin@263: return new (pool_) WhileStatement(pos, TOK_WHILE, condition, body); asherkin@263: } asherkin@263: asherkin@263: Statement * asherkin@263: Parser::do_() asherkin@263: { asherkin@263: // do ::= "do" block "while" "(" expr ")" asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: scanner_.scan(); asherkin@263: asherkin@263: Statement *body = block(); asherkin@263: if (!body) asherkin@263: return NULL; asherkin@263: asherkin@263: if (!expect(TOK_WHILE)) asherkin@263: return NULL; asherkin@263: asherkin@263: if (!expect(TOK_LPAREN)) asherkin@263: return NULL; asherkin@263: Expression *condition = expression(); asherkin@263: if (!condition) asherkin@263: return NULL; asherkin@263: if (!expect(TOK_RPAREN)) asherkin@263: return NULL; asherkin@263: asherkin@263: return new (pool_) WhileStatement(pos, TOK_DO, condition, body); asherkin@263: } asherkin@263: asherkin@263: Statement * asherkin@263: Parser::switch_() asherkin@263: { asherkin@263: // switch ::= "switch" "(" expr ")" "{" case* defaultcase? "}" asherkin@263: // case ::= "case" casevals ":" statement asherkin@263: // defaultcase ::= "default" ":" statement asherkin@263: // asherkin@263: expect(TOK_SWITCH); asherkin@263: asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: asherkin@263: if (!expect(TOK_LPAREN)) asherkin@263: return NULL; asherkin@263: Expression *expr = expression(); asherkin@263: if (!expr) asherkin@263: return NULL; asherkin@263: if (!expect(TOK_RPAREN)) asherkin@263: return NULL; asherkin@263: asherkin@263: if (!expect(TOK_LBRACE)) asherkin@263: return NULL; asherkin@263: asherkin@263: SourcePosition defaultPos; asherkin@263: PoolList *cases = new (pool_) PoolList(); asherkin@263: asherkin@263: Statement *defaultCase = NULL; asherkin@263: asherkin@263: while (!peek(TOK_RBRACE)) { asherkin@263: Expression *expr = NULL; asherkin@263: ExpressionList *others = NULL; asherkin@263: if (match(TOK_DEFAULT)) { asherkin@263: if (defaultCase) { asherkin@263: cc_.reportError(scanner_.begin(), Message_OneDefaultPerSwitch); asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: defaultPos = scanner_.begin(); asherkin@263: } else { asherkin@263: if (defaultCase) { asherkin@263: cc_.reportError(defaultPos, Message_DefaultMustBeLastCase); asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: if (!expect(TOK_CASE)) asherkin@263: return NULL; asherkin@263: asherkin@263: // A limitation in the grammar is that |case :| will be asherkin@263: // detected as a label. asherkin@263: AutoAllowTags disableTags(scanner_); asherkin@263: asherkin@263: if ((expr = expression()) == NULL) asherkin@263: return NULL; asherkin@263: asherkin@263: if (peek(TOK_COMMA)) { asherkin@263: others = new (pool_) ExpressionList(); asherkin@263: while (match(TOK_COMMA)) { asherkin@263: Expression *other = expression(); asherkin@263: if (!other) asherkin@263: return NULL; asherkin@263: if (!others->append(other)) asherkin@263: return NULL; asherkin@263: } asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: if (!expect(TOK_COLON)) asherkin@263: return NULL; asherkin@263: asherkin@263: Statement *statement = localStatement(); asherkin@263: if (!statement) asherkin@263: return NULL; asherkin@263: asherkin@263: if (!peek(TOK_CASE) && asherkin@263: !peek(TOK_DEFAULT) && asherkin@263: !peek(TOK_RBRACE)) asherkin@263: { asherkin@263: cc_.reportError(scanner_.begin(), Message_SingleStatementPerCase); asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: if (expr) { asherkin@263: Case *caze = new (pool_) Case(expr, others, statement); asherkin@263: if (!cases->append(caze)) asherkin@263: return NULL; asherkin@263: } else { asherkin@263: defaultCase = statement; asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: if (!expect(TOK_RBRACE)) asherkin@263: return NULL; asherkin@263: asherkin@263: return new (pool_) SwitchStatement(pos, expr, cases, defaultCase); asherkin@263: } asherkin@263: asherkin@263: Statement * asherkin@263: Parser::forStatement() asherkin@263: { asherkin@263: // for ::= "for" "(" forinit? ";" forcond? ";" forstep ")" statement asherkin@263: // forint ::= "new" vardecl | asherkin@263: // exprstmt asherkin@263: // forcond ::= expr asherkin@263: // forstep ::= exprstmt asherkin@263: // asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: scanner_.scan(); asherkin@263: if (!expect(TOK_LPAREN)) asherkin@263: return NULL; asherkin@263: asherkin@263: Statement *decl = NULL; asherkin@263: if (!match(TOK_SEMICOLON)) { asherkin@263: if (match(TOK_NEW)) { asherkin@263: if ((decl = vars(TypeQual_None)) == NULL) asherkin@263: return NULL; asherkin@263: } else { asherkin@263: if ((decl = expressionStatement()) == NULL) asherkin@263: return NULL; asherkin@263: } asherkin@263: if (!expect(TOK_SEMICOLON)) asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: Expression *condition = NULL; asherkin@263: if (!match(TOK_SEMICOLON)) { asherkin@263: if ((condition = expression()) == NULL) asherkin@263: return NULL; asherkin@263: if (!expect(TOK_SEMICOLON)) asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: Statement *update = NULL; asherkin@263: if (!match(TOK_RPAREN)) { asherkin@263: if ((update = expressionStatement()) == NULL) asherkin@263: return NULL; asherkin@263: if (!expect(TOK_RPAREN)) asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: Statement *body; asherkin@263: if (scanner_.peek() == TOK_LBRACE) asherkin@263: body = block(); asherkin@263: else asherkin@263: body = localStatement(); asherkin@263: if (!body) asherkin@263: return NULL; asherkin@263: asherkin@263: return new (pool_) ForStatement(pos, decl, condition, update, body); asherkin@263: } asherkin@263: asherkin@263: ExpressionList * asherkin@263: Parser::dimensions() asherkin@263: { asherkin@263: // dimensions ::= ("[" expr? "]")* asherkin@263: asherkin@263: ExpressionList *postDimensions = new (pool_) ExpressionList(); asherkin@263: while (match(TOK_LBRACKET)) { asherkin@263: Expression *dim = NULL; asherkin@263: if (!match(TOK_RBRACKET)) { asherkin@263: if ((dim = expression()) == NULL) asherkin@263: return NULL; asherkin@263: if (!expect(TOK_RBRACKET)) asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: if (!postDimensions->append(dim)) asherkin@263: return NULL; asherkin@263: } asherkin@263: return postDimensions; asherkin@263: } asherkin@263: asherkin@263: VariableDeclaration * asherkin@263: Parser::var(TypeQualifiers qual) asherkin@263: { asherkin@263: // vardecl ::= decl ("=" expr)? asherkin@263: asherkin@263: Expression *type; asherkin@263: Local name(zone_); asherkin@263: asherkin@263: if (!typeAndName(&type, name.ref())) asherkin@263: return NULL; asherkin@263: asherkin@263: ExpressionList *dims = NULL; asherkin@263: if (peek(TOK_LBRACKET)) { asherkin@263: if ((dims = dimensions()) == NULL) asherkin@263: return NULL;; asherkin@263: } asherkin@263: asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: asherkin@263: Expression *expr = NULL; asherkin@263: if (match(TOK_ASSIGN)) { asherkin@263: switch (scanner_.peek()) { asherkin@263: // Note: we don't support [] literals yet. asherkin@263: case TOK_LBRACE: asherkin@263: scanner_.scan(); asherkin@263: if ((expr = fixedArrayLiteral()) == NULL) asherkin@263: return NULL; asherkin@263: break; asherkin@263: asherkin@263: default: asherkin@263: if ((expr = expression()) == NULL) asherkin@263: return NULL; asherkin@263: break; asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: return new (pool_) VariableDeclaration(pos, qual, name, type, dims, expr); asherkin@263: } asherkin@263: asherkin@263: Statement * asherkin@263: Parser::vars(TypeQualifiers qual) asherkin@263: { asherkin@263: // localvars ::= ("new" | "const" | "decl") vardecl ("," vardecl)* asherkin@263: // globalvars ::= ("public" | "const" | "new" | "public" "const") vardecl asherkin@263: VariableDeclaration *decl = var(qual); asherkin@263: if (!decl) asherkin@263: return NULL; asherkin@263: asherkin@263: if (!peek(TOK_COMMA)) asherkin@263: return decl; asherkin@263: asherkin@263: StatementList *statements = new (pool_) StatementList(); asherkin@263: if (!statements->append(decl)) asherkin@263: return NULL; asherkin@263: asherkin@263: while (match(TOK_COMMA)) { asherkin@263: Statement *decl = var(qual); asherkin@263: if (!decl) asherkin@263: return NULL; asherkin@263: if (!statements->append(decl)) asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: // Create a fake-o block with no scope to create a statement list. asherkin@263: return new (pool_) BlockStatement(decl->pos(), statements, TOK_NEW); asherkin@263: } asherkin@263: asherkin@263: Statement * asherkin@263: Parser::returnStatement() asherkin@263: { asherkin@263: // return ::= "return" term | asherkin@263: // "return" "expr" asherkin@263: asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: if (!expect(TOK_RETURN)) asherkin@263: return NULL; asherkin@263: asherkin@263: Expression *expr = NULL; asherkin@263: if (scanner_.peek() != TOK_SEMICOLON) { asherkin@263: if ((expr = expression()) == NULL) asherkin@263: return NULL; asherkin@263: asherkin@263: // We only care about non-void returns when determining whether a asherkin@263: // tagless function is non-void. asherkin@263: encounteredReturn_ = true; asherkin@263: } asherkin@263: asherkin@263: return new (pool_) ReturnStatement(pos, expr); asherkin@263: } asherkin@263: asherkin@263: Statement * asherkin@263: Parser::expressionStatement() asherkin@263: { asherkin@263: // exprstmt ::= expr asherkin@263: Expression *left = assignment(); asherkin@263: if (!left) asherkin@263: return NULL; asherkin@263: asherkin@263: return new (pool_) ExpressionStatement(left); asherkin@263: } asherkin@263: asherkin@263: Statement * asherkin@263: Parser::block() asherkin@263: { asherkin@263: // block ::= "{" statement* "}" asherkin@263: asherkin@263: if (!expect(TOK_LBRACE)) asherkin@263: return NULL; asherkin@263: asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: asherkin@263: StatementList *statements = new (pool_) StatementList(); asherkin@263: while (!match(TOK_RBRACE)) { asherkin@263: Statement *statement = localStatement(); asherkin@263: if (statement == NULL) asherkin@263: return NULL; asherkin@263: if (!statements->append(statement)) asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: BlockStatement *block = new (pool_) BlockStatement(pos, statements, TOK_LBRACE); asherkin@263: return block; asherkin@263: } asherkin@263: asherkin@263: Statement * asherkin@263: Parser::if_() asherkin@263: { asherkin@263: // if ::= "if" "(" expr ")" statement elseif* else? asherkin@263: // elseif ::= "elseif" "(" expr ")" statement asherkin@263: // else ::= "else" statement asherkin@263: expect(TOK_IF); asherkin@263: asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: if (!expect(TOK_LPAREN)) asherkin@263: return NULL; asherkin@263: asherkin@263: Expression *cond = expression(); asherkin@263: if (!cond) asherkin@263: return NULL; asherkin@263: asherkin@263: if (!expect(TOK_RPAREN)) asherkin@263: return NULL; asherkin@263: asherkin@263: Statement *ifTrue = localStatement(); asherkin@263: if (!ifTrue) asherkin@263: return NULL; asherkin@263: asherkin@263: IfStatement *outer = new (pool_) IfStatement(pos, cond, ifTrue); asherkin@263: asherkin@263: IfStatement *last = outer; asherkin@263: while (match(TOK_ELSE)) { asherkin@263: if (!match(TOK_IF)) { asherkin@263: Statement *ifFalse = localStatement(); asherkin@263: if (!ifFalse) asherkin@263: return NULL; asherkin@263: asherkin@263: last->setIfFalse(ifFalse); asherkin@263: break; asherkin@263: } asherkin@263: asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: if (!expect(TOK_LPAREN)) asherkin@263: return NULL; asherkin@263: asherkin@263: Expression *otherCond = expression(); asherkin@263: if (!otherCond) asherkin@263: return NULL; asherkin@263: asherkin@263: if (!expect(TOK_RPAREN)) asherkin@263: return NULL; asherkin@263: asherkin@263: Statement *otherIfTrue = localStatement(); asherkin@263: if (!otherIfTrue) asherkin@263: return NULL; asherkin@263: asherkin@263: IfStatement *inner = new (pool_) IfStatement(pos, otherCond, otherIfTrue); asherkin@263: last->setIfFalse(inner); asherkin@263: last = inner; asherkin@263: } asherkin@263: asherkin@263: return outer; asherkin@263: } asherkin@263: asherkin@263: Statement * asherkin@263: Parser::localStatement() asherkin@263: { asherkin@263: // statement ::= stmt term asherkin@263: // stmt ::= do | for | if | while | struct | enum | asherkin@263: // localvars | return | switch | break | continue asherkin@263: asherkin@263: Statement *statement = NULL; asherkin@263: asherkin@263: // Statements which must be followed by a semicolon will break out of the asherkin@263: // switch. If they may end in BlockStatements, they'll immediately return. asherkin@263: asherkin@263: TokenKind kind = scanner_.peek(); asherkin@263: switch (kind) { asherkin@263: case TOK_CONST: asherkin@263: case TOK_NEW: asherkin@263: { asherkin@263: TypeQualifiers quals = (kind == TOK_CONST) asherkin@263: ? TypeQual_Const asherkin@263: : TypeQual_None; asherkin@263: scanner_.scan(); asherkin@263: if ((statement = vars(quals)) == NULL) asherkin@263: return NULL; asherkin@263: break; asherkin@263: } asherkin@263: asherkin@263: case TOK_FOR: asherkin@263: return forStatement(); asherkin@263: asherkin@263: case TOK_WHILE: asherkin@263: return while_(); asherkin@263: asherkin@263: case TOK_BREAK: asherkin@263: scanner_.scan(); asherkin@263: statement = new (pool_) BreakStatement(scanner_.begin()); asherkin@263: break; asherkin@263: asherkin@263: case TOK_CONTINUE: asherkin@263: scanner_.scan(); asherkin@263: statement = new (pool_) ContinueStatement(scanner_.begin()); asherkin@263: break; asherkin@263: asherkin@263: case TOK_DO: asherkin@263: if ((statement = do_()) == NULL) asherkin@263: return NULL; asherkin@263: break; asherkin@263: asherkin@263: case TOK_RETURN: asherkin@263: if ((statement = returnStatement()) == NULL) asherkin@263: return NULL; asherkin@263: break; asherkin@263: asherkin@263: case TOK_ENUM: asherkin@263: if ((statement = enum_(TOK_NONE)) == NULL) asherkin@263: return NULL; asherkin@263: break; asherkin@263: asherkin@263: case TOK_STRUCT: asherkin@263: if ((statement = struct_()) == NULL) asherkin@263: return NULL; asherkin@263: break; asherkin@263: asherkin@263: case TOK_SWITCH: asherkin@263: return switch_(); asherkin@263: asherkin@263: case TOK_IF: asherkin@263: return if_(); asherkin@263: asherkin@263: case TOK_LBRACE: asherkin@263: return block(); asherkin@263: asherkin@263: default: asherkin@263: break; asherkin@263: } asherkin@263: asherkin@263: if (!statement) { asherkin@263: if ((statement = expressionStatement()) == NULL) asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: if (!expect(TOK_SEMICOLON)) asherkin@263: return NULL; asherkin@263: asherkin@263: return statement; asherkin@263: } asherkin@263: asherkin@263: Statement * asherkin@263: Parser::struct_() asherkin@263: { asherkin@263: // struct ::= "struct" name { struct_fields } asherkin@263: // struct_fields ::= struct_field | asherkin@263: // struct_field struct_fields asherkin@263: // struct_field ::= label? name term asherkin@263: expect(TOK_STRUCT); asherkin@263: asherkin@263: Local name(zone_, expectName()); asherkin@263: if (!name) asherkin@263: return NULL; asherkin@263: asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: asherkin@263: if (!expect(TOK_LBRACE)) asherkin@263: return NULL; asherkin@263: asherkin@263: FieldList *fields = new (pool_) FieldList(); asherkin@263: asherkin@263: while (!peek(TOK_RBRACE)) { asherkin@263: Expression *type; asherkin@263: Local fieldName(zone_); asherkin@263: asherkin@263: if (!fullTypeAndName(&type, fieldName.ref(), DeclField)) asherkin@263: return NULL; asherkin@263: asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: asherkin@263: if (!matchSemicolon()) asherkin@263: return NULL; asherkin@263: asherkin@263: StructureStatement::Field *field = asherkin@263: new (pool_) StructureStatement::Field(pos, type, fieldName); asherkin@263: if (!field || !fields->append(field)) asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: if (!expect(TOK_RBRACE)) asherkin@263: return NULL; asherkin@263: asherkin@263: if (fields->empty()) { asherkin@263: cc_.reportError(pos, Message_StructCantBeEmpty); asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: return new (pool_) StructureStatement(pos, name, fields); asherkin@263: } asherkin@263: asherkin@263: Statement * asherkin@263: Parser::enum_(TokenKind kind) asherkin@263: { asherkin@263: // enum ::= "enum" name? { enum_members? } asherkin@263: // enum_members ::= enum_member ","? | asherkin@263: // enum_member "," enum_members asherkin@263: // enum_member ::= ident ("=" constexpr)? asherkin@263: expect(TOK_ENUM); asherkin@263: asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: asherkin@263: Local name(zone_); asherkin@263: if (matchName(name.ref()) && !name) asherkin@263: return NULL; asherkin@263: asherkin@263: EnumStatement::EntryList *entries = new (pool_) EnumStatement::EntryList(); asherkin@263: asherkin@263: if (!expect(TOK_LBRACE)) asherkin@263: return NULL; asherkin@263: asherkin@263: do { asherkin@263: if (scanner_.peek() == TOK_RBRACE) asherkin@263: break; asherkin@263: asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: Local name(zone_, expectName()); asherkin@263: if (!name) asherkin@263: return NULL; asherkin@263: asherkin@263: Expression *expr = NULL; asherkin@263: if (match(TOK_ASSIGN)) { asherkin@263: if ((expr = expression()) == NULL) asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: if (!entries->append(EnumStatement::Entry(name, expr, pos))) asherkin@263: return NULL; asherkin@263: } while (match(TOK_COMMA)); asherkin@263: if (!expect(TOK_RBRACE)) asherkin@263: return NULL; asherkin@263: asherkin@263: return new (pool_) EnumStatement(pos, kind, name, entries); asherkin@263: } asherkin@263: asherkin@263: template asherkin@263: static inline ScopedRoot * asherkin@263: NewScopedRoot(PoolAllocator &pool, Handle obj) asherkin@263: { asherkin@263: return new (pool) ScopedRoot(obj); asherkin@263: } asherkin@263: asherkin@263: ImportStatement * asherkin@263: Parser::import(TokenKind kind) asherkin@263: { asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: asherkin@263: // import ::= "from" import_path "import" import_names asherkin@263: // | "import" import_path asherkin@263: // | "import" import_path ".*" asherkin@263: // import_path ::= name asherkin@263: // | name "." import_path asherkin@263: // import_names ::= "*" asherkin@263: // | import_name_list asherkin@263: // import_name_list ::= name asherkin@263: // | name "," import_name_list asherkin@263: asherkin@263: Local name(zone_, expectName()); asherkin@263: if (!name) asherkin@263: return NULL; asherkin@263: asherkin@263: PathComponent *root = new (pool_) PathComponent(NewScopedRoot(pool_, name), NULL); asherkin@263: PathComponent *current = root; asherkin@263: asherkin@263: // NULL namelist means that we do not import any names. An empty namelist asherkin@263: // means we import all names. asherkin@263: NameList *names = NULL; asherkin@263: asherkin@263: while (match(TOK_DOT)) { asherkin@263: if (kind == TOK_IMPORT && match(TOK_STAR)) { asherkin@263: names = new (pool_) NameList(); asherkin@263: break; asherkin@263: } asherkin@263: asherkin@263: if ((name = expectName()) == NULL) asherkin@263: return NULL; asherkin@263: asherkin@263: current->next = new (pool_) PathComponent(NewScopedRoot(pool_, name), NULL); asherkin@263: current = current->next; asherkin@263: } asherkin@263: asherkin@263: if (kind == TOK_FROM) { asherkin@263: if (!expect(TOK_IMPORT)) asherkin@263: return NULL; asherkin@263: asherkin@263: names = new (pool_) NameList(); asherkin@263: asherkin@263: if (!match(TOK_STAR)) { asherkin@263: if (!matchName(name.address())) { asherkin@263: cc_.reportError(scanner_.begin(), Message_BadImportFrom); asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: if (!name || !names->append(NewScopedRoot(pool_, name))) asherkin@263: return NULL; asherkin@263: asherkin@263: while (match(TOK_COMMA)) { asherkin@263: if ((name = expectName()) == NULL) asherkin@263: return NULL; asherkin@263: if (!names->append(NewScopedRoot(pool_, name))) asherkin@263: return NULL; asherkin@263: } asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: return new (pool_) ImportStatement(pos, root, names); asherkin@263: } asherkin@263: asherkin@263: Statement * asherkin@263: Parser::function(TokenKind token) asherkin@263: { asherkin@263: Expression *returnType; asherkin@263: Local name(zone_); asherkin@263: asherkin@263: if (!fullTypeAndName(&returnType, name.ref(), DeclFun)) asherkin@263: return NULL; asherkin@263: asherkin@263: SourcePosition pos = scanner_.begin(); asherkin@263: ParameterList *parameters = new (pool_) ParameterList(); asherkin@263: asherkin@263: if (!expect(TOK_LPAREN)) asherkin@263: return NULL; asherkin@263: asherkin@263: bool variadic = false; asherkin@263: asherkin@263: if (!match(TOK_RPAREN)) { asherkin@263: while (true) { asherkin@263: TypeQualifiers quals = TypeQual_None; asherkin@263: if (match(TOK_CONST)) asherkin@263: quals = TypeQualifiers(quals | TypeQual_Const); asherkin@263: asherkin@263: bool ref = match(TOK_AMPERSAND); asherkin@263: asherkin@263: SourcePosition begin = scanner_.begin(); asherkin@263: Expression *type; asherkin@263: Local name(zone_); asherkin@263: if (!fullTypeAndName(&type, name.ref(), DeclArg)) asherkin@263: return NULL; asherkin@263: asherkin@263: if (!name) { asherkin@263: if ((quals & TypeQual_Const) || ref) { asherkin@263: cc_.reportError(begin, Message_InvalidVarArgs); asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: if (token != TOK_NATIVE) { asherkin@263: cc_.reportError(begin, Message_VarArgsOutsideNative); asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: variadic = true; asherkin@263: break; asherkin@263: } asherkin@263: asherkin@263: ExpressionList *dims = NULL; asherkin@263: if (peek(TOK_LBRACKET)) { asherkin@263: if ((dims = dimensions()) == NULL) asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: Expression *expr = NULL; asherkin@263: if (match(TOK_ASSIGN)) { asherkin@263: if ((expr = expression()) == NULL) asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: Parameter *parameter = new (pool_) Parameter(name, type, ref, quals, dims, expr, begin); asherkin@263: if (!parameters->append(parameter)) asherkin@263: return NULL; asherkin@263: asherkin@263: if (!match(TOK_COMMA)) asherkin@263: break; asherkin@263: } asherkin@263: if (!expect(TOK_RPAREN)) asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: encounteredReturn_ = false; asherkin@263: asherkin@263: Statement *body = NULL; asherkin@263: if (token != TOK_FORWARD && token != TOK_NATIVE && token != TOK_TYPEDEF) { asherkin@263: body = block(); asherkin@263: if (!body) asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: FunctionSignature signature(returnType, parameters, variadic); asherkin@263: if (token == TOK_TYPEDEF) asherkin@263: return new (pool_) FunctionTypeStatement(pos, name, signature); asherkin@263: asherkin@263: return new (pool_) FunctionStatement(pos, name, token, body, signature, encounteredReturn_); asherkin@263: } asherkin@263: asherkin@263: static inline bool asherkin@263: DeclareIntrinsicType(Zone *zone, Scope *scope, const char *name, Handle type) asherkin@263: { asherkin@263: Local tag(zone, zone->makeSymbol(name)); asherkin@263: if (!tag) asherkin@263: return false; asherkin@263: asherkin@263: assert(false); asherkin@263: return false; //return !!scope->declareType(tag, type); asherkin@263: } asherkin@263: asherkin@263: static inline bool asherkin@263: DeclareIntrinsicType(Zone *zone, Scope *scope, const char *name, PrimitiveType type) asherkin@263: { asherkin@263: Local primitive(zone, zone->types()->getPrimitive(type)); asherkin@263: assert(primitive); asherkin@263: return DeclareIntrinsicType(zone, scope, name, primitive); asherkin@263: } asherkin@263: asherkin@263: ParseTree * asherkin@263: Parser::parse() asherkin@263: { asherkin@263: StatementList *statements = new (pool_) StatementList(); asherkin@263: asherkin@263: for (;;) { asherkin@263: Statement *statement = NULL; asherkin@263: asherkin@263: TokenKind kind = scanner_.peek(); asherkin@263: switch (kind) { asherkin@263: case TOK_ERROR: asherkin@263: return NULL; asherkin@263: asherkin@263: case TOK_EOF: asherkin@263: break; asherkin@263: asherkin@263: case TOK_NAME: asherkin@263: if ((statement = function(TOK_NAME)) == NULL) asherkin@263: return NULL; asherkin@263: break; asherkin@263: asherkin@263: case TOK_FROM: asherkin@263: case TOK_IMPORT: asherkin@263: { asherkin@263: scanner_.scan(); asherkin@263: if (statements->length()) asherkin@263: cc_.reportError(scanner_.begin(), Message_ImportsMustBeFirst); asherkin@263: ImportStatement *stmt = import(kind); asherkin@263: if (!stmt) asherkin@263: return NULL; asherkin@263: if (!imports_->append(stmt)) asherkin@263: return NULL; asherkin@263: if (!matchSemicolon()) asherkin@263: return NULL; asherkin@263: continue; asherkin@263: } asherkin@263: asherkin@263: case TOK_FORWARD: asherkin@263: case TOK_PUBLIC: asherkin@263: case TOK_NATIVE: asherkin@263: case TOK_STOCK: asherkin@263: case TOK_LABEL: asherkin@263: case TOK_TYPEDEF: asherkin@263: { asherkin@263: if (kind != TOK_LABEL) asherkin@263: scanner_.scan(); asherkin@263: if (kind == TOK_PUBLIC && peek(TOK_CONST)) { asherkin@263: if ((statement = var(TypeQual_Const)) == NULL) asherkin@263: return NULL; asherkin@263: if (!matchSemicolon()) asherkin@263: return NULL; asherkin@263: } else if (kind == TOK_PUBLIC && peek(TOK_ENUM)) { asherkin@263: if ((statement = enum_(kind)) == NULL) asherkin@263: return NULL; asherkin@263: if (!matchSemicolon()) asherkin@263: return NULL; asherkin@263: } else { asherkin@263: if ((statement = function(kind)) == NULL) asherkin@263: return NULL; asherkin@263: if ((kind == TOK_FORWARD || kind == TOK_NATIVE || kind == TOK_TYPEDEF) && !matchSemicolon()) asherkin@263: return NULL; asherkin@263: } asherkin@263: break; asherkin@263: } asherkin@263: asherkin@263: case TOK_CONST: asherkin@263: case TOK_NEW: asherkin@263: { asherkin@263: TypeQualifiers quals = (kind == TOK_CONST) ? TypeQual_Const : TypeQual_None; asherkin@263: // Note: at global scope, we don't accept comma-delimited asherkin@263: // declarations yet, to see if we can get away with forcing asherkin@263: // a nicer top-level style. asherkin@263: scanner_.scan(); asherkin@263: if ((statement = var(quals)) == NULL) asherkin@263: return NULL; asherkin@263: if (!matchSemicolon()) asherkin@263: return NULL; asherkin@263: break; asherkin@263: } asherkin@263: asherkin@263: case TOK_ENUM: asherkin@263: if ((statement = enum_(TOK_NONE)) == NULL) asherkin@263: return NULL; asherkin@263: if (!matchSemicolon()) asherkin@263: return NULL; asherkin@263: break; asherkin@263: asherkin@263: case TOK_STRUCT: asherkin@263: if ((statement = struct_()) == NULL) asherkin@263: return NULL; asherkin@263: if (!matchSemicolon()) asherkin@263: return NULL; asherkin@263: break; asherkin@263: asherkin@263: default: asherkin@263: cc_.reportError(scanner_.begin(), Message_ExpectedGlobal); asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: if (!statement) asherkin@263: break; asherkin@263: asherkin@263: if (!statements->append(statement)) asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: return new (pool_) ParseTree(statements, unbound_, imports_); asherkin@263: } asherkin@263: asherkin@263: class AstPrinter : public AstVisitor asherkin@263: { asherkin@263: FILE *fp_; asherkin@263: size_t level_; asherkin@263: asherkin@263: private: asherkin@263: void prefix() { asherkin@263: for (size_t i = 0; i < level_; i++) asherkin@263: fprintf(fp_, " "); asherkin@263: } asherkin@263: void indent() { asherkin@263: level_++; asherkin@263: } asherkin@263: void unindent() { asherkin@263: level_--; asherkin@263: } asherkin@263: asherkin@263: public: asherkin@263: AstPrinter(FILE *fp) asherkin@263: : fp_(fp), asherkin@263: level_(0) asherkin@263: { asherkin@263: } asherkin@263: asherkin@263: void dump(const FunctionSignature &sig) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "()\n"); asherkin@263: } asherkin@263: void visitNameProxy(NameProxy *name) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ NameProxy (%s)\n", name->name()->chars()); asherkin@263: } asherkin@263: void visitCallExpression(CallExpression *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ CallExpression\n"); asherkin@263: indent(); asherkin@263: node->callee()->accept(this); asherkin@263: for (size_t i = 0; i < node->arguments()->length(); i++) asherkin@263: node->arguments()->at(i)->accept(this); asherkin@263: unindent(); asherkin@263: } asherkin@263: void visitFunctionTypeStatement(FunctionTypeStatement *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ FunctionTypeStatement (%s)\n", node->name()->chars()); asherkin@263: indent(); asherkin@263: dump(node->signature()); asherkin@263: unindent(); asherkin@263: } asherkin@263: void visitFunctionStatement(FunctionStatement *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ FunctionStatement (%s)\n", node->name()->chars()); asherkin@263: indent(); asherkin@263: dump(node->signature()); asherkin@263: if (node->body()) asherkin@263: node->body()->accept(this); asherkin@263: unindent(); asherkin@263: } asherkin@263: void visitExpressionStatement(ExpressionStatement *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ ExpressionStatement\n"); asherkin@263: indent(); asherkin@263: node->expression()->accept(this); asherkin@263: unindent(); asherkin@263: } asherkin@263: void visitAssignment(Assignment *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ Assignment\n"); asherkin@263: indent(); asherkin@263: node->lvalue()->accept(this); asherkin@263: node->expression()->accept(this); asherkin@263: unindent(); asherkin@263: } asherkin@263: void visitTernaryExpression(TernaryExpression *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ TernaryExpression\n"); asherkin@263: indent(); asherkin@263: node->condition()->accept(this); asherkin@263: node->left()->accept(this); asherkin@263: node->right()->accept(this); asherkin@263: unindent(); asherkin@263: } asherkin@263: void visitBinaryExpression(BinaryExpression *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ BinaryExpression (%s)\n", TokenNames[node->token()]); asherkin@263: indent(); asherkin@263: node->left()->accept(this); asherkin@263: node->right()->accept(this); asherkin@263: unindent(); asherkin@263: } asherkin@263: void visitUnaryExpression(UnaryExpression *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ UnaryExpression (%s)\n", TokenNames[node->token()]); asherkin@263: indent(); asherkin@263: node->expression()->accept(this); asherkin@263: unindent(); asherkin@263: } asherkin@263: void visitReturnStatement(ReturnStatement *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ ReturnStatement\n"); asherkin@263: indent(); asherkin@263: if (node->expression()) asherkin@263: node->expression()->accept(this); asherkin@263: unindent(); asherkin@263: } asherkin@263: void visitForStatement(ForStatement *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ ForStatement\n"); asherkin@263: indent(); asherkin@263: if (node->initialization()) asherkin@263: node->initialization()->accept(this); asherkin@263: if (node->condition()) asherkin@263: node->condition()->accept(this); asherkin@263: if (node->update()) asherkin@263: node->update()->accept(this); asherkin@263: node->body()->accept(this); asherkin@263: unindent(); asherkin@263: } asherkin@263: void visitBlockStatement(BlockStatement *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ BlockStatement\n"); asherkin@263: indent(); asherkin@263: for (size_t i = 0; i < node->statements()->length(); i++) asherkin@263: node->statements()->at(i)->accept(this); asherkin@263: unindent(); asherkin@263: } asherkin@263: void visitVariableDeclaration(VariableDeclaration *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ VariableDeclaration (%s)\n", node->name()->chars()); asherkin@263: indent(); asherkin@263: if (node->initialization()) asherkin@263: node->initialization()->accept(this); asherkin@263: unindent(); asherkin@263: } asherkin@263: void visitIntegerLiteral(IntegerLiteral *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ IntegerLiteral (%d)\n", node->value()); asherkin@263: } asherkin@263: void visitBooleanLiteral(BooleanLiteral *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ BooleanLiteral (%s)\n", asherkin@263: (node->token() == TOK_TRUE) ? "true" : "false"); asherkin@263: } asherkin@263: void visitFloatLiteral(FloatLiteral *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ FloatLiteral (%f)\n", node->value()); asherkin@263: } asherkin@263: void visitIfStatement(IfStatement *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ IfStatement\n"); asherkin@263: indent(); asherkin@263: node->ifTrue()->accept(this); asherkin@263: if (node->ifFalse()) asherkin@263: node->ifFalse()->accept(this); asherkin@263: unindent(); asherkin@263: } asherkin@263: void visitIndexExpression(IndexExpression *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ IndexExpression\n"); asherkin@263: indent(); asherkin@263: node->left()->accept(this); asherkin@263: node->right()->accept(this); asherkin@263: unindent(); asherkin@263: } asherkin@263: void visitEnumStatement(EnumStatement *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ EnumStatement (%s)\n", node->name() ? node->name()->chars() : ""); asherkin@263: indent(); asherkin@263: for (size_t i = 0; i < node->entries()->length(); i++) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "%s =\n", node->entries()->at(i).name->chars()); asherkin@263: if (node->entries()->at(i).expr) { asherkin@263: indent(); asherkin@263: node->entries()->at(i).expr->accept(this); asherkin@263: unindent(); asherkin@263: } asherkin@263: } asherkin@263: unindent(); asherkin@263: } asherkin@263: void visitWhileStatement(WhileStatement *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ WhileStatement (%s)\n", asherkin@263: (node->token() == TOK_DO) ? "do" : "while"); asherkin@263: indent(); asherkin@263: if (node->token() == TOK_DO) { asherkin@263: node->condition()->accept(this); asherkin@263: node->body()->accept(this); asherkin@263: } else { asherkin@263: node->condition()->accept(this); asherkin@263: node->body()->accept(this); asherkin@263: } asherkin@263: unindent(); asherkin@263: } asherkin@263: void visitBreakStatement(BreakStatement *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ BreakStatement\n"); asherkin@263: } asherkin@263: void visitContinueStatement(ContinueStatement *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ ContinueStatement\n"); asherkin@263: } asherkin@263: void visitStringLiteral(StringLiteral *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ StringLiteral\n"); asherkin@263: } asherkin@263: void visitIncDecExpression(IncDecExpression *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ IncDecExpression (postfix=%d)\n", node->postfix()); asherkin@263: indent(); asherkin@263: node->expression()->accept(this); asherkin@263: unindent(); asherkin@263: } asherkin@263: void visitStructureStatement(StructureStatement *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ StructureStatement %s\n", node->name()->chars()); asherkin@263: } asherkin@263: void visitFieldExpression(FieldExpression *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ FieldExpression %s\n", node->field()->chars()); asherkin@263: indent(); asherkin@263: node->left()->accept(this); asherkin@263: unindent(); asherkin@263: } asherkin@263: void visitSwitchStatement(SwitchStatement *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ SwitchStatement\n"); asherkin@263: indent(); asherkin@263: node->expression()->accept(this); asherkin@263: for (size_t i = 0; i < node->cases()->length(); i++) { asherkin@263: Case *c = node->cases()->at(i); asherkin@263: c->expression()->accept(this); asherkin@263: if (c->others()) { asherkin@263: for (size_t j = 0; j < c->others()->length(); j++) asherkin@263: c->others()->at(j)->accept(this); asherkin@263: } asherkin@263: indent(); asherkin@263: c->statement()->accept(this); asherkin@263: unindent(); asherkin@263: } asherkin@263: if (node->defaultCase()) asherkin@263: node->defaultCase()->accept(this); asherkin@263: unindent(); asherkin@263: } asherkin@263: void visitArrayLiteral(ArrayLiteral *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ ArrayLiteral\n"); asherkin@263: indent(); asherkin@263: for (size_t i = 0; i < node->expressions()->length(); i++) { asherkin@263: Expression *expr = node->expressions()->at(i); asherkin@263: indent(); asherkin@263: expr->accept(this); asherkin@263: unindent(); asherkin@263: } asherkin@263: } asherkin@263: void visitImportStatement(ImportStatement *node) { asherkin@263: prefix(); asherkin@263: fprintf(fp_, "[ ImportStatement\n"); asherkin@263: } asherkin@263: }; asherkin@263: asherkin@263: void asherkin@263: ParseTree::dump(FILE *fp) asherkin@263: { asherkin@263: AstPrinter printer(fp); asherkin@263: asherkin@263: for (size_t i = 0; i < statements_->length(); i++) asherkin@263: statements_->at(i)->accept(&printer); asherkin@263: }