1pub mod lexer;
11pub mod parser;
12mod tokenizer;
13pub mod vm;
14
15pub use besl_derive::BeslStruct;
16pub use lexer::Expressions;
17pub use lexer::Node;
18pub use lexer::Nodes;
19pub use lexer::Operators;
20
21pub use crate::lexer::BindingTypes;
22pub use crate::lexer::NodeReference;
23
24pub type ParserNode<'a> = parser::Node<'a>;
26
27pub trait BeslStructDefinition {
29 fn besl_struct_node() -> ParserNode<'static>;
30
31 fn besl_definition(&self) -> ParserNode<'static> {
32 Self::besl_struct_node()
33 }
34}
35
36#[macro_export]
38macro_rules! besl_struct_node {
39 (struct $name:ident { $($body:tt)* }) => {{
40 let mut fields = Vec::new();
41 $crate::besl_struct_node!(@fields fields [] $($body)*);
42
43 $crate::ParserNode::r#struct(
44 stringify!($name),
45 fields,
46 )
47 }};
48 (@fields $fields:ident [] ) => {};
49 (@fields $fields:ident [$($field:tt)+] ) => {
50 $crate::besl_struct_node!(@emit $fields [$($field)+]);
51 };
52 (@fields $fields:ident [$($field:tt)*] , $($rest:tt)*) => {
53 $crate::besl_struct_node!(@emit $fields [$($field)*]);
54 $crate::besl_struct_node!(@fields $fields [] $($rest)*);
55 };
56 (@fields $fields:ident [$($field:tt)*] $next:tt $($rest:tt)*) => {
57 $crate::besl_struct_node!(@fields $fields [$($field)* $next] $($rest)*);
58 };
59 (@emit $fields:ident []) => {};
60 (@emit $fields:ident [$field:ident : $($field_type:tt)+]) => {
61 {
62 let field_type = stringify!($($field_type)+).replace(' ', "");
63 $fields.push($crate::ParserNode::member(stringify!($field), &field_type));
64 }
65 };
66}
67
68pub fn parse<'a>(source: &'a str) -> Result<parser::Node<'a>, CompilationError> {
73 let tokens = tokenizer::tokenize(source).map_err(|_e| CompilationError::Tokenization)?;
74 let parser_root_node = parser::parse(&tokens).map_err(CompilationError::Parsing)?;
75
76 Ok(parser_root_node)
77}
78
79pub fn lex(node: parser::Node) -> Result<NodeReference, CompilationError> {
85 let besl = lexer::lex(node).map_err(CompilationError::Lex)?;
86
87 Ok(besl)
88}
89
90pub fn compile_to_besl(source: &str, parent: Option<Node>) -> Result<NodeReference, CompilationError> {
96 if source.split_whitespace().next().is_none() {
97 return Ok(lexer::Node::scope("".to_string()).into());
98 }
99
100 let parser_root_node = parse(source)?;
101
102 let besl = if let Some(parent) = parent {
103 lexer::lex_with_root(parent, parser_root_node).map_err(CompilationError::Lex)?
104 } else {
105 lexer::lex(parser_root_node).map_err(CompilationError::Lex)?
106 };
107
108 Ok(besl)
109}
110
111#[derive(Debug)]
112pub enum CompilationError {
113 Undefined,
114 Tokenization,
115 Parsing(parser::ParsingFailReasons),
116 Lex(lexer::LexError),
117}
118
119#[cfg(test)]
120mod tests {
121 use crate::parser::Nodes;
122
123 #[test]
124 fn besl_struct_node_macro_builds_a_struct_node() {
125 let mut node = crate::besl_struct_node!(struct Light {
126 position: vec3f,
127 color: vec3f,
128 indices: u32[3],
129 });
130
131 match node.node_mut() {
132 Nodes::Struct { name, fields } => {
133 assert_eq!(*name, "Light");
134 assert_eq!(fields.len(), 3);
135
136 match fields[0].node_mut() {
137 Nodes::Member { name, r#type } => {
138 assert_eq!(*name, "position");
139 assert_eq!(r#type, "vec3f");
140 }
141 _ => panic!("Expected member node."),
142 }
143
144 match fields[2].node_mut() {
145 Nodes::Member { name, r#type } => {
146 assert_eq!(*name, "indices");
147 assert_eq!(r#type, "u32[3]");
148 }
149 _ => panic!("Expected member node."),
150 }
151 }
152 _ => panic!("Expected struct node."),
153 }
154 }
155}