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}
28
29/// Parse a `valence_schema!` source file into generator IR.
30pub fn extract_schema_from_macro(
31    content: &str,
32) -> Result<ParsedSchemaFile, Box<dyn std::error::Error>> {
33    let parsed: ParsedSchema = parse_schema_file(content).map_err(|e| e.message)?;
34    if let Some(expr) = &parsed.database {
35        if matches!(
36            expr,
37            syn::Expr::Lit(syn::ExprLit {
38                lit: syn::Lit::Str(_),
39                ..
40            })
41        ) {
42            return Err(
43                "`database:` cannot be a string literal (no stable address for `&dyn DatabaseEvaluator`). \
44Use a named `const` / `static` evaluator instead."
45                    .into(),
46            );
47        }
48    }
49    Ok(ParsedSchemaFile {
50        schema: lower_parsed_schema(&parsed),
51        database: parsed.database,
52        policies: parsed.policies,
53    })
54}
55
56/// Extract a trait definition from a `valence_trait_schema!` file.
57pub fn extract_trait_from_file(
58    content: &str,
59) -> Result<ParsedTraitDef, Box<dyn std::error::Error>> {
60    let parsed = parse_trait_file(content).map_err(|e| e.message)?;
61    Ok(lower_parsed_trait(&parsed))
62}
63
64#[cfg(test)]
65mod parser_tests;