aboutsummaryrefslogtreecommitdiffstats
path: root/spec/lib/builtins/scopes_spec.moon
blob: 39ca3294993bfa89149d97c6316e2478fc00550f (plain)
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import TestPilot from require 'spec.test_setup'
import T, Constant, Scope from require 'alv'

describe "def", ->
  COPILOT = TestPilot!

  it "returns nothing", ->
    with COPILOT\eval_once '(def _ 3)'
      assert.is.true \is_const!
      assert.is.nil .result

  it "passes through side-effects", ->
    with COPILOT\eval_once '
        (import* time)
        (def nonconst (every 0.5 "bang!"))'
      assert.is.false \is_const!
      assert.is.nil .result
      assert.is.equal T.clock, (next .children[2].side_inputs).type

  it "validates args", ->
    err = assert.has.error -> COPILOT\eval_once '(def)'
    assert.matches "requires at least 2 arguments", err

    err = assert.has.error -> COPILOT\eval_once '(def a)'
    assert.matches "requires at least 2 arguments", err

    err = assert.has.error -> COPILOT\eval_once '(def a 1 b)'
    assert.matches "requires an even number of arguments", err

    err = assert.has.error -> COPILOT\eval_once '(def (+ 1 2) 3)'
    assert.matches "name is not a symbol", err

  it "cannot redefine symbols", ->
    err = assert.has.error -> COPILOT\eval_once '
      (def a 1
           a 2)'
    assert.matches "cannot redefine symbol", err

  it "can hide symbols", ->
    with COPILOT\eval_once '
        (def a 1)
        (do
          (def a 2)
          a)
        a'
      assert.is.true \is_const!
      assert.is.equal (Constant.num 1), .result
      assert.is.equal (Constant.num 2), .children[2].result

describe "export", ->
  COPILOT = TestPilot!

  it "returns a scope containing new defs", ->
    with COPILOT\eval_once '(export)'
      assert.is.true \is_const!
      assert.is.equal T.scope, .result.type
      assert.is.same {}, .result!.values

    with COPILOT\eval_once '(export (def a 1 b 2))'
      assert.is.true \is_const!
      assert.is.equal T.scope, .result.type
      assert.is.equal (Constant.num 1), .result!.values.a.result
      assert.is.equal (Constant.num 2), .result!.values.b.result

  it "passes through side-effects", ->
    with COPILOT\eval_once '
        (import* time)
        (export
          (def hello (every 0.5 "bang!"))
          (every 0.5 42))'
      assert.is.false \is_const!
      assert.is.equal T.scope, .result.type
      a = next .children[2].children[1].side_inputs
      b = next .children[2].children[2].side_inputs
      assert.is.truthy .side_inputs[a]
      assert.is.truthy .side_inputs[b]

  it "doesn't mutate the current scope", ->
    with COPILOT\eval_once '
      (def a 1)
      (export
        (def a 5)
        (def b 2))
      (export*)'
      assert.is.true \is_const!
      assert.is.equal T.scope, .result.type
      assert.is.equal (Constant.num 1), .result!.values.a.result
      assert.is.nil .result!.values.b

describe "export*", ->
  COPILOT = TestPilot!

  it "validates args", ->
    err = assert.has.error -> COPILOT\eval_once '(export* (+ 1 2))'
    assert.matches "arguments need to be symbols", err

    err = assert.has.error -> COPILOT\eval_once '(export* 3)'
    assert.matches "is not a sym", err

    err = assert.has.error -> COPILOT\eval_once '(export* a)'
    assert.matches "undefined symbol", err

  describe "without args", ->
    it "returns a scope containing all local defs", ->
      with COPILOT\eval_once '(export*)'
        assert.is.true \is_const!
        assert.is.equal T.scope, .result.type
        assert.is.same {}, .result!.values

      with COPILOT\eval_once '
        (def a 1 b "hello" c 3)
        (export*)'
        assert.is.true \is_const!
        assert.is.equal T.scope, .result.type
        assert.is.equal (Constant.num 1), .result!.values.a.result
        assert.is.equal (Constant.str 'hello'), .result!.values.b.result
        assert.is.equal (Constant.num 3), .result!.values.c.result

  describe "with args", ->
    it "returns a scope containing those defs", ->
      with COPILOT\eval_once '
        (def a 1 b "hello" c 3)
        (export* a b)'
        assert.is.true \is_const!
        assert.is.equal T.scope, .result.type
        assert.is.equal (Constant.num 1), .result!.values.a.result
        assert.is.equal (Constant.str 'hello'), .result!.values.b.result
        assert.is.nil .result!.values.c

describe "use", ->
  COPILOT = TestPilot!

  it "returns nothing", ->
    with COPILOT\eval_once '(use (export))'
      assert.is.true \is_const!
      assert.is.nil .result

  it "updates the current scope", ->
    with COPILOT\eval_once '
      (use (export
        (def a 2)))
      a'
      assert.is.true \is_const!
      assert.is.equal (Constant.num 2), .result

  it "terms and conditions apply", ->
    err = assert.has.error -> COPILOT\eval_once '
      (def a 1)
      (use
        (export
          (def a 5)
          (def b 2)))'
    assert.matches "cannot redefine symbol", err