mirror of
https://github.com/azur1s/bobbylisp.git
synced 2024-10-16 02:37:40 -05:00
pipe operator
This commit is contained in:
parent
26dd4f53e1
commit
9c782a0a29
|
@ -3,9 +3,9 @@ use std::fmt::Display;
|
|||
use hir::{IR, IRKind, Value};
|
||||
|
||||
const MODULE_INCLUDES: [&str; 3] = [
|
||||
"<stdbool.h>",
|
||||
"<iostream>",
|
||||
"<string>",
|
||||
"<iostream>", // stdin `@read()` and stdout `@write()`
|
||||
"<stdbool.h>", // bool type
|
||||
"<string>", // string type
|
||||
];
|
||||
|
||||
pub struct Codegen {
|
||||
|
@ -28,47 +28,91 @@ impl Codegen {
|
|||
self.emit(format!("#include {}\n", module));
|
||||
}
|
||||
for ir in irs {
|
||||
self.emit(&self.gen_ir(&ir.kind));
|
||||
self.emit(&self.gen_ir(&ir.kind, true));
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_ir(&self, ir: &IRKind) -> String {
|
||||
fn gen_ir(&self, ir: &IRKind, should_gen_semicolon: bool) -> String {
|
||||
#[macro_export]
|
||||
macro_rules! semicolon { () => { if should_gen_semicolon { ";" } else { "" } }; }
|
||||
match ir {
|
||||
IRKind::Define { name, type_hint, value } => {
|
||||
format!("{} {} = {};\n", type_hint, name, self.gen_ir(value))
|
||||
format!(
|
||||
"{} {} = {}{}\n",
|
||||
type_hint,
|
||||
name,
|
||||
self.gen_ir(value, false),
|
||||
semicolon!()
|
||||
)
|
||||
},
|
||||
|
||||
IRKind::Call { name, args } => {
|
||||
format!("{}({});\n", name, args.iter().map(|arg| self.gen_ir(arg)).collect::<Vec<_>>().join(", "))
|
||||
format!(
|
||||
"{}({}){}",
|
||||
name,
|
||||
args
|
||||
.iter()
|
||||
.map(|arg| self.gen_ir(arg, false))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
.trim_end_matches(";\n"),
|
||||
semicolon!(),
|
||||
)
|
||||
},
|
||||
|
||||
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])) },
|
||||
"write" => { format!("std::cout << {};\n", self.gen_ir(&args[0], false)) },
|
||||
"read" => { format!("std::cin >> {};\n", self.gen_ir(&args[0], false)) },
|
||||
_ => 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}}\n", return_type_hint, name, args, self.gen_ir(body))
|
||||
let args = args
|
||||
.iter()
|
||||
.map(|arg| format!("{} {}", arg.1, arg.0))
|
||||
.collect::<Vec<_>>().
|
||||
join(", ");
|
||||
format!(
|
||||
"{} {}({}) {{\n{}\n}}\n",
|
||||
return_type_hint,
|
||||
name,
|
||||
args,
|
||||
self.gen_ir(body, false)
|
||||
)
|
||||
},
|
||||
|
||||
IRKind::Return { value } => {
|
||||
format!("return {};\n", self.gen_ir(value))
|
||||
format!(
|
||||
"return {};\n",
|
||||
self.gen_ir(value, false)
|
||||
)
|
||||
},
|
||||
|
||||
IRKind::Do { body } => {
|
||||
let mut out = String::new();
|
||||
for expr in body {
|
||||
out.push_str(&self.gen_ir(&expr));
|
||||
out.push_str(&self.gen_ir(&expr, true));
|
||||
}
|
||||
out
|
||||
},
|
||||
|
||||
IRKind::If { cond, body, else_body } => {
|
||||
format!("if ({}) {{\n{}}} else {{\n{}}}\n", self.gen_ir(cond), self.gen_ir(body), self.gen_ir(else_body))
|
||||
format!(
|
||||
"if ({}) {{\n{}}} else {{\n{}}}\n",
|
||||
self.gen_ir(cond, true),
|
||||
self.gen_ir(body, true),
|
||||
self.gen_ir(else_body, true),
|
||||
)
|
||||
},
|
||||
|
||||
IRKind::Unary { op, right } => {
|
||||
format!("{}{}", op, self.gen_ir(right))
|
||||
format!("{}{}", op, self.gen_ir(right, false))
|
||||
},
|
||||
|
||||
IRKind::Binary { left, op, right } => {
|
||||
format!("{} {} {}", self.gen_ir(left), op, self.gen_ir(right))
|
||||
format!("{} {} {}", self.gen_ir(left, false), op, self.gen_ir(right, false))
|
||||
},
|
||||
|
||||
IRKind::Value { value } => {
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
use std::ops::Range;
|
||||
use parser::Expr;
|
||||
|
||||
const INTRINSICS: [&str; 2] = ["write", "read"];
|
||||
const INTRINSICS: [&str; 2] = [
|
||||
"write",
|
||||
"read",
|
||||
];
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Value { Int(i64), Boolean(bool), String(String), Ident(String) }
|
||||
|
@ -97,6 +100,41 @@ pub fn expr_to_ir(expr: &Expr) -> (Option<IRKind>, Option<LoweringError>) {
|
|||
return (Some(ir_kind), None);
|
||||
},
|
||||
|
||||
Expr::Pipe { lhs, rhs } => {
|
||||
let lhs_ir = expr_to_ir(&lhs.0);
|
||||
if_err_return!(lhs_ir.1);
|
||||
|
||||
match &rhs.0 {
|
||||
call @ Expr::Call { name, args } => {
|
||||
let name = match &name.0 {
|
||||
Expr::Identifier(s) => s.clone(),
|
||||
// Should never happen because the parser should have caught this
|
||||
_ => return (None, Some(LoweringError { span: name.1.clone(), message: "Expected identifier".to_string(), note: None }))
|
||||
};
|
||||
|
||||
let call = expr_to_ir(&call);
|
||||
if_err_return!(call.1);
|
||||
|
||||
let mut largs = Vec::new();
|
||||
for arg in &args.0 {
|
||||
let arg = expr_to_ir(&arg.0);
|
||||
if_err_return!(arg.1);
|
||||
largs.push(arg.0.unwrap());
|
||||
}
|
||||
|
||||
let mut args = vec![lhs_ir.0.unwrap()];
|
||||
args.append(&mut largs);
|
||||
|
||||
return (Some(IRKind::Call { name, args }), None);
|
||||
},
|
||||
_ => return (None, Some(LoweringError {
|
||||
span: rhs.1.clone(),
|
||||
message: "Expected call".to_string(),
|
||||
note: None
|
||||
})),
|
||||
};
|
||||
},
|
||||
|
||||
Expr::Let { name, type_hint, value } => {
|
||||
let value = expr_to_ir(&value.0);
|
||||
if_err_return!(value.1);
|
||||
|
|
|
@ -15,6 +15,7 @@ pub enum Token {
|
|||
// Operators
|
||||
Plus, Minus, Multiply, Divide,
|
||||
Not, Equal, NotEqual, Less, Greater,
|
||||
Pipe,
|
||||
|
||||
// Symbols & Delimiters
|
||||
Assign,
|
||||
|
@ -50,6 +51,7 @@ impl std::fmt::Display for Token {
|
|||
Token::NotEqual => write!(f, "!="),
|
||||
Token::Less => write!(f, "<"),
|
||||
Token::Greater => write!(f, ">"),
|
||||
Token::Pipe => write!(f, "|>"),
|
||||
|
||||
Token::Assign => write!(f, "="),
|
||||
Token::Dot => write!(f, "."),
|
||||
|
@ -79,10 +81,15 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = Simple<char>> {
|
|||
just('-').to(Token::Minus),
|
||||
just('*').to(Token::Multiply),
|
||||
just('/').to(Token::Divide),
|
||||
|
||||
just('!').to(Token::Not),
|
||||
just("==").to(Token::Equal),
|
||||
|
||||
just("|>").to(Token::Pipe),
|
||||
|
||||
just('<').to(Token::Less),
|
||||
just('>').to(Token::Greater),
|
||||
|
||||
just('=').to(Token::Assign),
|
||||
just('.').to(Token::Dot),
|
||||
just(',').to(Token::Comma),
|
||||
|
|
|
@ -40,7 +40,7 @@ fn main() {
|
|||
match args.options {
|
||||
Options::Compile {
|
||||
input: file_name,
|
||||
ast: _print_ast,
|
||||
ast: print_ast,
|
||||
log: should_log,
|
||||
output,
|
||||
} => {
|
||||
|
@ -73,12 +73,16 @@ fn main() {
|
|||
logif!(0, format!("Parsing took {}ms", start.elapsed().as_millis()));
|
||||
}
|
||||
|
||||
if print_ast { log(0, format!("{:#?}", ast)); }
|
||||
|
||||
match ast {
|
||||
Some(ast) => {
|
||||
// Convert the AST to HIR
|
||||
let (ir, lowering_error) = ast_to_ir(ast);
|
||||
for err in lowering_error { diagnostics.add_lowering_error(err); }
|
||||
|
||||
if print_ast { log(0, format!("{:#?}", ir)); }
|
||||
|
||||
// Report lowering errors if any
|
||||
if diagnostics.has_error() {
|
||||
diagnostics.display(src);
|
||||
|
|
|
@ -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>>> },
|
||||
Pipe { lhs: Box<Spanned<Self>>, rhs: Box<Spanned<Self>> },
|
||||
Intrinsic { name: Box<Spanned<Self>>, args: Spanned<Vec<Spanned<Self>>> },
|
||||
|
||||
Let {
|
||||
|
@ -171,6 +172,21 @@ fn expr_parser() -> impl Parser<Token, Vec<Spanned<Expr>>, Error = Simple<Token>
|
|||
)
|
||||
});
|
||||
|
||||
let pipe = compare.clone()
|
||||
.then(
|
||||
just(Token::Pipe)
|
||||
.then(compare)
|
||||
.repeated())
|
||||
.foldl(|lhs, (_, rhs)| {
|
||||
(
|
||||
Expr::Pipe {
|
||||
lhs: Box::new(lhs),
|
||||
rhs: Box::new(rhs.clone()),
|
||||
},
|
||||
rhs.1,
|
||||
)
|
||||
});
|
||||
|
||||
let let_ = just(Token::KwLet)
|
||||
.ignore_then(identifier)
|
||||
.then_ignore(just(Token::Colon))
|
||||
|
@ -272,7 +288,7 @@ fn expr_parser() -> impl Parser<Token, Vec<Spanned<Expr>>, Error = Simple<Token>
|
|||
.or(return_)
|
||||
.or(do_block)
|
||||
.or(if_block)
|
||||
.or(compare)
|
||||
.or(pipe)
|
||||
}).labelled("expression");
|
||||
|
||||
expr
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
fun main: int = do
|
||||
@writesss("Hello, World!\n");
|
||||
@write("Hello, World!\n");
|
||||
return 69;
|
||||
end;
|
8
example/pipe.hz
Normal file
8
example/pipe.hz
Normal file
|
@ -0,0 +1,8 @@
|
|||
fun foo (xs: int): int = return xs + 1;
|
||||
fun bar (xs: int) (x: int): int = return xs - x;
|
||||
|
||||
fun main: int = do
|
||||
let res: int = foo(69)
|
||||
|> bar(1);
|
||||
@write(res);
|
||||
end;
|
Loading…
Reference in a new issue