Skip to main content

vexil_lang/
lib.rs

1//! # vexil-lang
2//!
3//! Compiler library for the [Vexil](https://github.com/vexil-lang/vexil) schema
4//! definition language. Provides lexing, parsing, type checking, and compilation
5//! of `.vexil` schema files.
6//!
7//! ## Quick Start
8//!
9//! ```rust
10//! use vexil_lang::compile;
11//!
12//! let source = r#"
13//!     namespace example
14//!     message Point { x @0 : f32  y @1 : f32 }
15//! "#;
16//!
17//! let result = compile(source);
18//! assert!(result.diagnostics.iter().all(|d| d.severity != vexil_lang::Severity::Error));
19//! ```
20//!
21//! ## API Tiers
22//!
23//! - **Tier 1 (stable):** [`compile`], [`compile_project`], [`CompiledSchema`],
24//!   [`ProjectResult`], [`CodegenBackend`]
25//! - **Tier 2 (semi-stable):** AST types, pipeline stages
26//! - **Tier 3 (internal):** Lexer, parser -- subject to change
27
28/// Abstract syntax tree types produced by the parser.
29pub mod ast;
30/// Canonical form serialisation (spec section 7).
31pub mod canonical;
32/// Code generation backend trait and error types.
33pub mod codegen;
34/// Schema compatibility checker (spec section 10).
35pub mod compat;
36/// Diagnostic types for errors and warnings.
37pub mod diagnostic;
38/// Intermediate representation: compiled schema, type registry, and type definitions.
39pub mod ir;
40/// Lexer: tokenises Vexil source text.
41pub mod lexer;
42/// Lowering: transforms AST into IR.
43pub mod lower;
44/// Meta-schemas for Vexil's own IR types.
45pub mod meta;
46/// Parser: builds an AST from a token stream.
47pub mod parser;
48/// Multi-file project compilation and import graph resolution.
49pub mod project;
50/// Type remapping utilities for cross-registry type cloning.
51pub mod remap;
52/// Schema loading abstraction (filesystem, in-memory).
53pub mod resolve;
54/// Source span types for error reporting.
55pub mod span;
56/// Type checker: validates IR and computes wire sizes.
57pub mod typeck;
58/// Semantic validation of parsed schemas.
59pub mod validate;
60
61pub use codegen::{CodegenBackend, CodegenError};
62pub use ir::{CompiledSchema, ResolvedType, TypeDef, TypeId, TypeRegistry};
63pub use meta::{meta_schema, pack_schema};
64pub use project::compile_project;
65pub use project::ProjectResult;
66pub use resolve::SchemaLoader;
67
68pub use diagnostic::{Diagnostic, Severity};
69
70use ast::Schema;
71
72/// The result of parsing a Vexil source string.
73///
74/// Contains the parsed AST (if parsing succeeded) and any diagnostics
75/// produced during lexing, parsing, and validation.
76#[derive(Debug)]
77pub struct ParseResult {
78    /// The parsed schema AST, or `None` if a fatal parse error occurred.
79    pub schema: Option<Schema>,
80    /// Errors and warnings from lexing, parsing, and structural validation.
81    pub diagnostics: Vec<Diagnostic>,
82}
83
84/// Parse a Vexil schema source string.
85///
86/// Runs the lexer, parser, and structural validator. Does **not** lower to IR
87/// or type-check. Use [`compile`] for the full pipeline.
88pub fn parse(source: &str) -> ParseResult {
89    let (tokens, mut diagnostics) = lexer::lex(source);
90    let (schema, parse_diags) = parser::parse(source, tokens);
91    diagnostics.extend(parse_diags);
92    if let Some(ref schema) = schema {
93        let validate_diags = validate::validate(schema);
94        diagnostics.extend(validate_diags);
95    }
96    ParseResult {
97        schema,
98        diagnostics,
99    }
100}
101
102/// The result of the full compilation pipeline.
103///
104/// Contains both the source-faithful AST and the lowered/type-checked IR,
105/// along with all diagnostics produced at every stage.
106#[derive(Debug)]
107pub struct CompileResult {
108    /// The parsed schema AST, or `None` if a fatal parse error occurred.
109    pub schema: Option<Schema>,
110    /// The compiled IR, or `None` if errors prevented lowering or type-checking.
111    pub compiled: Option<CompiledSchema>,
112    /// All diagnostics (errors and warnings) from every pipeline stage.
113    pub diagnostics: Vec<Diagnostic>,
114}
115
116/// Compile a Vexil source string through the full pipeline.
117///
118/// Runs lexing, parsing, structural validation, lowering to IR, and
119/// type-checking in sequence. Returns a [`CompileResult`] containing both
120/// the AST and compiled IR (when compilation succeeds) plus all diagnostics.
121///
122/// For multi-file projects with imports, use [`compile_project`] instead.
123pub fn compile(source: &str) -> CompileResult {
124    compile_impl(source, false)
125}
126
127fn compile_impl(source: &str, allow_reserved: bool) -> CompileResult {
128    let (tokens, mut diagnostics) = lexer::lex(source);
129    let (schema, parse_diags) = parser::parse(source, tokens);
130    diagnostics.extend(parse_diags);
131    if let Some(ref schema) = schema {
132        let validate_diags = if allow_reserved {
133            validate::validate_allow_reserved(schema)
134        } else {
135            validate::validate(schema)
136        };
137        diagnostics.extend(validate_diags);
138    }
139    if diagnostics.iter().any(|d| d.severity == Severity::Error) {
140        return CompileResult {
141            schema,
142            compiled: None,
143            diagnostics,
144        };
145    }
146    let Some(schema) = schema else {
147        return CompileResult {
148            schema: None,
149            compiled: None,
150            diagnostics,
151        };
152    };
153    let (mut compiled, lower_diags) = lower::lower(&schema);
154    diagnostics.extend(lower_diags);
155    if let Some(ref mut compiled) = compiled {
156        let check_diags = typeck::check(compiled);
157        diagnostics.extend(check_diags);
158    }
159    CompileResult {
160        schema: Some(schema),
161        compiled,
162        diagnostics,
163    }
164}