This repository has been archived by the owner on Jul 4, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
eval_test.go
106 lines (97 loc) · 2.68 KB
/
eval_test.go
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
//-----------------------------------------------------------------------------
// Copyright (c) 2022 Detlef Stern
//
// This file is part of sxpf.
//
// sxpf is licensed under the latest version of the EUPL // (European Union
// Public License). Please see file LICENSE.txt for your rights and obligations
// under this license.
//-----------------------------------------------------------------------------
package sxpf_test
import (
"bytes"
"testing"
"github.com/t73fde/sxpf"
)
func TestEvaluate(t *testing.T) {
testcases := []struct {
src string
exp string
}{
{"a", "A"},
{`"a"`, `"a"`},
{"(CAT a b)", `"AB"`},
{"(QUOTE [(A b) c])", "[(A B) C]"},
{"[CAT a b]", `"AB"`},
{"[QUOTE [[A b] c]]", "[[A B] C]"},
}
env := newTestEnv()
for i, tc := range testcases {
expr, err := sxpf.ParseString(env, tc.src)
if err != nil {
t.Error(err)
continue
}
val, err := sxpf.Evaluate(env, expr)
if err != nil {
t.Error(err)
continue
}
got := val.String()
if got != tc.exp {
t.Errorf("%d: %v should evaluate to %v, but got: %v", i, tc.src, tc.exp, got)
}
}
}
type testEnv struct {
symbols sxpf.SymbolTable
symMap *sxpf.SymbolMap
}
func newTestEnv() *testEnv {
env := testEnv{symbols: sxpf.NewSymbolTable()}
symMap := sxpf.NewSymbolMap(nil)
for _, form := range testForms {
symMap.Set(env.MakeSymbol(form.Name()), form)
}
env.symMap = symMap
return &env
}
var testForms = []*sxpf.Builtin{
sxpf.NewBuiltin(
"CAT",
false, 0, -1,
func(env sxpf.Environment, args []sxpf.Value) (sxpf.Value, error) {
var buf bytes.Buffer
for _, arg := range args {
buf.WriteString(arg.String())
}
return sxpf.NewString(buf.String()), nil
},
),
sxpf.NewBuiltin(
"QUOTE",
true, 1, 1,
func(env sxpf.Environment, args []sxpf.Value) (sxpf.Value, error) {
return args[0], nil
},
),
}
func (te *testEnv) MakeSymbol(s string) *sxpf.Symbol { return te.symbols.MakeSymbol(s) }
func (te *testEnv) LookupForm(sym *sxpf.Symbol) (sxpf.Form, error) { return te.symMap.LookupForm(sym) }
func (*testEnv) EvaluateSymbol(sym *sxpf.Symbol) (sxpf.Value, error) { return sym, nil }
func (*testEnv) EvaluateString(str *sxpf.String) (sxpf.Value, error) { return str, nil }
func (te *testEnv) EvaluateList(p *sxpf.Pair) (sxpf.Value, error) { return te.evalAsCall(p.GetSlice()) }
func (te *testEnv) EvaluateVector(lst *sxpf.Vector) (sxpf.Value, error) {
return te.evalAsCall(lst.GetSlice())
}
func (te *testEnv) evalAsCall(vals []sxpf.Value) (sxpf.Value, error) {
res, err, done := sxpf.EvaluateCall(te, vals)
if done {
return res, err
}
result, err := sxpf.EvaluateSlice(te, vals)
if err != nil {
return nil, err
}
return sxpf.NewVector(result...), nil
}