thru-abi-gen 0.2.30

ABI code generation utilities for the Thru blockchain
Documentation
use crate::abi::resolved::ResolvedType;
use crate::codegen::shared::ir::*;
use crate::codegen::ts_gen::helpers::sanitize_type_ident;

pub fn emit_ir_constant(resolved_type: &ResolvedType, type_ir: &TypeIr) -> String {
    let const_name = ir_constant_name(resolved_type);
    let mut out = String::new();
    out.push_str(&format!(
        "const {} = {{\n  typeName: \"{}\",\n  root: {}\n}} as const;\n\n",
        const_name,
        resolved_type.name,
        emit_ir_node(&type_ir.root, 2)
    ));
    out
}

pub fn ir_constant_name(resolved_type: &ResolvedType) -> String {
    format!(
        "__tn_ir_{}",
        sanitize_type_ident(resolved_type.name.as_str())
    )
}

fn emit_ir_node(node: &IrNode, indent: usize) -> String {
    match node {
        IrNode::ZeroSize { .. } => format!("{{ op: \"zero\" }}"),
        IrNode::Const(c) => format!("{{ op: \"const\", value: {}n }}", c.value),
        IrNode::FieldRef(field) => {
            let param = field
                .parameter
                .as_deref()
                .unwrap_or_else(|| field.path.as_str());
            format!(
                "{{ op: \"field\", param: \"{}\" }}",
                param.replace('\"', "\\\"")
            )
        }
        IrNode::AddChecked(add) => format!(
            "{{ op: \"add\", left: {}, right: {} }}",
            emit_ir_node(&add.left, indent),
            emit_ir_node(&add.right, indent)
        ),
        IrNode::MulChecked(mul) => format!(
            "{{ op: \"mul\", left: {}, right: {} }}",
            emit_ir_node(&mul.left, indent),
            emit_ir_node(&mul.right, indent)
        ),
        IrNode::AlignUp(align) => format!(
            "{{ op: \"align\", alignment: {}, node: {} }}",
            align.alignment,
            emit_ir_node(&align.node, indent)
        ),
        IrNode::Switch(sw) => {
            let mut cases = String::new();
            cases.push('[');
            for (idx, case) in sw.cases.iter().enumerate() {
                if idx > 0 {
                    cases.push_str(", ");
                }
                cases.push_str(&format!(
                    "{{ value: {}, node: {} }}",
                    case.tag_value,
                    emit_ir_node(&case.node, indent + 2)
                ));
            }
            cases.push(']');
            let default = sw
                .default
                .as_ref()
                .map(|node| emit_ir_node(node, indent + 2))
                .map(|s| format!(", default: {}", s))
                .unwrap_or_default();
            format!(
                "{{ op: \"switch\", tag: \"{}\", cases: {}{} }}",
                sw.tag.replace('\"', "\\\""),
                cases,
                default
            )
        }
        IrNode::CallNested(call) => {
            let mut args = String::new();
            args.push('[');
            for (idx, arg) in call.arguments.iter().enumerate() {
                if idx > 0 {
                    args.push_str(", ");
                }
                args.push_str(&format!(
                    "{{ name: \"{}\", source: \"{}\" }}",
                    arg.name.replace('\"', "\\\""),
                    arg.value.replace('\"', "\\\"")
                ));
            }
            args.push(']');
            format!(
                "{{ op: \"call\", typeName: \"{}\", args: {} }}",
                call.type_name.replace('\"', "\\\""),
                args
            )
        }
        IrNode::SumOverArray(node) => format!(
            "{{ op: \"sumOverArray\", count: {}, elementTypeName: \"{}\", fieldName: \"{}\" }}",
            emit_ir_node(&node.count, indent),
            node.element_type_name.replace('\"', "\\\""),
            node.field_name.replace('\"', "\\\"")
        ),
    }
}