wasp_core/
parser.rs

1use crate::ast::*;
2use failure::Error;
3use nom::types::CompleteStr;
4use std::str;
5use wasmly::DataType;
6
7fn to_string(s: CompleteStr) -> String {
8    s.to_string()
9}
10
11fn is_start_identifier_char(c: char) -> bool {
12    c == '_' || c == '$' || c.is_alphabetic()
13}
14
15fn is_identifier_char(c: char) -> bool {
16    c == '_' || c == '!' || c == '-' || c == '$' || c.is_alphanumeric()
17}
18
19fn is_text_char(c: char) -> bool {
20    c != '"'
21}
22
23fn is_digit(c: char) -> bool {
24    c.is_digit(10)
25}
26
27fn is_comment_char(c: char) -> bool {
28    c != '\r' && c != '\n'
29}
30
31fn to_data_type(c: &str) -> DataType {
32    match c {
33        "i32" => DataType::I32,
34        "i64" => DataType::I64,
35        "f32" => DataType::F32,
36        "f64" => DataType::F64,
37        _ => panic!("invalid type"),
38    }
39}
40
41named!(
42    token_comment<CompleteStr,String>,
43    do_parse!(
44        pair: pair!(tag!("//"),take_while!(is_comment_char))>>
45        (pair.0.to_string())
46    )
47);
48
49named!(
50    token_identifier<CompleteStr,String>,
51    do_parse!(
52        start: map!(take_while1!(is_start_identifier_char), to_string) >>
53        end: map!(take_while!(is_identifier_char), to_string) >>
54        (format!("{}{}",start,end).to_string())
55    )
56);
57
58named!(
59    operator_identifiers<CompleteStr,String>,
60    do_parse!(
61        id: alt!(map!(tag!(">>"),to_string)|map!(tag!("<<"),to_string)|map!(tag!(">="),to_string)|map!(tag!("<="),to_string)|map!(tag!(">"),to_string)|map!(tag!("<"),to_string)|map!(tag!("or"),to_string)|map!(tag!("and"),to_string)|map!(tag!("!="),to_string)|map!(tag!("=="),to_string)|map!(tag!("+"),to_string)|map!(tag!("-"),to_string)|map!(tag!("*"),to_string)|map!(tag!("/"),to_string)|map!(tag!("%"),to_string)|map!(tag!("|"),to_string)|map!(tag!("&"),to_string))>>
62        (id)
63    )
64);
65
66named!(
67    unary_operator_identifiers<CompleteStr,String>,
68    do_parse!(
69        id: alt!(map!(tag!("^"),to_string)|map!(tag!("~"),to_string)|map!(tag!("!"),to_string))>>
70        (id)
71    )
72);
73
74named!(
75    function_identifiers<CompleteStr,String>,
76    do_parse!(
77        id: alt!(map!(tag!("assert"),to_string)|map!(tag!("call"),to_string)|token_identifier)>>
78        (id)
79    )
80);
81
82named!(
83    token_data_type<CompleteStr,DataType>,
84    do_parse!(
85        t: map!(alt!(tag!("()")|tag!("i32")|tag!("i64")|tag!("f32")|tag!("f64")), to_string) >>
86        (to_data_type(&t))
87    )
88);
89
90named!(
91    token_text<CompleteStr,String>,
92    do_parse!(
93        tag!("\"")
94            >> text: map!(take_while!(is_text_char), to_string)
95            >> tag!("\"")
96            >> (text)
97    )
98);
99
100named!(
101    token_symbol<CompleteStr,String>,
102    do_parse!(
103        tag!(":")
104            >> text: map!(take_while!(is_identifier_char), to_string)
105            >> (text)
106    )
107);
108
109named!(
110    base_float<CompleteStr,String>,
111    do_parse!(
112            num: map!(take_while1!(is_digit), to_string) >>
113            tag!(".") >>
114            den: map!(take_while1!(is_digit), to_string) >>
115            (format!("{}.{}",num,den).to_owned())
116    )
117);
118
119named!(
120    base_int<CompleteStr,String>,
121    do_parse!(
122            num: map!(take_while1!(is_digit), to_string) >>
123            (num.to_owned())
124    )
125);
126
127named!(
128    negative_number<CompleteStr,f64>,
129    do_parse!(
130        tag!("-")
131            >> num: alt!(base_float|base_int)
132            >> (-num.parse::<f64>().unwrap())
133    )
134);
135
136named!(
137    positive_number<CompleteStr,f64>,
138    do_parse!(
139         num: alt!(base_float|base_int)
140            >> (num.parse::<f64>().unwrap())
141    )
142);
143
144named!(
145    token_number<CompleteStr,f64>,
146    alt!(positive_number|negative_number)
147);
148
149named!(external_function<CompleteStr, TopLevelOperation>,
150  do_parse!(
151    ws!(tag!("extern"))   >>
152    function_name: ws!(token_identifier) >>
153    ws!(tag!("("))   >>
154    params: ws!(separated_list!(tag!(","),ws!(token_identifier))) >>
155    ws!(tag!(")"))   >>
156    (TopLevelOperation::ExternalFunction(ExternalFunction{name:function_name,params:params}))
157  )
158);
159
160named!(expression_literal_string<CompleteStr, Expression>,
161    do_parse!(
162      text: ws!(token_text) >>
163      (Expression::TextLiteral(text))
164    )
165);
166
167named!(expression_literal_token<CompleteStr, Expression>,
168    do_parse!(
169      text: ws!(token_symbol) >>
170      (Expression::SymbolLiteral(text))
171    )
172);
173
174named!(expression_identifier<CompleteStr, Expression>,
175    do_parse!(
176      text: ws!(token_identifier) >>
177      (Expression::Identifier(text))
178    )
179);
180
181named!(expression_number<CompleteStr, Expression>,
182    do_parse!(
183      num: ws!(token_number) >>
184      (Expression::Number(num))
185    )
186);
187
188named!(boolean_true<CompleteStr, Expression>,
189    do_parse!(
190      tag!("true") >>
191      (Expression::Number(1.0))
192    )
193);
194
195named!(boolean_false<CompleteStr, Expression>,
196    do_parse!(
197      tag!("false") >>
198      (Expression::Number(0.0))
199    )
200);
201
202named!(expression_let_pair<CompleteStr, (String, Expression)>,
203  do_parse!(
204    id: ws!(token_identifier)   >>
205    exp: ws!(expression)   >>
206    ((id,exp))
207  )
208);
209
210named!(expression_loop<CompleteStr, Expression>,
211  do_parse!(
212    ws!(tag!("loop"))   >>
213    many0!(ws!(token_comment)) >>
214    ws!(tag!("{"))   >>
215    expressions: expression_list >>
216    tag!("}")   >>
217    (Expression::Loop(OperationLoop{expressions:expressions}))
218  )
219);
220
221named!(expression_recur<CompleteStr, Expression>,
222  do_parse!(
223    tag!("recur")   >>
224    (Expression::Recur(OperationRecur{}))
225  )
226);
227
228named!(expression_fnsig<CompleteStr, Expression>,
229  do_parse!(
230    ws!(tag!("fn"))   >>
231    many0!(ws!(token_comment)) >>
232    ws!(tag!("("))   >>
233    many0!(ws!(token_comment)) >>
234    inputs: ws!(separated_list!(tag!(","),ws!(token_data_type))) >>
235    many0!(ws!(token_comment)) >>
236    ws!(tag!(")"))   >>
237    ws!(tag!("->"))   >>
238    many0!(ws!(token_comment)) >>
239    output: opt!(ws!(token_data_type)) >>
240    (Expression::FnSig(OperationFnSig{inputs:inputs, output:output}))
241  )
242);
243
244named!(expression<CompleteStr, Expression>,
245    alt!(expression_if_statement|expression_fnsig|expression_operator_call|expression_unary_operator_call|expression_assignment|expression_function_call|expression_loop|expression_recur|expression_number|boolean_true|boolean_false|expression_literal_token|expression_literal_string|expression_identifier)
246);
247
248named!(expression_list_item<CompleteStr, Expression>,
249    do_parse!(
250      many0!(ws!(token_comment)) >>
251      expr: ws!(expression) >>
252      (expr)
253    )
254);
255
256named!(expression_list<CompleteStr, Vec<Expression>>,
257    do_parse!(
258      exprs: ws!(ws!(many1!(ws!(expression_list_item)))) >>
259      (exprs)
260    )
261);
262
263named!(function_params<CompleteStr, Vec<Expression>>,
264    do_parse!(
265      op: ws!(separated_list!(tag!(","),ws!(expression))) >>
266      (op)
267    )
268);
269
270named!(expression_operator_call<CompleteStr, Expression>,
271  do_parse!(
272    tag!("(") >>
273    expr_a: ws!(expression) >>
274    function_name: ws!(operator_identifiers) >>
275    expr_b: ws!(expression) >>
276    tag!(")") >>
277    (Expression::FunctionCall(OperationFunctionCall{function_name:function_name,params:vec![expr_a,expr_b]}))
278  )
279);
280
281named!(expression_assignment<CompleteStr, Expression>,
282  do_parse!(
283    id: ws!(token_identifier) >>
284    ws!(tag!("=")) >>
285    expr: ws!(expression) >>
286    (Expression::Assignment(OperationAssignment{id:id,value:Box::new(expr)}))
287  )
288);
289
290named!(expression_else_statement<CompleteStr, Vec<Expression>>,
291  do_parse!(
292    ws!(tag!("else")) >>
293    ws!(tag!("{")) >>
294    expr_c: expression_list >>
295    tag!("}") >>
296    (expr_c)
297  )
298);
299
300named!(expression_if_statement<CompleteStr, Expression>,
301  do_parse!(
302    ws!(tag!("if")) >>
303    expr_a: ws!(expression) >>
304    ws!(tag!("{")) >>
305    expr_b: expression_list >>
306    tag!("}") >>
307    expr_c: ws!(opt!(expression_else_statement)) >>
308    (Expression::IfStatement(OperationIfStatement{condition:Box::new(expr_a),if_true:expr_b,if_false:expr_c}))
309  )
310);
311
312named!(expression_unary_operator_call<CompleteStr, Expression>,
313  do_parse!(
314    function_name: ws!(unary_operator_identifiers) >>
315    expr_a: ws!(expression) >>
316    (Expression::FunctionCall(OperationFunctionCall{function_name:function_name,params:vec![expr_a]}))
317  )
318);
319
320named!(expression_function_call<CompleteStr, Expression>,
321  do_parse!(
322    function_name: ws!(function_identifiers) >>
323    tag!("(")   >>
324    params: ws!(function_params) >>
325    ws!(tag!(")"))   >>
326    (Expression::FunctionCall(OperationFunctionCall{function_name:function_name,params:params}))
327  )
328);
329
330named!(define_function<CompleteStr, TopLevelOperation>,
331  do_parse!(
332    external_name:opt!( ws!(tag!("pub"))) >>
333    many0!(ws!(token_comment)) >>
334    ws!(tag!("fn"))   >>
335    many0!(ws!(token_comment)) >>
336    function_name: ws!(token_identifier) >>
337    many0!(ws!(token_comment)) >>
338    ws!(tag!("("))   >>
339    many0!(ws!(token_comment)) >>
340    params: ws!(separated_list!(tag!(","),ws!(token_identifier))) >>
341    many0!(ws!(token_comment)) >>
342    ws!(tag!(")"))   >>
343    many0!(ws!(token_comment)) >>
344    ws!(tag!("{"))   >>
345    children: expression_list >>
346    tag!("}")   >>
347    (TopLevelOperation::DefineFunction(FunctionDefinition{name: function_name,
348    exported: external_name.is_some(),
349    params: params,
350    output: None,
351    children: children}))
352  )
353);
354
355named!(struct_pair<CompleteStr, StructMember>,
356  do_parse!(
357    name: token_symbol >>
358    many0!(ws!(token_comment)) >>
359    (StructMember{name: name})
360  )
361);
362
363named!(define_struct<CompleteStr, TopLevelOperation>,
364  do_parse!(
365    ws!(tag!("struct"))   >>
366    many0!(ws!(token_comment)) >>
367    name: ws!(token_identifier) >>
368    many0!(ws!(token_comment)) >>
369    tag!("{")   >>
370    many0!(ws!(token_comment)) >>
371    members: many0!(ws!(struct_pair)) >>
372    many0!(ws!(token_comment)) >>
373    tag!("}")   >>
374    (TopLevelOperation::DefineGlobal(Global{name:name,value:GlobalValue::Struct(StructDefinition{
375    members: members})}))
376  )
377);
378
379named!(value_number<CompleteStr, GlobalValue>,
380  do_parse!(
381    value: token_number  >>
382    (GlobalValue::Number(value))
383  )
384);
385
386named!(value_text<CompleteStr, GlobalValue>,
387  do_parse!(
388    value: token_text  >>
389    (GlobalValue::Text(value))
390  )
391);
392
393named!(value_symbol<CompleteStr, GlobalValue>,
394  do_parse!(
395    value: token_symbol  >>
396    (GlobalValue::Symbol(value))
397  )
398);
399
400named!(global_bool_true<CompleteStr, GlobalValue>,
401  do_parse!(
402    tag!("true")  >>
403    (GlobalValue::Number(1.0))
404  )
405);
406
407named!(global_bool_false<CompleteStr, GlobalValue>,
408  do_parse!(
409    tag!("false")  >>
410    (GlobalValue::Number(0.0))
411  )
412);
413
414named!(global_identifier<CompleteStr, GlobalValue>,
415  do_parse!(
416    value: token_identifier >>
417    (GlobalValue::Identifier(value))
418  )
419);
420
421named!(global_data<CompleteStr, GlobalValue>,
422  do_parse!(
423    tag!("(")  >>
424    values: ws!(separated_list!(tag!(","),ws!(alt!(global_value|global_identifier)))) >>
425    tag!(")")  >>
426    (GlobalValue::Data(values))
427  )
428);
429
430named!(global_value<CompleteStr, GlobalValue>,
431  do_parse!(
432    value: ws!(alt!(global_bool_true|global_bool_false|value_number|value_symbol|value_text|global_data)) >>
433    (value)
434  )
435);
436
437named!(define_global<CompleteStr, TopLevelOperation>,
438  do_parse!(
439    ws!(tag!("static"))   >>
440    name: ws!(token_identifier) >>
441    ws!(tag!("="))   >>
442    value: global_value >>
443    (TopLevelOperation::DefineGlobal(Global{name: name,value:value}))
444  )
445);
446
447named!(comment<CompleteStr, TopLevelOperation>,
448  do_parse!(
449    tag!("//") >>
450    comment: map!(take_while!(is_comment_char),to_string) >>
451    (TopLevelOperation::Comment(comment))
452  )
453);
454
455named!(app<CompleteStr, App>,
456  do_parse!(
457    op: many0!(ws!(alt!(comment|external_function|define_function|define_struct|define_global))) >>
458    eof!() >>
459    (App{children:op})
460  )
461);
462
463pub fn parse(content: &str) -> Result<App, Error> {
464    let result = app(CompleteStr(content));
465    match result {
466        Ok((_, value)) => Ok(value),
467        Err(nom::Err::Incomplete(needed)) => Err(format_err!("{:?}", needed)),
468        Err(nom::Err::Error(e)) | Err(nom::Err::Failure(e)) => Err(format_err!("{:?}", e)),
469    }
470}