🐐 DORMI

This commit is contained in:
2026-04-21 21:30:59 +02:00
parent 78b1dd7667
commit 108e69291d
7 changed files with 130 additions and 0 deletions

View File

@@ -314,6 +314,11 @@ Returns VERITAS if a strict majority of the arguments are VERITAS, FALSITAS othe
Returns the type of `value` as a string: `NVMERVS` (integer), `LITTERA` (string), `VERAX` (boolean), `CATALOGVS` (list), `FRACTIO` (fraction), `TABVLA` (dict), `FVNCTIO` (function), or `NVLLVS` (null). Returns the type of `value` as a string: `NVMERVS` (integer), `LITTERA` (string), `VERAX` (boolean), `CATALOGVS` (list), `FRACTIO` (fraction), `TABVLA` (dict), `FVNCTIO` (function), or `NVLLVS` (null).
### DORMI
`DORMI(n)`
Sleeps for `n` seconds, where `n` is an integer, fraction, or NVLLVS (treated as 0). Returns nothing meaningful.
## Modules ## Modules
Modules are additions to the base `CENTVRION` syntax. They add or change certain features. Modules are included in your code by having Modules are additions to the base `CENTVRION` syntax. They add or change certain features. Modules are included in your code by having

View File

@@ -1,5 +1,6 @@
import re import re
import random import random
import time
from fractions import Fraction from fractions import Fraction
from rply.token import BaseBox from rply.token import BaseBox
@@ -1128,6 +1129,18 @@ class BuiltIn(Node):
ValFunc: "FVNCTIO", ValNul: "NVLLVS", ValFunc: "FVNCTIO", ValNul: "NVLLVS",
} }
return vtable, ValStr(type_map[type(params[0])]) return vtable, ValStr(type_map[type(params[0])])
case "DORMI":
v = params[0]
if isinstance(v, ValNul):
seconds = 0
elif isinstance(v, ValInt):
seconds = v.value()
elif isinstance(v, ValFrac):
seconds = float(v.value())
else:
raise CentvrionError("DORMI requires a number or NVLLVS")
time.sleep(seconds)
return vtable, ValNul()
case _: case _:
raise NotImplementedError(self.builtin) raise NotImplementedError(self.builtin)

View File

@@ -258,6 +258,10 @@ def _emit_builtin(node, ctx):
case "TYPVS": case "TYPVS":
lines.append(f"CentValue {tmp} = cent_typvs({param_vars[0]});") lines.append(f"CentValue {tmp} = cent_typvs({param_vars[0]});")
case "DORMI":
lines.append(f"cent_dormi({param_vars[0]});")
lines.append(f"CentValue {tmp} = cent_null();")
case _: case _:
raise NotImplementedError(node.builtin) raise NotImplementedError(node.builtin)

View File

@@ -559,6 +559,23 @@ CentValue cent_typvs(CentValue v) {
return cent_str("IGNOTA"); /* unreachable */ return cent_str("IGNOTA"); /* unreachable */
} }
void cent_dormi(CentValue n) {
struct timespec ts;
if (n.type == CENT_NULL) {
ts.tv_sec = 0; ts.tv_nsec = 0;
} else if (n.type == CENT_INT) {
ts.tv_sec = n.ival; ts.tv_nsec = 0;
} else if (n.type == CENT_FRAC) {
long sec = n.fval.num / n.fval.den;
long rem = n.fval.num % n.fval.den;
ts.tv_sec = sec;
ts.tv_nsec = rem * 1000000000L / n.fval.den;
} else {
cent_type_error("'DORMI' requires a number or NVLLVS");
}
nanosleep(&ts, NULL);
}
CentValue cent_fortis_numerus(CentValue lo, CentValue hi) { CentValue cent_fortis_numerus(CentValue lo, CentValue hi) {
if (lo.type != CENT_INT || hi.type != CENT_INT) if (lo.type != CENT_INT || hi.type != CENT_INT)
cent_type_error("'FORTIS_NVMERVS' requires two integers"); cent_type_error("'FORTIS_NVMERVS' requires two integers");

View File

@@ -221,6 +221,7 @@ void cent_semen(CentValue seed); /* SEMEN */
void cent_everro(void); /* EVERRO */ void cent_everro(void); /* EVERRO */
CentValue cent_senatus(CentValue *args, int n); /* SENATVS */ CentValue cent_senatus(CentValue *args, int n); /* SENATVS */
CentValue cent_typvs(CentValue v); /* TYPVS */ CentValue cent_typvs(CentValue v); /* TYPVS */
void cent_dormi(CentValue n); /* DORMI */
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
/* Array helpers */ /* Array helpers */

View File

@@ -44,6 +44,7 @@ builtin_tokens = [("BUILTIN", i) for i in [
"CLAVES", "CLAVES",
"DECIMATIO", "DECIMATIO",
"DICE", "DICE",
"DORMI",
"EVERRO", "EVERRO",
"FORTIS_NVMERVS", "FORTIS_NVMERVS",
"FORTIS_ELECTIONIS", "FORTIS_ELECTIONIS",

View File

@@ -2,6 +2,7 @@ import os
import random import random
import subprocess import subprocess
import tempfile import tempfile
import time
import unittest import unittest
from io import StringIO from io import StringIO
from unittest.mock import patch from unittest.mock import patch
@@ -2217,5 +2218,93 @@ class TestFvnctio(unittest.TestCase):
run_test(self, source, nodes, value, output) run_test(self, source, nodes, value, output)
# --- DORMI ---
dormi_tests = [
("DORMI(NVLLVS)",
Program([], [ExpressionStatement(BuiltIn("DORMI", [Nullus()]))]),
ValNul()),
]
class TestDormi(unittest.TestCase):
@parameterized.expand(dormi_tests)
def test_dormi(self, source, nodes, value, output=""):
run_test(self, source, nodes, value, output)
def test_dormi_timing_int(self):
source = "DORMI(I)\n"
lexer = Lexer().get_lexer()
tokens = lexer.lex(source)
program = Parser().parse(tokens)
start = time.time()
program.eval()
elapsed = time.time() - start
self.assertAlmostEqual(elapsed, 1.0, delta=0.5)
def test_dormi_timing_int_compiled(self):
source = "DORMI(I)\n"
lexer = Lexer().get_lexer()
tokens = lexer.lex(source)
program = Parser().parse(tokens)
c_source = compile_program(program)
with tempfile.NamedTemporaryFile(suffix=".c", delete=False, mode="w") as tmp_c:
tmp_c.write(c_source)
tmp_c_path = tmp_c.name
with tempfile.NamedTemporaryFile(suffix="", delete=False) as tmp_bin:
tmp_bin_path = tmp_bin.name
try:
subprocess.run(
["gcc", "-O2", tmp_c_path, _RUNTIME_C, "-o", tmp_bin_path],
check=True, capture_output=True,
)
start = time.time()
proc = subprocess.run([tmp_bin_path], capture_output=True, text=True)
elapsed = time.time() - start
self.assertEqual(proc.returncode, 0)
self.assertAlmostEqual(elapsed, 1.0, delta=0.5)
finally:
os.unlink(tmp_c_path)
os.unlink(tmp_bin_path)
def test_dormi_timing_frac(self):
source = "CVM FRACTIO\nDORMI(S)\n"
lexer = Lexer().get_lexer()
tokens = lexer.lex(source)
program = Parser().parse(tokens)
start = time.time()
program.eval()
elapsed = time.time() - start
self.assertAlmostEqual(elapsed, 0.5, delta=0.5)
def test_dormi_timing_frac_compiled(self):
source = "CVM FRACTIO\nDORMI(S)\n"
lexer = Lexer().get_lexer()
tokens = lexer.lex(source)
program = Parser().parse(tokens)
c_source = compile_program(program)
with tempfile.NamedTemporaryFile(suffix=".c", delete=False, mode="w") as tmp_c:
tmp_c.write(c_source)
tmp_c_path = tmp_c.name
with tempfile.NamedTemporaryFile(suffix="", delete=False) as tmp_bin:
tmp_bin_path = tmp_bin.name
try:
subprocess.run(
["gcc", "-O2", tmp_c_path, _RUNTIME_C, "-o", tmp_bin_path],
check=True, capture_output=True,
)
start = time.time()
proc = subprocess.run([tmp_bin_path], capture_output=True, text=True)
elapsed = time.time() - start
self.assertEqual(proc.returncode, 0)
self.assertAlmostEqual(elapsed, 0.5, delta=0.5)
finally:
os.unlink(tmp_c_path)
os.unlink(tmp_bin_path)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()