bool Parser::Impl::parseTest() { // test := identifier arguments // arguments := *argument [ test / test-list ] // // identifier // if ( !obtainToken() || atEnd() ) return false; if ( token() != Lexer::Identifier ) return false; if ( scriptBuilder() ) scriptBuilder()->testStart( tokenValue() ); consumeToken(); // // *argument // if ( !obtainToken() ) return false; if ( atEnd() ) // a test w/o args goto TestEnd; if ( isArgumentToken() && !parseArgumentList() ) { assert( error() ); return false; } // // test / test-list // if ( !obtainToken() ) return false; if ( atEnd() ) // a test w/o nested tests goto TestEnd; if ( token() == Lexer::Special && tokenValue() == "(" ) { // test-list if ( !parseTestList() ) { assert( error() ); return false; } } else if ( token() == Lexer::Identifier ) { // should be test: if ( !parseTest() ) { assert( error() ); return false; } } TestEnd: if ( scriptBuilder() ) scriptBuilder()->testEnd(); return true; }
DeclarationsPtr Parser::parseArgumentList_r() { if (match(TokenType::Semicolon)) { return parseArgumentList(); } return DeclarationsPtr(); }
void Parser::parseArguments(SubprogramDeclarationPtr sub) { if (match(TokenType::LParen)) { DeclarationsPtr arguments = parseArgumentList(); if (!match(TokenType::RParen)) { reportError(ErrorCodes::ExpectedRParen); return; } sub->arguments = arguments; return; } }
void PackageParser::parseProtocol(const EmojicodeString &documentation, const Token &theToken, bool exported) { EmojicodeChar name, enamespace; parseAndValidateNewTypeName(&name, &enamespace); auto protocol = new Protocol(name, package_, documentation, theToken); parseGenericArgumentList(protocol, Type(protocol, false)); protocol->finalizeGenericArguments(); auto token = stream_.consumeToken(IDENTIFIER); if (token.value[0] != E_GRAPES) { ecCharToCharStack(token.value[0], s); throw CompilerErrorException(token, "Expected 🍇 but found %s instead.", s); } auto protocolType = Type(protocol, false); package_->registerType(protocolType, name, enamespace, exported); while (stream_.nextTokenIsEverythingBut(E_WATERMELON)) { auto documentation = parseDocumentationToken(); auto token = stream_.consumeToken(IDENTIFIER); auto deprecated = Attribute<E_WARNING_SIGN>().parse(&stream_); if (token.value[0] != E_PIG) { throw CompilerErrorException(token, "Only method declarations are allowed inside a protocol."); } auto methodName = stream_.consumeToken(IDENTIFIER); auto method = new Method(methodName.value[0], PUBLIC, false, nullptr, package_, methodName.position(), false, documentation, deprecated.set()); auto a = parseArgumentList(method, protocolType); auto b = parseReturnType(method, protocolType); if (a || b) { protocol->setUsesSelf(); } protocol->addMethod(method); } stream_.consumeToken(IDENTIFIER); }
bool Parser::Impl::parseCommand() { // command := identifier arguments ( ";" / block ) // arguments := *argument [ test / test-list ] // block := "{" *command "}" // our ABNF: // block := "{" [ command-list ] "}" if ( atEnd() ) return false; // // identifier // if ( !obtainToken() || token() != Lexer::Identifier ) return false; if ( scriptBuilder() ) scriptBuilder()->commandStart( tokenValue() ); consumeToken(); // // *argument // if ( !obtainToken() ) return false; if ( atEnd() ) { makeError( Error::MissingSemicolonOrBlock ); return false; } if ( isArgumentToken() && !parseArgumentList() ) { assert( error() ); return false; } // // test / test-list // if ( !obtainToken() ) return false; if ( atEnd() ) { makeError( Error::MissingSemicolonOrBlock ); return false; } if ( token() == Lexer::Special && tokenValue() == "(" ) { // test-list if ( !parseTestList() ) { assert( error() ); return false; } } else if ( token() == Lexer::Identifier ) { // should be test: if ( !parseTest() ) { assert( error() ); return false; } } // // ";" / block // if ( !obtainToken() ) return false; if ( atEnd() ) { makeError( Error::MissingSemicolonOrBlock ); return false; } if ( token() != Lexer::Special ) { makeUnexpectedTokenError( Error::ExpectedBlockOrSemicolon ); return false; } if ( tokenValue() == ";" ) consumeToken(); else if ( tokenValue() == "{" ) { // block if ( !parseBlock() ) return false; // it's an error since we saw '{' } else { makeError( Error::MissingSemicolonOrBlock ); return false; } if ( scriptBuilder() ) scriptBuilder()->commandEnd(); return true; }