diff --git a/src/Parser/Parsing/Impl/AbstractLexer.h b/src/Parser/Parsing/Impl/AbstractLexer.h index 4fc22002..3f8911e7 100644 --- a/src/Parser/Parsing/Impl/AbstractLexer.h +++ b/src/Parser/Parsing/Impl/AbstractLexer.h @@ -259,13 +259,15 @@ protected: return floatingPointValue; } - void ReadNumber(bool& isFloatingPoint, double& floatingPointValue, int& integerValue) + void ReadNumber(bool& isFloatingPoint, bool& hasSignPrefix, double& floatingPointValue, int& integerValue) { const auto& currentLine = CurrentLine(); assert(m_current_line_offset >= 1); assert(isdigit(currentLine.m_line[m_current_line_offset - 1]) || currentLine.m_line[m_current_line_offset - 1] == '.' + || currentLine.m_line[m_current_line_offset - 1] == '+' || currentLine.m_line[m_current_line_offset - 1] == '-'); + hasSignPrefix = currentLine.m_line[m_current_line_offset - 1] == '+' || currentLine.m_line[m_current_line_offset - 1] == '-'; const auto lineLength = currentLine.m_line.size(); if (lineLength - m_current_line_offset >= 1 @@ -341,9 +343,12 @@ public: { for (const auto& line : m_line_cache) { - if (*line.m_filename == pos.m_filename.get() + if (line.m_filename + && *line.m_filename == pos.m_filename.get() && line.m_line_number == pos.m_line) + { return line; + } } return ParserLine(); diff --git a/src/Parser/Parsing/Simple/Expression/SimpleExpressionMatchers.cpp b/src/Parser/Parsing/Simple/Expression/SimpleExpressionMatchers.cpp index 1c87d2cf..dae82f95 100644 --- a/src/Parser/Parsing/Simple/Expression/SimpleExpressionMatchers.cpp +++ b/src/Parser/Parsing/Simple/Expression/SimpleExpressionMatchers.cpp @@ -1,5 +1,6 @@ #include "SimpleExpressionMatchers.h" +#include #include #include "SimpleExpressionConditionalOperator.h" @@ -273,6 +274,30 @@ std::unique_ptr SimpleExpressionMatchers::P } } + const auto hasAddOperation = std::any_of(enabledBinaryOperations.begin(), enabledBinaryOperations.end(), [](const SimpleExpressionBinaryOperationType* type) + { + return type == &SimpleExpressionBinaryOperationType::OPERATION_ADD; + }); + const auto hasSubtractOperation = std::any_of(enabledBinaryOperations.begin(), enabledBinaryOperations.end(), [](const SimpleExpressionBinaryOperationType* type) + { + return type == &SimpleExpressionBinaryOperationType::OPERATION_SUBTRACT; + }); + + if (hasAddOperation && hasSubtractOperation) + { + binaryOperationsMatchers.emplace_back( + create.Or({ + create.IntegerWithSign(), + create.FloatingPointWithSign() + }) + .NoConsume() + .Transform([](const SimpleMatcherFactory::token_list_t& values) + { + return SimpleParserValue::Integer(values[0].get().GetPos(), static_cast(SimpleBinaryOperationId::ADD)); + })); + } + + return create.Or(std::move(binaryOperationsMatchers)).Capture(CAPTURE_BINARY_OPERATION_TYPE); } diff --git a/src/Parser/Parsing/Simple/Matcher/SimpleMatcherFactory.cpp b/src/Parser/Parsing/Simple/Matcher/SimpleMatcherFactory.cpp index 5c5a881b..4d062e32 100644 --- a/src/Parser/Parsing/Simple/Matcher/SimpleMatcherFactory.cpp +++ b/src/Parser/Parsing/Simple/Matcher/SimpleMatcherFactory.cpp @@ -7,6 +7,7 @@ #include "SimpleMatcherKeywordPrefix.h" #include "SimpleMatcherMultiCharacter.h" #include "SimpleMatcherValueType.h" +#include "SimpleMatcherValueTypeAndHasSignPrefix.h" SimpleMatcherFactory::SimpleMatcherFactory(const IMatcherForLabelSupplier* labelSupplier) : AbstractMatcherFactory(labelSupplier) @@ -48,11 +49,21 @@ MatcherFactoryWrapper SimpleMatcherFactory::Integer() const return MatcherFactoryWrapper(std::make_unique(SimpleParserValueType::INTEGER)); } +MatcherFactoryWrapper SimpleMatcherFactory::IntegerWithSign() const +{ + return MatcherFactoryWrapper(std::make_unique(SimpleParserValueType::INTEGER, true)); +} + MatcherFactoryWrapper SimpleMatcherFactory::FloatingPoint() const { return MatcherFactoryWrapper(std::make_unique(SimpleParserValueType::FLOATING_POINT)); } +MatcherFactoryWrapper SimpleMatcherFactory::FloatingPointWithSign() const +{ + return MatcherFactoryWrapper(std::make_unique(SimpleParserValueType::FLOATING_POINT, true)); +} + MatcherFactoryWrapper SimpleMatcherFactory::Char(char c) const { return MatcherFactoryWrapper(std::make_unique(c)); diff --git a/src/Parser/Parsing/Simple/Matcher/SimpleMatcherFactory.h b/src/Parser/Parsing/Simple/Matcher/SimpleMatcherFactory.h index c5a801f5..5831a4fc 100644 --- a/src/Parser/Parsing/Simple/Matcher/SimpleMatcherFactory.h +++ b/src/Parser/Parsing/Simple/Matcher/SimpleMatcherFactory.h @@ -17,7 +17,9 @@ public: _NODISCARD MatcherFactoryWrapper Identifier() const; _NODISCARD MatcherFactoryWrapper String() const; _NODISCARD MatcherFactoryWrapper Integer() const; + _NODISCARD MatcherFactoryWrapper IntegerWithSign() const; _NODISCARD MatcherFactoryWrapper FloatingPoint() const; + _NODISCARD MatcherFactoryWrapper FloatingPointWithSign() const; _NODISCARD MatcherFactoryWrapper Char(char c) const; _NODISCARD MatcherFactoryWrapper MultiChar(int multiCharacterSequenceId) const; _NODISCARD MatcherFactoryWrapper AnyCharBesides(std::vector chars) const; diff --git a/src/Parser/Parsing/Simple/Matcher/SimpleMatcherValueTypeAndHasPrefix.cpp b/src/Parser/Parsing/Simple/Matcher/SimpleMatcherValueTypeAndHasPrefix.cpp new file mode 100644 index 00000000..4378a0e4 --- /dev/null +++ b/src/Parser/Parsing/Simple/Matcher/SimpleMatcherValueTypeAndHasPrefix.cpp @@ -0,0 +1,15 @@ +#include "SimpleMatcherValueTypeAndHasSignPrefix.h" + +SimpleMatcherValueTypeAndHasSignPrefix::SimpleMatcherValueTypeAndHasSignPrefix(const SimpleParserValueType type, bool hasSignPrefix) + : m_type(type), + m_has_sign_prefix(hasSignPrefix) +{ +} + +MatcherResult SimpleMatcherValueTypeAndHasSignPrefix::CanMatch(ILexer* lexer, const unsigned tokenOffset) +{ + const auto& token = lexer->GetToken(tokenOffset); + return token.m_type == m_type && token.m_has_sign_prefix == m_has_sign_prefix + ? MatcherResult::Match(1) + : MatcherResult::NoMatch(); +} diff --git a/src/Parser/Parsing/Simple/Matcher/SimpleMatcherValueTypeAndHasSignPrefix.h b/src/Parser/Parsing/Simple/Matcher/SimpleMatcherValueTypeAndHasSignPrefix.h new file mode 100644 index 00000000..b5564a9c --- /dev/null +++ b/src/Parser/Parsing/Simple/Matcher/SimpleMatcherValueTypeAndHasSignPrefix.h @@ -0,0 +1,16 @@ +#pragma once + +#include "Parsing/Simple/SimpleParserValue.h" +#include "Parsing/Matcher/AbstractMatcher.h" + +class SimpleMatcherValueTypeAndHasSignPrefix final : public AbstractMatcher +{ + SimpleParserValueType m_type; + bool m_has_sign_prefix; + +protected: + MatcherResult CanMatch(ILexer* lexer, unsigned tokenOffset) override; + +public: + explicit SimpleMatcherValueTypeAndHasSignPrefix(SimpleParserValueType type, bool hasSignPrefix); +}; diff --git a/src/Parser/Parsing/Simple/SimpleLexer.cpp b/src/Parser/Parsing/Simple/SimpleLexer.cpp index e95b098b..bb862a37 100644 --- a/src/Parser/Parsing/Simple/SimpleLexer.cpp +++ b/src/Parser/Parsing/Simple/SimpleLexer.cpp @@ -120,18 +120,19 @@ SimpleParserValue SimpleLexer::GetNextToken() if (m_config.m_read_strings && c == '\"') return SimpleParserValue::String(pos, new std::string(ReadString())); - if (m_config.m_read_numbers && (isdigit(c) || (c == '-' || c == '.') && isdigit(PeekChar()))) + if (m_config.m_read_numbers && (isdigit(c) || (c == '+' || c == '-' || c == '.') && isdigit(PeekChar()))) { bool isFloatingPointValue; + bool hasSignPrefix; double doubleValue; int integerValue; - ReadNumber(isFloatingPointValue, doubleValue, integerValue); + ReadNumber(isFloatingPointValue, hasSignPrefix, doubleValue, integerValue); if (isFloatingPointValue) - return SimpleParserValue::FloatingPoint(pos, doubleValue); + return SimpleParserValue::FloatingPoint(pos, doubleValue, hasSignPrefix); - return SimpleParserValue::Integer(pos, integerValue); + return SimpleParserValue::Integer(pos, integerValue, hasSignPrefix); } if (isalpha(c) || c == '_') diff --git a/src/Parser/Parsing/Simple/SimpleParserValue.cpp b/src/Parser/Parsing/Simple/SimpleParserValue.cpp index 51be28c9..3acdac5f 100644 --- a/src/Parser/Parsing/Simple/SimpleParserValue.cpp +++ b/src/Parser/Parsing/Simple/SimpleParserValue.cpp @@ -41,6 +41,14 @@ SimpleParserValue SimpleParserValue::Integer(const TokenPos pos, const int value return pv; } +SimpleParserValue SimpleParserValue::Integer(const TokenPos pos, const int value, const bool hasSignPrefix) +{ + SimpleParserValue pv(pos, SimpleParserValueType::INTEGER); + pv.m_value.int_value = value; + pv.m_has_sign_prefix = hasSignPrefix; + return pv; +} + SimpleParserValue SimpleParserValue::FloatingPoint(const TokenPos pos, const double value) { SimpleParserValue pv(pos, SimpleParserValueType::FLOATING_POINT); @@ -48,6 +56,14 @@ SimpleParserValue SimpleParserValue::FloatingPoint(const TokenPos pos, const dou return pv; } +SimpleParserValue SimpleParserValue::FloatingPoint(const TokenPos pos, const double value, const bool hasSignPrefix) +{ + SimpleParserValue pv(pos, SimpleParserValueType::FLOATING_POINT); + pv.m_value.double_value = value; + pv.m_has_sign_prefix = hasSignPrefix; + return pv; +} + SimpleParserValue SimpleParserValue::String(const TokenPos pos, std::string* stringValue) { SimpleParserValue pv(pos, SimpleParserValueType::STRING); @@ -67,6 +83,7 @@ SimpleParserValue::SimpleParserValue(const TokenPos pos, const SimpleParserValue : m_pos(pos), m_type(type), m_hash(0), + m_has_sign_prefix(false), m_value{} { } @@ -91,6 +108,7 @@ SimpleParserValue::SimpleParserValue(SimpleParserValue&& other) noexcept : m_pos(other.m_pos), m_type(other.m_type), m_hash(other.m_hash), + m_has_sign_prefix(other.m_has_sign_prefix), m_value(other.m_value) { other.m_value = ValueType(); @@ -102,6 +120,7 @@ SimpleParserValue& SimpleParserValue::operator=(SimpleParserValue&& other) noexc m_type = other.m_type; m_value = other.m_value; m_hash = other.m_hash; + m_has_sign_prefix = other.m_has_sign_prefix; other.m_value = ValueType(); return *this; diff --git a/src/Parser/Parsing/Simple/SimpleParserValue.h b/src/Parser/Parsing/Simple/SimpleParserValue.h index 520294f0..79cd3d40 100644 --- a/src/Parser/Parsing/Simple/SimpleParserValue.h +++ b/src/Parser/Parsing/Simple/SimpleParserValue.h @@ -33,6 +33,7 @@ public: TokenPos m_pos; SimpleParserValueType m_type; size_t m_hash; + bool m_has_sign_prefix; union ValueType { char char_value; @@ -48,7 +49,9 @@ public: static SimpleParserValue Character(TokenPos pos, char c); static SimpleParserValue MultiCharacter(TokenPos pos, int multiCharacterSequenceId); static SimpleParserValue Integer(TokenPos pos, int value); + static SimpleParserValue Integer(TokenPos pos, int value, bool hasSignPrefix); static SimpleParserValue FloatingPoint(TokenPos pos, double value); + static SimpleParserValue FloatingPoint(TokenPos pos, double value, bool hasSignPrefix); static SimpleParserValue String(TokenPos pos, std::string* stringValue); static SimpleParserValue Identifier(TokenPos pos, std::string* identifier); diff --git a/src/ZoneCodeGeneratorLib/Parsing/Commands/Impl/CommandsLexer.cpp b/src/ZoneCodeGeneratorLib/Parsing/Commands/Impl/CommandsLexer.cpp index 99d66933..97ec0b7a 100644 --- a/src/ZoneCodeGeneratorLib/Parsing/Commands/Impl/CommandsLexer.cpp +++ b/src/ZoneCodeGeneratorLib/Parsing/Commands/Impl/CommandsLexer.cpp @@ -119,10 +119,11 @@ CommandsParserValue CommandsLexer::GetNextToken() if (isdigit(c)) { bool isFloatingPointValue; + bool hasSignPrefix; double doubleValue; int integerValue; - ReadNumber(isFloatingPointValue, doubleValue, integerValue); + ReadNumber(isFloatingPointValue, hasSignPrefix, doubleValue, integerValue); if (isFloatingPointValue) return CommandsParserValue::FloatingPoint(pos, doubleValue); diff --git a/src/ZoneCodeGeneratorLib/Parsing/Header/Impl/HeaderLexer.cpp b/src/ZoneCodeGeneratorLib/Parsing/Header/Impl/HeaderLexer.cpp index b2a70215..ff4dd034 100644 --- a/src/ZoneCodeGeneratorLib/Parsing/Header/Impl/HeaderLexer.cpp +++ b/src/ZoneCodeGeneratorLib/Parsing/Header/Impl/HeaderLexer.cpp @@ -138,10 +138,11 @@ HeaderParserValue HeaderLexer::GetNextToken() if(isdigit(c)) { bool isFloatingPointValue; + bool hasSignPrefix; double doubleValue; int integerValue; - ReadNumber(isFloatingPointValue, doubleValue, integerValue); + ReadNumber(isFloatingPointValue, hasSignPrefix, doubleValue, integerValue); if (isFloatingPointValue) return HeaderParserValue::FloatingPoint(pos, doubleValue); diff --git a/test/ParserTests/Parsing/Simple/SimpleExpressionTests.cpp b/test/ParserTests/Parsing/Simple/SimpleExpressionTests.cpp index ce35b69a..8eaec2e8 100644 --- a/test/ParserTests/Parsing/Simple/SimpleExpressionTests.cpp +++ b/test/ParserTests/Parsing/Simple/SimpleExpressionTests.cpp @@ -1,6 +1,9 @@ #include +#include + #include "Parsing/Impl/AbstractParser.h" +#include "Parsing/Impl/ParserSingleInputStream.h" #include "Utils/ClassUtils.h" #include "Parsing/Mock/MockLexer.h" #include "Parsing/Simple/SimpleParserValue.h" @@ -33,22 +36,54 @@ namespace test::parsing::simple::expression protected: void ProcessMatch(SimpleExpressionTestState* state, SequenceResult& result) const override { + if (state->m_expression) + throw ParsingException(TokenPos(), "Expression already set"); + state->m_expression = m_expression_matchers.ProcessExpression(result); } }; + class SimpleExpressionParser final : public AbstractParser + { + public: + explicit SimpleExpressionParser(ILexer* lexer) + : AbstractParser(lexer, std::make_unique()) + { + } + + _NODISCARD SimpleExpressionTestState* GetState() const + { + return m_state.get(); + } + + protected: + const std::vector& GetTestsForState() override + { + static std::vector tests({ + new SimpleExpressionSequence() + }); + + return tests; + } + }; + class SimpleExpressionTestsHelper { public: - std::unique_ptr m_state; + SimpleExpressionTestState* m_state; + std::unique_ptr m_state_holder; + std::string m_str; + std::istringstream m_ss; + std::unique_ptr m_stream; std::unique_ptr> m_lexer; + std::unique_ptr m_parser; std::unique_ptr m_sequence; unsigned m_consumed_token_count; - explicit SimpleExpressionTestsHelper() - : m_state(std::make_unique()), + SimpleExpressionTestsHelper() + : m_state(nullptr), m_sequence(std::make_unique()), m_consumed_token_count(0u) { @@ -56,20 +91,48 @@ namespace test::parsing::simple::expression void Tokens(std::initializer_list> tokens) { + m_state_holder = std::make_unique(); + m_state = m_state_holder.get(); m_lexer = std::make_unique>(tokens, SimpleParserValue::EndOfFile(TokenPos())); } void Tokens(std::vector tokens) { + m_state_holder = std::make_unique(); + m_state = m_state_holder.get(); m_lexer = std::make_unique>(std::move(tokens), SimpleParserValue::EndOfFile(TokenPos())); } + void String(std::string str) + { + m_str = std::move(str); + m_ss = std::istringstream(m_str); + m_stream = std::make_unique(m_ss, "InputString"); + + SimpleLexer::Config lexerConfig; + lexerConfig.m_read_strings = true; + lexerConfig.m_read_numbers = true; + lexerConfig.m_emit_new_line_tokens = false; + SimpleExpressionMatchers(true, true, true, true, true).ApplyTokensToLexerConfig(lexerConfig); + m_lexer = std::make_unique(m_stream.get(), std::move(lexerConfig)); + m_parser = std::make_unique(m_lexer.get()); + m_state = m_parser->GetState(); + } + bool PerformTest() { REQUIRE(m_lexer); m_consumed_token_count = 0; - return m_sequence->MatchSequence(m_lexer.get(), m_state.get(), m_consumed_token_count); + return m_sequence->MatchSequence(m_lexer.get(), m_state, m_consumed_token_count); + } + + _NODISCARD bool PerformIntegrationTest() const + { + REQUIRE(m_lexer); + REQUIRE(m_parser); + + return m_parser->Parse(); } }; @@ -738,4 +801,41 @@ namespace test::parsing::simple::expression REQUIRE(value.m_type == SimpleExpressionValue::Type::INT); REQUIRE(value.m_int_value == 1337); } + + namespace it + { + TEST_CASE("SimpleExpressionsIT: Can parse subtraction without space", "[parsing][simple][expression][it]") + { + SimpleExpressionTestsHelper helper; + helper.String("6-5"); + + const auto result = helper.PerformIntegrationTest(); + + REQUIRE(result); + + const auto& expression = helper.m_state->m_expression; + REQUIRE(expression->IsStatic()); + + const auto value = expression->Evaluate(); + REQUIRE(value.m_type == SimpleExpressionValue::Type::INT); + REQUIRE(value.m_int_value == 1); + } + + TEST_CASE("SimpleExpressionsIT: Can parse addition without space", "[parsing][simple][expression][it]") + { + SimpleExpressionTestsHelper helper; + helper.String("6+5"); + + const auto result = helper.PerformIntegrationTest(); + + REQUIRE(result); + + const auto& expression = helper.m_state->m_expression; + REQUIRE(expression->IsStatic()); + + const auto value = expression->Evaluate(); + REQUIRE(value.m_type == SimpleExpressionValue::Type::INT); + REQUIRE(value.m_int_value == 11); + } + } }