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