diff --git a/schala-lang/src/parsing/combinator.rs b/schala-lang/src/parsing/combinator.rs index 0d112fa..cb05273 100644 --- a/schala-lang/src/parsing/combinator.rs +++ b/schala-lang/src/parsing/combinator.rs @@ -2,11 +2,12 @@ use std::{cell::RefCell, rc::Rc}; use nom::{ branch::alt, - bytes::complete::{tag, escaped_transform, take_while, take_till}, - character::is_alphanumeric, - character::complete::{ - alpha1, alphanumeric0, char, line_ending, none_of, not_line_ending, one_of, space0, - space1, + bytes::complete::{escaped_transform, tag, take_till, take_while}, + character::{ + complete::{ + alpha1, alphanumeric0, char, line_ending, none_of, not_line_ending, one_of, space0, space1, + }, + is_alphanumeric, }, combinator::{map, not, opt, peek, recognize, value}, error::{context, ParseError, VerboseError}, @@ -82,13 +83,16 @@ fn statement_delimiter(input: Span) -> ParseResult<()> { pub fn program(input: Span) -> ParseResult { let id = fresh_id(&input); //TODO `rest` should be empty - let (rest, statements) = context("AST", + let (rest, statements) = context( + "AST", map( - tuple(( - many0(statement_delimiter), - separated_list0(statement_delimiter, statement), - many0(statement_delimiter), - )), |(_, items, _)| items.into()) + tuple(( + many0(statement_delimiter), + separated_list0(statement_delimiter, statement), + many0(statement_delimiter), + )), + |(_, items, _)| items.into(), + ), )(input)?; println!("REST: {}", rest.fragment()); @@ -119,34 +123,96 @@ fn statement(input: Span) -> ParseResult { let id = fresh_id(&input); let (rest, kind) = context( "Parsing-statement", - alt(( - map(declaration, StatementKind::Declaration), - map(expression, StatementKind::Expression), - )) + alt((map(declaration, StatementKind::Declaration), map(expression, StatementKind::Expression))), )(input)?; Ok((rest, Statement { id, location, kind })) } fn declaration(input: Span) -> ParseResult { - alt((binding, module))(input) + alt((binding, type_decl, module))(input) +} + +fn type_decl(input: Span) -> ParseResult { + alt(( + map( + tuple((kw("type"), kw("alias"), tok(identifier), tok(char('=')), tok(identifier))), + |(_, _, alias, _, name)| Declaration::TypeAlias { + alias: rc_string(alias.fragment()), + original: rc_string(name.fragment()), + }, + ), + map( + tuple((kw("type"), opt(kw("mut")), type_singleton_name, tok(char('=')), type_body)), + |(_, mutable, name, _, body)| Declaration::TypeDecl { name, body, mutable: mutable.is_some() }, + ), + ))(input) +} + +fn type_body(input: Span) -> ParseResult { + let id = fresh_id(&input); + alt(( + map( + delimited(tok(char('{')), separated_list1(tok(char(',')), record_variant_item), tok(char('}'))), + move |items| TypeBody::ImmediateRecord(id, items), + ), + map(separated_list0(tok(char('|')), variant_spec), TypeBody::Variants), + ))(input) +} + +fn variant_spec(input: Span) -> ParseResult { + fn record_variant(input: Span) -> ParseResult { + map( + delimited(tok(char('{')), separated_list1(tok(char(',')), record_variant_item), tok(char('}'))), + VariantKind::Record, + )(input) + } + + fn tuple_variant(input: Span) -> ParseResult { + map( + delimited(tok(char('(')), separated_list1(tok(char(',')), type_identifier), tok(char(')'))), + VariantKind::TupleStruct, + )(input) + } + + let id = fresh_id(&input); + let (rest, (name, kind)) = alt(( + pair(tok(identifier), record_variant), + pair(tok(identifier), tuple_variant), + map(tok(identifier), |ident| (ident, VariantKind::UnitStruct)), + ))(input)?; + + Ok((rest, Variant { id, name: rc_string(name.fragment()), kind })) +} + +fn record_variant_item(input: Span) -> ParseResult<(Rc, TypeIdentifier)> { + map(tuple((tok(identifier), tok(char(':')), type_identifier)), |(name, _, ty)| { + (rc_string(name.fragment()), ty) + })(input) } fn binding(input: Span) -> ParseResult { - let parser = - tuple((kw("let"), opt(kw("mut")), tok(identifier), opt(type_anno), tok(char('=')), expression)); - map(parser, |(_, maybe_mut, ident, type_anno, _, expr)| - Declaration::Binding { name: rc_string(ident.fragment()), constant: maybe_mut.is_none(), - type_anno, expr })(input) + let parser = + tuple((kw("let"), opt(kw("mut")), tok(identifier), opt(type_anno), tok(char('=')), expression)); + map(parser, |(_, maybe_mut, ident, type_anno, _, expr)| Declaration::Binding { + name: rc_string(ident.fragment()), + constant: maybe_mut.is_none(), + type_anno, + expr, + })(input) } fn module(input: Span) -> ParseResult { - map(tuple((kw("module"), tok(identifier), block)), - |(_, name, items)| Declaration::Module { name: rc_string(name.fragment()), items })(input) + map(tuple((kw("module"), tok(identifier), block)), |(_, name, items)| Declaration::Module { + name: rc_string(name.fragment()), + items, + })(input) } pub fn expression(input: Span) -> ParseResult { let id = fresh_id(&input); - map(pair(expression_kind, opt(type_anno)), move |(kind, type_anno)| Expression { id, type_anno, kind })(input) + map(pair(expression_kind, opt(type_anno)), move |(kind, type_anno)| Expression { id, type_anno, kind })( + input, + ) } fn type_anno(input: Span) -> ParseResult { @@ -155,24 +221,23 @@ fn type_anno(input: Span) -> ParseResult { fn type_identifier(input: Span) -> ParseResult { alt(( - map(delimited(tok(char('(')), separated_list0(tok(char(',')), type_identifier), tok(char(')'))), - TypeIdentifier::Tuple), + map( + delimited(tok(char('(')), separated_list0(tok(char(',')), type_identifier), tok(char(')'))), + TypeIdentifier::Tuple, + ), map(type_singleton_name, TypeIdentifier::Singleton), ))(input) } fn type_singleton_name(input: Span) -> ParseResult { map(pair(tok(identifier), opt(type_params)), |(name, params)| TypeSingletonName { - name: rc_string(name.fragment()), params: if let Some(params) = params { params } else { vec![] } + name: rc_string(name.fragment()), + params: if let Some(params) = params { params } else { vec![] }, })(input) } fn type_params(input: Span) -> ParseResult> { - delimited( - tok(char('<')), - separated_list1(tok(char(',')), type_identifier), - tok(char('>')) - )(input) + delimited(tok(char('<')), separated_list1(tok(char(',')), type_identifier), tok(char('>')))(input) } pub fn expression_kind(input: Span) -> ParseResult { @@ -186,7 +251,8 @@ fn precedence_expr(input: Span) -> ParseResult { move |(first, rest): (ExpressionKind, Vec<(BinOp, ExpressionKind)>)| { let mut handle_ref = handle.borrow_mut(); BinopSequence { first, rest }.do_precedence(&mut handle_ref) - })(input) + }, + )(input) } fn precedence_continuation(input: Span) -> ParseResult<(BinOp, ExpressionKind)> { @@ -227,22 +293,19 @@ enum ExtendedPart<'a> { } fn extended_expr(input: Span) -> ParseResult { - let (s, (primary, parts)) = context("extended-expr", - pair(primary_expr, many0(extended_expr_part)))(input)?; + let (s, (primary, parts)) = + context("extended-expr", pair(primary_expr, many0(extended_expr_part)))(input)?; let mut expression = Expression::new(fresh_id(&s), primary); for part in parts.into_iter() { let kind = match part { - ExtendedPart::Index(indexers) => { - ExpressionKind::Index { indexee: Box::new(expression), indexers } - }, - ExtendedPart::Call(arguments) => { - ExpressionKind::Call { f: Box::new(expression), arguments } - } + ExtendedPart::Index(indexers) => + ExpressionKind::Index { indexee: Box::new(expression), indexers }, + ExtendedPart::Call(arguments) => ExpressionKind::Call { f: Box::new(expression), arguments }, ExtendedPart::Accessor(name) => { let name = rc_string(name); ExpressionKind::Access { name, expr: Box::new(expression) } - }, + } }; expression = Expression::new(fresh_id(&s), kind); } @@ -252,104 +315,90 @@ fn extended_expr(input: Span) -> ParseResult { fn extended_expr_part(input: Span) -> ParseResult { fn index_part(input: Span) -> ParseResult> { - delimited( - tok(char('[')), - separated_list1(tok(char(',')), expression), - tok(char(']')), - )(input) + delimited(tok(char('[')), separated_list1(tok(char(',')), expression), tok(char(']')))(input) } fn call_part(input: Span) -> ParseResult> { - delimited( - tok(char('(')), - separated_list0(tok(char(',')), invocation_argument), - tok(char(')')), - )(input) + delimited(tok(char('(')), separated_list0(tok(char(',')), invocation_argument), tok(char(')')))(input) } fn access_part(input: Span) -> ParseResult<&str> { - preceded( - tok(char('.')), - map(identifier, |item| *item.fragment()) - )(input) + preceded(tok(char('.')), map(identifier, |item| *item.fragment()))(input) } alt(( map(index_part, ExtendedPart::Index), map(call_part, ExtendedPart::Call), - map(access_part, ExtendedPart::Accessor) + map(access_part, ExtendedPart::Accessor), ))(input) } - //TODO this shouldn't be an expression b/c type annotations disallowed here +//TODO this shouldn't be an expression b/c type annotations disallowed here fn invocation_argument(input: Span) -> ParseResult { alt(( map(tok(char('_')), |_| InvocationArgument::Ignored), - map(tuple(( - tok(identifier), - tok(char('=')), - expression, - )), |(name, _, expr)| InvocationArgument::Keyword { name: rc_string(name.fragment()), expr }), + map(tuple((tok(identifier), tok(char('=')), expression)), |(name, _, expr)| { + InvocationArgument::Keyword { name: rc_string(name.fragment()), expr } + }), map(expression, InvocationArgument::Positional), ))(input) } - fn primary_expr(input: Span) -> ParseResult { - context("primary-expr", alt(( - list_expr, paren_expr, - string_literal, float_literal, number_literal, bool_literal, identifier_expr - )) + context( + "primary-expr", + alt(( + list_expr, + paren_expr, + string_literal, + float_literal, + number_literal, + bool_literal, + identifier_expr, + )), )(input) } fn paren_expr(input: Span) -> ParseResult { delimited( tok(char('(')), - map(separated_list0(tok(char(',')), expression), - |mut exprs| match exprs.len() { + map(separated_list0(tok(char(',')), expression), |mut exprs| match exprs.len() { 1 => exprs.pop().unwrap().kind, _ => ExpressionKind::TupleLiteral(exprs), }), - tok(char(')')) + tok(char(')')), )(input) - } fn list_expr(input: Span) -> ParseResult { - map( - delimited( - tok(char('[')), - separated_list0(tok(char(',')), expression), - tok(char(']')), - ), |items| ExpressionKind::ListLiteral(items))(input) + map(delimited(tok(char('[')), separated_list0(tok(char(',')), expression), tok(char(']'))), |items| { + ExpressionKind::ListLiteral(items) + })(input) } //TODO need to do something with prefix in the AST fn string_literal(input: Span) -> ParseResult { - tok( - map(pair(opt(identifier), bare_string_literal), - |(_maybe_prefix, s)| ExpressionKind::StringLiteral(Rc::new(s))) - )(input) + tok(map(pair(opt(identifier), bare_string_literal), |(_maybe_prefix, s)| { + ExpressionKind::StringLiteral(Rc::new(s)) + }))(input) } fn bare_string_literal(input: Span) -> ParseResult { - let string_escape_transforms = alt(( - value("\\", tag("\\")), - value("\"", tag("\"")), - value("\n", tag("n")), - value("\t", tag("t")), - )); - alt((map(tag(r#""""#), |_| String::new()), - map( - tuple(( - char('"'), - escaped_transform(none_of(r#""\"#), '\\', string_escape_transforms), - char('"'), - )), |(_, s, _)| s)))(input) + let string_escape_transforms = + alt((value("\\", tag("\\")), value("\"", tag("\"")), value("\n", tag("n")), value("\t", tag("t")))); + alt(( + map(tag(r#""""#), |_| String::new()), + map( + tuple(( + char('"'), + escaped_transform(none_of(r#""\"#), '\\', string_escape_transforms), + char('"'), + )), + |(_, s, _)| s, + ), + ))(input) } - fn identifier_expr(input: Span) -> ParseResult { context("identifier-expr", map(qualified_identifier, ExpressionKind::Value))(input) } @@ -362,7 +411,9 @@ fn qualified_identifier(input: Span) -> ParseResult { } fn identifier(input: Span) -> ParseResult { - recognize(pair(alt((tag("_"), alpha1)), take_while(|ch: char| { is_alphanumeric(ch as u8) || ch == '_'})))(input) + recognize(pair(alt((tag("_"), alpha1)), take_while(|ch: char| is_alphanumeric(ch as u8) || ch == '_')))( + input, + ) } fn bool_literal(input: Span) -> ParseResult { diff --git a/schala-lang/src/parsing/mod.rs b/schala-lang/src/parsing/mod.rs index b4086ce..abc60f1 100644 --- a/schala-lang/src/parsing/mod.rs +++ b/schala-lang/src/parsing/mod.rs @@ -44,9 +44,7 @@ impl Parser { let id_store: IdStore = IdStore::new(); let span = Span::new_extra(input, Rc::new(RefCell::new(id_store))); - combinator::expression(span).map_err(|err| convert_err(input, err)).map(|(rest, output)| { - output - }) + combinator::expression(span).map_err(|err| convert_err(input, err)).map(|(rest, output)| output) } #[cfg(test)] diff --git a/schala-lang/src/parsing/test.rs b/schala-lang/src/parsing/test.rs index 829fe13..43e68ef 100644 --- a/schala-lang/src/parsing/test.rs +++ b/schala-lang/src/parsing/test.rs @@ -98,7 +98,6 @@ macro_rules! assert_ast { }; } - macro_rules! assert_ast_comb { ($input:expr, $statements:expr) => { let mut parser = Parser::new(); @@ -692,12 +691,12 @@ fn type_declarations() { })] ); - assert_ast!( + assert_ast_comb!( "type alias Alpha = Beta", decl(Declaration::TypeAlias { alias: rc("Alpha"), original: rc("Beta") }) ); - assert_ast!("type Complex = Unit | Record { field: AnotherType, field2: (Nat, Int), field3: T } | Tuple(Int, (String, T))", + assert_ast_comb!("type Complex = Unit | Record { field: AnotherType, field2: (Nat, Int), field3: T } | Tuple(Int, (String, T))", decl(TypeDecl { name: TypeSingletonName { name: rc("Complex"), params: vec![ TypeIdentifier::Singleton(TypeSingletonName { name: rc("T"), params: vec![] }), @@ -734,7 +733,7 @@ fn type_declarations() { fn declarations() { use ExpressionKind::*; - assert_ast!( + assert_ast_comb!( "let q_q = Yolo::Swaggins", vec![decl(Declaration::Binding { name: rc("q_q"), @@ -749,7 +748,7 @@ fn declarations() { fn bindings() { use ExpressionKind::*; - assert_ast!( + assert_ast_comb!( "let mut a = 10", vec![decl(Declaration::Binding { name: rc("a"), @@ -759,7 +758,7 @@ fn bindings() { })] ); - assert_ast!( + assert_ast_comb!( "let a = 2 + a", vec![stmt(StatementKind::Declaration(Declaration::Binding { name: rc("a"), @@ -769,7 +768,7 @@ fn bindings() { }))] ); - assert_ast!( + assert_ast_comb!( "let a: Nat = 2", vec![stmt(StatementKind::Declaration(Declaration::Binding { name: rc("a"),