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
|
import Constant, Op, Builtin, Input, Error, T, any, const from require "alv.base"
import Cell, Tag, Dummy from require "alv.ast"
assert_ = Constant.meta
meta:
name: 'assert'
summary: "Throw an error if a condition is false."
examples: { "(assert check [msg])" }
description: "
Check is any bool result. When it is `false`, this op throws an error.
`msg` is a str= value that is used as the error message.
By default, the message contains the failing check expression."
value: class extends Builtin
assertOp = class extends Op
pattern = any.bool + const.str
setup: (inputs) =>
{ check, msg } = pattern\match inputs
super
check: Input.hot check
msg: msg and Input.cold msg
tick: =>
{ :check, :msg } = @unwrap_all!
assert check, Error 'assertion', msg or "assertion failed"
eval: (scope, tail) =>
L\trace "evaling #{@}"
assert #tail == 1 or #tail == 2, "'assert' takes one or two arguments"
tag = @tag\clone Tag.parse '-1'
inner = Cell tag, {
Dummy.literal T.opdef, assertOp
tail[1]
tail[2] or Constant.str "assertion failed: #{tail[1]\stringify 2}"
}
super inner\eval scope
expect_eq = Constant.meta
meta:
name: 'expect='
summary: "Throw an error if arguments aren't equal."
examples: { "(expect= expected actual [actual…])" }
description: "
Check if `expected` and `actual` are equal.
If not, throws an error."
value: class extends Builtin
expectOp = class extends Op
pattern = any! + (any! + const.str)\named('val', 'src')*0
setup: (inputs) =>
{ expected, values } = pattern\match inputs
super
expected: Input.hot expected
values: [Input.hot got.val for got in *values]
sources: [Input.cold got.src for got in *values]
type = expected\type!
for i, val in ipairs @inputs.values
same = type == val\type!
assert same, Error 'assertion', "Expected #{@inputs.sources[i]!} to equal #{expected.result} (got #{val.result})"
tick: =>
type = @inputs.expected\type!
expected = @inputs.expected!
for i, val in ipairs @inputs.values
assert (type\eq expected, val!), Error 'assertion', "Expected #{@inputs.sources[i]!} to equal #{@inputs.expected.result} (got #{val.result})"
eval: (scope, tail) =>
L\trace "evaling #{@}"
assert #tail > 1, "'expect=' takes at least two arguments"
children = {
Dummy.literal T.opdef, expectOp
tail[1]
}
for arg in *tail[2,]
table.insert children, arg
table.insert children, Constant.str arg\stringify 2
tag = @tag\clone Tag.parse '-1'
inner = Cell tag, children
super inner\eval scope
Constant.meta
meta:
name: 'testing'
summary: "Operators for testing."
value:
'assert': assert_
'expect=': expect_eq
|