feat(parser): add support for type-initiated expressions
Signed-off-by: erick-alcachofa <erick@artichoke.dev>
Implement TypeExpression AST node to allow types to be used within
expressions, enabling the parsing of anonymous slice and array
initializers like `[]Type { ... }`.
- Register `[` as a prefix-style token (NUD) in the Pratt parser.
- Add `TypeExpression` node to AST and expression variants.
- Update `toDot` and `toString` visitors for AST visualization.
- Update frontend to open source files directly to fix issues at opening
paths.
This commit is contained in:
parent
f024334da5
commit
c2f37d5702
@ -41,7 +41,7 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
std::ifstream file;
|
||||
file.open(sanitizePath(argv[1]));
|
||||
file.open(argv[1]);
|
||||
|
||||
if (! file.is_open()) {
|
||||
std::println("Failed to open file {}", argv[1]);
|
||||
|
||||
@ -47,6 +47,7 @@ namespace arti::lang::ast {
|
||||
struct SliceCreationExpression;
|
||||
struct SliceLengthExpression;
|
||||
struct SlicePtrExpression;
|
||||
struct TypeExpression;
|
||||
|
||||
} // namespace nodes
|
||||
|
||||
@ -67,6 +68,7 @@ namespace arti::lang::ast {
|
||||
using SliceCreationExprNode = Ptr<nodes::SliceCreationExpression>;
|
||||
using SliceLengthExprNode = Ptr<nodes::SliceLengthExpression>;
|
||||
using SlicePtrExprNode = Ptr<nodes::SlicePtrExpression>;
|
||||
using TypeExprNode = Ptr<nodes::TypeExpression>;
|
||||
|
||||
/* Variant nodes */
|
||||
using ExpressionNode = Variant<
|
||||
@ -92,7 +94,8 @@ namespace arti::lang::ast {
|
||||
SliceCreationExprNode,
|
||||
SliceLengthExprNode,
|
||||
SlicePtrExprNode,
|
||||
ReflectionExprNode
|
||||
ReflectionExprNode,
|
||||
TypeExprNode
|
||||
>;
|
||||
|
||||
/* Node definitions */
|
||||
@ -232,5 +235,11 @@ namespace arti::lang::ast {
|
||||
Optional<ObjectLtrlInitializerNode> initializer;
|
||||
};
|
||||
|
||||
struct nodes::TypeExpression {
|
||||
SourceLocation location;
|
||||
|
||||
TypeNode type;
|
||||
};
|
||||
|
||||
} // namespace arti::lang::ast
|
||||
|
||||
|
||||
@ -223,6 +223,7 @@ namespace arti::lang::ast {
|
||||
std::string emit(const ElseBranchNode &, GraphBuilder &);
|
||||
std::string emit(const DeferableNode &, GraphBuilder &);
|
||||
std::string emit(const PreLoopStmtNode &, GraphBuilder &);
|
||||
std::string emit(const TypeExprNode &, GraphBuilder &);
|
||||
|
||||
// Helpers for making leaf nodes with backticked values
|
||||
inline std::string makeLeaf(GraphBuilder &g, std::string_view value) {
|
||||
@ -766,6 +767,7 @@ namespace arti::lang::ast {
|
||||
[&g](const SlicePtrExprNode &n) { return emit(n, g); },
|
||||
[&g](const ReflectionExprNode &n) { return emit(n, g); },
|
||||
[&g](const GenericExprNode &n) { return emit(n, g); },
|
||||
[&g](const TypeExprNode &n) { return emit(n, g); },
|
||||
};
|
||||
return std::visit(visitor, node);
|
||||
}
|
||||
@ -1019,6 +1021,12 @@ namespace arti::lang::ast {
|
||||
return std::visit(visitor, node);
|
||||
}
|
||||
|
||||
std::string emit(const TypeExprNode &node, GraphBuilder &g) {
|
||||
auto id = g.makeNode("TypeExpression");
|
||||
g.addEdge(id, emit(node->type, g), "Type");
|
||||
return id;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Public API
|
||||
|
||||
@ -98,6 +98,7 @@ namespace arti::lang::ast {
|
||||
std::string toString(const ElseBranchNode &, std::string);
|
||||
std::string toString(const DeferableNode &, std::string);
|
||||
std::string toString(const PreLoopStmtNode &, std::string);
|
||||
std::string toString(const TypeExprNode &, std::string);
|
||||
std::string toString(PrefixOperator op);
|
||||
std::string toString(InfixOperator op);
|
||||
std::string toString(CompoundAssignOperator op);
|
||||
@ -976,6 +977,9 @@ namespace arti::lang::ast {
|
||||
[padding](const GenericExprNode &node) -> std::string {
|
||||
return toString(node, padding);
|
||||
},
|
||||
[padding](const TypeExprNode &node) -> std::string {
|
||||
return toString(node, padding);
|
||||
},
|
||||
};
|
||||
|
||||
return std::visit(visitor, node);
|
||||
@ -1457,6 +1461,13 @@ namespace arti::lang::ast {
|
||||
return std::visit(visitor, node);
|
||||
}
|
||||
|
||||
std::string toString(const TypeExprNode &node, std::string prefix) {
|
||||
std::stringstream ss;
|
||||
ss << "TypeÉxpression";
|
||||
appendItem(ss, prefix, node->type, true);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string toString(PrefixOperator op) {
|
||||
using enum PrefixOperator;
|
||||
|
||||
|
||||
@ -49,6 +49,29 @@ namespace arti::lang {
|
||||
lhs = std::move(lhsExpr).value();
|
||||
}
|
||||
}
|
||||
else if (peekToken->value == TokenV::opLBracket) {
|
||||
if (auto close = match(TokenV::opRBracket, 1); ! close) {
|
||||
return Unexpected<>{ std::move(close).error() };
|
||||
}
|
||||
else if (! close.value()) {
|
||||
return langException<ExceptCode::ecUnexpectedToken>(
|
||||
peekToken->line,
|
||||
peekToken->column,
|
||||
toString(*peekToken),
|
||||
"']'"
|
||||
);
|
||||
}
|
||||
|
||||
if (auto type = parseType(); ! type) {
|
||||
return Unexpected<>{ std::move(type).error() };
|
||||
}
|
||||
else {
|
||||
auto node = ast::MakeNode<ast::TypeExprNode>();
|
||||
node->location = type.value()->location;
|
||||
node->type = std::move(type).value();
|
||||
lhs = std::move(node);
|
||||
}
|
||||
}
|
||||
else if (pratt::isPrefixOperator(peekToken->value)) {
|
||||
if (auto newLhs = parsePrefixExpression(); ! newLhs) {
|
||||
return Unexpected<>{ std::move(newLhs).error() };
|
||||
|
||||
@ -34,6 +34,7 @@ namespace arti::lang::pratt {
|
||||
case opTilde:
|
||||
case opAnd:
|
||||
case opLParen:
|
||||
case opLBracket:
|
||||
case kwNot:
|
||||
return true;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user