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))
},
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))

View file

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

View file

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

View file

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

View file

@ -1,4 +1,4 @@
fun main: int = do
write("Hello, World!\n");
@write("Hello, World!\n");
return 0;
end;