feat(parser): support turbofish operator and specialize access expressions
Signed-off-by: erick-alcachofa <erick@artichoke.dev> Overhaul the AST and parser logic to support explicit generic instantiation in expressions (e.g., `Result::<u32, u32>::Ok(0)`). This is achieved by implementing the "turbofish" operator (`::<>`) and specializing how member and module access are handled. * Added `GenericExpression` to represent generic instantiations in expressions. * Updated the Pratt parser to look for `<` immediately following a `::` (ModuleAccess) operator. If found, it parses a `GenericExpression` containing the generic arguments. * This change resolves the ambiguity between generic lists and comparison operators in the expression parser. * Renamed `PointerAccessExpression` to `PointerMemberAccessExpression`. * Refactored `MemberAccessExpression` and `PointerMemberAccessExpression` to store the member as an `ExpressionNode`. This allows the right-hand side of a `.` or `->` to be a complex expression (like a generic call). * Simplified `ModuleAccessExpression` to a binary `left`/`right` structure, separating scope resolution from generic instantiation. * Flattened the `Type` AST: replaced recursive `baseType` structures with a `Vector<TypeExpressionNode>` (`typeNodes`) to represent namespaced paths (e.g., `std::collections::Map`) more efficiently. * Removed redundant `NamespacedType` and `NamespacedIdentifier` nodes. * Simplified `GenericType` and `IdentifierType` to use direct `String` type names. * Refactored `parseType` to iterate through namespaced components and populate the new flattened `typeNodes` vector. * Updated the Pratt infix loop to correctly dispatch to `ModuleAccess`, `MemberAccess`, or `GenericExpression` based on the operator and lookahead tokens. * Adjusted `toDot` and `toString` visitors to match the new AST definitions.
This commit is contained in:
parent
09c44f3b67
commit
8dd75e3b8a
@ -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<nodes::SliceAccessExpression>;
|
||||
using SliceRangeExprNode = Ptr<nodes::SliceRangeExpression>;
|
||||
using MemberAccessExprNode = Ptr<nodes::MemberAccessExpression>;
|
||||
using PointerAccessExprNode = Ptr<nodes::PointerAccessExpression>;
|
||||
using PointerMemberAccessExprNode = Ptr<nodes::PointerMemberAccessExpression>;
|
||||
using GenericExprNode = Ptr<nodes::GenericExpression>;
|
||||
using ModuleAccessExprNode = Ptr<nodes::ModuleAccessExpression>;
|
||||
using ReflectionExprNode = Ptr<nodes::ReflectionExpression>;
|
||||
using SliceCreationExprNode = Ptr<nodes::SliceCreationExpression>;
|
||||
@ -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<TypeNode> genericParams;
|
||||
ExpressionNode left;
|
||||
ExpressionNode right;
|
||||
};
|
||||
|
||||
struct nodes::GenericExpression {
|
||||
SourceLocation location;
|
||||
|
||||
ExpressionNode typeNode;
|
||||
std::vector<TypeNode> genericArgs;
|
||||
};
|
||||
|
||||
struct nodes::ReflectionExpression {
|
||||
|
||||
@ -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<nodes::Type>;
|
||||
using GenericTypeNode = Ptr<nodes::GenericType>;
|
||||
using IdentifierTypeNode = Ptr<nodes::IdentifierType>;
|
||||
using NamespacedTypeNode = Ptr<nodes::NamespacedType>;
|
||||
using NamespacedIdentifierNode = Ptr<nodes::NamespacedIdentifier>;
|
||||
|
||||
/* Variant nodes */
|
||||
using TypeExpressionNode = Variant<
|
||||
GenericTypeNode,
|
||||
IdentifierTypeNode,
|
||||
NamespacedTypeNode
|
||||
IdentifierTypeNode
|
||||
>;
|
||||
|
||||
/* Node definitions */
|
||||
@ -60,27 +57,20 @@ namespace arti::lang::ast {
|
||||
SourceLocation location;
|
||||
|
||||
Vector<TypeQualifier> qualifiers;
|
||||
TypeExpressionNode baseType;
|
||||
Vector<TypeExpressionNode> typeNodes;
|
||||
};
|
||||
|
||||
struct nodes::GenericType {
|
||||
SourceLocation location;
|
||||
|
||||
TypeExpressionNode baseType;
|
||||
String typeName;
|
||||
Vector<TypeNode> genericArgs;
|
||||
};
|
||||
|
||||
struct nodes::IdentifierType {
|
||||
SourceLocation location;
|
||||
|
||||
NamespacedIdentifierNode typeName;
|
||||
};
|
||||
|
||||
struct nodes::NamespacedType {
|
||||
SourceLocation location;
|
||||
|
||||
String typeName;
|
||||
TypeExpressionNode baseType;
|
||||
};
|
||||
|
||||
struct nodes::NamespacedIdentifier {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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 <typename T>
|
||||
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);
|
||||
|
||||
@ -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<ast::GenericExprNode>();
|
||||
|
||||
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<ast::AssignExprNode>();
|
||||
|
||||
@ -296,6 +319,45 @@ namespace arti::lang {
|
||||
|
||||
return node;
|
||||
}
|
||||
else if (op == ast::InfixOperator::ModuleAccess) {
|
||||
auto node = ast::MakeNode<ast::ModuleAccessExprNode>();
|
||||
|
||||
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<ast::MemberAccessExprNode>();
|
||||
|
||||
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<ast::PointerMemberAccessExprNode>();
|
||||
|
||||
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<ast::CompoundAssignExprNode>();
|
||||
|
||||
|
||||
@ -72,7 +72,6 @@ namespace arti::lang {
|
||||
|
||||
Expected<ast::TypeNode> Parser::parseType() {
|
||||
auto node = ast::MakeNode<ast::TypeNode>();
|
||||
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<ast::IdentifierTypeNode>();
|
||||
else if (not ident.value()) {
|
||||
auto peekToken = tokenizer.peek();
|
||||
|
||||
std::get<ast::IdentifierTypeNode>(currentNode)->location =
|
||||
(*identType)->location;
|
||||
|
||||
std::get<ast::IdentifierTypeNode>(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<ast::GenericTypeNode>();
|
||||
|
||||
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<ExceptCode::ecUnexpectedToken>(
|
||||
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<ast::NamespacedTypeNode>();
|
||||
|
||||
newNode->location = std::visit(
|
||||
[](const auto &node) { return node->location; },
|
||||
currentNode
|
||||
);
|
||||
auto newNode = ast::MakeNode<ast::IdentifierTypeNode>();
|
||||
|
||||
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<ast::GenericTypeNode>();
|
||||
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<ast::GenericTypeNode>();
|
||||
|
||||
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<ast::Vector<ast::TypeNode>> Parser::parseGenericArgumentsList() {
|
||||
auto args = ast::Vector<ast::TypeNode>{};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user