diff -r b029d63565a2 -r c1ba166f3fc4 src/Parser.cpp --- a/src/Parser.cpp Mon Sep 17 00:10:01 2012 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1846 +0,0 @@ -/* vim: set ts=4 sw=4 tw=99 et: - * - * Copyright (C) 2012 David Anderson - * - * This file is part of SourcePawn. - * - * SourcePawn is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) - * any later version. - * - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * SourcePawn. If not, see http://www.gnu.org/licenses/. - */ -#include -#include "Zone.h" -#include "Parser.h" -#include "FixedArray.h" -#include "Heap.h" -#include "Strings.h" -#include "TypeManager.h" -#include "Heap-inl.h" - -using namespace ke; - -Parser::Parser(Zone *zone, CompileContext &cc, const char *stream, size_t length) - : zone_(zone), - cc_(cc), - pool_(zone_->pool()), - scanner_(cc, stream, length), - scope_(NULL), - unbound_(NULL) -{ - unbound_ = new (pool_) PoolList(); -} - -bool -Parser::peek(TokenKind kind) -{ - return scanner_.peek() == kind; -} - -bool -Parser::match(TokenKind kind) -{ - if (!peek(kind)) - return false; - scanner_.scan(); - return true; -} - -bool -Parser::matchSemicolon() -{ - return expect(TOK_SEMICOLON); -} - -bool -Parser::expect(TokenKind kind) -{ - TokenKind got = scanner_.scan(); - if (got == kind) - return true; - cc_.reportError(scanner_.begin(), Message_WrongToken, TokenNames[kind], TokenNames[got]); - return false; -} - -Scope * -Parser::enterScope(Scope::Kind kind) -{ - scope_ = new (pool_) Scope(pool_, kind, scope_); - if (!scope_->initialize()) - return NULL; - return scope_; -} - -NameProxy * -Parser::bind(Handle name) -{ - BoundName *bound = scope_->lookup(name); - NameProxy *proxy = new (pool_) NameProxy(scanner_.begin(), name, bound); - if (!bound && !unbound_->append(proxy)) - return NULL; - return proxy; -} - -BoundName * -Parser::bindType(Handle name) -{ - if (BoundName *binding = scope_->lookup(name)) - return binding; - - return new (pool_) UnboundName(scope_, name); -} - -bool -Parser::matchName(String **name, TokenKind kind) -{ - assert(kind == TOK_NAME || kind == TOK_LABEL); - *name = NULL; - if (!match(kind)) - return false; - *name = zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()); - return true; -} - -String * -Parser::expectName() -{ - if (!expect(TOK_NAME)) - return NULL; - return zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()); -} - -void -Parser::redeclarationError(BoundName *other) -{ - cc_.reportError(scanner_.begin(), Message_RedeclaredName, other->name()->chars(), - other->pos().line, other->pos().col); -} - -Expression * -Parser::primitive() -{ - TokenKind kind = scanner_.peek(); - switch (kind) { - case TOK_FLOAT_LITERAL: - { - scanner_.scan(); - double value = Scanner::ParseDouble(scanner_.literal()); - return new (pool_) FloatLiteral(scanner_.begin(), value); - } - - case TOK_HEX_LITERAL: - { - scanner_.scan(); - int value = strtol(scanner_.literal(), NULL, 16); - return new (pool_) IntegerLiteral(scanner_.begin(), value); - } - - case TOK_INTEGER_LITERAL: - { - scanner_.scan(); - int value = atoi(scanner_.literal()); - return new (pool_) IntegerLiteral(scanner_.begin(), value); - } - - case TOK_TRUE: - case TOK_FALSE: - scanner_.scan(); - return new (pool_) BooleanLiteral(scanner_.begin(), kind); - - case TOK_STRING_LITERAL: - { - scanner_.scan(); - Local array(zone_, ByteArray::New(zone_, scanner_.literal_length() + 1)); - if (!array) - return NULL; - memcpy(array->raw(), scanner_.literal(), scanner_.literal_length() + 1); - return new (pool_) StringLiteral(scanner_.begin(), array); - } - - default: - { - if (kind != TOK_ERROR) - cc_.reportError(scanner_.begin(), Message_ExpectedExpression, TokenNames[kind]); - return NULL; - } - } -} - -Expression * -Parser::arrayLiteral(TokenKind kind) -{ - assert(kind == TOK_LBRACE || kind == TOK_LBRACKET); - - TokenKind close = (kind == TOK_LBRACE) - ? TOK_RBRACE - : TOK_RBRACKET; - - SourcePosition pos = scanner_.begin(); - - ExpressionList *list = new (pool_) ExpressionList(); - do { - if (match(close)) - break; - - Expression *expr = NULL; - if (kind == TOK_LBRACE) { - if (peek(TOK_LBRACE)) - expr = arrayLiteral(TOK_LBRACE); - else - expr = primitive(); - } else { - expr = expression(); - } - if (!expr) - return NULL; - - if (!list->append(expr)) - return NULL; - - if (!match(TOK_COMMA)) { - if (!expect(close)) - return NULL; - break; - } - } while (true); - - return new (pool_) ArrayLiteral(pos, kind, list); -} - -Expression * -Parser::prefix() -{ - switch (scanner_.peek()) { - case TOK_LPAREN: - { - scanner_.scan(); - Expression *expr = expression(); - if (!expr) - return NULL; - if (!expect(TOK_RPAREN)) - return NULL; - return expr; - } - - case TOK_NAME: - { - Local name(zone_, expectName()); - if (!name) - return NULL; - return bind(name); - } - - default: - return primitive(); - } -} - -Expression * -Parser::call(Expression *callee) -{ - ExpressionList *arguments = new (pool_) ExpressionList(); - - SourcePosition pos = scanner_.begin(); - expect(TOK_LPAREN); - - if (!match(TOK_RPAREN)) { - while (true) { - Expression *expr = expression(); - if (!expr) - return NULL; - - if (!arguments->append(expr)) - return NULL; - - if (!match(TOK_COMMA)) - break; - } - - if (!expect(TOK_RPAREN)) - return NULL; - } - - return new (pool_) CallExpression(pos, callee, arguments); -} - -Expression * -Parser::index(Expression *left) -{ - expect(TOK_LBRACKET); - - SourcePosition pos = scanner_.begin(); - Expression *expr = expression(); - if (!expr) - return NULL; - - if (!expect(TOK_RBRACKET)) - return NULL; - - return new (pool_) IndexExpression(pos, left, expr); -} - -Expression * -Parser::field(Expression *left) -{ - expect(TOK_DOT); - - SourcePosition pos = scanner_.begin(); - Local name(zone_, expectName()); - if (!name) - return NULL; - - return new (pool_) FieldExpression(pos, left, name); -} - -Expression * -Parser::primary() -{ - Expression *expr = prefix(); - if (!expr) - return NULL; - - for (;;) { - switch (scanner_.peek()) { - case TOK_LPAREN: - if ((expr = call(expr)) == NULL) - return NULL; - break; - - case TOK_LBRACKET: - if ((expr = index(expr)) == NULL) - return NULL; - break; - - case TOK_DOT: - if ((expr = field(expr)) == NULL) - return NULL; - break; - - default: - return expr; - } - } -} - -Expression * -Parser::unary() -{ - TokenKind token = scanner_.peek(); - - SourcePosition pos = scanner_.begin(); - switch (token) { - case TOK_INCREMENT: - case TOK_DECREMENT: - { - scanner_.scan(); - Expression *expr = unary(); - if (!expr) - return NULL; - return new (pool_) IncDecExpression(pos, token, expr, false); - } - - case TOK_MINUS: - case TOK_NOT: - case TOK_TILDE: - { - scanner_.scan(); - Expression *expr = unary(); - if (!expr) - return NULL; - return new (pool_) UnaryExpression(pos, token, expr); - } - - case TOK_SIZEOF: - { - scanner_.scan(); - if (!expect(TOK_LPAREN)) - return NULL; - Expression *expr = unary(); - if (!expr) - return NULL; - if (!expect(TOK_RPAREN)) - return NULL; - return new (pool_) UnaryExpression(pos, token, expr); - } - - case TOK_LABEL: - { - scanner_.scan(); - Local tag(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length())); - if (!tag) - return NULL; - - BoundName *type = NULL; - if (tag) - type = bindType(tag); - - Expression *expr = unary(); - if (!expr) - return NULL; - - return new (pool_) UnaryExpression(pos, TOK_LABEL, expr, type); - } - - default: - break; - } - - Expression *expr = primary(); - - token = scanner_.peek(); - if (token == TOK_INCREMENT || token == TOK_DECREMENT) { - scanner_.scan(); - return new (pool_) IncDecExpression(pos, token, expr, true); - } - - return expr; -} - -Expression * -Parser::multiplication() -{ - Expression *left = unary(); - do { - if (!match(TOK_SLASH) && !match(TOK_STAR) && !match(TOK_PERCENT)) - break; - SourcePosition pos = scanner_.begin(); - TokenKind kind = scanner_.last(); - Expression *right = unary(); - if (!right) - return NULL; - left = new (pool_) BinaryExpression(pos, kind, left, right); - } while (left); - return left; -} - -Expression * -Parser::addition() -{ - Expression *left = multiplication(); - while (left) { - if (!match(TOK_PLUS) && !match(TOK_MINUS)) - break; - SourcePosition pos = scanner_.begin(); - TokenKind kind = scanner_.last(); - Expression *right = multiplication(); - if (!right) - return NULL; - left = new (pool_) BinaryExpression(pos, kind, left, right); - } - return left; -} - -Expression * -Parser::shift() -{ - Expression *left = addition(); - while (left) { - if (!match(TOK_SHL) && !match(TOK_SHR) && !match(TOK_USHR)) - break; - SourcePosition pos = scanner_.begin(); - TokenKind kind = scanner_.last(); - Expression *right = addition(); - if (!right) - return NULL; - left = new (pool_) BinaryExpression(pos, kind, left, right); - } - return left; -} - -Expression * -Parser::bitand_() -{ - Expression *left = shift(); - while (left) { - if (!match(TOK_BITAND)) - break; - SourcePosition pos = scanner_.begin(); - Expression *right = shift(); - if (!right) - return NULL; - left = new (pool_) BinaryExpression(pos, TOK_BITAND, left, right); - } - return left; -} - -Expression * -Parser::bitxor() -{ - Expression *left = bitand_(); - while (left) { - if (!match(TOK_BITXOR)) - break; - SourcePosition pos = scanner_.begin(); - Expression *right = shift(); - if (!right) - return NULL; - left = new (pool_) BinaryExpression(pos, TOK_BITXOR, left, right); - } - return left; -} - -Expression * -Parser::bitor_() -{ - Expression *left = bitxor(); - while (left) { - if (!match(TOK_BITOR)) - break; - SourcePosition pos = scanner_.begin(); - Expression *right = bitxor(); - if (!right) - return NULL; - left = new (pool_) BinaryExpression(pos, TOK_BITOR, left, right); - } - return left; -} - -Expression * -Parser::relational() -{ - Expression *left = bitor_(); - while (left) { - TokenKind kind = scanner_.peek(); - if (kind < TOK_LT || kind > TOK_GE) - break; - scanner_.scan(); - SourcePosition pos = scanner_.begin(); - Expression *right = shift(); - if (!right) - return NULL; - left = new (pool_) BinaryExpression(pos, kind, left, right); - } - return left; -} - -Expression * -Parser::equals() -{ - Expression *left = relational(); - while (left) { - if (!match(TOK_EQUALS) && !match(TOK_NOTEQUALS)) - break; - TokenKind kind = scanner_.last(); - SourcePosition pos = scanner_.begin(); - Expression *right = relational(); - if (!right) - return NULL; - left = new (pool_) BinaryExpression(pos, kind, left, right); - } - return left; -} - -Expression * -Parser::and_() -{ - Expression *left = equals(); - while (left) { - if (!match(TOK_AND)) - break; - SourcePosition pos = scanner_.begin(); - Expression *right = equals(); - if (!right) - return NULL; - left = new (pool_) BinaryExpression(pos, TOK_AND, left, right); - } - return left; -} - -Expression * -Parser::or_() -{ - Expression *left = and_(); - while (left) { - if (!match(TOK_OR)) - break; - SourcePosition pos = scanner_.begin(); - Expression *right = and_(); - if (!right) - return NULL; - left = new (pool_) BinaryExpression(pos, TOK_OR, left, right); - } - return left; -} - -Expression * -Parser::ternary() -{ - Expression *cond = or_(); - if (!cond) - return NULL; - - if (!match(TOK_QMARK)) - return cond; - - Expression *left; - SourcePosition pos = scanner_.begin(); - AutoAllowTags disableTags(scanner_); - { - if ((left = expression()) == NULL) - return NULL; - } - - if (!expect(TOK_COLON)) - return NULL; - - Expression *right = expression(); - if (!right) - return NULL; - - return new (pool_) TernaryExpression(pos, cond, left, right); -} - -Expression * -Parser::assignment() -{ - Expression *left = ternary(); - while (left) { - TokenKind token = scanner_.peek(); - if (token != TOK_ASSIGN && (token < TOK_ASSIGN_ADD || token > TOK_ASSIGN_SHL)) - break; - scanner_.scan(); - SourcePosition pos = scanner_.begin(); - Expression *expr = ternary(); - if (!expr) - return NULL; - - left = new (pool_) Assignment(pos, token, left, expr); - } - return left; -} - -Expression * -Parser::expression() -{ - return assignment(); -} - -Statement * -Parser::while_() -{ - SourcePosition pos = scanner_.begin(); - scanner_.scan(); - - if (!expect(TOK_LPAREN)) - return NULL; - - Expression *condition = expression(); - if (!condition) - return NULL; - - if (!expect(TOK_RPAREN)) - return NULL; - - // Inside a loop, we force the creation of a scope object. Normally, we - // will cull scopes if they have no variables. However inside a loop, - // function calls that take references may compute a LIFO object, and to - // avoid temporarily leaking many such objects, we ensure that a scope - // is present so a LIFO slot can be allocated. - if (!enterScope(Scope::BLOCK)) - return NULL; - - Statement *body; - if (scanner_.peek() == TOK_LBRACE) - body = block(scope_); - else - body = localStatement(); - if (!body) - return NULL; - - scope_ = scope_->enclosing(); - return new (pool_) WhileStatement(pos, TOK_WHILE, condition, body); -} - -Statement * -Parser::do_() -{ - SourcePosition pos = scanner_.begin(); - scanner_.scan(); - - // See the comment in ::while_() as to why we force a scope. - if (!enterScope(Scope::BLOCK)) - return NULL; - - Statement *body; - if (scanner_.peek() == TOK_LBRACE) - body = block(scope_); - else - body = localStatement(); - if (!body) - return NULL; - - scope_ = scope_->enclosing(); - - if (!expect(TOK_WHILE)) - return NULL; - - if (!expect(TOK_LPAREN)) - return NULL; - Expression *condition = expression(); - if (!condition) - return NULL; - if (!expect(TOK_RPAREN)) - return NULL; - - return new (pool_) WhileStatement(pos, TOK_DO, condition, body); -} - -Statement * -Parser::switch_() -{ - expect(TOK_SWITCH); - - SourcePosition pos = scanner_.begin(); - - if (!expect(TOK_LPAREN)) - return NULL; - Expression *expr = expression(); - if (!expr) - return NULL; - if (!expect(TOK_RPAREN)) - return NULL; - - if (!expect(TOK_LBRACE)) - return NULL; - - SourcePosition defaultPos; - PoolList *cases = new (pool_) PoolList(); - - Statement *defaultCase = NULL; - - while (!peek(TOK_RBRACE)) { - Expression *expr = NULL; - ExpressionList *others = NULL; - if (match(TOK_DEFAULT)) { - if (defaultCase) { - cc_.reportError(scanner_.begin(), Message_OneDefaultPerSwitch); - return NULL; - } - - defaultPos = scanner_.begin(); - } else { - if (defaultCase) { - cc_.reportError(defaultPos, Message_DefaultMustBeLastCase); - return NULL; - } - - if (!expect(TOK_CASE)) - return NULL; - - // A limitation in the grammar is that |case :| will be - // detected as a label. - AutoAllowTags disableTags(scanner_); - - if ((expr = expression()) == NULL) - return NULL; - - if (peek(TOK_COMMA)) { - others = new (pool_) ExpressionList(); - while (match(TOK_COMMA)) { - Expression *other = expression(); - if (!other) - return NULL; - if (!others->append(other)) - return NULL; - } - } - } - - if (!expect(TOK_COLON)) - return NULL; - - Statement *statement = localStatement(); - if (!statement) - return NULL; - - if (!peek(TOK_CASE) && - !peek(TOK_DEFAULT) && - !peek(TOK_RBRACE)) - { - cc_.reportError(scanner_.begin(), Message_SingleStatementPerCase); - return NULL; - } - - if (expr) { - Case *caze = new (pool_) Case(expr, others, statement); - if (!cases->append(caze)) - return NULL; - } else { - defaultCase = statement; - } - } - - if (!expect(TOK_RBRACE)) - return NULL; - - return new (pool_) SwitchStatement(pos, expr, cases, defaultCase); -} - -Statement * -Parser::forStatement() -{ - SourcePosition pos = scanner_.begin(); - scanner_.scan(); - if (!expect(TOK_LPAREN)) - return NULL; - - Statement *decl = NULL; - if (!match(TOK_SEMICOLON)) { - if (match(TOK_NEW)) { - if (!enterScope(Scope::BLOCK)) - return NULL; - if ((decl = vars(TOK_STOCK, TOK_NEW)) == NULL) - return NULL; - } else { - if ((decl = expressionStatement()) == NULL) - return NULL; - } - if (!expect(TOK_SEMICOLON)) - return NULL; - } - - Expression *condition = NULL; - if (!match(TOK_SEMICOLON)) { - if ((condition = expression()) == NULL) - return NULL; - if (!expect(TOK_SEMICOLON)) - return NULL; - } - - Statement *update = NULL; - if (!match(TOK_RPAREN)) { - if ((update = expressionStatement()) == NULL) - return NULL; - if (!expect(TOK_RPAREN)) - return NULL; - } - - // See the comment in ::while_() as to why we force a scope. - if (!enterScope(Scope::BLOCK)) - return NULL; - - Statement *body; - if (scanner_.peek() == TOK_LBRACE) - body = block(scope_); - else - body = localStatement(); - if (!body) - return NULL; - - scope_ = scope_->enclosing(); - - Scope *declScope = NULL; - if (decl && (decl->isVariableDeclaration() || decl->isBlockStatement())) { - declScope = scope_->unlinkIfEmpty(); - scope_ = scope_->enclosing(); - } - return new (pool_) ForStatement(pos, declScope, decl, condition, update, body); -} - -ExpressionList * -Parser::dimensions() -{ - ExpressionList *postDimensions = new (pool_) ExpressionList(); - while (match(TOK_LBRACKET)) { - Expression *dim = NULL; - if (!match(TOK_RBRACKET)) { - if ((dim = expression()) == NULL) - return NULL; - if (!expect(TOK_RBRACKET)) - return NULL; - } - - if (!postDimensions->append(dim)) - return NULL; - } - return postDimensions; -} - -VariableDeclaration * -Parser::var(TokenKind scope, TokenKind kind) -{ - Local tag(zone_); - if (matchName(tag.ref(), TOK_LABEL) && !tag) - return NULL; - - BoundName *type = NULL; - if (tag) - type = bindType(tag); - - Local name(zone_, expectName()); - if (!name) - return NULL; - - SourcePosition pos = scanner_.begin(); - - if (BoundName *other = scope_->localLookup(name)) { - redeclarationError(other); - return NULL; - } - - ExpressionList *postDimensions = NULL; - if (peek(TOK_LBRACKET)) { - if ((postDimensions = dimensions()) == NULL) - return NULL; - } - - Expression *expr = NULL; - if (match(TOK_ASSIGN)) { - switch (scanner_.peek()) { - // Note: we don't support [] literals yet. - case TOK_LBRACE: - if ((expr = arrayLiteral(scanner_.scan())) == NULL) - return NULL; - break; - - default: - if ((expr = expression()) == NULL) - return NULL; - break; - } - } - - Variable *var = scope_->declareVariable(name, pos); - if (!var) - return NULL; - - if (scope == TOK_PUBLIC) - var->setPublic(); - - return new (pool_) VariableDeclaration(var->pos(), kind, var, type, postDimensions, expr); -} - -Statement * -Parser::vars(TokenKind scope, TokenKind kind) -{ - VariableDeclaration *decl = var(scope, kind); - if (!decl) - return NULL; - - if (!peek(TOK_COMMA)) - return decl; - - StatementList *statements = new (pool_) StatementList(); - if (!statements->append(decl)) - return NULL; - - while (match(TOK_COMMA)) { - Statement *decl = var(scope, kind); - if (!decl) - return NULL; - if (!statements->append(decl)) - return NULL; - } - - // Create a fake-o block with no scope to create a statement list. - return new (pool_) BlockStatement(decl->pos(), NULL, statements); -} - -Statement * -Parser::returnStatement() -{ - SourcePosition pos = scanner_.begin(); - if (!expect(TOK_RETURN)) - return NULL; - - Expression *expr = NULL; - if (scanner_.peek() != TOK_SEMICOLON) { - if ((expr = expression()) == NULL) - return NULL; - - // We only care about non-void returns when determining whether a - // tagless function is non-void. - encounteredReturn_ = true; - } - - return new (pool_) ReturnStatement(pos, expr); -} - -Statement * -Parser::expressionStatement() -{ - Expression *left = assignment(); - if (!left) - return NULL; - - return new (pool_) ExpressionStatement(left); -} - -Statement * -Parser::block(Scope *scope) -{ - if (!expect(TOK_LBRACE)) - return NULL; - - SourcePosition pos = scanner_.begin(); - if (!scope && !enterScope(Scope::BLOCK)) - return NULL; - - StatementList *statements = new (pool_) StatementList(); - while (!match(TOK_RBRACE)) { - Statement *statement = localStatement(); - if (statement == NULL) - return NULL; - if (!statements->append(statement)) - return NULL; - } - - if (!scope) { - scope = scope_->unlinkIfEmpty(); - scope_ = scope_->enclosing(); - } - BlockStatement *block = new (pool_) BlockStatement(pos, scope, statements); - return block; -} - -Statement * -Parser::if_() -{ - expect(TOK_IF); - - SourcePosition pos = scanner_.begin(); - if (!expect(TOK_LPAREN)) - return NULL; - - Expression *cond = expression(); - if (!cond) - return NULL; - - if (!expect(TOK_RPAREN)) - return NULL; - - Statement *ifTrue = localStatement(); - if (!ifTrue) - return NULL; - - IfStatement *outer = new (pool_) IfStatement(pos, cond, ifTrue); - - IfStatement *last = outer; - while (match(TOK_ELSE)) { - if (!match(TOK_IF)) { - Statement *ifFalse = localStatement(); - if (!ifFalse) - return NULL; - - last->setIfFalse(ifFalse); - break; - } - - SourcePosition pos = scanner_.begin(); - if (!expect(TOK_LPAREN)) - return NULL; - - Expression *otherCond = expression(); - if (!otherCond) - return NULL; - - if (!expect(TOK_RPAREN)) - return NULL; - - Statement *otherIfTrue = localStatement(); - if (!otherIfTrue) - return NULL; - - IfStatement *inner = new (pool_) IfStatement(pos, otherCond, otherIfTrue); - last->setIfFalse(inner); - last = inner; - } - - return outer; -} - -Statement * -Parser::localStatement() -{ - Statement *statement = NULL; - - // Statements which must be followed by a semicolon will break out of the - // switch. If they may end in BlockStatements, they'll immediately return. - - TokenKind kind = scanner_.peek(); - switch (kind) { - case TOK_CONST: - case TOK_NEW: - scanner_.scan(); - if ((statement = vars(TOK_STOCK, kind)) == NULL) - return NULL; - break; - - case TOK_FOR: - return forStatement(); - - case TOK_WHILE: - return while_(); - - case TOK_BREAK: - scanner_.scan(); - statement = new (pool_) BreakStatement(scanner_.begin()); - break; - - case TOK_CONTINUE: - scanner_.scan(); - statement = new (pool_) ContinueStatement(scanner_.begin()); - break; - - case TOK_DO: - if ((statement = do_()) == NULL) - return NULL; - break; - - case TOK_RETURN: - if ((statement = returnStatement()) == NULL) - return NULL; - break; - - case TOK_ENUM: - if ((statement = enum_()) == NULL) - return NULL; - break; - - case TOK_STRUCT: - if ((statement = struct_()) == NULL) - return NULL; - break; - - case TOK_SWITCH: - return switch_(); - - case TOK_IF: - return if_(); - - case TOK_LBRACE: - return block(); - - default: - break; - } - - if (!statement) { - if ((statement = expressionStatement()) == NULL) - return NULL; - } - - if (!expect(TOK_SEMICOLON)) - return NULL; - - return statement; -} - -Statement * -Parser::struct_() -{ - expect(TOK_STRUCT); - - Local name(zone_, expectName()); - if (!name) - return NULL; - - SourcePosition pos = scanner_.begin(); - - if (BoundName *other = scope_->localLookup(name)) { - redeclarationError(other); - return NULL; - } - - NamedType *type; - if ((type = scope_->declareType(name, scanner_.begin())) == NULL) - return NULL; - - if (!expect(TOK_LBRACE)) - return NULL; - - FieldList *fields = new (pool_) FieldList(); - - while (!peek(TOK_RBRACE)) { - if (matchName(name.ref(), TOK_LABEL) && !name) - return NULL; - - BoundName *type = NULL; - if (name) { - if ((type = bindType(name)) == NULL) - return NULL; - } - - name = expectName(); - if (!name) - return NULL; - - SourcePosition pos = scanner_.begin(); - - ExpressionList *postDimensions = NULL; - if (peek(TOK_LBRACKET)) { - if ((postDimensions = dimensions()) == NULL) - return NULL; - } - - if (!matchSemicolon()) - return NULL; - - StructureStatement::Field *field = - new (pool_) StructureStatement::Field(pos, type, name, postDimensions); - if (!field || !fields->append(field)) - return NULL; - } - - if (!expect(TOK_RBRACE)) - return NULL; - - if (fields->empty()) { - cc_.reportError(pos, Message_StructCantBeEmpty); - return NULL; - } - - return new (pool_) StructureStatement(pos, type, fields); -} - -Statement * -Parser::enum_() -{ - expect(TOK_ENUM); - - NamedType *type = NULL; - SourcePosition pos = scanner_.begin(); - - Local name(zone_); - if (matchName(name.ref())) { - if (!name) - return NULL; - - if (BoundName *other = scope_->localLookup(name)) { - redeclarationError(other); - return NULL; - } - - if ((type = scope_->declareType(name, scanner_.begin())) == NULL) - return NULL; - } - - EnumStatement::EntryList *entries = new (pool_) EnumStatement::EntryList(); - - if (!expect(TOK_LBRACE)) - return NULL; - - do { - if (scanner_.peek() == TOK_RBRACE) - break; - - Local name(zone_, expectName()); - if (!name) - return NULL; - - if (BoundName *other = scope_->localLookup(name)) { - redeclarationError(other); - return NULL; - } - - NamedConstant *constant = scope_->declareConstant(name, scanner_.begin()); - if (!constant) - return NULL; - - Expression *expr = NULL; - if (match(TOK_ASSIGN)) { - if ((expr = expression()) == NULL) - return NULL; - } - - if (!entries->append(EnumStatement::Entry(constant, expr))) - return NULL; - } while (match(TOK_COMMA)); - if (!expect(TOK_RBRACE)) - return NULL; - - return new (pool_) EnumStatement(pos, type, name, entries); -} - -Statement * -Parser::function(TokenKind token) -{ - Local returnTag(zone_); - if (token == TOK_LABEL) { - returnTag = zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()); - if (!returnTag) - return NULL; - - token = TOK_STOCK; - } else { - if (peek(TOK_LABEL)) { - if (matchName(returnTag.ref(), TOK_LABEL) && !returnTag) - return NULL; - } else if (peek(TOK_NAME)) { - // Peek for a type that has no : - returnTag = expectName(); - if (!returnTag) - return NULL; - } - } - - Local name(zone_); - ExpressionList *returnDimensions = NULL; - - bool allowArrayReturns = token != TOK_NATIVE && - token != TOK_PUBLIC && - token != TOK_FORWARD; - - if (allowArrayReturns && peek(TOK_LBRACKET)) { - if ((returnDimensions = dimensions()) == NULL) - return NULL; - if ((name = expectName()) == NULL) - return NULL; - } else if (peek(TOK_NAME)) { - if ((name = expectName()) == NULL) - return NULL; - } else { - // We predicted |type name|, but just got |name| instead. - name = returnTag; - returnTag = NULL; - } - - BoundName *returnType = NULL; - if (returnTag) - returnType = bindType(returnTag); - - SourcePosition pos = scanner_.begin(); - - // The function name goes into the outer (global) scope. - assert(!scope_->enclosing()); - - NamedType *type = NULL; - NamedFunction *fun = NULL; - if (BoundName *other = scope_->localLookup(name)) { - // We allow a redeclaration if the new type is a public, and the old - // type was a forward. However, the forward must come first. - if (token == TOK_TYPEDEF || other->kind() != BoundName::FUNCTION) { - redeclarationError(other); - return NULL; - } - - fun = other->toNamedFunction(); - if (!fun->isForward() || token != TOK_PUBLIC) { - redeclarationError(other); - return NULL; - } - - // We've got the same name, but the original is a forward, so let it - // slide and re-use the original declaration. - fun->setImplemented(scanner_.begin()); - } else if (token == TOK_TYPEDEF) { - type = scope_->declareType(name, scanner_.begin()); - if (!type) - return NULL; - } else { - fun = scope_->declareFunction(name, scanner_.begin(), token); - if (!fun) - return NULL; - } - - if (fun && fun->isPublic()) - fun->setUsed(); - - Scope *scope = enterScope(Scope::FUNCTION); - if (!scope) - return NULL; - - ParameterList *parameters = new (pool_) ParameterList(); - - if (!expect(TOK_LPAREN)) - return NULL; - - if (!match(TOK_RPAREN)) { - while (true) { - bool isConst = match(TOK_CONST); - bool ref = match(TOK_AMPERSAND); - - SourcePosition begin = scanner_.begin(); - Local tag(zone_); - if (matchName(tag.ref(), TOK_LABEL) && !tag) - return NULL; - - BoundName *type = NULL; - if (tag) - type = bindType(tag); - - if (match(TOK_ELLIPSES)) { - if (isConst || ref) { - cc_.reportError(begin, Message_InvalidVarArgs); - return NULL; - } - - if (token != TOK_NATIVE) { - cc_.reportError(begin, Message_VarArgsOutsideNative); - return NULL; - } - - fun->markNativeVariadic(); - break; - } - - Local name(zone_, expectName()); - if (!name) - return NULL; - - if (BoundName *other = scope_->localLookup(name)) { - redeclarationError(other); - return NULL; - } - Variable *arg = scope_->declareArgument(name, scanner_.begin()); - if (!arg) - return NULL; - - // Look for dimensions. - ExpressionList *postDimensions = NULL; - if (peek(TOK_LBRACKET)) { - if ((postDimensions = dimensions()) == NULL) - return NULL; - } - - Expression *expr = NULL; - if (match(TOK_ASSIGN)) { - if ((expr = expression()) == NULL) - return NULL; - } - - Parameter *parameter = new (pool_) Parameter(arg, type, ref, isConst, postDimensions, - expr); - if (!parameters->append(parameter)) - return NULL; - - if (!match(TOK_COMMA)) - break; - } - if (!expect(TOK_RPAREN)) - return NULL; - } - - encounteredReturn_ = false; - - Statement *body = NULL; - if (token != TOK_FORWARD && token != TOK_NATIVE && token != TOK_TYPEDEF) { - body = block(); - if (!body) - return NULL; - } - - scope_ = scope_->enclosing(); - - FunctionSignature signature(returnType, returnDimensions, parameters); - if (token == TOK_TYPEDEF) - return new (pool_) FunctionTypeStatement(pos, type, signature); - - return new (pool_) FunctionStatement(pos, scope, fun, body, signature, encounteredReturn_); -} - -static inline bool -DeclareIntrinsicType(Zone *zone, Scope *scope, const char *name, Handle type) -{ - Local tag(zone, zone->makeSymbol(name)); - if (!tag) - return false; - - return !!scope->declareType(tag, type); -} - -static inline bool -DeclareIntrinsicType(Zone *zone, Scope *scope, const char *name, PrimitiveType type) -{ - Local primitive(zone, zone->types()->getPrimitive(type)); - assert(primitive); - return DeclareIntrinsicType(zone, scope, name, primitive); -} - -bool -Parser::setupIntrinsics() -{ - if (!DeclareIntrinsicType(zone_, scope_, "Float", PrimitiveType_Float)) - return false; - if (!DeclareIntrinsicType(zone_, scope_, "_", PrimitiveType_Int32)) - return false; - if (!DeclareIntrinsicType(zone_, scope_, "bool", PrimitiveType_Bool)) - return false; - if (!DeclareIntrinsicType(zone_, scope_, "String", PrimitiveType_Char)) - return false; - - Local unchecked(zone_, zone_->types()->getUnchecked()); - if (!DeclareIntrinsicType(zone_, scope_, "unchecked", unchecked)) - return false; - - Local voidType(zone_, zone_->types()->getVoid()); - if (!DeclareIntrinsicType(zone_, scope_, "void", voidType)) - return false; - - Local intType(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32)); - if (!DeclareIntrinsicType(zone_, scope_, "int", intType)) - return false; - - return true; -} - -ParseTree * -Parser::parse() -{ - StatementList *statements = new (pool_) StatementList(); - - if (!enterScope(Scope::GLOBAL)) - return NULL; - - if (!setupIntrinsics()) - return NULL; - - for (;;) { - Statement *statement = NULL; - - TokenKind kind = scanner_.peek(); - switch (kind) { - case TOK_ERROR: - return NULL; - - case TOK_EOF: - break; - - case TOK_NAME: - if ((statement = function(TOK_NAME)) == NULL) - return NULL; - break; - - case TOK_FORWARD: - case TOK_PUBLIC: - case TOK_NATIVE: - case TOK_STOCK: - case TOK_LABEL: - case TOK_TYPEDEF: - { - scanner_.scan(); - if (kind == TOK_PUBLIC && peek(TOK_CONST)) { - if ((statement = var(TOK_PUBLIC, scanner_.scan())) == NULL) - return NULL; - if (!matchSemicolon()) - return NULL; - } else { - if ((statement = function(kind)) == NULL) - return NULL; - if ((kind == TOK_FORWARD || kind == TOK_NATIVE || kind == TOK_TYPEDEF) && !matchSemicolon()) - return NULL; - } - break; - } - - case TOK_CONST: - case TOK_NEW: - { - // Note: at global scope, we don't accept comma-delimited - // declarations yet, to see if we can get away with forcing - // a nicer top-level style. - scanner_.scan(); - if ((statement = var(TOK_STOCK, kind)) == NULL) - return NULL; - if (!matchSemicolon()) - return NULL; - break; - } - - case TOK_ENUM: - if ((statement = enum_()) == NULL) - return NULL; - if (!matchSemicolon()) - return NULL; - break; - - case TOK_STRUCT: - if ((statement = struct_()) == NULL) - return NULL; - if (!matchSemicolon()) - return NULL; - break; - - default: - cc_.reportError(scanner_.begin(), Message_ExpectedGlobal); - return NULL; - } - - if (!statement) - break; - - if (!statements->append(statement)) - return NULL; - } - - return new (pool_) ParseTree(scope_, statements, unbound_); -} - -class AstPrinter : public AstVisitor -{ - FILE *fp_; - size_t level_; - - private: - void prefix() { - for (size_t i = 0; i < level_; i++) - fprintf(fp_, " "); - } - void indent() { - level_++; - } - void unindent() { - level_--; - } - - public: - AstPrinter(FILE *fp) - : fp_(fp), - level_(0) - { - } - - void dump(const FunctionSignature &sig) { - prefix(); - fprintf(fp_, "%s", sig.returnType() - ? sig.returnType()->name()->chars() - : "_"); - if (sig.returnDimensions()) { - for (size_t i = 0; i < sig.returnDimensions()->length(); i++) - fprintf(fp_, "[]"); - } - fprintf(fp_, "()\n"); - } - void visit(NameProxy *name) { - prefix(); - fprintf(fp_, "[ NameProxy (%s)%s\n", name->name()->chars(), - (name->binding() ? "" : " unbound")); - } - void visit(CallExpression *node) { - prefix(); - fprintf(fp_, "[ CallExpression\n"); - indent(); - node->callee()->accept(this); - for (size_t i = 0; i < node->arguments()->length(); i++) - node->arguments()->at(i)->accept(this); - unindent(); - } - void visit(FunctionTypeStatement *node) { - prefix(); - fprintf(fp_, "[ FunctionTypeStatement (%s)\n", node->decl()->name()->chars()); - indent(); - dump(node->signature()); - unindent(); - } - void visit(FunctionStatement *node) { - prefix(); - fprintf(fp_, "[ FunctionStatement (%s)\n", node->fun()->name()->chars()); - indent(); - dump(node->signature()); - if (node->body()) - node->body()->accept(this); - unindent(); - } - void visit(ExpressionStatement *node) { - prefix(); - fprintf(fp_, "[ ExpressionStatement\n"); - indent(); - node->expression()->accept(this); - unindent(); - } - void visit(Assignment *node) { - prefix(); - fprintf(fp_, "[ Assignment\n"); - indent(); - node->lvalue()->accept(this); - node->expression()->accept(this); - unindent(); - } - void visit(TernaryExpression *node) { - prefix(); - fprintf(fp_, "[ TernaryExpression\n"); - indent(); - node->condition()->accept(this); - node->left()->accept(this); - node->right()->accept(this); - unindent(); - } - void visit(BinaryExpression *node) { - prefix(); - fprintf(fp_, "[ BinaryExpression (%s)\n", TokenNames[node->token()]); - indent(); - node->left()->accept(this); - node->right()->accept(this); - unindent(); - } - void visit(UnaryExpression *node) { - prefix(); - fprintf(fp_, "[ UnaryExpression (%s)\n", TokenNames[node->token()]); - indent(); - node->expression()->accept(this); - unindent(); - } - void visit(ReturnStatement *node) { - prefix(); - fprintf(fp_, "[ ReturnStatement\n"); - indent(); - if (node->expression()) - node->expression()->accept(this); - unindent(); - } - void visit(ForStatement *node) { - prefix(); - fprintf(fp_, "[ ForStatement\n"); - indent(); - if (node->initialization()) - node->initialization()->accept(this); - if (node->condition()) - node->condition()->accept(this); - if (node->update()) - node->update()->accept(this); - node->body()->accept(this); - unindent(); - } - void visit(BlockStatement *node) { - prefix(); - fprintf(fp_, "[ BlockStatement\n"); - indent(); - for (size_t i = 0; i < node->statements()->length(); i++) - node->statements()->at(i)->accept(this); - unindent(); - } - void visit(VariableDeclaration *node) { - prefix(); - fprintf(fp_, "[ VariableDeclaration (%s)\n", node->variable()->name()->chars()); - indent(); - if (node->initialization()) - node->initialization()->accept(this); - unindent(); - } - void visit(IntegerLiteral *node) { - prefix(); - fprintf(fp_, "[ IntegerLiteral (%d)\n", node->value()); - } - void visit(BooleanLiteral *node) { - prefix(); - fprintf(fp_, "[ BooleanLiteral (%s)\n", - (node->token() == TOK_TRUE) ? "true" : "false"); - } - void visit(FloatLiteral *node) { - prefix(); - fprintf(fp_, "[ FloatLiteral (%f)\n", node->value()); - } - void visit(IfStatement *node) { - prefix(); - fprintf(fp_, "[ IfStatement\n"); - indent(); - node->ifTrue()->accept(this); - if (node->ifFalse()) - node->ifFalse()->accept(this); - unindent(); - } - void visit(IndexExpression *node) { - prefix(); - fprintf(fp_, "[ IndexExpression\n"); - indent(); - node->left()->accept(this); - node->right()->accept(this); - unindent(); - } - void visit(EnumStatement *node) { - prefix(); - fprintf(fp_, "[ EnumStatement (%s)\n", node->name() ? node->name()->chars() : ""); - indent(); - for (size_t i = 0; i < node->entries()->length(); i++) { - prefix(); - fprintf(fp_, "%s =\n", node->entries()->at(i).name->name()->chars()); - if (node->entries()->at(i).expr) { - indent(); - node->entries()->at(i).expr->accept(this); - unindent(); - } - } - unindent(); - } - void visit(WhileStatement *node) { - prefix(); - fprintf(fp_, "[ WhileStatement (%s)\n", - (node->token() == TOK_DO) ? "do" : "while"); - indent(); - if (node->token() == TOK_DO) { - node->condition()->accept(this); - node->body()->accept(this); - } else { - node->condition()->accept(this); - node->body()->accept(this); - } - unindent(); - } - void visit(BreakStatement *node) { - prefix(); - fprintf(fp_, "[ BreakStatement\n"); - } - void visit(ContinueStatement *node) { - prefix(); - fprintf(fp_, "[ ContinueStatement\n"); - } - void visit(StringLiteral *node) { - prefix(); - fprintf(fp_, "[ StringLiteral\n"); - } - void visit(IncDecExpression *node) { - prefix(); - fprintf(fp_, "[ IncDecExpression (postfix=%d)\n", node->postfix()); - indent(); - node->expression()->accept(this); - unindent(); - } - void visit(StructureStatement *node) { - prefix(); - fprintf(fp_, "[ StructureStatement %s\n", node->decl()->name()->chars()); - } - void visit(FieldExpression *node) { - prefix(); - fprintf(fp_, "[ FieldExpression %s\n", node->field()->chars()); - indent(); - node->left()->accept(this); - unindent(); - } - void visit(SwitchStatement *node) { - prefix(); - fprintf(fp_, "[ SwitchStatement\n"); - indent(); - node->expression()->accept(this); - for (size_t i = 0; i < node->cases()->length(); i++) { - Case *c = node->cases()->at(i); - c->expression()->accept(this); - if (c->others()) { - for (size_t j = 0; j < c->others()->length(); j++) - c->others()->at(j)->accept(this); - } - indent(); - c->statement()->accept(this); - unindent(); - } - if (node->defaultCase()) - node->defaultCase()->accept(this); - unindent(); - } - void visit(ArrayLiteral *node) { - prefix(); - fprintf(fp_, "[ ArrayLiteral\n"); - indent(); - for (size_t i = 0; i < node->expressions()->length(); i++) { - Expression *expr = node->expressions()->at(i); - indent(); - expr->accept(this); - unindent(); - } - } -}; - -void -ParseTree::dump(FILE *fp) -{ - AstPrinter printer(fp); - - for (size_t i = 0; i < statements_->length(); i++) - statements_->at(i)->accept(&printer); -}