diff --git a/schala-lang/language/src/parser.rs b/schala-lang/language/src/parser.rs index b02ab5e..5d4fbe4 100644 --- a/schala-lang/language/src/parser.rs +++ b/schala-lang/language/src/parser.rs @@ -10,7 +10,7 @@ use nom::combinator::{cut, map, map_res, value, opt, verify}; use nom::multi::{separated_list, separated_nonempty_list, many1, many0}; use nom::error::{context, ParseError, VerboseError}; use nom::branch::alt; -use nom::sequence::{pair, delimited, preceded}; +use nom::sequence::{pair, tuple, delimited, preceded}; use crate::ast::*; use crate::builtin::Builtin; @@ -26,6 +26,10 @@ where delimited(space0, parser, space0) } +fn statement_sep(text: &str) -> ParseResult<()> { + value((), one_of("\n;"))(text) +} + fn single_alphabetic_character(text: &str) -> ParseResult { let p = verify(take(1usize), |s: &str| s.chars().nth(0).map(|c| c.is_alphabetic()).unwrap_or(false)); map(p, |s: &str| s.chars().nth(0).unwrap())(text) @@ -124,18 +128,15 @@ fn prefix_op(text: &str) -> ParseResult { map(p, |sigil| PrefixOp::from_str(&sigil.to_string()).unwrap())(text) } -fn identifier_expr(text: &str) -> ParseResult { - let (text, qualified_identifier) = map( - qualified_identifier_list, +fn qualified_name(text: &str) -> ParseResult { + map( + separated_nonempty_list(tag("::"), identifier), |components| QualifiedName { id: ItemId::new(0), components } - )(text)?; - //TODO handle struct literals - let exp = Expression::new(ItemId::new(0), ExpressionKind::Value(qualified_identifier)); - Ok((text, exp.kind)) + )(text) } -fn qualified_identifier_list(text: &str) -> ParseResult>> { - separated_nonempty_list(tag("::"), identifier)(text) +fn identifier_expr(text: &str) -> ParseResult { + map(qualified_name, ExpressionKind::Value)(text) } fn primary_expr(text: &str) -> ParseResult { @@ -173,6 +174,94 @@ fn if_expr(text: &str) -> ParseResult { } */ +fn if_expr_body(text: &str) -> ParseResult { + alt(( + preceded(tag("then"), simple_conditional), + preceded(tag("is"), simple_pattern_match), + cond_block, + ))(text) +} + +fn simple_conditional(text: &str) -> ParseResult { + map( + pair(expr_or_block, else_case), + |(then_case, else_case)| IfExpressionBody::SimpleConditional { then_case, else_case } + )(text) +} + +fn else_case(text: &str) -> ParseResult> { + opt(preceded(tag("else"), expr_or_block))(text) +} + +fn simple_pattern_match(text: &str) -> ParseResult { + let p = tuple((pattern, tag("then"), expr_or_block, else_case)); + map(p, |(pattern, _, then_case, else_case)| + IfExpressionBody::SimplePatternMatch { pattern, then_case, else_case } + )(text) +} + +fn pattern(text: &str) -> ParseResult { + use nom::character::complete::char; + + let t = delimited(char('('), + separated_nonempty_list(char(','), pattern), + char(')') + ); + + alt(( + map(t, |patterns| Pattern::TuplePattern(patterns)), + simple_pattern, + ))(text) +} + +fn simple_pattern(text: &str) -> ParseResult { + alt(( + value(Pattern::Ignored, tag("_")), + tuple_struct_pattern, + record_pattern, + map(pattern_literal, Pattern::Literal), + map(qualified_name, Pattern::VarOrName), + ))(text) +} + +fn tuple_struct_pattern(text: &str) -> ParseResult { + unimplemented!() +} + +fn record_pattern(text: &str) -> ParseResult { + unimplemented!() +} + +fn pattern_literal(text: &str) -> ParseResult { + use PatternLiteral::*; + use nom::character::complete::char; + alt(( + value(BoolPattern(true), tag("true")), + value(BoolPattern(false), tag("false")), + map(delimited(char('"'), take_until("\""), char('"')), |s: &str| StringPattern(Rc::new(s.to_string()))), + ))(text) + //TODO handle signed_number_literal +} + +fn cond_block(text: &str) -> ParseResult { + unimplemented!() +} + +fn expr_or_block(text: &str) -> ParseResult { + //TODO fix + alt((block, map(expression, |expr| vec![Statement { id: ItemId::new(0), kind: StatementKind::Expression(expr)}])))(text) +} + +fn block(text: &str) -> ParseResult { + use nom::character::complete::char; + //TODO fix this so it can handle nested statements + delimited(char('{'), + separated_nonempty_list(statement_sep, + map(expression, |e| Statement { id: ItemId::new(0), kind: StatementKind::Expression(e) }) + ), + char('}'))(text) +} + fn call_expr(text: &str) -> ParseResult { use nom::character::complete::char; let parse_call = opt(