1
1
Fork 0
mirror of https://github.com/azur1s/bobbylisp.git synced 2024-10-16 02:37:40 -05:00

Compare commits

...

3 commits

Author SHA1 Message Date
azur 4b5a61c060 rename mod 2023-03-01 02:26:23 +07:00
azur 5aa7add0cc remove unused use 2023-03-01 02:25:15 +07:00
azur e6bbbdd5bd parser again 2023-03-01 02:23:45 +07:00
9 changed files with 307 additions and 71 deletions

7
b.hlm
View file

@ -1,5 +1,4 @@
let foo : num = 1 in bar(foo) end println((\x: num -> x + 35)(34));
16---1*3/-f(16)+8%-2;
lambda (foo : num) -> unknown = bar(foo) a(b, c(d(e, f), g(h), i), j(k, l), m);
let x : t = e1 in e2 end

View file

@ -1,55 +1,59 @@
#![feature(trait_alias)] #![feature(trait_alias)]
pub mod parse; pub mod read;
pub mod trans; pub mod trans;
use parse::parse::lex; use read::parse::{lex, parse};
use trans::low::{translate_expr, translate_js};
fn main() { fn main() {
let input = r#" let path = std::env::args().nth(1).expect("No file path provided");
println((\x: int -> x + 1)(1)); let src = std::fs::read_to_string(path).expect("Failed to read file");
"#;
let tokens = lex(input.to_owned()); let (tokens, lex_errs) = lex(src.to_owned());
println!("{:?}", tokens);
// use parse::past::*; let parse_errs = if let Some(tokens) = tokens {
// use trans::ty::Type; let (ast, parse_errs) = parse(tokens, src.len());
// use trans::low::*;
// let exprs = vec![ if let Some(ast) = ast {
// PExpr::Call(Box::new(PExpr::Sym("println".to_string())), vec![ println!();
// PExpr::Str("Hello, world!".to_string()), println!("\x1b[90m───SOURCE─────────────────────────────────────────\x1b[0m");
// ]), println!("{src}");
// PExpr::Let { println!("\x1b[90m───PARSE TREE─────────────────────────────────────\x1b[0m");
// vars: vec![ for (e, _) in &ast {
// ("x".to_string(), Type::Num, PExpr::Num(1)), println!("{}", {
// ], let e = format!("{:?}", e);
// body: Box::new(PExpr::Sym("x".to_string())), if e.len() > 50 {
// }, format!("{}...", &e[..47])
// PExpr::Let { } else {
// vars: vec![ e
// ("x".to_string(), Type::Num, PExpr::Num(34)), }
// ("y".to_string(), Type::Num, PExpr::Num(35)), });
// ], }
// body: Box::new(PExpr::BinaryOp( println!("\x1b[90m───INTERNAL AST───────────────────────────────────\x1b[0m");
// PBinaryOp::Add, let nexprs = ast.into_iter().map(|(e, _)| translate_expr(e)).collect::<Vec<_>>();
// Box::new(PExpr::Sym("x".to_string())),
// Box::new(PExpr::Sym("y".to_string())), for expr in &nexprs {
// )), println!("{}", expr);
// }, }
// ]; println!("\x1b[90m───JS OUTPUT──────────────────────────────────────\x1b[0m");
let jsexprs = nexprs.into_iter().map(translate_js).collect::<Vec<_>>();
// let nexprs = exprs.into_iter().map(translate_expr).collect::<Vec<_>>();
for expr in &jsexprs {
// for expr in &nexprs { println!("{}", expr);
// println!("{}", expr); }
// } println!();
}
// println!("──────────────────────────────────────────────────");
parse_errs
// let jsexprs = nexprs.into_iter().map(translate_js).collect::<Vec<_>>(); } else {
Vec::new()
// for expr in &jsexprs { };
// println!("{}", expr);
// } if !lex_errs.is_empty() || !parse_errs.is_empty() {
lex_errs
.into_iter()
.map(|e| e.map(|c| c.to_string()))
.chain(parse_errs.into_iter().map(|e| e.map(|t| t.to_string())))
.for_each(|e| println!("{}", e));
}
} }

View file

@ -1,6 +1,8 @@
#![allow(clippy::type_complexity)] #![allow(clippy::type_complexity)]
use chumsky::{error, prelude::*, Stream}; use chumsky::{prelude::*, Stream};
use std::fmt::{Display, Formatter, Result as FmtResult}; use std::fmt::{Display, Formatter, Result as FmtResult};
use crate::trans::ty::Type;
use super::past::*; use super::past::*;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
@ -174,6 +176,32 @@ pub fn symbol_parser() -> impl P<String> {
.labelled("symbol") .labelled("symbol")
} }
pub fn type_parser() -> impl P<Type> {
recursive(|ty| {
let litty = symbol_parser().map(|s| match s.as_str() {
"num" => Type::Num,
"str" => Type::Str,
"bool" => Type::Bool,
"?" => Type::Unknown,
_ => Type::Sym(s),
});
let fun = just(Token::Open(Delim::Paren))
.ignore_then(
ty.clone()
.separated_by(just(Token::Comma))
)
.then_ignore(just(Token::Close(Delim::Paren)))
.then_ignore(just(Token::Arrow))
.then(ty)
.map(|(args, ret)| Type::Fun(args, Box::new(ret)));
litty
.or(fun)
.labelled("type")
})
}
pub fn nested_parser<'a, T: 'a>( pub fn nested_parser<'a, T: 'a>(
parser: impl P<T> + 'a, parser: impl P<T> + 'a,
delim: Delim, delim: Delim,
@ -202,3 +230,181 @@ pub fn nested_parser<'a, T: 'a>(
)) ))
.boxed() .boxed()
} }
pub fn expr_parser() -> impl P<Spanned<PExpr>> {
recursive(|expr: Recursive<Token, Spanned<PExpr>, Simple<Token>>| {
let lit = literal_parser().map(PExpr::Lit);
let sym = symbol_parser().map(PExpr::Sym);
let vec = nested_parser(
expr.clone()
.separated_by(just(Token::Comma))
.allow_trailing()
.map(Some),
Delim::Brack,
|_| None,
)
.map(|xs| match xs {
Some(xs) => PExpr::Vec(xs),
None => PExpr::Vec(Vec::new()),
})
.labelled("vector");
// (e)
let paren_expr = just(Token::Open(Delim::Paren))
.ignore_then(expr.clone())
.then_ignore(just(Token::Close(Delim::Paren)))
.map(|e| e.0)
.labelled("parenthesized expression");
// \[sym : type]* -> expr
let lam = just(Token::Lambda)
.ignore_then(
(
symbol_parser()
.then_ignore(just(Token::Colon))
.then(type_parser())
)
.repeated()
)
.then_ignore(just(Token::Arrow))
.then(expr.clone())
.map(|(args, body)| PExpr::Lambda {
args,
body: Box::new(body),
})
.labelled("lambda");
let atom = lit
.or(sym)
.or(vec)
.or(paren_expr)
.or(lam)
.map_with_span(|e, s| (e, s))
.boxed()
.labelled("atom");
// e(e*)
let call = atom
.then(
nested_parser(
expr.clone()
.separated_by(just(Token::Comma))
.allow_trailing()
.map(Some),
Delim::Paren,
|_| None,
)
.or_not(),
)
.map_with_span(|(f, args), s| match args {
Some(Some(args)) => (PExpr::Call(Box::new(f), args), s),
Some(None) => (PExpr::Error, s),
None => f,
});
// op e
let unary = choice((
just(Token::Sub).to(PUnaryOp::Neg),
just(Token::Not).to(PUnaryOp::Not),
))
.map_with_span(|op, s| (op, s))
.repeated()
.then(call)
.foldr(|op, expr| {
let s = op.1.start()..expr.1.end();
(PExpr::Unary(op, Box::new(expr)), s)
})
.boxed();
let product = unary
.clone()
.then(
choice((
just(Token::Mul).to(PBinaryOp::Mul),
just(Token::Div).to(PBinaryOp::Div),
just(Token::Mod).to(PBinaryOp::Mod),
))
.map_with_span(|op, s| (op, s))
.then(unary)
.repeated(),
)
.foldl(|lhs, (op, rhs)| {
let s = lhs.1.start()..rhs.1.end();
(PExpr::Binary(op, Box::new(lhs), Box::new(rhs)), s)
})
.boxed();
let sum = product
.clone()
.then(
choice((
just(Token::Add).to(PBinaryOp::Add),
just(Token::Sub).to(PBinaryOp::Sub),
))
.map_with_span(|op, s| (op, s))
.then(product)
.repeated(),
)
.foldl(|lhs, (op, rhs)| {
let s = lhs.1.start()..rhs.1.end();
(PExpr::Binary(op, Box::new(lhs), Box::new(rhs)), s)
})
.boxed();
let comparison = sum
.clone()
.then(
choice((
just(Token::Eq).to(PBinaryOp::Eq),
just(Token::Neq).to(PBinaryOp::Neq),
just(Token::Lt).to(PBinaryOp::Lt),
just(Token::Lte).to(PBinaryOp::Lte),
just(Token::Gt).to(PBinaryOp::Gt),
just(Token::Gte).to(PBinaryOp::Gte),
))
.map_with_span(|op, s| (op, s))
.then(sum)
.repeated(),
)
.foldl(|lhs, (op, rhs)| {
let s = lhs.1.start()..rhs.1.end();
(PExpr::Binary(op, Box::new(lhs), Box::new(rhs)), s)
})
.boxed();
comparison
.clone()
.then(
choice((
just(Token::And).to(PBinaryOp::And),
just(Token::Or).to(PBinaryOp::Or),
))
.map_with_span(|op, s| (op, s))
.then(comparison)
.repeated(),
)
.foldl(|lhs, (op, rhs)| {
let s = lhs.1.start()..rhs.1.end();
(PExpr::Binary(op, Box::new(lhs), Box::new(rhs)), s)
})
.boxed()
})
}
pub fn exprs_parser() -> impl P<Vec<Spanned<PExpr>>> {
expr_parser()
.then_ignore(just(Token::Semicolon))
.repeated()
}
pub fn parse(
tokens: Vec<Spanned<Token>>,
len: usize,
) -> (Option<Vec<Spanned<PExpr>>>, Vec<Simple<Token>>) {
let (ast, parse_error) = exprs_parser()
.then_ignore(end())
.parse_recovery(Stream::from_iter(len..len + 1, tokens.into_iter()));
(ast, parse_error)
}

View file

@ -1,6 +1,7 @@
use std::fmt::{Display, Formatter, Result as FmtResult};
use crate::trans::ty::*; use crate::trans::ty::*;
use super::parse::Spanned;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum PUnaryOp { pub enum PUnaryOp {
Neg, Neg,
@ -20,21 +21,22 @@ pub enum PLiteral { Num(i64), Str(String), Bool(bool) }
/// Enum to represent a parsed expression /// Enum to represent a parsed expression
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum PExpr { pub enum PExpr {
Error,
Lit(PLiteral), Lit(PLiteral),
Sym(String), Sym(String),
Vec(Vec<Spanned<Self>>),
Vec(Vec<Self>), Unary(Spanned<PUnaryOp>, Box<Spanned<Self>>),
Binary(Spanned<PBinaryOp>, Box<Spanned<Self>>, Box<Spanned<Self>>),
UnaryOp(PUnaryOp, Box<Self>), Call(Box<Spanned<Self>>, Vec<Spanned<Self>>),
BinaryOp(PBinaryOp, Box<Self>, Box<Self>),
Call(Box<Self>, Vec<Self>),
Lambda { Lambda {
args: Vec<(String, Type)>, args: Vec<(String, Type)>,
body: Box<Self>, body: Box<Spanned<Self>>,
}, },
Let { Let {
vars: Vec<(String, Type, Self)>, vars: Vec<(String, Type, Self)>,
body: Box<Self>, body: Box<Self>,
} },
} }

View file

@ -24,6 +24,7 @@ pub enum Literal {
pub enum Expr { pub enum Expr {
Lit(Literal), Lit(Literal),
Sym(String), Sym(String),
Vec(Vec<Self>),
UnaryOp(UnaryOp, Box<Self>), UnaryOp(UnaryOp, Box<Self>),
BinaryOp(BinaryOp, Box<Self>, Box<Self>), BinaryOp(BinaryOp, Box<Self>, Box<Self>),
@ -44,9 +45,17 @@ impl Display for Expr {
Literal::Bool(b) => write!(f, "{}", b), Literal::Bool(b) => write!(f, "{}", b),
}, },
Expr::Sym(s) => write!(f, "{}", s), Expr::Sym(s) => write!(f, "{}", s),
Expr::Vec(v) => {
write!(f, "[")?;
for (i, e) in v.iter().enumerate() {
if i > 0 { write!(f, " ")?; }
write!(f, "{}", e)?;
}
write!(f, "]")
},
Expr::UnaryOp(op, e) => write!(f, "({:?} {})", op, e), Expr::UnaryOp(op, e) => write!(f, "({} {})", format!("{:?}", op).to_lowercase(), e),
Expr::BinaryOp(op, e1, e2) => write!(f, "({:?} {} {})", op, e1, e2), Expr::BinaryOp(op, e1, e2) => write!(f, "({} {} {})", format!("{:?}", op).to_lowercase(), e1, e2),
Expr::Call(c, args) => { Expr::Call(c, args) => {
write!(f, "({}", c)?; write!(f, "({}", c)?;

View file

@ -9,6 +9,7 @@ pub enum JSLiteral { Num(i64), Str(String), Bool(bool) }
pub enum JSExpr { pub enum JSExpr {
Lit(JSLiteral), Lit(JSLiteral),
Sym(String), Sym(String),
Array(Vec<Self>),
Op(&'static str, Box<Self>, Option<Box<Self>>), Op(&'static str, Box<Self>, Option<Box<Self>>),
@ -29,6 +30,14 @@ impl Display for JSExpr {
JSLiteral::Bool(b) => write!(f, "{}", b), JSLiteral::Bool(b) => write!(f, "{}", b),
}, },
JSExpr::Sym(s) => write!(f, "{}", s), JSExpr::Sym(s) => write!(f, "{}", s),
JSExpr::Array(v) => {
write!(f, "[")?;
for (i, e) in v.iter().enumerate() {
if i > 0 { write!(f, ", ")?; }
write!(f, "{}", e)?;
}
write!(f, "]")
},
JSExpr::Op(op, lhs, rhs) => { JSExpr::Op(op, lhs, rhs) => {
match rhs { match rhs {

View file

@ -1,4 +1,4 @@
use crate::parse::past::{PExpr, PLiteral, PBinaryOp, PUnaryOp}; use crate::read::past::{PExpr, PLiteral, PBinaryOp, PUnaryOp};
use super::{ use super::{
ast::{Expr, Literal, BinaryOp, UnaryOp}, ast::{Expr, Literal, BinaryOp, UnaryOp},
js::{JSExpr, JSLiteral}, js::{JSExpr, JSLiteral},
@ -6,18 +6,21 @@ use super::{
pub fn translate_expr(expr: PExpr) -> Expr { pub fn translate_expr(expr: PExpr) -> Expr {
match expr { match expr {
PExpr::Error => panic!("Error in expression!"),
PExpr::Lit(l) => Expr::Lit(match l { PExpr::Lit(l) => Expr::Lit(match l {
PLiteral::Num(n) => Literal::Num(n), PLiteral::Num(n) => Literal::Num(n),
PLiteral::Str(s) => Literal::Str(s), PLiteral::Str(s) => Literal::Str(s),
PLiteral::Bool(b) => Literal::Bool(b), PLiteral::Bool(b) => Literal::Bool(b),
}), }),
PExpr::Sym(s) => Expr::Sym(s), PExpr::Sym(s) => Expr::Sym(s),
PExpr::Vec(v) => Expr::Vec(v.into_iter().map(|e| translate_expr(e.0)).collect()),
PExpr::UnaryOp(op, e) => Expr::UnaryOp(match op { PExpr::Unary(op, e) => Expr::UnaryOp(match op.0 {
PUnaryOp::Neg => UnaryOp::Neg, PUnaryOp::Neg => UnaryOp::Neg,
PUnaryOp::Not => UnaryOp::Not, PUnaryOp::Not => UnaryOp::Not,
}, Box::new(translate_expr(*e))), }, Box::new(translate_expr((*e).0))),
PExpr::BinaryOp(op, e1, e2) => Expr::BinaryOp( PExpr::Binary((op, _), e1, e2) => Expr::BinaryOp(
match op { match op {
PBinaryOp::Add => BinaryOp::Add, PBinaryOp::Add => BinaryOp::Add,
PBinaryOp::Sub => BinaryOp::Sub, PBinaryOp::Sub => BinaryOp::Sub,
@ -36,33 +39,34 @@ pub fn translate_expr(expr: PExpr) -> Expr {
PBinaryOp::And => BinaryOp::And, PBinaryOp::And => BinaryOp::And,
PBinaryOp::Or => BinaryOp::Or, PBinaryOp::Or => BinaryOp::Or,
}, },
Box::new(translate_expr(*e1)), Box::new(translate_expr((*e1).0)),
Box::new(translate_expr(*e2)), Box::new(translate_expr((*e2).0)),
), ),
PExpr::Call(f, args) => Expr::Call( PExpr::Call(f, args) => Expr::Call(
Box::new(translate_expr(*f)), Box::new(translate_expr((*f).0)),
args.into_iter().map(translate_expr).collect(), args.into_iter().map(|a| translate_expr(a.0)).collect(),
), ),
PExpr::Lambda { args, body } => Expr::Lambda { PExpr::Lambda { args, body } => Expr::Lambda {
args, args,
body: Box::new(translate_expr(*body)), body: Box::new(translate_expr((*body).0)),
}, },
PExpr::Let { vars, body } => { PExpr::Let { vars, body } => {
let mut expr = *body; // The expression we're building up let mut expr: Expr = translate_expr(*body); // The expression we're building up
for (name, ty, val) in vars.into_iter().rev() { // Reverse so we can build up the lambda for (name, ty, val) in vars.into_iter().rev() { // Reverse so we can build up the lambda
// e.g.: let x : t = e1 in e2 end => (lambda (x : t) = e2)(e1) // e.g.: let x : t = e1 in e2 end => (lambda (x : t) = e2)(e1)
// Build up the lambda // Build up the lambda
expr = PExpr::Lambda { expr = Expr::Lambda {
args: vec![(name, ty)], args: vec![(name, ty)],
body: Box::new(expr), body: Box::new(expr),
}; };
// Call the lambda with the value // Call the lambda with the value
expr = PExpr::Call(Box::new(expr), vec![val]); let val = translate_expr(val);
expr = Expr::Call(Box::new(expr), vec![val]);
} }
translate_expr(expr) expr
} }
} }
} }
@ -75,6 +79,7 @@ pub fn translate_js(expr: Expr) -> JSExpr {
Literal::Bool(b) => JSExpr::Lit(JSLiteral::Bool(b)), Literal::Bool(b) => JSExpr::Lit(JSLiteral::Bool(b)),
}, },
Expr::Sym(s) => JSExpr::Sym(s), Expr::Sym(s) => JSExpr::Sym(s),
Expr::Vec(v) => JSExpr::Array(v.into_iter().map(translate_js).collect()),
Expr::UnaryOp(op, e) => JSExpr::Op(match op { Expr::UnaryOp(op, e) => JSExpr::Op(match op {
UnaryOp::Neg => "-", UnaryOp::Neg => "-",

View file

@ -3,6 +3,7 @@ use std::fmt::{Display, Formatter, Result as FmtResult};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Type { pub enum Type {
Num, Str, Bool, Num, Str, Bool,
Sym(String),
Fun(Vec<Self>, Box<Self>), Fun(Vec<Self>, Box<Self>),
Unknown, Unknown,
} }
@ -13,6 +14,7 @@ impl Display for Type {
Type::Num => write!(f, "num"), Type::Num => write!(f, "num"),
Type::Str => write!(f, "str"), Type::Str => write!(f, "str"),
Type::Bool => write!(f, "bool"), Type::Bool => write!(f, "bool"),
Type::Sym(s) => write!(f, "{}", s),
Type::Fun(args, ret) => { Type::Fun(args, ret) => {
write!(f, "(")?; write!(f, "(")?;
for (i, arg) in args.iter().enumerate() { for (i, arg) in args.iter().enumerate() {