typescript_ast/parser/
mod.rs

1use std::{error::Error, path::Path, sync::Arc, collections::HashMap};
2
3use crate::ast::{
4    class::Class,
5    function::{Function, Param},
6    interface::Interface,
7    module::{Import, ImportAlias, Module},
8    statement::{ElseIf, Statement},
9    tstype::TsType,
10    typedefinition::{TypeBlock, TypeDefinition},
11    value::Value,
12};
13use pest::{iterators::Pair, Parser};
14use pest_derive::Parser;
15
16#[derive(Parser)]
17#[grammar = "parser/typescript.pest"] // relative to src
18pub struct TypeScriptParser;
19
20fn parse_term(term: Pair<Rule>) -> Value {
21    let inner = term.into_inner().next().unwrap();
22
23    match inner.as_rule() {
24        Rule::Number => {
25            if let Ok(flt) = inner.as_str().parse::<f64>() {
26                Value::Number(flt)
27            } else {
28                Value::Undefined
29            }
30        }
31        Rule::False => Value::Boolean(false),
32        Rule::True => Value::Boolean(true),
33        Rule::Identifier => {
34            let names: Vec<String> = inner.as_str().split(".").map(|n| n.to_string()).collect();
35
36            Value::Identifier(names)
37        }
38        Rule::String => {
39            let data = inner.as_str();
40            Value::String(data[1..data.len() - 1].into())
41        }
42        Rule::Call => {
43            parse_call(inner)
44        }
45        _ => {
46            Value::Undefined
47        }
48    }
49}
50
51fn parse_value(expr: Pair<Rule>) -> Arc<Value> {
52    let mut inner = expr.into_inner();
53
54    let term = inner.next().unwrap();
55
56    if let Some(op) = inner.next() {
57        let term1 = inner.next().unwrap();
58        Arc::new(Value::Expression {
59            left: Arc::new(parse_term(term)),
60            op: op.as_str().into(),
61            right: Arc::new(parse_term(term1)),
62        })
63    } else {
64        Arc::new(parse_term(term))
65    }
66}
67
68fn parse_param_kind(kind: Pair<Rule>) -> Vec<TsType> {
69    let mut kinds = Vec::new();
70
71    for k in kind.into_inner() {
72        kinds.push(k.as_str().into());
73    }
74
75    kinds
76}
77
78fn parse_param(param: Pair<Rule>) -> Param {
79    let mut inner = param.into_inner();
80    let name = inner.next().unwrap();
81    let mut kinds = Vec::new();
82    let mut default = None;
83
84    while let Some(t) = inner.next() {
85        match t.as_rule() {
86            Rule::TypeIdentifiers => {
87                kinds = parse_param_kind(t);
88            }
89            Rule::Term => {
90                default = Some(parse_term(t));
91            }
92            _ => {}
93        }
94    }
95
96    Param {
97        name: name.as_str().to_string(),
98        kinds,
99        default,
100    }
101}
102
103fn parse_template_definition(tmp: Pair<Rule>) -> (String, Vec<TsType>) {
104    let mut inner = tmp.into_inner();
105
106    let name = inner.next().unwrap().as_str();
107
108    let kinds = if let Some(typedef) = inner.next() {
109        parse_param_kind(typedef)
110    }
111    else {
112        Vec::new()
113    };
114
115    (name.into(), kinds)
116}
117
118fn parse_function(func: Pair<Rule>) -> Function {
119    let mut name = None;
120    let mut params = Vec::new();
121    let mut returns = Vec::new();
122    let mut block_statements = Vec::new();
123    let mut template_args = HashMap::new();
124
125    for inner in func.into_inner() {
126        match inner.as_rule() {
127            Rule::Name => {
128                name = Some(inner.as_str().into());
129            }
130            Rule::TemplateDefinition => {
131                for p in inner.into_inner() {
132                    let (name, kinds) = parse_template_definition(p);
133                    template_args.insert(name, kinds);
134                }
135            }
136            Rule::FunctionDefinition => {
137                for p in inner.into_inner() {
138                    match p.as_rule() {
139                        Rule::ParamList => {
140                            for p in p.into_inner() {
141                                params.push(parse_param(p));
142                            }
143                        }
144                        Rule::ReturnType => {
145                            for r in p.into_inner() {
146                                returns.push(r.as_str().into());
147                            }
148                        }
149                        _ => {}
150                    }
151                }
152            }
153            Rule::Block => {
154                for stmnt in inner.into_inner() {
155                    if let Some(s) = parse_statement(stmnt) {
156                        block_statements.push(s);
157                    }
158                }
159            }
160            _ => {}
161        }
162    }
163
164    let f = Function {
165        name,
166        is_async: false,
167        template_args,
168        params,
169        returns,
170        block: block_statements,
171    };
172    f
173}
174
175fn parse_call(stmnt: Pair<Rule>) -> Value {
176    let mut inner = stmnt.into_inner();
177    let identifier: Vec<String> = inner
178        .next()
179        .unwrap()
180        .as_str()
181        .split(".")
182        .map(|n| n.to_string())
183        .collect();
184
185    let args = inner
186        .next()
187        .unwrap()
188        .into_inner()
189        .map(|n| parse_value(n))
190        .collect();
191
192    Value::Call { identifier, args }
193}
194
195fn parse_statement(stmnt: Pair<Rule>) -> Option<Statement> {
196    let stmnt = stmnt.into_inner().next().unwrap();
197
198    match stmnt.as_rule() {
199        Rule::Const => {
200            let mut inner = stmnt.into_inner();
201            let name = inner.next().unwrap();
202            let expr = inner.next().unwrap();
203
204            Some(Statement::Const {
205                name: name.as_str().to_string(),
206                value: parse_value(expr),
207            })
208        }
209        Rule::Let => {
210            let mut inner = stmnt.into_inner();
211            let name = inner.next().unwrap();
212            let expr = inner.next().unwrap();
213
214            Some(Statement::Let {
215                name: name.as_str().to_string(),
216                value: parse_value(expr),
217            })
218        }
219        Rule::Assign => {
220            let mut inner = stmnt.into_inner();
221            let name = inner.next().unwrap();
222            let expr = inner.next().unwrap();
223
224            Some(Statement::Assign {
225                identifier: name.as_str().to_string(),
226                value: parse_value(expr),
227            })
228        }
229        Rule::If => {
230            let mut inner = stmnt.into_inner();
231            let expr = inner.next().unwrap();
232            let block = inner.next().unwrap();
233
234            let mut block_stmnts = Vec::new();
235            for stmnt in block.into_inner() {
236                if let Some(s) = parse_statement(stmnt) {
237                    block_stmnts.push(s);
238                }
239            }
240
241            let mut else_block = Vec::new();
242            let mut elseifs = Vec::new();
243            for next in inner {
244                match next.as_rule() {
245                    Rule::ElseIf => {
246                        let mut inner = next.into_inner();
247                        let expr = inner.next().unwrap();
248                        let block = inner.next().unwrap();
249
250                        let mut block_statements = Vec::new();
251                        for stmnt in block.into_inner() {
252                            if let Some(s) = parse_statement(stmnt) {
253                                block_statements.push(s);
254                            }
255                        }
256
257                        elseifs.push(ElseIf {
258                            expr: parse_value(expr),
259                            block: block_statements,
260                        });
261                    }
262                    Rule::Else => {
263                        let block = next.into_inner().next().unwrap();
264                        for stmnt in block.into_inner() {
265                            if let Some(s) = parse_statement(stmnt) {
266                                else_block.push(s);
267                            }
268                        }
269                    }
270                    _ => {}
271                }
272            }
273
274            Some(Statement::If {
275                expr: parse_value(expr),
276                block: block_stmnts,
277                elseifs,
278                els: else_block,
279            })
280        }
281        Rule::Function => {
282            let func = parse_function(stmnt);
283            Some(Statement::Function(func))
284        }
285        Rule::Call => Some(Statement::Call(Arc::new(parse_call(stmnt)))),
286        Rule::Return => {
287            Some(Statement::Return(parse_value(stmnt.into_inner().next().unwrap())))
288        }
289        _ => None,
290    }
291}
292
293fn parse_interface(stmnt: Pair<Rule>) -> Statement {
294    let mut inner = stmnt.into_inner();
295
296    let name = inner.next().unwrap().as_str();
297    let mut extends = None;
298    let mut attributes = Vec::new();
299    let mut methods = Vec::new();
300
301    while let Some(block) = inner.next() {
302        match block.as_rule() {
303            Rule::InterfaceExtends => {
304                let inner = block.into_inner().next().unwrap();
305                extends = Some(inner.as_str().into());
306            }
307            Rule::InterfaceBody => {
308                for part in block.into_inner() {
309                    match part.as_rule() {
310                        Rule::InterfaceMethod => {
311                            methods.push(parse_function(part));
312                        }
313                        Rule::InterfaceAttribute => {
314                            attributes.push(parse_param(part.into_inner().next().unwrap()));
315                        }
316                        _ => {}
317                    }
318                }
319            }
320            _ => {}
321        }
322    }
323
324    let interface = Interface {
325        name: name.to_string(),
326        extends,
327        attributes,
328        methods,
329    };
330    Statement::Interface(interface)
331}
332
333fn parse_class(stmnt: Pair<Rule>) -> Statement {
334    let mut inner = stmnt.into_inner();
335
336    let name = inner.next().unwrap().as_str();
337    let mut extends = None;
338    let mut implements = Vec::new();
339    let mut attributes = Vec::new();
340    let mut methods = Vec::new();
341    let mut template_args = HashMap::new();
342
343    while let Some(block) = inner.next() {
344        match block.as_rule() {
345            Rule::TemplateDefinition => {
346                for inner in block.into_inner() {
347                    let (name, args) = parse_template_definition(inner);
348                    template_args.insert(name, args);
349                }
350            }
351            Rule::Extends => {
352                let inner = block.into_inner().next().unwrap();
353                extends = Some(inner.as_str().into());
354            }
355            Rule::Implements => {
356                for name in block.into_inner() {
357                    implements.push(name.as_str().into());
358                }
359            }
360            Rule::ClassBody => {
361                for part in block.into_inner() {
362                    match part.as_rule() {
363                        Rule::Method => {
364                            methods.push(parse_function(part));
365                        }
366                        Rule::ClassAttribute => {
367                            attributes.push(parse_param(part.into_inner().next().unwrap()));
368                        }
369                        _ => {}
370                    }
371                }
372            }
373            _ => {}
374        }
375    }
376
377    let class = Class {
378        name: name.to_string(),
379        extends,
380        implements,
381        attributes,
382        methods,
383        template_args,
384    };
385    Statement::Class(class)
386}
387
388fn parse_type(stmnt: Pair<Rule>) -> Statement {
389    let mut inner = stmnt.into_inner();
390
391    let name = inner.next().unwrap().as_str();
392    let mut blocks = Vec::new();
393    let mut aggregates = Vec::new();
394
395    let definitions = inner.next().unwrap().into_inner();
396    for def in definitions {
397        match def.as_rule() {
398            Rule::TypeBlock => {
399                let mut attributes = Vec::new();
400                for tuple in def.into_inner() {
401                    let mut inner = tuple.into_inner();
402
403                    let name = inner.next().unwrap().as_str();
404                    let kind = inner.next().unwrap();
405                    attributes.push(Param {
406                        name: name.to_string(),
407                        kinds: parse_param_kind(kind),
408                        default: None,
409                    });
410                }
411
412                blocks.push(TypeBlock { attributes })
413            }
414            Rule::Name => {
415                aggregates.push(def.as_str().to_string());
416            }
417            _ => {}
418        }
419    }
420
421    Statement::Type(TypeDefinition {
422        name: name.to_string(),
423        blocks,
424        aggregates,
425    })
426}
427
428pub fn file<T: AsRef<Path>>(filename: T) -> Result<Module, Box<dyn Error>> {
429    let src = std::fs::read_to_string(filename)?;
430    source(&src)
431}
432
433pub fn source(source: &str) -> Result<Module, Box<dyn Error>> {
434    let mut module = Module::new();
435    let rules = TypeScriptParser::parse(Rule::Statements, &source)?
436        .next()
437        .unwrap();
438
439    for stmnt in rules.into_inner() {
440        match stmnt.as_rule() {
441            Rule::Import => {
442                let path = stmnt.into_inner().next().unwrap();
443                let name = path.as_str();
444                let clean_name = &name[1..name.len() - 1];
445
446                module.imports.push(Import::Normal {
447                    path: clean_name.to_string(),
448                });
449            }
450            Rule::ImportFrom => {
451                let mut inner = stmnt.into_inner();
452                let namelist = inner.next().unwrap();
453                let mut names = Vec::new();
454
455                for n in namelist.into_inner() {
456                    let mut inner = n.into_inner();
457                    let name = inner.next().unwrap();
458                    let name_str = name.as_str();
459
460                    if let Some(alias) = inner.next() {
461                        let alias_str = alias.as_str();
462                        names.push(ImportAlias::Alias {
463                            name: name_str.to_string(),
464                            alias: alias_str.to_string(),
465                        });
466                    } else {
467                        names.push(ImportAlias::None {
468                            name: name_str.to_string(),
469                        });
470                    }
471                }
472
473                let file = inner.next().unwrap();
474                let filename = file.as_str();
475
476                module.imports.push(Import::From {
477                    names,
478                    path: filename[1..filename.len() - 1].to_string(),
479                })
480            }
481            Rule::Interface => {
482                module.statements.push(parse_interface(stmnt));
483            }
484            Rule::Class => {
485                module.statements.push(parse_class(stmnt));
486            }
487            Rule::Type => {
488                module.statements.push(parse_type(stmnt));
489            }
490            Rule::Statement => {
491                if let Some(s) = parse_statement(stmnt) {
492                    module.statements.push(s);
493                }
494            }
495            _ => {}
496        }
497    }
498
499    Ok(module)
500}