diff --git a/crates/frontend/src/ast.rs b/crates/frontend/src/ast.rs index 94d6ff6..904651b 100644 --- a/crates/frontend/src/ast.rs +++ b/crates/frontend/src/ast.rs @@ -72,13 +72,19 @@ pub fn items<'db>(db: &'db dyn Database, file: workspace::File) -> Vec(db: &'db dyn Database, meta: ItemMeta<'db>) -> WithAst> { - match meta.kind(db) { - ItemKind::Relation => todo!(), - ItemKind::TypeAlias => todo!(), - ItemKind::Import => todo!(), - ItemKind::Rule => todo!(), - ItemKind::Assumption => todo!(), - } + use Item::*; + + let ast = meta.ast(db); + + let item = match meta.kind(db) { + ItemKind::Relation => Relation(relation(db, ast)), + ItemKind::TypeAlias => TypeAlias(type_alias(db, ast)), + ItemKind::Import => Import(import(db, ast)), + ItemKind::Rule => Rule(rule(db, ast)), + ItemKind::Assumption => Assumption(assumption(db, ast)), + }; + + WithAst::new(ast, item) } /// Common information on top-level items. @@ -106,6 +112,12 @@ pub enum Item<'db> { Assumption(Assumption<'db>), } +/// Parses [Relation] from an [AstNode]. +#[salsa::tracked] +pub fn relation<'db>(db: &'db dyn Database, ast: AstNode) -> Relation<'db> { + todo!() +} + /// A definition of a relation. #[salsa::tracked] pub struct Relation<'db> { @@ -122,6 +134,12 @@ pub struct Relation<'db> { pub ty: WithAst, } +/// Parses [TypeAlias] from an [AstNode]. +#[salsa::tracked] +pub fn type_alias<'db>(db: &'db dyn Database, ast: AstNode) -> TypeAlias<'db> { + todo!() +} + /// An abstract type alias (syntax representation). #[salsa::tracked] pub struct TypeAlias<'db> { @@ -132,18 +150,68 @@ pub struct TypeAlias<'db> { pub ty: WithAst, } +/// Parses [Rule] from an [AstNode]. +// TODO: after confirming that syntax is desirable, parse negation syntax +#[salsa::tracked] +pub fn rule<'db>(db: &'db dyn Database, ast: AstNode) -> Rule<'db> { + let relation = ast.expect_field(db, "relation").with_contents(db); + let head = expr(db, ast.expect_field(db, "head")); + let body = ast.get_field(db, "body").map(|ast| rule_body(db, ast)); + Rule::new(db, relation, head, body) +} + /// An abstract rule. #[salsa::tracked] -pub struct Rule<'db> {} +pub struct Rule<'db> { + /// The name of the relation this rule stores to. + pub relation: WithAst, + + /// The expression making up this rule's head. + pub head: Expr, + + /// This rule's body. + pub body: Option>, +} + +/// Parses [Import] from an [AstNode]. +#[salsa::tracked] +pub fn import<'db>(db: &'db dyn Database, ast: AstNode) -> Import<'db> { + todo!() +} /// An abstract import item. #[salsa::tracked] pub struct Import<'db> {} +/// Parses [Assumption] from an [AstNode]. +#[salsa::tracked] +pub fn assumption<'db>(db: &'db dyn Database, ast: AstNode) -> Assumption<'db> { + todo!() +} + /// An abstract assumption. #[salsa::tracked] pub struct Assumption<'db> {} +/// Parses a rule body. +// TODO: parallelize? +#[salsa::tracked] +pub fn rule_body<'db>(db: &'db dyn Database, ast: AstNode) -> RuleBody<'db> { + let clauses = ast + .get_fields(db, "clause") + .map(|clause| expr(db, clause)) + .collect(); + + RuleBody::new(db, clauses) +} + +/// An abstract rule body. +#[salsa::tracked] +pub struct RuleBody<'db> { + /// Each clause in the body. + pub clauses: Vec, +} + /// Parse an expression from the AST. #[salsa::tracked] pub fn expr(db: &dyn Database, ast: AstNode) -> Expr { @@ -222,7 +290,7 @@ impl ir::ProgramInfo for AstProgramInfo { } /// Extra [ExprKind] variants in the parse stage. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum ExprExtra { /// A structured tuple of sub-expressions. Tuple(Vec),