ltk_ritobin 0.9.0

Ritobin text format parser and writer for League Toolkit
Documentation
use ltk_hash::{BinHash, Hash as _};
use ltk_meta::PropertyKind;

use crate::{
    ast::{
        builder::Builder,
        diagnostics::{
            Diagnostic::{self, *},
            RitoTypeOrVirtual,
        },
        hash::HashedLiteral,
        Object, Value,
    },
    cst::{ChildrenExt as _, Kind},
    parse::{Token, TokenKind},
    Node, RitoType,
};

impl<'a> Builder<'a> {
    pub(crate) fn resolve_class_hash(
        &mut self,
        token: &Token,
    ) -> Result<HashedLiteral<BinHash>, Diagnostic> {
        match token {
            Token {
                kind: TokenKind::Name,
                span,
            } => Ok(HashedLiteral::new(
                *span,
                crate::ast::hash::Originally::Name,
                BinHash::hash_str(&self.text[span]),
            )),
            Token {
                kind: TokenKind::HexLit,
                span,
            } => match Value::eval_unknown_hash(self.text, *span)? {
                Value::Hash(hash) => Ok(hash),
                value => Err(TypeMismatch {
                    span: value.span(),
                    expected: RitoType::simple(PropertyKind::Hash).into(),
                    expected_span: None,
                    got: value.rito_type().into(),
                }),
            },
            _ => Err(InvalidHash(token.span)),
        }
    }
    pub(crate) fn resolve_class(
        &mut self,
        class: &Node,
        hint: RitoType,
    ) -> Result<Value, Diagnostic> {
        let children = class.children.get(self.cst);
        let Some(name_token) = children.first().and_then(|c| c.token(self.cst)) else {
            return Err(InvalidHash(class.span));
        };
        let class_hash = self.resolve_class_hash(name_token)?;

        if !matches!(hint.base, PropertyKind::Struct | PropertyKind::Embedded) {
            return Err(TypeMismatch {
                span: name_token.span,
                expected: RitoType::simple(hint.base).into(),
                expected_span: None,
                got: RitoTypeOrVirtual::StructOrEmbedded,
            });
        }

        let properties = match children.find_tree(self.cst, Kind::Block) {
            Some(block) => self.resolve_body_properties(block, hint),
            None => Vec::new(),
        };

        let ast_struct = Object {
            class_hash,
            span: class.span,
            properties,
        };

        Ok(match hint.base {
            PropertyKind::Struct => Value::Struct(ast_struct),
            PropertyKind::Embedded => Value::Embedded(ast_struct),
            _ => unreachable!(),
        })
    }
}