🐐 Continue statement
This commit is contained in:
@@ -180,6 +180,11 @@ Reads one line from stdin and returns it as a string.
|
|||||||
|
|
||||||
Reads one line from stdin, parses it as a Roman numeral, and returns it as an integer. Raises an error if the input is not a valid numeral.
|
Reads one line from stdin, parses it as a Roman numeral, and returns it as an integer. Raises an error if the input is not a valid numeral.
|
||||||
|
|
||||||
|
### CONTINVA
|
||||||
|
`CONTINVA`
|
||||||
|
|
||||||
|
Skips the rest of the current loop body and continues to the next iteration (`DVM` or `PER`). Has no meaningful return value.
|
||||||
|
|
||||||
### ERVMPE
|
### ERVMPE
|
||||||
`ERVMPE`
|
`ERVMPE`
|
||||||
|
|
||||||
|
|||||||
@@ -494,6 +494,21 @@ class Erumpe(Node):
|
|||||||
return vtable, ValNul()
|
return vtable, ValNul()
|
||||||
|
|
||||||
|
|
||||||
|
class Continva(Node):
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) == type(other)
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return "Continva()"
|
||||||
|
|
||||||
|
def print(self):
|
||||||
|
return "CONTINVA"
|
||||||
|
|
||||||
|
def _eval(self, vtable):
|
||||||
|
vtable["#continue"] = True
|
||||||
|
return vtable, ValNul()
|
||||||
|
|
||||||
|
|
||||||
class Nullus(Node):
|
class Nullus(Node):
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return type(self) == type(other)
|
return type(self) == type(other)
|
||||||
@@ -723,12 +738,16 @@ class DumStatement(Node):
|
|||||||
while not cond:
|
while not cond:
|
||||||
for statement in self.statements:
|
for statement in self.statements:
|
||||||
vtable, val = statement.eval(vtable)
|
vtable, val = statement.eval(vtable)
|
||||||
if vtable["#break"] or vtable["#return"] is not None:
|
if vtable["#break"] or vtable["#continue"] or vtable["#return"] is not None:
|
||||||
break
|
break
|
||||||
last_val = val
|
last_val = val
|
||||||
if vtable["#break"]:
|
if vtable["#break"]:
|
||||||
vtable["#break"] = False
|
vtable["#break"] = False
|
||||||
break
|
break
|
||||||
|
if vtable["#continue"]:
|
||||||
|
vtable["#continue"] = False
|
||||||
|
vtable, cond = self.test.eval(vtable)
|
||||||
|
continue
|
||||||
if vtable["#return"] is not None:
|
if vtable["#return"] is not None:
|
||||||
break
|
break
|
||||||
vtable, cond = self.test.eval(vtable)
|
vtable, cond = self.test.eval(vtable)
|
||||||
@@ -765,12 +784,15 @@ class PerStatement(Node):
|
|||||||
vtable[variable_name] = item
|
vtable[variable_name] = item
|
||||||
for statement in self.statements:
|
for statement in self.statements:
|
||||||
vtable, val = statement.eval(vtable)
|
vtable, val = statement.eval(vtable)
|
||||||
if vtable["#break"] or vtable["#return"] is not None:
|
if vtable["#break"] or vtable["#continue"] or vtable["#return"] is not None:
|
||||||
break
|
break
|
||||||
last_val = val
|
last_val = val
|
||||||
if vtable["#break"]:
|
if vtable["#break"]:
|
||||||
vtable["#break"] = False
|
vtable["#break"] = False
|
||||||
break
|
break
|
||||||
|
if vtable["#continue"]:
|
||||||
|
vtable["#continue"] = False
|
||||||
|
continue
|
||||||
if vtable["#return"] is not None:
|
if vtable["#return"] is not None:
|
||||||
break
|
break
|
||||||
return vtable, last_val
|
return vtable, last_val
|
||||||
@@ -904,6 +926,7 @@ class Program(BaseBox):
|
|||||||
def eval(self, *_):
|
def eval(self, *_):
|
||||||
vtable = {
|
vtable = {
|
||||||
"#break": False,
|
"#break": False,
|
||||||
|
"#continue": False,
|
||||||
"#return": None,
|
"#return": None,
|
||||||
"#modules": [m.module_name for m in self.modules],
|
"#modules": [m.module_name for m in self.modules],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from centvrion.ast_nodes import (
|
from centvrion.ast_nodes import (
|
||||||
Designa, DesignaIndex, SiStatement, DumStatement, PerStatement,
|
Designa, DesignaIndex, SiStatement, DumStatement, PerStatement,
|
||||||
Defini, Redi, Erumpe, ExpressionStatement, ID,
|
Defini, Redi, Erumpe, Continva, ExpressionStatement, ID,
|
||||||
)
|
)
|
||||||
from centvrion.compiler.emit_expr import emit_expr
|
from centvrion.compiler.emit_expr import emit_expr
|
||||||
|
|
||||||
@@ -92,6 +92,9 @@ def emit_stmt(node, ctx):
|
|||||||
if isinstance(node, Erumpe):
|
if isinstance(node, Erumpe):
|
||||||
return ["break;"]
|
return ["break;"]
|
||||||
|
|
||||||
|
if isinstance(node, Continva):
|
||||||
|
return ["continue;"]
|
||||||
|
|
||||||
if isinstance(node, ExpressionStatement):
|
if isinstance(node, ExpressionStatement):
|
||||||
lines, _ = emit_expr(node.expression, ctx)
|
lines, _ = emit_expr(node.expression, ctx)
|
||||||
return lines
|
return lines
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ keyword_tokens = [("KEYWORD_"+i, i) for i in [
|
|||||||
"DESIGNA",
|
"DESIGNA",
|
||||||
"DONICVM",
|
"DONICVM",
|
||||||
"DVM",
|
"DVM",
|
||||||
|
"CONTINVA",
|
||||||
"ERVMPE",
|
"ERVMPE",
|
||||||
"EST",
|
"EST",
|
||||||
"ET",
|
"ET",
|
||||||
|
|||||||
@@ -97,6 +97,10 @@ class Parser():
|
|||||||
def erumpe(_):
|
def erumpe(_):
|
||||||
return ast_nodes.Erumpe()
|
return ast_nodes.Erumpe()
|
||||||
|
|
||||||
|
@self.pg.production('statement : KEYWORD_CONTINVA')
|
||||||
|
def continva(_):
|
||||||
|
return ast_nodes.Continva()
|
||||||
|
|
||||||
@self.pg.production('si_statement : KEYWORD_SI expression KEYWORD_TVNC SYMBOL_LCURL statements SYMBOL_RCURL')
|
@self.pg.production('si_statement : KEYWORD_SI expression KEYWORD_TVNC SYMBOL_LCURL statements SYMBOL_RCURL')
|
||||||
@self.pg.production('si_statement : KEYWORD_SI expression KEYWORD_TVNC SYMBOL_LCURL statements SYMBOL_RCURL aluid_statement')
|
@self.pg.production('si_statement : KEYWORD_SI expression KEYWORD_TVNC SYMBOL_LCURL statements SYMBOL_RCURL aluid_statement')
|
||||||
def si_statement(tokens):
|
def si_statement(tokens):
|
||||||
|
|||||||
@@ -36,7 +36,8 @@
|
|||||||
\languageline{statement}{\texttt{PER} \textbf{id} \texttt{IN} \textit{expression} \texttt{FACE} \textit{scope}} \\
|
\languageline{statement}{\texttt{PER} \textbf{id} \texttt{IN} \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{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}} \\ \hline
|
\languageline{statement}{\texttt{ERVMPE}} \\
|
||||||
|
\languageline{statement}{\texttt{CONTINVA}} \\ \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
|
||||||
|
|||||||
58
tests.py
58
tests.py
@@ -11,7 +11,7 @@ from fractions import Fraction
|
|||||||
|
|
||||||
from centvrion.ast_nodes import (
|
from centvrion.ast_nodes import (
|
||||||
ArrayIndex, Bool, BinOp, BuiltIn, DataArray, DataRangeArray, Defini,
|
ArrayIndex, Bool, BinOp, BuiltIn, DataArray, DataRangeArray, Defini,
|
||||||
Designa, DesignaIndex, DumStatement, Erumpe, ExpressionStatement, ID,
|
Continva, Designa, DesignaIndex, DumStatement, Erumpe, ExpressionStatement, ID,
|
||||||
Invoca, ModuleCall, Nullus, Numeral, PerStatement,
|
Invoca, ModuleCall, Nullus, Numeral, PerStatement,
|
||||||
Program, Redi, SiStatement, String, UnaryMinus, UnaryNot,
|
Program, Redi, SiStatement, String, UnaryMinus, UnaryNot,
|
||||||
Fractio, frac_to_fraction, fraction_to_frac,
|
Fractio, frac_to_fraction, fraction_to_frac,
|
||||||
@@ -868,6 +868,62 @@ loop_edge_tests = [
|
|||||||
ExpressionStatement(ID("cnt")),
|
ExpressionStatement(ID("cnt")),
|
||||||
]),
|
]),
|
||||||
ValInt(3), ""),
|
ValInt(3), ""),
|
||||||
|
# PER with CONTINVA: skip odd numbers, sum evens
|
||||||
|
# [I,II,III,IV] → skip I and III; cnt increments on II and IV → cnt = III
|
||||||
|
("DESIGNA cnt VT I\nPER i IN [I, II, III, IV] FACE {\nSI i EST I AVT i EST III TVNC { CONTINVA }\nDESIGNA cnt VT cnt + I\n}\ncnt",
|
||||||
|
Program([], [
|
||||||
|
Designa(ID("cnt"), Numeral("I")),
|
||||||
|
PerStatement(
|
||||||
|
DataArray([Numeral("I"), Numeral("II"), Numeral("III"), Numeral("IV")]),
|
||||||
|
ID("i"),
|
||||||
|
[SiStatement(BinOp(BinOp(ID("i"), Numeral("I"), "KEYWORD_EST"), BinOp(ID("i"), Numeral("III"), "KEYWORD_EST"), "KEYWORD_AVT"), [Continva()], None),
|
||||||
|
Designa(ID("cnt"), BinOp(ID("cnt"), Numeral("I"), "SYMBOL_PLUS"))],
|
||||||
|
),
|
||||||
|
ExpressionStatement(ID("cnt")),
|
||||||
|
]),
|
||||||
|
ValInt(3), ""),
|
||||||
|
# DVM with CONTINVA: skip body when x is II, increment regardless
|
||||||
|
# x goes 1→2→3; on x=2 we continue (no DICE); DICE fires for x=1 and x=3
|
||||||
|
("DESIGNA x VT I\nDVM x EST IV FACE {\nSI x EST II TVNC { DESIGNA x VT x + I\nCONTINVA }\nDICE(x)\nDESIGNA x VT x + I\n}\nx",
|
||||||
|
Program([], [
|
||||||
|
Designa(ID("x"), Numeral("I")),
|
||||||
|
DumStatement(
|
||||||
|
BinOp(ID("x"), Numeral("IV"), "KEYWORD_EST"),
|
||||||
|
[SiStatement(BinOp(ID("x"), Numeral("II"), "KEYWORD_EST"),
|
||||||
|
[Designa(ID("x"), BinOp(ID("x"), Numeral("I"), "SYMBOL_PLUS")), Continva()], None),
|
||||||
|
ExpressionStatement(BuiltIn("DICE", [ID("x")])),
|
||||||
|
Designa(ID("x"), BinOp(ID("x"), Numeral("I"), "SYMBOL_PLUS"))],
|
||||||
|
),
|
||||||
|
ExpressionStatement(ID("x")),
|
||||||
|
]),
|
||||||
|
ValInt(4), "I\nIII\n"),
|
||||||
|
# nested PER: CONTINVA in inner only skips rest of inner body; outer still increments
|
||||||
|
("DESIGNA cnt VT I\nPER i IN [I, II] FACE {\nPER k IN [I, II] FACE {\nCONTINVA\nDESIGNA cnt VT cnt + I\n}\nDESIGNA cnt VT cnt + I\n}\ncnt",
|
||||||
|
Program([], [
|
||||||
|
Designa(ID("cnt"), Numeral("I")),
|
||||||
|
PerStatement(
|
||||||
|
DataArray([Numeral("I"), Numeral("II")]),
|
||||||
|
ID("i"),
|
||||||
|
[PerStatement(DataArray([Numeral("I"), Numeral("II")]), ID("k"),
|
||||||
|
[Continva(), Designa(ID("cnt"), BinOp(ID("cnt"), Numeral("I"), "SYMBOL_PLUS"))]),
|
||||||
|
Designa(ID("cnt"), BinOp(ID("cnt"), Numeral("I"), "SYMBOL_PLUS"))],
|
||||||
|
),
|
||||||
|
ExpressionStatement(ID("cnt")),
|
||||||
|
]),
|
||||||
|
ValInt(3), ""),
|
||||||
|
# DONICVM with CONTINVA: skip value III, count remaining
|
||||||
|
("DESIGNA cnt VT I\nDONICVM i VT I VSQVE IV FACE {\nSI i EST III TVNC { CONTINVA }\nDESIGNA cnt VT cnt + I\n}\ncnt",
|
||||||
|
Program([], [
|
||||||
|
Designa(ID("cnt"), Numeral("I")),
|
||||||
|
PerStatement(
|
||||||
|
DataRangeArray(Numeral("I"), Numeral("IV")),
|
||||||
|
ID("i"),
|
||||||
|
[SiStatement(BinOp(ID("i"), Numeral("III"), "KEYWORD_EST"), [Continva()], None),
|
||||||
|
Designa(ID("cnt"), BinOp(ID("cnt"), Numeral("I"), "SYMBOL_PLUS"))],
|
||||||
|
),
|
||||||
|
ExpressionStatement(ID("cnt")),
|
||||||
|
]),
|
||||||
|
ValInt(3)),
|
||||||
# DVM condition true from start — body never runs
|
# DVM condition true from start — body never runs
|
||||||
("DESIGNA x VT I\nDVM VERITAS FACE {\nDESIGNA x VT x + I\n}\nx",
|
("DESIGNA x VT I\nDVM VERITAS FACE {\nDESIGNA x VT x + I\n}\nx",
|
||||||
Program([], [
|
Program([], [
|
||||||
|
|||||||
Reference in New Issue
Block a user