gbf_core/decompiler/ast/
mod.rs#![deny(missing_docs)]
use crate::decompiler::ast::visitors::AstVisitor;
use assignable::AssignableKind;
use ast_vec::AstVec;
use bin_op::BinaryOperationNode;
use expr::ExprKind;
use func_call::FunctionCallNode;
use function::FunctionNode;
use identifier::IdentifierNode;
use literal::LiteralNode;
use member_access::MemberAccessNode;
use meta::MetaNode;
use ret::ReturnNode;
use serde::{Deserialize, Serialize};
use ssa::SsaVersion;
use statement::StatementNode;
use thiserror::Error;
use unary_op::UnaryOperationNode;
use visitors::{emit_context::EmitContext, emitter::Gs2Emitter};
pub mod assignable;
pub mod ast_enum_type;
pub mod ast_vec;
pub mod bin_op;
pub mod expr;
pub mod func_call;
pub mod function;
pub mod identifier;
pub mod literal;
pub mod member_access;
pub mod meta;
pub mod ret;
pub mod ssa;
pub mod statement;
pub mod unary_op;
pub mod visitors;
#[derive(Debug, Error)]
pub enum AstNodeError {
#[error("Expected {0}, found {1}")]
InvalidConversion(String, String),
#[error("Invalid {0} operand for {1}. Expected types in {2:?}, found {3}")]
InvalidOperand(String, String, Vec<String>, String),
#[error("Cannot invert {0}")]
CannotInvert(String),
}
pub trait AstVisitable: Clone {
fn clone_box(&self) -> Box<Self>
where
Self: Sized,
{
Box::new(self.clone())
}
fn accept(&self, visitor: &mut dyn AstVisitor);
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum AstKind {
Statement(StatementNode),
Function(FunctionNode),
Expression(ExprKind),
Return(ReturnNode),
Meta(MetaNode), Empty,
}
impl AstVisitable for AstKind {
fn accept(&self, visitor: &mut dyn AstVisitor) {
match self {
AstKind::Expression(expr) => expr.accept(visitor),
AstKind::Meta(meta) => meta.accept(visitor),
AstKind::Statement(stmt) => stmt.accept(visitor),
AstKind::Function(func) => func.accept(visitor),
AstKind::Return(ret) => ret.accept(visitor),
AstKind::Empty => {}
}
}
}
pub fn emit<N>(node: N) -> String
where
N: Into<AstKind>,
{
let node: AstKind = node.into();
let mut emit = Gs2Emitter::new(EmitContext::default());
node.accept(&mut emit);
emit.output().to_string()
}
pub fn comment<N>(node: N, comment: &str) -> MetaNode
where
N: Into<AstKind>,
{
MetaNode::new(
node.into().into(),
Some(comment.to_string()),
None,
Default::default(),
)
}
pub fn statement<L, R>(lhs: L, rhs: R) -> StatementNode
where
L: Into<Box<AssignableKind>>,
R: Into<Box<ExprKind>>,
{
StatementNode {
lhs: lhs.into(),
rhs: rhs.into(),
}
}
pub fn create_return<N>(node: N) -> ReturnNode
where
N: Into<Box<ExprKind>>,
{
ReturnNode::new(node.into())
}
pub fn member_access<L, R>(lhs: L, rhs: R) -> Result<MemberAccessNode, AstNodeError>
where
L: Into<Box<AssignableKind>>,
R: Into<Box<AssignableKind>>,
{
MemberAccessNode::new(lhs.into(), rhs.into())
}
pub fn new_id(name: &str) -> IdentifierNode {
IdentifierNode::new(name)
}
pub fn new_id_with_version(name: &str, version: SsaVersion) -> IdentifierNode {
IdentifierNode::with_ssa(name, version)
}
pub fn new_fn_call<N, A>(name: N, args: A) -> FunctionCallNode
where
N: Into<AssignableKind>,
A: Into<AstVec<ExprKind>>,
{
FunctionCallNode::new(name.into(), args.into())
}
pub fn new_bin_op<L, R>(
lhs: L,
rhs: R,
op_type: bin_op::BinOpType,
) -> Result<BinaryOperationNode, AstNodeError>
where
L: Into<Box<ExprKind>>,
R: Into<Box<ExprKind>>,
{
BinaryOperationNode::new(lhs.into(), rhs.into(), op_type)
}
pub fn new_unary_op<A>(
operand: A,
op_type: unary_op::UnaryOpType,
) -> Result<UnaryOperationNode, AstNodeError>
where
A: Into<Box<ExprKind>>,
{
UnaryOperationNode::new(operand.into(), op_type)
}
pub fn new_str(value: &str) -> LiteralNode {
LiteralNode::String(value.to_string())
}
pub fn new_num(value: i32) -> LiteralNode {
LiteralNode::Number(value)
}
pub fn new_float(value: &str) -> LiteralNode {
LiteralNode::Float(value.to_string())
}
pub fn new_bool(value: bool) -> LiteralNode {
LiteralNode::Boolean(value)
}