444 lines
16 KiB
Python
444 lines
16 KiB
Python
from tests._helpers import (
|
|
unittest, parameterized, Fraction, time,
|
|
run_test, run_compiler_error_test,
|
|
ArrayIndex, ArraySlice, Bool, BinOp, BuiltIn, DataArray, DataDict, DataRangeArray,
|
|
Defini, Continva, Designa, DesignaDestructure, DesignaIndex, DumStatement,
|
|
Erumpe, ExpressionStatement, Fvnctio, ID, InterpolatedString, Invoca,
|
|
ModuleCall, Nullus, Numeral, PerStatement, Program, Redi, SiStatement,
|
|
String, TemptaStatement, UnaryMinus, UnaryNot, Fractio, frac_to_fraction,
|
|
fraction_to_frac, num_to_int, int_to_num, make_string,
|
|
ValInt, ValStr, ValBool, ValList, ValDict, ValNul, ValFunc, ValFrac,
|
|
CentvrionError, _RUNTIME_C, _cent_rng,
|
|
Lexer, Parser, compile_program,
|
|
os, subprocess, tempfile, StringIO, patch,
|
|
)
|
|
|
|
|
|
# --- Comments ---
|
|
|
|
comment_tests = [
|
|
# trailing line comment
|
|
('DIC("hello") // this is ignored', Program([], [ExpressionStatement(BuiltIn("DIC", [String("hello")]))]), ValStr("hello"), "hello\n"),
|
|
# line comment on its own line before code
|
|
('// ignored\nDIC("hi")', Program([], [ExpressionStatement(BuiltIn("DIC", [String("hi")]))]), ValStr("hi"), "hi\n"),
|
|
# inline block comment
|
|
('DIC(/* ignored */ "hi")', Program([], [ExpressionStatement(BuiltIn("DIC", [String("hi")]))]), ValStr("hi"), "hi\n"),
|
|
# block comment spanning multiple lines
|
|
('/* line one\nline two */\nDIC("hi")', Program([], [ExpressionStatement(BuiltIn("DIC", [String("hi")]))]), ValStr("hi"), "hi\n"),
|
|
# block comment mid-expression
|
|
("II /* ignored */ + III", Program([], [ExpressionStatement(BinOp(Numeral("II"), Numeral("III"), "SYMBOL_PLUS"))]), ValInt(5)),
|
|
# line comment after expression (no output)
|
|
("II + III // ignored", Program([], [ExpressionStatement(BinOp(Numeral("II"), Numeral("III"), "SYMBOL_PLUS"))]), ValInt(5)),
|
|
# division still works (/ token not confused with //)
|
|
("X / II", Program([], [ExpressionStatement(BinOp(Numeral("X"), Numeral("II"), "SYMBOL_DIVIDE"))]), ValInt(5)),
|
|
# multiple line comments
|
|
('// first\n// second\nDIC("ok")', Program([], [ExpressionStatement(BuiltIn("DIC", [String("ok")]))]), ValStr("ok"), "ok\n"),
|
|
# comment-only line between two statements
|
|
('DESIGNA x VT I\n// set y\nDESIGNA y VT II\nx + y',
|
|
Program([], [Designa(ID("x"), Numeral("I")), Designa(ID("y"), Numeral("II")), ExpressionStatement(BinOp(ID("x"), ID("y"), "SYMBOL_PLUS"))]),
|
|
ValInt(3)),
|
|
# blank line between two statements (double newline)
|
|
('DESIGNA x VT I\n\nDESIGNA y VT II\nx + y',
|
|
Program([], [Designa(ID("x"), Numeral("I")), Designa(ID("y"), Numeral("II")), ExpressionStatement(BinOp(ID("x"), ID("y"), "SYMBOL_PLUS"))]),
|
|
ValInt(3)),
|
|
# multiple comment-only lines between statements
|
|
('DESIGNA x VT I\n// one\n// two\nDESIGNA y VT III\nx + y',
|
|
Program([], [Designa(ID("x"), Numeral("I")), Designa(ID("y"), Numeral("III")), ExpressionStatement(BinOp(ID("x"), ID("y"), "SYMBOL_PLUS"))]),
|
|
ValInt(4)),
|
|
]
|
|
|
|
class TestComments(unittest.TestCase):
|
|
@parameterized.expand(comment_tests)
|
|
def test_comments(self, source, nodes, value, output=""):
|
|
run_test(self, source, nodes, value, output)
|
|
|
|
# --- Scope ---
|
|
|
|
scope_tests = [
|
|
# SI: variable assigned in true branch persists in outer scope
|
|
("SI VERITAS TVNC { DESIGNA r VT X }\nr",
|
|
Program([], [SiStatement(Bool(True), [Designa(ID("r"), Numeral("X"))], None), ExpressionStatement(ID("r"))]),
|
|
ValInt(10)),
|
|
# SI: variable assigned in ALIVD branch persists in outer scope
|
|
("SI FALSITAS TVNC { DESIGNA r VT X } ALIVD { DESIGNA r VT V }\nr",
|
|
Program([], [SiStatement(Bool(False), [Designa(ID("r"), Numeral("X"))], [Designa(ID("r"), Numeral("V"))]), ExpressionStatement(ID("r"))]),
|
|
ValInt(5)),
|
|
# DVM: variable assigned in body persists after loop exits
|
|
# x goes 1→2→3→4→5; r tracks x each iteration; loop exits when x==5
|
|
("DESIGNA x VT I\nDVM x EST V FAC { DESIGNA x VT x + I\nDESIGNA r VT x }\nr",
|
|
Program([], [
|
|
Designa(ID("x"), Numeral("I")),
|
|
DumStatement(BinOp(ID("x"), Numeral("V"), "KEYWORD_EST"), [
|
|
Designa(ID("x"), BinOp(ID("x"), Numeral("I"), "SYMBOL_PLUS")),
|
|
Designa(ID("r"), ID("x")),
|
|
]),
|
|
ExpressionStatement(ID("r")),
|
|
]),
|
|
ValInt(5)),
|
|
# PER: loop variable holds last array element after loop (no ERVMPE)
|
|
("PER i IN [I, II, III] FAC { DESIGNA nop VT I }\ni",
|
|
Program([], [
|
|
PerStatement(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), ID("i"), [Designa(ID("nop"), Numeral("I"))]),
|
|
ExpressionStatement(ID("i")),
|
|
]),
|
|
ValInt(3)),
|
|
# PER: reassigning loop var in body doesn't prevent remaining iterations from running
|
|
# cnt increments once per iteration (all 3); C=100 doesn't replace next element assignment
|
|
("DESIGNA cnt VT I\nPER i IN [I, II, III] FAC { DESIGNA i VT C\nDESIGNA cnt VT cnt + I }\ncnt",
|
|
Program([], [
|
|
Designa(ID("cnt"), Numeral("I")),
|
|
PerStatement(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), ID("i"), [
|
|
Designa(ID("i"), Numeral("C")),
|
|
Designa(ID("cnt"), BinOp(ID("cnt"), Numeral("I"), "SYMBOL_PLUS")),
|
|
]),
|
|
ExpressionStatement(ID("cnt")),
|
|
]),
|
|
ValInt(4)),
|
|
# PER: loop var after loop reflects the last body assignment, not the last array element
|
|
# body sets i=C=100 on every iteration; after loop ends, i stays at 100
|
|
("PER i IN [I, II, III] FAC { DESIGNA i VT C }\ni",
|
|
Program([], [
|
|
PerStatement(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), ID("i"), [Designa(ID("i"), Numeral("C"))]),
|
|
ExpressionStatement(ID("i")),
|
|
]),
|
|
ValInt(100)),
|
|
# DONICVM: counter holds last range value after loop ends
|
|
# [I VSQVE IV] = [1,2,3,4]; last value assigned by loop is IV=4
|
|
("DONICVM i VT I VSQVE IV FAC { DESIGNA nop VT I }\ni",
|
|
Program([], [
|
|
PerStatement(DataRangeArray(Numeral("I"), Numeral("IV")), ID("i"), [Designa(ID("nop"), Numeral("I"))]),
|
|
ExpressionStatement(ID("i")),
|
|
]),
|
|
ValInt(4)),
|
|
# DONICVM: reassigning counter inside body doesn't reduce the number of iterations
|
|
# range [I VSQVE IV] evaluated once; i reset each time; cnt still increments 4 times → 5
|
|
("DESIGNA cnt VT I\nDONICVM i VT I VSQVE IV FAC { DESIGNA cnt VT cnt + I\nDESIGNA i VT C }\ncnt",
|
|
Program([], [
|
|
Designa(ID("cnt"), Numeral("I")),
|
|
PerStatement(DataRangeArray(Numeral("I"), Numeral("IV")), ID("i"), [
|
|
Designa(ID("cnt"), BinOp(ID("cnt"), Numeral("I"), "SYMBOL_PLUS")),
|
|
Designa(ID("i"), Numeral("C")),
|
|
]),
|
|
ExpressionStatement(ID("cnt")),
|
|
]),
|
|
ValInt(5)),
|
|
# DONICVM: ERVMPE exits loop early; counter persists at break value
|
|
("DONICVM i VT I VSQVE X FAC {\nSI i EST III TVNC { ERVMPE }\n}\ni",
|
|
Program([], [
|
|
PerStatement(DataRangeArray(Numeral("I"), Numeral("X")), ID("i"), [
|
|
SiStatement(BinOp(ID("i"), Numeral("III"), "KEYWORD_EST"), [Erumpe()], None),
|
|
]),
|
|
ExpressionStatement(ID("i")),
|
|
]),
|
|
ValInt(3)),
|
|
# Function: modifying parameter inside function does not affect outer variable of same name
|
|
# outer n=1; f receives n=5 and modifies its local copy; outer n unchanged
|
|
("DESIGNA n VT I\nDEFINI f (n) VT { DESIGNA n VT n + X\nREDI (n) }\nINVOCA f (V)\nn",
|
|
Program([], [
|
|
Designa(ID("n"), Numeral("I")),
|
|
Defini(ID("f"), [ID("n")], [Designa(ID("n"), BinOp(ID("n"), Numeral("X"), "SYMBOL_PLUS")), Redi([ID("n")])]),
|
|
ExpressionStatement(Invoca(ID("f"), [Numeral("V")])),
|
|
ExpressionStatement(ID("n")),
|
|
]),
|
|
ValInt(1)),
|
|
# Function: mutating outer variable inside function (via DESIGNA) is not visible outside
|
|
# Invoca creates func_vtable = vtable.copy(); mutations to func_vtable don't propagate back
|
|
("DESIGNA x VT I\nDEFINI f () VT { DESIGNA x VT C\nREDI (x) }\nINVOCA f ()\nx",
|
|
Program([], [
|
|
Designa(ID("x"), Numeral("I")),
|
|
Defini(ID("f"), [], [Designa(ID("x"), Numeral("C")), Redi([ID("x")])]),
|
|
ExpressionStatement(Invoca(ID("f"), [])),
|
|
ExpressionStatement(ID("x")),
|
|
]),
|
|
ValInt(1)),
|
|
# Function: two successive calls with same parameter name don't share state
|
|
("DEFINI f (n) VT { REDI (n * II) }\nINVOCA f (III) + INVOCA f (IV)",
|
|
Program([], [
|
|
Defini(ID("f"), [ID("n")], [Redi([BinOp(ID("n"), Numeral("II"), "SYMBOL_TIMES")])]),
|
|
ExpressionStatement(BinOp(Invoca(ID("f"), [Numeral("III")]), Invoca(ID("f"), [Numeral("IV")]), "SYMBOL_PLUS")),
|
|
]),
|
|
ValInt(14)),
|
|
# Function: calling f(I) with param named n does not overwrite outer n=II
|
|
# f is defined before n is designated; INVOCA creates a local copy, outer vtable unchanged
|
|
("DEFINI f (n) VT { REDI (n * II) }\nDESIGNA n VT II\nINVOCA f (I)\nn",
|
|
Program([], [
|
|
Defini(ID("f"), [ID("n")], [Redi([BinOp(ID("n"), Numeral("II"), "SYMBOL_TIMES")])]),
|
|
Designa(ID("n"), Numeral("II")),
|
|
ExpressionStatement(Invoca(ID("f"), [Numeral("I")])),
|
|
ExpressionStatement(ID("n")),
|
|
]),
|
|
ValInt(2)),
|
|
]
|
|
|
|
class TestScope(unittest.TestCase):
|
|
@parameterized.expand(scope_tests)
|
|
def test_scope(self, source, nodes, value):
|
|
run_test(self, source, nodes, value)
|
|
|
|
# --- First-class functions / FVNCTIO ---
|
|
|
|
fvnctio_tests = [
|
|
# Lambda assigned to variable, then called
|
|
(
|
|
"DESIGNA f VT FVNCTIO (x) VT { REDI (x + I) }\nINVOCA f (V)",
|
|
Program([], [
|
|
Designa(ID("f"), Fvnctio([ID("x")], [Redi([BinOp(ID("x"), Numeral("I"), "SYMBOL_PLUS")])])),
|
|
ExpressionStatement(Invoca(ID("f"), [Numeral("V")])),
|
|
]),
|
|
ValInt(6),
|
|
),
|
|
# IIFE: immediately invoked lambda
|
|
(
|
|
"INVOCA FVNCTIO (x) VT { REDI (x * II) } (III)",
|
|
Program([], [
|
|
ExpressionStatement(Invoca(
|
|
Fvnctio([ID("x")], [Redi([BinOp(ID("x"), Numeral("II"), "SYMBOL_TIMES")])]),
|
|
[Numeral("III")],
|
|
)),
|
|
]),
|
|
ValInt(6),
|
|
),
|
|
# Zero-arg lambda
|
|
(
|
|
"INVOCA FVNCTIO () VT { REDI (XLII) } ()",
|
|
Program([], [
|
|
ExpressionStatement(Invoca(
|
|
Fvnctio([], [Redi([Numeral("XLII")])]),
|
|
[],
|
|
)),
|
|
]),
|
|
ValInt(42),
|
|
),
|
|
# Function passed as argument
|
|
(
|
|
"DEFINI apply (f, x) VT { REDI (INVOCA f (x)) }\n"
|
|
"DESIGNA dbl VT FVNCTIO (n) VT { REDI (n * II) }\n"
|
|
"INVOCA apply (dbl, V)",
|
|
Program([], [
|
|
Defini(ID("apply"), [ID("f"), ID("x")], [
|
|
Redi([Invoca(ID("f"), [ID("x")])])
|
|
]),
|
|
Designa(ID("dbl"), Fvnctio([ID("n")], [
|
|
Redi([BinOp(ID("n"), Numeral("II"), "SYMBOL_TIMES")])
|
|
])),
|
|
ExpressionStatement(Invoca(ID("apply"), [ID("dbl"), Numeral("V")])),
|
|
]),
|
|
ValInt(10),
|
|
),
|
|
# Lambda uses caller-scope variable (copy-caller semantics)
|
|
(
|
|
"DESIGNA n VT III\n"
|
|
"DESIGNA f VT FVNCTIO (x) VT { REDI (x + n) }\n"
|
|
"INVOCA f (V)",
|
|
Program([], [
|
|
Designa(ID("n"), Numeral("III")),
|
|
Designa(ID("f"), Fvnctio([ID("x")], [
|
|
Redi([BinOp(ID("x"), ID("n"), "SYMBOL_PLUS")])
|
|
])),
|
|
ExpressionStatement(Invoca(ID("f"), [Numeral("V")])),
|
|
]),
|
|
ValInt(8),
|
|
),
|
|
# Named function passed as value
|
|
(
|
|
"DEFINI sqr (x) VT { REDI (x * x) }\n"
|
|
"DESIGNA f VT sqr\n"
|
|
"INVOCA f (IV)",
|
|
Program([], [
|
|
Defini(ID("sqr"), [ID("x")], [Redi([BinOp(ID("x"), ID("x"), "SYMBOL_TIMES")])]),
|
|
Designa(ID("f"), ID("sqr")),
|
|
ExpressionStatement(Invoca(ID("f"), [Numeral("IV")])),
|
|
]),
|
|
ValInt(16),
|
|
),
|
|
# Nested lambdas
|
|
(
|
|
"INVOCA FVNCTIO (x) VT { REDI (INVOCA FVNCTIO (y) VT { REDI (y + I) } (x)) } (V)",
|
|
Program([], [
|
|
ExpressionStatement(Invoca(
|
|
Fvnctio([ID("x")], [
|
|
Redi([Invoca(
|
|
Fvnctio([ID("y")], [Redi([BinOp(ID("y"), Numeral("I"), "SYMBOL_PLUS")])]),
|
|
[ID("x")],
|
|
)])
|
|
]),
|
|
[Numeral("V")],
|
|
)),
|
|
]),
|
|
ValInt(6),
|
|
),
|
|
# DIC on a function value
|
|
(
|
|
"DESIGNA f VT FVNCTIO (x) VT { REDI (x) }\nDIC(f)",
|
|
Program([], [
|
|
Designa(ID("f"), Fvnctio([ID("x")], [Redi([ID("x")])])),
|
|
ExpressionStatement(BuiltIn("DIC", [ID("f")])),
|
|
]),
|
|
ValStr("FVNCTIO"),
|
|
"FVNCTIO\n",
|
|
),
|
|
# Lambda stored in array, called via index
|
|
(
|
|
"DESIGNA fns VT [FVNCTIO (x) VT { REDI (x + I) }, FVNCTIO (x) VT { REDI (x * II) }]\n"
|
|
"INVOCA fns[I] (V)",
|
|
Program([], [
|
|
Designa(ID("fns"), DataArray([
|
|
Fvnctio([ID("x")], [Redi([BinOp(ID("x"), Numeral("I"), "SYMBOL_PLUS")])]),
|
|
Fvnctio([ID("x")], [Redi([BinOp(ID("x"), Numeral("II"), "SYMBOL_TIMES")])]),
|
|
])),
|
|
ExpressionStatement(Invoca(
|
|
ArrayIndex(ID("fns"), Numeral("I")),
|
|
[Numeral("V")],
|
|
)),
|
|
]),
|
|
ValInt(6),
|
|
),
|
|
# Lambda stored in dict, called via key
|
|
(
|
|
'DESIGNA d VT TABVLA {"add" VT FVNCTIO (x) VT { REDI (x + I) }}\n'
|
|
'INVOCA d["add"] (V)',
|
|
Program([], [
|
|
Designa(ID("d"), DataDict([
|
|
(String("add"), Fvnctio([ID("x")], [Redi([BinOp(ID("x"), Numeral("I"), "SYMBOL_PLUS")])])),
|
|
])),
|
|
ExpressionStatement(Invoca(
|
|
ArrayIndex(ID("d"), String("add")),
|
|
[Numeral("V")],
|
|
)),
|
|
]),
|
|
ValInt(6),
|
|
),
|
|
# Multi-param lambda
|
|
(
|
|
"DESIGNA add VT FVNCTIO (a, b) VT { REDI (a + b) }\nINVOCA add (III, IV)",
|
|
Program([], [
|
|
Designa(ID("add"), Fvnctio([ID("a"), ID("b")], [
|
|
Redi([BinOp(ID("a"), ID("b"), "SYMBOL_PLUS")])
|
|
])),
|
|
ExpressionStatement(Invoca(ID("add"), [Numeral("III"), Numeral("IV")])),
|
|
]),
|
|
ValInt(7),
|
|
),
|
|
]
|
|
|
|
class TestFvnctio(unittest.TestCase):
|
|
@parameterized.expand(fvnctio_tests)
|
|
def test_fvnctio(self, source, nodes, value, output=""):
|
|
run_test(self, source, nodes, value, output)
|
|
|
|
# --- Tempta/Cape (try/catch) ---
|
|
|
|
tempta_tests = [
|
|
# Try block succeeds — catch not entered
|
|
(
|
|
"TEMPTA {\nDESIGNA r VT I\n} CAPE e {\nDESIGNA r VT II\n}\nr",
|
|
Program([], [
|
|
TemptaStatement(
|
|
[Designa(ID("r"), Numeral("I"))],
|
|
ID("e"),
|
|
[Designa(ID("r"), Numeral("II"))],
|
|
),
|
|
ExpressionStatement(ID("r")),
|
|
]),
|
|
ValInt(1),
|
|
),
|
|
# Try block errors — caught by catch
|
|
(
|
|
"TEMPTA {\nDESIGNA r VT I / NVLLVS\n} CAPE e {\nDESIGNA r VT II\n}\nr",
|
|
Program([], [
|
|
TemptaStatement(
|
|
[Designa(ID("r"), BinOp(Numeral("I"), Nullus(), "SYMBOL_DIVIDE"))],
|
|
ID("e"),
|
|
[Designa(ID("r"), Numeral("II"))],
|
|
),
|
|
ExpressionStatement(ID("r")),
|
|
]),
|
|
ValInt(2),
|
|
),
|
|
# Error variable contains the error message
|
|
(
|
|
'DESIGNA e VT NVLLVS\nTEMPTA {\nDESIGNA r VT I / NVLLVS\n} CAPE e {\nNVLLVS\n}\ne',
|
|
Program([], [
|
|
Designa(ID("e"), Nullus()),
|
|
TemptaStatement(
|
|
[Designa(ID("r"), BinOp(Numeral("I"), Nullus(), "SYMBOL_DIVIDE"))],
|
|
ID("e"),
|
|
[ExpressionStatement(Nullus())],
|
|
),
|
|
ExpressionStatement(ID("e")),
|
|
]),
|
|
ValStr("Division by zero"),
|
|
),
|
|
# Nested tempta — inner catches, outer unaffected
|
|
(
|
|
"DESIGNA r VT NVLLVS\nTEMPTA {\nTEMPTA {\nDESIGNA r VT I / NVLLVS\n} CAPE e {\nDESIGNA r VT I\n}\n} CAPE e {\nDESIGNA r VT II\n}\nr",
|
|
Program([], [
|
|
Designa(ID("r"), Nullus()),
|
|
TemptaStatement(
|
|
[TemptaStatement(
|
|
[Designa(ID("r"), BinOp(Numeral("I"), Nullus(), "SYMBOL_DIVIDE"))],
|
|
ID("e"),
|
|
[Designa(ID("r"), Numeral("I"))],
|
|
)],
|
|
ID("e"),
|
|
[Designa(ID("r"), Numeral("II"))],
|
|
),
|
|
ExpressionStatement(ID("r")),
|
|
]),
|
|
ValInt(1),
|
|
),
|
|
# REDI inside catch block
|
|
(
|
|
"DEFINI f () VT {\nTEMPTA {\nDESIGNA x VT I / NVLLVS\n} CAPE e {\nREDI (III)\n}\nREDI (IV)\n}\nINVOCA f ()",
|
|
Program([], [
|
|
Defini(ID("f"), [], [
|
|
TemptaStatement(
|
|
[Designa(ID("x"), BinOp(Numeral("I"), Nullus(), "SYMBOL_DIVIDE"))],
|
|
ID("e"),
|
|
[Redi([Numeral("III")])],
|
|
),
|
|
Redi([Numeral("IV")]),
|
|
]),
|
|
ExpressionStatement(Invoca(ID("f"), [])),
|
|
]),
|
|
ValInt(3),
|
|
),
|
|
# ERVMPE inside catch block (inside a loop)
|
|
(
|
|
"DESIGNA r VT NVLLVS\nDVM r EST I FAC {\nTEMPTA {\nDESIGNA x VT I / NVLLVS\n} CAPE e {\nDESIGNA r VT I\nERVMPE\n}\n}\nr",
|
|
Program([], [
|
|
Designa(ID("r"), Nullus()),
|
|
DumStatement(
|
|
BinOp(ID("r"), Numeral("I"), "KEYWORD_EST"),
|
|
[TemptaStatement(
|
|
[Designa(ID("x"), BinOp(Numeral("I"), Nullus(), "SYMBOL_DIVIDE"))],
|
|
ID("e"),
|
|
[Designa(ID("r"), Numeral("I")), Erumpe()],
|
|
)],
|
|
),
|
|
ExpressionStatement(ID("r")),
|
|
]),
|
|
ValInt(1),
|
|
),
|
|
# Statement after error in try block is not executed
|
|
(
|
|
"DESIGNA r VT NVLLVS\nTEMPTA {\nDESIGNA x VT I / NVLLVS\nDESIGNA r VT III\n} CAPE e {\nDESIGNA r VT II\n}\nr",
|
|
Program([], [
|
|
Designa(ID("r"), Nullus()),
|
|
TemptaStatement(
|
|
[Designa(ID("x"), BinOp(Numeral("I"), Nullus(), "SYMBOL_DIVIDE")),
|
|
Designa(ID("r"), Numeral("III"))],
|
|
ID("e"),
|
|
[Designa(ID("r"), Numeral("II"))],
|
|
),
|
|
ExpressionStatement(ID("r")),
|
|
]),
|
|
ValInt(2),
|
|
),
|
|
]
|
|
|
|
class TestTempta(unittest.TestCase):
|
|
@parameterized.expand(tempta_tests)
|
|
def test_tempta(self, source, nodes, value, output=""):
|
|
run_test(self, source, nodes, value, output)
|