From 646f9f6bd2be6024ac7672319c96df6dde6dc639 Mon Sep 17 00:00:00 2001 From: azur Date: Wed, 29 Mar 2023 20:47:48 +0700 Subject: [PATCH] block expression --- hh.hlm | 7 -- ret.hlm | 19 ----- sketch.hlm | 25 ++++++ src/main.rs | 6 +- src/parse/parser.rs | 19 ++++- src/typing/_infer.rs | 195 ------------------------------------------- src/typing/check.rs | 33 ++++++-- src/typing/typed.rs | 3 +- 8 files changed, 74 insertions(+), 233 deletions(-) delete mode 100644 hh.hlm delete mode 100644 ret.hlm create mode 100644 sketch.hlm delete mode 100644 src/typing/_infer.rs diff --git a/hh.hlm b/hh.hlm deleted file mode 100644 index fdc6b03..0000000 --- a/hh.hlm +++ /dev/null @@ -1,7 +0,0 @@ -\x -> x // => x : t0 -\x -> x + 1 // => x : Int -(\x -> x)(1) // => x : Int - -let a : num = 1, - b : num = a + 1, - c : num = b + 1; \ No newline at end of file diff --git a/ret.hlm b/ret.hlm deleted file mode 100644 index 6a8a318..0000000 --- a/ret.hlm +++ /dev/null @@ -1,19 +0,0 @@ -let something: bool = true; - -let a: num = 4 in - println(a); - -fun foo(x: bool): num = { - fun id(a: T): T = id; - - if !id(x) then - return 1; - - 42 -}; - -fun main(): () = { - let r: num = foo(something); - - println(r); -}; \ No newline at end of file diff --git a/sketch.hlm b/sketch.hlm new file mode 100644 index 0000000..db009b4 --- /dev/null +++ b/sketch.hlm @@ -0,0 +1,25 @@ +mut ret_ty: Option + +if type_check(expr) = Return { + if ret_ty.is_some() && ret_ty != this_ty { + error + } else { + ret_ty = this_ty + } +} + +===== + +{ + if true { + return 1; + } + + if false { + return "Hello"; + } + + do_something(); + + return 4; +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 19a4726..7f0fb63 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,11 @@ pub mod typing; fn main() { let src = " - (\\x : num, y : num, z : num -> x)() + { + let x: num = 1; + let y: num = 2; + x + } ".to_string(); let filename = "?".to_string(); diff --git a/src/parse/parser.rs b/src/parse/parser.rs index 96c8708..715c981 100644 --- a/src/parse/parser.rs +++ b/src/parse/parser.rs @@ -206,6 +206,7 @@ pub enum Expr<'src> { Assign(Vec>), Block { exprs: Vec>>, + void: bool, // True if last expression is discarded (ends with semicolon). }, } @@ -307,14 +308,26 @@ pub fn expr_parser<'tokens, 'src: 'tokens>() -> impl Parser< let block = expr.clone() .map(boxspan) - .separated_by(just(Token::Semicolon)) - .allow_trailing() + .then_ignore(just(Token::Semicolon)) + .repeated() .collect::>() + .then(expr.clone() + .map(boxspan) + .or_not()) .delimited_by( just(Token::Open(Delim::Brace)), just(Token::Close(Delim::Brace)), ) - .map(|exprs| Expr::Block { exprs }); + .map(|(mut exprs, end)| { + let void = end.is_none(); + if let Some(end) = end { + exprs.push(end); + } + Expr::Block { + exprs, + void, + } + }); let atom = lit .or(ident) diff --git a/src/typing/_infer.rs b/src/typing/_infer.rs deleted file mode 100644 index 1b07eee..0000000 --- a/src/typing/_infer.rs +++ /dev/null @@ -1,195 +0,0 @@ -use super::{ - ty::Type, - typed::TExpr, -}; -use crate::{parse::{ - ptree::*, - span::*, -}, span}; - -#[derive(Clone, Debug)] -struct TypeEnv { - bindings: Vec<(String, Type)>, - funcs: Vec<(String, Vec, Type)>, -} - -impl TypeEnv { - fn new() -> Self { - Self { - bindings: Vec::new(), - funcs: Vec::new(), - } - } - - fn bind(&mut self, name: String, ty: Type) { - self.bindings.push((name, ty)); - } - - fn bind_func(&mut self, name: String, args: Vec, ret_ty: Type) { - self.funcs.push((name, args, ret_ty)); - } - - fn lookup(&self, name: &str) -> Option { - self.bindings.iter() - .rev() - .find(|(n, _)| *n == name) - .map(|(_, t)| t.clone()) - } - - fn lookup_func(&self, name: &str) -> Option<(Vec, Type)> { - self.funcs.iter() - .rev() - .find(|(n, _, _)| *n == name) - .map(|(_, args, ret_ty)| (args.clone(), ret_ty.clone())) - } -} - -struct TypeError { - msg: String, - loc: Span, -} - -fn type_expr(env: &mut TypeEnv, expr: Spanned) -> Result, TypeError> { - match expr.value { - Expr::Lit(lit) => match lit { - Lit::Unit => Ok(span!(TExpr::Lit(Lit::Unit), expr.span)), - Lit::Bool(x) => Ok(span!(TExpr::Lit(Lit::Bool(x)), expr.span)), - Lit::Num(x) => Ok(span!(TExpr::Lit(Lit::Num(x)), expr.span)), - Lit::Str(x) => Ok(span!(TExpr::Lit(Lit::Str(x)), expr.span)), - }, - - Expr::Ident(name) => { - let ty = env.lookup(&name) - .ok_or(TypeError { - msg: format!("unknown identifier `{}`", name), - loc: expr.span.clone(), - })?; - Ok(span!(TExpr::Ident(name, ty), expr.span)) - }, - - Expr::Unary(op, expr) => { - let span = expr.span.clone(); - let texpr = type_expr(env, *expr)?; - let ret_ty = match op { - UnaryOp::Neg => Type::Num, - UnaryOp::Not => Type::Bool, - }; - Ok(span!( - TExpr::Unary { op, expr: Box::new(texpr), ret_ty }, - span - )) - }, - - Expr::Binary(op, lhs, rhs) => { - let span = lhs.span.clone(); - let tlhs = type_expr(env, *lhs)?; - let trhs = type_expr(env, *rhs)?; - let ret_ty = match op { - BinaryOp::Add - | BinaryOp::Sub - | BinaryOp::Mul - | BinaryOp::Div - | BinaryOp::Rem => Type::Num, - BinaryOp::And - | BinaryOp::Or => Type::Bool, - BinaryOp::Eq - | BinaryOp::Ne - | BinaryOp::Lt - | BinaryOp::Le - | BinaryOp::Gt - | BinaryOp::Ge => Type::Bool, - }; - Ok(span!( - TExpr::Binary { op, lhs: Box::new(tlhs), rhs: Box::new(trhs), ret_ty }, - span - )) - }, - - Expr::Call(func, args) => { - let span = func.span.clone(); - - match func.value { - Expr::Ident(name) => { - // Get the function's argument and return types - let (arg_tys, ret_ty) = env.lookup_func(&name) - .ok_or(TypeError { - msg: format!("unknown function `{}`", name), - loc: span.clone(), - })?; - - // Create a typed identifier - let tfunc = TExpr::Ident( - name, - Type::Func(arg_tys.clone(), Box::new(ret_ty.clone())) - ); - - // Check that the number of arguments matches - if arg_tys.len() != args.len() { - return Err(TypeError { - msg: format!( - "expected {} arguments, got {}", - arg_tys.len(), args.len() - ), - loc: span, - }); - } - - // Type check the arguments - let mut targs = Vec::new(); - for (arg, ty) in args.into_iter().zip(arg_tys) { - let targ = type_expr(env, arg)?; - if targ.value.ty() != &ty { - return Err(TypeError { - msg: format!( - "expected argument of type `{}`, got `{}`", - ty, targ.value.ty() - ), - loc: targ.span, - }); - } - targs.push(targ); - } - - Ok(span!( - TExpr::Call { - func: Box::new(span!(tfunc, span.clone())), - args: targs, - ret_ty - }, - span - )) - }, - Expr::Lambda(args, body) => { - // Create a new type environment - let mut new_env = env.clone(); - - // Bind the arguments to the new environment and also infer their types - let mut arg_tys = Vec::new(); - for (arg, maybe_ty) in args { - let ty = match maybe_ty { - Some(ty) => ty, - None => todo!(), // TODO: infer the type - }; - arg_tys.push((arg.clone(), ty.clone())); - env.bind(arg, ty); - } - - // Type check the body - let tbody = type_expr(&mut new_env, *body)?; - - // Return the typed lambda expression - Ok(span!( - TExpr::Lambda { - params: arg_tys, - body: Box::new(tbody.clone()), - ret_ty: tbody.value.ty().clone(), - }, - span - )) - }, - _ => todo!(), - } - }, - _ => todo!(), - } -} \ No newline at end of file diff --git a/src/typing/check.rs b/src/typing/check.rs index 0e9f20e..e5f7de0 100644 --- a/src/typing/check.rs +++ b/src/typing/check.rs @@ -292,7 +292,7 @@ fn type_expr<'src>( for (name, maybe_ty, expr) in bindings { let ty = match maybe_ty { Some(ty) => ty, - None => todo!(), // TODO: infer. + None => todo!("Type inferrence"), // TODO: infer. }; let texpr = type_expr(&mut new_env, unbox!(expr))?; @@ -326,17 +326,14 @@ fn type_expr<'src>( } Expr::Assign(bindings) => { - // Create a new type environment. - let mut new_env = env.clone(); - // Type check the bindings. let mut tbindings = Vec::new(); for (name, maybe_ty, expr) in bindings { let ty = match maybe_ty { Some(ty) => ty, - None => todo!(), // TODO: infer. + None => todo!("Type inferrence"), // TODO: infer. }; - let texpr = type_expr(&mut new_env, unbox!(expr))?; + let texpr = type_expr(env, unbox!(expr))?; // Check if the type of the binding matches the type of the expression. if texpr.0.ty() != &ty { @@ -354,13 +351,35 @@ fn type_expr<'src>( } tbindings.push((name, ty.clone(), sbox!(texpr))); - new_env.bind(name, ty); + env.bind(name, ty); } // Return the typed assign expression. oks!(TExpr::Assign(tbindings)) } + Expr::Block { exprs, void } => { + let texprs = exprs + .into_iter() + .map(|e| type_expr(env, unbox!(e))) + .collect::, _>>()?; + + let ret_ty = if void { + Type::Unit + } else if let Some(texpr) = texprs.last() { + texpr.0.ty().clone() + } else { + Type::Unit + }; + + oks!(TExpr::Block { + exprs: texprs, + void, + ret_ty, + }) + } + + #[allow(unreachable_patterns)] _ => todo!(), } } diff --git a/src/typing/typed.rs b/src/typing/typed.rs index 6e9b1fc..e87d758 100644 --- a/src/typing/typed.rs +++ b/src/typing/typed.rs @@ -49,7 +49,8 @@ pub enum TExpr<'src> { }, Assign(Vec>), Block { - exprs: Vec, + exprs: Vec>, + void: bool, ret_ty: Type, }, }