🐐 TEMPTA/CAPE
This commit is contained in:
18
README.md
18
README.md
@@ -240,6 +240,24 @@ condition. Exit the loop with `ERVMPE` (or `REDI` from inside a function).
|
|||||||
> V
|
> V
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Error handling
|
||||||
|
|
||||||
|
Errors can be caught using `TEMPTA` (temptare = to try) and `CAPE` (capere = to catch). The `CAPE` block binds the error message to a variable as a string.
|
||||||
|
|
||||||
|
```
|
||||||
|
TEMPTA {
|
||||||
|
DESIGNA x VT I / NVLLVS
|
||||||
|
} CAPE error {
|
||||||
|
DICE(error)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
> Division by zero
|
||||||
|
```
|
||||||
|
|
||||||
|
If the try block succeeds, the catch block is skipped. If an error occurs in the catch block, it propagates up. `TEMPTA`/`CAPE` blocks can be nested.
|
||||||
|
|
||||||
## Functions
|
## Functions
|
||||||
Functions are defined with the `DEFINI` and `VT` keywords. The `REDI` keyword is used to return. `REDI` can also be used to end the program, if used outside of a function.
|
Functions are defined with the `DEFINI` and `VT` keywords. The `REDI` keyword is used to return. `REDI` can also be used to end the program, if used outside of a function.
|
||||||
|
|
||||||
|
|||||||
@@ -1045,6 +1045,45 @@ class PerStatement(Node):
|
|||||||
return vtable, last_val
|
return vtable, last_val
|
||||||
|
|
||||||
|
|
||||||
|
class TemptaStatement(Node):
|
||||||
|
def __init__(self, try_statements, error_var, catch_statements) -> None:
|
||||||
|
self.try_statements = try_statements
|
||||||
|
self.error_var = error_var
|
||||||
|
self.catch_statements = catch_statements
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return (type(self) == type(other)
|
||||||
|
and self.try_statements == other.try_statements
|
||||||
|
and self.error_var == other.error_var
|
||||||
|
and self.catch_statements == other.catch_statements)
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
try_stmts = f"try([{rep_join(self.try_statements)}])"
|
||||||
|
catch_stmts = f"catch([{rep_join(self.catch_statements)}])"
|
||||||
|
tempta_string = rep_join([try_stmts, repr(self.error_var), catch_stmts])
|
||||||
|
return f"Tempta({tempta_string})"
|
||||||
|
|
||||||
|
def print(self):
|
||||||
|
try_body = "\n".join(s.print() for s in self.try_statements)
|
||||||
|
catch_body = "\n".join(s.print() for s in self.catch_statements)
|
||||||
|
return f"TEMPTA {{\n{try_body}\n}} CAPE {self.error_var.print()} {{\n{catch_body}\n}}"
|
||||||
|
|
||||||
|
def _eval(self, vtable):
|
||||||
|
last_val = ValNul()
|
||||||
|
try:
|
||||||
|
for statement in self.try_statements:
|
||||||
|
vtable, last_val = statement.eval(vtable)
|
||||||
|
if vtable["#return"] is not None or vtable["#break"] or vtable["#continue"]:
|
||||||
|
return vtable, last_val
|
||||||
|
except CentvrionError as e:
|
||||||
|
vtable[self.error_var.name] = ValStr(str(e))
|
||||||
|
for statement in self.catch_statements:
|
||||||
|
vtable, last_val = statement.eval(vtable)
|
||||||
|
if vtable["#return"] is not None or vtable["#break"] or vtable["#continue"]:
|
||||||
|
return vtable, last_val
|
||||||
|
return vtable, last_val
|
||||||
|
|
||||||
|
|
||||||
class Invoca(Node):
|
class Invoca(Node):
|
||||||
def __init__(self, callee, parameters) -> None:
|
def __init__(self, callee, parameters) -> None:
|
||||||
self.callee = callee
|
self.callee = callee
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from centvrion.ast_nodes import (
|
from centvrion.ast_nodes import (
|
||||||
Designa, DesignaIndex, DesignaDestructure, SiStatement, DumStatement,
|
Designa, DesignaIndex, DesignaDestructure, SiStatement, DumStatement,
|
||||||
PerStatement, Defini, Redi, Erumpe, Continva, ExpressionStatement, ID,
|
PerStatement, TemptaStatement, Defini, Redi, Erumpe, Continva,
|
||||||
|
ExpressionStatement, ID,
|
||||||
)
|
)
|
||||||
from centvrion.compiler.emit_expr import emit_expr
|
from centvrion.compiler.emit_expr import emit_expr
|
||||||
|
|
||||||
@@ -125,6 +126,24 @@ def emit_stmt(node, ctx):
|
|||||||
if isinstance(node, Continva):
|
if isinstance(node, Continva):
|
||||||
return ["continue;"]
|
return ["continue;"]
|
||||||
|
|
||||||
|
if isinstance(node, TemptaStatement):
|
||||||
|
lines = [
|
||||||
|
"_cent_try_depth++;",
|
||||||
|
"if (setjmp(_cent_try_stack[_cent_try_depth - 1]) == 0) {",
|
||||||
|
]
|
||||||
|
try_lines = _emit_body(node.try_statements, ctx)
|
||||||
|
lines += [f" {l}" for l in try_lines]
|
||||||
|
lines += [
|
||||||
|
" _cent_try_depth--;",
|
||||||
|
"} else {",
|
||||||
|
" _cent_try_depth--;",
|
||||||
|
f' cent_scope_set(&_scope, "{node.error_var.name}", cent_str(_cent_error_msg));',
|
||||||
|
]
|
||||||
|
catch_lines = _emit_body(node.catch_statements, ctx)
|
||||||
|
lines += [f" {l}" for l in catch_lines]
|
||||||
|
lines += ["}"]
|
||||||
|
return lines
|
||||||
|
|
||||||
if isinstance(node, ExpressionStatement):
|
if isinstance(node, ExpressionStatement):
|
||||||
lines, _ = emit_expr(node.expression, ctx)
|
lines, _ = emit_expr(node.expression, ctx)
|
||||||
return lines
|
return lines
|
||||||
|
|||||||
@@ -11,6 +11,10 @@
|
|||||||
CentArena *cent_arena;
|
CentArena *cent_arena;
|
||||||
int cent_magnvm = 0;
|
int cent_magnvm = 0;
|
||||||
|
|
||||||
|
jmp_buf _cent_try_stack[CENT_TRY_STACK_MAX];
|
||||||
|
int _cent_try_depth = 0;
|
||||||
|
const char *_cent_error_msg = NULL;
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------ */
|
||||||
/* Arena allocator */
|
/* Arena allocator */
|
||||||
/* ------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------ */
|
||||||
@@ -50,11 +54,19 @@ void *cent_arena_alloc(CentArena *a, size_t n) {
|
|||||||
/* ------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
void cent_type_error(const char *msg) {
|
void cent_type_error(const char *msg) {
|
||||||
|
if (_cent_try_depth > 0) {
|
||||||
|
_cent_error_msg = msg;
|
||||||
|
longjmp(_cent_try_stack[_cent_try_depth - 1], 1);
|
||||||
|
}
|
||||||
fprintf(stderr, "CENTVRION type error: %s\n", msg);
|
fprintf(stderr, "CENTVRION type error: %s\n", msg);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cent_runtime_error(const char *msg) {
|
void cent_runtime_error(const char *msg) {
|
||||||
|
if (_cent_try_depth > 0) {
|
||||||
|
_cent_error_msg = msg;
|
||||||
|
longjmp(_cent_try_stack[_cent_try_depth - 1], 1);
|
||||||
|
}
|
||||||
fprintf(stderr, "CENTVRION error: %s\n", msg);
|
fprintf(stderr, "CENTVRION error: %s\n", msg);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------ */
|
||||||
/* Types */
|
/* Types */
|
||||||
@@ -145,8 +146,13 @@ static inline CentValue cent_dict_val(CentValue *keys, CentValue *vals, int len,
|
|||||||
/* Error handling */
|
/* Error handling */
|
||||||
/* ------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
void cent_type_error(const char *msg); /* type mismatch → exit(1) */
|
#define CENT_TRY_STACK_MAX 64
|
||||||
void cent_runtime_error(const char *msg); /* runtime fault → exit(1) */
|
extern jmp_buf _cent_try_stack[];
|
||||||
|
extern int _cent_try_depth;
|
||||||
|
extern const char *_cent_error_msg;
|
||||||
|
|
||||||
|
void cent_type_error(const char *msg); /* type mismatch → longjmp or exit(1) */
|
||||||
|
void cent_runtime_error(const char *msg); /* runtime fault → longjmp or exit(1) */
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------ */
|
||||||
/* Truthiness — conditions must be booleans; anything else is a fault */
|
/* Truthiness — conditions must be booleans; anything else is a fault */
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ keyword_tokens = [("KEYWORD_"+i, i) for i in [
|
|||||||
"AETERNVM",
|
"AETERNVM",
|
||||||
"ALVID",
|
"ALVID",
|
||||||
"AVGE",
|
"AVGE",
|
||||||
|
"CAPE",
|
||||||
"AVT",
|
"AVT",
|
||||||
"DEFINI",
|
"DEFINI",
|
||||||
"DESIGNA",
|
"DESIGNA",
|
||||||
@@ -32,6 +33,7 @@ keyword_tokens = [("KEYWORD_"+i, i) for i in [
|
|||||||
"SI",
|
"SI",
|
||||||
"TVNC",
|
"TVNC",
|
||||||
"TABVLA",
|
"TABVLA",
|
||||||
|
"TEMPTA",
|
||||||
"VSQVE",
|
"VSQVE",
|
||||||
"VT",
|
"VT",
|
||||||
"VERITAS",
|
"VERITAS",
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ class Parser():
|
|||||||
@self.pg.production('statement : dum_statement')
|
@self.pg.production('statement : dum_statement')
|
||||||
@self.pg.production('statement : donicum_statement')
|
@self.pg.production('statement : donicum_statement')
|
||||||
@self.pg.production('statement : si_statement')
|
@self.pg.production('statement : si_statement')
|
||||||
|
@self.pg.production('statement : tempta_statement')
|
||||||
def nested_statements(tokens):
|
def nested_statements(tokens):
|
||||||
return tokens[0]
|
return tokens[0]
|
||||||
|
|
||||||
@@ -203,6 +204,10 @@ class Parser():
|
|||||||
def per(tokens):
|
def per(tokens):
|
||||||
return ast_nodes.PerStatement(tokens[3], tokens[1], tokens[6])
|
return ast_nodes.PerStatement(tokens[3], tokens[1], tokens[6])
|
||||||
|
|
||||||
|
@self.pg.production('tempta_statement : KEYWORD_TEMPTA SYMBOL_LCURL statements SYMBOL_RCURL KEYWORD_CAPE id SYMBOL_LCURL statements SYMBOL_RCURL')
|
||||||
|
def tempta(tokens):
|
||||||
|
return ast_nodes.TemptaStatement(tokens[2], tokens[5], tokens[7])
|
||||||
|
|
||||||
@self.pg.production('donicum_statement : KEYWORD_DONICVM id KEYWORD_VT expression KEYWORD_VSQVE expression KEYWORD_FACE SYMBOL_LCURL statements SYMBOL_RCURL')
|
@self.pg.production('donicum_statement : KEYWORD_DONICVM id KEYWORD_VT expression KEYWORD_VSQVE expression KEYWORD_FACE SYMBOL_LCURL statements SYMBOL_RCURL')
|
||||||
def donicum(tokens):
|
def donicum(tokens):
|
||||||
range_array = ast_nodes.DataRangeArray(tokens[3], tokens[5])
|
range_array = ast_nodes.DataRangeArray(tokens[3], tokens[5])
|
||||||
|
|||||||
@@ -41,7 +41,10 @@
|
|||||||
\languageline{statement}{\texttt{DONICVM} \textbf{id} \texttt{VT} \textit{expression} \texttt{VSQVE} \textit{expression} \texttt{FACE} \textit{scope}} \\
|
\languageline{statement}{\texttt{DONICVM} \textbf{id} \texttt{VT} \textit{expression} \texttt{VSQVE} \textit{expression} \texttt{FACE} \textit{scope}} \\
|
||||||
\languageline{statement}{\texttt{REDI(} \textit{optional-expressions} \texttt{)}} \\
|
\languageline{statement}{\texttt{REDI(} \textit{optional-expressions} \texttt{)}} \\
|
||||||
\languageline{statement}{\texttt{ERVMPE}} \\
|
\languageline{statement}{\texttt{ERVMPE}} \\
|
||||||
\languageline{statement}{\texttt{CONTINVA}} \\ \hline
|
\languageline{statement}{\texttt{CONTINVA}} \\
|
||||||
|
\languageline{statement}{\textit{try-statement}} \\ \hline
|
||||||
|
|
||||||
|
\languageline{try-statement}{\texttt{TEMPTA} \textit{scope} \texttt{CAPE} \textbf{id} \textit{scope}} \\ \hline
|
||||||
|
|
||||||
\languageline{if-statement}{\texttt{SI} \textit{expression} \texttt{TVNC} \textit{scope}} \\
|
\languageline{if-statement}{\texttt{SI} \textit{expression} \texttt{TVNC} \textit{scope}} \\
|
||||||
\languageline{if-statement}{\texttt{SI} \textit{expression} \texttt{TVNC} \textit{scope} \textit{optional-newline} \textit{else-statement}} \\ \hline
|
\languageline{if-statement}{\texttt{SI} \textit{expression} \texttt{TVNC} \textit{scope} \textit{optional-newline} \textit{else-statement}} \\ \hline
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ contexts:
|
|||||||
scope: support.class.module.centvrion
|
scope: support.class.module.centvrion
|
||||||
|
|
||||||
keywords:
|
keywords:
|
||||||
- match: '\b(AETERNVM|ALVID|AVGE|AVT|CONTINVA|DEFINI|DESIGNA|DISPAR|DONICVM|DVM|ERVMPE|EST|ET|FACE|FVNCTIO|INVOCA|IN|MINVE|MINVS|NON|PER|PLVS|REDI|RELIQVVM|SI|TABVLA|TVNC|VSQVE|VT|CVM)\b'
|
- match: '\b(AETERNVM|ALVID|AVGE|AVT|CAPE|CONTINVA|DEFINI|DESIGNA|DISPAR|DONICVM|DVM|ERVMPE|EST|ET|FACE|FVNCTIO|INVOCA|IN|MINVE|MINVS|NON|PER|PLVS|REDI|RELIQVVM|SI|TABVLA|TEMPTA|TVNC|VSQVE|VT|CVM)\b'
|
||||||
scope: keyword.control.centvrion
|
scope: keyword.control.centvrion
|
||||||
|
|
||||||
operators:
|
operators:
|
||||||
|
|||||||
122
tests.py
122
tests.py
@@ -15,8 +15,8 @@ from centvrion.ast_nodes import (
|
|||||||
Defini, Continva, Designa, DesignaDestructure, DesignaIndex, DumStatement,
|
Defini, Continva, Designa, DesignaDestructure, DesignaIndex, DumStatement,
|
||||||
Erumpe, ExpressionStatement, Fvnctio, ID, InterpolatedString, Invoca,
|
Erumpe, ExpressionStatement, Fvnctio, ID, InterpolatedString, Invoca,
|
||||||
ModuleCall, Nullus, Numeral, PerStatement, Program, Redi, SiStatement,
|
ModuleCall, Nullus, Numeral, PerStatement, Program, Redi, SiStatement,
|
||||||
String, UnaryMinus, UnaryNot, Fractio, frac_to_fraction, fraction_to_frac,
|
String, TemptaStatement, UnaryMinus, UnaryNot, Fractio, frac_to_fraction,
|
||||||
num_to_int, int_to_num, make_string,
|
fraction_to_frac, num_to_int, int_to_num, make_string,
|
||||||
)
|
)
|
||||||
from centvrion.compiler.emitter import compile_program
|
from centvrion.compiler.emitter import compile_program
|
||||||
from centvrion.errors import CentvrionError
|
from centvrion.errors import CentvrionError
|
||||||
@@ -686,6 +686,7 @@ error_tests = [
|
|||||||
("CVM FRACTIO\n[I, II, III][IIIS VSQVE III]", CentvrionError), # slice with fractional lower bound
|
("CVM FRACTIO\n[I, II, III][IIIS VSQVE III]", CentvrionError), # slice with fractional lower bound
|
||||||
("CVM FRACTIO\n[I, II, III][I VSQVE IIIS]", CentvrionError), # slice with fractional upper bound
|
("CVM FRACTIO\n[I, II, III][I VSQVE IIIS]", CentvrionError), # slice with fractional upper bound
|
||||||
("CVM FRACTIO\n[I, II, III][I / II VSQVE III]", CentvrionError), # slice with division-fraction lower bound
|
("CVM FRACTIO\n[I, II, III][I / II VSQVE III]", CentvrionError), # slice with division-fraction lower bound
|
||||||
|
("TEMPTA {\nDESIGNA x VT I / NVLLVS\n} CAPE e {\nDESIGNA y VT I / NVLLVS\n}", CentvrionError), # uncaught error in catch block propagates
|
||||||
]
|
]
|
||||||
|
|
||||||
class TestErrors(unittest.TestCase):
|
class TestErrors(unittest.TestCase):
|
||||||
@@ -2642,5 +2643,122 @@ class TestScripta(unittest.TestCase):
|
|||||||
os.unlink(path)
|
os.unlink(path)
|
||||||
|
|
||||||
|
|
||||||
|
# --- 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 FACE {\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)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user