Skip to main content

mech_syntax/
statements.rs

1#[macro_use]
2use crate::*;
3use nom::sequence::tuple as nom_tuple;
4
5// #### Statements
6
7// comment-sigil := "--" | "//" ;
8pub fn comment_sigil(input: ParseString) -> ParseResult<()> {
9  let (input, _) = alt((tag("--"),tag("//")))(input)?;
10  Ok((input, ()))
11}
12
13// comment := comment_sigil, paragraph ;
14pub fn comment(input: ParseString) -> ParseResult<Comment> {
15  let (input, _) = many0(space_tab)(input)?;
16  let (input, _) = comment_sigil(input)?;
17  let (input, line_token) = skip_till_eol(input)?;
18  let comment_text = line_token.to_string();
19
20  if comment_text.is_empty() {
21    return Ok((input, Comment { paragraph: Paragraph { elements: vec![], error_range: None } }));
22  }
23
24  let line_graphemes = graphemes::init_source(&comment_text);
25  let line_input = ParseString::new(&line_graphemes);
26
27  match inline_paragraph(line_input) {
28    Ok((remaining, paragraph)) => {
29      // A rich comment must parse the full line.
30      if new_line(remaining.clone()).is_ok() {
31        Ok((input, Comment { paragraph }))
32      } else {
33        let mut recovered_input = input;
34        let start = line_token.src_range.start;
35        let end = line_token.src_range.end;
36        recovered_input.error_log.push((
37          SourceRange { start, end },
38          ParseErrorDetail {
39            message: "Invalid rich comment syntax, preserving raw comment text",
40            annotation_rngs: vec![],
41          },
42        ));
43        Ok((recovered_input, Comment { paragraph: Paragraph::from_tokens(vec![line_token]) }))
44      }
45    }
46    Err(_) => {
47      let mut recovered_input = input;
48      let start = line_token.src_range.start;
49      let end = line_token.src_range.end;
50      recovered_input.error_log.push((
51        SourceRange { start, end },
52        ParseErrorDetail {
53          message: "Invalid rich comment syntax, preserving raw comment text",
54          annotation_rngs: vec![],
55        },
56      ));
57      Ok((recovered_input, Comment { paragraph: Paragraph::from_tokens(vec![line_token]) }))
58    }
59  }
60}
61
62// op-assign-operator := add-assign-operator | sub-assign-operator | mul-assign-operator | div-assign-operator | exp-assign-operator ;
63pub fn op_assign_operator(input: ParseString) -> ParseResult<OpAssignOp> {
64  alt((add_assign_operator, sub_assign_operator, mul_assign_operator, div_assign_operator, exp_assign_operator))(input)
65}
66
67// add-assign-operator := "+=" ;
68pub fn add_assign_operator(input: ParseString) -> ParseResult<OpAssignOp> {
69  let (input, _) = whitespace0(input)?;
70  let (input, _) = tag("+=")(input)?;
71  let (input, _) = whitespace0(input)?;
72  Ok((input, OpAssignOp::Add))
73}
74
75// sub-assign-operator := "-=" ;
76pub fn sub_assign_operator(input: ParseString) -> ParseResult<OpAssignOp> {
77  let (input, _) = whitespace0(input)?;
78  let (input, _) = tag("-=")(input)?;
79  let (input, _) = whitespace0(input)?;
80  Ok((input, OpAssignOp::Sub))
81}
82
83// mul-assign-operator := "*=" ;
84pub fn mul_assign_operator(input: ParseString) -> ParseResult<OpAssignOp> {
85  let (input, _) = whitespace0(input)?;
86  let (input, _) = tag("*=")(input)?;
87  let (input, _) = whitespace0(input)?;
88  Ok((input, OpAssignOp::Mul))
89}
90// div-assign-operator := "/=" ;
91pub fn div_assign_operator(input: ParseString) -> ParseResult<OpAssignOp> {
92  let (input, _) = whitespace0(input)?;
93  let (input, _) = tag("/=")(input)?;
94  let (input, _) = whitespace0(input)?;
95  Ok((input, OpAssignOp::Div))
96}
97
98// exp-assign-operator := "^=" ;
99pub fn exp_assign_operator(input: ParseString) -> ParseResult<OpAssignOp> {
100  let (input, _) = whitespace0(input)?;
101  let (input, _) = tag("^=")(input)?;
102  let (input, _) = whitespace0(input)?;
103  Ok((input, OpAssignOp::Exp))
104}
105
106// split_data := (identifier | table), <!stmt_operator>, space*, split_operator, <space+>, <expression> ;
107/*pub fn split_data(input: ParseString) -> ParseResult<ParserNode> {
108  /*let msg1 = "Expects spaces around operator";
109  let msg2 = "Expects expression";
110  let (input, table) = alt((identifier, table))(input)?;
111  let (input, _) = labelr!(null(is_not(stmt_operator)), skip_nil, msg1)(input)?;
112  let (input, _) = many0(space)(input)?;
113  let (input, _) = split_operator(input)?;
114  let (input, _) = labelr!(null(many1(space)), skip_nil, msg1)(input)?;
115  let (input, expression) = label!(expression, msg2)(input)?;*/
116  Ok((input, ParserNode::SplitData{children: vec![]}))
117}*/
118
119// flatten_data := identifier, <!stmt_operator>, space*, flatten_operator, <space+>, <expression> ;
120/*pub fn flatten_data(input: ParseString) -> ParseResult<ParserNode> {
121  /*let msg1 = "Expects spaces around operator";
122  let msg2 = "Expects expression";
123  let (input, table) = identifier(input)?;
124  let (input, _) = labelr!(null(is_not(stmt_operator)), skip_nil, msg1)(input)?;
125  let (input, _) = many0(space)(input)?;
126  let (input, _) = flatten_operator(input)?;
127  let (input, _) = labelr!(null(many1(space)), skip_nil, msg1)(input)?;
128  let (input, expression) = label!(expression, msg2)(input)?;*/
129  Ok((input, ParserNode::FlattenData{children: vec![]}))
130}*/
131
132// variable-define := tilde?, var, !assign-operator, define-operator, expression ;
133pub fn variable_define(input: ParseString) -> ParseResult<VariableDefine> {
134  let msg1 = "Expects spaces around operator";
135  let msg2 = "Expects expression";
136  let (input, mutable) = opt(tilde)(input)?; 
137  let (input, var) = var(input)?;
138  let (input, _) = labelr!(null(is_not(assign_operator)), skip_nil, msg1)(input)?;
139  let (input, _) = define_operator(input)?;
140  let (input, expression) = label!(expression, msg2)(input)?;
141  let mutable = match mutable {
142    Some(_) => true,
143    None => false,
144  };
145  Ok((input, VariableDefine{mutable, var, expression}))
146}
147
148// variable-assign := slice-ref, !define-operator, assign-operator, expression ;
149pub fn variable_assign(input: ParseString) -> ParseResult<VariableAssign> {
150  let msg1 = "Expects spaces around operator";
151  let msg2 = "Expects expression";
152  let (input, target) = slice_ref(input)?;
153  let (input, _) = labelr!(null(is_not(define_operator)), skip_nil, msg1)(input)?;
154  let (input, _) = assign_operator(input)?;
155  let (input, expression) = label!(expression, msg2)(input)?;
156  Ok((input, VariableAssign{target,expression}))
157}
158
159// op-assign := slice-ref, !define-operator, op-assign-operator, expression ;
160pub fn op_assign(input: ParseString) -> ParseResult<OpAssign> {
161  let msg1 = "Expects spaces around operator";
162  let msg2 = "Expects expression";
163  let (input, target) = slice_ref(input)?;
164  let (input, _) = labelr!(null(is_not(define_operator)), skip_nil, msg1)(input)?;
165  let (input, op) = op_assign_operator(input)?;
166  let (input, expression) = label!(expression, msg2)(input)?;
167  Ok((input, OpAssign{target,op,expression}))
168}
169
170// parser for the second line of the output table, generate the 
171// var name if there is one.
172
173// split_operator := ">-" ;
174/*pub fn split_operator(input: ParseString) -> ParseResult<ParserNode> {
175  let (input, _) = tag(">-")(input)?;
176  Ok((input, ParserNode::Null))
177}*/
178
179// flatten_operator := "-<" ;
180/*pub fn flatten_operator(input: ParseString) -> ParseResult<ParserNode> {
181  let (input, _) = tag("-<")(input)?;
182  Ok((input, ParserNode::Null))
183}*/
184
185
186// tuple-destructure := "(", list1(identifier, comma), ")", ":=", expression ;
187fn tuple_destructure(input: ParseString) -> ParseResult<TupleDestructure> {
188  let (input, _) = left_parenthesis(input)?;
189  let (input, vars) = separated_list1(list_separator, identifier)(input)?;
190  let (input, _) = right_parenthesis(input)?;
191  let (input, _) = define_operator(input)?;
192  let (input, expression) = expression(input)?;
193  Ok((input, TupleDestructure{vars, expression}))
194}
195
196// statement := variable-define | variable-assign | op-assign | enum-define | tuple-destructure | kind-define ;
197pub fn statement(input: ParseString) -> ParseResult<Statement> {
198  let parsers: Vec<(&'static str,Box<dyn Fn(ParseString) -> ParseResult<Statement>>)> = vec![
199    ("fsm_declare", Box::new(|i| fsm_declare(i).map(|(i, v)| (i, Statement::FsmDeclare(v))))),
200    ("variable_define", Box::new(|i| variable_define(i).map(|(i, v)| (i, Statement::VariableDefine(v))))),
201    ("variable_assign", Box::new(|i| variable_assign(i).map(|(i, v)| (i, Statement::VariableAssign(v))))),
202    ("op_assign", Box::new(|i| op_assign(i).map(|(i, v)| (i, Statement::OpAssign(v))))),
203    ("enum_define", Box::new(|i| enum_define(i).map(|(i, v)| (i, Statement::EnumDefine(v))))),
204    ("tuple_destructure", Box::new(|i| tuple_destructure(i).map(|(i, v)| (i, Statement::TupleDestructure(v))))),
205    ("kind_define", Box::new(|i| kind_define(i).map(|(i, v)| (i, Statement::KindDefine(v))))),
206  ];
207  alt_best(input, &parsers)
208}
209
210// enum-define := "<", identifier, ">", define-operator, list1(enum-separator, enum-variant);
211pub fn enum_define(input: ParseString) -> ParseResult<EnumDefine> {
212  let (input, _) = left_angle(input)?;
213  let (input, name) = identifier(input)?;
214  let (input, _) = right_angle(input)?;
215  let (input, _) = define_operator(input)?;
216  let (input, variants) = separated_list1(enum_separator, enum_variant)(input)?;
217  Ok((input, EnumDefine{name, variants}))
218}
219
220// enum-variant := grave?, colon?, identifier, enum-variant-kind? ;
221pub fn enum_variant(input: ParseString) -> ParseResult<EnumVariant> {
222  let (input, _) = opt(grave)(input)?;
223  let (input, _) = opt(colon)(input)?;
224  let (input, name) = identifier(input)?;
225  let (input, value) = opt(alt((enum_variant_kind, enum_variant_inline_kind)))(input)?;
226  Ok((input, EnumVariant{name, value}))
227}
228
229// enum-variant-kind := "(", kind-annotation, ")" ;
230pub fn enum_variant_kind(input: ParseString) -> ParseResult<KindAnnotation> {
231  let (input, _) = left_parenthesis(input)?;
232  let (input, annotation) = kind_annotation(input)?;
233  let (input, _) = right_parenthesis(input)?;
234  Ok((input, annotation))
235}
236
237// enum-variant-inline-kind := kind-annotation ;
238// Allows compact tagged-union syntax like `:ok<u64>`.
239pub fn enum_variant_inline_kind(input: ParseString) -> ParseResult<KindAnnotation> {
240  kind_annotation(input)
241}
242
243// kind-define := "<", identifier, ">", define-operator, kind-annotation ;
244pub fn kind_define(input: ParseString) -> ParseResult<KindDefine> {
245  let (input, _) = left_angle(input)?;
246  let (input, name) = identifier(input)?;
247  let (input, _) = right_angle(input)?;
248  let (input, _) = define_operator(input)?;
249  let (input, knd) = kind_annotation(input)?;
250  Ok((input, KindDefine{name,kind:knd}))
251}