From 6d4a456010a3523aefda741da01f16810499456a Mon Sep 17 00:00:00 2001 From: NikolajDanger Date: Fri, 24 Apr 2026 16:45:23 +0200 Subject: [PATCH] :goat: LITTERA --- README.md | 5 +++ centvrion/ast_nodes.py | 4 +++ centvrion/compiler/emit_expr.py | 3 ++ centvrion/compiler/runtime/cent_runtime.c | 4 +++ centvrion/compiler/runtime/cent_runtime.h | 1 + centvrion/lexer.py | 1 + snippets/littera.cent | 3 ++ snippets/littera.png | Bin 0 -> 19877 bytes snippets/syntaxes/centvrion.sublime-syntax | 2 +- tests.py | 32 ++++++++++++++++++ vscode-extension/snippets/cent.json | 1 + .../syntaxes/cent.tmLanguage.json | 2 +- 12 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 snippets/littera.cent create mode 100644 snippets/littera.png diff --git a/README.md b/README.md index 984097e..932a7d2 100644 --- a/README.md +++ b/README.md @@ -366,6 +366,11 @@ Parses a Roman numeral string and returns its integer value. The argument must b 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). +### LITTERA +`LITTERA(value)` + +Returns `value` formatted as the same display string `DIC` would print. Integers become Roman numerals (zero becomes `NVLLVS`), fractions use the `S`/`:`/`.`/`|` notation, booleans become `VERITAS`/`FALSITAS`, arrays are space-separated in brackets, and dicts use the `{ key VT value, ... }` form. Strings pass through unchanged. Respects `MAGNVM` and `SVBNVLLA` for large and negative numbers. Inverse of `NVMERVS` for integers: `NVMERVS(LITTERA(n)) == n`. + ### DORMI `DORMI(n)` diff --git a/centvrion/ast_nodes.py b/centvrion/ast_nodes.py index 2788188..38e9d81 100644 --- a/centvrion/ast_nodes.py +++ b/centvrion/ast_nodes.py @@ -1441,6 +1441,10 @@ class BuiltIn(Node): if isinstance(params[0], (ValList, ValStr, ValDict)): return vtable, ValInt(len(params[0].value())) raise CentvrionError("LONGITVDO requires an array, string, or dict") + case "LITTERA": + if len(params) != 1: + raise CentvrionError("LITTERA takes exactly I argument") + return vtable, ValStr(make_string(params[0], magnvm, svbnvlla)) case "CLAVES": if not isinstance(params[0], ValDict): raise CentvrionError("CLAVES requires a dict") diff --git a/centvrion/compiler/emit_expr.py b/centvrion/compiler/emit_expr.py index 61863c9..bdd66a4 100644 --- a/centvrion/compiler/emit_expr.py +++ b/centvrion/compiler/emit_expr.py @@ -237,6 +237,9 @@ def _emit_builtin(node, ctx): case "LONGITVDO": lines.append(f"CentValue {tmp} = cent_longitudo({param_vars[0]});") + case "LITTERA": + lines.append(f"CentValue {tmp} = cent_littera({param_vars[0]});") + case "FORTVITVS_NVMERVS": if not ctx.has_module("FORS"): lines.append('cent_runtime_error("FORS module required for FORTVITVS_NVMERVS");') diff --git a/centvrion/compiler/runtime/cent_runtime.c b/centvrion/compiler/runtime/cent_runtime.c index c29e086..3248ff2 100644 --- a/centvrion/compiler/runtime/cent_runtime.c +++ b/centvrion/compiler/runtime/cent_runtime.c @@ -644,6 +644,10 @@ CentValue cent_longitudo(CentValue v) { return cent_null(); /* unreachable; silences warning */ } +CentValue cent_littera(CentValue v) { + return cent_str(cent_make_string(v)); +} + CentValue cent_typvs(CentValue v) { switch (v.type) { case CENT_INT: return cent_str("NVMERVS"); diff --git a/centvrion/compiler/runtime/cent_runtime.h b/centvrion/compiler/runtime/cent_runtime.h index b3707dc..a6c8e3b 100644 --- a/centvrion/compiler/runtime/cent_runtime.h +++ b/centvrion/compiler/runtime/cent_runtime.h @@ -223,6 +223,7 @@ void cent_dic(CentValue v); /* DIC */ CentValue cent_avdi(void); /* AVDI */ CentValue cent_avdi_numerus(void); /* AVDI_NVMERVS */ CentValue cent_longitudo(CentValue v); /* LONGITVDO */ +CentValue cent_littera(CentValue v); /* LITTERA */ CentValue cent_fortuitus_numerus(CentValue lo, CentValue hi); /* FORTVITVS_NVMERVS */ CentValue cent_fortuita_electionis(CentValue lst); /* FORTVITA_ELECTIO */ CentValue cent_decimatio(CentValue lst); /* DECIMATIO */ diff --git a/centvrion/lexer.py b/centvrion/lexer.py index 9951af8..09b1523 100644 --- a/centvrion/lexer.py +++ b/centvrion/lexer.py @@ -54,6 +54,7 @@ builtin_tokens = [("BUILTIN", i) for i in [ "EVERRE", "FORTVITVS_NVMERVS", "FORTVITA_ELECTIO", + "LITTERA", "LONGITVDO", "NVMERVS", "ORDINA", diff --git a/snippets/littera.cent b/snippets/littera.cent new file mode 100644 index 0000000..4f05f84 --- /dev/null +++ b/snippets/littera.cent @@ -0,0 +1,3 @@ +DESIGNA n VT VII +DESIGNA s VT LITTERA(n) & " est septem" +DIC(s) diff --git a/snippets/littera.png b/snippets/littera.png new file mode 100644 index 0000000000000000000000000000000000000000..ac6ecf262f5ed5ed10b77be05fb562ed4687f73a GIT binary patch literal 19877 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 literal 0 HcmV?d00001 diff --git a/snippets/syntaxes/centvrion.sublime-syntax b/snippets/syntaxes/centvrion.sublime-syntax index 9c7c496..2bcd36a 100644 --- a/snippets/syntaxes/centvrion.sublime-syntax +++ b/snippets/syntaxes/centvrion.sublime-syntax @@ -70,7 +70,7 @@ contexts: scope: constant.language.centvrion builtins: - - match: '\b(ADIVNGE|AVDI_NVMERVS|AVDI|AVSCVLTA|CLAVES|DECIMATIO|DIC|DORMI|EVERRE|FORTVITVS_NVMERVS|FORTVITA_ELECTIO|LEGE|LONGITVDO|NVMERVS|ORDINA|PETE|PETITVR|QVAERE|SCINDE|SCRIBE|SEMEN|SENATVS|SVBSTITVE|TYPVS)\b' + - match: '\b(ADIVNGE|AVDI_NVMERVS|AVDI|AVSCVLTA|CLAVES|DECIMATIO|DIC|DORMI|EVERRE|FORTVITVS_NVMERVS|FORTVITA_ELECTIO|LEGE|LITTERA|LONGITVDO|NVMERVS|ORDINA|PETE|PETITVR|QVAERE|SCINDE|SCRIBE|SEMEN|SENATVS|SVBSTITVE|TYPVS)\b' scope: support.function.builtin.centvrion modules: diff --git a/tests.py b/tests.py index d155a2e..bd65d74 100644 --- a/tests.py +++ b/tests.py @@ -646,6 +646,38 @@ builtin_tests = [ ("TYPVS(FVNCTIO () VT { REDI(I) })", Program([], [ExpressionStatement(BuiltIn("TYPVS", [Fvnctio([], [Redi([Numeral("I")])])]))]), ValStr("FVNCTIO")), # TYPVS: null ("TYPVS(NVLLVS)", Program([], [ExpressionStatement(BuiltIn("TYPVS", [Nullus()]))]), ValStr("NVLLVS")), + # LITTERA: integer → Roman numeral + ("LITTERA(V)", Program([], [ExpressionStatement(BuiltIn("LITTERA", [Numeral("V")]))]), ValStr("V")), + # LITTERA: larger integer + ("LITTERA(MCMLXXXIV)", Program([], [ExpressionStatement(BuiltIn("LITTERA", [Numeral("MCMLXXXIV")]))]), ValStr("MCMLXXXIV")), + # LITTERA: zero → NVLLVS + ("LITTERA(I - I)", Program([], [ExpressionStatement(BuiltIn("LITTERA", [BinOp(Numeral("I"), Numeral("I"), "SYMBOL_MINUS")]))]), ValStr("NVLLVS")), + # LITTERA: string passthrough + ('LITTERA("salve")', Program([], [ExpressionStatement(BuiltIn("LITTERA", [String("salve")]))]), ValStr("salve")), + # LITTERA: empty string + ('LITTERA("")', Program([], [ExpressionStatement(BuiltIn("LITTERA", [String("")]))]), ValStr("")), + # LITTERA: VERITAS + ("LITTERA(VERITAS)", Program([], [ExpressionStatement(BuiltIn("LITTERA", [Bool(True)]))]), ValStr("VERITAS")), + # LITTERA: FALSITAS + ("LITTERA(FALSITAS)", Program([], [ExpressionStatement(BuiltIn("LITTERA", [Bool(False)]))]), ValStr("FALSITAS")), + # LITTERA: NVLLVS + ("LITTERA(NVLLVS)", Program([], [ExpressionStatement(BuiltIn("LITTERA", [Nullus()]))]), ValStr("NVLLVS")), + # LITTERA: array of integers + ("LITTERA([I, II, III])", Program([], [ExpressionStatement(BuiltIn("LITTERA", [DataArray([Numeral("I"), Numeral("II"), Numeral("III")])]))]), ValStr("[I II III]")), + # LITTERA: empty array + ("LITTERA([])", Program([], [ExpressionStatement(BuiltIn("LITTERA", [DataArray([])]))]), ValStr("[]")), + # LITTERA: dict with string keys (make_string emits bare keys, not quoted — matches DIC's output) + ('LITTERA(TABVLA {"a" VT I})', Program([], [ExpressionStatement(BuiltIn("LITTERA", [DataDict([(String("a"), Numeral("I"))])]))]), ValStr('{a VT I}')), + # LITTERA: fraction (requires FRACTIO module) + ("CVM FRACTIO\nLITTERA(S)", Program([ModuleCall("FRACTIO")], [ExpressionStatement(BuiltIn("LITTERA", [Fractio("S")]))]), ValStr("S")), + # LITTERA: negative integer + ("CVM SVBNVLLA\nLITTERA(-III)", Program([ModuleCall("SVBNVLLA")], [ExpressionStatement(BuiltIn("LITTERA", [UnaryMinus(Numeral("III"))]))]), ValStr("-III")), + # LITTERA: round-trips through NVMERVS + ('NVMERVS(LITTERA(VII))', Program([], [ExpressionStatement(BuiltIn("NVMERVS", [BuiltIn("LITTERA", [Numeral("VII")])]))]), ValInt(7)), + # LITTERA: concatenated with a string via & + ('LITTERA(V) & " est quinque"', Program([], [ExpressionStatement(BinOp(BuiltIn("LITTERA", [Numeral("V")]), String(" est quinque"), "SYMBOL_AMPERSAND"))]), ValStr("V est quinque")), + # LITTERA: via variable + ("DESIGNA x VT IX\nLITTERA(x)", Program([], [Designa(ID("x"), Numeral("IX")), ExpressionStatement(BuiltIn("LITTERA", [ID("x")]))]), ValStr("IX")), # QVAERE: basic literal match ('QVAERE("ab", "abcabc")', Program([], [ExpressionStatement(BuiltIn("QVAERE", [String("ab"), String("abcabc")]))]), ValList([ValStr("ab"), ValStr("ab")])), # QVAERE: no match → empty list diff --git a/vscode-extension/snippets/cent.json b/vscode-extension/snippets/cent.json index 95ba2d0..9140b13 100644 --- a/vscode-extension/snippets/cent.json +++ b/vscode-extension/snippets/cent.json @@ -72,6 +72,7 @@ "FORTVITA_ELECTIO": { "prefix": "FORTVITA_ELECTIO", "body": "FORTVITA_ELECTIO", "description": "pick a random element from an array (FORS module)" }, "FORTVITVS_NVMERVS": { "prefix": "FORTVITVS_NVMERVS", "body": "FORTVITVS_NVMERVS", "description": "random integer in a range (FORS module)" }, "LEGE": { "prefix": "LEGE", "body": "LEGE", "description": "read file contents (SCRIPTA module)" }, + "LITTERA": { "prefix": "LITTERA", "body": "LITTERA", "description": "coerce any value to its display string" }, "LONGITVDO": { "prefix": "LONGITVDO", "body": "LONGITVDO", "description": "length of array, string, or dict" }, "NVMERVS": { "prefix": "NVMERVS", "body": "NVMERVS", "description": "parse a Roman numeral string to an integer" }, "ORDINA": { "prefix": "ORDINA", "body": "ORDINA", "description": "sort an array in ascending order" }, diff --git a/vscode-extension/syntaxes/cent.tmLanguage.json b/vscode-extension/syntaxes/cent.tmLanguage.json index ee3bcd0..aac2132 100644 --- a/vscode-extension/syntaxes/cent.tmLanguage.json +++ b/vscode-extension/syntaxes/cent.tmLanguage.json @@ -65,7 +65,7 @@ "patterns": [ { "name": "support.function.builtin.cent", - "match": "\\b(ADIVNGE|AVDI_NVMERVS|AVDI|AVSCVLTA|CLAVES|DECIMATIO|DIC|DORMI|EVERRE|FORTVITVS_NVMERVS|FORTVITA_ELECTIO|LEGE|LONGITVDO|NVMERVS|ORDINA|PETE|PETITVR|QVAERE|SCINDE|SCRIBE|SEMEN|SENATVS|SVBSTITVE|TYPVS)\\b" + "match": "\\b(ADIVNGE|AVDI_NVMERVS|AVDI|AVSCVLTA|CLAVES|DECIMATIO|DIC|DORMI|EVERRE|FORTVITVS_NVMERVS|FORTVITA_ELECTIO|LEGE|LITTERA|LONGITVDO|NVMERVS|ORDINA|PETE|PETITVR|QVAERE|SCINDE|SCRIBE|SEMEN|SENATVS|SVBSTITVE|TYPVS)\\b" } ] },