kaiju_core/
parser.rs

1use crate::ast::*;
2use crate::error::*;
3use pest::error::{Error, InputLocation, LineColLocation};
4use pest::iterators::Pair;
5use pest::Parser;
6
7#[derive(Parser)]
8#[grammar = "grammars/kaiju.pest"]
9pub struct KaijuParser;
10
11fn translate_error(err: Error<Rule>) -> Error<Rule> {
12    err.renamed_rules(|rule| match *rule {
13        Rule::shebang => "shebang (`#!{ ... }`)".to_owned(),
14        Rule::identifier => "identifier (`name` or `$extra.name`)".to_owned(),
15        Rule::identifier_simple => "simple identifier (`name`)".to_owned(),
16        Rule::identifier_extended => "extended identifier (`$extra.name`)".to_owned(),
17        Rule::type_ann => "type annotation (`:type`, `:*type`, `:(typeA, typeB)`)".to_owned(),
18        Rule::type_ => "type (`type`, `*type`, `(typeA, typeB)`)".to_owned(),
19        Rule::tuple_type => "tuple type (`(typeA, typeB)`)".to_owned(),
20        Rule::pointer_type => "pointer type (`*type`)".to_owned(),
21        Rule::string => "string (`'hello'`)".to_owned(),
22        Rule::integer => "integer (`42`, `42u8`, `0x2A`, `0x2Au8`)".to_owned(),
23        Rule::integer_inner => "integer (`42`, `0x2A`)".to_owned(),
24        Rule::hex => "hex (`0x2A`)".to_owned(),
25        Rule::float => "float (`4.2`, `4.2f64`, `4.2e7`, `4.2e7f64`)".to_owned(),
26        Rule::float_inner => "float (`4.2`, `4.2e7`)".to_owned(),
27        Rule::number => "number (`42`, `4.2`, `4.2e7`, `0x2A`, `42u8`, `4.2e7f64`)".to_owned(),
28        Rule::tuple_value => "tuple value (`(42, '42', &4.2)`)".to_owned(),
29        Rule::variable => "variable (`a:i32`)".to_owned(),
30        Rule::variable_access => "variable access (`a.foo`)".to_owned(),
31        Rule::tuple_access => "tuple access (`a.0`)".to_owned(),
32        Rule::ref_value => "reference access (`&<a>`, `&<a.v>`)".to_owned(),
33        Rule::deref_value => "dereference value (`*<a>`, `*<a.v>`)".to_owned(),
34        Rule::label => "label (`name:`)".to_owned(),
35        Rule::block => "code block (`{ ... }`)".to_owned(),
36        Rule::operation => "operation (`op param => target`)".to_owned(),
37        Rule::operation_inline => "inline operation (`(op param)`)".to_owned(),
38        Rule::operation_id => "operation identifier (`name`)".to_owned(),
39        Rule::operation_params => "operation params (`param1 param2 ...`)".to_owned(),
40        Rule::operation_targets => "operation targets (`=> target1 target2`)".to_owned(),
41        Rule::function => "function (`fn foo(v:i32):i32 { ... }`)".to_owned(),
42        Rule::function_header => "function header (`fn foo(v:i32):i32`)".to_owned(),
43        Rule::function_params => "function params (`(a:i32, b:f64)`)".to_owned(),
44        Rule::function_locals => "function locals (`<a:i32, b:f64>`)".to_owned(),
45        Rule::function_call => "function call (`foo(42, 4.2)`)".to_owned(),
46        Rule::function_call_args => "function call args (`foo(42, 4.2)`)".to_owned(),
47        Rule::meta_global => "global meta (`#![attrib];`)".to_owned(),
48        Rule::meta_local => "local meta (`#[attrib]`)".to_owned(),
49        Rule::meta_fields => "meta fields (`#[attrib1, attrib2]`)".to_owned(),
50        Rule::meta_field => "meta field (`#[attrib()]`)".to_owned(),
51        Rule::meta_field_args => "meta field args (`#[attrib(arg)]`)".to_owned(),
52        Rule::meta_value => {
53            "meta field value (`#[attrib(42, 4.2, '42', named = 42, attrib2())]`)".to_owned()
54        }
55        Rule::meta_named_value => "meta field named value (`#[attrib(named = 42)]`)".to_owned(),
56        Rule::extern_ => "external function (`extern fn log() from console:log;`)".to_owned(),
57        Rule::extern_item => "external function header (`fn foo(v:i32):i32`)".to_owned(),
58        Rule::extern_location => "external function location (`module:funname`)".to_owned(),
59        Rule::import => "import symbols (`import { foo, bar } from 'std';`)".to_owned(),
60        Rule::import_name => "import symbol identifier (`foo`)".to_owned(),
61        Rule::import_names => "import symbol identifiers (`{ foo, bar }`)".to_owned(),
62        Rule::import_module => "import module path (`'path/to/module`)".to_owned(),
63        Rule::globals => "globals (`<a:i32, b:f64>`)".to_owned(),
64        Rule::struct_ => "struct (`struct A { a:i32, b:f64 }`)".to_owned(),
65        Rule::struct_fields => "struct fields (`{ a:i32, b:f64 }`)".to_owned(),
66        Rule::op_rule => "rule (`add @value:a @value:b => r {}`)".to_owned(),
67        Rule::op_rule_def => "rule definition (`{ field: { name: 'value' } }`)".to_owned(),
68        Rule::op_rule_def_field => "rule definition field (`field: { name: 'value' }`)".to_owned(),
69        Rule::op_rule_def_field_id => "field id (`foo`)".to_owned(),
70        Rule::op_rule_def_field_desc => "field description (`{ name: 'value' }`)".to_owned(),
71        Rule::op_rule_def_field_desc_field => {
72            "field description parameter (`name: 'value'`)".to_owned()
73        }
74        _ => format!("{:?}", rule),
75    })
76}
77
78pub fn parse_module(source: &str) -> CompilationResult<AstModule> {
79    match KaijuParser::parse(Rule::module, source) {
80        Ok(mut ast) => {
81            let pair = ast.next().unwrap();
82            match pair.as_rule() {
83                Rule::module => Ok(parse_module_inner(pair)),
84                _ => unreachable!(),
85            }
86        }
87        Err(err) => {
88            let location = match err.location {
89                InputLocation::Pos(a) => (a, a),
90                InputLocation::Span((a, b)) => (a, b),
91            };
92            let (line, column) = match err.line_col {
93                LineColLocation::Pos((a, b)) => ((a, a), (b, b)),
94                LineColLocation::Span((a, b), (c, d)) => ((a, c), (b, d)),
95            };
96            let err = translate_error(err);
97            Err(CompilationError {
98                message: "".to_owned(),
99                location,
100                line,
101                column,
102                pretty: format!("{}", err),
103            })
104        }
105    }
106}
107
108pub fn parse_ops_descriptor(source: &str) -> CompilationResult<AstOpsDescriptor> {
109    match KaijuParser::parse(Rule::ops_descriptor, source) {
110        Ok(mut ast) => {
111            let pair = ast.next().unwrap();
112            match pair.as_rule() {
113                Rule::ops_descriptor => Ok(parse_ops_descriptor_inner(pair)),
114                _ => unreachable!(),
115            }
116        }
117        Err(err) => {
118            let location = match err.location {
119                InputLocation::Pos(a) => (a, a),
120                InputLocation::Span((a, b)) => (a, b),
121            };
122            let (line, column) = match err.line_col {
123                LineColLocation::Pos((a, b)) => ((a, a), (b, b)),
124                LineColLocation::Span((a, b), (c, d)) => ((a, c), (b, d)),
125            };
126            let err = translate_error(err);
127            Err(CompilationError {
128                message: "".to_owned(),
129                location,
130                line,
131                column,
132                pretty: format!("{}", err),
133            })
134        }
135    }
136}
137
138fn parse_module_inner(pair: Pair<Rule>) -> AstModule {
139    let mut shebang = None;
140    let mut instructions = vec![];
141    for p in pair.into_inner() {
142        match p.as_rule() {
143            Rule::shebang => shebang = Some(p.as_str().trim().to_owned()),
144            Rule::instruction => {
145                instructions.push(parse_instruction(p.into_inner().next().unwrap()))
146            }
147            Rule::EOI => {}
148            _ => unreachable!(),
149        }
150    }
151    AstModule {
152        shebang,
153        instructions,
154    }
155}
156
157fn parse_instruction(pair: Pair<Rule>) -> AstInstruction {
158    match pair.as_rule() {
159        Rule::meta_global => AstInstruction::Meta(parse_meta(pair)),
160        Rule::import => AstInstruction::Import(parse_import(pair)),
161        Rule::globals => AstInstruction::Globals(pair.into_inner().map(parse_variable).collect()),
162        Rule::extern_ => AstInstruction::Extern(parse_extern(pair)),
163        Rule::struct_ => AstInstruction::Struct(parse_struct(pair)),
164        Rule::function => AstInstruction::Function(parse_function(pair)),
165        _ => unreachable!(),
166    }
167}
168
169fn parse_meta(pair: Pair<Rule>) -> AstMeta {
170    AstMeta(
171        pair.into_inner()
172            .next()
173            .unwrap()
174            .into_inner()
175            .map(parse_meta_field)
176            .collect(),
177    )
178}
179
180fn parse_meta_field(pair: Pair<Rule>) -> AstMetaField {
181    let mut inner = pair.into_inner();
182    let id = parse_identifier(inner.next().unwrap());
183    let args = if let Some(p) = inner.next() {
184        p.into_inner()
185            .map(|p| parse_meta_value(p.into_inner().next().unwrap()))
186            .collect()
187    } else {
188        vec![]
189    };
190    AstMetaField { id, args }
191}
192
193fn parse_meta_value(pair: Pair<Rule>) -> AstMetaValue {
194    match pair.as_rule() {
195        Rule::meta_named_value => {
196            let (id, val) = parse_meta_named_value(pair);
197            AstMetaValue::Named(id, val)
198        }
199        Rule::meta_field => AstMetaValue::Field(parse_meta_field(pair)),
200        Rule::string => AstMetaValue::String(parse_string(pair)),
201        Rule::number => AstMetaValue::Number(parse_number(pair)),
202        _ => unreachable!(),
203    }
204}
205
206fn parse_meta_named_value(pair: Pair<Rule>) -> (AstIdentifier, Box<AstMetaValue>) {
207    let mut inner = pair.into_inner();
208    let pid = inner.next().unwrap();
209    let pval = inner.next().unwrap();
210    (
211        parse_identifier(pid),
212        Box::new(parse_meta_value(pval.into_inner().next().unwrap())),
213    )
214}
215
216fn parse_identifier(pair: Pair<Rule>) -> AstIdentifier {
217    let p = pair.into_inner().next().unwrap();
218    match p.as_rule() {
219        Rule::identifier_simple => AstIdentifier(p.as_str().to_owned()),
220        Rule::identifier_extended => {
221            AstIdentifier(p.into_inner().next().unwrap().as_str().to_owned())
222        }
223        _ => unreachable!(),
224    }
225}
226
227fn parse_string(pair: Pair<Rule>) -> AstString {
228    let mut inner = pair.into_inner();
229    let value = inner.next().unwrap().as_str().to_owned();
230    let type_ = if let Some(t) = inner.next() {
231        parse_type(t)
232    } else {
233        AstType::Pointer(Box::new(AstType::Identifier(AstIdentifier(
234            "{string}".to_string(),
235        ))))
236    };
237    AstString(value, type_)
238}
239
240fn parse_number(pair: Pair<Rule>) -> AstNumber {
241    let p = pair.into_inner().next().unwrap();
242    match p.as_rule() {
243        Rule::integer => AstNumber::Integer(parse_integer(p)),
244        Rule::float => AstNumber::Float(parse_float(p)),
245        _ => unreachable!(),
246    }
247}
248
249fn parse_integer(pair: Pair<Rule>) -> AstInteger {
250    let mut inner = pair.into_inner();
251    let value = inner.next().unwrap().as_str();
252    let type_ = if let Some(t) = inner.next() {
253        parse_type(t)
254    } else {
255        AstType::Identifier(AstIdentifier("{integer}".to_string()))
256    };
257    if value.starts_with("0x") {
258        AstInteger(
259            i64::from_str_radix(value.trim_start_matches("0x"), 16).unwrap(),
260            type_,
261        )
262    } else {
263        AstInteger(value.parse().unwrap(), type_)
264    }
265}
266
267fn parse_float(pair: Pair<Rule>) -> AstFloat {
268    let mut inner = pair.into_inner();
269    let value = inner.next().unwrap().as_str();
270    let type_ = if let Some(t) = inner.next() {
271        parse_type(t)
272    } else {
273        AstType::Identifier(AstIdentifier("{float}".to_string()))
274    };
275    AstFloat(value.parse().unwrap(), type_)
276}
277
278fn parse_import(pair: Pair<Rule>) -> AstImport {
279    let mut meta = vec![];
280    let mut names = vec![];
281    let mut module = AstString::default();
282    for p in pair.into_inner() {
283        match p.as_rule() {
284            Rule::meta_local => meta.push(parse_meta(p)),
285            Rule::import_names => names.extend(
286                p.into_inner()
287                    .map(|p| parse_identifier(p.into_inner().next().unwrap()))
288                    .collect::<Vec<AstIdentifier>>(),
289            ),
290            Rule::import_name => names.push(parse_identifier(p.into_inner().next().unwrap())),
291            Rule::import_module => module = parse_string(p.into_inner().next().unwrap()),
292            _ => unreachable!(),
293        }
294    }
295    AstImport {
296        meta,
297        names,
298        module,
299    }
300}
301
302fn parse_variable(pair: Pair<Rule>) -> AstVariable {
303    let mut inner = pair.into_inner();
304    let id = parse_identifier(inner.next().unwrap());
305    let typeid = parse_type(inner.next().unwrap().into_inner().next().unwrap());
306    AstVariable { id, typeid }
307}
308
309fn parse_type(pair: Pair<Rule>) -> AstType {
310    let p = pair.into_inner().next().unwrap();
311    match p.as_rule() {
312        Rule::tuple_type => AstType::Tuple(p.into_inner().map(parse_type).collect()),
313        Rule::pointer_type => {
314            AstType::Pointer(Box::new(parse_type(p.into_inner().next().unwrap())))
315        }
316        Rule::identifier => AstType::Identifier(parse_identifier(p)),
317        _ => unreachable!(),
318    }
319}
320
321fn parse_extern(pair: Pair<Rule>) -> AstExtern {
322    let mut meta = vec![];
323    let mut item = AstFunctionHeader {
324        id: AstIdentifier::default(),
325        params: vec![],
326        typeid: None,
327    };
328    let mut location_module = AstIdentifier::default();
329    let mut location_function = AstIdentifier::default();
330    for p in pair.into_inner() {
331        match p.as_rule() {
332            Rule::meta_local => meta.push(parse_meta(p)),
333            Rule::extern_item => item = parse_function_header(p),
334            Rule::extern_location => {
335                let mut inner = p.into_inner();
336                location_module = parse_identifier(inner.next().unwrap());
337                location_function = parse_identifier(inner.next().unwrap());
338            }
339            _ => unreachable!(),
340        }
341    }
342    AstExtern {
343        meta,
344        item,
345        location_module,
346        location_function,
347    }
348}
349
350fn parse_struct(pair: Pair<Rule>) -> AstStruct {
351    let mut meta = vec![];
352    let mut export = false;
353    let mut id = AstIdentifier::default();
354    let mut fields = vec![];
355    for p in pair.into_inner() {
356        match p.as_rule() {
357            Rule::meta_local => meta.push(parse_meta(p)),
358            Rule::export => export = true,
359            Rule::identifier => id = parse_identifier(p),
360            Rule::struct_fields => fields = p.into_inner().map(parse_variable).collect(),
361            _ => unreachable!(),
362        }
363    }
364    AstStruct {
365        meta,
366        export,
367        id,
368        fields,
369    }
370}
371
372fn parse_function(pair: Pair<Rule>) -> AstFunction {
373    let mut meta = vec![];
374    let mut export = false;
375    let mut header = None;
376    let mut locals = vec![];
377    let mut ops = vec![];
378    for p in pair.into_inner() {
379        match p.as_rule() {
380            Rule::meta_local => meta.push(parse_meta(p)),
381            Rule::export => export = true,
382            Rule::function_header => header = Some(parse_function_header(p)),
383            Rule::function_locals => locals = p.into_inner().map(parse_variable).collect(),
384            Rule::block => ops = parse_block(p),
385            _ => unreachable!(),
386        }
387    }
388    AstFunction {
389        meta,
390        export,
391        header: header.unwrap(),
392        locals,
393        ops,
394    }
395}
396
397fn parse_function_header(pair: Pair<Rule>) -> AstFunctionHeader {
398    let mut id = AstIdentifier::default();
399    let mut params = vec![];
400    let mut typeid = None;
401    for p in pair.into_inner() {
402        match p.as_rule() {
403            Rule::identifier => id = parse_identifier(p),
404            Rule::function_params => params = p.into_inner().map(parse_variable).collect(),
405            Rule::type_ann => typeid = Some(parse_type(p.into_inner().next().unwrap())),
406            _ => unreachable!(),
407        }
408    }
409    AstFunctionHeader { id, params, typeid }
410}
411
412fn parse_block(pair: Pair<Rule>) -> Vec<AstBlockOp> {
413    pair.into_inner()
414        .map(|p| match p.as_rule() {
415            Rule::label => AstBlockOp::Label(parse_identifier(p.into_inner().next().unwrap())),
416            Rule::operation => AstBlockOp::Operation(parse_operation(p)),
417            _ => unreachable!(),
418        })
419        .collect()
420}
421
422fn parse_operation(pair: Pair<Rule>) -> AstOperation {
423    let mut meta = vec![];
424    let mut id = AstIdentifier::default();
425    let mut params = vec![];
426    let mut targets = vec![];
427    for p in pair.into_inner() {
428        match p.as_rule() {
429            Rule::meta_local => meta.push(parse_meta(p)),
430            Rule::operation_id => id = parse_identifier(p),
431            Rule::operation_params => params = p.into_inner().map(parse_value).collect(),
432            Rule::operation_targets => targets = p.into_inner().map(parse_value).collect(),
433            _ => unreachable!(),
434        }
435    }
436    AstOperation {
437        meta,
438        id,
439        params,
440        targets,
441    }
442}
443
444fn parse_value(pair: Pair<Rule>) -> AstValue {
445    let mut inner = pair.into_inner();
446    let p = inner.next().unwrap().into_inner().next().unwrap();
447    let a = inner.next().map(|p| Box::new(parse_access(p)));
448    match p.as_rule() {
449        Rule::ref_value => parse_ref(p, a),
450        Rule::deref_value => parse_deref(p, a),
451        Rule::function_call => parse_function_call(p, a),
452        Rule::tuple_value => AstValue::Tuple(p.into_inner().map(parse_value).collect(), a),
453        Rule::string => AstValue::String(parse_string(p)),
454        Rule::number => AstValue::Number(parse_number(p)),
455        Rule::operation_inline => parse_operation_inline(p, a),
456        Rule::variable_value => {
457            AstValue::Variable(parse_identifier(p.into_inner().next().unwrap()), a)
458        }
459        _ => unreachable!(),
460    }
461}
462
463fn parse_ref(pair: Pair<Rule>, access: Option<Box<AstAccess>>) -> AstValue {
464    AstValue::Ref(
465        Box::new(parse_value(pair.into_inner().next().unwrap())),
466        access,
467    )
468}
469
470fn parse_deref(pair: Pair<Rule>, access: Option<Box<AstAccess>>) -> AstValue {
471    AstValue::Deref(
472        Box::new(parse_value(pair.into_inner().next().unwrap())),
473        access,
474    )
475}
476
477fn parse_function_call(pair: Pair<Rule>, access: Option<Box<AstAccess>>) -> AstValue {
478    let mut inner = pair.into_inner();
479    let id = parse_identifier(inner.next().unwrap());
480    let params = inner
481        .next()
482        .unwrap()
483        .into_inner()
484        .map(parse_value)
485        .collect();
486    AstValue::FunctionCall(id, params, access)
487}
488
489fn parse_access(pair: Pair<Rule>) -> AstAccess {
490    let p = pair.into_inner().next().unwrap();
491    match p.as_rule() {
492        Rule::variable_access => parse_variable_access(p),
493        Rule::tuple_access => parse_tuple_access(p),
494        _ => unreachable!(),
495    }
496}
497
498fn parse_variable_access(pair: Pair<Rule>) -> AstAccess {
499    let mut inner = pair.into_inner();
500    let id = parse_identifier(inner.next().unwrap());
501    let next = if let Some(p) = inner.next() {
502        Some(Box::new(parse_access(p)))
503    } else {
504        None
505    };
506    AstAccess::Variable(id, next)
507}
508
509fn parse_tuple_access(pair: Pair<Rule>) -> AstAccess {
510    let mut inner = pair.into_inner();
511    let id = parse_integer(inner.next().unwrap());
512    let next = if let Some(p) = inner.next() {
513        Some(Box::new(parse_access(p)))
514    } else {
515        None
516    };
517    AstAccess::Tuple(id, next)
518}
519
520fn parse_operation_inline(pair: Pair<Rule>, access: Option<Box<AstAccess>>) -> AstValue {
521    let mut inner = pair.into_inner();
522    let id = parse_identifier(inner.next().unwrap());
523    let params = inner
524        .next()
525        .unwrap()
526        .into_inner()
527        .map(parse_value)
528        .collect();
529    AstValue::OperationInline(id, params, access)
530}
531
532fn parse_ops_descriptor_inner(pair: Pair<Rule>) -> AstOpsDescriptor {
533    let mut meta = vec![];
534    let mut rules = vec![];
535    for p in pair.into_inner() {
536        match p.as_rule() {
537            Rule::meta_global => meta.push(parse_meta(p)),
538            Rule::op_rule => rules.push(parse_op_rule(p)),
539            Rule::EOI => {}
540            _ => unreachable!(),
541        }
542    }
543    AstOpsDescriptor { meta, rules }
544}
545
546fn parse_op_rule(pair: Pair<Rule>) -> AstOpRule {
547    let mut meta = vec![];
548    let mut id = AstIdentifier::default();
549    let mut params = vec![];
550    let mut targets = vec![];
551    let mut definition = vec![];
552    for p in pair.into_inner() {
553        match p.as_rule() {
554            Rule::meta_local => meta.push(parse_meta(p)),
555            Rule::identifier_simple => id = AstIdentifier(p.as_str().to_owned()),
556            Rule::op_param => params.push(parse_op_param(p)),
557            Rule::op_targets => targets = p.into_inner().map(parse_type).collect(),
558            Rule::op_rule_def => definition = p.into_inner().map(parse_op_rule_def).collect(),
559            _ => unreachable!(),
560        }
561    }
562    AstOpRule {
563        meta,
564        id,
565        params,
566        targets,
567        definition,
568    }
569}
570
571fn parse_op_param(pair: Pair<Rule>) -> AstOpParam {
572    let mut inner = pair.into_inner();
573    AstOpParam {
574        id: AstIdentifier(inner.next().unwrap().as_str().to_owned()),
575        typeid: parse_op_value(inner.next().unwrap()),
576    }
577}
578
579fn parse_op_value(pair: Pair<Rule>) -> AstType {
580    match pair.as_rule() {
581        Rule::op_value => parse_type(pair.into_inner().next().unwrap()),
582        _ => unreachable!(),
583    }
584}
585
586fn parse_op_rule_def(pair: Pair<Rule>) -> AstOpRuleDef {
587    let mut inner = pair.into_inner();
588    AstOpRuleDef {
589        id: AstIdentifier(inner.next().unwrap().as_str().to_owned()),
590        description: inner
591            .next()
592            .unwrap()
593            .into_inner()
594            .map(parse_op_rule_def_desc)
595            .collect(),
596    }
597}
598
599fn parse_op_rule_def_desc(pair: Pair<Rule>) -> AstOpRuleDefDesc {
600    let mut inner = pair.into_inner();
601    AstOpRuleDefDesc {
602        id: AstIdentifier(inner.next().unwrap().as_str().to_owned()),
603        value: parse_string(inner.next().unwrap()),
604    }
605}