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