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

intrinsic

This commit is contained in:
Natapat Samutpong 2022-03-12 08:37:47 +07:00
parent 1079d53f05
commit 0ee36feecb
5 changed files with 57 additions and 8 deletions

View file

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

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

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

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;