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 super::NativeSpec;
5
use super::comparison::bool_result;
6
use crate::ast::{Expr, WasmType};
7
use crate::error::{Error, Result};
8
use crate::runtime::SymbolTable;
9

            
10
pub(super) const NATIVES: &[NativeSpec] = &[
11
    NativeSpec {
12
        name: "UPCASE-STRING",
13
        eval: upcase_string,
14
        stack: None,
15
        effect: Some(compile_upcase_string),
16
    },
17
    NativeSpec {
18
        name: "STRING=",
19
        eval: string_eq,
20
        stack: Some(compile_string_eq_to_stack),
21
        effect: None,
22
    },
23
];
24

            
25
415
pub(super) fn upcase_string(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
26
415
    if args.len() != 1 {
27
83
        return Err(Error::Arity {
28
83
            name: "UPCASE-STRING".to_string(),
29
83
            expected: 1,
30
83
            actual: args.len(),
31
83
        });
32
332
    }
33

            
34
332
    let arg = eval_value(symbols, &args[0])?;
35
332
    match arg {
36
249
        Expr::String(s) => Ok(Expr::String(s.to_uppercase())),
37
83
        other => Err(Error::Compile(format!(
38
83
            "UPCASE-STRING: expected string, got {}",
39
83
            format_expr(&other)
40
83
        ))),
41
    }
42
415
}
43

            
44
332
pub(super) fn compile_upcase_string(
45
332
    ctx: &mut CompileContext,
46
332
    emit: &mut FunctionEmitter,
47
332
    symbols: &mut SymbolTable,
48
332
    args: &[Expr],
49
332
) -> Result<()> {
50
332
    let result = upcase_string(symbols, args)?;
51
166
    compile_expr(ctx, emit, symbols, &result)
52
332
}
53

            
54
1494
pub(super) fn string_eq(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
55
1494
    if args.len() != 2 {
56
        return Err(Error::Arity {
57
            name: "STRING=".to_string(),
58
            expected: 2,
59
            actual: args.len(),
60
        });
61
1494
    }
62
1494
    let a = eval_value(symbols, &args[0])?;
63
1494
    let b = eval_value(symbols, &args[1])?;
64

            
65
1494
    if let (Expr::String(sa), Expr::String(sb)) = (&a, &b) {
66
        return Ok(bool_result(sa == sb));
67
1494
    }
68

            
69
1494
    Ok(Expr::WasmRuntime(WasmType::Bool))
70
1494
}
71

            
72
2407
pub(super) fn compile_string_eq_to_stack(
73
2407
    ctx: &mut CompileContext,
74
2407
    emit: &mut FunctionEmitter,
75
2407
    symbols: &mut SymbolTable,
76
2407
    args: &[Expr],
77
2407
) -> Result<WasmType> {
78
2407
    if args.len() != 2 {
79
83
        return Err(Error::Arity {
80
83
            name: "STRING=".to_string(),
81
83
            expected: 2,
82
83
            actual: args.len(),
83
83
        });
84
2324
    }
85
2324
    let a = eval_value(symbols, &args[0])?;
86
2324
    let b = eval_value(symbols, &args[1])?;
87

            
88
    // Constant fold
89
2324
    if let (Expr::String(sa), Expr::String(sb)) = (&a, &b) {
90
166
        emit.i32_const(i32::from(sa == sb));
91
166
        return Ok(WasmType::Bool);
92
2158
    }
93

            
94
    // Compile both args to stack as StringRef
95
2158
    compile_string_arg_to_stack(ctx, emit, symbols, &args[0], &a)?;
96
1909
    compile_string_arg_to_stack(ctx, emit, symbols, &args[1], &b)?;
97
1909
    emit.call(ctx.ids.string_eq);
98
1909
    Ok(WasmType::Bool)
99
2407
}
100

            
101
4067
fn compile_string_arg_to_stack(
102
4067
    ctx: &mut CompileContext,
103
4067
    emit: &mut FunctionEmitter,
104
4067
    symbols: &mut SymbolTable,
105
4067
    arg: &Expr,
106
4067
    resolved: &Expr,
107
4067
) -> Result<()> {
108
4067
    if let Expr::String(s) = resolved {
109
1909
        let data_idx = ctx.add_data(s.as_bytes())?;
110
1909
        emit.i32_const(0);
111
1909
        emit.i32_const(s.len() as i32);
112
1909
        emit.array_new_data(ctx.ids.ty_i8_array, data_idx);
113
    } else {
114
2158
        let ty = compile_for_stack(ctx, emit, symbols, arg)?;
115
2158
        if ty != WasmType::StringRef {
116
249
            return Err(Error::Compile(format!(
117
249
                "STRING= arguments must be strings, got {ty}"
118
249
            )));
119
1909
        }
120
    }
121
3818
    Ok(())
122
4067
}