1use crate::{parse::*, parser::*, syntax::*};
5use microcad_lang_base::Refer;
6use microcad_syntax::ast;
7use microcad_syntax::ast::{Element, LiteralKind};
8
9impl FromAst for RangeFirst {
10 type AstNode = ast::ArrayItem;
11
12 fn from_ast(node: &Self::AstNode, context: &ParseContext) -> Result<Self, ParseError> {
13 if matches!(
14 node.expression,
15 ast::Expression::Literal(
16 ast::Literal {
17 literal: ast::LiteralKind::Float(_)
18 | ast::LiteralKind::String(_)
19 | ast::LiteralKind::Quantity(_)
20 | ast::LiteralKind::Bool(_),
21 ..
22 },
23 ..
24 )
25 ) {
26 return Err(ParseError::InvalidRangeType {
27 src_ref: context.src_ref(&node.expression.span()),
28 });
29 }
30 Ok(RangeFirst(Box::new(Expression::from_ast(
31 &node.expression,
32 context,
33 )?)))
34 }
35}
36
37impl FromAst for RangeLast {
38 type AstNode = ast::ArrayItem;
39
40 fn from_ast(node: &Self::AstNode, context: &ParseContext) -> Result<Self, ParseError> {
41 if matches!(
42 node.expression,
43 ast::Expression::Literal(
44 ast::Literal {
45 literal: ast::LiteralKind::Float(_)
46 | ast::LiteralKind::String(_)
47 | ast::LiteralKind::Quantity(_)
48 | ast::LiteralKind::Bool(_),
49 ..
50 },
51 ..
52 )
53 ) {
54 return Err(ParseError::InvalidRangeType {
55 src_ref: context.src_ref(&node.expression.span()),
56 });
57 }
58 Ok(RangeLast(Box::new(Expression::from_ast(
59 &node.expression,
60 context,
61 )?)))
62 }
63}
64
65impl FromAst for RangeExpression {
66 type AstNode = ast::ArrayRangeExpression;
67
68 fn from_ast(node: &Self::AstNode, context: &ParseContext) -> Result<Self, ParseError> {
69 Ok(RangeExpression {
70 first: RangeFirst::from_ast(&node.start, context)?,
71 last: RangeLast::from_ast(&node.end, context)?,
72 src_ref: context.src_ref(&node.span),
73 })
74 }
75}
76
77impl FromAst for ListExpression {
78 type AstNode = ast::ArrayListExpression;
79
80 fn from_ast(node: &Self::AstNode, context: &ParseContext) -> Result<Self, ParseError> {
81 node.items
82 .iter()
83 .map(|item| Expression::from_ast(&item.expression, context))
84 .collect::<Result<ListExpression, _>>()
85 }
86}
87
88impl FromAst for Marker {
89 type AstNode = ast::Identifier;
90
91 fn from_ast(node: &Self::AstNode, context: &ParseContext) -> Result<Self, ParseError> {
92 Ok(Marker {
93 id: Identifier::from_ast(node, context)?,
94 src_ref: context.src_ref(&node.span),
95 })
96 }
97}
98
99impl FromAst for Expression {
100 type AstNode = ast::Expression;
101
102 fn from_ast(node: &Self::AstNode, context: &ParseContext) -> Result<Self, ParseError> {
103 Ok(match node {
104 ast::Expression::Call(expr) => Expression::Call(Call::from_ast(expr, context)?),
105 ast::Expression::Literal(ast::Literal {
106 literal: LiteralKind::String(s),
107 span,
108 ..
109 }) => Expression::FormatString(FormatString(Refer::new(
110 vec![FormatStringInner::String(Refer::new(
111 s.content.clone(),
112 context.src_ref(&s.span),
113 ))],
114 context.src_ref(span),
115 ))),
116 ast::Expression::Literal(expr) => {
117 Expression::Literal(Literal::from_ast(expr, context)?)
118 }
119 ast::Expression::String(s) => {
120 Expression::FormatString(FormatString::from_ast(s, context)?)
121 }
122 ast::Expression::Tuple(t) => {
123 Expression::TupleExpression(TupleExpression::from_ast(t, context)?)
124 }
125 ast::Expression::ArrayRange(a) => Expression::ArrayExpression(ArrayExpression {
126 inner: ArrayExpressionInner::Range(RangeExpression::from_ast(a, context)?),
127 unit: a
128 .ty
129 .as_ref()
130 .map(|ty| Unit::from_ast(ty, context))
131 .transpose()?
132 .unwrap_or_default(),
133 src_ref: context.src_ref(&a.span),
134 }),
135 ast::Expression::ArrayList(a) => Expression::ArrayExpression(ArrayExpression {
136 inner: ArrayExpressionInner::List(ListExpression::from_ast(a, context)?),
137 unit: a
138 .ty
139 .as_ref()
140 .map(|ty| Unit::from_ast(ty, context))
141 .transpose()?
142 .unwrap_or_default(),
143 src_ref: context.src_ref(&a.span),
144 }),
145 ast::Expression::QualifiedName(n) => {
146 Expression::QualifiedName(QualifiedName::from_ast(n, context)?)
147 }
148 ast::Expression::Marker(m) => Expression::Marker(Marker::from_ast(m, context)?),
149 ast::Expression::BinaryOperation(binop) => Expression::BinaryOp {
150 lhs: Box::new(Expression::from_ast(&binop.lhs, context)?),
151 rhs: Box::new(Expression::from_ast(&binop.rhs, context)?),
152 op: Refer::new(
153 binop.operation.operation.as_str().into(),
154 context.src_ref(&binop.operation.span),
155 ),
156 src_ref: context.src_ref(&binop.span),
157 },
158 ast::Expression::UnaryOperation(unop) => Expression::UnaryOp {
159 rhs: Box::new(Expression::from_ast(&unop.rhs, context)?),
160 op: Refer::new(
161 unop.operation.operation.as_str().into(),
162 context.src_ref(&unop.operation.span),
163 ),
164 src_ref: context.src_ref(&unop.span),
165 },
166 ast::Expression::Block(b) => Expression::Body(Body::from_ast(b, context)?),
167 ast::Expression::ElementAccess(access) => match &access.element {
168 Element::Attribute(a) => Expression::AttributeAccess(
169 Box::new(Expression::from_ast(&access.value, context)?),
170 Identifier::from_ast(a, context)?,
171 context.src_ref(&access.span),
172 ),
173 Element::Tuple(t) => Expression::PropertyAccess(
174 Box::new(Expression::from_ast(&access.value, context)?),
175 Identifier::from_ast(t, context)?,
176 context.src_ref(&access.span),
177 ),
178 Element::Method(m) => Expression::MethodCall(
179 Box::new(Expression::from_ast(&access.value, context)?),
180 MethodCall::from_ast(m, context)?,
181 context.src_ref(&access.span),
182 ),
183 Element::ArrayElement(e) => Expression::ArrayElementAccess(
184 Box::new(Expression::from_ast(&access.value, context)?),
185 Box::new(Expression::from_ast(e, context)?),
186 context.src_ref(&access.span),
187 ),
188 },
189 ast::Expression::If(i) => Expression::If(Box::new(IfStatement::from_ast(i, context)?)),
190 ast::Expression::Error(span) => {
191 return Err(ParseError::InvalidExpression {
192 src_ref: context.src_ref(span),
193 });
194 }
195 })
196 }
197}
198
199impl FromAst for TupleExpression {
200 type AstNode = ast::TupleExpression;
201
202 fn from_ast(node: &Self::AstNode, context: &ParseContext) -> Result<Self, ParseError> {
203 let mut args = ArgumentList::default();
204 for value in &node.values {
205 args.value
206 .try_push(Argument {
207 id: value
208 .name
209 .as_ref()
210 .map(|name| Identifier::from_ast(name, context))
211 .transpose()?,
212 expression: Expression::from_ast(&value.value, context)?,
213 src_ref: context.src_ref(&value.span),
214 })
215 .map_err(|(previous, id)| ParseError::DuplicateArgument { previous, id })?;
216 }
217
218 Ok(TupleExpression {
219 args,
220 src_ref: context.src_ref(&node.span),
221 })
222 }
223}
224
225#[cfg(test)]
227#[macro_export]
228macro_rules! tuple_expression {
229 ($code:literal) => {{
230 use microcad_syntax::ast;
231 use $crate::parser::FromAst;
232 let context = $crate::parser::ParseContext::new($code);
233 let ast = $crate::parse::build_ast($code, &context).unwrap();
234 let statement = ast
235 .statements
236 .statements
237 .first()
238 .or(ast.statements.tail.as_deref())
239 .expect("empty source");
240 let tuple_expression = match statement {
241 ast::Statement::Expression(ast::ExpressionStatement {
242 expression: ast::Expression::Tuple(tuple),
243 ..
244 }) => tuple,
245 _ => panic!("non tuple source"),
246 };
247 TupleExpression::from_ast(&tuple_expression, &context).unwrap()
248 }};
249}