mirror of
https://github.com/azur1s/bobbylisp.git
synced 2024-10-16 02:37:40 -05:00
intrinsic
This commit is contained in:
parent
1079d53f05
commit
0ee36feecb
|
@ -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<_>>();
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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