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

pipe operator

This commit is contained in:
Natapat Samutpong 2022-03-13 05:00:42 +07:00
parent 26dd4f53e1
commit 9c782a0a29
7 changed files with 138 additions and 21 deletions

View file

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

View file

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

View file

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

View file

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

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

View file

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