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
Natapat Samutpong 04e35046b2 😱 trailing whitespace 2022-03-12 08:41:51 +07:00
Natapat Samutpong cd196f8619 Update README.md 2022-03-12 08:39:37 +07:00
Natapat Samutpong 0ee36feecb intrinsic 2022-03-12 08:37:47 +07:00
6 changed files with 65 additions and 9 deletions

View file

@ -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

View file

@ -29,19 +29,22 @@ impl Codegen {
self.emit(&self.gen_ir(&ir.kind)); self.emit(&self.gen_ir(&ir.kind));
} }
} }
fn gen_ir(&self, ir: &IRKind) -> String { fn gen_ir(&self, ir: &IRKind) -> String {
match ir { match ir {
IRKind::Define { name, type_hint, value } => { IRKind::Define { name, type_hint, value } => {
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))

View file

@ -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<_>>();

View file

@ -15,12 +15,13 @@ pub enum Token {
// Operators // Operators
Plus, Minus, Multiply, Divide, Plus, Minus, Multiply, Divide,
Not, Equal, NotEqual, Less, Greater, Not, Equal, NotEqual, Less, Greater,
// Symbols & Delimiters // Symbols & Delimiters
Assign, Assign,
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 {
@ -49,7 +50,7 @@ impl std::fmt::Display for Token {
Token::NotEqual => write!(f, "!="), Token::NotEqual => write!(f, "!="),
Token::Less => write!(f, "<"), Token::Less => write!(f, "<"),
Token::Greater => write!(f, ">"), Token::Greater => write!(f, ">"),
Token::Assign => write!(f, "="), Token::Assign => write!(f, "="),
Token::Dot => write!(f, "."), Token::Dot => write!(f, "."),
Token::Comma => write!(f, ","), Token::Comma => write!(f, ","),
@ -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() {

View file

@ -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 {

View file

@ -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;