mirror of
https://github.com/azur1s/bobbylisp.git
synced 2024-10-16 02:37:40 -05:00
Compare commits
3 commits
1079d53f05
...
04e35046b2
Author | SHA1 | Date | |
---|---|---|---|
Natapat Samutpong | 04e35046b2 | ||
Natapat Samutpong | cd196f8619 | ||
Natapat Samutpong | 0ee36feecb |
|
@ -1,6 +1,13 @@
|
|||
# Hades
|
||||
Programming language that compiles to C++!
|
||||
|
||||
```sml
|
||||
fun main: int = do
|
||||
@write("Hello, World!\n");
|
||||
return 0;
|
||||
end;
|
||||
```
|
||||
|
||||
Note: Everything in this project can be changed at anytime! (I'm still finding out what work best for lots of thing) if you have an idea, feel free to create an issues about it, or even create a PR! (I'd be very happy)
|
||||
|
||||
# Prerequistie
|
||||
|
|
|
@ -29,19 +29,22 @@ impl Codegen {
|
|||
self.emit(&self.gen_ir(&ir.kind));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn gen_ir(&self, ir: &IRKind) -> String {
|
||||
match ir {
|
||||
IRKind::Define { name, type_hint, value } => {
|
||||
format!("{} {} = {};\n", type_hint, name, self.gen_ir(value))
|
||||
},
|
||||
IRKind::Call { name, args } => {
|
||||
format!("{}({});\n", name, args.iter().map(|arg| self.gen_ir(arg)).collect::<Vec<_>>().join(", "))
|
||||
},
|
||||
IRKind::Intrinsic { name, args } => {
|
||||
match name.as_str() {
|
||||
"write" => { format!("std::cout << {};\n", self.gen_ir(&args[0])) },
|
||||
"read" => { format!("std::cin >> {};\n", self.gen_ir(&args[0])) },
|
||||
_ => format!("{}({});\n", name, args.iter().map(|arg| self.gen_ir(arg)).collect::<Vec<_>>().join(", ")),
|
||||
_ => unreachable!(format!("Unknown intrinsic: {}", name)) // Shoul be handled by lowering
|
||||
}
|
||||
},
|
||||
}
|
||||
IRKind::Fun { name, return_type_hint, args, body } => {
|
||||
let args = args.iter().map(|arg| format!("{} {}", arg.1, arg.0)).collect::<Vec<_>>().join(", ");
|
||||
format!("{} {}({}) {{\n{}}}\n", return_type_hint, name, args, self.gen_ir(body))
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use std::ops::Range;
|
||||
use parser::Expr;
|
||||
|
||||
const INTRINSICS: [&str; 2] = ["write", "read"];
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Value { Int(i64), Boolean(bool), String(String), Ident(String) }
|
||||
|
||||
|
@ -9,6 +11,7 @@ pub enum IRKind {
|
|||
Define { name: String, type_hint: String, value: Box<Self> },
|
||||
Fun { name: String, return_type_hint: String, args: Vec<(String, String)>, body: Box<Self> },
|
||||
Call { name: String, args: Vec<Self> },
|
||||
Intrinsic { name: String, args: Vec<Self> },
|
||||
Do { body: Vec<Self> },
|
||||
If { cond: Box<Self>, body: Box<Self>, else_body: Box<Self> },
|
||||
Value { value: Value },
|
||||
|
@ -63,7 +66,12 @@ pub fn expr_to_ir(expr: &Expr) -> (Option<IRKind>, Option<LoweringError>) {
|
|||
},
|
||||
Expr::Call { name, args } => {
|
||||
let name = match &name.0 {
|
||||
Expr::Identifier(s) => s.clone(),
|
||||
Expr::Identifier(s) => {
|
||||
if INTRINSICS.contains(&s.as_str()) { s.clone() }
|
||||
else {
|
||||
return (None, Some(LoweringError { span: name.1.clone(), message: format!("Unknown intrinsic: {}", s) }));
|
||||
}
|
||||
}
|
||||
// Should never happen because the parser should have caught this
|
||||
_ => return (None, Some(LoweringError { span: name.1.clone(), message: "Expected identifier".to_string() }))
|
||||
};
|
||||
|
@ -82,6 +90,20 @@ pub fn expr_to_ir(expr: &Expr) -> (Option<IRKind>, Option<LoweringError>) {
|
|||
let ir_kind = IRKind::Call { name, args: largs };
|
||||
return (Some(ir_kind), None);
|
||||
},
|
||||
Expr::Intrinsic { name, args } => {
|
||||
let name = match &name.0 {
|
||||
Expr::Identifier(s) => s.clone(),
|
||||
_ => return (None, Some(LoweringError { span: name.1.clone(), message: "Expected identifier".to_string() }))
|
||||
};
|
||||
let mut largs = Vec::new();
|
||||
for arg in &args.0 {
|
||||
let arg = expr_to_ir(&arg.0);
|
||||
if let Some(err) = arg.1 { return (None, Some(err)); }
|
||||
else { largs.push(arg.0.unwrap()); }
|
||||
}
|
||||
let ir_kind = IRKind::Intrinsic { name, args: largs };
|
||||
return (Some(ir_kind), None);
|
||||
},
|
||||
Expr::Fun { name, type_hint, args, body } => {
|
||||
// Iterate each argument and give it a type hint
|
||||
let args = args.0.iter().map(|arg| (arg.0.0.clone(), gen_type_hint(&arg.1.0))).collect::<Vec<_>>();
|
||||
|
|
|
@ -15,12 +15,13 @@ pub enum Token {
|
|||
// Operators
|
||||
Plus, Minus, Multiply, Divide,
|
||||
Not, Equal, NotEqual, Less, Greater,
|
||||
|
||||
|
||||
// Symbols & Delimiters
|
||||
Assign,
|
||||
Dot, Comma,
|
||||
Colon, SemiColon,
|
||||
OpenParen, CloseParen,
|
||||
At,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Token {
|
||||
|
@ -49,7 +50,7 @@ impl std::fmt::Display for Token {
|
|||
Token::NotEqual => write!(f, "!="),
|
||||
Token::Less => write!(f, "<"),
|
||||
Token::Greater => write!(f, ">"),
|
||||
|
||||
|
||||
Token::Assign => write!(f, "="),
|
||||
Token::Dot => write!(f, "."),
|
||||
Token::Comma => write!(f, ","),
|
||||
|
@ -57,6 +58,7 @@ impl std::fmt::Display for Token {
|
|||
Token::SemiColon => write!(f, ";"),
|
||||
Token::OpenParen => write!(f, "("),
|
||||
Token::CloseParen => write!(f, ")"),
|
||||
Token::At => write!(f, "@"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,6 +90,7 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = Simple<char>> {
|
|||
just(';').to(Token::SemiColon),
|
||||
just('(').to(Token::OpenParen),
|
||||
just(')').to(Token::CloseParen),
|
||||
just('@').to(Token::At),
|
||||
));
|
||||
|
||||
let keyword = text::ident().map(|s: String| match s.as_str() {
|
||||
|
|
|
@ -11,6 +11,7 @@ pub enum Expr {
|
|||
Unary { op: String, rhs: Box<Spanned<Self>> },
|
||||
Binary { lhs: Box<Spanned<Self>>, op: String, rhs: Box<Spanned<Self>> },
|
||||
Call { name: Box<Spanned<Self>>, args: Spanned<Vec<Spanned<Self>>> },
|
||||
Intrinsic { name: Box<Spanned<Self>>, args: Spanned<Vec<Spanned<Self>>> },
|
||||
|
||||
Let {
|
||||
name: String,
|
||||
|
@ -60,7 +61,7 @@ fn expr_parser() -> impl Parser<Token, Vec<Spanned<Expr>>, Error = Simple<Token>
|
|||
// .delimited_by(just(Token::OpenParen), just(Token::CloseParen)))
|
||||
.labelled("atom");
|
||||
|
||||
let call = atom
|
||||
let call = atom.clone()
|
||||
.then(
|
||||
args.clone()
|
||||
.delimited_by(
|
||||
|
@ -79,11 +80,31 @@ fn expr_parser() -> impl Parser<Token, Vec<Spanned<Expr>>, Error = Simple<Token>
|
|||
)
|
||||
});
|
||||
|
||||
let intrinsic = just(Token::At)
|
||||
.ignore_then(atom)
|
||||
.then(
|
||||
args.clone()
|
||||
.delimited_by(
|
||||
just(Token::OpenParen),
|
||||
just(Token::CloseParen),
|
||||
)
|
||||
.repeated()
|
||||
)
|
||||
.foldl(|name, args| {
|
||||
(
|
||||
Expr::Intrinsic {
|
||||
name: Box::new(name.clone()),
|
||||
args: (args, name.1.clone()),
|
||||
},
|
||||
name.1,
|
||||
)
|
||||
});
|
||||
|
||||
let unary = choice((
|
||||
just(Token::Plus),
|
||||
just(Token::Minus)))
|
||||
.repeated()
|
||||
.then(call)
|
||||
.then(call.or(intrinsic))
|
||||
.foldr(|op, rhs| {
|
||||
(
|
||||
Expr::Unary {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
fun main: int = do
|
||||
write("Hello, World!\n");
|
||||
@write("Hello, World!\n");
|
||||
return 0;
|
||||
end;
|
Loading…
Reference in a new issue