diff --git a/Grammar.md b/Syntax.md similarity index 66% rename from Grammar.md rename to Syntax.md index e787985..b0bd0c7 100644 --- a/Grammar.md +++ b/Syntax.md @@ -1,15 +1,30 @@ +# Detailed Syntax + +This documents specifies what is the allowed syntax for statements and expressions. + +### Symbols used `?` 0 or 1 instances `*` 0 or more instance `+` 1 or more instances +`` Terminal token, usually new line , but it can also sometimes be `,`, `else`, or `;` + `` New line -`` Identifier +`` Identifier + +`` Expression block + +`` Statements block + +`` Expression + +`` Statement ### Statement Function -` fun (: ? (, )*)? (-> ? )? ;` +` fun (: ? (, ? )*)? (-> ? )? ; ` ``` stuff fun ; @@ -25,24 +40,37 @@ sint32 ; ``` +### Statement Meta Extern Function: +`@extern fun (: ? (, ? )*)? (-> ? )? ` +``` +@extern sum fun: +num1 sint32, +num2 sint32 -> +sint32 +``` + + +### Statemnet Variable +` <- ` +``` +num sint32 <- 42 + +``` + ### Statement Assignment -` <- ` +` <- ` ``` num1 <- 5 ``` -### StatementBlock +### Statement Block ( )* -### StatementExpression +### Statement Expression -StatementFunction: - fun (: (, )*)? (-> )? -; - ### StatementLoop `loop [ | ] (, ? (, ? )?)? ;` ``` @@ -64,17 +92,9 @@ i < 10 `loop ( (, ? )?)? ;` - -StatementMetaExternFunction: -@extern fun (: (, )*)? (-> )? - - ### StatementReturn `ret ` -### Statemnet Variable -` <- ` - ### ExpressionVariable: `` diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index 95e617f..718984a 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -33,6 +33,12 @@ vector> Parser::getStatements() { exit(1); } statements.push_back(statement); + + // Expect new line after statement + if (!tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true)) { + cerr << "Expected new line" << endl; + exit(1); + } } return statements; @@ -115,12 +121,12 @@ shared_ptr Parser::matchStatementFunction() { returnType = *type; currentIndex++; // type - - // consume new line - if (!tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true)) - return matchStatementInvalid("Expected new line after function declaration"); } + // consume new line + if (!tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true)) + return matchStatementInvalid("Expected new line after function declaration"); + // block statementBlock = matchStatementBlock({TokenKind::SEMICOLON}); if (statementBlock == nullptr || !statementBlock->isValid()) @@ -136,7 +142,7 @@ shared_ptr Parser::matchStatementVariable() { if (!tryMatchingTokenKinds({TokenKind::IDENTIFIER, TokenKind::TYPE}, true, false)) return nullptr; - shared_ptr identifierToken = tokens.at(currentIndex); + shared_ptr identifierToken = tokens.at(currentIndex++); currentIndex++; // identifier shared_ptr valueTypeToken = tokens.at(currentIndex); @@ -158,7 +164,7 @@ shared_ptr Parser::matchStatementVariable() { shared_ptr expression = nextExpression(); if (expression == nullptr || !expression->isValid()) - return matchStatementInvalid(); + return matchStatementInvalid("Invalid expression"); // Expect comma or new line if (!tryMatchingTokenKinds({TokenKind::COMMA}, true, false) && !tryMatchingTokenKinds({TokenKind::NEW_LINE}, false, true)) @@ -167,6 +173,54 @@ shared_ptr Parser::matchStatementVariable() { return make_shared(identifierToken->getLexme(), valueType, expression); } +shared_ptr Parser::matchStatementMetaExternFunction() { + if (!tryMatchingTokenKinds({TokenKind::M_EXTERN, TokenKind::IDENTIFIER, TokenKind::FUNCTION}, true, false)) + return nullptr; + + string name; + vector> arguments; + ValueType returnType = ValueType::NONE; + + currentIndex++; // skip meta + shared_ptr identifierToken = tokens.at(currentIndex++); + currentIndex++; // skip fun + + // arguments + if (tryMatchingTokenKinds({TokenKind::COLON}, true, true)) { + do { + tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); // skip new line + if (!tryMatchingTokenKinds({TokenKind::IDENTIFIER, TokenKind::TYPE}, true, false)) + return matchStatementInvalid("Expected function argument"); + shared_ptr identifierToken = tokens.at(currentIndex++); + shared_ptr typeToken = tokens.at(currentIndex++); + optional argumentType = valueTypeForToken(typeToken); + if (!argumentType) + return matchStatementInvalid("Invalid argument type"); + + arguments.push_back(pair(identifierToken->getLexme(), *argumentType)); + } while (tryMatchingTokenKinds({TokenKind::COMMA}, true, true)); + } + + // Return type + if (tryMatchingTokenKinds({TokenKind::RIGHT_ARROW}, true, true)) { + tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); // skip new line + + shared_ptr typeToken = tokens.at(currentIndex); + optional type = valueTypeForToken(typeToken); + if (!type) + return matchStatementInvalid("Expected return type"); + returnType = *type; + + currentIndex++; // type + + // consume new line + if (!tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true)) + return matchStatementInvalid("Expected new line after function declaration"); + } + + return make_shared(identifierToken->getLexme(), arguments, returnType); +} + shared_ptr Parser::matchStatementAssignment() { if (!tryMatchingTokenKinds({TokenKind::IDENTIFIER, TokenKind::LEFT_ARROW}, true, false)) return nullptr; @@ -269,56 +323,6 @@ shared_ptr Parser::matchStatementExpression() { return make_shared(expression); } -shared_ptr Parser::matchStatementMetaExternFunction() { - if (!tryMatchingTokenKinds({TokenKind::M_EXTERN, TokenKind::IDENTIFIER, TokenKind::FUNCTION}, true, false)) - return nullptr; - - currentIndex++; // skip meta - shared_ptr identifierToken = tokens.at(currentIndex); - currentIndex++; - currentIndex++; // skip fun - - // Get arguments - vector> arguments; - if (tryMatchingTokenKinds({TokenKind::COLON}, true, true)) { - do { - tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); // skip new line - if (!tryMatchingTokenKinds({TokenKind::IDENTIFIER, TokenKind::TYPE}, true, false)) - return matchStatementInvalid("Expected function argument"); - shared_ptr identifierToken = tokens.at(currentIndex); - currentIndex++; // identifier - shared_ptr typeToken = tokens.at(currentIndex); - currentIndex++; // type - optional argumentType = valueTypeForToken(typeToken); - if (!argumentType) - return matchStatementInvalid("Invalid argument type"); - - arguments.push_back(pair(identifierToken->getLexme(), *argumentType)); - } while (tryMatchingTokenKinds({TokenKind::COMMA}, true, true)); - } - - // consume optional new line - tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); - - // Return type - ValueType returnType = ValueType::NONE; - if (tryMatchingTokenKinds({TokenKind::RIGHT_ARROW}, true, true)) { - shared_ptr typeToken = tokens.at(currentIndex); - optional type = valueTypeForToken(typeToken); - if (!type) - return matchStatementInvalid("Expected return type"); - returnType = *type; - - currentIndex++; // type - - // consume new line - if (!tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true)) - return matchStatementInvalid("Expected new line after function declaration"); - } - - return make_shared(identifierToken->getLexme(), arguments, returnType); -} - shared_ptr Parser::matchStatementBlock(vector terminalTokenKinds) { vector> statements; diff --git a/test.brc b/test.brc index c6ce4fc..ec1a111 100644 --- a/test.brc +++ b/test.brc @@ -1,7 +1,2 @@ stuff fun: num1 sint32, num2 sint32 -> sint32 - if num1 > num2: - ret 32 * num1 - else - ret 45 * num2 - ; ; \ No newline at end of file