diff --git a/src/lexer/token.rs b/src/lexer/token.rs index 0e7664a8..3c50d2a5 100644 --- a/src/lexer/token.rs +++ b/src/lexer/token.rs @@ -92,6 +92,7 @@ pub enum Token { As, Block, Boxed, + Can, Do, Effect, Else, @@ -278,6 +279,7 @@ impl Display for Token { Token::As => write!(f, "'as'"), Token::Block => write!(f, "'block'"), Token::Boxed => write!(f, "'boxed'"), + Token::Can => write!(f, "'can'"), Token::Do => write!(f, "'do'"), Token::Effect => write!(f, "'effect'"), Token::Else => write!(f, "'else'"), @@ -376,6 +378,7 @@ pub fn lookup_keyword(word: &str) -> Option { "as" => Some(Token::As), "block" => Some(Token::Block), "boxed" => Some(Token::Boxed), + "can" => Some(Token::Can), "do" => Some(Token::Do), "effect" => Some(Token::Effect), "else" => Some(Token::Else), diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 10c229d0..f982bdff 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -118,6 +118,7 @@ pub struct Lambda<'a> { pub args: Vec>, pub body: Box>, pub return_type: Option>, + pub effects: Option>>, pub closure_environment: ClosureEnvironment, @@ -127,6 +128,8 @@ pub struct Lambda<'a> { pub typ: Option, } +pub type EffectName<'a> = (String, Vec>); + // TODO: Remove. This is only used for experimenting with ante-lsp // which does not refer to the instantiation_mapping field at all. unsafe impl<'c> Send for Lambda<'c> {} @@ -268,6 +271,7 @@ pub enum TypeDefinitionBody<'a> { /// type Name arg1 arg2 ... argN = definition #[derive(Debug, Clone)] pub struct TypeDefinition<'a> { + pub boxed: bool, pub name: String, pub args: Vec, pub definition: TypeDefinitionBody<'a>, @@ -593,10 +597,14 @@ impl<'a> Ast<'a> { }) } - pub fn lambda(args: Vec>, return_type: Option>, body: Ast<'a>, location: Location<'a>) -> Ast<'a> { + pub fn lambda( + args: Vec>, return_type: Option>, effects: Option>>, body: Ast<'a>, + location: Location<'a>, + ) -> Ast<'a> { assert!(!args.is_empty()); Ast::Lambda(Lambda { args, + effects, body: Box::new(body), closure_environment: BTreeMap::new(), return_type, @@ -656,9 +664,9 @@ impl<'a> Ast<'a> { } pub fn type_definition( - name: String, args: Vec, definition: TypeDefinitionBody<'a>, location: Location<'a>, + boxed: bool, name: String, args: Vec, definition: TypeDefinitionBody<'a>, location: Location<'a>, ) -> Ast<'a> { - Ast::TypeDefinition(TypeDefinition { name, args, definition, location, type_info: None, typ: None }) + Ast::TypeDefinition(TypeDefinition { boxed, name, args, definition, location, type_info: None, typ: None }) } pub fn type_annotation(lhs: Ast<'a>, rhs: Type<'a>, location: Location<'a>) -> Ast<'a> { diff --git a/src/parser/desugar.rs b/src/parser/desugar.rs index ab8d3de8..06141f09 100644 --- a/src/parser/desugar.rs +++ b/src/parser/desugar.rs @@ -36,7 +36,7 @@ where }); let function_call = call_function(function, args, loc); - Ast::lambda(curried_args, None, function_call, loc) + Ast::lambda(curried_args, None, None, function_call, loc) } fn matches_underscore(arg: &Ast) -> bool { @@ -85,7 +85,7 @@ fn prepend_argument_to_function<'a>(f: Ast<'a>, arg: Ast<'a>, location: Location pub fn desugar_loop<'a>(params_defaults: Vec<(Ast<'a>, Ast<'a>)>, body: Ast<'a>, location: Location<'a>) -> Ast<'a> { let (params, args) = params_defaults.into_iter().unzip(); let recur_name = || Ast::variable(vec![], "recur".to_owned(), location); - let recur_def = Ast::definition(recur_name(), Ast::lambda(params, None, body, location), location); + let recur_def = Ast::definition(recur_name(), Ast::lambda(params, None, None, body, location), location); let recur_call = Ast::function_call(recur_name(), args, location); Ast::new_scope(Ast::sequence(vec![recur_def, recur_call], location), location) } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 0705dd0c..69050a6b 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -72,6 +72,7 @@ parser!(statement_list loc = fn statement<'a, 'b>(input: Input<'a, 'b>) -> AstResult<'a, 'b> { match input[0].0 { Token::ParenthesisLeft | Token::Identifier(_) => or(&[definition, assignment, expression], "statement")(input), + Token::Boxed => type_definition(input), Token::Type => or(&[type_definition, type_alias], "statement")(input), Token::Import => import(input), Token::Trait => trait_definition(input), @@ -95,11 +96,12 @@ parser!(function_definition location -> 'b ast::Definition<'b> = name <- pattern_argument; args <- many1(pattern_argument); return_type <- maybe(function_return_type); + effects <- maybe(effect_clause); _ <- expect(Token::Equal); body !<- block_or_statement; ast::Definition { pattern: Box::new(name), - expr: Box::new(Ast::lambda(args, return_type, body, location)), + expr: Box::new(Ast::lambda(args, return_type, effects, body, location)), mutable: false, location, level: None, @@ -108,6 +110,18 @@ parser!(function_definition location -> 'b ast::Definition<'b> = } ); +parser!(effect_clause location -> 'b Vec<(String, Vec>)> = + _ <- expect(Token::Can); + effects <- many1(effect); + effects +); + +parser!(effect location -> 'b (String, Vec>) = + name <- typename; + args <- many0(basic_type); + (name, args) +); + parser!(varargs location -> 'b () = _ <- expect(Token::Range); _ <- expect(Token::MemberAccess); @@ -168,12 +182,13 @@ fn parenthesized_irrefutable_pattern<'a, 'b>(input: Input<'a, 'b>) -> AstResult< } parser!(type_definition loc = + boxed <- maybe(expect(Token::Boxed)); _ <- expect(Token::Type); name <- typename; args <- many0(identifier); _ <- expect(Token::Equal); body <- type_definition_body; - Ast::type_definition(name, args, body, loc) + Ast::type_definition(boxed.is_some(), name, args, body, loc) ); parser!(type_alias loc = @@ -182,7 +197,7 @@ parser!(type_alias loc = args <- many0(identifier); _ <- expect(Token::Equal); body <- parse_type; - Ast::type_definition(name, args, TypeDefinitionBody::Alias(body), loc) + Ast::type_definition(false, name, args, TypeDefinitionBody::Alias(body), loc) ); fn type_definition_body<'a, 'b>(input: Input<'a, 'b>) -> ParseResult<'a, 'b, ast::TypeDefinitionBody<'b>> { @@ -717,9 +732,10 @@ parser!(lambda loc = _ <- expect(Token::Fn); args !<- many1(pattern_argument); return_type <- maybe(function_return_type); + effects <- maybe(effect_clause); _ !<- expect(Token::RightArrow); body !<- block_or_statement; - Ast::lambda(args, return_type, body, loc) + Ast::lambda(args, return_type, effects, body, loc) ); parser!(operator loc =