1
use super::super::context::CompileContext;
2
use super::super::emit::FunctionEmitter;
3
use super::super::expr::{compile_expr, compile_for_stack, eval_value, format_expr};
4
use crate::ast::{Expr, WasmType};
5
use crate::error::{Error, Result};
6
use crate::runtime::SymbolTable;
7

            
8
pub(super) fn upcase_string(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
9
    if args.len() != 1 {
10
        return Err(Error::Arity {
11
            name: "UPCASE-STRING".to_string(),
12
            expected: 1,
13
            actual: args.len(),
14
        });
15
    }
16

            
17
    let arg = eval_value(symbols, &args[0])?;
18
    match arg {
19
        Expr::String(s) => Ok(Expr::String(s.to_uppercase())),
20
        other => Err(Error::Compile(format!(
21
            "UPCASE-STRING: expected string, got {}",
22
            format_expr(&other)
23
        ))),
24
    }
25
}
26

            
27
pub(super) fn compile_upcase_string(
28
    ctx: &mut CompileContext,
29
    emit: &mut FunctionEmitter,
30
    symbols: &mut SymbolTable,
31
    args: &[Expr],
32
) -> Result<()> {
33
    let result = upcase_string(symbols, args)?;
34
    compile_expr(ctx, emit, symbols, &result)
35
}
36

            
37
804
pub(super) fn string_eq(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
38
804
    if args.len() != 2 {
39
        return Err(Error::Arity {
40
            name: "STRING=".to_string(),
41
            expected: 2,
42
            actual: args.len(),
43
        });
44
804
    }
45
804
    let a = eval_value(symbols, &args[0])?;
46
804
    let b = eval_value(symbols, &args[1])?;
47

            
48
    // Constant fold if both are compile-time strings
49
804
    if let (Expr::String(sa), Expr::String(sb)) = (&a, &b) {
50
        return Ok(Expr::Bool(sa == sb));
51
804
    }
52

            
53
804
    Ok(Expr::WasmRuntime(WasmType::I32))
54
804
}
55

            
56
402
pub(super) fn compile_string_eq_to_stack(
57
402
    ctx: &mut CompileContext,
58
402
    emit: &mut FunctionEmitter,
59
402
    symbols: &mut SymbolTable,
60
402
    args: &[Expr],
61
402
) -> Result<WasmType> {
62
402
    if args.len() != 2 {
63
        return Err(Error::Arity {
64
            name: "STRING=".to_string(),
65
            expected: 2,
66
            actual: args.len(),
67
        });
68
402
    }
69
402
    let a = eval_value(symbols, &args[0])?;
70
402
    let b = eval_value(symbols, &args[1])?;
71

            
72
    // Constant fold
73
402
    if let (Expr::String(sa), Expr::String(sb)) = (&a, &b) {
74
        emit.i32_const(i32::from(sa == sb));
75
        return Ok(WasmType::I32);
76
402
    }
77

            
78
    // Compile both args to stack as StringRef
79
402
    compile_string_arg_to_stack(ctx, emit, symbols, &args[0], &a)?;
80
402
    compile_string_arg_to_stack(ctx, emit, symbols, &args[1], &b)?;
81
402
    emit.call(ctx.func("string_eq"));
82
402
    Ok(WasmType::I32)
83
402
}
84

            
85
804
fn compile_string_arg_to_stack(
86
804
    ctx: &mut CompileContext,
87
804
    emit: &mut FunctionEmitter,
88
804
    symbols: &mut SymbolTable,
89
804
    arg: &Expr,
90
804
    resolved: &Expr,
91
804
) -> Result<()> {
92
804
    if let Expr::String(s) = resolved {
93
402
        let data_idx = ctx.add_data(s.as_bytes());
94
402
        emit.i32_const(0);
95
402
        emit.i32_const(s.len() as i32);
96
402
        emit.array_new_data(ctx.type_idx("i8_array"), data_idx);
97
402
    } else {
98
402
        let ty = compile_for_stack(ctx, emit, symbols, arg)?;
99
402
        if ty != WasmType::StringRef {
100
            return Err(Error::Compile(format!(
101
                "STRING= arguments must be strings, got {ty}"
102
            )));
103
402
        }
104
    }
105
804
    Ok(())
106
804
}
107

            
108
pub(super) fn compile_string_eq(
109
    ctx: &mut CompileContext,
110
    emit: &mut FunctionEmitter,
111
    symbols: &mut SymbolTable,
112
    args: &[Expr],
113
) -> Result<()> {
114
    let ty = compile_string_eq_to_stack(ctx, emit, symbols, args)?;
115
    super::super::expr::serialize_stack_to_output(ctx, emit, ty);
116
    Ok(())
117
}