arxo-codegen 0.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- arxo_codegen/__init__.py +5 -0
- arxo_codegen/__main__.py +7 -0
- arxo_codegen/active-outcomes.json +6837 -0
- arxo_codegen/check.py +158 -0
- arxo_codegen/check_active_canaries.py +262 -0
- arxo_codegen/check_api.py +76 -0
- arxo_codegen/check_conformance.py +414 -0
- arxo_codegen/check_matrix.py +131 -0
- arxo_codegen/check_packages.py +281 -0
- arxo_codegen/check_semantic_probes.py +293 -0
- arxo_codegen/check_xlsx.py +320 -0
- arxo_codegen/consumer_runner.py +316 -0
- arxo_codegen/core_support.py +203 -0
- arxo_codegen/coverage.py +341 -0
- arxo_codegen/deliver.py +180 -0
- arxo_codegen/examples/xlsx/pricing.lawir.json +409 -0
- arxo_codegen/examples/xlsx/pricing.xlsx.json +52 -0
- arxo_codegen/excel_plan.py +602 -0
- arxo_codegen/harness/verify/ci/gates/backends/check_backends.py +1248 -0
- arxo_codegen/harness/verify/ci/gates/backends/l1_fixtures.py +463 -0
- arxo_codegen/inert-nodes.json +62 -0
- arxo_codegen/inert.py +91 -0
- arxo_codegen/inputs.py +59 -0
- arxo_codegen/package.py +565 -0
- arxo_codegen/plan.py +4053 -0
- arxo_codegen/recertify_registry.py +100 -0
- arxo_codegen/runtime-cert.json +5259 -0
- arxo_codegen/runtime_cert.py +233 -0
- arxo_codegen/survey.py +272 -0
- arxo_codegen/target_runner.py +101 -0
- arxo_codegen/targets/bsl/cert.bsl +113 -0
- arxo_codegen/targets/bsl/emit.py +356 -0
- arxo_codegen/targets/bsl/json.bsl +243 -0
- arxo_codegen/targets/bsl/runner.bsl +210 -0
- arxo_codegen/targets/bsl/runtime.bsl +858 -0
- arxo_codegen/targets/cs/Cert.cs +90 -0
- arxo_codegen/targets/cs/Runner.cs +154 -0
- arxo_codegen/targets/cs/Runtime.cs +243 -0
- arxo_codegen/targets/cs/emit.py +223 -0
- arxo_codegen/targets/dart/cert.dart +99 -0
- arxo_codegen/targets/dart/emit.py +206 -0
- arxo_codegen/targets/dart/json.dart +166 -0
- arxo_codegen/targets/dart/runner.dart +154 -0
- arxo_codegen/targets/dart/runtime.dart +293 -0
- arxo_codegen/targets/erl/cert.erl +64 -0
- arxo_codegen/targets/erl/emit.py +216 -0
- arxo_codegen/targets/erl/rt.erl +238 -0
- arxo_codegen/targets/erl/runner.erl +130 -0
- arxo_codegen/targets/ex/cert.exs +62 -0
- arxo_codegen/targets/ex/emit.py +204 -0
- arxo_codegen/targets/ex/runner.exs +124 -0
- arxo_codegen/targets/ex/runtime.ex +227 -0
- arxo_codegen/targets/go/apiBase.go +483 -0
- arxo_codegen/targets/go/apicheck.go +97 -0
- arxo_codegen/targets/go/cert.go +218 -0
- arxo_codegen/targets/go/emit.py +1806 -0
- arxo_codegen/targets/go/evaluate.go +1826 -0
- arxo_codegen/targets/go/runner.go +38 -0
- arxo_codegen/targets/go/runtime.go +2612 -0
- arxo_codegen/targets/java/Cert.java +91 -0
- arxo_codegen/targets/java/Json.java +148 -0
- arxo_codegen/targets/java/Runner.java +151 -0
- arxo_codegen/targets/java/Runtime.java +243 -0
- arxo_codegen/targets/java/emit.py +198 -0
- arxo_codegen/targets/kt/Cert.kt +67 -0
- arxo_codegen/targets/kt/Json.kt +103 -0
- arxo_codegen/targets/kt/Runner.kt +126 -0
- arxo_codegen/targets/kt/Runtime.kt +196 -0
- arxo_codegen/targets/kt/emit.py +195 -0
- arxo_codegen/targets/lua/cert.lua +82 -0
- arxo_codegen/targets/lua/emit.py +250 -0
- arxo_codegen/targets/lua/json.lua +133 -0
- arxo_codegen/targets/lua/runner.lua +167 -0
- arxo_codegen/targets/lua/runtime.lua +541 -0
- arxo_codegen/targets/php/cert.php +84 -0
- arxo_codegen/targets/php/emit.py +229 -0
- arxo_codegen/targets/php/json.php +144 -0
- arxo_codegen/targets/php/runner.php +189 -0
- arxo_codegen/targets/php/runtime.php +660 -0
- arxo_codegen/targets/py/api_base.py +334 -0
- arxo_codegen/targets/py/apicheck.py +51 -0
- arxo_codegen/targets/py/cert.py +140 -0
- arxo_codegen/targets/py/emit.py +1140 -0
- arxo_codegen/targets/py/evaluate.py +980 -0
- arxo_codegen/targets/py/runner.py +38 -0
- arxo_codegen/targets/py/runtime.py +1634 -0
- arxo_codegen/targets/rb/cert.rb +73 -0
- arxo_codegen/targets/rb/emit.py +203 -0
- arxo_codegen/targets/rb/runner.rb +130 -0
- arxo_codegen/targets/rb/runtime.rb +255 -0
- arxo_codegen/targets/rs/Cargo.lock +142 -0
- arxo_codegen/targets/rs/Cargo.toml +16 -0
- arxo_codegen/targets/rs/cert.rs +106 -0
- arxo_codegen/targets/rs/emit.py +233 -0
- arxo_codegen/targets/rs/prefetch.rs +1 -0
- arxo_codegen/targets/rs/runner.rs +181 -0
- arxo_codegen/targets/rs/runtime.rs +448 -0
- arxo_codegen/targets/scala/Cert.scala +77 -0
- arxo_codegen/targets/scala/Json.scala +140 -0
- arxo_codegen/targets/scala/Runner.scala +121 -0
- arxo_codegen/targets/scala/Runtime.scala +269 -0
- arxo_codegen/targets/scala/emit.py +193 -0
- arxo_codegen/targets/swift/cert.swift +105 -0
- arxo_codegen/targets/swift/emit.py +231 -0
- arxo_codegen/targets/swift/json.swift +208 -0
- arxo_codegen/targets/swift/runner.swift +133 -0
- arxo_codegen/targets/swift/runtime.swift +528 -0
- arxo_codegen/targets/ts/apiBase.ts +250 -0
- arxo_codegen/targets/ts/apicheck.ts +37 -0
- arxo_codegen/targets/ts/cert.ts +96 -0
- arxo_codegen/targets/ts/emit.py +1214 -0
- arxo_codegen/targets/ts/evaluate.ts +894 -0
- arxo_codegen/targets/ts/package-lock.json +45 -0
- arxo_codegen/targets/ts/package.json +9 -0
- arxo_codegen/targets/ts/runner.ts +31 -0
- arxo_codegen/targets/ts/runtime.ts +1369 -0
- arxo_codegen/targets/xlsx/README.ru.md +176 -0
- arxo_codegen/targets/xlsx/emit.py +198 -0
- arxo_codegen/temporal.py +59 -0
- arxo_codegen/test_alias_types.py +171 -0
- arxo_codegen/test_api_contract.py +89 -0
- arxo_codegen/test_calendar_policy.py +48 -0
- arxo_codegen/test_check.py +49 -0
- arxo_codegen/test_check_active_canaries.py +96 -0
- arxo_codegen/test_check_conformance.py +132 -0
- arxo_codegen/test_check_semantic_probes.py +85 -0
- arxo_codegen/test_check_xlsx.py +52 -0
- arxo_codegen/test_consumer_runner.py +175 -0
- arxo_codegen/test_core_support.py +80 -0
- arxo_codegen/test_e0212_decision_time.py +63 -0
- arxo_codegen/test_head_aggregate.py +71 -0
- arxo_codegen/test_inert.py +143 -0
- arxo_codegen/test_instant_types.py +113 -0
- arxo_codegen/test_key_conflict_scope.py +92 -0
- arxo_codegen/test_key_conflict_targets.py +17 -0
- arxo_codegen/test_package_layout.py +163 -0
- arxo_codegen/test_plan_language_version.py +44 -0
- arxo_codegen/test_positions_refusal.py +43 -0
- arxo_codegen/test_recertify_registry.py +77 -0
- arxo_codegen/test_ruby_target.py +41 -0
- arxo_codegen/test_runtime_cert.py +83 -0
- arxo_codegen/test_secondary_key_conflict_scope.py +17 -0
- arxo_codegen/test_stage_r.py +108 -0
- arxo_codegen/test_standalone_inputs.py +71 -0
- arxo_codegen/test_support.py +150 -0
- arxo_codegen/test_survey_inputs.py +115 -0
- arxo_codegen-0.4.0.dist-info/LICENSE +202 -0
- arxo_codegen-0.4.0.dist-info/METADATA +1673 -0
- arxo_codegen-0.4.0.dist-info/RECORD +152 -0
- arxo_codegen-0.4.0.dist-info/WHEEL +5 -0
- arxo_codegen-0.4.0.dist-info/entry_points.txt +13 -0
- arxo_codegen-0.4.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// Харнесс сертификации рантайма: исполняет runtime-cert.json и печатает,
|
|
2
|
+
// что получилось. Ожидания сверяют ворота, харнесс их не читает.
|
|
3
|
+
using System.Numerics;
|
|
4
|
+
using System.Text.Json;
|
|
5
|
+
using System.Text.Json.Nodes;
|
|
6
|
+
|
|
7
|
+
public static class Program
|
|
8
|
+
{
|
|
9
|
+
static string S(JsonNode? n) => n is JsonValue v && v.TryGetValue<string>(out var s) ? s : n?.ToJsonString() ?? "";
|
|
10
|
+
|
|
11
|
+
static object Lit(JsonNode? x)
|
|
12
|
+
{
|
|
13
|
+
if (x is JsonValue v && v.TryGetValue<string>(out var s)) return s;
|
|
14
|
+
var m = (JsonObject)x!;
|
|
15
|
+
if (m.ContainsKey("dec")) return RT.dec(S(m["dec"]));
|
|
16
|
+
if (m.ContainsKey("money")) return RT.money(S(m["money"]), S(m["cur"]));
|
|
17
|
+
if (m.ContainsKey("text")) return S(m["text"]);
|
|
18
|
+
if (m.ContainsKey("date")) return RT.date(S(m["date"]));
|
|
19
|
+
if (m.ContainsKey("sym")) return RT.sym(S(m["sym"]));
|
|
20
|
+
if (m.ContainsKey("row")) return ((JsonArray)m["row"]!).Select(Lit).ToList();
|
|
21
|
+
throw new InvalidOperationException("литерал фикстуры: " + x);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Отображение с ЯВНЫМ масштабом: 2.00 и 2 — разные записи одного значения.
|
|
25
|
+
static string Digits(BigInteger u, int s)
|
|
26
|
+
{
|
|
27
|
+
bool neg = u.Sign < 0;
|
|
28
|
+
string body = BigInteger.Abs(u).ToString().PadLeft(s + 1, '0');
|
|
29
|
+
string text = s == 0 ? body : body[..^s] + "." + body[^s..];
|
|
30
|
+
return (neg ? "-" : "") + text;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static JsonNode? Render(object? v) => v switch
|
|
34
|
+
{
|
|
35
|
+
null => null,
|
|
36
|
+
bool b => JsonValue.Create(b),
|
|
37
|
+
string t => JsonValue.Create(t),
|
|
38
|
+
Money m => JsonValue.Create(Digits(m.U, m.S) + " " + m.Cur),
|
|
39
|
+
Date d => JsonValue.Create(d.V),
|
|
40
|
+
Sym y => JsonValue.Create(y.Id),
|
|
41
|
+
Dec d => JsonValue.Create(Digits(d.U, d.S)),
|
|
42
|
+
_ => throw new InvalidOperationException("отображение: " + v.GetType()),
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
static object? Run(JsonObject c)
|
|
46
|
+
{
|
|
47
|
+
var a = ((JsonArray)c["args"]!).Select(Lit).ToList();
|
|
48
|
+
return S(c["op"]) switch
|
|
49
|
+
{
|
|
50
|
+
"dec" => RT.dec((string)a[0]),
|
|
51
|
+
"money" => RT.money((string)a[0], (string)a[1]),
|
|
52
|
+
"date" => RT.date((string)a[0]),
|
|
53
|
+
"sym" => RT.sym((string)a[0]),
|
|
54
|
+
"add" => RT.add(a[0], a[1]),
|
|
55
|
+
"sub" => RT.sub(a[0], a[1]),
|
|
56
|
+
"mul" => RT.mul(a[0], a[1]),
|
|
57
|
+
"div" => RT.div(a[0], a[1]),
|
|
58
|
+
"mod" => RT.mod(a[0], a[1]),
|
|
59
|
+
"min" => RT.min(a[0], a[1]),
|
|
60
|
+
"max" => RT.max(a[0], a[1]),
|
|
61
|
+
"abs" => RT.abs(a[0]),
|
|
62
|
+
"pow" => RT.pow(a[0], a[1]),
|
|
63
|
+
"round" => RT.round(a[0], a[1], (string)a[2]),
|
|
64
|
+
"cmp" => RT.cmp(a[0], (string)a[1], a[2]),
|
|
65
|
+
"eq" => RT.eq(a[0], a[1]),
|
|
66
|
+
"keyEq" => RT.key((List<object>)a[0]) == RT.key((List<object>)a[1]),
|
|
67
|
+
"legalTime" => RT.legalTime(),
|
|
68
|
+
"setLegalTime" => Set((string)a[0]),
|
|
69
|
+
var op => throw new InvalidOperationException("неизвестная операция фикстуры: " + op),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
static object? Set(string t) { RT.setLegalTime(t); return null; }
|
|
74
|
+
|
|
75
|
+
public static int Main(string[] argv)
|
|
76
|
+
{
|
|
77
|
+
var fixture = (JsonObject)JsonNode.Parse(File.ReadAllText(argv[0]))!;
|
|
78
|
+
var outp = new JsonArray();
|
|
79
|
+
foreach (var c in (JsonArray)fixture["cases"]!)
|
|
80
|
+
{
|
|
81
|
+
var cm = (JsonObject)c!;
|
|
82
|
+
JsonNode? got;
|
|
83
|
+
try { got = Render(Run(cm)); }
|
|
84
|
+
catch (Refused e) { got = new JsonObject { ["refused"] = e.Message }; }
|
|
85
|
+
outp.Add(new JsonObject { ["id"] = cm["id"]?.DeepClone(), ["got"] = got });
|
|
86
|
+
}
|
|
87
|
+
Console.WriteLine(outp.ToJsonString(new JsonSerializerOptions { Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping }));
|
|
88
|
+
return 0;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// Раннер C#-бэкенда: тот же вход и тот же ответ, что у runner.py.
|
|
2
|
+
//
|
|
3
|
+
// Протокол выхода общий для всех целей: ответ — JSON и код 0; названный отказ
|
|
4
|
+
// среза — JSON {"refused": текст} и код 3; любой другой код — крах.
|
|
5
|
+
using System.Text.Json;
|
|
6
|
+
using System.Text.Json.Nodes;
|
|
7
|
+
|
|
8
|
+
public static class Program
|
|
9
|
+
{
|
|
10
|
+
static readonly List<object> Issues = new();
|
|
11
|
+
|
|
12
|
+
static string Text(JsonNode? n) => n is JsonValue v && v.TryGetValue<string>(out var s) ? s : n?.ToJsonString() ?? "";
|
|
13
|
+
|
|
14
|
+
static object Arg(JsonObject a)
|
|
15
|
+
{
|
|
16
|
+
string kind = Text(a["kind"]);
|
|
17
|
+
if (kind == "entity_ref") return Text(a["id"]);
|
|
18
|
+
if (kind == "const_ref")
|
|
19
|
+
{
|
|
20
|
+
// §54: разыменование предшествует исполнению; член перечисления §38 либо
|
|
21
|
+
// имя без объявления остаётся идентичностью, как в ключе атома оракула.
|
|
22
|
+
return Model.CONSTS.TryGetValue(Text(a["id"]), out var c) ? c.Item2 : RT.sym(Text(a["id"]));
|
|
23
|
+
}
|
|
24
|
+
if (kind != "value") throw new Refused("аргумент вне среза раннера: " + kind);
|
|
25
|
+
string t = Text(a["type"]?["name"]);
|
|
26
|
+
string v = Text(a["value"]);
|
|
27
|
+
return t switch
|
|
28
|
+
{
|
|
29
|
+
"urn:law:std#Money" => RT.money(v, Text(a["currency"])),
|
|
30
|
+
"urn:law:std#Decimal" or "urn:law:std#Integer" => RT.dec(v),
|
|
31
|
+
"urn:law:std#Text" => v,
|
|
32
|
+
"urn:law:std#Date" => RT.date(v),
|
|
33
|
+
_ => throw new Refused("аргумент вне среза раннера: " + t),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Тип аргумента, если известен: у value — из узла, у const_ref — из объявления
|
|
38
|
+
// константы; entity_ref типа не несёт (как у оракула).
|
|
39
|
+
static string? ArgType(JsonObject a)
|
|
40
|
+
{
|
|
41
|
+
string kind = Text(a["kind"]);
|
|
42
|
+
if (kind == "value") return Text(a["type"]?["name"]);
|
|
43
|
+
if (kind == "const_ref") return Model.CONSTS.TryGetValue(Text(a["id"]), out var c) ? c.Item1 : null;
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Совпадение типа с наследованием сущностей вверх от фактического.
|
|
48
|
+
static bool Conforms(string actual, string expected)
|
|
49
|
+
{
|
|
50
|
+
var seen = new HashSet<string>();
|
|
51
|
+
string? cur = actual;
|
|
52
|
+
while (cur is not null && seen.Add(cur))
|
|
53
|
+
{
|
|
54
|
+
if (cur == expected) return true;
|
|
55
|
+
cur = Model.BASES.TryGetValue(cur, out var b) ? b : null;
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static List<JsonObject> Args(JsonObject lit) => (lit["args"] as JsonArray ?? new JsonArray()).Select(x => (JsonObject)x!).ToList();
|
|
61
|
+
|
|
62
|
+
// Арность и типы аргументов утверждения против сигнатуры §189 (E-0046).
|
|
63
|
+
static bool WellTyped(JsonObject lit)
|
|
64
|
+
{
|
|
65
|
+
if (!Model.PARAMS.TryGetValue(Text(lit["predicate"]), out var ps)) return true;
|
|
66
|
+
var args = Args(lit);
|
|
67
|
+
if (args.Count != ps.Length) { Issues.Add("TYPE_ERROR"); return false; }
|
|
68
|
+
for (int i = 0; i < ps.Length; i++)
|
|
69
|
+
{
|
|
70
|
+
var actual = ArgType(args[i]);
|
|
71
|
+
if (actual is not null && !Conforms(actual, ps[i])) { Issues.Add("TYPE_ERROR"); return false; }
|
|
72
|
+
}
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Ключ атома у оракула §208 включает ТИП значения: несогласованный запрос
|
|
77
|
+
// атома не находит — NEITHER без issue.
|
|
78
|
+
static bool QueryTyped(JsonObject lit)
|
|
79
|
+
{
|
|
80
|
+
if (!Model.PARAMS.TryGetValue(Text(lit["predicate"]), out var ps)) return false;
|
|
81
|
+
var args = Args(lit);
|
|
82
|
+
if (args.Count != ps.Length) return false;
|
|
83
|
+
for (int i = 0; i < ps.Length; i++)
|
|
84
|
+
{
|
|
85
|
+
var actual = ArgType(args[i]);
|
|
86
|
+
if (actual is not null && !Conforms(actual, ps[i])) return false;
|
|
87
|
+
}
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
static bool KeyConflictBlocks(string predicate)
|
|
92
|
+
{
|
|
93
|
+
var tainted = Model.KeyConflictPredicates();
|
|
94
|
+
var waiting = new Stack<string>(tainted);
|
|
95
|
+
while (waiting.Count > 0)
|
|
96
|
+
{
|
|
97
|
+
var source = waiting.Pop();
|
|
98
|
+
if (!Model.KEY_READERS.TryGetValue(source, out var consumers)) continue;
|
|
99
|
+
foreach (var consumer in consumers) if (tainted.Add(consumer)) waiting.Push(consumer);
|
|
100
|
+
}
|
|
101
|
+
return tainted.Contains(predicate);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
static void Run(string casePath, string queryPath)
|
|
105
|
+
{
|
|
106
|
+
var kase = (JsonObject)JsonNode.Parse(File.ReadAllText(casePath))!;
|
|
107
|
+
var query = (JsonObject)JsonNode.Parse(File.ReadAllText(queryPath))!;
|
|
108
|
+
RT.setLegalTime(Text(kase["context"]?["legalTime"]));
|
|
109
|
+
Model.PackageFacts();
|
|
110
|
+
foreach (var a in kase["assertions"] as JsonArray ?? new JsonArray())
|
|
111
|
+
{
|
|
112
|
+
var lit = (JsonObject)a!["literal"]!;
|
|
113
|
+
if (Text(lit["polarity"]) != "positive") throw new Refused("§113: отрицательный факт вне L0-среза");
|
|
114
|
+
if (!WellTyped(lit)) continue;
|
|
115
|
+
string pred = Text(lit["predicate"]);
|
|
116
|
+
if (!Model.PARAMS.ContainsKey(pred)) continue;
|
|
117
|
+
Model.Register(pred, Args(lit).Select(Arg).ToList());
|
|
118
|
+
}
|
|
119
|
+
Model.Saturate();
|
|
120
|
+
for (int n = Model.KeyConflicts(); n > 0; n--) Issues.Add("KEY_CONFLICT");
|
|
121
|
+
if (Text(query["kind"]) != "truth") throw new Refused("вид запроса вне среза раннера: " + Text(query["kind"]));
|
|
122
|
+
var qlit = (JsonObject)query["literal"]!;
|
|
123
|
+
bool hit = false;
|
|
124
|
+
if (QueryTyped(qlit))
|
|
125
|
+
{
|
|
126
|
+
var want = Args(qlit).Select(Arg).ToList();
|
|
127
|
+
var rows = Model.TABLES.TryGetValue(Text(qlit["predicate"]), out var r) ? r : new List<List<object>>();
|
|
128
|
+
hit = rows.Any(row => row.Count == want.Count && row.Select((v, i) => RT.eq(v, want[i])).All(x => x));
|
|
129
|
+
}
|
|
130
|
+
// Открытый мир: отсутствие строки — это NEITHER, а не FALSE_ONLY.
|
|
131
|
+
var outp = new JsonObject
|
|
132
|
+
{
|
|
133
|
+
["queryId"] = query["queryId"]?.DeepClone(),
|
|
134
|
+
["truthStatus"] = hit ? "TRUE_ONLY" : "NEITHER",
|
|
135
|
+
["evaluationStatus"] = KeyConflictBlocks(Text(qlit["predicate"])) ? "NON_EXECUTABLE" : "COMPUTED",
|
|
136
|
+
["issues"] = new JsonArray(Issues.Select(x => (JsonNode)JsonValue.Create((string)x)!).ToArray()),
|
|
137
|
+
};
|
|
138
|
+
Console.WriteLine(outp.ToJsonString(new JsonSerializerOptions { Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping }));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
public static int Main(string[] argv)
|
|
142
|
+
{
|
|
143
|
+
try
|
|
144
|
+
{
|
|
145
|
+
Run(argv[0], argv[1]);
|
|
146
|
+
return 0;
|
|
147
|
+
}
|
|
148
|
+
catch (Refused e)
|
|
149
|
+
{
|
|
150
|
+
Console.WriteLine(new JsonObject { ["refused"] = e.Message }.ToJsonString(new JsonSerializerOptions { Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping }));
|
|
151
|
+
return 3;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
// Рантайм L0 для C#. Тот же контракт, что у runtime.py: точная десятичная
|
|
2
|
+
// арифметика §58 на BigInteger, деньги с валютой, названный режим округления,
|
|
3
|
+
// календарный день, член перечисления. Отказ — исключение Refused; любое
|
|
4
|
+
// другое исключение — крах.
|
|
5
|
+
using System.Numerics;
|
|
6
|
+
using System.Text;
|
|
7
|
+
|
|
8
|
+
public sealed class Refused : Exception { public Refused(string m) : base(m) { } }
|
|
9
|
+
|
|
10
|
+
public class Dec { public BigInteger U; public int S; public Dec(BigInteger u, int s) { U = u; S = s; } }
|
|
11
|
+
public sealed class Money : Dec { public string Cur; public Money(BigInteger u, int s, string cur) : base(u, s) { Cur = cur; } }
|
|
12
|
+
// Календарный день §2.15 в канонической записи ISO YYYY-MM-DD.
|
|
13
|
+
public sealed class Date { public string V; public Date(string v) { V = v; } }
|
|
14
|
+
// Член перечисления §38 либо ссылка const_ref без объявления.
|
|
15
|
+
public sealed class Sym { public string Id; public Sym(string id) { Id = id; } }
|
|
16
|
+
|
|
17
|
+
public static class RT
|
|
18
|
+
{
|
|
19
|
+
static BigInteger P10(int n) => BigInteger.Pow(10, n);
|
|
20
|
+
|
|
21
|
+
public static Dec dec(string lit)
|
|
22
|
+
{
|
|
23
|
+
int dot = lit.IndexOf('.');
|
|
24
|
+
string i = dot < 0 ? lit : lit[..dot];
|
|
25
|
+
string f = dot < 0 ? "" : lit[(dot + 1)..];
|
|
26
|
+
bool neg = i.StartsWith("-");
|
|
27
|
+
var u = BigInteger.Parse((neg ? i[1..] : i) + f);
|
|
28
|
+
return new Dec(neg ? -u : u, f.Length);
|
|
29
|
+
}
|
|
30
|
+
public static Money money(string lit, string cur) { var d = dec(lit); return new Money(d.U, d.S, cur); }
|
|
31
|
+
public static Date date(string lit) => new Date(lit);
|
|
32
|
+
public static Sym sym(string id) => new Sym(id);
|
|
33
|
+
|
|
34
|
+
// --- виды ---------------------------------------------------------------
|
|
35
|
+
static bool IsNum(object v) => v is Dec;
|
|
36
|
+
static bool IsMoney(object v) => v is Money;
|
|
37
|
+
|
|
38
|
+
// §48/§58: сложение, вычитание, min/max требуют совпадения видов; у денег — и валюты.
|
|
39
|
+
static void Same(object a, object b, string op)
|
|
40
|
+
{
|
|
41
|
+
if (!IsNum(a) || !IsNum(b) || IsMoney(a) != IsMoney(b)) throw new Refused("§58: виды операндов не совпадают: " + op);
|
|
42
|
+
if (a is Money ma && b is Money mb && ma.Cur != mb.Cur) throw new Refused("§58: разные валюты: " + op);
|
|
43
|
+
}
|
|
44
|
+
static (BigInteger, BigInteger, int) Pair(Dec a, Dec b)
|
|
45
|
+
{
|
|
46
|
+
int s = Math.Max(a.S, b.S);
|
|
47
|
+
return (a.U * P10(s - a.S), b.U * P10(s - b.S), s);
|
|
48
|
+
}
|
|
49
|
+
static Dec Mk(BigInteger u, int s, object like) => like is Money m ? new Money(u, s, m.Cur) : new Dec(u, s);
|
|
50
|
+
// Целое значение: дробная часть нулевая (защита в глубину под статикой плана).
|
|
51
|
+
static BigInteger? Integral(object v)
|
|
52
|
+
{
|
|
53
|
+
if (v is not Dec d || v is Money) return null;
|
|
54
|
+
var q = BigInteger.DivRem(d.U, P10(d.S), out var r);
|
|
55
|
+
return r.IsZero ? q : null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// --- арифметика §58 -----------------------------------------------------
|
|
59
|
+
public static Dec add(object a, object b) { Same(a, b, "add"); var (x, y, s) = Pair((Dec)a, (Dec)b); return Mk(x + y, s, a); }
|
|
60
|
+
public static Dec sub(object a, object b) { Same(a, b, "sub"); var (x, y, s) = Pair((Dec)a, (Dec)b); return Mk(x - y, s, a); }
|
|
61
|
+
|
|
62
|
+
// Правило скаляра §49: безразмерное масштабирует размерное; масштаб результата —
|
|
63
|
+
// сумма масштабов. Два размерных не перемножаются.
|
|
64
|
+
public static Dec mul(object a, object b)
|
|
65
|
+
{
|
|
66
|
+
if (!IsNum(a) || !IsNum(b)) throw new Refused("§58: виды операндов не совпадают: mul");
|
|
67
|
+
if (IsMoney(a) && IsMoney(b)) throw new Refused("§58: произведение двух размерных величин не определено");
|
|
68
|
+
var x = (Dec)a; var y = (Dec)b;
|
|
69
|
+
return Mk(x.U * y.U, x.S + y.S, IsMoney(a) ? a : b);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Точное десятичное частное num/den при 10-гладком знаменателе (§18).
|
|
73
|
+
static (BigInteger, int)? Exact(BigInteger num, BigInteger den)
|
|
74
|
+
{
|
|
75
|
+
var g = BigInteger.GreatestCommonDivisor(num, den);
|
|
76
|
+
if (g.IsZero) g = BigInteger.One;
|
|
77
|
+
num /= g; den /= g;
|
|
78
|
+
if (den.Sign < 0) { num = -num; den = -den; }
|
|
79
|
+
int twos = 0, fives = 0;
|
|
80
|
+
while ((den % 2).IsZero) { den /= 2; twos++; }
|
|
81
|
+
while ((den % 5).IsZero) { den /= 5; fives++; }
|
|
82
|
+
if (!den.IsOne) return null;
|
|
83
|
+
int k = Math.Max(twos, fives);
|
|
84
|
+
return (num * BigInteger.Pow(2, k - twos) * BigInteger.Pow(5, k - fives), k);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Таблица делимых §58 в срезе: Decimal/Decimal, Money/Decimal, Money/Money одной
|
|
88
|
+
// валюты. Integer/Integer даёт Rational — вне среза, отвергается планом статически.
|
|
89
|
+
public static Dec div(object a, object b)
|
|
90
|
+
{
|
|
91
|
+
if (!IsNum(a) || !IsNum(b)) throw new Refused("§58: деление вне таблицы делимых");
|
|
92
|
+
var x = (Dec)a; var y = (Dec)b;
|
|
93
|
+
if (y.U.IsZero) throw new Refused("деление на ноль — evaluation error (§58)");
|
|
94
|
+
Money? like = null;
|
|
95
|
+
if (a is Money ma && b is Money mb)
|
|
96
|
+
{
|
|
97
|
+
if (ma.Cur != mb.Cur) throw new Refused("CURRENCY_MISMATCH: §58 делит Money на Money только при тождественной валюте");
|
|
98
|
+
}
|
|
99
|
+
else if (a is Money m) like = m;
|
|
100
|
+
else if (b is Money) throw new Refused("§58: деление вне таблицы делимых");
|
|
101
|
+
var q = Exact(x.U * P10(y.S), y.U * P10(x.S));
|
|
102
|
+
if (q is null)
|
|
103
|
+
{
|
|
104
|
+
if (like is not null) throw new Refused("INEXACT_DIVISION: округление только явной политикой (§50/§18)");
|
|
105
|
+
throw new Refused("§58: частное не 10-гладкое — Rational вне среза");
|
|
106
|
+
}
|
|
107
|
+
var (u, s) = q.Value;
|
|
108
|
+
return like is not null ? new Money(u, s, like.Cur) : new Dec(u, s);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Евклидов остаток §58: 0 <= r < |b| при любых знаках операндов.
|
|
112
|
+
public static Dec mod(object a, object b)
|
|
113
|
+
{
|
|
114
|
+
var x = Integral(a); var y = Integral(b);
|
|
115
|
+
if (x is null || y is null) throw new Refused("§58: mod определён только для Integer");
|
|
116
|
+
if (y.Value.IsZero) throw new Refused("остаток от деления на ноль — evaluation error (§58)");
|
|
117
|
+
var m = BigInteger.Abs(y.Value);
|
|
118
|
+
var r = ((x.Value % m) + m) % m;
|
|
119
|
+
return new Dec(r, 0);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public static Dec min(object a, object b) { Same(a, b, "min"); var (x, y, _) = Pair((Dec)a, (Dec)b); return x <= y ? (Dec)a : (Dec)b; }
|
|
123
|
+
public static Dec max(object a, object b) { Same(a, b, "max"); var (x, y, _) = Pair((Dec)a, (Dec)b); return x >= y ? (Dec)a : (Dec)b; }
|
|
124
|
+
|
|
125
|
+
public static Dec abs(object v)
|
|
126
|
+
{
|
|
127
|
+
if (!IsNum(v)) throw new Refused("§58: abs — не числовой вид");
|
|
128
|
+
var d = (Dec)v;
|
|
129
|
+
return Mk(BigInteger.Abs(d.U), d.S, v);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
static readonly BigInteger PowMin = long.MinValue, PowMax = long.MaxValue;
|
|
133
|
+
|
|
134
|
+
// §58 (E-0075): только Integer pow Integer; порядок проверок — знак, предел,
|
|
135
|
+
// вычисление, диапазон — часть контракта.
|
|
136
|
+
public static Dec pow(object bas, object exp)
|
|
137
|
+
{
|
|
138
|
+
var x = Integral(bas); var e = Integral(exp);
|
|
139
|
+
if (x is null || e is null) throw new Refused("§58: pow определён только для Integer");
|
|
140
|
+
if (e.Value.Sign < 0) throw new Refused("§58: pow — показатель отрицателен");
|
|
141
|
+
if (e.Value > 4096) throw new Refused("RESOURCE_LIMIT: pow — показатель превышает 4096");
|
|
142
|
+
var r = BigInteger.Pow(x.Value, (int)e.Value);
|
|
143
|
+
if (r < PowMin || r > PowMax) throw new Refused("RESOURCE_LIMIT: pow — результат вне 64-битного диапазона");
|
|
144
|
+
return new Dec(r, 0);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
public static Dec round(object m, object digits, string mode)
|
|
148
|
+
{
|
|
149
|
+
if (mode != "HALF_UP") throw new Refused("§50: режим округления не реализован: " + mode);
|
|
150
|
+
if (!IsNum(m)) throw new Refused("§50: round — не числовой вид");
|
|
151
|
+
var x = (Dec)m;
|
|
152
|
+
int n = digits is Dec d ? (int)(d.U / P10(d.S)) : 0;
|
|
153
|
+
if (x.S <= n) return Mk(x.U * P10(n - x.S), n, m);
|
|
154
|
+
var drop = P10(x.S - n);
|
|
155
|
+
bool neg = x.U.Sign < 0;
|
|
156
|
+
var q = BigInteger.DivRem(BigInteger.Abs(x.U), drop, out var r);
|
|
157
|
+
var up = r * 2 >= drop ? q + 1 : q; // HALF_UP — от нуля
|
|
158
|
+
return Mk(neg ? -up : up, n, m);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// --- сравнение и равенство -----------------------------------------------
|
|
162
|
+
static bool Ordered(string op, int c) => op switch
|
|
163
|
+
{
|
|
164
|
+
"lt" => c < 0, "le" => c <= 0, "gt" => c > 0, "ge" => c >= 0, "eq" => c == 0, "ne" => c != 0,
|
|
165
|
+
_ => throw new Refused("сравнение вне среза рантайма: " + op),
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
public static bool cmp(object a, string op, object b)
|
|
169
|
+
{
|
|
170
|
+
if (a is Sym || b is Sym)
|
|
171
|
+
{
|
|
172
|
+
bool same = a is Sym sa && b is Sym sb && sa.Id == sb.Id;
|
|
173
|
+
if (op == "eq") return same;
|
|
174
|
+
if (op == "ne") return !same;
|
|
175
|
+
throw new Refused("§57: вид enum не упорядочен");
|
|
176
|
+
}
|
|
177
|
+
if (a is Date || b is Date)
|
|
178
|
+
{
|
|
179
|
+
if (a is Date da && b is Date db) return Ordered(op, string.CompareOrdinal(da.V, db.V));
|
|
180
|
+
if (op == "eq") return false;
|
|
181
|
+
if (op == "ne") return true;
|
|
182
|
+
throw new Refused("§57: Date сравнивается только с Date");
|
|
183
|
+
}
|
|
184
|
+
if (a is string || b is string)
|
|
185
|
+
{
|
|
186
|
+
bool same = a is string x && b is string y && x == y;
|
|
187
|
+
if (op == "eq") return same;
|
|
188
|
+
if (op == "ne") return !same;
|
|
189
|
+
throw new Refused("порядок на Text вне среза рантайма: " + op);
|
|
190
|
+
}
|
|
191
|
+
if (IsMoney(a) != IsMoney(b)) throw new Refused("§49: сравнение денег с безразмерным");
|
|
192
|
+
if (a is Money ma && b is Money mb && ma.Cur != mb.Cur) throw new Refused("§49: разные валюты");
|
|
193
|
+
var (p, q, _) = Pair((Dec)a, (Dec)b);
|
|
194
|
+
return Ordered(op, p.CompareTo(q));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
public static bool eq(object a, object b)
|
|
198
|
+
{
|
|
199
|
+
if (a is Sym || b is Sym) return a is Sym sa && b is Sym sb && sa.Id == sb.Id;
|
|
200
|
+
if (a is Date || b is Date) return a is Date da && b is Date db && da.V == db.V;
|
|
201
|
+
if (a is string || b is string) return a is string x && b is string y && x == y;
|
|
202
|
+
if (IsMoney(a) != IsMoney(b)) return false;
|
|
203
|
+
if (a is Money ma && b is Money mb && ma.Cur != mb.Cur) return false;
|
|
204
|
+
var (p, q, _) = Pair((Dec)a, (Dec)b);
|
|
205
|
+
return p == q;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
static string Norm(Dec d)
|
|
209
|
+
{
|
|
210
|
+
var u = d.U; int s = d.S;
|
|
211
|
+
while (s > 0 && (u % 10).IsZero) { u /= 10; s--; }
|
|
212
|
+
return u + "e-" + s;
|
|
213
|
+
}
|
|
214
|
+
// Разделитель и экран внутри текста экранируются: иначе ["a|e:b","c"] и
|
|
215
|
+
// ["a","b|e:c"] склеивались в один ключ, и второй факт терялся.
|
|
216
|
+
static string Esc(string t) => t.Replace("\\", "\\\\").Replace("|", "\\|");
|
|
217
|
+
|
|
218
|
+
public static string key(List<object> row)
|
|
219
|
+
{
|
|
220
|
+
var sb = new StringBuilder();
|
|
221
|
+
for (int i = 0; i < row.Count; i++)
|
|
222
|
+
{
|
|
223
|
+
if (i > 0) sb.Append('|');
|
|
224
|
+
var v = row[i];
|
|
225
|
+
if (v is string t) sb.Append("e:").Append(Esc(t));
|
|
226
|
+
else if (v is Date dt) sb.Append("t:").Append(dt.V);
|
|
227
|
+
else if (v is Sym sy) sb.Append("c:").Append(Esc(sy.Id));
|
|
228
|
+
else if (v is Money mo) sb.Append("m:").Append(mo.Cur).Append(':').Append(Norm(mo));
|
|
229
|
+
else sb.Append("d:").Append(Norm((Dec)v));
|
|
230
|
+
}
|
|
231
|
+
return sb.ToString();
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
static string legalTimeValue = "";
|
|
235
|
+
public static void setLegalTime(string t) => legalTimeValue = t;
|
|
236
|
+
public static string legalTime()
|
|
237
|
+
{
|
|
238
|
+
if (legalTimeValue == "") throw new Refused("legalTime не подан делом");
|
|
239
|
+
return legalTimeValue;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
public static List<object> row(params object[] vs) => new List<object>(vs);
|
|
243
|
+
}
|