More parser work
This commit is contained in:
parent
9a4c342586
commit
3067af1304
|
@ -5,7 +5,7 @@ use std::{error::Error, fmt::Display, fs::File, io::Write, process::exit, str::F
|
||||||
use axc::{
|
use axc::{
|
||||||
ast2ir::ast2ir,
|
ast2ir::ast2ir,
|
||||||
backends,
|
backends,
|
||||||
parser::{parser, ParserError},
|
parser::{parser, ParserError, ParserMeta},
|
||||||
typeck::typeck,
|
typeck::typeck,
|
||||||
};
|
};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
@ -254,7 +254,8 @@ fn main() {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
|
||||||
let source = std::fs::read_to_string(&args.source_file)?;
|
let source = std::fs::read_to_string(&args.source_file)?;
|
||||||
let ast = chumsky::Parser::parse(&parser(), source).map_err(ParserError)?;
|
let meta = ParserMeta::default();
|
||||||
|
let ast = chumsky::Parser::parse(&parser(&meta), source).map_err(ParserError)?;
|
||||||
typeck(&ast)?;
|
typeck(&ast)?;
|
||||||
|
|
||||||
let ir = ast2ir(ast);
|
let ir = ast2ir(ast);
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
use std::{error::Error, fmt::Display};
|
use std::{error::Error, fmt::Display};
|
||||||
|
|
||||||
use chumsky::{
|
use chumsky::{
|
||||||
prelude::{choice, empty, end, just, todo, Simple},
|
prelude::{choice, end, just, todo, Simple},
|
||||||
text::{ident, keyword},
|
text::{ident, keyword},
|
||||||
Parser,
|
Parser,
|
||||||
};
|
};
|
||||||
|
@ -25,44 +25,228 @@ impl Display for ParserError {
|
||||||
|
|
||||||
impl Error for ParserError {}
|
impl Error for ParserError {}
|
||||||
|
|
||||||
|
/// Information required to be able to parse AlexScript code, beyond the code itself.
|
||||||
|
pub struct ParserMeta {
|
||||||
|
// This struct is just a total hacky workaround for the fact that chumsky isn't capable of
|
||||||
|
// parsing a context-sensitive grammar. I don't intend on ever fixing this: the stage-1 compiler
|
||||||
|
// will have a hardcoded list of operators, and the stage-2 compiler will have fully
|
||||||
|
// overloadable custom operators.
|
||||||
|
/// The list of registered binary operators.
|
||||||
|
operators: Vec<OperatorDef>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Definition of an operator.
|
||||||
|
struct OperatorDef {
|
||||||
|
/// The string of symbols that goes between two terms to invoke this operator.
|
||||||
|
name: String,
|
||||||
|
|
||||||
|
/// The precedence level; if X has lower precedence than Y, then a X b Y c is a X (b Y c);
|
||||||
|
/// otherwise, it is (a X b) Y c.
|
||||||
|
precedence: u32,
|
||||||
|
|
||||||
|
/// The associativity; if this is Left, then a X b X c is (a X b) X c; for Right, it is a X (b X
|
||||||
|
/// c); for None, it is a syntax error.
|
||||||
|
assoc: Option<Associativity>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The possible associativity directions of an operator.
|
||||||
|
enum Associativity {
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ParserMeta {
|
||||||
|
fn default() -> Self {
|
||||||
|
use Associativity::*;
|
||||||
|
Self {
|
||||||
|
// These are mostly stolen from Haskell.
|
||||||
|
operators: vec![
|
||||||
|
OperatorDef {
|
||||||
|
// Exponentiation.
|
||||||
|
name: "^".to_string(),
|
||||||
|
precedence: 8,
|
||||||
|
assoc: Some(Right),
|
||||||
|
},
|
||||||
|
OperatorDef {
|
||||||
|
name: "*".to_string(),
|
||||||
|
precedence: 7,
|
||||||
|
assoc: Some(Left),
|
||||||
|
},
|
||||||
|
OperatorDef {
|
||||||
|
// Division, which always returns an exact result and does not round to an
|
||||||
|
// integer (unlike C etc.).
|
||||||
|
name: "/".to_string(),
|
||||||
|
precedence: 7,
|
||||||
|
assoc: Some(Left),
|
||||||
|
},
|
||||||
|
OperatorDef {
|
||||||
|
// Modulo, defined as Euclidean remainder.
|
||||||
|
name: "%".to_string(),
|
||||||
|
precedence: 7,
|
||||||
|
assoc: Some(Left),
|
||||||
|
},
|
||||||
|
OperatorDef {
|
||||||
|
name: "+".to_string(),
|
||||||
|
precedence: 6,
|
||||||
|
assoc: Some(Left),
|
||||||
|
},
|
||||||
|
OperatorDef {
|
||||||
|
name: "-".to_string(),
|
||||||
|
precedence: 6,
|
||||||
|
assoc: Some(Left),
|
||||||
|
},
|
||||||
|
OperatorDef {
|
||||||
|
// Append to head of list. This might get removed since it's inefficient,
|
||||||
|
// depending.
|
||||||
|
name: "::".to_string(),
|
||||||
|
precedence: 5,
|
||||||
|
assoc: Some(Right),
|
||||||
|
},
|
||||||
|
OperatorDef {
|
||||||
|
// Append lists.
|
||||||
|
name: "++".to_string(),
|
||||||
|
precedence: 5,
|
||||||
|
assoc: Some(Right),
|
||||||
|
},
|
||||||
|
OperatorDef {
|
||||||
|
name: "==".to_string(),
|
||||||
|
precedence: 4,
|
||||||
|
assoc: None,
|
||||||
|
},
|
||||||
|
OperatorDef {
|
||||||
|
name: "!=".to_string(),
|
||||||
|
precedence: 4,
|
||||||
|
assoc: None,
|
||||||
|
},
|
||||||
|
OperatorDef {
|
||||||
|
name: "<".to_string(),
|
||||||
|
precedence: 4,
|
||||||
|
assoc: None,
|
||||||
|
},
|
||||||
|
OperatorDef {
|
||||||
|
name: "<=".to_string(),
|
||||||
|
precedence: 4,
|
||||||
|
assoc: None,
|
||||||
|
},
|
||||||
|
OperatorDef {
|
||||||
|
name: ">".to_string(),
|
||||||
|
precedence: 4,
|
||||||
|
assoc: None,
|
||||||
|
},
|
||||||
|
OperatorDef {
|
||||||
|
name: ">=".to_string(),
|
||||||
|
precedence: 4,
|
||||||
|
assoc: None,
|
||||||
|
},
|
||||||
|
OperatorDef {
|
||||||
|
// Functor map.
|
||||||
|
name: "<$>".to_string(),
|
||||||
|
precedence: 4,
|
||||||
|
assoc: Some(Left),
|
||||||
|
},
|
||||||
|
OperatorDef {
|
||||||
|
// Functor map to constant.
|
||||||
|
name: "<$".to_string(),
|
||||||
|
precedence: 4,
|
||||||
|
assoc: Some(Left),
|
||||||
|
},
|
||||||
|
OperatorDef {
|
||||||
|
// Flipped `<$`.
|
||||||
|
name: "$>".to_string(),
|
||||||
|
precedence: 4,
|
||||||
|
assoc: Some(Left),
|
||||||
|
},
|
||||||
|
OperatorDef {
|
||||||
|
// Sequential application of applicative actions.
|
||||||
|
name: "<*>".to_string(),
|
||||||
|
precedence: 4,
|
||||||
|
assoc: Some(Left),
|
||||||
|
},
|
||||||
|
OperatorDef {
|
||||||
|
// Sequence applicative actions, discarding the left value.
|
||||||
|
name: "*>".to_string(),
|
||||||
|
precedence: 4,
|
||||||
|
assoc: Some(Left),
|
||||||
|
},
|
||||||
|
OperatorDef {
|
||||||
|
// Sequence applicative actions, discarding the right value.
|
||||||
|
name: "<*".to_string(),
|
||||||
|
precedence: 4,
|
||||||
|
assoc: Some(Left),
|
||||||
|
},
|
||||||
|
OperatorDef {
|
||||||
|
// Binary and boolean `and`.
|
||||||
|
name: "&".to_string(),
|
||||||
|
precedence: 3,
|
||||||
|
assoc: Some(Right),
|
||||||
|
},
|
||||||
|
OperatorDef {
|
||||||
|
// Binary and boolean `or`.
|
||||||
|
name: "|".to_string(),
|
||||||
|
precedence: 2,
|
||||||
|
assoc: Some(Right),
|
||||||
|
},
|
||||||
|
OperatorDef {
|
||||||
|
// Monad sequence.
|
||||||
|
name: ">>".to_string(),
|
||||||
|
precedence: 1,
|
||||||
|
assoc: Some(Left),
|
||||||
|
},
|
||||||
|
OperatorDef {
|
||||||
|
// Monad bind.
|
||||||
|
name: ">>=".to_string(),
|
||||||
|
precedence: 1,
|
||||||
|
assoc: Some(Left),
|
||||||
|
},
|
||||||
|
OperatorDef {
|
||||||
|
// Function application.
|
||||||
|
name: "$".to_string(),
|
||||||
|
precedence: 1,
|
||||||
|
assoc: Some(Left),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Parser for AlexScript code.
|
/// Parser for AlexScript code.
|
||||||
pub fn parser() -> impl Parser<char, SyntaxTree, Error = Simple<char>> {
|
pub fn parser(m: &ParserMeta) -> impl Parser<char, SyntaxTree, Error = Simple<char>> {
|
||||||
parse_statement()
|
parse_statement(m)
|
||||||
.repeated()
|
.repeated()
|
||||||
.map(SyntaxTree)
|
.map(SyntaxTree)
|
||||||
.then_ignore(end())
|
.then_ignore(end())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_statement() -> impl Parser<char, Statement, Error = Simple<char>> {
|
fn parse_statement(m: &ParserMeta) -> impl Parser<char, Statement, Error = Simple<char>> {
|
||||||
choice((
|
choice((
|
||||||
parse_type_def(),
|
parse_type_def(m),
|
||||||
parse_instance_def(),
|
parse_instance_def(m),
|
||||||
parse_class_def(),
|
parse_class_def(m),
|
||||||
parse_class_decl_stmt(),
|
parse_class_decl_stmt(m),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_type_def() -> impl Parser<char, Statement, Error = Simple<char>> {
|
fn parse_type_def(m: &ParserMeta) -> impl Parser<char, Statement, Error = Simple<char>> {
|
||||||
keyword("data")
|
keyword("data")
|
||||||
.ignore_then(parse_type())
|
.ignore_then(parse_type(m))
|
||||||
.then_ignore(just('='))
|
.then_ignore(just('='))
|
||||||
.then(parse_constructor().repeated())
|
.then(parse_constructor(m).repeated())
|
||||||
.then_ignore(just(';'))
|
.then_ignore(just(';'))
|
||||||
.map(|(typ, constructors)| Statement::TypeDefinition { typ, constructors })
|
.map(|(typ, constructors)| Statement::TypeDefinition { typ, constructors })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_constructor() -> impl Parser<char, TypeConstructor, Error = Simple<char>> {
|
fn parse_constructor(m: &ParserMeta) -> impl Parser<char, TypeConstructor, Error = Simple<char>> {
|
||||||
ident()
|
ident()
|
||||||
.then(parse_type().repeated())
|
.then(parse_type(m).repeated())
|
||||||
.map(|(name, args)| TypeConstructor { name, args })
|
.map(|(name, args)| TypeConstructor { name, args })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_instance_def() -> impl Parser<char, Statement, Error = Simple<char>> {
|
fn parse_instance_def(m: &ParserMeta) -> impl Parser<char, Statement, Error = Simple<char>> {
|
||||||
keyword("instance")
|
keyword("instance")
|
||||||
.ignore_then(ident())
|
.ignore_then(ident())
|
||||||
.then(parse_type())
|
.then(parse_type(m))
|
||||||
.then(
|
.then(
|
||||||
parse_class_member()
|
parse_class_member(m)
|
||||||
.repeated()
|
.repeated()
|
||||||
.delimited_by(just('{'), just('}')),
|
.delimited_by(just('{'), just('}')),
|
||||||
)
|
)
|
||||||
|
@ -73,22 +257,19 @@ fn parse_instance_def() -> impl Parser<char, Statement, Error = Simple<char>> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_class_decl_stmt() -> impl Parser<char, Statement, Error = Simple<char>> {
|
fn parse_class_decl_stmt(m: &ParserMeta) -> impl Parser<char, Statement, Error = Simple<char>> {
|
||||||
parse_class_member().map(Statement::ClassMember)
|
parse_class_member(m).map(Statement::ClassMember)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_class_member() -> impl Parser<char, ClassMember, Error = Simple<char>> {
|
fn parse_class_member(m: &ParserMeta) -> impl Parser<char, ClassMember, Error = Simple<char>> {
|
||||||
choice((parse_func_decl(), parse_type_alias()))
|
choice((parse_func_decl(m), parse_type_alias(m)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_func_decl() -> impl Parser<char, ClassMember, Error = Simple<char>> {
|
fn parse_func_decl(m: &ParserMeta) -> impl Parser<char, ClassMember, Error = Simple<char>> {
|
||||||
keyword("def")
|
keyword("def")
|
||||||
.ignore_then(ident())
|
.ignore_then(ident())
|
||||||
.then(parse_pattern().repeated())
|
.then(parse_pattern(m).repeated())
|
||||||
.then(choice((
|
.then(just('=').ignore_then(parse_expression(m)).or_not())
|
||||||
just('=').ignore_then(parse_expression()).map(Some),
|
|
||||||
empty().to(None),
|
|
||||||
)))
|
|
||||||
.then_ignore(just(';'))
|
.then_ignore(just(';'))
|
||||||
.map(|((name, arguments), definition)| ClassMember::Function {
|
.map(|((name, arguments), definition)| ClassMember::Function {
|
||||||
name,
|
name,
|
||||||
|
@ -97,37 +278,34 @@ fn parse_func_decl() -> impl Parser<char, ClassMember, Error = Simple<char>> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_type_alias() -> impl Parser<char, ClassMember, Error = Simple<char>> {
|
fn parse_type_alias(m: &ParserMeta) -> impl Parser<char, ClassMember, Error = Simple<char>> {
|
||||||
keyword("type")
|
keyword("type")
|
||||||
.ignore_then(parse_type())
|
.ignore_then(parse_type(m))
|
||||||
.then(choice((
|
.then(just('=').ignore_then(parse_type(m)).or_not())
|
||||||
just('=').ignore_then(parse_type()).map(Some),
|
|
||||||
empty().to(None),
|
|
||||||
)))
|
|
||||||
.then_ignore(just(';'))
|
.then_ignore(just(';'))
|
||||||
.map(|(left, right)| ClassMember::TypeAlias { left, right })
|
.map(|(left, right)| ClassMember::TypeAlias { left, right })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_class_def() -> impl Parser<char, Statement, Error = Simple<char>> {
|
fn parse_class_def(m: &ParserMeta) -> impl Parser<char, Statement, Error = Simple<char>> {
|
||||||
keyword("class")
|
keyword("class")
|
||||||
.ignore_then(ident())
|
.ignore_then(ident())
|
||||||
.then(ident())
|
.then(ident())
|
||||||
.then(
|
.then(
|
||||||
parse_class_member()
|
parse_class_member(m)
|
||||||
.repeated()
|
.repeated()
|
||||||
.delimited_by(just('{'), just('}')),
|
.delimited_by(just('{'), just('}')),
|
||||||
)
|
)
|
||||||
.map(|((name, var), decls)| Statement::ClassDefinition { name, var, decls })
|
.map(|((name, var), decls)| Statement::ClassDefinition { name, var, decls })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_expression() -> impl Parser<char, Expr, Error = Simple<char>> {
|
fn parse_expression(m: &ParserMeta) -> impl Parser<char, Expr, Error = Simple<char>> {
|
||||||
todo()
|
todo()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_type() -> impl Parser<char, Type, Error = Simple<char>> {
|
fn parse_type(m: &ParserMeta) -> impl Parser<char, Type, Error = Simple<char>> {
|
||||||
todo()
|
todo()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_pattern() -> impl Parser<char, Pattern, Error = Simple<char>> {
|
fn parse_pattern(m: &ParserMeta) -> impl Parser<char, Pattern, Error = Simple<char>> {
|
||||||
todo()
|
todo()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue