diff --git a/schala-lang/language/src/parser.rs b/schala-lang/language/src/parser.rs index 635c1b4..d0b9548 100644 --- a/schala-lang/language/src/parser.rs +++ b/schala-lang/language/src/parser.rs @@ -8,7 +8,7 @@ use nom::character::complete::{one_of, space0, alphanumeric0}; use nom::bytes::complete::{tag, take, take_while, take_while1, take_until}; use nom::combinator::{cut, cond, map, map_res, value, opt, verify}; use nom::multi::{separated_list, separated_nonempty_list, many1, many0}; -use nom::error::{context, ParseError, VerboseError}; +use nom::error::{context, ParseError, VerboseError, ErrorKind, make_error}; use nom::branch::alt; use nom::sequence::{pair, tuple, delimited, preceded}; @@ -326,11 +326,11 @@ fn expr_or_block(text: &str) -> ParseResult { fn block(text: &str) -> ParseResult { use nom::character::complete::char; //TODO fix this so it can handle nested statements - delimited(char('{'), + delimited(ws(char('{')), separated_nonempty_list(statement_sep, map(expression, |e| Statement { id: ItemId::new(0), kind: StatementKind::Expression(e) }) ), - char('}'))(text) + ws(char('}')))(text) } fn call_expr(text: &str) -> ParseResult { @@ -411,8 +411,100 @@ fn expression(text: &str) -> ParseResult { Ok((rest, expr)) } +fn import(text: &str) -> ParseResult { + let p = preceded( + tag("import"), + separated_nonempty_list(tag("::"), identifier) + ); + map(p, |path_components| ImportSpecifier { + id: ItemId::new(0), + path_components, + imported_names: ImportedNames::LastOfPath, //TODO finish + })(text) +} + +fn module(text: &str) -> ParseResult { + let p = tuple((tag("module"), ws(identifier), ws(block))); + map(p, |(_, name, contents)| ModuleSpecifier { name, contents }) + (text) +} + +fn declaration(text: &str) -> ParseResult { + alt(( + func_declaration, + type_declaration, + ))(text) +} + +fn func_declaration(text: &str) -> ParseResult { + use Declaration::*; + let p = tuple((func_signature, opt(block))); + map(p, |(signature, maybe_block)| match maybe_block { + Some(block) => FuncDecl(signature, block), + None => FuncSig(signature), + })(text) +} + +fn func_signature(text: &str) -> ParseResult { + let p = preceded(tag("fn"), tuple((identifier, formal_params, opt(type_anno)))); + //TODO fix op + map(p, |(name, params, type_anno)| Signature { name, params, type_anno, operator: false }) + (text) +} + +fn formal_params(text: &str) -> ParseResult> { + delimited(tag("("), ws(separated_list(ws(tag(",")), formal_param)), tag(")"))(text) +} + +fn formal_param(text: &str) -> ParseResult { + let p = tuple((identifier, opt(type_anno))); + //TODO handle default arg +} + +fn type_declaration(text: &str) -> ParseResult { + preceded(tag("type"), ws(type_declaration_body))(text) +} + +fn type_declaration_body(text: &str) -> ParseResult { + let t = tuple((opt(tag("mut"))), ws(type_singleton_name), ws(tag("=")), ws(type_body)); + alt(( + preceded(tag("alias"), ws(type_alias)), + map(t, |(mut_kw, name, _, body)| { + Declaration::TypeDecl { name, body, mutable: mut_kw.is_some() } + }) + ))(text) +} + +fn type_singleton_name(text: &str) -> ParseResult { + tuple((identifier, opt(delimited(tag("<"), + separated_nonempty_list(tag(","), ws(type_name)), + tag(">")))))(text) +} + +fn type_alias(text: &str) -> ParseResult { + let p = tuple((ws(identifier), ws(tag("=")), ws(identifier))); + map(p, |(alias, _, original)| Declaration::TypeAlias { alias, original }) + (text) +} + +fn statement(text: &str) -> ParseResult { + let p = alt(( + map(import, StatementKind::Import), + map(module, StatementKind::Module), + map(declaration, StatementKind::Declaration), + map(expression, StatementKind::Expression), + )); + map(p, |kind| Statement { id: ItemId::new(0), kind })(text) +} + +pub fn parse_ast(text: &str) -> ParseResult { + map(separated_list(statement_sep, statement), + |statements| AST { id: ItemId::new(0), statements } + )(text) +} + pub fn perform_parsing(input: &str) -> Result { - let output = match expression(input) { + let output = match parse_ast(input) { Ok((rest, ast)) => format!("{:?} (rest: {})", ast, rest), Err(nom::Err::Incomplete(needed)) => format!("Incomplete: {:?}" ,needed), Err(nom::Err::Error(verbose_error) | nom::Err::Failure(verbose_error)) => {