🐐 Aeternum loops
This commit is contained in:
12
README.md
12
README.md
@@ -141,6 +141,18 @@ The keyword `ET` can be used as a boolean "and". The keyword `AVT` can be used a
|
||||
> XI
|
||||
```
|
||||
|
||||
### AETERNVM loops
|
||||
|
||||
`AETERNVM FACE { ... }` is shorthand for an infinite loop — equivalent
|
||||
to `DVM FALSITAS FACE { ... }` but without relying on `DVM`'s inverted
|
||||
condition. Exit the loop with `ERVMPE` (or `REDI` from inside a function).
|
||||
|
||||

|
||||
|
||||
```
|
||||
> X
|
||||
```
|
||||
|
||||
### PER loops
|
||||
|
||||

|
||||
|
||||
@@ -3,6 +3,7 @@ from rply import LexerGenerator
|
||||
valid_characters = '|'.join(list("abcdefghiklmnopqrstvxyz_"))
|
||||
|
||||
keyword_tokens = [("KEYWORD_"+i, i) for i in [
|
||||
"AETERNVM",
|
||||
"ALVID",
|
||||
"AVT",
|
||||
"DEFINI",
|
||||
|
||||
@@ -121,6 +121,11 @@ class Parser():
|
||||
def dum(tokens):
|
||||
return ast_nodes.DumStatement(tokens[1], tokens[4])
|
||||
|
||||
# AETERNVM is sugar for `DVM FALSITAS` — same AST, no observable difference.
|
||||
@self.pg.production('dum_statement : KEYWORD_AETERNVM KEYWORD_FACE SYMBOL_LCURL statements SYMBOL_RCURL')
|
||||
def aeternvm(tokens):
|
||||
return ast_nodes.DumStatement(ast_nodes.Bool(False), tokens[3])
|
||||
|
||||
@self.pg.production('per_statement : KEYWORD_PER id KEYWORD_IN expression KEYWORD_FACE SYMBOL_LCURL statements SYMBOL_RCURL')
|
||||
def per(tokens):
|
||||
return ast_nodes.PerStatement(tokens[3], tokens[1], tokens[6])
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
\languageline{statement}{\texttt{DEFINI} \textbf{id} \texttt{(} \textit{optional-ids} \texttt{)} \texttt{VT} \textit{scope}} \\
|
||||
\languageline{statement}{\textit{if-statement}} \\
|
||||
\languageline{statement}{\texttt{DVM} \textit{expression} \texttt{FACE} \textit{scope}} \\
|
||||
\languageline{statement}{\texttt{AETERNVM} \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{REDI(} \textit{optional-expressions} \texttt{)}} \\
|
||||
|
||||
8
snippets/aeternvm.cent
Normal file
8
snippets/aeternvm.cent
Normal file
@@ -0,0 +1,8 @@
|
||||
DESIGNA x VT NVLLVS
|
||||
AETERNVM FACE {
|
||||
DESIGNA x VT x+I
|
||||
SI x EST X TVNC {
|
||||
ERVMPE
|
||||
}
|
||||
}
|
||||
DICE(x)
|
||||
@@ -65,7 +65,7 @@ contexts:
|
||||
scope: support.class.module.centvrion
|
||||
|
||||
keywords:
|
||||
- match: '\b(ALVID|AVT|DEFINI|DESIGNA|DONICVM|DVM|ERVMPE|EST|ET|FACE|INVOCA|IN|MINVS|NON|PER|PLVS|REDI|RELIQVVM|SI|TVNC|VSQVE|VT|CVM)\b'
|
||||
- match: '\b(AETERNVM|ALVID|AVT|DEFINI|DESIGNA|DONICVM|DVM|ERVMPE|EST|ET|FACE|INVOCA|IN|MINVS|NON|PER|PLVS|REDI|RELIQVVM|SI|TVNC|VSQVE|VT|CVM)\b'
|
||||
scope: keyword.control.centvrion
|
||||
|
||||
operators:
|
||||
|
||||
44
tests.py
44
tests.py
@@ -342,6 +342,50 @@ control_tests = [
|
||||
DumStatement(Bool(False), [ExpressionStatement(BuiltIn("DICE", [ID("x")])), Erumpe()]),
|
||||
]),
|
||||
ValStr("I"), "I\n"),
|
||||
# AETERNVM is sugar for DVM FALSITAS — must produce the same AST.
|
||||
("DESIGNA x VT I\nAETERNVM FACE {\nDICE(x)\nERVMPE\n}",
|
||||
Program([], [
|
||||
Designa(ID("x"), Numeral("I")),
|
||||
DumStatement(Bool(False), [ExpressionStatement(BuiltIn("DICE", [ID("x")])), Erumpe()]),
|
||||
]),
|
||||
ValStr("I"), "I\n"),
|
||||
# AETERNVM with counter + ERVMPE on condition
|
||||
("DESIGNA x VT I\nAETERNVM FACE {\nSI x EST III TVNC { ERVMPE }\nDESIGNA x VT x + I\n}\nx",
|
||||
Program([], [
|
||||
Designa(ID("x"), Numeral("I")),
|
||||
DumStatement(Bool(False), [
|
||||
SiStatement(BinOp(ID("x"), Numeral("III"), "KEYWORD_EST"), [Erumpe()], None),
|
||||
Designa(ID("x"), BinOp(ID("x"), Numeral("I"), "SYMBOL_PLUS")),
|
||||
]),
|
||||
ExpressionStatement(ID("x")),
|
||||
]),
|
||||
ValInt(3)),
|
||||
# AETERNVM with CONTINVA — skip printing III; ERVMPE after V.
|
||||
# Return value is ValNul because the iteration that triggers ERVMPE runs
|
||||
# Designa first (resetting last_val); we test on output, which is the point.
|
||||
("DESIGNA x VT NVLLVS\nAETERNVM FACE {\nDESIGNA x VT x + I\nSI x PLVS V TVNC { ERVMPE }\nSI x EST III TVNC { CONTINVA }\nDICE(x)\n}",
|
||||
Program([], [
|
||||
Designa(ID("x"), Nullus()),
|
||||
DumStatement(Bool(False), [
|
||||
Designa(ID("x"), BinOp(ID("x"), Numeral("I"), "SYMBOL_PLUS")),
|
||||
SiStatement(BinOp(ID("x"), Numeral("V"), "KEYWORD_PLVS"), [Erumpe()], None),
|
||||
SiStatement(BinOp(ID("x"), Numeral("III"), "KEYWORD_EST"), [Continva()], None),
|
||||
ExpressionStatement(BuiltIn("DICE", [ID("x")])),
|
||||
]),
|
||||
]),
|
||||
ValNul(), "I\nII\nIV\nV\n"),
|
||||
# REDI inside AETERNVM (inside DEFINI) — exits both loop and function
|
||||
(
|
||||
"DEFINI f () VT {\nDESIGNA x VT I\nAETERNVM FACE {\nREDI (x)\n}\n}\nINVOCA f ()",
|
||||
Program([], [
|
||||
Defini(ID("f"), [], [
|
||||
Designa(ID("x"), Numeral("I")),
|
||||
DumStatement(Bool(False), [Redi([ID("x")])]),
|
||||
]),
|
||||
ExpressionStatement(Invoca(ID("f"), [])),
|
||||
]),
|
||||
ValInt(1),
|
||||
),
|
||||
# PER foreach
|
||||
("PER i IN [I, II, III] FACE { DICE(i) }",
|
||||
Program([], [PerStatement(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), ID("i"), [ExpressionStatement(BuiltIn("DICE", [ID("i")]))])]),
|
||||
|
||||
Reference in New Issue
Block a user