use std::{error::Error, path::Path, sync::Arc};
use crate::ast::{
module::{ImportAlias, Module, Import},
statement::{ElseIf, Param, Statement},
value::Value,
};
use pest::{iterators::Pair, Parser};
use pest_derive::Parser;
#[derive(Parser)]
#[grammar = "parser/typescript.pest"] pub struct TypeScriptParser;
fn parse_term(term: Pair<Rule>) -> Value {
let inner = term.into_inner().next().unwrap();
match inner.as_rule() {
Rule::Number => {
if let Ok(flt) = inner.as_str().parse::<f64>() {
Value::Number(flt)
} else {
Value::Undefined
}
}
Rule::Identifier => {
let names: Vec<String> = inner.as_str().split(".").map(|n| n.to_string()).collect();
Value::Identifier(names)
}
Rule::Call => {
Value::Undefined
}
_ => Value::Undefined,
}
}
fn parse_value(expr: Pair<Rule>) -> Arc<Value> {
let mut inner = expr.into_inner();
let term = inner.next().unwrap();
if let Some(op) = inner.next() {
let term1 = inner.next().unwrap();
Arc::new(Value::Expression {
left: Arc::new(parse_term(term)),
op: op.as_str().into(),
right: Arc::new(parse_term(term1)),
})
} else {
Arc::new(parse_term(term))
}
}
fn parse_statement(stmnt: Pair<Rule>) -> Option<Statement> {
let stmnt = stmnt.into_inner().next().unwrap();
match stmnt.as_rule() {
Rule::Const => {
let mut inner = stmnt.into_inner();
let name = inner.next().unwrap();
let expr = inner.next().unwrap();
Some(Statement::Const {
name: name.as_str().to_string(),
value: parse_value(expr),
})
}
Rule::Let => {
let mut inner = stmnt.into_inner();
let name = inner.next().unwrap();
let expr = inner.next().unwrap();
Some(Statement::Let {
name: name.as_str().to_string(),
value: parse_value(expr),
})
}
Rule::Assign => {
let mut inner = stmnt.into_inner();
let name = inner.next().unwrap();
let expr = inner.next().unwrap();
Some(Statement::Assign {
identifier: name.as_str().to_string(),
value: parse_value(expr),
})
}
Rule::If => {
let mut inner = stmnt.into_inner();
let expr = inner.next().unwrap();
let block = inner.next().unwrap();
let mut block_stmnts = Vec::new();
for stmnt in block.into_inner() {
if let Some(s) = parse_statement(stmnt) {
block_stmnts.push(s);
}
}
let mut else_block = Vec::new();
let mut elseifs = Vec::new();
for next in inner {
match next.as_rule() {
Rule::ElseIf => {
let mut inner = next.into_inner();
let expr = inner.next().unwrap();
let block = inner.next().unwrap();
let mut block_statements = Vec::new();
for stmnt in block.into_inner() {
if let Some(s) = parse_statement(stmnt) {
block_statements.push(s);
}
}
elseifs.push(ElseIf {
expr: parse_value(expr),
block: block_statements,
});
}
Rule::Else => {
let block = next.into_inner().next().unwrap();
for stmnt in block.into_inner() {
if let Some(s) = parse_statement(stmnt) {
else_block.push(s);
}
}
}
_ => {}
}
}
Some(Statement::If {
expr: parse_value(expr),
block: block_stmnts,
elseifs,
els: else_block,
})
}
Rule::Function => {
let mut inner = stmnt.into_inner();
let name = inner.next().unwrap();
let param_list = inner.next().unwrap();
let block = inner.next().unwrap();
let mut params = Vec::new();
for p in param_list.into_inner() {
let mut inner = p.into_inner();
let name = inner.next().unwrap();
params.push(Param {
name: name.as_str().to_string(),
kind: inner.next().map(|n| n.as_str()).into(),
});
}
let mut block_statements = Vec::new();
for stmnt in block.into_inner() {
if let Some(s) = parse_statement(stmnt) {
block_statements.push(s);
}
}
Some(Statement::Function {
name: name.as_str().to_string(),
params,
block: block_statements,
})
}
Rule::Call => {
let mut inner = stmnt.into_inner();
let identifier: Vec<String> = inner
.next()
.unwrap()
.as_str()
.split(".")
.map(|n| n.to_string())
.collect();
let params = inner
.next()
.unwrap()
.into_inner()
.map(|n| parse_value(n))
.collect();
Some(Statement::Call {
identifier,
params,
})
}
_ => None,
}
}
pub fn file<T: AsRef<Path>>(filename: T) -> Result<Module, Box<dyn Error>> {
let src = std::fs::read_to_string(filename)?;
source(&src)
}
pub fn source(source: &str) -> Result<Module, Box<dyn Error>> {
let mut module = Module::new();
let rules = TypeScriptParser::parse(Rule::Statements, &source)?
.next()
.unwrap();
for stmnt in rules.into_inner() {
match stmnt.as_rule() {
Rule::Import => {
let path = stmnt.into_inner().next().unwrap();
let name = path.as_str();
let clean_name = &name[1..name.len() - 1];
module.imports.push(Import::Normal {
path: clean_name.to_string(),
});
}
Rule::ImportFrom => {
let mut inner = stmnt.into_inner();
let namelist = inner.next().unwrap();
let mut names = Vec::new();
for n in namelist.into_inner() {
let mut inner = n.into_inner();
let name = inner.next().unwrap();
let name_str = name.as_str();
if let Some(alias) = inner.next() {
let alias_str = alias.as_str();
names.push(ImportAlias::Alias {
name: name_str.to_string(),
alias: alias_str.to_string(),
});
} else {
names.push(ImportAlias::None {
name: name_str.to_string(),
});
}
}
let file = inner.next().unwrap();
let filename = file.as_str();
module.imports.push(Import::From {
names,
path: filename[1..filename.len() - 1].to_string(),
})
}
Rule::Interface => {}
Rule::Class => {}
Rule::Statement => {
if let Some(s) = parse_statement(stmnt) {
module.statements.push(s);
}
}
_ => {}
}
}
Ok(module)
}