diff --git a/Cargo.lock b/Cargo.lock index 6e05333..7095ba5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -198,13 +198,13 @@ dependencies = [ [[package]] name = "derivative" -version = "1.0.3" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942ca430eef7a3806595a6737bc388bf51adb888d3fc0dd1b50f1c170167ee3a" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "syn 0.15.44", + "proc-macro2 1.0.30", + "quote 1.0.10", + "syn 1.0.80", ] [[package]] diff --git a/schala-lang/Cargo.toml b/schala-lang/Cargo.toml index 0a9df4a..6c5a6f3 100644 --- a/schala-lang/Cargo.toml +++ b/schala-lang/Cargo.toml @@ -10,7 +10,7 @@ take_mut = "0.2.2" failure = "0.1.5" ena = "0.11.0" stopwatch = "0.0.7" -derivative = "1.0.3" +derivative = "2.2.0" colored = "1.8" radix_trie = "0.1.5" assert_matches = "1.5" diff --git a/schala-lang/src/ast/mod.rs b/schala-lang/src/ast/mod.rs index 40ff36a..34e7d5d 100644 --- a/schala-lang/src/ast/mod.rs +++ b/schala-lang/src/ast/mod.rs @@ -143,10 +143,15 @@ pub struct Signature { } //TODO I can probably get rid of TypeBody -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, Derivative, Clone)] +#[derivative(PartialEq)] pub enum TypeBody { Variants(Vec), - ImmediateRecord(ItemId, Vec<(Rc, TypeIdentifier)>), + ImmediateRecord { + #[derivative(PartialEq = "ignore")] + id: ItemId, + fields: Vec<(Rc, TypeIdentifier)>, + }, } #[derive(Debug, Derivative, Clone)] diff --git a/schala-lang/src/parsing/combinator.rs b/schala-lang/src/parsing/combinator.rs index cb05273..bbb993f 100644 --- a/schala-lang/src/parsing/combinator.rs +++ b/schala-lang/src/parsing/combinator.rs @@ -129,7 +129,34 @@ fn statement(input: Span) -> ParseResult { } fn declaration(input: Span) -> ParseResult { - alt((binding, type_decl, module))(input) + alt((binding, type_decl, func, module))(input) +} + +fn func(input: Span) -> ParseResult { + alt((func_decl, map(func_signature, Declaration::FuncSig)))(input) +} + +fn func_decl(input: Span) -> ParseResult { + map(pair(func_signature, block), |(sig, decl)| Declaration::FuncDecl(sig, decl))(input) +} + +//TODO handle operators +fn func_signature(input: Span) -> ParseResult { + map(tuple((kw("fn"), tok(identifier), formal_params, opt(type_anno))), |(_, name, params, type_anno)| { + Signature { name: rc_string(name.fragment()), operator: false, params, type_anno } + })(input) +} + +fn formal_params(input: Span) -> ParseResult> { + delimited(tok(char('(')), separated_list0(tok(char(',')), formal_param), tok(char(')')))(input) +} + +//TODO support 256-limit +fn formal_param(input: Span) -> ParseResult { + map( + tuple((tok(identifier), opt(type_anno), opt(preceded(tok(char('=')), expression)))), + |(name, anno, default)| FormalParam { name: rc_string(name.fragment()), anno, default }, + )(input) } fn type_decl(input: Span) -> ParseResult { @@ -153,7 +180,7 @@ fn type_body(input: Span) -> ParseResult { alt(( map( delimited(tok(char('{')), separated_list1(tok(char(',')), record_variant_item), tok(char('}'))), - move |items| TypeBody::ImmediateRecord(id, items), + move |items| TypeBody::ImmediateRecord { id, fields: items }, ), map(separated_list0(tok(char('|')), variant_spec), TypeBody::Variants), ))(input) diff --git a/schala-lang/src/parsing/mod.rs b/schala-lang/src/parsing/mod.rs index abc60f1..c4eded8 100644 --- a/schala-lang/src/parsing/mod.rs +++ b/schala-lang/src/parsing/mod.rs @@ -56,7 +56,6 @@ impl Parser { fn block_comb(&mut self, input: &str) -> Result { let id_store: IdStore = IdStore::new(); let span = Span::new_extra(input, Rc::new(RefCell::new(id_store))); - combinator::block(span).map_err(|err| convert_err(input, err)).map(|(_, output)| output) } diff --git a/schala-lang/src/parsing/peg_parser.rs b/schala-lang/src/parsing/peg_parser.rs index 9b4adc9..3fc771b 100644 --- a/schala-lang/src/parsing/peg_parser.rs +++ b/schala-lang/src/parsing/peg_parser.rs @@ -165,7 +165,7 @@ peg::parser! { singleton:type_singleton_name() { TypeIdentifier::Singleton(singleton) } rule type_body(parser: &mut Parser) -> TypeBody = - "{" _ items:(record_variant_item() ** (__ "," __)) __ "}" { TypeBody::ImmediateRecord(parser.fresh(), items) } / + "{" _ items:(record_variant_item() ** (__ "," __)) __ "}" { TypeBody::ImmediateRecord { id: parser.fresh(), fields: items } } / variants:(variant_spec(parser) ** (__ "|" __)) { TypeBody::Variants(variants) } rule variant_spec(parser: &mut Parser) -> Variant = diff --git a/schala-lang/src/parsing/test.rs b/schala-lang/src/parsing/test.rs index 43e68ef..64ca58c 100644 --- a/schala-lang/src/parsing/test.rs +++ b/schala-lang/src/parsing/test.rs @@ -609,7 +609,7 @@ fn type_annotations() { #[test] fn type_declarations() { use Declaration::TypeDecl; - assert_ast! { + assert_ast_comb! { "type Alpha = Alpha", vec![ decl(TypeDecl { name: TypeSingletonName { name: rc("Alpha"), params: vec![] }, @@ -625,7 +625,7 @@ fn type_declarations() { ] }; - assert_ast!( + assert_ast_comb!( "type mut Kuah = Kuah", decl(TypeDecl { name: TypeSingletonName { name: rc("Kuah"), params: vec![] }, @@ -638,7 +638,7 @@ fn type_declarations() { }) ); - assert_ast! { + assert_ast_comb! { "type Alpha = Alpha { a: Int, b: Int }", vec![decl(TypeDecl { name: TypeSingletonName { name: rc("Alpha"), params: vec![] }, @@ -656,20 +656,20 @@ fn type_declarations() { })] }; - assert_ast! { + assert_ast_comb! { "type Alpha = { a: Int, b: Int }", vec![decl(TypeDecl { name: TypeSingletonName { name: rc("Alpha"), params: vec![] }, mutable: false, - body: TypeBody::ImmediateRecord(Default::default(), vec![ + body: TypeBody::ImmediateRecord { id: Default::default(), fields: vec![ (rc("a"), ty_simple("Int")), (rc("b"), ty_simple("Int")) - ]) + ]} })] }; - assert_ast!( + assert_ast_comb!( "type Option = None | Some(T)", vec![decl(TypeDecl { name: TypeSingletonName { @@ -782,7 +782,7 @@ fn bindings() { #[test] fn functions() { use ExpressionKind::*; - assert_ast!( + assert_ast_comb!( "fn oi()", vec![stmt(StatementKind::Declaration(Declaration::FuncSig(Signature { name: rc("oi"), @@ -792,12 +792,12 @@ fn functions() { })))] ); - assert_ast!( + assert_ast_comb!( "oi()", vec![stmt(StatementKind::Expression(expr(Call { f: bx(expr(Value(qn!(oi)))), arguments: vec![] })))] ); - assert_expr!( + assert_expr_comb!( "oi(a, 2+2)", expr(Call { f: bx(expr(Value(qn!(oi)))), @@ -809,7 +809,7 @@ fn functions() { ); assert_fail!("a(b,,c)","error at 1:5: expected one of \"(\", \".\", \"0b\", \"0x\", \"[\", \"\\\"\", \"_\", \"false\", \"for\", \"if\", \"true\", \"while\", ['+' | '-' | '!'], ['0' ..= '9'], ['a' ..= 'z' | 'A' ..= 'Z' | '_'], r#\"\\\"#"); - assert_ast!( + assert_ast_comb!( "fn a(b, c: Int): Int", vec![stmt(StatementKind::Declaration(Declaration::FuncSig(Signature { name: rc("a"), @@ -834,7 +834,7 @@ fn functions() { }"#; - assert_ast!( + assert_ast_comb!( source, vec![fn_decl( Signature { name: rc("some_function"), operator: false, type_anno: None, params: vec![] }, @@ -874,7 +874,7 @@ fn functions_with_different_whitespace() { "#; for item in [a, b, c].iter() { - assert_ast!( + assert_ast_comb!( item, vec![fn_decl( Signature { @@ -897,7 +897,7 @@ fn functions_with_different_whitespace() { fn functions_with_default_args() { use ExpressionKind::*; - assert_ast!( + assert_ast_comb!( "fn func(x: Int, y: Int = 4) { }", vec![fn_decl( Signature { diff --git a/schala-lang/src/symbol_table/populator.rs b/schala-lang/src/symbol_table/populator.rs index 38b9700..fdda8c5 100644 --- a/schala-lang/src/symbol_table/populator.rs +++ b/schala-lang/src/symbol_table/populator.rs @@ -194,7 +194,7 @@ impl<'a> SymbolTablePopulator<'a> { ) -> Vec { let (variants, immediate_variant) = match type_body { TypeBody::Variants(variants) => (variants.clone(), false), - TypeBody::ImmediateRecord(id, fields) => ( + TypeBody::ImmediateRecord { id, fields } => ( vec![Variant { id: *id, name: type_name.name.clone(),