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
|
# Hades
|
||||||
Programming language that compiles to C++!
|
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)
|
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
|
# Prerequistie
|
||||||
|
|
|
@ -36,12 +36,15 @@ impl Codegen {
|
||||||
format!("{} {} = {};\n", type_hint, name, self.gen_ir(value))
|
format!("{} {} = {};\n", type_hint, name, self.gen_ir(value))
|
||||||
},
|
},
|
||||||
IRKind::Call { name, args } => {
|
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() {
|
match name.as_str() {
|
||||||
"write" => { format!("std::cout << {};\n", self.gen_ir(&args[0])) },
|
"write" => { format!("std::cout << {};\n", self.gen_ir(&args[0])) },
|
||||||
"read" => { format!("std::cin >> {};\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 } => {
|
IRKind::Fun { name, return_type_hint, args, body } => {
|
||||||
let args = args.iter().map(|arg| format!("{} {}", arg.1, arg.0)).collect::<Vec<_>>().join(", ");
|
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))
|
format!("{} {}({}) {{\n{}}}\n", return_type_hint, name, args, self.gen_ir(body))
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use parser::Expr;
|
use parser::Expr;
|
||||||
|
|
||||||
|
const INTRINSICS: [&str; 2] = ["write", "read"];
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Value { Int(i64), Boolean(bool), String(String), Ident(String) }
|
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> },
|
Define { name: String, type_hint: String, value: Box<Self> },
|
||||||
Fun { name: String, return_type_hint: String, args: Vec<(String, String)>, body: Box<Self> },
|
Fun { name: String, return_type_hint: String, args: Vec<(String, String)>, body: Box<Self> },
|
||||||
Call { name: String, args: Vec<Self> },
|
Call { name: String, args: Vec<Self> },
|
||||||
|
Intrinsic { name: String, args: Vec<Self> },
|
||||||
Do { body: Vec<Self> },
|
Do { body: Vec<Self> },
|
||||||
If { cond: Box<Self>, body: Box<Self>, else_body: Box<Self> },
|
If { cond: Box<Self>, body: Box<Self>, else_body: Box<Self> },
|
||||||
Value { value: Value },
|
Value { value: Value },
|
||||||
|
@ -63,7 +66,12 @@ pub fn expr_to_ir(expr: &Expr) -> (Option<IRKind>, Option<LoweringError>) {
|
||||||
},
|
},
|
||||||
Expr::Call { name, args } => {
|
Expr::Call { name, args } => {
|
||||||
let name = match &name.0 {
|
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
|
// Should never happen because the parser should have caught this
|
||||||
_ => return (None, Some(LoweringError { span: name.1.clone(), message: "Expected identifier".to_string() }))
|
_ => 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 };
|
let ir_kind = IRKind::Call { name, args: largs };
|
||||||
return (Some(ir_kind), None);
|
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 } => {
|
Expr::Fun { name, type_hint, args, body } => {
|
||||||
// Iterate each argument and give it a type hint
|
// 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<_>>();
|
let args = args.0.iter().map(|arg| (arg.0.0.clone(), gen_type_hint(&arg.1.0))).collect::<Vec<_>>();
|
||||||
|
|
|
@ -21,6 +21,7 @@ pub enum Token {
|
||||||
Dot, Comma,
|
Dot, Comma,
|
||||||
Colon, SemiColon,
|
Colon, SemiColon,
|
||||||
OpenParen, CloseParen,
|
OpenParen, CloseParen,
|
||||||
|
At,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for Token {
|
impl std::fmt::Display for Token {
|
||||||
|
@ -57,6 +58,7 @@ impl std::fmt::Display for Token {
|
||||||
Token::SemiColon => write!(f, ";"),
|
Token::SemiColon => write!(f, ";"),
|
||||||
Token::OpenParen => write!(f, "("),
|
Token::OpenParen => write!(f, "("),
|
||||||
Token::CloseParen => 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::SemiColon),
|
||||||
just('(').to(Token::OpenParen),
|
just('(').to(Token::OpenParen),
|
||||||
just(')').to(Token::CloseParen),
|
just(')').to(Token::CloseParen),
|
||||||
|
just('@').to(Token::At),
|
||||||
));
|
));
|
||||||
|
|
||||||
let keyword = text::ident().map(|s: String| match s.as_str() {
|
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>> },
|
Unary { op: String, rhs: Box<Spanned<Self>> },
|
||||||
Binary { lhs: Box<Spanned<Self>>, 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>>> },
|
Call { name: Box<Spanned<Self>>, args: Spanned<Vec<Spanned<Self>>> },
|
||||||
|
Intrinsic { name: Box<Spanned<Self>>, args: Spanned<Vec<Spanned<Self>>> },
|
||||||
|
|
||||||
Let {
|
Let {
|
||||||
name: String,
|
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)))
|
// .delimited_by(just(Token::OpenParen), just(Token::CloseParen)))
|
||||||
.labelled("atom");
|
.labelled("atom");
|
||||||
|
|
||||||
let call = atom
|
let call = atom.clone()
|
||||||
.then(
|
.then(
|
||||||
args.clone()
|
args.clone()
|
||||||
.delimited_by(
|
.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((
|
let unary = choice((
|
||||||
just(Token::Plus),
|
just(Token::Plus),
|
||||||
just(Token::Minus)))
|
just(Token::Minus)))
|
||||||
.repeated()
|
.repeated()
|
||||||
.then(call)
|
.then(call.or(intrinsic))
|
||||||
.foldr(|op, rhs| {
|
.foldr(|op, rhs| {
|
||||||
(
|
(
|
||||||
Expr::Unary {
|
Expr::Unary {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
fun main: int = do
|
fun main: int = do
|
||||||
write("Hello, World!\n");
|
@write("Hello, World!\n");
|
||||||
return 0;
|
return 0;
|
||||||
end;
|
end;
|
Loading…
Reference in a new issue