Move ParseTree to ast::Ast
This commit is contained in:
parent
3172d7d460
commit
62109e84ad
|
@ -0,0 +1,759 @@
|
|||
// Copyright (c) 2022 Marceline Cramer
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
use super::lexer::{Lexer, Token};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Ast<'a> {
|
||||
pub defs: Vec<Definition<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> Ast<'a> {
|
||||
pub fn build(lexer: &mut Lexer<'a>) -> Self {
|
||||
let mut defs = Vec::new();
|
||||
let mut associated_struct = None;
|
||||
while let Some(tok) = lexer.next() {
|
||||
if let Some(struct_name) = associated_struct {
|
||||
let mut mutable = false;
|
||||
if tok == Token::Mut {
|
||||
mutable = true;
|
||||
lexer.eat_expect(Token::Function);
|
||||
} else if tok != Token::Function {
|
||||
lexer.panic_message("Expected fn or mut");
|
||||
}
|
||||
|
||||
defs.push(Definition::build_function(
|
||||
mutable,
|
||||
Some(struct_name),
|
||||
lexer,
|
||||
));
|
||||
|
||||
associated_struct = None;
|
||||
} else {
|
||||
match tok {
|
||||
Token::Struct => defs.push(Definition::build_structure(lexer)),
|
||||
Token::Function => defs.push(Definition::build_function(false, None, lexer)),
|
||||
Token::Interface => defs.push(Definition::build_interface(lexer)),
|
||||
Token::Impl => defs.push(Definition::build_impl(lexer)),
|
||||
Token::Identifier => associated_struct = Some(lexer.slice()),
|
||||
_ => lexer.panic_message("Expected function, struct, impl block, or interface"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Self { defs }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Definition<'a> {
|
||||
Struct {
|
||||
name: &'a str,
|
||||
members: Vec<StructMember<'a>>,
|
||||
},
|
||||
Function {
|
||||
associated_struct: Option<&'a str>,
|
||||
implementation: FnImpl<'a>,
|
||||
},
|
||||
Interface {
|
||||
name: &'a str,
|
||||
functions: Vec<FnDef<'a>>,
|
||||
},
|
||||
Impl {
|
||||
structure: &'a str,
|
||||
interface: Option<&'a str>,
|
||||
functions: Vec<FnImpl<'a>>,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a> Definition<'a> {
|
||||
pub fn build_structure(lexer: &mut Lexer<'a>) -> Self {
|
||||
let name = lexer.eat_expect_id();
|
||||
lexer.eat_expect(Token::BraceOpen);
|
||||
|
||||
let mut members = Vec::new();
|
||||
|
||||
loop {
|
||||
match lexer.eat_id() {
|
||||
Ok(member_type) => {
|
||||
let member_name = lexer.eat_expect_id();
|
||||
members.push(StructMember {
|
||||
type_name: member_type,
|
||||
name: member_name,
|
||||
});
|
||||
}
|
||||
Err(Some(Token::Comma)) => {}
|
||||
Err(Some(Token::BraceClose)) => break,
|
||||
_ => lexer.panic_message("Expected comma or closing brace"),
|
||||
}
|
||||
}
|
||||
|
||||
Self::Struct { name, members }
|
||||
}
|
||||
|
||||
pub fn build_function(
|
||||
mutable: bool,
|
||||
associated_struct: Option<&'a str>,
|
||||
lexer: &mut Lexer<'a>,
|
||||
) -> Self {
|
||||
let implementation = FnImpl::build(mutable, lexer);
|
||||
|
||||
Self::Function {
|
||||
associated_struct,
|
||||
implementation,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_interface(lexer: &mut Lexer<'a>) -> Self {
|
||||
let name = lexer.eat_expect_id();
|
||||
lexer.eat_expect(Token::BraceOpen);
|
||||
|
||||
let mut functions = Vec::new();
|
||||
loop {
|
||||
match lexer.next().unwrap() {
|
||||
Token::Function => functions.push(FnDef::eat_with_semicolon(false, lexer)),
|
||||
Token::Mut => {
|
||||
lexer.eat_expect(Token::Function);
|
||||
functions.push(FnDef::eat_with_semicolon(true, lexer));
|
||||
}
|
||||
Token::BraceClose => break,
|
||||
_ => lexer.panic_message("Expected function definition or closing bracket"),
|
||||
}
|
||||
}
|
||||
|
||||
Self::Interface { name, functions }
|
||||
}
|
||||
|
||||
pub fn build_impl(lexer: &mut Lexer<'a>) -> Self {
|
||||
let structure = lexer.eat_expect_id();
|
||||
let interface = match lexer.next().unwrap() {
|
||||
Token::Identifier => {
|
||||
let interface = lexer.slice();
|
||||
lexer.eat_expect(Token::BraceOpen);
|
||||
Some(interface)
|
||||
}
|
||||
Token::BraceOpen => None,
|
||||
_ => lexer.panic_message("Expected interface name or opening brace"),
|
||||
};
|
||||
|
||||
let mut functions = Vec::new();
|
||||
loop {
|
||||
match lexer.next().unwrap() {
|
||||
Token::BraceClose => break,
|
||||
Token::Function => functions.push(FnImpl::build(false, lexer)),
|
||||
Token::Mut => {
|
||||
lexer.eat_expect(Token::Function);
|
||||
functions.push(FnImpl::build(true, lexer));
|
||||
}
|
||||
_ => lexer.panic_message("Expected function implementation or closing brace"),
|
||||
}
|
||||
}
|
||||
|
||||
Self::Impl {
|
||||
structure,
|
||||
interface,
|
||||
functions,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FnImpl<'a> {
|
||||
pub def: FnDef<'a>,
|
||||
pub body: BranchBody<'a>,
|
||||
}
|
||||
|
||||
impl<'a> FnImpl<'a> {
|
||||
pub fn build(mutable: bool, lexer: &mut Lexer<'a>) -> Self {
|
||||
let def = FnDef::eat_with_brace(mutable, lexer);
|
||||
let body = BranchBody::build(lexer);
|
||||
Self { def, body }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FnDef<'a> {
|
||||
pub mutable: bool,
|
||||
pub name: &'a str,
|
||||
pub signature: FnSig<'a>,
|
||||
}
|
||||
|
||||
impl<'a> FnDef<'a> {
|
||||
pub fn build(mutable: bool, lexer: &mut Lexer<'a>) -> (Self, Token) {
|
||||
let name = lexer.eat_expect_id();
|
||||
let (signature, tail) = FnSig::build(lexer);
|
||||
(
|
||||
Self {
|
||||
mutable,
|
||||
name,
|
||||
signature,
|
||||
},
|
||||
tail,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn eat_with_semicolon(mutable: bool, lexer: &mut Lexer<'a>) -> Self {
|
||||
let (fn_def, tail) = Self::build(mutable, lexer);
|
||||
if tail != Token::Semicolon {
|
||||
lexer.panic_message("Expected semicolon");
|
||||
}
|
||||
|
||||
fn_def
|
||||
}
|
||||
|
||||
pub fn eat_with_brace(mutable: bool, lexer: &mut Lexer<'a>) -> Self {
|
||||
let (fn_def, tail) = Self::build(mutable, lexer);
|
||||
if tail != Token::BraceOpen {
|
||||
lexer.panic_message("Expected opening brace");
|
||||
}
|
||||
|
||||
fn_def
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StructMember<'a> {
|
||||
pub type_name: &'a str,
|
||||
pub name: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FnSig<'a> {
|
||||
pub args: Vec<FnArg<'a>>,
|
||||
pub return_type: Option<&'a str>,
|
||||
}
|
||||
|
||||
impl<'a> FnSig<'a> {
|
||||
pub fn build(lexer: &mut Lexer<'a>) -> (Self, Token) {
|
||||
lexer.eat_expect(Token::ParenOpen);
|
||||
let mut args = Vec::new();
|
||||
|
||||
loop {
|
||||
match lexer.eat_id() {
|
||||
Ok(type_name) => match lexer.next().unwrap() {
|
||||
Token::Identifier => args.push(FnArg {
|
||||
type_name,
|
||||
name: Some(lexer.slice()),
|
||||
}),
|
||||
Token::Comma => args.push(FnArg {
|
||||
type_name,
|
||||
name: None,
|
||||
}),
|
||||
Token::ParenClose => {
|
||||
args.push(FnArg {
|
||||
type_name,
|
||||
name: None,
|
||||
});
|
||||
break;
|
||||
}
|
||||
_ => lexer.panic_message("Unexpected token"),
|
||||
},
|
||||
Err(Some(Token::Comma)) => {}
|
||||
Err(Some(Token::ParenClose)) => break,
|
||||
_ => lexer.panic_message("Expected comma, type, or closing parentheses"),
|
||||
}
|
||||
}
|
||||
|
||||
let mut next = lexer.next().unwrap();
|
||||
let mut return_type = None;
|
||||
if next == Token::Identifier {
|
||||
return_type = Some(lexer.slice());
|
||||
next = lexer.next().unwrap();
|
||||
}
|
||||
|
||||
(Self { args, return_type }, next)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FnArg<'a> {
|
||||
pub type_name: &'a str,
|
||||
pub name: Option<&'a str>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BranchBody<'a> {
|
||||
pub statements: Vec<Statement<'a>>,
|
||||
pub tail_expr: Option<Box<Expr<'a>>>,
|
||||
}
|
||||
|
||||
impl<'a> BranchBody<'a> {
|
||||
pub fn build(lexer: &mut Lexer<'a>) -> Self {
|
||||
let mut statements = Vec::new();
|
||||
|
||||
let mut next = None;
|
||||
let tail_expr = loop {
|
||||
let tok = if let Some(tok) = next {
|
||||
next = None;
|
||||
tok
|
||||
} else {
|
||||
lexer.next().unwrap()
|
||||
};
|
||||
|
||||
match tok {
|
||||
Token::Let => {
|
||||
let (statement, next) = Statement::build_let(lexer);
|
||||
statements.push(statement);
|
||||
match next {
|
||||
Token::Semicolon => {}
|
||||
Token::BraceClose => break None,
|
||||
_ => lexer.panic_message("Unexpected token"),
|
||||
}
|
||||
}
|
||||
Token::If => {
|
||||
let (stmt, tail) = IfStmt::build(lexer);
|
||||
if tail == Token::BraceClose {
|
||||
if let Some(_) = stmt.else_body {
|
||||
let expr = stmt.to_expr();
|
||||
break Some(Expr::If(expr));
|
||||
} else {
|
||||
statements.push(Statement::If(stmt));
|
||||
break None;
|
||||
}
|
||||
} else {
|
||||
statements.push(Statement::If(stmt));
|
||||
next = Some(tail);
|
||||
}
|
||||
}
|
||||
Token::While => {
|
||||
let test_expr = match Expr::build(lexer) {
|
||||
(Some(test_expr), Token::BraceOpen) => test_expr,
|
||||
(Some(_), _) => lexer.panic_message("Expected opening brace"),
|
||||
_ => lexer.panic_message("Expected test expression"),
|
||||
};
|
||||
|
||||
let loop_body = BranchBody::build(lexer);
|
||||
|
||||
statements.push(Statement::While {
|
||||
test_expr,
|
||||
loop_body,
|
||||
});
|
||||
}
|
||||
Token::BraceClose => break None,
|
||||
_ => match Expr::build_start(tok, lexer) {
|
||||
(None, Token::Semicolon | Token::BraceClose) => {}
|
||||
(Some(expr), Token::Semicolon) => statements.push(Statement::Expr(expr)),
|
||||
(Some(expr), Token::BraceClose) => break Some(expr),
|
||||
_ => lexer.panic_message("Unexpected token"),
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
Self {
|
||||
statements,
|
||||
tail_expr: tail_expr.map(|x| Box::new(x)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type ExprPair<'a> = Box<(Expr<'a>, Expr<'a>)>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Expr<'a> {
|
||||
BinaryOp(BinaryOp, ExprPair<'a>),
|
||||
UnaryOp(UnaryOp, Box<Expr<'a>>),
|
||||
Literal(Literal<'a>),
|
||||
Local(&'a str),
|
||||
Member(&'a str, Box<Expr<'a>>),
|
||||
SelfMember(&'a str),
|
||||
Group(Box<Expr<'a>>),
|
||||
FnCall(Box<Expr<'a>>, Vec<Expr<'a>>),
|
||||
If(IfExpr<'a>),
|
||||
}
|
||||
|
||||
impl<'a> Expr<'a> {
|
||||
pub fn build_start(tok: Token, lexer: &mut Lexer<'a>) -> (Option<Self>, Token) {
|
||||
let (unary_op, tok) = if let Some(op) = UnaryOp::from_token(tok) {
|
||||
(Some(op), lexer.next().unwrap())
|
||||
} else {
|
||||
(None, tok)
|
||||
};
|
||||
|
||||
let lhs = match tok {
|
||||
Token::Identifier => Self::Local(lexer.slice()),
|
||||
Token::Dot => Self::SelfMember(lexer.eat_expect_id()),
|
||||
Token::ParenOpen => {
|
||||
let (inner, next) = Self::build(lexer);
|
||||
if next != Token::ParenClose {
|
||||
lexer.panic_message("Expected closing parentheses");
|
||||
}
|
||||
Self::Group(Box::new(inner.unwrap()))
|
||||
}
|
||||
Token::If => Self::If(IfExpr::build(lexer)),
|
||||
Token::BinaryInteger => Self::Literal(Literal::BinaryInteger(lexer.slice())),
|
||||
Token::OctalInteger => Self::Literal(Literal::OctalInteger(lexer.slice())),
|
||||
Token::HexInteger => Self::Literal(Literal::HexInteger(lexer.slice())),
|
||||
Token::DecimalInteger => Self::Literal(Literal::DecimalInteger(lexer.slice())),
|
||||
Token::DecimalFloat => Self::Literal(Literal::DecimalFloat(lexer.slice())),
|
||||
Token::StringLiteral => Self::Literal(Literal::String(lexer.slice())),
|
||||
Token::True => Self::Literal(Literal::Boolean(true)),
|
||||
Token::False => Self::Literal(Literal::Boolean(false)),
|
||||
Token::Semicolon | Token::BraceClose | Token::ParenClose => return (None, tok),
|
||||
_ => lexer.panic_message("Unexpected token"),
|
||||
};
|
||||
|
||||
let mut lhs = if let Some(op) = unary_op {
|
||||
Self::UnaryOp(op, Box::new(lhs))
|
||||
} else {
|
||||
lhs
|
||||
};
|
||||
|
||||
loop {
|
||||
let tok = lexer.next().unwrap();
|
||||
|
||||
match tok {
|
||||
Token::Dot => {
|
||||
let member = lexer.eat_expect_id();
|
||||
let expr = Self::Member(member, Box::new(lhs));
|
||||
lhs = expr;
|
||||
}
|
||||
Token::ParenOpen => lhs = Self::FnCall(Box::new(lhs), Self::eat_args(lexer)),
|
||||
_ => {
|
||||
if let Some(op) = BinaryOp::from_token(tok) {
|
||||
match Self::build(lexer) {
|
||||
(Some(rhs), tail) => {
|
||||
break (Some(Self::BinaryOp(op, Box::new((lhs, rhs)))), tail)
|
||||
}
|
||||
_ => lexer.panic_message("Expected right-hand expression"),
|
||||
}
|
||||
} else {
|
||||
break (Some(lhs), tok);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build(lexer: &mut Lexer<'a>) -> (Option<Self>, Token) {
|
||||
Self::build_start(lexer.next().unwrap(), lexer)
|
||||
}
|
||||
|
||||
pub fn eat_args(lexer: &mut Lexer<'a>) -> Vec<Self> {
|
||||
let mut args = Vec::new();
|
||||
|
||||
loop {
|
||||
match Self::build(lexer) {
|
||||
(Some(arg), Token::Comma) => args.push(arg),
|
||||
(Some(arg), Token::ParenClose) => {
|
||||
args.push(arg);
|
||||
break;
|
||||
}
|
||||
(None, Token::ParenClose) => break,
|
||||
_ => lexer.panic_message("Unexpected token"),
|
||||
}
|
||||
}
|
||||
|
||||
args
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum BinaryOp {
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
Assign,
|
||||
BoolOr,
|
||||
BoolAnd,
|
||||
BitOr,
|
||||
BitAnd,
|
||||
BitXor,
|
||||
Less,
|
||||
LessEq,
|
||||
Greater,
|
||||
GreaterEq,
|
||||
Eq,
|
||||
Neq,
|
||||
}
|
||||
|
||||
impl BinaryOp {
|
||||
pub fn from_token(tok: Token) -> Option<Self> {
|
||||
use BinaryOp::*;
|
||||
use Token::*;
|
||||
match tok {
|
||||
OpAdd => Some(Add),
|
||||
OpSub => Some(Sub),
|
||||
OpMul => Some(Mul),
|
||||
OpDiv => Some(Div),
|
||||
OpAssign => Some(Assign),
|
||||
OpBoolOr => Some(BoolOr),
|
||||
OpBoolAnd => Some(BoolAnd),
|
||||
OpBitOr => Some(BitOr),
|
||||
OpBitAnd => Some(BitAnd),
|
||||
OpBitXor => Some(BitXor),
|
||||
OpLess => Some(Less),
|
||||
OpLessEq => Some(LessEq),
|
||||
OpGreater => Some(Greater),
|
||||
OpGreaterEq => Some(GreaterEq),
|
||||
OpEq => Some(Eq),
|
||||
OpNeq => Some(Neq),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum UnaryOp {
|
||||
BoolNot,
|
||||
BitNot,
|
||||
Negate,
|
||||
}
|
||||
|
||||
impl UnaryOp {
|
||||
pub fn from_token(tok: Token) -> Option<Self> {
|
||||
use Token::*;
|
||||
use UnaryOp::*;
|
||||
match tok {
|
||||
OpBoolNot => Some(BoolNot),
|
||||
OpBitNot => Some(BitNot),
|
||||
OpSub => Some(Negate),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Literal<'a> {
|
||||
BinaryInteger(&'a str),
|
||||
OctalInteger(&'a str),
|
||||
HexInteger(&'a str),
|
||||
DecimalInteger(&'a str),
|
||||
DecimalFloat(&'a str),
|
||||
String(&'a str),
|
||||
Boolean(bool),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Statement<'a> {
|
||||
Expr(Expr<'a>),
|
||||
If(IfStmt<'a>),
|
||||
While {
|
||||
test_expr: Expr<'a>,
|
||||
loop_body: BranchBody<'a>,
|
||||
},
|
||||
Let {
|
||||
var: &'a str,
|
||||
mutable: bool,
|
||||
expr: Expr<'a>,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a> Statement<'a> {
|
||||
pub fn eat_assign(lexer: &mut Lexer<'a>) -> (Expr<'a>, Token) {
|
||||
lexer.eat_expect(Token::OpAssign);
|
||||
let (expr, tail) = Expr::build(lexer);
|
||||
(expr.unwrap(), tail)
|
||||
}
|
||||
|
||||
pub fn build_let(lexer: &mut Lexer<'a>) -> (Self, Token) {
|
||||
let mut mutable = false;
|
||||
let var = match lexer.next().unwrap() {
|
||||
Token::Identifier => lexer.slice(),
|
||||
Token::Mut => {
|
||||
mutable = true;
|
||||
lexer.eat_expect_id()
|
||||
}
|
||||
_ => lexer.panic_message("Unexpected token"),
|
||||
};
|
||||
|
||||
let (expr, tail) = Self::eat_assign(lexer);
|
||||
(Self::Let { var, mutable, expr }, tail)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IfExpr<'a> {
|
||||
pub test_expr: Box<Expr<'a>>,
|
||||
pub then_body: BranchBody<'a>,
|
||||
pub else_body: BranchBody<'a>,
|
||||
}
|
||||
|
||||
impl<'a> IfExpr<'a> {
|
||||
pub fn build(lexer: &mut Lexer<'a>) -> Self {
|
||||
let test_expr = Box::new(Self::eat_test_expr(lexer));
|
||||
let then_body = BranchBody::build(lexer);
|
||||
|
||||
lexer.eat_expect(Token::Else);
|
||||
let else_body = match lexer.next().unwrap() {
|
||||
Token::BraceOpen => BranchBody::build(lexer),
|
||||
Token::If => BranchBody {
|
||||
statements: Vec::new(),
|
||||
tail_expr: Some(Box::new(Expr::If(IfExpr::build(lexer)))),
|
||||
},
|
||||
_ => lexer.panic_message("Expected if or opening brace"),
|
||||
};
|
||||
|
||||
Self {
|
||||
test_expr,
|
||||
then_body,
|
||||
else_body,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eat_test_expr(lexer: &mut Lexer<'a>) -> Expr<'a> {
|
||||
match Expr::build(lexer) {
|
||||
(Some(test_expr), Token::BraceOpen) => test_expr,
|
||||
(Some(_), _) => lexer.panic_message("Expected opening brace"),
|
||||
_ => lexer.panic_message("Expected test expression"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IfStmt<'a> {
|
||||
pub test_expr: Expr<'a>,
|
||||
pub then_body: BranchBody<'a>,
|
||||
pub else_body: Option<BranchBody<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> IfStmt<'a> {
|
||||
pub fn build(lexer: &mut Lexer<'a>) -> (Self, Token) {
|
||||
let test_expr = IfExpr::eat_test_expr(lexer);
|
||||
let then_body = BranchBody::build(lexer);
|
||||
|
||||
let (else_body, tail) = match lexer.next().unwrap() {
|
||||
Token::Else => {
|
||||
lexer.eat_expect(Token::BraceOpen);
|
||||
(Some(BranchBody::build(lexer)), lexer.next().unwrap())
|
||||
}
|
||||
next => (None, next),
|
||||
};
|
||||
|
||||
(
|
||||
Self {
|
||||
test_expr,
|
||||
then_body,
|
||||
else_body,
|
||||
},
|
||||
tail,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn to_expr(self) -> IfExpr<'a> {
|
||||
let Self {
|
||||
test_expr,
|
||||
then_body,
|
||||
else_body,
|
||||
} = self;
|
||||
|
||||
IfExpr {
|
||||
test_expr: Box::new(test_expr),
|
||||
then_body,
|
||||
else_body: else_body.unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn parse(source: &str) {
|
||||
let mut lex = Lexer::new(source);
|
||||
let parse_tree = Ast::build(&mut lex);
|
||||
println!("{:#?}", parse_tree);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function() {
|
||||
parse(include_str!("../test/function.fae"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tail_expression() {
|
||||
parse("fn add(i32 x, i32 y) i32 { x + y }");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn structure() {
|
||||
parse(include_str!("../test/structure.fae"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn interface() {
|
||||
parse(include_str!("../test/interface.fae"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn example() {
|
||||
parse(include_str!("../test/example.fae"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clock() {
|
||||
parse(include_str!("../test/clock.fae"));
|
||||
}
|
||||
|
||||
mod expr {
|
||||
use super::*;
|
||||
|
||||
fn parse_expr(source: &str) {
|
||||
println!("Source: {}", source);
|
||||
let mut lex = Lexer::new(source);
|
||||
let expr = Expr::build(&mut lex);
|
||||
println!("{:#?}", expr);
|
||||
assert_eq!(expr.1, Token::Semicolon);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn int_literals() {
|
||||
parse_expr("0b1 + 0x2 - 0o3 * 0x4;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn float_literals() {
|
||||
parse_expr("0.1 + .1 * 1.;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn string_literals() {
|
||||
parse_expr("\"String contents\";");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn locals() {
|
||||
parse_expr("local1 + local2 - local3;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nesting() {
|
||||
parse_expr("(1 + 2) * (3 / (4 + 5));")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unary_ops() {
|
||||
parse_expr("not false + -(2 + 3) * -1 / ~0xff;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn members() {
|
||||
parse_expr(".member1 * .member2;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_expr() {
|
||||
parse_expr("if true { 1 } else { 0 };");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn else_if_expr() {
|
||||
parse_expr("if a { 1 } else if b { 2 } else { c };");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn func_call() {
|
||||
parse_expr("func_call(1 + 2, 3, 4 * 5);");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn method() {
|
||||
parse_expr(".method();");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn submembers() {
|
||||
parse_expr(".member.submember1 / .member.submember2.submember3;");
|
||||
}
|
||||
}
|
||||
}
|
758
src/parse/mod.rs
758
src/parse/mod.rs
|
@ -1,762 +1,6 @@
|
|||
// Copyright (c) 2022 Marceline Cramer
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
pub mod ast;
|
||||
pub mod lexer;
|
||||
pub mod pest;
|
||||
|
||||
use lexer::{Lexer, Token};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ParseTree<'a> {
|
||||
pub defs: Vec<Definition<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> ParseTree<'a> {
|
||||
pub fn build(lexer: &mut Lexer<'a>) -> Self {
|
||||
let mut defs = Vec::new();
|
||||
let mut associated_struct = None;
|
||||
while let Some(tok) = lexer.next() {
|
||||
if let Some(struct_name) = associated_struct {
|
||||
let mut mutable = false;
|
||||
if tok == Token::Mut {
|
||||
mutable = true;
|
||||
lexer.eat_expect(Token::Function);
|
||||
} else if tok != Token::Function {
|
||||
lexer.panic_message("Expected fn or mut");
|
||||
}
|
||||
|
||||
defs.push(Definition::build_function(
|
||||
mutable,
|
||||
Some(struct_name),
|
||||
lexer,
|
||||
));
|
||||
|
||||
associated_struct = None;
|
||||
} else {
|
||||
match tok {
|
||||
Token::Struct => defs.push(Definition::build_structure(lexer)),
|
||||
Token::Function => defs.push(Definition::build_function(false, None, lexer)),
|
||||
Token::Interface => defs.push(Definition::build_interface(lexer)),
|
||||
Token::Impl => defs.push(Definition::build_impl(lexer)),
|
||||
Token::Identifier => associated_struct = Some(lexer.slice()),
|
||||
_ => lexer.panic_message("Expected function, struct, impl block, or interface"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Self { defs }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Definition<'a> {
|
||||
Struct {
|
||||
name: &'a str,
|
||||
members: Vec<StructMember<'a>>,
|
||||
},
|
||||
Function {
|
||||
associated_struct: Option<&'a str>,
|
||||
implementation: FnImpl<'a>,
|
||||
},
|
||||
Interface {
|
||||
name: &'a str,
|
||||
functions: Vec<FnDef<'a>>,
|
||||
},
|
||||
Impl {
|
||||
structure: &'a str,
|
||||
interface: Option<&'a str>,
|
||||
functions: Vec<FnImpl<'a>>,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a> Definition<'a> {
|
||||
pub fn build_structure(lexer: &mut Lexer<'a>) -> Self {
|
||||
let name = lexer.eat_expect_id();
|
||||
lexer.eat_expect(Token::BraceOpen);
|
||||
|
||||
let mut members = Vec::new();
|
||||
|
||||
loop {
|
||||
match lexer.eat_id() {
|
||||
Ok(member_type) => {
|
||||
let member_name = lexer.eat_expect_id();
|
||||
members.push(StructMember {
|
||||
type_name: member_type,
|
||||
name: member_name,
|
||||
});
|
||||
}
|
||||
Err(Some(Token::Comma)) => {}
|
||||
Err(Some(Token::BraceClose)) => break,
|
||||
_ => lexer.panic_message("Expected comma or closing brace"),
|
||||
}
|
||||
}
|
||||
|
||||
Self::Struct { name, members }
|
||||
}
|
||||
|
||||
pub fn build_function(
|
||||
mutable: bool,
|
||||
associated_struct: Option<&'a str>,
|
||||
lexer: &mut Lexer<'a>,
|
||||
) -> Self {
|
||||
let implementation = FnImpl::build(mutable, lexer);
|
||||
|
||||
Self::Function {
|
||||
associated_struct,
|
||||
implementation,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_interface(lexer: &mut Lexer<'a>) -> Self {
|
||||
let name = lexer.eat_expect_id();
|
||||
lexer.eat_expect(Token::BraceOpen);
|
||||
|
||||
let mut functions = Vec::new();
|
||||
loop {
|
||||
match lexer.next().unwrap() {
|
||||
Token::Function => functions.push(FnDef::eat_with_semicolon(false, lexer)),
|
||||
Token::Mut => {
|
||||
lexer.eat_expect(Token::Function);
|
||||
functions.push(FnDef::eat_with_semicolon(true, lexer));
|
||||
}
|
||||
Token::BraceClose => break,
|
||||
_ => lexer.panic_message("Expected function definition or closing bracket"),
|
||||
}
|
||||
}
|
||||
|
||||
Self::Interface { name, functions }
|
||||
}
|
||||
|
||||
pub fn build_impl(lexer: &mut Lexer<'a>) -> Self {
|
||||
let structure = lexer.eat_expect_id();
|
||||
let interface = match lexer.next().unwrap() {
|
||||
Token::Identifier => {
|
||||
let interface = lexer.slice();
|
||||
lexer.eat_expect(Token::BraceOpen);
|
||||
Some(interface)
|
||||
}
|
||||
Token::BraceOpen => None,
|
||||
_ => lexer.panic_message("Expected interface name or opening brace"),
|
||||
};
|
||||
|
||||
let mut functions = Vec::new();
|
||||
loop {
|
||||
match lexer.next().unwrap() {
|
||||
Token::BraceClose => break,
|
||||
Token::Function => functions.push(FnImpl::build(false, lexer)),
|
||||
Token::Mut => {
|
||||
lexer.eat_expect(Token::Function);
|
||||
functions.push(FnImpl::build(true, lexer));
|
||||
}
|
||||
_ => lexer.panic_message("Expected function implementation or closing brace"),
|
||||
}
|
||||
}
|
||||
|
||||
Self::Impl {
|
||||
structure,
|
||||
interface,
|
||||
functions,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FnImpl<'a> {
|
||||
pub def: FnDef<'a>,
|
||||
pub body: BranchBody<'a>,
|
||||
}
|
||||
|
||||
impl<'a> FnImpl<'a> {
|
||||
pub fn build(mutable: bool, lexer: &mut Lexer<'a>) -> Self {
|
||||
let def = FnDef::eat_with_brace(mutable, lexer);
|
||||
let body = BranchBody::build(lexer);
|
||||
Self { def, body }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FnDef<'a> {
|
||||
pub mutable: bool,
|
||||
pub name: &'a str,
|
||||
pub signature: FnSig<'a>,
|
||||
}
|
||||
|
||||
impl<'a> FnDef<'a> {
|
||||
pub fn build(mutable: bool, lexer: &mut Lexer<'a>) -> (Self, Token) {
|
||||
let name = lexer.eat_expect_id();
|
||||
let (signature, tail) = FnSig::build(lexer);
|
||||
(
|
||||
Self {
|
||||
mutable,
|
||||
name,
|
||||
signature,
|
||||
},
|
||||
tail,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn eat_with_semicolon(mutable: bool, lexer: &mut Lexer<'a>) -> Self {
|
||||
let (fn_def, tail) = Self::build(mutable, lexer);
|
||||
if tail != Token::Semicolon {
|
||||
lexer.panic_message("Expected semicolon");
|
||||
}
|
||||
|
||||
fn_def
|
||||
}
|
||||
|
||||
pub fn eat_with_brace(mutable: bool, lexer: &mut Lexer<'a>) -> Self {
|
||||
let (fn_def, tail) = Self::build(mutable, lexer);
|
||||
if tail != Token::BraceOpen {
|
||||
lexer.panic_message("Expected opening brace");
|
||||
}
|
||||
|
||||
fn_def
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StructMember<'a> {
|
||||
pub type_name: &'a str,
|
||||
pub name: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FnSig<'a> {
|
||||
pub args: Vec<FnArg<'a>>,
|
||||
pub return_type: Option<&'a str>,
|
||||
}
|
||||
|
||||
impl<'a> FnSig<'a> {
|
||||
pub fn build(lexer: &mut Lexer<'a>) -> (Self, Token) {
|
||||
lexer.eat_expect(Token::ParenOpen);
|
||||
let mut args = Vec::new();
|
||||
|
||||
loop {
|
||||
match lexer.eat_id() {
|
||||
Ok(type_name) => match lexer.next().unwrap() {
|
||||
Token::Identifier => args.push(FnArg {
|
||||
type_name,
|
||||
name: Some(lexer.slice()),
|
||||
}),
|
||||
Token::Comma => args.push(FnArg {
|
||||
type_name,
|
||||
name: None,
|
||||
}),
|
||||
Token::ParenClose => {
|
||||
args.push(FnArg {
|
||||
type_name,
|
||||
name: None,
|
||||
});
|
||||
break;
|
||||
}
|
||||
_ => lexer.panic_message("Unexpected token"),
|
||||
},
|
||||
Err(Some(Token::Comma)) => {}
|
||||
Err(Some(Token::ParenClose)) => break,
|
||||
_ => lexer.panic_message("Expected comma, type, or closing parentheses"),
|
||||
}
|
||||
}
|
||||
|
||||
let mut next = lexer.next().unwrap();
|
||||
let mut return_type = None;
|
||||
if next == Token::Identifier {
|
||||
return_type = Some(lexer.slice());
|
||||
next = lexer.next().unwrap();
|
||||
}
|
||||
|
||||
(Self { args, return_type }, next)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FnArg<'a> {
|
||||
pub type_name: &'a str,
|
||||
pub name: Option<&'a str>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BranchBody<'a> {
|
||||
pub statements: Vec<Statement<'a>>,
|
||||
pub tail_expr: Option<Box<Expr<'a>>>,
|
||||
}
|
||||
|
||||
impl<'a> BranchBody<'a> {
|
||||
pub fn build(lexer: &mut Lexer<'a>) -> Self {
|
||||
let mut statements = Vec::new();
|
||||
|
||||
let mut next = None;
|
||||
let tail_expr = loop {
|
||||
let tok = if let Some(tok) = next {
|
||||
next = None;
|
||||
tok
|
||||
} else {
|
||||
lexer.next().unwrap()
|
||||
};
|
||||
|
||||
match tok {
|
||||
Token::Let => {
|
||||
let (statement, next) = Statement::build_let(lexer);
|
||||
statements.push(statement);
|
||||
match next {
|
||||
Token::Semicolon => {}
|
||||
Token::BraceClose => break None,
|
||||
_ => lexer.panic_message("Unexpected token"),
|
||||
}
|
||||
}
|
||||
Token::If => {
|
||||
let (stmt, tail) = IfStmt::build(lexer);
|
||||
if tail == Token::BraceClose {
|
||||
if let Some(_) = stmt.else_body {
|
||||
let expr = stmt.to_expr();
|
||||
break Some(Expr::If(expr));
|
||||
} else {
|
||||
statements.push(Statement::If(stmt));
|
||||
break None;
|
||||
}
|
||||
} else {
|
||||
statements.push(Statement::If(stmt));
|
||||
next = Some(tail);
|
||||
}
|
||||
}
|
||||
Token::While => {
|
||||
let test_expr = match Expr::build(lexer) {
|
||||
(Some(test_expr), Token::BraceOpen) => test_expr,
|
||||
(Some(_), _) => lexer.panic_message("Expected opening brace"),
|
||||
_ => lexer.panic_message("Expected test expression"),
|
||||
};
|
||||
|
||||
let loop_body = BranchBody::build(lexer);
|
||||
|
||||
statements.push(Statement::While {
|
||||
test_expr,
|
||||
loop_body,
|
||||
});
|
||||
}
|
||||
Token::BraceClose => break None,
|
||||
_ => match Expr::build_start(tok, lexer) {
|
||||
(None, Token::Semicolon | Token::BraceClose) => {}
|
||||
(Some(expr), Token::Semicolon) => statements.push(Statement::Expr(expr)),
|
||||
(Some(expr), Token::BraceClose) => break Some(expr),
|
||||
_ => lexer.panic_message("Unexpected token"),
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
Self {
|
||||
statements,
|
||||
tail_expr: tail_expr.map(|x| Box::new(x)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type ExprPair<'a> = Box<(Expr<'a>, Expr<'a>)>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Expr<'a> {
|
||||
BinaryOp(BinaryOp, ExprPair<'a>),
|
||||
UnaryOp(UnaryOp, Box<Expr<'a>>),
|
||||
Literal(Literal<'a>),
|
||||
Local(&'a str),
|
||||
Member(&'a str, Box<Expr<'a>>),
|
||||
SelfMember(&'a str),
|
||||
Group(Box<Expr<'a>>),
|
||||
FnCall(Box<Expr<'a>>, Vec<Expr<'a>>),
|
||||
If(IfExpr<'a>),
|
||||
}
|
||||
|
||||
impl<'a> Expr<'a> {
|
||||
pub fn build_start(tok: Token, lexer: &mut Lexer<'a>) -> (Option<Self>, Token) {
|
||||
let (unary_op, tok) = if let Some(op) = UnaryOp::from_token(tok) {
|
||||
(Some(op), lexer.next().unwrap())
|
||||
} else {
|
||||
(None, tok)
|
||||
};
|
||||
|
||||
let lhs = match tok {
|
||||
Token::Identifier => Self::Local(lexer.slice()),
|
||||
Token::Dot => Self::SelfMember(lexer.eat_expect_id()),
|
||||
Token::ParenOpen => {
|
||||
let (inner, next) = Self::build(lexer);
|
||||
if next != Token::ParenClose {
|
||||
lexer.panic_message("Expected closing parentheses");
|
||||
}
|
||||
Self::Group(Box::new(inner.unwrap()))
|
||||
}
|
||||
Token::If => Self::If(IfExpr::build(lexer)),
|
||||
Token::BinaryInteger => Self::Literal(Literal::BinaryInteger(lexer.slice())),
|
||||
Token::OctalInteger => Self::Literal(Literal::OctalInteger(lexer.slice())),
|
||||
Token::HexInteger => Self::Literal(Literal::HexInteger(lexer.slice())),
|
||||
Token::DecimalInteger => Self::Literal(Literal::DecimalInteger(lexer.slice())),
|
||||
Token::DecimalFloat => Self::Literal(Literal::DecimalFloat(lexer.slice())),
|
||||
Token::StringLiteral => Self::Literal(Literal::String(lexer.slice())),
|
||||
Token::True => Self::Literal(Literal::Boolean(true)),
|
||||
Token::False => Self::Literal(Literal::Boolean(false)),
|
||||
Token::Semicolon | Token::BraceClose | Token::ParenClose => return (None, tok),
|
||||
_ => lexer.panic_message("Unexpected token"),
|
||||
};
|
||||
|
||||
let mut lhs = if let Some(op) = unary_op {
|
||||
Self::UnaryOp(op, Box::new(lhs))
|
||||
} else {
|
||||
lhs
|
||||
};
|
||||
|
||||
loop {
|
||||
let tok = lexer.next().unwrap();
|
||||
|
||||
match tok {
|
||||
Token::Dot => {
|
||||
let member = lexer.eat_expect_id();
|
||||
let expr = Self::Member(member, Box::new(lhs));
|
||||
lhs = expr;
|
||||
}
|
||||
Token::ParenOpen => lhs = Self::FnCall(Box::new(lhs), Self::eat_args(lexer)),
|
||||
_ => {
|
||||
if let Some(op) = BinaryOp::from_token(tok) {
|
||||
match Self::build(lexer) {
|
||||
(Some(rhs), tail) => {
|
||||
break (Some(Self::BinaryOp(op, Box::new((lhs, rhs)))), tail)
|
||||
}
|
||||
_ => lexer.panic_message("Expected right-hand expression"),
|
||||
}
|
||||
} else {
|
||||
break (Some(lhs), tok);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build(lexer: &mut Lexer<'a>) -> (Option<Self>, Token) {
|
||||
Self::build_start(lexer.next().unwrap(), lexer)
|
||||
}
|
||||
|
||||
pub fn eat_args(lexer: &mut Lexer<'a>) -> Vec<Self> {
|
||||
let mut args = Vec::new();
|
||||
|
||||
loop {
|
||||
match Self::build(lexer) {
|
||||
(Some(arg), Token::Comma) => args.push(arg),
|
||||
(Some(arg), Token::ParenClose) => {
|
||||
args.push(arg);
|
||||
break;
|
||||
}
|
||||
(None, Token::ParenClose) => break,
|
||||
_ => lexer.panic_message("Unexpected token"),
|
||||
}
|
||||
}
|
||||
|
||||
args
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum BinaryOp {
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
Assign,
|
||||
BoolOr,
|
||||
BoolAnd,
|
||||
BitOr,
|
||||
BitAnd,
|
||||
BitXor,
|
||||
Less,
|
||||
LessEq,
|
||||
Greater,
|
||||
GreaterEq,
|
||||
Eq,
|
||||
Neq,
|
||||
}
|
||||
|
||||
impl BinaryOp {
|
||||
pub fn from_token(tok: Token) -> Option<Self> {
|
||||
use BinaryOp::*;
|
||||
use Token::*;
|
||||
match tok {
|
||||
OpAdd => Some(Add),
|
||||
OpSub => Some(Sub),
|
||||
OpMul => Some(Mul),
|
||||
OpDiv => Some(Div),
|
||||
OpAssign => Some(Assign),
|
||||
OpBoolOr => Some(BoolOr),
|
||||
OpBoolAnd => Some(BoolAnd),
|
||||
OpBitOr => Some(BitOr),
|
||||
OpBitAnd => Some(BitAnd),
|
||||
OpBitXor => Some(BitXor),
|
||||
OpLess => Some(Less),
|
||||
OpLessEq => Some(LessEq),
|
||||
OpGreater => Some(Greater),
|
||||
OpGreaterEq => Some(GreaterEq),
|
||||
OpEq => Some(Eq),
|
||||
OpNeq => Some(Neq),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum UnaryOp {
|
||||
BoolNot,
|
||||
BitNot,
|
||||
Negate,
|
||||
}
|
||||
|
||||
impl UnaryOp {
|
||||
pub fn from_token(tok: Token) -> Option<Self> {
|
||||
use Token::*;
|
||||
use UnaryOp::*;
|
||||
match tok {
|
||||
OpBoolNot => Some(BoolNot),
|
||||
OpBitNot => Some(BitNot),
|
||||
OpSub => Some(Negate),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Literal<'a> {
|
||||
BinaryInteger(&'a str),
|
||||
OctalInteger(&'a str),
|
||||
HexInteger(&'a str),
|
||||
DecimalInteger(&'a str),
|
||||
DecimalFloat(&'a str),
|
||||
String(&'a str),
|
||||
Boolean(bool),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Statement<'a> {
|
||||
Expr(Expr<'a>),
|
||||
If(IfStmt<'a>),
|
||||
While {
|
||||
test_expr: Expr<'a>,
|
||||
loop_body: BranchBody<'a>,
|
||||
},
|
||||
Let {
|
||||
var: &'a str,
|
||||
mutable: bool,
|
||||
expr: Expr<'a>,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a> Statement<'a> {
|
||||
pub fn eat_assign(lexer: &mut Lexer<'a>) -> (Expr<'a>, Token) {
|
||||
lexer.eat_expect(Token::OpAssign);
|
||||
let (expr, tail) = Expr::build(lexer);
|
||||
(expr.unwrap(), tail)
|
||||
}
|
||||
|
||||
pub fn build_let(lexer: &mut Lexer<'a>) -> (Self, Token) {
|
||||
let mut mutable = false;
|
||||
let var = match lexer.next().unwrap() {
|
||||
Token::Identifier => lexer.slice(),
|
||||
Token::Mut => {
|
||||
mutable = true;
|
||||
lexer.eat_expect_id()
|
||||
}
|
||||
_ => lexer.panic_message("Unexpected token"),
|
||||
};
|
||||
|
||||
let (expr, tail) = Self::eat_assign(lexer);
|
||||
(Self::Let { var, mutable, expr }, tail)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IfExpr<'a> {
|
||||
pub test_expr: Box<Expr<'a>>,
|
||||
pub then_body: BranchBody<'a>,
|
||||
pub else_body: BranchBody<'a>,
|
||||
}
|
||||
|
||||
impl<'a> IfExpr<'a> {
|
||||
pub fn build(lexer: &mut Lexer<'a>) -> Self {
|
||||
let test_expr = Box::new(Self::eat_test_expr(lexer));
|
||||
let then_body = BranchBody::build(lexer);
|
||||
|
||||
lexer.eat_expect(Token::Else);
|
||||
let else_body = match lexer.next().unwrap() {
|
||||
Token::BraceOpen => BranchBody::build(lexer),
|
||||
Token::If => BranchBody {
|
||||
statements: Vec::new(),
|
||||
tail_expr: Some(Box::new(Expr::If(IfExpr::build(lexer)))),
|
||||
},
|
||||
_ => lexer.panic_message("Expected if or opening brace"),
|
||||
};
|
||||
|
||||
Self {
|
||||
test_expr,
|
||||
then_body,
|
||||
else_body,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eat_test_expr(lexer: &mut Lexer<'a>) -> Expr<'a> {
|
||||
match Expr::build(lexer) {
|
||||
(Some(test_expr), Token::BraceOpen) => test_expr,
|
||||
(Some(_), _) => lexer.panic_message("Expected opening brace"),
|
||||
_ => lexer.panic_message("Expected test expression"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IfStmt<'a> {
|
||||
pub test_expr: Expr<'a>,
|
||||
pub then_body: BranchBody<'a>,
|
||||
pub else_body: Option<BranchBody<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> IfStmt<'a> {
|
||||
pub fn build(lexer: &mut Lexer<'a>) -> (Self, Token) {
|
||||
let test_expr = IfExpr::eat_test_expr(lexer);
|
||||
let then_body = BranchBody::build(lexer);
|
||||
|
||||
let (else_body, tail) = match lexer.next().unwrap() {
|
||||
Token::Else => {
|
||||
lexer.eat_expect(Token::BraceOpen);
|
||||
(Some(BranchBody::build(lexer)), lexer.next().unwrap())
|
||||
}
|
||||
next => (None, next),
|
||||
};
|
||||
|
||||
(
|
||||
Self {
|
||||
test_expr,
|
||||
then_body,
|
||||
else_body,
|
||||
},
|
||||
tail,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn to_expr(self) -> IfExpr<'a> {
|
||||
let Self {
|
||||
test_expr,
|
||||
then_body,
|
||||
else_body,
|
||||
} = self;
|
||||
|
||||
IfExpr {
|
||||
test_expr: Box::new(test_expr),
|
||||
then_body,
|
||||
else_body: else_body.unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn parse(source: &str) {
|
||||
let mut lex = Lexer::new(source);
|
||||
let parse_tree = ParseTree::build(&mut lex);
|
||||
println!("{:#?}", parse_tree);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function() {
|
||||
parse(include_str!("../test/function.fae"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tail_expression() {
|
||||
parse("fn add(i32 x, i32 y) i32 { x + y }");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn structure() {
|
||||
parse(include_str!("../test/structure.fae"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn interface() {
|
||||
parse(include_str!("../test/interface.fae"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn example() {
|
||||
parse(include_str!("../test/example.fae"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clock() {
|
||||
parse(include_str!("../test/clock.fae"));
|
||||
}
|
||||
|
||||
mod expr {
|
||||
use super::*;
|
||||
|
||||
fn parse_expr(source: &str) {
|
||||
println!("Source: {}", source);
|
||||
let mut lex = Lexer::new(source);
|
||||
let expr = Expr::build(&mut lex);
|
||||
println!("{:#?}", expr);
|
||||
assert_eq!(expr.1, Token::Semicolon);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn int_literals() {
|
||||
parse_expr("0b1 + 0x2 - 0o3 * 0x4;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn float_literals() {
|
||||
parse_expr("0.1 + .1 * 1.;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn string_literals() {
|
||||
parse_expr("\"String contents\";");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn locals() {
|
||||
parse_expr("local1 + local2 - local3;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nesting() {
|
||||
parse_expr("(1 + 2) * (3 / (4 + 5));")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unary_ops() {
|
||||
parse_expr("not false + -(2 + 3) * -1 / ~0xff;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn members() {
|
||||
parse_expr(".member1 * .member2;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_expr() {
|
||||
parse_expr("if true { 1 } else { 0 };");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn else_if_expr() {
|
||||
parse_expr("if a { 1 } else if b { 2 } else { c };");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn func_call() {
|
||||
parse_expr("func_call(1 + 2, 3, 4 * 5);");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn method() {
|
||||
parse_expr(".method();");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn submembers() {
|
||||
parse_expr(".member.submember1 / .member.submember2.submember3;");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2022 Marceline Cramer
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
use crate::parse;
|
||||
use crate::parse::ast;
|
||||
use std::collections::HashMap;
|
||||
|
||||
type SymbolMap<T> = HashMap<String, T>;
|
||||
|
@ -31,11 +31,11 @@ pub struct SymbolTable {
|
|||
}
|
||||
|
||||
impl SymbolTable {
|
||||
pub fn from_parse_tree<'a>(pt: &parse::ParseTree<'a>) -> Self {
|
||||
pub fn from_parse_tree<'a>(pt: &ast::Ast<'a>) -> Self {
|
||||
let mut structures = SymbolMap::new();
|
||||
|
||||
for def in pt.defs.iter() {
|
||||
if let parse::Definition::Struct { name, members } = def {
|
||||
if let ast::Definition::Struct { name, members } = def {
|
||||
structures.insert(
|
||||
name.to_string(),
|
||||
StructDef {
|
||||
|
@ -56,7 +56,7 @@ impl SymbolTable {
|
|||
let mut interfaces = SymbolMap::new();
|
||||
|
||||
for def in pt.defs.iter() {
|
||||
if let parse::Definition::Interface { name, functions } = def {
|
||||
if let ast::Definition::Interface { name, functions } = def {
|
||||
interfaces.insert(
|
||||
name.to_string(),
|
||||
IfaceDef {
|
||||
|
@ -69,7 +69,7 @@ impl SymbolTable {
|
|||
let mut functions = SymbolMap::new();
|
||||
|
||||
for def in pt.defs.iter() {
|
||||
if let parse::Definition::Function {
|
||||
if let ast::Definition::Function {
|
||||
associated_struct,
|
||||
implementation,
|
||||
} = def
|
||||
|
@ -121,8 +121,8 @@ pub struct FnDef {
|
|||
pub return_type: Option<String>,
|
||||
}
|
||||
|
||||
impl<'a> From<&parse::FnDef<'a>> for FnDef {
|
||||
fn from(def: &parse::FnDef<'a>) -> Self {
|
||||
impl<'a> From<&ast::FnDef<'a>> for FnDef {
|
||||
fn from(def: &ast::FnDef<'a>) -> Self {
|
||||
Self {
|
||||
mutable: def.mutable,
|
||||
name: def.name.to_string(),
|
||||
|
@ -151,8 +151,8 @@ mod tests {
|
|||
use super::*;
|
||||
|
||||
fn from_source(source: &str) -> SymbolTable {
|
||||
let mut lex = parse::lexer::Lexer::new(source);
|
||||
let pt = parse::ParseTree::build(&mut lex);
|
||||
let mut lex = crate::parse::lexer::Lexer::new(source);
|
||||
let pt = ast::Ast::build(&mut lex);
|
||||
let symtab = SymbolTable::from_parse_tree(&pt);
|
||||
println!("{:#?}", symtab);
|
||||
symtab
|
||||
|
|
Loading…
Reference in New Issue