builtins/
conversions.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use bridge_adapters::add_builtin;
use compile_state::state::{SloshVm, SloshVmTrait};
use slvm::{VMError, VMResult, Value};

fn to_sym(vm: &mut SloshVm, registers: &[Value]) -> VMResult<Value> {
    let mut i = registers.iter();
    if let (Some(string), None) = (i.next(), i.next()) {
        match string {
            Value::StringConst(i) => Ok(Value::Symbol(*i)),
            Value::Keyword(i) => Ok(Value::Symbol(*i)),
            Value::Symbol(i) => Ok(Value::Symbol(*i)),
            _ => {
                let string = string.pretty_value(vm);
                let i = vm.intern(&string);
                Ok(Value::Symbol(i))
            }
        }
    } else {
        Err(VMError::new_conversion("->sym: takes one arg".to_string()))
    }
}

fn to_key(vm: &mut SloshVm, registers: &[Value]) -> VMResult<Value> {
    let mut i = registers.iter();
    if let (Some(string), None) = (i.next(), i.next()) {
        match string {
            Value::StringConst(i) => Ok(Value::Keyword(*i)),
            Value::Keyword(i) => Ok(Value::Keyword(*i)),
            Value::Symbol(i) => Ok(Value::Keyword(*i)),
            _ => {
                let string = string.pretty_value(vm);
                let i = vm.intern(&string);
                Ok(Value::Keyword(i))
            }
        }
    } else {
        Err(VMError::new_conversion("->key: takes one arg".to_string()))
    }
}

fn global_ref(vm: &mut SloshVm, registers: &[Value]) -> VMResult<Value> {
    let mut i = registers.iter();
    if let (Some(symbol), None) = (i.next(), i.next()) {
        match symbol {
            Value::Symbol(i) => {
                if let Some(slot) = vm.global_intern_slot(*i) {
                    Ok(vm.get_global(slot))
                } else {
                    Err(VMError::new_conversion("ref: not a global var".to_string()))
                }
            }
            _ => Err(VMError::new_conversion(format!(
                "ref: expected a symbol, got a {}",
                symbol.display_type(vm)
            ))),
        }
    } else {
        Err(VMError::new_conversion("ref: takes one arg".to_string()))
    }
}

fn is_def(vm: &mut SloshVm, registers: &[Value]) -> VMResult<Value> {
    let mut i = registers.iter();
    if let (Some(symbol), None) = (i.next(), i.next()) {
        match symbol {
            Value::Symbol(i) => {
                if let Some(_slot) = vm.global_intern_slot(*i) {
                    Ok(Value::True)
                } else {
                    Ok(Value::False)
                }
            }
            _ => Err(VMError::new_conversion(format!(
                "def?: expected a symbol, got a {}",
                symbol.display_type(vm)
            ))),
        }
    } else {
        Err(VMError::new_conversion("def?: takes one arg".to_string()))
    }
}

pub fn add_conv_builtins(env: &mut SloshVm) {
    add_builtin(
        env,
        "->sym",
        to_sym,
        //space is needed here for test to pass do not know why
        r#" Usage: (->sym exp) -> symbol

Converts exp to a symbol.

Section: conversion
"#,
    );
    add_builtin(
        env,
        "->key",
        to_key,
        r#"Usage: (->key exp) -> keyword

Converts exp to a keyword.

Section: conversion
"#,
    );
    add_builtin(
        env,
        "ref",
        global_ref,
        r#"Usage: (ref symbol) -> Value

If symbol is defined then return the thing it references.

Section: conversion
"#,
    );
    add_builtin(
        env,
        "def?",
        is_def,
        r#"Usage: (def? symbol) -> #t/#f

If symbol is defined then return true else false.

Section: conversion
"#,
    );
}