about summary refs log tree commit diff
path: root/users/glittershark/achilles/src/parser
diff options
context:
space:
mode:
authorGriffin Smith <grfn@gws.fyi>2021-03-28T17·28-0400
committerglittershark <grfn@gws.fyi>2021-03-28T17·33+0000
commit8e13b1303a0d152c2f3b68f2421163e94fdf226c (patch)
tree0cac0fee2cd52f912bb118cff78fdca9d28ac895 /users/glittershark/achilles/src/parser
parentdb62866d820cf524b67cebe34033d3928804cf3c (diff)
feat(achilles): Implement a Unit type r/2356
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
Diffstat (limited to 'users/glittershark/achilles/src/parser')
-rw-r--r--users/glittershark/achilles/src/parser/expr.rs22
-rw-r--r--users/glittershark/achilles/src/parser/mod.rs27
-rw-r--r--users/glittershark/achilles/src/parser/type_.rs2
3 files changed, 46 insertions, 5 deletions
diff --git a/users/glittershark/achilles/src/parser/expr.rs b/users/glittershark/achilles/src/parser/expr.rs
index 99c8018fd00c..8a28d00984c9 100644
--- a/users/glittershark/achilles/src/parser/expr.rs
+++ b/users/glittershark/achilles/src/parser/expr.rs
@@ -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),
@@ -432,6 +433,11 @@ pub(crate) mod tests {
     }
 
     #[test]
+    fn unit() {
+        assert_eq!(test_parse!(expr, "()"), Expr::Literal(Literal::Unit));
+    }
+
+    #[test]
     fn bools() {
         assert_eq!(
             test_parse!(expr, "true"),
@@ -516,6 +522,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");
         assert_eq!(
diff --git a/users/glittershark/achilles/src/parser/mod.rs b/users/glittershark/achilles/src/parser/mod.rs
index 652b083fdae5..3e0081bd391d 100644
--- a/users/glittershark/achilles/src/parser/mod.rs
+++ b/users/glittershark/achilles/src/parser/mod.rs
@@ -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),
+                },
+            }
+        )
+    }
 }
diff --git a/users/glittershark/achilles/src/parser/type_.rs b/users/glittershark/achilles/src/parser/type_.rs
index 1e6e380bb823..8a1081e2521f 100644
--- a/users/glittershark/achilles/src/parser/type_.rs
+++ b/users/glittershark/achilles/src/parser/type_.rs
@@ -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]