Skip to main content

microcad_lang/parse/
statement.rs

1// Copyright © 2025-2026 The µcad authors <info@ucad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4use crate::{parse::*, parser::*, rc::*, syntax::*};
5use microcad_syntax::ast;
6
7impl FromAst for Assignment {
8    type AstNode = ast::Assignment;
9
10    fn from_ast(node: &Self::AstNode, context: &ParseContext) -> Result<Self, ParseError> {
11        Ok(Assignment {
12            doc: node
13                .doc
14                .as_ref()
15                .map(|doc| DocBlock::from_ast(doc, context))
16                .transpose()?,
17            visibility: node
18                .visibility
19                .as_ref()
20                .map(|v| Visibility::from_ast(v, context))
21                .transpose()?
22                .unwrap_or_default(),
23            id: Identifier::from_ast(&node.name, context)?,
24            qualifier: node
25                .qualifier
26                .as_ref()
27                .map(|q| Qualifier::from_ast(q, context))
28                .transpose()?
29                .unwrap_or_default(),
30            specified_type: node
31                .ty
32                .as_ref()
33                .map(|ty| TypeAnnotation::from_ast(ty, context))
34                .transpose()?,
35            expression: Expression::from_ast(&node.value, context)?,
36            src_ref: context.src_ref(&node.span),
37        })
38    }
39}
40
41impl FromAst for AssignmentStatement {
42    type AstNode = ast::Assignment;
43
44    fn from_ast(node: &Self::AstNode, context: &ParseContext) -> Result<Self, ParseError> {
45        Ok(AssignmentStatement {
46            attribute_list: AttributeList::from_ast(&node.attributes, context)?,
47            assignment: Rc::new(Assignment::from_ast(node, context)?),
48            src_ref: context.src_ref(&node.span),
49        })
50    }
51}
52
53impl FromAst for IfStatement {
54    type AstNode = ast::If;
55
56    fn from_ast(node: &Self::AstNode, context: &ParseContext) -> Result<Self, ParseError> {
57        Ok(IfStatement {
58            cond: Expression::from_ast(&node.condition, context)?,
59            body: Body::from_ast(&node.body, context)?,
60            next_if: node
61                .next_if
62                .as_ref()
63                .map(|next| IfStatement::from_ast(next, context))
64                .transpose()?
65                .map(Box::new),
66            body_else: node
67                .else_body
68                .as_ref()
69                .map(|body| Body::from_ast(body, context))
70                .transpose()?,
71            src_ref: context.src_ref(&node.span),
72        })
73    }
74}
75
76impl FromAst for ExpressionStatement {
77    type AstNode = ast::ExpressionStatement;
78
79    fn from_ast(node: &Self::AstNode, context: &ParseContext) -> Result<Self, ParseError> {
80        Ok(ExpressionStatement {
81            src_ref: context.src_ref(&node.span),
82            attribute_list: AttributeList::from_ast(&node.attributes, context)?,
83            expression: Expression::from_ast(&node.expression, context)?,
84        })
85    }
86}
87
88impl FromAst for Statement {
89    type AstNode = ast::Statement;
90
91    fn from_ast(node: &Self::AstNode, context: &ParseContext) -> Result<Self, ParseError> {
92        Ok(match node {
93            ast::Statement::Module(module) => {
94                Statement::Module(Rc::new(ModuleDefinition::from_ast(module, context)?))
95            }
96            ast::Statement::Use(statement) => {
97                Statement::Use(UseStatement::from_ast(statement, context)?)
98            }
99            ast::Statement::Expression(ast::ExpressionStatement { expression: ast::Expression::If(if_statement), .. }) => {
100                Statement::If(IfStatement::from_ast(if_statement, context)?)
101            }
102            ast::Statement::Expression(statement) => {
103                Statement::Expression(ExpressionStatement::from_ast(statement, context)?)
104            }
105            ast::Statement::Workbench(w) => {
106                Statement::Workbench(<Rc<WorkbenchDefinition>>::from_ast(w, context)?)
107            }
108            ast::Statement::Function(f) => {
109                Statement::Function(Rc::new(FunctionDefinition::from_ast(f, context)?))
110            }
111            ast::Statement::Init(i) => {
112                Statement::Init(Rc::new(InitDefinition::from_ast(i, context)?))
113            }
114            ast::Statement::Return(r) => Statement::Return(ReturnStatement::from_ast(r, context)?),
115            ast::Statement::InnerAttribute(a) => {
116                Statement::InnerAttribute(Attribute::from_ast(a, context)?)
117            }
118            ast::Statement::Assignment(a) => {
119                Statement::Assignment(AssignmentStatement::from_ast(a, context)?)
120            }
121            ast::Statement::Comment(_) => unreachable!("comments are filtered out"),
122            ast::Statement::Error(span) => {
123                return Err(ParseError::InvalidStatement {
124                    src_ref: context.src_ref(span),
125                });
126            }
127        })
128    }
129}
130
131impl FromAst for ReturnStatement {
132    type AstNode = ast::Return;
133
134    fn from_ast(node: &Self::AstNode, context: &ParseContext) -> Result<Self, ParseError> {
135        Ok(ReturnStatement {
136            result: node
137                .value
138                .as_ref()
139                .map(|res| Expression::from_ast(res, context))
140                .transpose()?,
141            src_ref: context.src_ref(&node.span),
142        })
143    }
144}
145
146impl FromAst for StatementList {
147    type AstNode = ast::StatementList;
148
149    fn from_ast(node: &Self::AstNode, context: &ParseContext) -> Result<Self, ParseError> {
150        Ok(StatementList(
151            node.statements
152                .iter()
153                .chain(node.tail.iter().map(|tail| tail.as_ref()))
154                .filter(|statement| !matches!(statement, ast::Statement::Comment(_)))
155                .map(|statement| Statement::from_ast(statement, context))
156                .collect::<Result<Vec<_>, _>>()?,
157        ))
158    }
159}
160
161impl FromAst for Qualifier {
162    type AstNode = ast::AssignmentQualifier;
163
164    fn from_ast(node: &Self::AstNode, _context: &ParseContext) -> Result<Self, ParseError> {
165        Ok(match node {
166            ast::AssignmentQualifier::Const => Qualifier::Const,
167            ast::AssignmentQualifier::Prop => Qualifier::Prop,
168        })
169    }
170}