diff --git a/lib/include/artichoke/Parser/AST/Expressions.hpp b/lib/include/artichoke/Parser/AST/Expressions.hpp index 695b541..e24679f 100644 --- a/lib/include/artichoke/Parser/AST/Expressions.hpp +++ b/lib/include/artichoke/Parser/AST/Expressions.hpp @@ -40,7 +40,8 @@ namespace arti::lang::ast { struct SliceAccessExpression; struct SliceRangeExpression; struct MemberAccessExpression; - struct PointerAccessExpression; + struct PointerMemberAccessExpression; + struct GenericExpression; struct ModuleAccessExpression; struct ReflectionExpression; struct SliceCreationExpression; @@ -59,7 +60,8 @@ namespace arti::lang::ast { using SliceAccessExprNode = Ptr; using SliceRangeExprNode = Ptr; using MemberAccessExprNode = Ptr; - using PointerAccessExprNode = Ptr; + using PointerMemberAccessExprNode = Ptr; + using GenericExprNode = Ptr; using ModuleAccessExprNode = Ptr; using ReflectionExprNode = Ptr; using SliceCreationExprNode = Ptr; @@ -85,7 +87,8 @@ namespace arti::lang::ast { SliceAccessExprNode, SliceRangeExprNode, MemberAccessExprNode, - PointerAccessExprNode, + PointerMemberAccessExprNode, + GenericExprNode, ModuleAccessExprNode, SliceCreationExprNode, SliceLengthExprNode, @@ -153,23 +156,29 @@ namespace arti::lang::ast { struct nodes::MemberAccessExpression { SourceLocation location; - String memberName; + ExpressionNode member; ExpressionNode object; }; - struct nodes::PointerAccessExpression { + struct nodes::PointerMemberAccessExpression { SourceLocation location; - String memberName; + ExpressionNode member; ExpressionNode object; }; struct nodes::ModuleAccessExpression { SourceLocation location; - String memberName; - ExpressionNode scope; - Vector genericParams; + ExpressionNode left; + ExpressionNode right; + }; + + struct nodes::GenericExpression { + SourceLocation location; + + ExpressionNode typeNode; + std::vector genericArgs; }; struct nodes::ReflectionExpression { diff --git a/lib/include/artichoke/Parser/AST/Types.hpp b/lib/include/artichoke/Parser/AST/Types.hpp index 040d76b..37b2143 100644 --- a/lib/include/artichoke/Parser/AST/Types.hpp +++ b/lib/include/artichoke/Parser/AST/Types.hpp @@ -33,7 +33,6 @@ namespace arti::lang::ast { struct Type; struct GenericType; struct IdentifierType; - struct NamespacedType; /* Helper type node types */ struct NamespacedIdentifier; @@ -44,14 +43,12 @@ namespace arti::lang::ast { using TypeNode = Ptr; using GenericTypeNode = Ptr; using IdentifierTypeNode = Ptr; - using NamespacedTypeNode = Ptr; using NamespacedIdentifierNode = Ptr; /* Variant nodes */ using TypeExpressionNode = Variant< GenericTypeNode, - IdentifierTypeNode, - NamespacedTypeNode + IdentifierTypeNode >; /* Node definitions */ @@ -60,27 +57,20 @@ namespace arti::lang::ast { SourceLocation location; Vector qualifiers; - TypeExpressionNode baseType; + Vector typeNodes; }; struct nodes::GenericType { SourceLocation location; - TypeExpressionNode baseType; + String typeName; Vector genericArgs; }; struct nodes::IdentifierType { SourceLocation location; - NamespacedIdentifierNode typeName; - }; - - struct nodes::NamespacedType { - SourceLocation location; - String typeName; - TypeExpressionNode baseType; }; struct nodes::NamespacedIdentifier { diff --git a/lib/src/Parser/AST/toDot.cpp b/lib/src/Parser/AST/toDot.cpp index 50042f9..461e756 100644 --- a/lib/src/Parser/AST/toDot.cpp +++ b/lib/src/Parser/AST/toDot.cpp @@ -171,8 +171,6 @@ namespace arti::lang::ast { std::string emit(const TypeNode &, GraphBuilder &); std::string emit(const GenericTypeNode &, GraphBuilder &); std::string emit(const IdentifierTypeNode &, GraphBuilder &); - std::string emit(const NamespacedTypeNode &, GraphBuilder &); - std::string emit(const NamespacedIdentifierNode &, GraphBuilder &); std::string emit(const TypeExpressionNode &, GraphBuilder &); std::string emit(const CharLtrlNode &, GraphBuilder &); std::string emit(const NullLtrlNode &, GraphBuilder &); @@ -196,7 +194,8 @@ namespace arti::lang::ast { std::string emit(const SliceAccessExprNode &, GraphBuilder &); std::string emit(const SliceRangeExprNode &, GraphBuilder &); std::string emit(const MemberAccessExprNode &, GraphBuilder &); - std::string emit(const PointerAccessExprNode &, GraphBuilder &); + std::string emit(const PointerMemberAccessExprNode &, GraphBuilder &); + std::string emit(const GenericExprNode &, GraphBuilder &); std::string emit(const ModuleAccessExprNode &, GraphBuilder &); std::string emit(const ReflectionExprNode &, GraphBuilder &); std::string emit(const SliceCreationExprNode &, GraphBuilder &); @@ -494,15 +493,16 @@ namespace arti::lang::ast { }); } } - auto baseId = emit(node->baseType, g); - g.addEdge(id, baseId, "BaseType"); + emitGroupVec(g, id, "TypeNodes", node->typeNodes, [&](const auto &arg) { + return emit(arg, g); + }); return id; } std::string emit(const GenericTypeNode &node, GraphBuilder &g) { auto id = g.makeNode("GenericType"); - auto baseId = emit(node->baseType, g); - g.addEdge(id, baseId, "BaseType"); + auto typeId = g.makeNode(node->typeName); + g.addEdge(id, typeId, "TypeName"); if (! node->genericArgs.empty()) { emitGroupVec( g, @@ -516,30 +516,17 @@ namespace arti::lang::ast { } std::string emit(const IdentifierTypeNode &node, GraphBuilder &g) { + std::ignore = node; auto id = g.makeNode("IdentifierType"); - auto cid = emit(node->typeName, g); - g.addEdge(id, cid, "TypeName"); + auto typeId = g.makeNode(node->typeName); + g.addEdge(id, typeId, "TypeName"); return id; } - std::string emit(const NamespacedTypeNode &node, GraphBuilder &g) { - auto id = g.makeNode("NamespacedType"); - auto baseId = emit(node->baseType, g); - g.addEdge(id, baseId, "BaseType"); - auto leaf = makeLeaf(g, node->typeName); - g.addEdge(id, leaf, "TypeName"); - return id; - } - - std::string emit(const NamespacedIdentifierNode &node, GraphBuilder &g) { - return g.makeNode(namespacedIdentToString(node)); - } - std::string emit(const TypeExpressionNode &node, GraphBuilder &g) { auto visitor = OverloadSet{ [&g](const GenericTypeNode &n) { return emit(n, g); }, [&g](const IdentifierTypeNode &n) { return emit(n, g); }, - [&g](const NamespacedTypeNode &n) { return emit(n, g); }, }; return std::visit(visitor, node); } @@ -714,30 +701,36 @@ namespace arti::lang::ast { std::string emit(const MemberAccessExprNode &node, GraphBuilder &g) { auto id = g.makeNode("MemberAccessExpression"); g.addEdge(id, emit(node->object, g), "Object"); - g.addEdge(id, makeLeaf(g, node->memberName), "Member"); + g.addEdge(id, emit(node->member, g), "Member"); return id; } - std::string emit(const PointerAccessExprNode &node, GraphBuilder &g) { + std::string emit(const PointerMemberAccessExprNode &node, GraphBuilder &g) { auto id = g.makeNode("PointerAccessExpression"); g.addEdge(id, emit(node->object, g), "Object"); - g.addEdge(id, makeLeaf(g, node->memberName), "Member"); + g.addEdge(id, emit(node->member, g), "Member"); return id; } std::string emit(const ModuleAccessExprNode &node, GraphBuilder &g) { - auto id = g.makeNode("ScopeAccessExpression"); - g.addEdge(id, emit(node->scope, g), "Object"); - if (! node->genericParams.empty()) { + auto id = g.makeNode("ModuleAccessExpression"); + g.addEdge(id, emit(node->left, g), "Scope"); + g.addEdge(id, emit(node->right, g), "Member"); + return id; + } + + std::string emit(const GenericExprNode &node, GraphBuilder &g) { + auto id = g.makeNode("GenericExpression"); + g.addEdge(id, emit(node->typeNode, g), "TypeNode"); + if (! node->genericArgs.empty()) { emitGroupVec( g, id, - "GenericParams", - node->genericParams, - [&](const auto &p) { return emit(p, g); } + "GenericArguments", + node->genericArgs, + [&](const auto &arg) { return emit(arg, g); } ); } - g.addEdge(id, makeLeaf(g, node->memberName), "Member"); return id; } @@ -788,12 +781,13 @@ namespace arti::lang::ast { [&g](const SliceAccessExprNode &n) { return emit(n, g); }, [&g](const SliceRangeExprNode &n) { return emit(n, g); }, [&g](const MemberAccessExprNode &n) { return emit(n, g); }, - [&g](const PointerAccessExprNode &n) { return emit(n, g); }, + [&g](const PointerMemberAccessExprNode &n) { return emit(n, g); }, [&g](const ModuleAccessExprNode &n) { return emit(n, g); }, [&g](const SliceCreationExprNode &n) { return emit(n, g); }, [&g](const SliceLengthExprNode &n) { return emit(n, g); }, [&g](const SlicePtrExprNode &n) { return emit(n, g); }, [&g](const ReflectionExprNode &n) { return emit(n, g); }, + [&g](const GenericExprNode &n) { return emit(n, g); }, }; return std::visit(visitor, node); } diff --git a/lib/src/Parser/AST/toString.cpp b/lib/src/Parser/AST/toString.cpp index 0b27951..6ec8b31 100644 --- a/lib/src/Parser/AST/toString.cpp +++ b/lib/src/Parser/AST/toString.cpp @@ -45,7 +45,6 @@ namespace arti::lang::ast { std::string toString(const TypeNode &, std::string); std::string toString(const GenericTypeNode &, std::string); std::string toString(const IdentifierTypeNode &, std::string); - std::string toString(const NamespacedTypeNode &, std::string); std::string toString(const NamespacedIdentifierNode &, std::string); std::string toString(const TypeExpressionNode &, std::string); std::string toString(const CharLtrlNode &, std::string); @@ -70,7 +69,8 @@ namespace arti::lang::ast { std::string toString(const SliceAccessExprNode &, std::string); std::string toString(const SliceRangeExprNode &, std::string); std::string toString(const MemberAccessExprNode &, std::string); - std::string toString(const PointerAccessExprNode &, std::string); + std::string toString(const PointerMemberAccessExprNode &, std::string); + std::string toString(const GenericExprNode &, std::string); std::string toString(const ModuleAccessExprNode &, std::string); std::string toString(const ReflectionExprNode &, std::string); std::string toString(const SliceCreationExprNode &, std::string); @@ -126,6 +126,17 @@ namespace arti::lang::ast { << toString(item, nextPrefix(prefix, isLastChild)); } + void appendItemString( + std::stringstream &ss, + const std::string &prefix, + const std::string &item, + bool isLastChild + ) { + ss << "\n" + << prefix << (isLastChild ? StrTreeLast : StrTreeChilds) << " " + << item; + } + template void appendGroupVec( std::stringstream &ss, @@ -529,12 +540,22 @@ namespace arti::lang::ast { if (! qls.empty()) { ++total; } - ++total; // BaseType is always present + if (! node->typeNodes.empty()) { + ++total; + } int emitted = 0; if (! qls.empty()) { appendGroupLeafList(ss, prefix, "Qualifiers", qls, ++emitted == total); } - appendGroupOne(ss, prefix, "BaseType", node->baseType, ++emitted == total); + if (! node->typeNodes.empty()) { + appendGroupVec( + ss, + prefix, + "TypeNodes", + node->typeNodes, + ++emitted == total + ); + } return ss.str(); } @@ -546,7 +567,9 @@ namespace arti::lang::ast { ++total; } int emitted = 0; - appendGroupOne(ss, prefix, "BaseType", node->baseType, ++emitted == total); + + appendItemString(ss, prefix, std::format("TypeName `{}`", node->typeName), ++emitted == total); + if (! node->genericArgs.empty()) { appendGroupVec( ss, @@ -560,17 +583,10 @@ namespace arti::lang::ast { } std::string toString(const IdentifierTypeNode &node, std::string prefix) { + std::ignore = node; + std::ignore = prefix; std::stringstream ss; - ss << "IdentifierType"; - appendGroupOne(ss, prefix, "TypeName", node->typeName, true); - return ss.str(); - } - - std::string toString(const NamespacedTypeNode &node, std::string prefix) { - std::stringstream ss; - ss << "NamespacedType"; - appendGroupOne(ss, prefix, "BaseType", node->baseType, false); - appendGroupLeaf(ss, prefix, "TypeName", node->typeName, true); + ss << "TypeName `" << node->typeName << "`"; return ss.str(); } @@ -591,9 +607,6 @@ namespace arti::lang::ast { [padding](const IdentifierTypeNode &node) -> std::string { return toString(node, padding); }, - [padding](const NamespacedTypeNode &node) -> std::string { - return toString(node, padding); - }, }; return std::visit(visitor, node); @@ -837,37 +850,46 @@ namespace arti::lang::ast { std::stringstream ss; ss << "MemberAccessExpression"; appendGroupOne(ss, prefix, "Object", node->object, false); - appendGroupLeaf(ss, prefix, "Member", node->memberName, true); + appendGroupOne(ss, prefix, "Member", node->member, true); return ss.str(); } - std::string toString(const PointerAccessExprNode &node, std::string prefix) { + std::string toString(const PointerMemberAccessExprNode &node, std::string prefix) { std::stringstream ss; ss << "PointerAccessExpression"; appendGroupOne(ss, prefix, "Object", node->object, false); - appendGroupLeaf(ss, prefix, "Member", node->memberName, true); + appendGroupOne(ss, prefix, "Member", node->member, true); return ss.str(); } std::string toString(const ModuleAccessExprNode &node, std::string prefix) { std::stringstream ss; - ss << "ScopeAccessExpression"; + ss << "ModuleAccessExpression"; int total = 2; - if (! node->genericParams.empty()) { + int emitted = 0; + appendGroupOne(ss, prefix, "Scope", node->left, ++emitted == total); + appendGroupOne(ss, prefix, "Member", node->right, ++emitted == total); + return ss.str(); + } + + std::string toString(const GenericExprNode &node, std::string prefix) { + std::stringstream ss; + ss << "GenericExpression"; + int total = 1; + if (! node->genericArgs.empty()) { ++total; } int emitted = 0; - appendGroupOne(ss, prefix, "Object", node->scope, ++emitted == total); - if (! node->genericParams.empty()) { + appendGroupOne(ss, prefix, "TypeNode", node->typeNode, ++emitted == total); + if (! node->genericArgs.empty()) { appendGroupVec( ss, prefix, - "GenericParams", - node->genericParams, + "GenericArguments", + node->genericArgs, ++emitted == total ); } - appendGroupLeaf(ss, prefix, "Member", node->memberName, ++emitted == total); return ss.str(); } @@ -967,7 +989,7 @@ namespace arti::lang::ast { [padding](const MemberAccessExprNode &node) -> std::string { return toString(node, padding); }, - [padding](const PointerAccessExprNode &node) -> std::string { + [padding](const PointerMemberAccessExprNode &node) -> std::string { return toString(node, padding); }, [padding](const ModuleAccessExprNode &node) -> std::string { @@ -985,6 +1007,9 @@ namespace arti::lang::ast { [padding](const ReflectionExprNode &node) -> std::string { return toString(node, padding); }, + [padding](const GenericExprNode &node) -> std::string { + return toString(node, padding); + }, }; return std::visit(visitor, node); diff --git a/lib/src/Parser/Expressions.cpp b/lib/src/Parser/Expressions.cpp index c7ffb89..a55fae1 100644 --- a/lib/src/Parser/Expressions.cpp +++ b/lib/src/Parser/Expressions.cpp @@ -274,6 +274,30 @@ namespace arti::lang { auto op = pratt::getInfixOperator(peekToken->value); auto [lbp, rbp] = pratt::infixBindingPower(op); + if (op == ast::InfixOperator::ModuleAccess) { + if (auto isGeneric = match(TokenV::opLt); ! isGeneric) { + return Unexpected<>{ std::move(isGeneric).error() }; + } + else if (isGeneric.value()) { + auto node = ast::MakeNode(); + + node->location = { + .line = peekToken->line, + .column = peekToken->column + }; + + if (auto args = parseGenericArgumentsList(); ! args) { + return Unexpected<>{ std::move(args).error() }; + } + else { + node->typeNode = std::move(lhs); + node->genericArgs = std::move(args).value(); + } + + return node; + } + } + auto rhs = parseExpression(rbp); if (! rhs) { @@ -282,7 +306,6 @@ namespace arti::lang { /* TODO: MemberAccess and PointerMemberAccess do not use their respective * nodes types yet */ - /* TODO: ModuleAccess do not use its respective node type yet */ if (op == ast::InfixOperator::Assignment) { auto node = ast::MakeNode(); @@ -296,6 +319,45 @@ namespace arti::lang { return node; } + else if (op == ast::InfixOperator::ModuleAccess) { + auto node = ast::MakeNode(); + + node->location = { + .line = peekToken->line, + .column = peekToken->column + }; + + node->left = std::move(lhs); + node->right = std::move(rhs).value(); + + return node; + } + else if (op == ast::InfixOperator::MemberAccess) { + auto node = ast::MakeNode(); + + node->location = { + .line = peekToken->line, + .column = peekToken->column + }; + + node->object = std::move(lhs); + node->member = std::move(rhs).value(); + + return node; + } + else if (op == ast::InfixOperator::PointerMemberAccess) { + auto node = ast::MakeNode(); + + node->location = { + .line = peekToken->line, + .column = peekToken->column + }; + + node->object = std::move(lhs); + node->member = std::move(rhs).value(); + + return node; + } else if (pratt::isCompoundAssignOperator(op)) { auto node = ast::MakeNode(); diff --git a/lib/src/Parser/Types.cpp b/lib/src/Parser/Types.cpp index 650fe77..ec18e98 100644 --- a/lib/src/Parser/Types.cpp +++ b/lib/src/Parser/Types.cpp @@ -72,7 +72,6 @@ namespace arti::lang { Expected Parser::parseType() { auto node = ast::MakeNode(); - auto currentNode = ast::TypeExpressionNode{}; if (auto nextToken = tokenizer.peek(); ! nextToken) { return Unexpected<>{ std::move(nextToken).error() }; @@ -93,105 +92,91 @@ namespace arti::lang { } } - if (auto identType = parseNamespacedIdentifier(); ! identType) { - return Unexpected<>{ std::move(identType).error() }; + if (auto ident = match(TokenV::tkIdentifier); ! ident) { + return Unexpected<>{ std::move(ident).error() }; } - else { - currentNode = ast::MakeNode(); + else if (not ident.value()) { + auto peekToken = tokenizer.peek(); - std::get(currentNode)->location = - (*identType)->location; - - std::get(currentNode)->typeName = - std::move(identType).value(); - } - - if (auto lt = matchAndConsume(TokenV::opLt); ! lt) { - return Unexpected<>{ std::move(lt).error() }; - } - else if (lt.value()) { - if (auto genericArgs = parseGenericArgumentsList(); ! genericArgs) { - return Unexpected<>{ std::move(genericArgs).error() }; + if (! peekToken) { + return Unexpected<>{ std::move(peekToken).error() }; } - else { - auto genParamsNode = ast::MakeNode(); - genParamsNode->location = std::visit( - [](const auto &node) { return node->location; }, - currentNode - ); - - genParamsNode->baseType = std::move(currentNode); - genParamsNode->genericArgs = std::move(genericArgs).value(); - currentNode = std::move(genParamsNode); - - if (auto gt = consume(TokenV::opGt, "'>'"); ! gt) { - return Unexpected<>{ std::move(gt).error() }; - } - } + return langException( + peekToken->line, + peekToken->column, + toString(*peekToken), + "identifier type name" + ); } - bool keepParsing = false; - - if (auto access = matchAndConsume(TokenV::opAccess); ! access) { - return Unexpected<>{ std::move(access).error() }; - } - else if (access.value()) { - keepParsing = true; - } + bool keepParsing = true; while (keepParsing) { + auto currentNode = ast::TypeExpressionNode{}; + if (auto ident = consume(TokenV::tkIdentifier, "identifier"); ! ident) { return Unexpected<>{ std::move(ident).error() }; } else { - auto newNode = ast::MakeNode(); - - newNode->location = std::visit( - [](const auto &node) { return node->location; }, - currentNode - ); + auto newNode = ast::MakeNode(); + newNode->location = { + .line = ident->line, + .column = ident->column + }; newNode->typeName = ident->strValue; - newNode->baseType = std::move(currentNode); - currentNode = std::move(newNode); - } - if (auto lt = matchAndConsume(TokenV::opLt); ! lt) { - return Unexpected<>{ std::move(lt).error() }; - } - else if (lt.value()) { - if (auto genericArgs = parseGenericArgumentsList(); ! genericArgs) { - return Unexpected<>{ std::move(genericArgs).error() }; + if (auto access = match(TokenV::opAccess); ! access) { + return Unexpected<>{ std::move(access).error() }; + } + else if (not access.value()) { + currentNode = std::move(newNode); + keepParsing = false; } else { - auto genParamsNode = ast::MakeNode(); + std::ignore = tokenizer.consume(); - genParamsNode->location = std::visit( - [](const auto &node) { return node->location; }, - currentNode - ); + if (auto access = match(TokenV::opLt); ! access) { + return Unexpected<>{ std::move(access).error() }; + } + else if (not access.value()) { + currentNode = std::move(newNode); + } + else { + auto newNode = ast::MakeNode(); - genParamsNode->baseType = std::move(currentNode); - genParamsNode->genericArgs = std::move(genericArgs).value(); - currentNode = std::move(genParamsNode); + newNode->location = { + .line = ident->line, + .column = ident->column + }; + newNode->typeName = ident->strValue; - if (auto gt = consume(TokenV::opGt, "'>'"); ! gt) { - return Unexpected<>{ std::move(gt).error() }; + if (auto args = parseGenericArgumentsList(); ! args) { + return Unexpected<>{ std::move(args).error() }; + } + else { + newNode->genericArgs = std::move(args).value(); + } + + if (auto access = match(TokenV::opAccess); ! access) { + return Unexpected<>{ std::move(access).error() }; + } + else if (not access.value()) { + keepParsing = false; + } + else { + std::ignore = tokenizer.consume(); + } + + currentNode = std::move(newNode); } } } - if (auto access = matchAndConsume(TokenV::opAccess); ! access) { - return Unexpected<>{ std::move(access).error() }; - } - else { - keepParsing = access.value(); - } + node->typeNodes.emplace_back(std::move(currentNode)); } - node->baseType = std::move(currentNode); - return node; } @@ -268,11 +253,9 @@ namespace arti::lang { Expected> Parser::parseGenericArgumentsList() { auto args = ast::Vector{}; - - auto peekToken = tokenizer.peek(); - - if (! peekToken) { - return Unexpected{ std::move(peekToken).error() }; + + if (auto lt = consume(TokenV::opLt, "'<'"); ! lt) { + return Unexpected<>{ std::move(lt).error() }; } bool keepParsing = true; @@ -299,7 +282,7 @@ namespace arti::lang { return Unexpected{ std::move(comma).error() }; } else if (! comma.value()) { - if (peekToken = tokenizer.peekExpect(TokenV::opGt); ! peekToken) { + if (auto peekToken = tokenizer.peekExpect(TokenV::opGt); ! peekToken) { return Unexpected{ std::move(peekToken).error() }; } else { @@ -308,6 +291,10 @@ namespace arti::lang { } } + if (auto gt = consume(TokenV::opGt, "'>'"); ! gt) { + return Unexpected<>{ std::move(gt).error() }; + } + return args; }