12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079 |
- /*
- * ECAL
- *
- * Copyright 2020 Matthias Ladkau. All rights reserved.
- *
- * This Source Code Form is subject to the terms of the MIT
- * License, If a copy of the MIT License was not distributed with this
- * file, You can obtain one at https://opensource.org/licenses/MIT.
- */
- package interpreter
- import (
- "testing"
- "devt.de/krotik/ecal/scope"
- )
- func TestGuardStatements(t *testing.T) {
- // Test normal if
- vs := scope.NewScope(scope.GlobalScope)
- _, err := UnitTestEvalAndAST(
- `
- a := 1
- if a == 1 {
- b := 1
- a := a + 1
- }
- `, vs,
- `
- statements
- :=
- identifier: a
- number: 1
- if
- guard
- ==
- identifier: a
- number: 1
- statements
- :=
- identifier: b
- number: 1
- :=
- identifier: a
- plus
- identifier: a
- number: 1
- `[1:])
- if err != nil {
- t.Error(err)
- return
- }
- if vs.String() != `
- GlobalScope {
- a (float64) : 2
- block: if (Line:3 Pos:1) {
- b (float64) : 1
- }
- }`[1:] {
- t.Error("Unexpected result: ", vs)
- return
- }
- // Test elif
- vs = scope.NewScope(scope.GlobalScope)
- _, err = UnitTestEvalAndAST(
- `
- a := 2
- if a == 1 {
- a := a + 1
- } elif a == 2 {
- a := a + 2
- }
- `, vs, `
- statements
- :=
- identifier: a
- number: 2
- if
- guard
- ==
- identifier: a
- number: 1
- statements
- :=
- identifier: a
- plus
- identifier: a
- number: 1
- guard
- ==
- identifier: a
- number: 2
- statements
- :=
- identifier: a
- plus
- identifier: a
- number: 2
- `[1:])
- if err != nil {
- t.Error(err)
- return
- }
- if vs.String() != `
- GlobalScope {
- a (float64) : 4
- block: if (Line:3 Pos:5) {
- }
- }`[1:] {
- t.Error("Unexpected result: ", vs)
- return
- }
- // Test else
- vs = scope.NewScope(scope.GlobalScope)
- _, err = UnitTestEvalAndAST(
- `
- a := 3
- if a == 1 {
- a := a + 1
- } elif a == 2 {
- a := a + 2
- } else {
- a := 99
- }
- `, vs, `
- statements
- :=
- identifier: a
- number: 3
- if
- guard
- ==
- identifier: a
- number: 1
- statements
- :=
- identifier: a
- plus
- identifier: a
- number: 1
- guard
- ==
- identifier: a
- number: 2
- statements
- :=
- identifier: a
- plus
- identifier: a
- number: 2
- guard
- true
- statements
- :=
- identifier: a
- number: 99
- `[1:])
- if err != nil {
- t.Error(err)
- return
- }
- if vs.String() != `
- GlobalScope {
- a (float64) : 99
- block: if (Line:3 Pos:5) {
- }
- }`[1:] {
- t.Error("Unexpected result: ", vs)
- return
- }
- }
- func TestLoopStatements(t *testing.T) {
- vs := scope.NewScope(scope.GlobalScope)
- buf := addLogFunction(vs)
- _, err := UnitTestEvalAndAST(
- `
- a := 10
- for a > 0 {
- testlog("Info: ", "-> ", a)
- a := a - 1
- }
- `, vs,
- `
- statements
- :=
- identifier: a
- number: 10
- loop
- guard
- >
- identifier: a
- number: 0
- statements
- identifier: testlog
- funccall
- string: 'Info: '
- string: '-> '
- identifier: a
- :=
- identifier: a
- minus
- identifier: a
- number: 1
- `[1:])
- if err != nil {
- t.Error(err)
- return
- }
- if vs.String() != `
- GlobalScope {
- a (float64) : 0
- testlog (*interpreter.TestLogger) : TestLogger
- block: loop (Line:4 Pos:1) {
- }
- }`[1:] {
- t.Error("Unexpected result: ", vs)
- return
- }
- if res := buf.String(); res != `
- Info: -> 10
- Info: -> 9
- Info: -> 8
- Info: -> 7
- Info: -> 6
- Info: -> 5
- Info: -> 4
- Info: -> 3
- Info: -> 2
- Info: -> 1`[1:] {
- t.Error("Unexpected result: ", res)
- return
- }
- vs = scope.NewScope(scope.GlobalScope)
- buf = addLogFunction(vs)
- _, err = UnitTestEvalAndAST(
- `
- for a in range(2, 10, 1) {
- testlog("Info", "->", a)
- }
- `, vs,
- `
- loop
- in
- identifier: a
- identifier: range
- funccall
- number: 2
- number: 10
- number: 1
- statements
- identifier: testlog
- funccall
- string: 'Info'
- string: '->'
- identifier: a
- `[1:])
- if err != nil {
- t.Error(err)
- return
- }
- if vs.String() != `
- GlobalScope {
- testlog (*interpreter.TestLogger) : TestLogger
- block: loop (Line:2 Pos:5) {
- a (float64) : 10
- }
- }`[1:] {
- t.Error("Unexpected result: ", vs)
- return
- }
- if res := buf.String(); res != `
- Info->2
- Info->3
- Info->4
- Info->5
- Info->6
- Info->7
- Info->8
- Info->9
- Info->10`[1:] {
- t.Error("Unexpected result: ", res)
- return
- }
- vs = scope.NewScope(scope.GlobalScope)
- buf = addLogFunction(vs)
- _, err = UnitTestEvalAndAST(
- `
- for a in range(10, 3, -3) {
- testlog("Info", "->", a)
- }
- `, vs,
- `
- loop
- in
- identifier: a
- identifier: range
- funccall
- number: 10
- number: 3
- minus
- number: 3
- statements
- identifier: testlog
- funccall
- string: 'Info'
- string: '->'
- identifier: a
- `[1:])
- if err != nil {
- t.Error(err)
- return
- }
- if vs.String() != `
- GlobalScope {
- testlog (*interpreter.TestLogger) : TestLogger
- block: loop (Line:2 Pos:1) {
- a (float64) : 4
- }
- }`[1:] {
- t.Error("Unexpected result: ", vs)
- return
- }
- if res := buf.String(); res != `
- Info->10
- Info->7
- Info->4`[1:] {
- t.Error("Unexpected result: ", res)
- return
- }
- // Test nested loops
- vs = scope.NewScope(scope.GlobalScope)
- buf = addLogFunction(vs)
- _, err = UnitTestEvalAndAST(
- `
- for a in range(10, 3, -3) {
- for b in range(1, 3, 1) {
- testlog("Info", "->", a, b)
- }
- }
- `, vs,
- `
- loop
- in
- identifier: a
- identifier: range
- funccall
- number: 10
- number: 3
- minus
- number: 3
- statements
- loop
- in
- identifier: b
- identifier: range
- funccall
- number: 1
- number: 3
- number: 1
- statements
- identifier: testlog
- funccall
- string: 'Info'
- string: '->'
- identifier: a
- identifier: b
- `[1:])
- if err != nil {
- t.Error(err)
- return
- }
- if vs.String() != `
- GlobalScope {
- testlog (*interpreter.TestLogger) : TestLogger
- block: loop (Line:2 Pos:1) {
- a (float64) : 4
- block: loop (Line:3 Pos:3) {
- b (float64) : 3
- }
- }
- }`[1:] {
- t.Error("Unexpected result: ", vs)
- return
- }
- if res := buf.String(); res != `
- Info->10 1
- Info->10 2
- Info->10 3
- Info->7 1
- Info->7 2
- Info->7 3
- Info->4 1
- Info->4 2
- Info->4 3`[1:] {
- t.Error("Unexpected result: ", res)
- return
- }
- // Break statement
- vs = scope.NewScope(scope.GlobalScope)
- buf = addLogFunction(vs)
- _, err = UnitTestEvalAndAST(
- `
- for a in range(1, 10, 1) {
- testlog("Info", "->", a)
- if a == 3 {
- break
- }
- }`, vs,
- `
- loop
- in
- identifier: a
- identifier: range
- funccall
- number: 1
- number: 10
- number: 1
- statements
- identifier: testlog
- funccall
- string: 'Info'
- string: '->'
- identifier: a
- if
- guard
- ==
- identifier: a
- number: 3
- statements
- break
- `[1:])
- if err != nil {
- t.Error(err)
- return
- }
- if vs.String() != `
- GlobalScope {
- testlog (*interpreter.TestLogger) : TestLogger
- block: loop (Line:2 Pos:1) {
- a (float64) : 3
- block: if (Line:4 Pos:3) {
- }
- }
- }`[1:] {
- t.Error("Unexpected result: ", vs)
- return
- }
- if res := buf.String(); res != `
- Info->1
- Info->2
- Info->3`[1:] {
- t.Error("Unexpected result: ", res)
- return
- }
- // Continue statement
- vs = scope.NewScope(scope.GlobalScope)
- buf = addLogFunction(vs)
- _, err = UnitTestEvalAndAST(
- `
- for a in range(1, 10, 1) {
- if a > 3 and a < 6 {
- continue
- }
- testlog("Info", "->", a)
- }`, vs,
- `
- loop
- in
- identifier: a
- identifier: range
- funccall
- number: 1
- number: 10
- number: 1
- statements
- if
- guard
- and
- >
- identifier: a
- number: 3
- <
- identifier: a
- number: 6
- statements
- continue
- identifier: testlog
- funccall
- string: 'Info'
- string: '->'
- identifier: a
- `[1:])
- if err != nil {
- t.Error(err)
- return
- }
- if vs.String() != `
- GlobalScope {
- testlog (*interpreter.TestLogger) : TestLogger
- block: loop (Line:2 Pos:1) {
- a (float64) : 10
- block: if (Line:3 Pos:3) {
- }
- }
- }`[1:] {
- t.Error("Unexpected result: ", vs)
- return
- }
- if res := buf.String(); res != `
- Info->1
- Info->2
- Info->3
- Info->6
- Info->7
- Info->8
- Info->9
- Info->10`[1:] {
- t.Error("Unexpected result: ", res)
- return
- }
- // Loop over lists
- vs = scope.NewScope(scope.GlobalScope)
- buf = addLogFunction(vs)
- _, err = UnitTestEvalAndAST(
- `
- for a in [1,2] {
- for b in [1,2,3,"Hans", 4] {
- testlog("Info", "->", a, "-", b)
- }
- }
- `, vs,
- `
- loop
- in
- identifier: a
- list
- number: 1
- number: 2
- statements
- loop
- in
- identifier: b
- list
- number: 1
- number: 2
- number: 3
- string: 'Hans'
- number: 4
- statements
- identifier: testlog
- funccall
- string: 'Info'
- string: '->'
- identifier: a
- string: '-'
- identifier: b
- `[1:])
- if err != nil {
- t.Error(err)
- return
- }
- if vs.String() != `
- GlobalScope {
- testlog (*interpreter.TestLogger) : TestLogger
- block: loop (Line:2 Pos:1) {
- a (float64) : 2
- block: loop (Line:3 Pos:3) {
- b (float64) : 4
- }
- }
- }`[1:] {
- t.Error("Unexpected result: ", vs)
- return
- }
- if res := buf.String(); res != `
- Info->1-1
- Info->1-2
- Info->1-3
- Info->1-Hans
- Info->1-4
- Info->2-1
- Info->2-2
- Info->2-3
- Info->2-Hans
- Info->2-4`[1:] {
- t.Error("Unexpected result: ", res)
- return
- }
- vs = scope.NewScope(scope.GlobalScope)
- buf = addLogFunction(vs)
- _, err = UnitTestEvalAndAST(
- `
- l := [1,2,3,4]
- for a in range(0, 3, 1) {
- testlog("Info", "-a>", a, "-", l[a])
- }
- for a in range(0, 3, 1) {
- testlog("Info", "-b>", a, "-", l[-a])
- }
- testlog("Info", "xxx>", l[-1])
- `, vs,
- `
- statements
- :=
- identifier: l
- list
- number: 1
- number: 2
- number: 3
- number: 4
- loop
- in
- identifier: a
- identifier: range
- funccall
- number: 0
- number: 3
- number: 1
- statements
- identifier: testlog
- funccall
- string: 'Info'
- string: '-a>'
- identifier: a
- string: '-'
- identifier: l
- compaccess
- identifier: a
- loop
- in
- identifier: a
- identifier: range
- funccall
- number: 0
- number: 3
- number: 1
- statements
- identifier: testlog
- funccall
- string: 'Info'
- string: '-b>'
- identifier: a
- string: '-'
- identifier: l
- compaccess
- minus
- identifier: a
- identifier: testlog
- funccall
- string: 'Info'
- string: 'xxx>'
- identifier: l
- compaccess
- minus
- number: 1
- `[1:])
- if err != nil {
- t.Error(err)
- return
- }
- if vs.String() != `
- GlobalScope {
- l ([]interface {}) : [1,2,3,4]
- testlog (*interpreter.TestLogger) : TestLogger
- block: loop (Line:3 Pos:1) {
- a (float64) : 3
- }
- block: loop (Line:6 Pos:1) {
- a (float64) : 3
- }
- }`[1:] {
- t.Error("Unexpected result: ", vs)
- return
- }
- if res := buf.String(); res != `
- Info-a>0-1
- Info-a>1-2
- Info-a>2-3
- Info-a>3-4
- Info-b>0-1
- Info-b>1-4
- Info-b>2-3
- Info-b>3-2
- Infoxxx>4`[1:] {
- t.Error("Unexpected result: ", res)
- return
- }
- // Loop over a map
- vs = scope.NewScope(scope.GlobalScope)
- buf = addLogFunction(vs)
- _, err = UnitTestEvalAndAST(
- `
- x := { "c": 0, "a":2, "b":4}
- for [a, b] in x {
- testlog("Info", "->", a, "-", b)
- }
- `, vs,
- `
- statements
- :=
- identifier: x
- map
- kvp
- string: 'c'
- number: 0
- kvp
- string: 'a'
- number: 2
- kvp
- string: 'b'
- number: 4
- loop
- in
- list
- identifier: a
- identifier: b
- identifier: x
- statements
- identifier: testlog
- funccall
- string: 'Info'
- string: '->'
- identifier: a
- string: '-'
- identifier: b
- `[1:])
- if err != nil {
- t.Error(err)
- return
- }
- if res := buf.String(); res != `
- Info->a-2
- Info->b-4
- Info->c-0`[1:] {
- t.Error("Unexpected result: ", res)
- return
- }
- _, err = UnitTestEval(
- `
- x := { "c": 0, "a":2, "b":4}
- for [1, b] in x {
- testlog("Info", "->", a, "-", b)
- }
- `, vs)
- if err == nil || err.Error() != "ECAL error in ECALTestRuntime: Invalid construct (Must have a list of simple variables on the left side of the In expression) (Line:3 Pos:1)" {
- t.Error("Unexpected result:", err)
- return
- }
- // Test continue
- _, err = UnitTestEval(`
- for [a] in [1,2,3] {
- continue
- [a, b] := "Hans"
- }
- `[1:], vs)
- if err != nil {
- t.Error("Unexpected result:", err)
- return
- }
- _, err = UnitTestEval(`
- a := 1
- for a < 10 {
- a := a + 1
- continue
- [a,b] := "Hans"
- }
- `[1:], vs)
- if err != nil {
- t.Error("Unexpected result:", err)
- return
- }
- // Test single value
- _, err = UnitTestEval(`
- for a in 1 {
- continue
- [a,b] := "Hans"
- }
- `[1:], vs)
- if err != nil {
- t.Error("Unexpected result:", err)
- return
- }
- _, err = UnitTestEval(`
- for a[t] in 1 {
- continue
- [a,b] := "Hans"
- }
- `[1:], vs)
- if err == nil || err.Error() != "ECAL error in ECALTestRuntime: Invalid construct (Must have a simple variable on the left side of the In expression) (Line:1 Pos:1)" {
- t.Error("Unexpected result:", err)
- return
- }
- _, err = UnitTestEval(`
- for [a, b] in [[1,2],[3,4],3] {
- }
- `[1:], vs)
- if err == nil || err.Error() != "ECAL error in ECALTestRuntime: Runtime error (Result for loop variable is not a list (value is 3)) (Line:1 Pos:1)" {
- t.Error("Unexpected result:", err)
- return
- }
- _, err = UnitTestEval(`
- for [a, b] in [[1,2],[3,4],[5,6,7]] {
- }
- `[1:], vs)
- if err == nil || err.Error() != "ECAL error in ECALTestRuntime: Runtime error (Assigned number of variables is different to number of values (2 variables vs 3 values)) (Line:1 Pos:1)" {
- t.Error("Unexpected result:", err)
- return
- }
- }
- func TestTryStatements(t *testing.T) {
- vs := scope.NewScope(scope.GlobalScope)
- _, err := UnitTestEvalAndAST(
- `
- try {
- debug("Raising custom error")
- raise("test 12", null, [1,2,3])
- } except "test 12" as e {
- error("Something happened: ", e)
- } finally {
- log("Cleanup")
- }
- `, vs,
- `
- try
- statements
- identifier: debug
- funccall
- string: 'Raising custom error'
- identifier: raise
- funccall
- string: 'test 12'
- null
- list
- number: 1
- number: 2
- number: 3
- except
- string: 'test 12'
- as
- identifier: e
- statements
- identifier: error
- funccall
- string: 'Something happened: '
- identifier: e
- finally
- statements
- identifier: log
- funccall
- string: 'Cleanup'
- `[1:])
- if err != nil {
- t.Error(err)
- return
- }
- if testlogger.String() != `
- debug: Raising custom error
- error: Something happened: {
- "data": [
- 1,
- 2,
- 3
- ],
- "detail": "",
- "error": "ECAL error in ECALTestRuntime: test 12 () (Line:4 Pos:5)",
- "line": 4,
- "pos": 5,
- "source": "ECALTestRuntime",
- "trace": [
- "raise(\"test 12\", null, [1, 2, 3]) (ECALEvalTest:4)"
- ],
- "type": "test 12"
- }
- Cleanup`[1:] {
- t.Error("Unexpected result:", testlogger.String())
- return
- }
- _, err = UnitTestEval(
- `
- try {
- debug("Raising custom error")
- raise("test 13", null, [1,2,3])
- } except "test 12" as e {
- error("Something happened: ", e)
- } except e {
- error("Something else happened: ", e)
- try {
- x := 1 + a
- } except e {
- log("Runtime error: ", e)
- }
- } finally {
- log("Cleanup")
- }
- `, vs)
- if err != nil {
- t.Error(err)
- return
- }
- if testlogger.String() != `
- debug: Raising custom error
- error: Something else happened: {
- "data": [
- 1,
- 2,
- 3
- ],
- "detail": "",
- "error": "ECAL error in ECALTestRuntime: test 13 () (Line:4 Pos:5)",
- "line": 4,
- "pos": 5,
- "source": "ECALTestRuntime",
- "trace": [
- "raise(\"test 13\", null, [1, 2, 3]) (ECALEvalTest:4)"
- ],
- "type": "test 13"
- }
- Runtime error: {
- "detail": "a=NULL",
- "error": "ECAL error in ECALTestRuntime: Operand is not a number (a=NULL) (Line:11 Pos:12)",
- "line": 11,
- "pos": 12,
- "source": "ECALTestRuntime",
- "trace": [],
- "type": "Operand is not a number"
- }
- Cleanup`[1:] {
- t.Error("Unexpected result:", testlogger.String())
- return
- }
- _, err = UnitTestEval(
- `
- try {
- x := 1 + "a"
- } except {
- error("This did not work")
- }
- `, vs)
- if err != nil {
- t.Error(err)
- return
- }
- if testlogger.String() != `
- error: This did not work`[1:] {
- t.Error("Unexpected result:", testlogger.String())
- return
- }
- }
- func TestMutexStatements(t *testing.T) {
- vs := scope.NewScope(scope.GlobalScope)
- _, err := UnitTestEvalAndAST(
- `
- mutex foo {
- a := 1
- raise("test 12", null, [1,2,3])
- }
- `, vs,
- `
- mutex
- identifier: foo
- statements
- :=
- identifier: a
- number: 1
- identifier: raise
- funccall
- string: 'test 12'
- null
- list
- number: 1
- number: 2
- number: 3
- `[1:])
- if err != nil {
- t.Error(err)
- return
- }
- }
|