feat(achilles): Implement a Unit type
Add support for a zero-sized Unit type. This requires some special at the codegen level because LLVM (unsurprisingly) only allows Void types in function return position - to make that a little easier to handle there's a new pass that strips any unit-only expressions and pulls unit-only function arguments up to new `let` bindings, so we never have to actually pass around unit values. Change-Id: I0fc18a516821f2d69172c42a6a5d246b23471e38 Reviewed-on: https://cl.tvl.fyi/c/depot/+/2695 Reviewed-by: glittershark <grfn@gws.fyi> Tested-by: BuildkiteCI
This commit is contained in:
parent
db62866d82
commit
8e13b1303a
16 changed files with 447 additions and 88 deletions
|
|
@ -186,7 +186,9 @@ named!(string(&str) -> Literal, preceded!(
|
|||
)
|
||||
));
|
||||
|
||||
named!(literal(&str) -> Literal, alt!(int | bool_ | string));
|
||||
named!(unit(&str) -> Literal, map!(complete!(tag!("()")), |_| Literal::Unit));
|
||||
|
||||
named!(literal(&str) -> Literal, alt!(int | bool_ | string | unit));
|
||||
|
||||
named!(literal_expr(&str) -> Expr, map!(literal, Expr::Literal));
|
||||
|
||||
|
|
@ -270,7 +272,6 @@ named!(funcref(&str) -> Expr, alt!(
|
|||
|
||||
named!(no_arg_call(&str) -> Expr, do_parse!(
|
||||
fun: funcref
|
||||
>> multispace0
|
||||
>> complete!(tag!("()"))
|
||||
>> (Expr::Call {
|
||||
fun: Box::new(fun),
|
||||
|
|
@ -431,6 +432,11 @@ pub(crate) mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unit() {
|
||||
assert_eq!(test_parse!(expr, "()"), Expr::Literal(Literal::Unit));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bools() {
|
||||
assert_eq!(
|
||||
|
|
@ -515,6 +521,18 @@ pub(crate) mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unit_call() {
|
||||
let res = test_parse!(expr, "f ()");
|
||||
assert_eq!(
|
||||
res,
|
||||
Expr::Call {
|
||||
fun: ident_expr("f"),
|
||||
args: vec![Expr::Literal(Literal::Unit)]
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_with_args() {
|
||||
let res = test_parse!(expr, "f x 1");
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use nom::character::complete::{multispace0, multispace1};
|
||||
use nom::error::{ErrorKind, ParseError};
|
||||
use nom::{alt, char, complete, do_parse, many0, named, separated_list0, tag, terminated};
|
||||
use nom::{alt, char, complete, do_parse, eof, many0, named, separated_list0, tag, terminated};
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
pub(crate) mod macros;
|
||||
mod expr;
|
||||
mod type_;
|
||||
|
||||
|
|
@ -136,7 +136,11 @@ named!(pub decl(&str) -> Decl, alt!(
|
|||
extern_decl
|
||||
));
|
||||
|
||||
named!(pub toplevel(&str) -> Vec<Decl>, terminated!(many0!(decl), multispace0));
|
||||
named!(pub toplevel(&str) -> Vec<Decl>, do_parse!(
|
||||
decls: many0!(decl)
|
||||
>> multispace0
|
||||
>> eof!()
|
||||
>> (decls)));
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
@ -215,4 +219,21 @@ mod tests {
|
|||
}]
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn return_unit() {
|
||||
assert_eq!(
|
||||
test_parse!(decl, "fn g _ = ()"),
|
||||
Decl::Fun {
|
||||
name: "g".try_into().unwrap(),
|
||||
body: Fun {
|
||||
args: vec![Arg {
|
||||
ident: "_".try_into().unwrap(),
|
||||
type_: None,
|
||||
}],
|
||||
body: Expr::Literal(Literal::Unit),
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ named!(pub type_(&str) -> Type, alt!(
|
|||
tag!("float") => { |_| Type::Float } |
|
||||
tag!("bool") => { |_| Type::Bool } |
|
||||
tag!("cstring") => { |_| Type::CString } |
|
||||
tag!("()") => { |_| Type::Unit } |
|
||||
function_type => { |ft| Type::Function(ft) }|
|
||||
ident => { |id| Type::Var(id) } |
|
||||
delimited!(
|
||||
|
|
@ -51,6 +52,7 @@ mod tests {
|
|||
assert_eq!(test_parse!(type_, "float"), Type::Float);
|
||||
assert_eq!(test_parse!(type_, "bool"), Type::Bool);
|
||||
assert_eq!(test_parse!(type_, "cstring"), Type::CString);
|
||||
assert_eq!(test_parse!(type_, "()"), Type::Unit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue