BlockNode* Parser::parseBlock(bool needBraces, const bool scoped/* = true */) { if (needBraces) { ensureToken(tLBRACE); } if (scoped) { pushScope(); } BlockNode* block = new BlockNode(_currentTokenIndex, _currentScope); TokenKind sentinel = needBraces ? tRBRACE : tEOF; while (currentToken() != sentinel) { if (currentToken() == tSEMICOLON) { consumeToken(); continue; } AstNode* statement = parseStatement(); // Ignore statements that doesn't result in AST nodes, such // as variable or function declaration. if (statement != 0) { block->add(statement); } } if (scoped) { popScope(); } if (needBraces) { ensureToken(tRBRACE); } return block; }
FunctionNode* Parser::parseFunction() { uint32_t tokenIndex = _currentTokenIndex; ensureKeyword("function"); if (currentToken() != tIDENT) { error("identifier expected"); } const string& returnTypeName = currentTokenValue(); VarType returnType = nameToType(returnTypeName); if (returnType == VT_INVALID) { error("wrong return type"); } consumeToken(); if (currentToken() != tIDENT) { error("name expected"); } const string& name = currentTokenValue(); consumeToken(); Signature signature; signature.push_back(SignatureElement(returnType, "return")); ensureToken(tLPAREN); while (currentToken() != tRPAREN) { const string& parameterTypeName = currentTokenValue(); VarType parameterType = nameToType(parameterTypeName); if (parameterType == VT_INVALID) { error("wrong parameter type"); } consumeToken(); const string& parameterName = currentTokenValue(); if (currentToken() != tIDENT) { error("identifier expected"); } consumeToken(); signature.push_back(SignatureElement(parameterType, parameterName)); if (currentToken() == tCOMMA) { consumeToken(); } } ensureToken(tRPAREN); BlockNode* body = 0; pushScope(); for (uint32_t i = 1; i < signature.size(); i++) { const string& name = signature[i].second; VarType type = signature[i].first; if (!_currentScope->declareVariable(name, type)) { error("Formal \"%s\" already declared", name.c_str()); } } if ((currentToken() == tIDENT) && currentTokenValue() == "native") { consumeToken(); if (currentToken() != tSTRING) { error("Native name expected, got %s", tokenStr(currentToken())); } pushScope(); body = new BlockNode(_currentTokenIndex, _currentScope); body->add(new NativeCallNode(tokenIndex, currentTokenValue(), signature)); consumeToken(); ensureToken(tSEMICOLON); body->add(new ReturnNode(0, 0)); popScope(); } else { body = parseBlock(true, false); if (body->nodes() == 0 || !(body->nodeAt(body->nodes() - 1)->isReturnNode())) { body->add(new ReturnNode(0, defaultReturnExpr(returnType))); } } popScope(); if (_currentScope->lookupFunction(name) != 0) { error("Function %s already defined", name.c_str()); } FunctionNode* result = new FunctionNode(tokenIndex, name, signature, body); _currentScope->declareFunction(result); // We don't add function node into AST. return 0; }