gbf_core/decompiler/ast/
statement.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#![deny(missing_docs)]

use gbf_macros::AstNodeTransform;
use serde::{Deserialize, Serialize};

use super::{
    assignable::AssignableKind, expr::ExprKind, visitors::AstVisitor, AstKind, AstNodeError,
};
use crate::decompiler::ast::AstVisitable;

/// Represents a statement node in the AST, such as `variable = value`.
#[derive(Debug, Clone, Serialize, Deserialize, Eq, AstNodeTransform)]
#[convert_to(AstKind::Statement)]
pub struct StatementNode {
    /// The left-hand side of the statement, usually a variable.
    pub lhs: Box<AssignableKind>,
    /// The right-hand side of the statement, the value to assign.
    pub rhs: Box<ExprKind>,
}

impl StatementNode {
    /// Creates a new `StatementNode` after validating `lhs` and `rhs` types.
    ///
    /// # Arguments
    /// - `lhs` - The left-hand side of the statement.
    /// - `rhs` - The right-hand side of the statement.
    ///
    /// # Returns
    /// A new `StatementNode`.
    ///
    /// # Errors
    /// Returns an `AstNodeError` if `lhs` or `rhs` is of an unsupported type.
    pub fn new(lhs: Box<AssignableKind>, rhs: Box<ExprKind>) -> Result<Self, AstNodeError> {
        Ok(Self { lhs, rhs })
    }
}

impl AstVisitable for StatementNode {
    /// Accepts the visitor and calls the appropriate visit method.
    fn accept(&self, visitor: &mut dyn AstVisitor) {
        visitor.visit_statement(self);
    }
}

// == Other implementations for statement ==
impl PartialEq for StatementNode {
    fn eq(&self, other: &Self) -> bool {
        self.lhs == other.lhs && self.rhs == other.rhs
    }
}

#[cfg(test)]
mod tests {
    use crate::decompiler::ast::{emit, member_access, new_id, new_str, statement, AstNodeError};

    #[test]
    fn test_statement_emit() -> Result<(), AstNodeError> {
        let stmt = statement(new_id("test1"), new_id("test2"));
        assert_eq!(emit(stmt), "test1 = test2;");

        // player.chat = "Hello, world!";
        let stmt = statement(
            member_access(new_id("player"), new_id("chat"))?,
            new_str("Hello, world!"),
        );
        assert_eq!(emit(stmt), "player.chat = \"Hello, world!\";");
        Ok(())
    }
}