Skip to main content

valence_codegen/codegen/parser/
mod.rs

1//! Schema and trait DSL parsing via shared [`valence_schema_dsl`].
2//!
3//! Host `schemas/*.rs` files are parsed as Rust sources; the single
4//! `valence_schema!` / `valence_trait_schema!` body is lowered into generator IR.
5
6mod lower;
7
8use valence_core::SchemaConnection;
9use valence_schema_dsl::{parse_schema_file, parse_trait_file, ParsedPolicies, ParsedSchema};
10
11pub use lower::{lower_parsed_schema, lower_parsed_trait};
12
13/// Parsed trait definition from a `valence_trait_schema!` file (generator IR).
14#[derive(Debug, Clone)]
15pub struct ParsedTraitDef {
16    pub name: String,
17    pub fields: Vec<valence_core::SchemaField>,
18    pub connections: Vec<SchemaConnection>,
19}
20
21/// Result of parsing a schema file: core [`Schema`] plus emission-critical AST.
22#[derive(Debug, Clone)]
23pub struct ParsedSchemaFile {
24    pub schema: valence_core::Schema,
25    pub database: Option<syn::Expr>,
26    pub policies: Option<ParsedPolicies>,
27    /// Per-field policy AST (parallel to [`Schema::fields`]) for metadata emission.
28    pub field_policies: Vec<Option<ParsedPolicies>>,
29}
30
31/// Parse a `valence_schema!` source file into generator IR.
32pub fn extract_schema_from_macro(
33    content: &str,
34) -> Result<ParsedSchemaFile, Box<dyn std::error::Error>> {
35    let parsed: ParsedSchema = parse_schema_file(content).map_err(|e| e.message)?;
36    if let Some(expr) = &parsed.database {
37        if matches!(
38            expr,
39            syn::Expr::Lit(syn::ExprLit {
40                lit: syn::Lit::Str(_),
41                ..
42            })
43        ) {
44            return Err(
45                "`database:` cannot be a string literal (no stable address for `&dyn DatabaseEvaluator`). \
46Use a named `const` / `static` evaluator instead."
47                    .into(),
48            );
49        }
50    }
51    let field_policies = parsed.fields.iter().map(|f| f.policies.clone()).collect();
52    Ok(ParsedSchemaFile {
53        schema: lower_parsed_schema(&parsed),
54        database: parsed.database,
55        policies: parsed.policies,
56        field_policies,
57    })
58}
59
60/// Extract a trait definition from a `valence_trait_schema!` file.
61pub fn extract_trait_from_file(
62    content: &str,
63) -> Result<ParsedTraitDef, Box<dyn std::error::Error>> {
64    let parsed = parse_trait_file(content).map_err(|e| e.message)?;
65    Ok(lower_parsed_trait(&parsed))
66}
67
68#[cfg(test)]
69mod parser_tests;