Created
February 6, 2021 21:20
-
-
Save ExpHP/cb14c27a352a05dcc8b304d328188211 to your computer and use it in GitHub Desktop.
ast
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use bstr::{BString}; | |
use crate::meta; | |
use crate::var::{VarId}; | |
use crate::ident::Ident; | |
use crate::pos::{Sp, Span}; | |
use crate::error::CompileError; | |
use crate::type_system::{self, NameId}; | |
// ============================================================================= | |
/// Type used in the AST for the span of a single token with no useful data. | |
/// | |
/// This can be used for things like keywords. We use [`Sp`]`<()>` instead of [`Span`] | |
/// because the latter would have an impact on equality tests. | |
pub type TokenSpan = Sp<()>; | |
/// Represents a complete script file. | |
#[derive(Debug, Clone, PartialEq)] | |
pub struct Script { | |
pub mapfiles: Vec<Sp<LitString>>, | |
pub image_sources: Vec<Sp<LitString>>, | |
pub items: Vec<Sp<Item>>, | |
} | |
#[derive(Debug, Clone, PartialEq)] | |
pub enum Item { | |
Func { | |
inline: Option<TokenSpan>, | |
keyword: Sp<FuncKeyword>, | |
name: Sp<Ident>, | |
params: Vec<(Sp<VarDeclKeyword>, Sp<Ident>)>, | |
/// `Some` for definitions, `None` for declarations. | |
code: Option<Block>, | |
}, | |
AnmScript { | |
keyword: TokenSpan, | |
number: Option<Sp<i32>>, | |
name: Sp<Ident>, | |
code: Block, | |
}, | |
Meta { | |
keyword: Sp<MetaKeyword>, | |
name: Option<Sp<Ident>>, | |
fields: Sp<meta::Fields>, | |
}, | |
FileList { | |
keyword: Sp<FileListKeyword>, | |
files: Vec<Sp<LitString>> | |
}, | |
} | |
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] | |
pub enum FuncKeyword { | |
Type(FuncReturnType), | |
Sub, | |
Timeline, | |
} | |
string_enum!{ | |
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] | |
pub enum FuncReturnType { | |
#[str = "int"] Int, | |
#[str = "float"] Float, | |
#[str = "void"] Void, | |
} | |
} | |
string_enum!{ | |
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] | |
pub enum FileListKeyword { | |
#[str = "anim"] Anim, | |
#[str = "ecli"] Ecli, | |
} | |
} | |
string_enum! { | |
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] | |
pub enum MetaKeyword { | |
/// `entry` block for a texture in ANM. | |
#[str = "entry"] Entry, | |
#[str = "meta"] Meta, | |
} | |
} | |
// ============================================================================= | |
#[derive(Debug, Clone, PartialEq)] | |
pub struct Stmt { | |
pub time: i32, | |
pub body: StmtBody, | |
} | |
// FIXME: awkward now that `label:` is implemented as a statement instead | |
#[derive(Debug, Clone, PartialEq)] | |
pub enum StmtLabel { | |
Difficulty { | |
/// If `true`, the difficulty reverts to `"*"` after the next statement. | |
temporary: bool, | |
flags: DifficultyLabel, | |
}, | |
} | |
/// Represents a statement, including the ';' if required, but | |
/// without any labels. | |
#[derive(Debug, Clone, PartialEq)] | |
pub enum StmtBody { | |
Jump(StmtGoto), | |
CondJump { | |
keyword: Sp<CondKeyword>, | |
cond: Sp<Cond>, | |
jump: StmtGoto, | |
}, | |
Return { | |
keyword: TokenSpan, | |
value: Option<Sp<Expr>>, | |
}, | |
CondChain(StmtCondChain), | |
Loop { | |
keyword: TokenSpan, | |
block: Block, | |
}, | |
While { | |
while_keyword: TokenSpan, | |
do_keyword: Option<TokenSpan>, | |
cond: Sp<Cond>, | |
block: Block, | |
}, | |
Times { | |
keyword: TokenSpan, | |
clobber: Option<Sp<Var>>, | |
count: Sp<Expr>, | |
block: Block, | |
}, | |
/// Expression followed by a semicolon. | |
/// | |
/// This is primarily for void-type "expressions" like raw instruction | |
/// calls (which are grammatically indistinguishable from value-returning | |
/// function calls), but may also represent a stack push in ECL. | |
Expr(Sp<Expr>), | |
Assignment { | |
var: Sp<Var>, | |
op: Sp<AssignOpKind>, | |
value: Sp<Expr>, | |
}, | |
Declaration { | |
keyword: Sp<VarDeclKeyword>, | |
vars: Vec<Sp<(Sp<Var>, Option<Sp<Expr>>)>>, | |
}, | |
/// An explicit subroutine call. (ECL only) | |
/// | |
/// Will always have at least one of either the `@` or `async`. | |
/// (otherwise, it will fall under `Expr` instead) | |
CallSub { | |
at_symbol: bool, | |
async_: Option<CallAsyncKind>, | |
func: Sp<Ident>, | |
args: Vec<Sp<Expr>>, | |
}, | |
/// An interrupt label: `interrupt[2]:`. | |
/// | |
/// Because this compiles to an instruction, we store it as a statement in the AST rather than | |
/// as a label. | |
InterruptLabel(Sp<i32>), | |
/// A virtual instruction representing a label that can be jumped to. | |
Label(Sp<Ident>), | |
/// A virtual instruction that marks the end of a variable's lexical scope. | |
/// | |
/// Blocks are eliminated during early compilation passes, leaving behind these as the only | |
/// remaining way of identifying the end of a variable's scope. They are used during lowering | |
/// to determine when to release resources (like registers) held by locals. | |
ScopeEnd(NameId), | |
/// A virtual instruction that completely disappears during compilation. | |
/// | |
/// This is a trivial statement that doesn't even compile to a `nop();`. | |
/// It is inserted at the beginning and end of code blocks in order to help implement some | |
/// of the following things: | |
/// | |
/// * A time label at the end of a block. | |
/// * A time label at the beginning of a loop's body. | |
/// | |
/// Note that these may also appear in the middle of a block in the AST if a transformation | |
/// pass has e.g. inlined the contents of one block into another. | |
NoInstruction, | |
} | |
/// The body of a `goto` statement, without the `;`. | |
#[derive(Debug, Clone, PartialEq)] | |
pub struct StmtGoto { | |
pub destination: Sp<Ident>, | |
pub time: Option<i32>, | |
} | |
#[derive(Debug, Clone, PartialEq)] | |
pub struct StmtCondChain { | |
// FIXME why do these have spans | |
pub cond_blocks: Vec<Sp<CondBlock>>, | |
pub else_block: Option<Block>, | |
} | |
#[derive(Debug, Clone, PartialEq)] | |
pub struct CondBlock { | |
pub keyword: Sp<CondKeyword>, | |
pub cond: Sp<Cond>, | |
pub block: Block, | |
} | |
#[derive(Debug, Clone, PartialEq)] | |
pub enum Cond { | |
Expr(Sp<Expr>), | |
/// This is how jmpDec works in register-based languages. | |
/// | |
/// (stack-based ECL instead has a decrement operator that is postdec) | |
PreDecrement(Sp<Var>), | |
} | |
#[derive(Debug, Clone, PartialEq)] | |
pub enum CallAsyncKind { | |
CallAsync, | |
CallAsyncId(Box<Sp<Expr>>), | |
} | |
string_enum! { | |
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] | |
pub enum CondKeyword { | |
#[str = "if"] If, | |
#[str = "unless"] Unless, | |
} | |
} | |
// TODO: Parse | |
pub type DifficultyLabel = BString; | |
string_enum! { | |
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] | |
pub enum AssignOpKind { | |
#[str = "="] Assign, | |
#[str = "+="] Add, | |
#[str = "-="] Sub, | |
#[str = "*="] Mul, | |
#[str = "/="] Div, | |
#[str = "%="] Rem, | |
#[str = "|="] BitOr, | |
#[str = "^="] BitXor, | |
#[str = "&="] BitAnd, | |
} | |
} | |
/// A braced series of statements, typically written at an increased indentation level. | |
/// | |
/// Every Block always has at least two [`Stmt`]s, as on creation it is bookended by dummy | |
/// statements to ensure it has a well-defined start and end time. | |
#[derive(Debug, Clone, PartialEq)] | |
pub struct Block(pub Vec<Sp<Stmt>>); | |
// ============================================================================= | |
#[derive(Debug, Clone, PartialEq)] | |
pub enum Expr { | |
Ternary { | |
cond: Box<Sp<Expr>>, | |
question: Sp<()>, | |
left: Box<Sp<Expr>>, | |
colon: Sp<()>, | |
right: Box<Sp<Expr>>, | |
}, | |
Binop(Box<Sp<Expr>>, Sp<BinopKind>, Box<Sp<Expr>>), | |
Call { | |
func: Sp<Ident>, | |
args: Vec<Sp<Expr>>, | |
}, | |
Unop(Sp<UnopKind>, Box<Sp<Expr>>), | |
LitInt { | |
value: i32, | |
/// A hint to the formatter that it should use hexadecimal. | |
/// (may not necessarily represent the original radix of a parsed token) | |
hex: bool, | |
}, | |
LitFloat { value: f32 }, | |
LitString(LitString), | |
Var(Sp<Var>), | |
} | |
#[derive(Debug, Clone, PartialEq)] | |
pub enum Var { | |
/// A variable mentioned by name, possibly with a type sigil. | |
/// | |
/// There should be none of these left in the AST after name resolution. | |
Named { | |
ty_sigil: Option<VarReadType>, | |
ident: Ident, | |
}, | |
/// A resolved variable. | |
/// | |
/// It can be created by performing [name resolution](crate::type_system::TypeSystem::resolve_names). | |
/// Additionally, variable accesses written in raw notation (e.g. `[10004.0]`) | |
/// parse directly to this form. | |
Resolved { | |
ty_sigil: Option<VarReadType>, | |
var_id: VarId, | |
}, | |
} | |
string_enum! { | |
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] | |
pub enum BinopKind { | |
#[str = "+"] Add, | |
#[str = "-"] Sub, | |
#[str = "*"] Mul, | |
#[str = "/"] Div, | |
#[str = "%"] Rem, | |
#[str = "=="] Eq, | |
#[str = "!="] Ne, | |
#[str = "<"] Lt, | |
#[str = "<="] Le, | |
#[str = ">"] Gt, | |
#[str = ">="] Ge, | |
#[str = "|"] BitOr, | |
#[str = "^"] BitXor, | |
#[str = "&"] BitAnd, | |
#[str = "||"] LogicOr, | |
#[str = "&&"] LogicAnd, | |
} | |
} | |
string_enum! { | |
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] | |
pub enum UnopKind { | |
#[str = "!"] Not, | |
#[str = "-"] Neg, | |
#[str = "sin"] Sin, | |
#[str = "cos"] Cos, | |
#[str = "sqrt"] Sqrt, | |
#[str = "_S"] CastI, | |
#[str = "_f"] CastF, | |
} | |
} | |
// ============================================================================= | |
string_enum! { | |
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] | |
pub enum VarDeclKeyword { | |
#[str = "int"] Int, | |
#[str = "float"] Float, | |
#[str = "var"] Var, | |
} | |
} | |
/// The hinted type of a variable at a usage site, which can differ from its inherent type. | |
/// | |
/// E.g. a variable's type may be hinted with the use of `$` or `%` prefixes. | |
/// (or it might not be hinted, meaning its type must be determined through other means) | |
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] | |
pub enum VarReadType { | |
Int, | |
Float, | |
} | |
/// A literal string, which may be encoded in UTF-8 or Shift-JIS. | |
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] | |
pub struct LitString<S=BString> { | |
pub string: S, | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment