silt_lua/
lib.rs

1use error::ErrorTuple;
2use lua::Lua;
3use value::Value;
4
5mod chunk;
6mod code;
7pub mod compiler;
8mod error;
9mod function;
10mod lexer;
11pub mod lua;
12pub mod prelude;
13pub mod standard;
14pub mod table;
15mod token;
16mod userdata;
17pub mod value;
18
19use wasm_bindgen::prelude::*;
20
21fn simple(source: &str) -> Value {
22    let mut vm = Lua::new();
23    vm.load_standard_library();
24    match vm.run(source) {
25        Ok(v) => v,
26        Err(e) => Value::String(Box::new(e[0].to_string())),
27    }
28
29    // let e = compiler.get_errors();
30    // if e.len() > 0 {
31    //     return Value::String(Box::new(e[0].to_string()));
32    // }
33    // Value::String(Box::new("Unknown error".to_string()))
34}
35
36fn complex(source: &str) -> Result<Value, ErrorTuple> {
37    let mut vm = Lua::new();
38    vm.load_standard_library();
39    match vm.run(source) {
40        Ok(v) => Ok(v),
41        Err(e) => Err(e.get(0).unwrap().clone()),
42    }
43}
44
45#[wasm_bindgen]
46extern "C" {
47    pub fn jprintln(s: &str);
48}
49
50#[wasm_bindgen]
51pub fn run(source: &str) -> String {
52    let mut vm = Lua::new();
53    vm.load_standard_library();
54    match vm.run(source) {
55        Ok(v) => v.to_string(),
56        Err(e) => e[0].to_string(),
57    }
58}
59
60macro_rules! valeq {
61    ($source:literal, $val:expr) => {
62        assert_eq!(simple($source), $val);
63    };
64}
65
66macro_rules! fails {
67    ($source:literal, $val:expr) => {{
68        match complex($source) {
69            Ok(_) => panic!("Expected error"),
70            Err(e) => assert_eq!(e.code, $val),
71        }
72    }};
73}
74
75macro_rules! vstr {
76    ($source:literal) => {
77        Value::String(Box::new($source.to_string()))
78    };
79}
80
81#[cfg(test)]
82mod tests {
83    use crate::{
84        chunk::Chunk,
85        code::{self, OpCode},
86        complex,
87        error::SiltError,
88        function::FunctionObject,
89        lua::Lua,
90        prelude::ErrorTypes,
91        simple,
92        token::{Operator, Token},
93        value::Value,
94    };
95    use std::{mem::size_of, println, rc::Rc};
96
97    #[test]
98    fn test_32bits() {
99        println!("size of i32: {}", size_of::<i32>());
100        println!("size of i64: {}", size_of::<i64>());
101        println!("size of f32: {}", size_of::<f32>());
102        println!("size of f64: {}", size_of::<f64>());
103        println!("size of bool: {}", size_of::<bool>());
104        println!("size of char: {}", size_of::<char>());
105        println!("size of usize: {}", size_of::<usize>());
106        println!("size of u8: {}", size_of::<u8>());
107        println!("size of &str: {}", size_of::<&str>());
108        println!("size of String: {}", size_of::<String>());
109        println!("size of Box<str>: {}", size_of::<Box<str>>());
110        println!("size of boxed<Strinv> {}", size_of::<Box<String>>());
111        println!("size of Operator: {}", size_of::<crate::token::Operator>());
112        println!("size of Tester: {}", size_of::<crate::code::Tester>());
113        println!("size of Flag: {}", size_of::<crate::token::Flag>());
114        println!("size of token: {}", size_of::<Token>());
115
116        println!("size of token: {}", size_of::<Token>());
117        println!(
118            "size of silt_error: {}",
119            size_of::<crate::error::SiltError>()
120        );
121        println!(
122            "size of error_types: {}",
123            size_of::<crate::error::ErrorTypes>()
124        );
125
126        println!("size of value: {}", size_of::<crate::value::Value>());
127        println!("size of OpCode: {}", size_of::<crate::code::OpCode>());
128
129        assert!(size_of::<Token>() == 24);
130        assert!(size_of::<crate::code::OpCode>() == 4);
131    }
132
133    #[test]
134    fn speed() {
135        let source_in = r#"
136    start=clock()
137    i=1
138    a="a"
139    while i < 100000 do
140        i = i +1
141        a = a .. "1"
142    end
143    elapsed=clock()-start
144    print "done "
145    print ("elapsed: "..elapsed)
146    return {elapsed,i}
147    "#;
148        let tuple = if let crate::value::Value::Table(t) = simple(source_in) {
149            let tt = t.borrow();
150            (
151                if let Some(&Value::Number(n)) = tt.getn(1) {
152                    n
153                } else {
154                    999999.
155                },
156                if let Some(&Value::Integer(n)) = tt.getn(2) {
157                    println!("{} iterations", n);
158                    n
159                } else {
160                    0
161                },
162            )
163        } else {
164            panic!("not a table")
165        };
166
167        // assert!(tuple.0 < 2.14);
168        assert!(tuple.1 == 100_000);
169    }
170
171    // #[test]
172    // fn fibby() {
173    //     let source_in = r#"
174    //     function fib(n)
175    //         if n <= 1 then
176    //         return n
177    //         else
178    //             return fib(n-1) + fib(n-2)
179    //         end
180    //     end
181
182    //     for i = 1, 35 do
183    //         sprint i..":"..fib(i)
184    //     end
185    // "#;
186    //     println!("{}", simple(source_in));
187    // }
188
189    #[test]
190    fn fib() {
191        let source_in = r#"
192        start=clock() 
193        function fib(n)
194            if n <= 1 then
195                return n
196            else
197                return fib(n-1) + fib(n-2)
198            end
199        end
200        
201        for i = 1, 25 do
202            print(i..":"..fib(i))
203        end
204        elapsed=clock()-start
205        return elapsed
206        "#;
207
208        let n = if let crate::value::Value::Number(n) = simple(source_in) {
209            println!("{} seconds", n);
210            n
211        } else {
212            999999.
213        };
214        println!("{} seconds", n);
215        // assert!(n < 3.4)
216    }
217    #[test]
218    fn chunk_validity() {
219        let mut c = Chunk::new();
220        c.write_value(Value::Number(1.2), (1, 1));
221        c.write_value(Value::Number(3.4), (1, 2));
222        c.write_code(OpCode::ADD, (1, 3));
223        c.write_value(Value::Number(9.2), (1, 4));
224        c.write_code(OpCode::DIVIDE, (1, 5));
225        c.write_code(OpCode::NEGATE, (1, 1));
226        c.write_code(OpCode::RETURN, (1, 3));
227        c.print_chunk(None);
228        println!("-----------------");
229        let blank = FunctionObject::new(None, false);
230        let mut tester = FunctionObject::new(None, false);
231        tester.set_chunk(c);
232        let mut vm = Lua::new();
233        match vm.execute(Rc::new(tester)) {
234            Ok(v) => {
235                assert_eq!(v, Value::Number(-0.5));
236            }
237            Err(e) => {
238                panic!("Test should not fail with error: {}", e)
239            }
240        }
241    }
242
243    #[test]
244    fn compliance() {
245        valeq!("return 1+2", Value::Integer(3));
246        valeq!("return '1'..'2'", vstr!("12"));
247
248        valeq!(
249            r#"
250            local a= 1+2
251            return a
252            "#,
253            Value::Integer(3)
254        );
255        valeq!(
256            r#"
257            local a= '1'..'2'
258            return a
259            "#,
260            vstr!("12")
261        );
262        valeq!(
263            r#"
264            local a= 'a'
265            a='b'
266            local b='c'
267            b=a..b
268            return b
269            "#,
270            vstr!("bc")
271        );
272    }
273
274    #[test]
275    fn string_infererence() {
276        valeq!("return '1'+2", Value::Integer(3));
277        fails!(
278            "return 'a1'+2",
279            SiltError::ExpOpValueWithValue(ErrorTypes::String, Operator::Add, ErrorTypes::Integer)
280        );
281    }
282
283    #[test]
284    fn scope() {
285        valeq!(
286            r#"
287            -- for loop closures should capture the loop variable at that point in time and not the final value of the loop variable
288            a = {}
289            do
290                for i = 1, 3 do
291                    local function t()
292                        return i
293                    end
294                    a[i] = t
295                end
296
297                return a[1]() + a[2]() + a[3]() -- 1+2+3 = 6
298            end
299            "#,
300            Value::Integer(6)
301        );
302        valeq!(
303            r#"
304            -- Same but test in global scope
305            a = {}
306            for i = 1, 3 do
307                local function t()
308                    return i
309                end
310                a[i] = t
311            end
312
313            return a[1]() + a[2]() + a[3]() -- 1+2+3 = 6
314            "#,
315            Value::Integer(6)
316        );
317    }
318
319    #[test]
320    fn closures() {
321        valeq!(
322            r#"
323            do
324                local a = 1
325                local b = 2
326                local function f1()
327                    local c = 3
328                    local function f2()
329                        local d = 4
330                        c = c + d            -- 7, 11
331                        return a + b + c + d -- 1+2+7+4= 14, 1+2+11+4 = 18
332                    end
333                    return f2
334                end
335                local e = 1000
336                local x = f1()
337                return x() + x() -- 14+18 = 32
338            end
339            "#,
340            Value::Integer(32)
341        );
342    }
343
344    #[test]
345    fn closures2() {
346        valeq!(
347            r#"
348            do
349                local a = 1
350                function f1()
351                    return a
352                end
353
354                local b = f1()
355                a = 3
356                b = b + f1()
357                return b --4
358            end
359            "#,
360            Value::Integer(4)
361        );
362        valeq!(
363            r#"
364            do
365                function outer()
366                    local y = 0
367                    local x = 2
368                    local function middle()
369                        local function inner()
370                            return x
371                        end
372                        y = y + 1
373                        return inner
374                    end
375            
376                    y = y + 1
377                    x = x + y
378                    return middle
379                end
380            
381                a = outer()
382                b = a()
383                return b()
384            end
385            "#,
386            Value::Integer(3)
387        );
388    }
389}