diff --git a/libnixf/src/Basic/diagnostic.py b/libnixf/src/Basic/diagnostic.py index 8261d8548..58f82e9cc 100644 --- a/libnixf/src/Basic/diagnostic.py +++ b/libnixf/src/Basic/diagnostic.py @@ -87,6 +87,12 @@ class Diagnostic(TypedDict): "severity": "Error", "message": "extra `@` for lambda arg", }, + { + "sname": "parse-operator-noassoc", + "cname": "OperatorNotAssociative", + "severity": "Error", + "message": "operator is non-associative", + }, { "sname": "let-dynamic", "cname": "LetDynamic", diff --git a/libnixf/src/Parse/ParseOp.cpp b/libnixf/src/Parse/ParseOp.cpp index 45e7f0b77..0e842bb32 100644 --- a/libnixf/src/Parse/ParseOp.cpp +++ b/libnixf/src/Parse/ParseOp.cpp @@ -3,6 +3,7 @@ #include "Parser.h" +#include "nixf/Basic/Diagnostic.h" #include "nixf/Basic/Nodes/Op.h" #include @@ -115,7 +116,9 @@ std::shared_ptr Parser::parseExprOpBP(unsigned LeftRBP) { if (LeftRBP > LBP) return Prefix; if (LeftRBP == LBP) { - // TODO: noassoc + // Report error, operator OP and expr_op is not associative. + Diags.emplace_back(Diagnostic::DK_OperatorNotAssociative, + Tok.range()); } consume(); assert(LastToken && "consume() should have set LastToken"); diff --git a/libnixf/test/Parse/ParseOp.cpp b/libnixf/test/Parse/ParseOp.cpp index 840f7fb91..444b37643 100644 --- a/libnixf/test/Parse/ParseOp.cpp +++ b/libnixf/test/Parse/ParseOp.cpp @@ -2,6 +2,7 @@ #include "Parser.h" +#include "nixf/Basic/Diagnostic.h" #include "nixf/Basic/Nodes/Op.h" namespace { @@ -71,4 +72,16 @@ TEST(Parser, OpHasAttr_empty) { ASSERT_EQ(Diags.size(), 0); } +TEST(Parser, Op_NonAssociative) { + auto Src = R"(1 == 1 == 1)"sv; + + std::vector Diags; + Parser P(Src, Diags); + auto AST = P.parseExpr(); + + ASSERT_TRUE(AST); + ASSERT_EQ(Diags.size(), 1); + ASSERT_EQ(Diags[0].kind(), Diagnostic::DK_OperatorNotAssociative); +} + } // namespace