From 319cfed69692b79f69ed989485485081e1f40192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Tup=C3=BD?= Date: Wed, 24 Jan 2024 16:45:35 +0100 Subject: [PATCH] Added more in-depth parser documentation and cleaned up the generic parsing structure. --- source/compiler/compiler/compiler.cpp | 3 +- source/compiler/test/main.s | 16 +- source/parser/parser.cpp | 309 +++++++++++++++----------- source/parser/parser.h | 12 +- tests/variables/negation.s | 5 + 5 files changed, 193 insertions(+), 152 deletions(-) create mode 100644 tests/variables/negation.s diff --git a/source/compiler/compiler/compiler.cpp b/source/compiler/compiler/compiler.cpp index 910449e0..56342ea8 100644 --- a/source/compiler/compiler/compiler.cpp +++ b/source/compiler/compiler/compiler.cpp @@ -33,15 +33,14 @@ namespace sigma { TRY(const std::string file, utility::fs::file::load(m_description.path)); TRY(tokenizer::tokenize(file, &m_description.path, frontend)); TRY(parser::parse(frontend)); + frontend.syntax.print_ast(); // backend // at this point we want to merge all frontend contexts into the backend context backend_context backend(frontend.syntax, m_description.target); - backend.syntax.print_ast(); // run analysis on the generated AST TRY(type_checker::type_check(backend)); - TRY(ir_translator::translate(backend)); // compile the generated IR module diff --git a/source/compiler/test/main.s b/source/compiler/test/main.s index b2162bac..d14ee78e 100644 --- a/source/compiler/test/main.s +++ b/source/compiler/test/main.s @@ -12,18 +12,8 @@ // - cleanup ir gen alignment sizes (u64 vs u32 vs u16) i32 main() { - printf("%d\n", sizeof(i8)); - printf("%d\n", sizeof(i16)); - printf("%d\n", sizeof(i32)); - printf("%d\n", sizeof(i64)); - printf("%d\n", sizeof(u8)); - printf("%d\n", sizeof(u16)); - printf("%d\n", sizeof(u32)); - printf("%d\n", sizeof(u64)); - printf("%d\n", sizeof(bool)); - printf("%d\n", sizeof(char)); - printf("%d\n", sizeof(i32*)); - printf("%d\n", sizeof(i32**)); - + i32 x = 12u; + printf("%d\n", -x); + ret 0; } diff --git a/source/parser/parser.cpp b/source/parser/parser.cpp index 8897e121..aacb1a89 100644 --- a/source/parser/parser.cpp +++ b/source/parser/parser.cpp @@ -20,8 +20,37 @@ EXPECT_CURRENT_TOKEN((__token)) namespace sigma { parser::parser(frontend_context& context) : m_context(context), m_tokens(context.tokens) {} + auto parser::parse(frontend_context& context) -> utility::result { + return parser(context).parse(); + } + + auto parser::parse() -> utility::result { + // TODO: manage local context (ie. function body, loop body, if body etc), probably use a stack + + while (m_tokens.get_current_token() != token_type::END_OF_FILE) { + handle result; + + if(m_tokens.get_current_token() == token_type::NAMESPACE) { + // parse nested namespaces + TRY(result, parse_namespace_declaration()); + } + else if (peek_is_function_definition()) { + // parse globally declared functions + TRY(result, parse_function_declaration()); + } + else { + // parse globals + PANIC("globals aren't implemented yet"); + } + + m_context.syntax.ast.add_node(result); + } + + return SUCCESS; + } + auto parser::parse_namespace_declaration() -> utility::result> { - // NAMESPACE IDENTIFIER + // expect 'NAMESPACE IDENTIFIER' EXPECT_CURRENT_TOKEN(token_type::NAMESPACE); // parse the namespace identifier @@ -29,6 +58,7 @@ namespace sigma { const utility::string_table_key identifier_key = m_tokens.get_current().symbol_key; const handle location = m_tokens.get_current_token_location(); + // parse contained functions, namespaces, and globals m_tokens.next(); // prime the left brace TRY(const auto top, parse_namespace_block()); @@ -36,36 +66,35 @@ namespace sigma { node_type::NAMESPACE_DECLARATION, top.size(), location ); + std::memcpy(namespace_node->children.get_data(), top.data(), top.size() * sizeof(handle)); namespace_node->get().identifier_key = identifier_key; - std::memcpy(namespace_node->children.get_data(), top.data(), top.size() * sizeof(handle)); return namespace_node; } auto parser::parse_namespace_block() -> utility::result>> { - // { NAMESPACE | FUNCTION | GLOBAL } + // expect '{ NAMESPACE | FUNCTION | GLOBAL }' EXPECT_CURRENT_TOKEN(token_type::LEFT_BRACE); std::vector> block; m_tokens.next(); - while(m_tokens.get_current_token() != token_type::RIGHT_BRACE) { - handle result = nullptr; + handle parsed = nullptr; if(m_tokens.get_current_token() == token_type::NAMESPACE) { // parse a nested namespace - TRY(result, parse_namespace_declaration()); + TRY(parsed, parse_namespace_declaration()); } else if(peek_is_function_definition()) { // parse a nested function declaration - TRY(result, parse_function_declaration()); + TRY(parsed, parse_function_declaration()); } - else { - // global - NOT_IMPLEMENTED(); + else{ + // parse globals + PANIC("globals aren't implemented yet"); } - block.push_back(result); + block.push_back(parsed); } EXPECT_CURRENT_TOKEN(token_type::RIGHT_BRACE); @@ -74,79 +103,60 @@ namespace sigma { return block; } - auto parser::parse(frontend_context& context) -> utility::result { - return parser(context).parse(); - } - - auto parser::parse() -> utility::result { - // TODO: handle peeks looking past EOF - // TODO: update the allocation strategy -> right now we can request more - // memory that our allocator can allocate per block - // TODO: manage local context (ie. function body, loop body, if body etc), - // probably use a stack - - while (m_tokens.get_current_token() != token_type::END_OF_FILE) { - handle result; - - if(m_tokens.get_current_token() == token_type::NAMESPACE) { - TRY(result, parse_namespace_declaration()); - } - else if (peek_is_function_definition()) { - TRY(result, parse_function_declaration()); - } - else { - // global - NOT_IMPLEMENTED(); - } - - m_context.syntax.ast.add_node(result); - } - - return SUCCESS; - } - auto parser::parse_function_declaration() -> utility::result> { - // TYPE IDENTIFIER ( TYPE IDENTIFIER, ..., TYPE IDENTIFIER ) + // expect 'TYPE IDENTIFIER ( TYPE IDENTIFIER, ..., TYPE IDENTIFIER )' const handle function_location = m_tokens.get_current_token_location(); std::vector parameters; + // parse the return type TRY(const data_type return_type, parse_type()); // parse the function identifier - EXPECT_NEXT_TOKEN(token_type::IDENTIFIER); + EXPECT_CURRENT_TOKEN(token_type::IDENTIFIER); const utility::string_table_key identifier_key = m_tokens.get_current().symbol_key; - m_tokens.next(); // LEFT_PARENTHESIS (guaranteed) + // parse the parameter list + EXPECT_NEXT_TOKEN(token_type::LEFT_PARENTHESIS); + m_tokens.next(); - // parse function parameters - while(m_tokens.peek_next_token() != token_type::RIGHT_PARENTHESIS) { - // prime the type token - m_tokens.next(); - TRY(data_type parameter_type, parse_type()); + if(m_tokens.get_current_token() != token_type::RIGHT_PARENTHESIS) { + while (true) { + // parse the parameter type + TRY(data_type parameter_type, parse_type()); + + // parse the parameter identifier + EXPECT_CURRENT_TOKEN(token_type::IDENTIFIER); + auto parameter_identifier_key = m_tokens.get_current().symbol_key; + parameters.emplace_back(parameter_type, parameter_identifier_key); - // prime the identifier - EXPECT_NEXT_TOKEN(token_type::IDENTIFIER); - const auto parameter_identifier_key = m_tokens.get_current().symbol_key; - parameters.emplace_back(parameter_type, parameter_identifier_key); + // consume the next token and check if it's the end of the parameter list + m_tokens.next(); + + if(m_tokens.get_current_token() == token_type::RIGHT_PARENTHESIS) { + break; // end of parameter list + } - if (m_tokens.peek_next_token() == token_type::COMMA) { - EXPECT_NEXT_TOKEN(token_type::COMMA); + m_tokens.next(); // prime the next token for the next iteration } } + EXPECT_CURRENT_TOKEN(token_type::RIGHT_PARENTHESIS); + // parse the function body - EXPECT_NEXT_TOKEN(token_type::RIGHT_PARENTHESIS); m_tokens.next(); // prime the first block token - TRY(const std::vector> statements, parse_statement_block()); + utility::block_allocator& allocator = m_context.syntax.ast.get_allocator(); + function_signature signature = { - .return_type = return_type, - .parameter_types = utility::slice(m_context.syntax.ast.get_allocator(), parameters.size()), - .identifier_key = identifier_key + .return_type = return_type, + .parameter_types = utility::slice(allocator, parameters.size()), + .identifier_key = identifier_key }; - const handle function_node = create_node(node_type::FUNCTION_DECLARATION, statements.size(), function_location); + const handle function_node = create_node( + node_type::FUNCTION_DECLARATION, statements.size(), function_location + ); // initialize the function signature auto& function = function_node->get(); @@ -160,14 +170,15 @@ namespace sigma { } auto parser::parse_statement_block() -> utility::result>> { - // { STATEMENT, ..., STATEMENT } + // expect '{ STATEMENT, ..., STATEMENT }' EXPECT_CURRENT_TOKEN(token_type::LEFT_BRACE); + m_tokens.next(); // prime the first statement token + std::vector> statements; - m_tokens.next(); + // parse individual statements while(m_tokens.get_current_token() != token_type::RIGHT_BRACE) { TRY(handle statement, parse_statement()); - statements.push_back(statement); } @@ -178,7 +189,7 @@ namespace sigma { } auto parser::parse_statement() -> utility::result> { - // TYPE | IF | RET | IDENTIFIER ... ; + // expect 'TYPE | IF | RET | IDENTIFIER ... ;' handle result; if(peek_is_variable_declaration()) { @@ -204,13 +215,13 @@ namespace sigma { // expect a trailing semicolon EXPECT_CURRENT_TOKEN(token_type::SEMICOLON); - m_tokens.next(); + m_tokens.next(); return result; } auto parser::parse_return_statement() -> utility::result> { - // RET value + // expect 'RET value' EXPECT_CURRENT_TOKEN(token_type::RET); const handle location = m_tokens.get_current_token_location(); m_tokens.next(); @@ -229,8 +240,7 @@ namespace sigma { } auto parser::parse_if_else_statement_block() -> utility::result> { - // IF ( condition ) { statements } - // ELSE | ELSE IF ( condition ) { statements } + // expect 'IF ( condition ) { statements } ELSE | ELSE IF ( condition ) { statements }' TRY(const handle entry, parse_if_statement()); handle preceding_branch = entry; @@ -254,16 +264,20 @@ namespace sigma { preceding_branch->children[1] = branch_node; // point to the next branch break; } + else { + NOT_IMPLEMENTED(); + } } return entry; } auto parser::parse_if_statement() -> utility::result> { - // IF ( condition ) { statements } + // expect 'IF ( condition ) { statements }' EXPECT_CURRENT_TOKEN(token_type::IF); EXPECT_NEXT_TOKEN(token_type::LEFT_PARENTHESIS); + // parse the condition m_tokens.next(); // prime the expression token TRY(const handle condition, parse_expression()); @@ -275,26 +289,29 @@ namespace sigma { const handle branch_node = create_node(node_type::CONDITIONAL_BRANCH, statements.size() + 2, nullptr); - // copy all child statements - std::memcpy(branch_node->children.get_data() + 2, statements.data(), statements.size() * sizeof(handle)); - branch_node->children[0] = condition; // condition branch_node->children[1] = nullptr; // false condition target + // copy all child statements + std::memcpy(branch_node->children.get_data() + 2, statements.data(), statements.size() * sizeof(handle)); + return branch_node; } auto parser::parse_identifier_statement() -> utility::result> { // parse a statement which starts with an identifier - // parse a namespace, if there is one std::vector namespaces; while(peek_is_namespace_access()) { - // first token here is an IDENTIFIER + // expect 'IDENTIFIER ::' + EXPECT_CURRENT_TOKEN(token_type::IDENTIFIER); namespaces.push_back(m_tokens.get_current().symbol_key); - m_tokens.next(); // COLON 1 - m_tokens.next(); // COLON 2 + + // sanity checks + EXPECT_NEXT_TOKEN(token_type::COLON); + EXPECT_NEXT_TOKEN(token_type::COLON); + m_tokens.next(); // prime the next token } @@ -333,7 +350,7 @@ namespace sigma { } auto parser::parse_function_call(const std::vector& namespaces) -> utility::result> { - // IDENTIFIER ( PARAMETER, ... , PARAMETER ) + // expect 'IDENTIFIER ( PARAMETER, ... , PARAMETER )' EXPECT_CURRENT_TOKEN(token_type::IDENTIFIER); const handle call_location = m_tokens.get_current_token_location(); @@ -344,20 +361,25 @@ namespace sigma { m_tokens.next(); // parse call parameters - while(m_tokens.get_current_token() != token_type::RIGHT_PARENTHESIS) { - TRY(handle expression_node, parse_expression()); - parameters.push_back(expression_node); + if(m_tokens.get_current_token() != token_type::RIGHT_PARENTHESIS) { + while(true) { + TRY(handle expression_node, parse_expression()); + parameters.push_back(expression_node); + + if(m_tokens.get_current_token() == token_type::RIGHT_PARENTHESIS) { + break; // end of parameter list + } - if(m_tokens.get_current_token() == token_type::COMMA) { m_tokens.next(); } } EXPECT_CURRENT_TOKEN(token_type::RIGHT_PARENTHESIS); - m_tokens.next(); // create the callee - const handle call_node = create_node(node_type::FUNCTION_CALL, parameters.size(), call_location); + const handle call_node = create_node( + node_type::FUNCTION_CALL, parameters.size(), call_location + ); // copy over function parameters std::memcpy(call_node->children.get_data(), parameters.data(), parameters.size() * sizeof(handle)); @@ -367,43 +389,52 @@ namespace sigma { function.signature.identifier_key = identifier_key; function.namespaces = namespaces; + m_tokens.next(); return call_node; } auto parser::parse_variable_declaration() -> utility::result> { + // expect 'TYPE IDENTIFIER' const handle location = m_tokens.get_current_token_location(); + handle assigned_value = nullptr; - // first token is the type + // parse the variable type TRY(const data_type type, parse_type()); - handle assigned_value = nullptr; - EXPECT_NEXT_TOKEN(token_type::IDENTIFIER); + // parse the identifier + EXPECT_CURRENT_TOKEN(token_type::IDENTIFIER); const auto identifier_key = m_tokens.get_current().symbol_key; - m_tokens.next(); + // parse an assignment, if there is one if(m_tokens.get_current_token() == token_type::EQUALS_SIGN) { m_tokens.next(); TRY(assigned_value, parse_expression()); } // create the variable node - const handle variable_node = create_node(node_type::VARIABLE_DECLARATION, assigned_value ? 1 : 0, location); - // initialize the variable - auto& variable = variable_node->get(); - variable.identifier_key = identifier_key; - variable.type = type; + handle variable_node; if(assigned_value) { + variable_node = create_node(node_type::VARIABLE_DECLARATION, 1, location); variable_node->children[0] = assigned_value; } + else { + variable_node = create_node(node_type::VARIABLE_DECLARATION, 0, location); + } + + // initialize the variable + auto& variable = variable_node->get(); + variable.identifier_key = identifier_key; + variable.type = type; return variable_node; } auto parser::parse_variable_access() -> utility::result> { - const handle location = m_tokens.get_current_token_location(); + // expect 'IDENTIFIER' EXPECT_CURRENT_TOKEN(token_type::IDENTIFIER); + const handle location = m_tokens.get_current_token_location(); // create the access node const handle variable_node = create_node(node_type::VARIABLE_ACCESS, 0, location); @@ -413,22 +444,23 @@ namespace sigma { variable.identifier_key = m_tokens.get_current().symbol_key; m_tokens.next(); - return variable_node; } auto parser::parse_sizeof() -> utility::result> { - // SIZEOF ( type ) + // expect 'SIZEOF ( type )' EXPECT_CURRENT_TOKEN(token_type::SIZEOF); const handle location = m_tokens.get_current_token_location(); EXPECT_NEXT_TOKEN(token_type::LEFT_PARENTHESIS); + // parse the type m_tokens.next(); // prime the type token TRY(const data_type type, parse_type()); - EXPECT_NEXT_TOKEN(token_type::RIGHT_PARENTHESIS); + EXPECT_CURRENT_TOKEN(token_type::RIGHT_PARENTHESIS); + // create the sizeof node const handle sizeof_node = create_node(node_type::SIZEOF, 0, location); sizeof_node->get().type = type; @@ -437,14 +469,16 @@ namespace sigma { } auto parser::parse_assignment() -> utility::result> { - // = expression + // expect '= expression' EXPECT_CURRENT_TOKEN(token_type::EQUALS_SIGN); const handle location = m_tokens.get_current_token_location(); m_tokens.next(); // create the assignment node - const handle assignment_node = create_node(node_type::VARIABLE_ASSIGNMENT, 2, location); + const handle assignment_node = create_node( + node_type::VARIABLE_ASSIGNMENT, 2, location + ); // handle the assigned expression TRY(assignment_node->children[1], parse_expression()); @@ -526,15 +560,17 @@ namespace sigma { } auto parser::parse_primary() -> utility::result> { - // current token is the first token + // parse a numerical literals if(m_tokens.get_current_token().is_numerical_literal()) { return parse_numerical_literal(); } + // parse an explicit cast if(peek_is_explicit_cast()) { return parse_explicit_cast(); } + // fallback parsers switch (m_tokens.get_current_token()) { case token_type::IDENTIFIER: return parse_identifier_statement(); case token_type::SIZEOF: return parse_sizeof(); @@ -543,31 +579,38 @@ namespace sigma { case token_type::MINUS_SIGN: return parse_negative_expression(); case token_type::BOOL_LITERAL_TRUE: case token_type::BOOL_LITERAL_FALSE: return parse_bool_literal(); - default: error::emit(error::code::UNEXPECTED_TOKEN, m_tokens.get_current_token_location(), m_tokens.get_current_token().to_string()); + default: { + return error::emit( + error::code::UNEXPECTED_TOKEN, + m_tokens.get_current_token_location(), + m_tokens.get_current_token().to_string() + ); + } } - - return nullptr; } auto parser::parse_explicit_cast() -> utility::result> { + // expect 'CAST < TYPE >' + EXPECT_CURRENT_TOKEN(token_type::CAST); const handle location = m_tokens.get_current_token_location(); - // cast(value) - EXPECT_CURRENT_TOKEN(token_type::CAST); EXPECT_NEXT_TOKEN(token_type::LESS_THAN); + // parse the target type m_tokens.next(); // prime the type token TRY(const data_type target_type, parse_type()); - EXPECT_NEXT_TOKEN(token_type::GREATER_THAN); + EXPECT_CURRENT_TOKEN(token_type::GREATER_THAN); EXPECT_NEXT_TOKEN(token_type::LEFT_PARENTHESIS); + // parse the expression we want to cast m_tokens.next(); // prime the statement TRY(const handle value_to_cast, parse_expression()); EXPECT_CURRENT_TOKEN(token_type::RIGHT_PARENTHESIS); m_tokens.next(); // prime the next token (probably a SEMICOLON) + // create the cast node const handle cast_node = create_node(node_type::EXPLICIT_CAST, 1, location); cast_node->children[0] = value_to_cast; @@ -578,29 +621,39 @@ namespace sigma { } auto parser::parse_type() -> utility::result { + // expect '(TYPE | IDENTIFIER)* ... *' const token type_token = m_tokens.get_current_token(); u8 pointer_level = 0; if(!type_token.is_type()) { - return error::emit(error::code::UNEXPECTED_TOKEN, m_tokens.get_current_token_location(), type_token.to_string()); + return error::emit( + error::code::UNEXPECTED_TOKEN, + m_tokens.get_current_token_location(), + type_token.to_string() + ); } + // parse pointers while(m_tokens.peek_next_token() == token_type::ASTERISK) { m_tokens.next(); pointer_level++; } + m_tokens.next(); return data_type{ type_token, pointer_level }; } auto parser::parse_numerical_literal() -> utility::result> { - // NUMERICAL_LITERAL - + // expect 'NUMERICAL_LITERAL' const token literal_token = m_tokens.get_current_token(); const handle location = m_tokens.get_current_token_location(); if(!literal_token.is_numerical_literal()) { - return error::emit(error::code::UNEXPECTED_NON_NUMERICAL, m_tokens.get_current_token_location(), literal_token.to_string()); + return error::emit( + error::code::UNEXPECTED_NON_NUMERICAL, + m_tokens.get_current_token_location(), + literal_token.to_string() + ); } data_type::data_type_base base = data_type::UNKNOWN; @@ -608,11 +661,11 @@ namespace sigma { // these types won't be used most of the time, but its nice to hav a place we can // fall back to switch (literal_token) { - case token_type::SIGNED_LITERAL: base = data_type::I32; break; case token_type::UNSIGNED_LITERAL: base = data_type::U32; break; //case lex::token_type::F32_LITERAL: base = data_type::F32; break; //case lex::token_type::F64_LITERAL: base = data_type::F64; break; - case token_type::HEXADECIMAL_LITERAL: base = data_type::I32; break; + case token_type::SIGNED_LITERAL: + case token_type::HEXADECIMAL_LITERAL: case token_type::BINARY_LITERAL: base = data_type::I32; break; default: PANIC("unhandled literal to data type conversion '{}'", literal_token.to_string()); } @@ -630,7 +683,7 @@ namespace sigma { } auto parser::parse_character_literal() -> utility::result> { - // CHARACTER_LITERAL + // expect 'CHARACTER_LITERAL' EXPECT_CURRENT_TOKEN(token_type::CHARACTER_LITERAL); const handle location = m_tokens.get_current_token_location(); @@ -647,25 +700,24 @@ namespace sigma { } auto parser::parse_string_literal() -> utility::result> { - // STRING_LITERAL + // expect 'STRING_LITERAL' EXPECT_CURRENT_TOKEN(token_type::STRING_LITERAL); const handle location = m_tokens.get_current_token_location(); - const utility::string_table_key literal_key = m_tokens.get_current().symbol_key; - m_tokens.next(); // create the string node const handle string_node = create_node(node_type::STRING_LITERAL, 0, location); // initialize the literal auto& literal = string_node->get(); - literal.value_key = literal_key; + literal.value_key = m_tokens.get_current().symbol_key; literal.type = { data_type::CHAR, 1 }; // char* + m_tokens.next(); return string_node; } auto parser::parse_bool_literal() -> utility::result> { - // BOOL_LITERAL_TRUE | BOOL_LITERAL_FALSE + // expect 'BOOL_LITERAL_TRUE | BOOL_LITERAL_FALSE' const handle location = m_tokens.get_current_token_location(); ASSERT( @@ -697,6 +749,7 @@ namespace sigma { } auto parser::peek_is_function_definition() -> bool { + // peek 'TYPE IDENTIFIER (' // starting token is presumably the beginning token of a type if (!is_current_token_type()) { return false; @@ -713,6 +766,7 @@ namespace sigma { } auto parser::peek_is_explicit_cast() const -> bool { + // peek 'CAST <' if(m_tokens.get_current_token() != token_type::CAST) { return false; } @@ -721,6 +775,7 @@ namespace sigma { } auto parser::peek_is_function_call() const -> bool { + // peek 'IDENTIFIER (' if (m_tokens.get_current_token() != token_type::IDENTIFIER) { return false; } @@ -730,6 +785,7 @@ namespace sigma { } auto parser::peek_is_variable_declaration() -> bool { + // peek 'TYPE * ... * IDENTIFIER' if (!is_current_token_type()) { return false; } @@ -743,9 +799,7 @@ namespace sigma { } auto parser::peek_is_namespace_access() -> bool { - // matches 'IDENTIFIER COLON COLON' - // 'IDENTIFIER::' - + // peek 'IDENTIFIER::' if(m_tokens.get_current_token() != token_type::IDENTIFIER) { return false; } @@ -760,17 +814,6 @@ namespace sigma { return res; } - auto parser::peek_is_double_colon() -> bool { - if(m_tokens.peek_token() != token_type::COLON) { - m_tokens.synchronize(); - return false; - } - - const bool res = m_tokens.peek_token() == token_type::COLON; - m_tokens.synchronize(); - return res; - } - auto parser::create_binary_expression(node_type type, handle left, handle right) const -> handle { return m_context.syntax.ast.create_binary_expression(type, left, right); } diff --git a/source/parser/parser.h b/source/parser/parser.h index 52ae1e0d..74ce5d6b 100644 --- a/source/parser/parser.h +++ b/source/parser/parser.h @@ -2,9 +2,11 @@ // // - Whenever we're parsing the first expected token is located at 'm_tokens.get_current_token()', // after we're done parsing, we also have to prime the next token using 'm_tokens.next()'. -// - Two main parse 'operations' +// - Three main parse 'operations' // 1. Final operation - an operation which does not invoke any other operations -// 2. Operation group - a set of other operation groups / final operations. +// 2. Operation group - a set of other operation groups / final operations. +// 3. Peek operations - looks ahead in the token list and determines if a token sequence is +// present or not. Does not throw errors #pragma once #include "parser/data_type.h" @@ -64,13 +66,15 @@ namespace sigma { auto parse_string_literal() -> utility::result>; auto parse_bool_literal() -> utility::result>; - auto is_current_token_type() const -> bool; + // peeks auto peek_is_function_definition() -> bool; auto peek_is_explicit_cast() const -> bool; auto peek_is_function_call() const -> bool; auto peek_is_variable_declaration() -> bool; auto peek_is_namespace_access() -> bool; - auto peek_is_double_colon() -> bool; + + // utility + auto is_current_token_type() const -> bool; template auto create_node(node_type type, u64 child_count, handle location) const -> handle { diff --git a/tests/variables/negation.s b/tests/variables/negation.s new file mode 100644 index 00000000..1fcfcab0 --- /dev/null +++ b/tests/variables/negation.s @@ -0,0 +1,5 @@ +i32 main() { + i32 value = 10; + i32 value2 = -value; + ret 0; +}