From fb1ff759e11e35a5717e87eb098c70eeda55f61e Mon Sep 17 00:00:00 2001 From: rvcas Date: Sun, 2 Oct 2022 18:53:29 -0400 Subject: [PATCH] feat: function calls and captures --- crates/lang/src/ast.rs | 4 +- crates/lang/src/parser.rs | 71 +++++++++++--- crates/lang/src/tests/parser.rs | 164 ++++++++++++++++++++++++++++++++ 3 files changed, 226 insertions(+), 13 deletions(-) diff --git a/crates/lang/src/ast.rs b/crates/lang/src/ast.rs index 4264994c..4a0d8f65 100644 --- a/crates/lang/src/ast.rs +++ b/crates/lang/src/ast.rs @@ -7,6 +7,8 @@ use crate::{ tipo::{self, PatternConstructor, Type, ValueConstructor}, }; +pub const CAPTURE_VARIABLE: &str = "_capture"; + pub type TypedModule = Module; pub type UntypedModule = Module<(), UntypedDefinition>; @@ -465,7 +467,6 @@ pub enum TodoKind { pub struct SrcId(Intern>); impl SrcId { - #[cfg(test)] pub fn empty() -> Self { SrcId(Intern::new(Vec::new())) } @@ -479,7 +480,6 @@ pub struct Span { } impl Span { - #[cfg(test)] pub fn empty() -> Self { use chumsky::Span; diff --git a/crates/lang/src/parser.rs b/crates/lang/src/parser.rs index 2e6bca86..ce91c04c 100644 --- a/crates/lang/src/parser.rs +++ b/crates/lang/src/parser.rs @@ -2,22 +2,12 @@ use chumsky::prelude::*; use vec1::Vec1; use crate::{ - ast::{self, BinOp, Span, TodoKind}, + ast::{self, BinOp, Span, TodoKind, CAPTURE_VARIABLE}, error::ParseError, expr, token::Token, }; -// Parsing a function call into the appropriate structure -#[derive(Debug)] -pub enum ParserArg { - Arg(Box>), - Hole { - location: Span, - label: Option, - }, -} - pub fn module_parser( kind: ast::ModuleKind, ) -> impl Parser { @@ -463,6 +453,16 @@ pub fn expr_parser( assert_parser, )); + // Parsing a function call into the appropriate structure + #[derive(Debug)] + enum ParserArg { + Arg(Box>), + Hole { + location: Span, + label: Option, + }, + } + enum Chain { FieldAccess(String, Span), RecordUpdate, @@ -511,6 +511,55 @@ pub fn expr_parser( label, container: Box::new(e), }, + Chain::Call(args, span) => { + let mut holes = Vec::new(); + + let args = args + .into_iter() + .enumerate() + .map(|(index, a)| match a { + ParserArg::Arg(arg) => *arg, + ParserArg::Hole { location, label } => { + holes.push(ast::Arg { + location: Span::empty(), + annotation: None, + arg_name: ast::ArgName::Named { + name: format!("{}__{}", CAPTURE_VARIABLE, index), + location: Span::empty(), + }, + tipo: (), + }); + + ast::CallArg { + label, + location, + value: expr::UntypedExpr::Var { + location, + name: format!("{}__{}", CAPTURE_VARIABLE, index), + }, + } + } + }) + .collect(); + + let call = expr::UntypedExpr::Call { + location: span, + fun: Box::new(e), + arguments: args, + }; + + if holes.is_empty() { + call + } else { + expr::UntypedExpr::Fn { + location: call.location(), + is_capture: true, + arguments: holes, + body: Box::new(call), + return_annotation: None, + } + } + } _ => todo!(), }); diff --git a/crates/lang/src/tests/parser.rs b/crates/lang/src/tests/parser.rs index 5ab777e9..7e3335a5 100644 --- a/crates/lang/src/tests/parser.rs +++ b/crates/lang/src/tests/parser.rs @@ -81,6 +81,14 @@ fn module() { fn name(user: User) { user.name } + + fn calls() { + let x = add_one(3) + + let map_add_x = list.map(_, fn (y) { x + y }) + + map_add_x([ 1, 2, 3 ]) + } "#; let len = code.chars().count(); @@ -759,6 +767,162 @@ fn module() { return_annotation: None, return_type: (), }, + ast::UntypedDefinition::Fn { + arguments: vec![], + body: expr::UntypedExpr::Sequence { + location: Span::new(SrcId::empty(), 1521..1642), + expressions: vec![ + expr::UntypedExpr::Assignment { + location: Span::new(SrcId::empty(), 1521..1539), + value: Box::new(expr::UntypedExpr::Call { + location: Span::new(SrcId::empty(), 1536..1539), + fun: Box::new(expr::UntypedExpr::Var { + location: Span::new(SrcId::empty(), 1529..1536), + name: "add_one".to_string(), + }), + arguments: vec![ast::CallArg { + label: None, + location: Span::new(SrcId::empty(), 1537..1538), + value: expr::UntypedExpr::Int { + location: Span::new(SrcId::empty(), 1537..1538), + value: "3".to_string(), + }, + },], + }), + pattern: ast::Pattern::Var { + location: Span::new(SrcId::empty(), 1525..1526), + name: "x".to_string(), + }, + kind: ast::AssignmentKind::Let, + annotation: None, + }, + expr::UntypedExpr::Assignment { + location: Span::new(SrcId::empty(), 1557..1602), + value: Box::new(expr::UntypedExpr::Fn { + location: Span::new(SrcId::empty(), 1581..1602), + is_capture: true, + arguments: vec![ast::Arg { + arg_name: ast::ArgName::Named { + name: "_capture__0".to_string(), + location: Span::new(SrcId::empty(), 0..0), + }, + location: Span::new(SrcId::empty(), 0..0), + annotation: None, + tipo: (), + },], + body: Box::new(expr::UntypedExpr::Call { + location: Span::new(SrcId::empty(), 1581..1602), + fun: Box::new(expr::UntypedExpr::FieldAccess { + location: Span::new(SrcId::empty(), 1573..1581), + label: "map".to_string(), + container: Box::new(expr::UntypedExpr::Var { + location: Span::new(SrcId::empty(), 1573..1577), + name: "list".to_string(), + }), + }), + arguments: vec![ + ast::CallArg { + label: None, + location: Span::new(SrcId::empty(), 1582..1583), + value: expr::UntypedExpr::Var { + location: Span::new(SrcId::empty(), 1582..1583), + name: "_capture__0".to_string(), + }, + }, + ast::CallArg { + label: None, + location: Span::new(SrcId::empty(), 1585..1601), + value: expr::UntypedExpr::Fn { + location: Span::new(SrcId::empty(), 1585..1601), + is_capture: false, + arguments: vec![ast::Arg { + arg_name: ast::ArgName::Named { + name: "y".to_string(), + location: Span::new( + SrcId::empty(), + 1589..1590 + ), + }, + location: Span::new( + SrcId::empty(), + 1589..1590 + ), + annotation: None, + tipo: (), + },], + body: Box::new(expr::UntypedExpr::BinOp { + location: Span::new( + SrcId::empty(), + 1594..1599 + ), + name: ast::BinOp::AddInt, + left: Box::new(expr::UntypedExpr::Var { + location: Span::new( + SrcId::empty(), + 1594..1595 + ), + name: "x".to_string(), + }), + right: Box::new(expr::UntypedExpr::Var { + location: Span::new( + SrcId::empty(), + 1598..1599 + ), + name: "y".to_string(), + }), + }), + return_annotation: None, + }, + }, + ], + }), + return_annotation: None, + }), + pattern: ast::Pattern::Var { + location: Span::new(SrcId::empty(), 1561..1570), + name: "map_add_x".to_string(), + }, + kind: ast::AssignmentKind::Let, + annotation: None, + }, + expr::UntypedExpr::Call { + location: Span::new(SrcId::empty(), 1629..1642), + fun: Box::new(expr::UntypedExpr::Var { + location: Span::new(SrcId::empty(), 1620..1629), + name: "map_add_x".to_string(), + }), + arguments: vec![ast::CallArg { + label: None, + location: Span::new(SrcId::empty(), 1630..1641), + value: expr::UntypedExpr::List { + location: Span::new(SrcId::empty(), 1630..1641), + elements: vec![ + expr::UntypedExpr::Int { + location: Span::new(SrcId::empty(), 1632..1633), + value: "1".to_string(), + }, + expr::UntypedExpr::Int { + location: Span::new(SrcId::empty(), 1635..1636), + value: "2".to_string(), + }, + expr::UntypedExpr::Int { + location: Span::new(SrcId::empty(), 1638..1639), + value: "3".to_string(), + }, + ], + tail: None, + }, + },], + }, + ], + }, + doc: None, + location: Span::new(SrcId::empty(), 1492..1656), + name: "calls".to_string(), + public: false, + return_annotation: None, + return_type: (), + }, ] }, );