gbas 0.1.0

An assembler for Game Boy
Documentation
use diagnostics::DiagnosticsListener;
use span::Span;

#[cfg(test)]
#[macro_use]
mod ast;
pub mod keyword;
pub mod lexer;
mod parser;

pub use frontend::syntax::keyword::Operand;

#[derive(Clone, Debug, PartialEq)]
pub enum Token<I, C = keyword::Command, L = Literal<I>, E = lexer::LexError> {
    ClosingParenthesis,
    Colon,
    Comma,
    Command(C),
    Endm,
    Eof,
    Eol,
    Error(E),
    Ident(I),
    Literal(L),
    Macro,
    OpeningParenthesis,
    Plus,
}

pub fn tokenize(src: &str) -> self::lexer::Lexer {
    self::lexer::Lexer::new(src)
}

pub fn parse_token_seq<Id, S: Span, I, F>(tokens: I, actions: F)
where
    I: Iterator<Item = (Token<Id>, S)>,
    F: FileContext<Id, keyword::Command, Literal<Id>, S>,
{
    self::parser::parse_src(tokens, actions);
}

#[derive(Clone, Debug, PartialEq)]
pub enum Literal<S> {
    Operand(Operand),
    Number(i32),
    String(S),
}

pub trait FileContext<I, C, L, S>
where
    Self: DiagnosticsListener<S> + Sized,
{
    type StmtContext: StmtContext<I, C, L, S, Parent = Self>;
    fn enter_stmt(self, label: Option<(I, S)>) -> Self::StmtContext;
}

pub trait StmtContext<I, C, L, S>
where
    Self: DiagnosticsListener<S> + Sized,
{
    type CommandContext: CommandContext<S, Ident = I, Command = C, Literal = L, Parent = Self>;
    type MacroParamsContext: MacroParamsContext<
        S,
        Ident = I,
        Command = C,
        Literal = L,
        Parent = Self,
    >;
    type MacroInvocationContext: MacroInvocationContext<S, Token = Token<I, C, L>, Parent = Self>;
    type Parent;
    fn enter_command(self, name: (C, S)) -> Self::CommandContext;
    fn enter_macro_def(self, keyword: S) -> Self::MacroParamsContext;
    fn enter_macro_invocation(self, name: (I, S)) -> Self::MacroInvocationContext;
    fn exit(self) -> Self::Parent;
}

pub trait CommandContext<S>
where
    Self: DiagnosticsListener<S> + Sized,
{
    type Ident;
    type Command;
    type Literal;
    type ArgContext: ExprContext<S, Ident = Self::Ident, Literal = Self::Literal, Parent = Self>;
    type Parent;
    fn add_argument(self) -> Self::ArgContext;
    fn exit(self) -> Self::Parent;
}

pub trait ExprContext<S>
where
    Self: DiagnosticsListener<S>,
{
    type Ident;
    type Literal;
    type Parent;
    fn push_atom(&mut self, atom: (ExprAtom<Self::Ident, Self::Literal>, S));
    fn apply_operator(&mut self, operator: (ExprOperator, S));
    fn exit(self) -> Self::Parent;
}

#[derive(Clone, Debug, PartialEq)]
pub enum ExprAtom<I, L> {
    Ident(I),
    Literal(L),
}

#[derive(Clone, Debug, PartialEq)]
pub enum ExprOperator {
    Parentheses,
    Plus,
}

pub trait MacroParamsContext<S>: DiagnosticsListener<S> {
    type Ident;
    type Command;
    type Literal;
    type MacroBodyContext: TokenSeqContext<
        S,
        Token = Token<Self::Ident, Self::Command, Self::Literal>,
        Parent = Self::Parent,
    >;
    type Parent;
    fn add_parameter(&mut self, param: (Self::Ident, S));
    fn exit(self) -> Self::MacroBodyContext;
}

pub trait MacroInvocationContext<S>
where
    Self: DiagnosticsListener<S> + Sized,
{
    type Token;
    type Parent;
    type MacroArgContext: TokenSeqContext<S, Token = Self::Token, Parent = Self>;
    fn enter_macro_arg(self) -> Self::MacroArgContext;
    fn exit(self) -> Self::Parent;
}

pub trait TokenSeqContext<S>
where
    Self: DiagnosticsListener<S>,
{
    type Token;
    type Parent;
    fn push_token(&mut self, token: (Self::Token, S));
    fn exit(self) -> Self::Parent;
}