1
//! `SPLIT-*` accessors — `VALUE-NUM`, `VALUE-DENOM`, `VALUE` (combined
2
//! ratio), `RECONCILE-STATE`, `RECONCILE-DATE`. Each takes an entity
3
//! index and reads a single field from `SplitData`.
4

            
5
use crate::ast::{Expr, WasmType};
6
use crate::compiler::context::CompileContext;
7
use crate::compiler::emit::FunctionEmitter;
8
use crate::compiler::expr::{LOCAL_TEMP_I32, eval_value};
9
use crate::error::Result;
10
use crate::runtime::SymbolTable;
11

            
12
use super::{arity_check, compile_idx_to_stack, emit_entity_data_offset};
13

            
14
284
pub(super) fn split_value_num(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
15
284
    arity_check("SPLIT-VALUE-NUM", args, 1)?;
16
284
    eval_value(symbols, &args[0])?;
17
284
    Ok(Expr::WasmRuntime(WasmType::Ratio))
18
284
}
19

            
20
142
pub(super) fn compile_split_value_num_to_stack(
21
142
    ctx: &mut CompileContext,
22
142
    emit: &mut FunctionEmitter,
23
142
    symbols: &mut SymbolTable,
24
142
    args: &[Expr],
25
142
) -> Result<WasmType> {
26
142
    arity_check("SPLIT-VALUE-NUM", args, 1)?;
27
142
    compile_idx_to_stack(ctx, emit, symbols, &args[0])?;
28
142
    emit_entity_data_offset(ctx, emit, LOCAL_TEMP_I32)?;
29
142
    emit.i64_load(32); // value_num at SplitData offset 32
30
142
    emit.call(ctx.ids.ratio_from_i64);
31
142
    Ok(WasmType::Ratio)
32
142
}
33

            
34
284
pub(super) fn split_value_denom(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
35
284
    arity_check("SPLIT-VALUE-DENOM", args, 1)?;
36
284
    eval_value(symbols, &args[0])?;
37
284
    Ok(Expr::WasmRuntime(WasmType::Ratio))
38
284
}
39

            
40
142
pub(super) fn compile_split_value_denom_to_stack(
41
142
    ctx: &mut CompileContext,
42
142
    emit: &mut FunctionEmitter,
43
142
    symbols: &mut SymbolTable,
44
142
    args: &[Expr],
45
142
) -> Result<WasmType> {
46
142
    arity_check("SPLIT-VALUE-DENOM", args, 1)?;
47
142
    compile_idx_to_stack(ctx, emit, symbols, &args[0])?;
48
142
    emit_entity_data_offset(ctx, emit, LOCAL_TEMP_I32)?;
49
142
    emit.i64_load(40); // value_denom at SplitData offset 40
50
142
    emit.call(ctx.ids.ratio_from_i64);
51
142
    Ok(WasmType::Ratio)
52
142
}
53

            
54
/// (split-value idx) — reads both `value_num` and `value_denom`, returns proper Ratio
55
2556
pub(super) fn split_value(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
56
2556
    arity_check("SPLIT-VALUE", args, 1)?;
57
2556
    eval_value(symbols, &args[0])?;
58
2556
    Ok(Expr::WasmRuntime(WasmType::Ratio))
59
2556
}
60

            
61
710
pub(super) fn compile_split_value_to_stack(
62
710
    ctx: &mut CompileContext,
63
710
    emit: &mut FunctionEmitter,
64
710
    symbols: &mut SymbolTable,
65
710
    args: &[Expr],
66
710
) -> Result<WasmType> {
67
710
    arity_check("SPLIT-VALUE", args, 1)?;
68
710
    let temp = LOCAL_TEMP_I32;
69
    // Compute data offset, save in temp
70
710
    compile_idx_to_stack(ctx, emit, symbols, &args[0])?;
71
710
    emit_entity_data_offset(ctx, emit, temp)?;
72
710
    emit.local_set(temp);
73
    // Load value_num (i64 at offset 32)
74
710
    emit.local_get(temp);
75
710
    emit.i64_load(32);
76
    // Load value_denom (i64 at offset 40)
77
710
    emit.local_get(temp);
78
710
    emit.i64_load(40);
79
    // Construct ratio from num and denom
80
710
    emit.call(ctx.ids.ratio_new);
81
710
    Ok(WasmType::Ratio)
82
710
}
83

            
84
852
pub(super) fn split_reconcile_state(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
85
852
    arity_check("SPLIT-RECONCILE-STATE", args, 1)?;
86
852
    eval_value(symbols, &args[0])?;
87
852
    Ok(Expr::WasmRuntime(WasmType::I32))
88
852
}
89

            
90
284
pub(super) fn compile_split_reconcile_state_to_stack(
91
284
    ctx: &mut CompileContext,
92
284
    emit: &mut FunctionEmitter,
93
284
    symbols: &mut SymbolTable,
94
284
    args: &[Expr],
95
284
) -> Result<WasmType> {
96
284
    arity_check("SPLIT-RECONCILE-STATE", args, 1)?;
97
284
    compile_idx_to_stack(ctx, emit, symbols, &args[0])?;
98
284
    emit_entity_data_offset(ctx, emit, LOCAL_TEMP_I32)?;
99
284
    emit.i32_load8_u(48); // reconcile_state at SplitData offset 48
100
284
    Ok(WasmType::I32)
101
284
}
102

            
103
284
pub(super) fn split_reconcile_date(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
104
284
    arity_check("SPLIT-RECONCILE-DATE", args, 1)?;
105
284
    eval_value(symbols, &args[0])?;
106
284
    Ok(Expr::WasmRuntime(WasmType::Ratio))
107
284
}
108

            
109
142
pub(super) fn compile_split_reconcile_date_to_stack(
110
142
    ctx: &mut CompileContext,
111
142
    emit: &mut FunctionEmitter,
112
142
    symbols: &mut SymbolTable,
113
142
    args: &[Expr],
114
142
) -> Result<WasmType> {
115
142
    arity_check("SPLIT-RECONCILE-DATE", args, 1)?;
116
142
    compile_idx_to_stack(ctx, emit, symbols, &args[0])?;
117
142
    emit_entity_data_offset(ctx, emit, LOCAL_TEMP_I32)?;
118
142
    emit.i64_load(56); // reconcile_date at SplitData offset 56
119
142
    emit.call(ctx.ids.ratio_from_i64);
120
142
    Ok(WasmType::Ratio)
121
142
}
122

            
123
570
pub(super) fn split_account_name(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
124
570
    arity_check("SPLIT-ACCOUNT-NAME", args, 1)?;
125
569
    eval_value(symbols, &args[0])?;
126
569
    Ok(Expr::WasmRuntime(WasmType::StringRef))
127
570
}
128

            
129
/// `(split-account-name idx)` — copies the posting account's display name out
130
/// of the strings pool into a fresh `(array (mut i8))`, reading the
131
/// `account_name_offset` (u32) / `account_name_len` (u32) pair the serializer
132
/// wrote into `SplitData`. Mirrors the tag string reader; the length is a u32
133
/// here (a full `i32.load`), not the u16 a tag carries.
134
568
pub(super) fn compile_split_account_name_to_stack(
135
568
    ctx: &mut CompileContext,
136
568
    emit: &mut FunctionEmitter,
137
568
    symbols: &mut SymbolTable,
138
568
    args: &[Expr],
139
568
) -> Result<WasmType> {
140
    use std::mem::offset_of;
141
568
    arity_check("SPLIT-ACCOUNT-NAME", args, 1)?;
142

            
143
568
    let data_local = ctx.alloc_local(WasmType::I32)?;
144
568
    let str_off_local = ctx.alloc_local(WasmType::I32)?;
145
568
    let str_len_local = ctx.alloc_local(WasmType::I32)?;
146
568
    let pool_local = ctx.alloc_local(WasmType::I32)?;
147
568
    let arr_local = ctx.alloc_local(WasmType::StringRef)?;
148
568
    let idx_local = ctx.alloc_local(WasmType::I32)?;
149

            
150
568
    compile_idx_to_stack(ctx, emit, symbols, &args[0])?;
151
568
    emit_entity_data_offset(ctx, emit, LOCAL_TEMP_I32)?;
152
568
    emit.local_set(data_local);
153

            
154
568
    emit.local_get(data_local);
155
568
    emit.i32_load(offset_of!(scripting_format::SplitData, account_name_offset) as u64);
156
568
    emit.local_set(str_off_local);
157

            
158
568
    emit.local_get(data_local);
159
568
    emit.i32_load(offset_of!(scripting_format::SplitData, account_name_len) as u64);
160
568
    emit.local_set(str_len_local);
161

            
162
568
    emit.call(ctx.ids.get_input_offset()?);
163
568
    emit.i32_load(offset_of!(scripting_format::GlobalHeader, strings_pool_offset) as u64);
164
568
    emit.local_set(pool_local);
165

            
166
568
    let i8_array_idx = ctx.ids.ty_i8_array;
167
568
    emit.local_get(str_len_local);
168
568
    emit.array_new_default(i8_array_idx);
169
568
    emit.local_set(arr_local);
170

            
171
568
    emit.i32_const(0);
172
568
    emit.local_set(idx_local);
173
568
    emit.block_start();
174
568
    emit.loop_start();
175

            
176
568
    emit.local_get(idx_local);
177
568
    emit.local_get(str_len_local);
178
568
    emit.i32_ge_u();
179
568
    emit.br_if(1);
180

            
181
568
    emit.local_get(arr_local);
182
568
    emit.local_get(idx_local);
183
568
    emit.local_get(pool_local);
184
568
    emit.local_get(str_off_local);
185
568
    emit.i32_add();
186
568
    emit.local_get(idx_local);
187
568
    emit.i32_add();
188
568
    emit.i32_load8_u(0);
189
568
    emit.array_set(i8_array_idx);
190

            
191
568
    emit.local_get(idx_local);
192
568
    emit.i32_const(1);
193
568
    emit.i32_add();
194
568
    emit.local_set(idx_local);
195
568
    emit.br(0);
196
568
    emit.block_end(); // loop
197
568
    emit.block_end(); // block
198

            
199
568
    emit.local_get(arr_local);
200
568
    Ok(WasmType::StringRef)
201
568
}