Parse names with paths

This commit is contained in:
2026-05-04 18:53:46 -06:00
parent 68725b5984
commit 94578c90ba

View File

@@ -251,7 +251,7 @@ pub fn expr(db: &dyn Database, ast: AstNode) -> Expr {
} else if ast.get_field(db, "false").is_some() {
Value(Boolean(false))
} else if let Some(sym) = ast.get_field(db, "symbol") {
todo!()
Extra(Arc::new(ExprExtra::SymbolName(name(db, sym))))
} else if let Some(int) = ast.get_field(db, "integer") {
Value(match int.contents(db).to_string().parse() {
Ok(val) => Integer(val),
@@ -304,7 +304,7 @@ pub fn aggregate(db: &dyn Database, ast: AstNode) -> Aggregate {
/// Parses an application operation.
pub fn apply(db: &dyn Database, ast: AstNode) -> Apply {
let head = ast.expect_field(db, "head").with_contents(db);
let head = name(db, ast.expect_field(db, "head"));
let body = expr(db, ast.expect_field(db, "body"));
Apply { head, body }
}
@@ -336,7 +336,13 @@ pub enum ExprExtra {
/// A structured tuple of sub-expressions.
Tuple(Vec<Expr>),
/// An unresolved symbol name.
SymbolName(Name),
/// An unresolved variable name.
///
/// Variables are only locally-scoped, so this is represented as a plain
/// string, not a [Name] with a full path.
VariableName(String),
/// An abstract application expression.
@@ -373,12 +379,42 @@ pub enum AggregateBody {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Apply {
/// The name of the relation to query or function to invoke.
pub head: WithAst<String>,
pub head: Name,
/// The parameters to the function or query.
pub body: Expr,
}
/// Parses a name.
#[salsa::tracked]
pub fn name(db: &dyn Database, ast: AstNode) -> Name {
Name {
ast,
path: ast
.get_fields(db, "path")
.map(|ast| ast.with_contents(db))
.collect(),
}
}
/// A named reference to some object.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Name {
/// The AST node of the name.
pub ast: AstNode,
/// The segments of the path to the object.
pub path: Vec<WithAst<String>>,
}
impl Display for Name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let segments = self.path.iter().cloned().map(|ast| ast.inner);
let path = segments.collect::<Vec<_>>().join(".");
write!(f, "{path}")
}
}
/// Extends [ir::BinaryOpKind] with the omitted operators to preserve syntax.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum BinaryOpKind {
@@ -465,7 +501,7 @@ impl ir::EnumRepr for RedundantBinaryOpKind {
/// Parses a type.
pub fn ty(db: &dyn Database, ast: AstNode) -> WithAst<Type> {
ast.with(if let Some(ast) = ast.get_field(db, "named") {
Type::Named(ast.contents(db).to_string())
Type::Named(name(db, ast))
} else {
Type::Tuple(ast.get_fields(db, "tuple").map(|ast| ty(db, ast)).collect())
})
@@ -477,7 +513,7 @@ pub fn ty(db: &dyn Database, ast: AstNode) -> WithAst<Type> {
/// dereferencing any aliases or checking semantic validity.
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum Type {
Named(String),
Named(Name),
Tuple(Vec<WithAst<Type>>),
}