diff --git a/axc/src/parser.rs b/axc/src/parser.rs index 276dada..b430a8d 100644 --- a/axc/src/parser.rs +++ b/axc/src/parser.rs @@ -3,10 +3,13 @@ use std::{error::Error, fmt::Display}; use chumsky::{ - prelude::{filter, Simple}, + prelude::{choice, empty, end, just, todo, Simple}, + text::{ident, keyword}, Parser, }; +use crate::syntax::{ClassMember, Expr, Pattern, Statement, SyntaxTree, Type, TypeConstructor}; + /// Adapter to make `chumsky`'s parser errors usable as standard Rust errors. #[derive(Debug)] pub struct ParserError(pub Vec>); @@ -23,14 +26,108 @@ impl Display for ParserError { impl Error for ParserError {} /// Parser for AlexScript code. -pub fn parser() -> impl Parser> { - filter(|c: &char| c.is_numeric()).map(|_| todo!()) +pub fn parser() -> impl Parser> { + parse_statement() + .repeated() + .map(SyntaxTree) + .then_ignore(end()) } -fn parse_expression() -> impl Parser> { - parser().map(|_| todo!()) +fn parse_statement() -> impl Parser> { + choice(( + parse_type_def(), + parse_instance_def(), + parse_class_def(), + parse_class_decl_stmt(), + )) } -fn parse_type() -> impl Parser> { - parser().map(|_| todo!()) +fn parse_type_def() -> impl Parser> { + keyword("data") + .ignore_then(parse_type()) + .then_ignore(just('=')) + .then(parse_constructor().repeated()) + .then_ignore(just(';')) + .map(|(typ, constructors)| Statement::TypeDefinition { typ, constructors }) +} + +fn parse_constructor() -> impl Parser> { + ident() + .then(parse_type().repeated()) + .map(|(name, args)| TypeConstructor { name, args }) +} + +fn parse_instance_def() -> impl Parser> { + keyword("instance") + .ignore_then(ident()) + .then(parse_type()) + .then( + parse_class_member() + .repeated() + .delimited_by(just('{'), just('}')), + ) + .map(|((classname, typ), decls)| Statement::InstanceDefinition { + class_name: classname, + typ, + decls, + }) +} + +fn parse_class_decl_stmt() -> impl Parser> { + parse_class_member().map(Statement::ClassMember) +} + +fn parse_class_member() -> impl Parser> { + choice((parse_func_decl(), parse_type_alias())) +} + +fn parse_func_decl() -> impl Parser> { + keyword("def") + .ignore_then(ident()) + .then(parse_pattern().repeated()) + .then(choice(( + just('=').ignore_then(parse_expression()).map(Some), + empty().to(None), + ))) + .then_ignore(just(';')) + .map(|((name, arguments), definition)| ClassMember::Function { + name, + arguments, + definition, + }) +} + +fn parse_type_alias() -> impl Parser> { + keyword("type") + .ignore_then(parse_type()) + .then(choice(( + just('=').ignore_then(parse_type()).map(Some), + empty().to(None), + ))) + .then_ignore(just(';')) + .map(|(left, right)| ClassMember::TypeAlias { left, right }) +} + +fn parse_class_def() -> impl Parser> { + keyword("class") + .ignore_then(ident()) + .then(ident()) + .then( + parse_class_member() + .repeated() + .delimited_by(just('{'), just('}')), + ) + .map(|((name, var), decls)| Statement::ClassDefinition { name, var, decls }) +} + +fn parse_expression() -> impl Parser> { + todo() +} + +fn parse_type() -> impl Parser> { + todo() +} + +fn parse_pattern() -> impl Parser> { + todo() } diff --git a/axc/src/syntax.rs b/axc/src/syntax.rs index 22c87b1..ca607e8 100644 --- a/axc/src/syntax.rs +++ b/axc/src/syntax.rs @@ -5,14 +5,16 @@ use num_bigint::BigUint; /// A concrete syntax tree. This represents the full content of an AlexScript program, including all /// whitespace, comments, and tokens: the source code of the original program can be recovered /// completely using the syntax tree. -pub struct SyntaxTree {} +#[derive(Clone)] +pub struct SyntaxTree(pub Vec); /// Top-level statements, making up the overall program. +#[derive(Clone)] pub enum Statement { /// Declaration of an abstract data type. TypeDefinition { /// The type being defined. This is only allowed to be `Named` or `Application`. - left: Type, + typ: Type, /// The possible constructors of the data type. constructors: Vec, @@ -28,20 +30,34 @@ pub enum Statement { /// The list of declarations that dictate the type's behavior when treated as an instance of /// the type class. - decls: Vec, + decls: Vec, + }, + + /// Declaration of a type class. + ClassDefinition { + /// The name of the class. + name: String, + + /// The type variable representing a type conforming to the class. + var: String, + + /// The list of declarations (optionally filled-in) that are necessary for a type to conform + /// to the type class. + decls: Vec, }, /// Other declarations. - ClassDeclaration(ClassDeclaration), + ClassMember(ClassMember), } /// Top-level statements that are also allowed to occur within a type class definition, and which /// therefore have an optional rather than strictly-required right-hand side, e.g., `type X;` rather /// than `type X = Y;`. -pub enum ClassDeclaration { +#[derive(Clone)] +pub enum ClassMember { /// Declaration of a function or constant. Function { - /// Name of the function and its arguments. + /// Name of the function. name: String, /// The function arguments. @@ -59,22 +75,10 @@ pub enum ClassDeclaration { /// The target type. right: Option, }, - - /// Declaration of a type class. - ClassDefinition { - /// The name of the class. - name: String, - - /// The type variable representing a type conforming to the class. - var: String, - - /// The list of declarations (optionally filled-in) that are necessary for a type to conform - /// to the type class. - decls: Vec, - }, } /// A possible constructor for an abstract data type. +#[derive(Clone)] pub struct TypeConstructor { /// The name of the constructor. pub name: String, @@ -84,6 +88,7 @@ pub struct TypeConstructor { } /// Expressions. +#[derive(Clone)] pub enum Expr { /// Unary operators, e.g., `-5`. UnaryOp { @@ -179,6 +184,7 @@ pub enum Expr { } /// Type names. +#[derive(Clone)] pub enum Type { /// `Foo` Named(String), @@ -202,6 +208,7 @@ pub enum Type { /// Patterns for use in function arguments, lambda arguments, `let` statements, and `match` /// statements. +#[derive(Clone)] pub enum Pattern { /// `(a, b)` Tuple(Vec), @@ -232,6 +239,7 @@ pub enum Pattern { } /// Record syntax blocks, e.g., "{a: b, c: d, ...}". +#[derive(Clone)] pub struct Record { /// The named members of the record, in order of occurrence. pub members: Vec<(String, Expr)>, @@ -241,6 +249,7 @@ pub struct Record { } /// Literal values included in source code. +#[derive(Clone)] pub enum Literal { /// `"hello"` String(String),