aboutsummaryrefslogtreecommitdiffstats
path: root/research/experiments/045-proof-compiler/app-way.h
diff options
context:
space:
mode:
Diffstat (limited to 'research/experiments/045-proof-compiler/app-way.h')
-rw-r--r--research/experiments/045-proof-compiler/app-way.h193
1 files changed, 193 insertions, 0 deletions
diff --git a/research/experiments/045-proof-compiler/app-way.h b/research/experiments/045-proof-compiler/app-way.h
new file mode 100644
index 0000000..44e3d98
--- /dev/null
+++ b/research/experiments/045-proof-compiler/app-way.h
@@ -0,0 +1,193 @@
+/* Research 045: UAX #14's app (aup's examples/linebreak.aup: on line, decide and the fns it calls), written once by hand
+ * as an emitter would write it, against the macros a way (app.c) defines first: how numbers that are whole are held
+ * (IDX) and computed, how an index is checked, how the event's lists, the message's points and the stored ranges are
+ * held and read (LIST_N numbers, LIST_I whole numbers, LIST_B bools), what a record of lists takes (CAPTURE), and what
+ * the budget charges. Included once a way, with WAY
+ * the suffix of its names. Locals are C's (registers) and each aup fn a C function in every way.
+ *
+ * C's && and || go no further than they must; where the executor evaluates both sides, this does less (so the first
+ * way is cheaper than the module's code would be, never dearer). */
+#define JOIN2(a, b) a##_##b
+#define JOIN(a, b) JOIN2(a, b)
+#define FN(name) JOIN(name, WAY)
+
+/* -1 aside, every value the app keeps of a code point's position: the result of a call that faulted is 0 and x->fault set. */
+#define FAIL do { x->fault = true; x->fault_line = __LINE__; return 0; } while (0)
+#define CALLED(e) ({ __typeof__(e) called_ = (e); if (x->fault) return 0; called_; })
+
+typedef struct { LIST_N codes, cls, eff; LIST_I start, nonspace, ri, at; LIST_B joined, numeric; } FN(Text);
+
+static double FN(range)(CONTEXT *x, double c) {
+ CHARGE(CALL_COST);
+ IDX low = 0, high = R_COUNT;
+ while (GT(SUB(high, low), 1)) {
+ CHARGE(ROUND_COST);
+ IDX middle = DIV2(ADD(low, high));
+ if (R_START(middle) <= c) low = middle;
+ else high = middle;
+ }
+ return (double)low;
+}
+
+static IDX FN(next_unit)(CONTEXT *x, const FN(Text) *t, IDX i) {
+ CHARGE(CALL_COST);
+ IDX j = ADD(i, 1);
+ while (j < NCOUNT(t->codes) && GETB(t->joined, j)) {
+ CHARGE(ROUND_COST);
+ j = ADD(j, 1);
+ }
+ return j;
+}
+
+static bool FN(aksara)(CONTEXT *x, const FN(Text) *t, IDX u) {
+ CHARGE(CALL_COST);
+ return GETN(t->eff, u) == AK || GETN(t->eff, u) == AS || GETN(t->codes, u) == 0x25CC;
+}
+static bool FN(pi)(CONTEXT *x, const FN(Text) *t, IDX k) { CHARGE(CALL_COST); return R_PI(GETI(t->at, k)); }
+static bool FN(pf)(CONTEXT *x, const FN(Text) *t, IDX k) { CHARGE(CALL_COST); return R_PF(GETI(t->at, k)); }
+static bool FN(east)(CONTEXT *x, const FN(Text) *t, IDX k) { CHARGE(CALL_COST); return R_EAST(GETI(t->at, k)); }
+
+#define END(c) ((c) == BK || (c) == CR || (c) == LF || (c) == NL)
+#define NEXT_UNIT(i) CALLED(FN(next_unit)(x, t, (i)))
+#define AKSARA(u) CALLED(FN(aksara)(x, t, (u)))
+#define PI(k) CALLED(FN(pi)(x, t, (k)))
+#define PF(k) CALLED(FN(pf)(x, t, (k)))
+#define EAST(k) CALLED(FN(east)(x, t, (k)))
+
+static int FN(decide)(CONTEXT *x, const FN(Text) *t, IDX i) {
+ CHARGE(CALL_COST);
+ IDX n = NCOUNT(t->codes);
+ double a = GETN(t->cls, SUB(i, 1)), b = GETN(t->cls, i), A = GETN(t->eff, SUB(i, 1)), B = GETN(t->eff, i);
+ IDX unit = GETI(t->start, SUB(i, 1)), before = GETI(t->nonspace, SUB(i, 1));
+ double base = GETN(t->codes, unit);
+ if (a == BK) return MANDATORY; /* LB4 */
+ if (a == CR && b == LF) return NONE; /* LB5 */
+ if (a == CR || a == LF || a == NL) return MANDATORY;
+ if (END(b)) return NONE; /* LB6 */
+ if (b == SP || b == ZW) return NONE; /* LB7 */
+ if (before >= 0 && GETN(t->eff, before) == ZW) return ALLOWED; /* LB8 */
+ if (a == ZWJ) return NONE; /* LB8a */
+ if (GETB(t->joined, i)) return NONE; /* LB9 */
+ if (A == WJ || B == WJ) return NONE; /* LB11 */
+ if (A == GL) return NONE; /* LB12 */
+ if (B == GL && A != SP && A != BA && A != HY) return NONE; /* LB12a */
+ if (B == CL || B == CP || B == EX || B == SY) return NONE; /* LB13 */
+ if (before >= 0 && GETN(t->eff, before) == OP) return NONE; /* LB14 */
+ if (before >= 0 && GETN(t->eff, before) == QU && PI(before)) { /* LB15a */
+ if (before == 0) return NONE;
+ double q = GETN(t->eff, SUB(before, 1));
+ if (END(q) || q == OP || q == QU || q == GL || q == SP || q == ZW) return NONE;
+ }
+ if (B == QU && PF(i)) { /* LB15b */
+ IDX j = NEXT_UNIT(i);
+ if (j == n) return NONE;
+ double e = GETN(t->eff, j);
+ if (e == SP || e == GL || e == WJ || e == CL || e == QU || e == CP || e == EX || e == IS || e == SY || END(e) || e == ZW)
+ return NONE;
+ }
+ if (A == SP && B == IS) { /* LB15c */
+ IDX j = NEXT_UNIT(i);
+ if (j < n && GETN(t->eff, j) == NU) return ALLOWED;
+ }
+ if (B == IS) return NONE; /* LB15d */
+ if (B == NS && before >= 0 && (GETN(t->eff, before) == CL || GETN(t->eff, before) == CP)) return NONE; /* LB16 */
+ if (B == B2 && before >= 0 && GETN(t->eff, before) == B2) return NONE; /* LB17 */
+#ifdef BREAK_ONE_RULE
+ if (A == SP) return NONE; /* a rule made wrong: the check must refuse the way */
+#else
+ if (A == SP) return ALLOWED; /* LB18 */
+#endif
+ if (B == QU && !PI(i)) return NONE; /* LB19 */
+ if (A == QU && !PF(unit)) return NONE;
+ if (B == QU) { /* LB19a */
+ IDX j = NEXT_UNIT(i);
+ if (!EAST(unit) || j == n || !EAST(j)) return NONE;
+ }
+ if (A == QU && (!EAST(i) || unit == 0 || !EAST(GETI(t->start, SUB(unit, 1))))) return NONE;
+ if (B == CB || A == CB) return ALLOWED; /* LB20 */
+ if ((A == HY || base == 0x2010) && B == AL) { /* LB20a */
+ double w = unit > 0 ? GETN(t->eff, SUB(unit, 1)) : SP;
+ if (END(w) || w == SP || w == ZW || w == CB || w == GL) return NONE;
+ }
+ if (B == BA || B == HY || B == NS || A == BB) return NONE; /* LB21 */
+ if ((A == HY || (A == BA && !EAST(unit))) && unit > 0 && GETN(t->eff, SUB(unit, 1)) == HL && B != HL) return NONE; /* LB21a */
+ if (A == SY && B == HL) return NONE; /* LB21b */
+ if (B == IN) return NONE; /* LB22 */
+ if (((A == AL || A == HL) && B == NU) || (A == NU && (B == AL || B == HL))) return NONE; /* LB23 */
+ if ((A == PR && (B == ID || B == EB || B == EM)) || ((A == ID || A == EB || A == EM) && B == PO)) return NONE; /* LB23a */
+ if (((A == PR || A == PO) && (B == AL || B == HL)) || ((A == AL || A == HL) && (B == PR || B == PO))) return NONE; /* LB24 */
+ if ((B == PO || B == PR) &&
+ (GETB(t->numeric, SUB(i, 1)) || ((A == CL || A == CP) && unit > 0 && GETB(t->numeric, SUB(unit, 1)))))
+ return NONE; /* LB25 */
+ if (A == PO || A == PR) {
+ if (B == NU) return NONE;
+ if (B == OP) {
+ IDX j = NEXT_UNIT(i);
+ if (j < n && GETN(t->eff, j) == IS) j = NEXT_UNIT(j);
+ if (j < n && GETN(t->eff, j) == NU) return NONE;
+ }
+ }
+ if ((A == HY || A == IS || GETB(t->numeric, SUB(i, 1))) && B == NU) return NONE;
+ if (A == JL && (B == JL || B == JV || B == H2 || B == H3)) return NONE; /* LB26 */
+ if (((A == JV || A == H2) && (B == JV || B == JT)) || ((A == JT || A == H3) && B == JT)) return NONE;
+ bool jamo = A == JL || A == JV || A == JT || A == H2 || A == H3; /* LB27 */
+ if ((jamo && B == PO) || (A == PR && (B == JL || B == JV || B == JT || B == H2 || B == H3))) return NONE;
+ if ((A == AL || A == HL) && (B == AL || B == HL)) return NONE; /* LB28 */
+ if (A == AP && AKSARA(i)) return NONE; /* LB28a */
+ if (AKSARA(unit) && (B == VF || B == VI)) return NONE;
+ if (A == VI && unit > 0 && AKSARA(GETI(t->start, SUB(unit, 1))) && (B == AK || GETN(t->codes, i) == 0x25CC)) return NONE;
+ if (AKSARA(unit) && AKSARA(i)) {
+ IDX j = NEXT_UNIT(i);
+ if (j < n && GETN(t->eff, j) == VF) return NONE;
+ }
+ if (A == IS && (B == AL || B == HL)) return NONE; /* LB29 */
+ if ((A == AL || A == HL || A == NU) && B == OP && !EAST(i)) return NONE; /* LB30 */
+ if (A == CP && !EAST(unit) && (B == AL || B == HL || B == NU)) return NONE;
+ if (A == RI && B == RI && MOD2(GETI(t->ri, SUB(i, 1))) == 1) return NONE; /* LB30a */
+ if (B == EM && (A == EB || R_PICT(GETI(t->at, unit)))) return NONE; /* LB30b */
+ return ALLOWED; /* LB31 */
+}
+
+/* on line: the boundaries of the line's points into got (0 none, 1 allowed, 2 mandatory), count + 1 of them; false on a fault. */
+static bool FN(on_line)(CONTEXT *x, const POINTS *points, uint8_t *got) {
+ LINE_BEGIN;
+ for (IDX k = 0; k < P_COUNT(points); k = k + 1) {
+ CHARGE(ROUND_COST);
+ double code = P_CODE(points, k);
+ IDX i = NCOUNT(L(codes));
+ IDX r = (IDX)CALLED(FN(range)(x, code));
+ double c = R_CLASS(r);
+ bool mark = c == CM || c == ZWJ;
+ double previous = i > 0 ? GETN(L(eff), SUB(i, 1)) : SP;
+ bool joins = mark && i > 0 && !END(previous) && previous != SP && previous != ZW; /* LB9, LB10 */
+ double e = joins ? previous : mark ? AL : c;
+ APPN(L(codes), code);
+ APPN(L(cls), c);
+ APPI(L(at), r);
+ APPB(L(joined), joins);
+ APPN(L(eff), e);
+ APPI(L(start), joins ? GETI(L(start), SUB(i, 1)) : i);
+ APPI(L(nonspace), e != SP ? GETI(L(start), i) : i > 0 ? GETI(L(nonspace), SUB(i, 1)) : (IDX)-1);
+ APPB(L(numeric), joins ? GETB(L(numeric), SUB(i, 1)) : e == NU || ((e == SY || e == IS) && i > 0 && GETB(L(numeric), SUB(i, 1))));
+ APPI(L(ri), joins ? GETI(L(ri), SUB(i, 1)) : e == RI ? ADD(i > 0 ? GETI(L(ri), SUB(i, 1)) : (IDX)0, 1) : (IDX)0);
+ }
+ FN(Text) t;
+ CAPTURE(t.codes, codes); CAPTURE(t.cls, cls); CAPTURE(t.eff, eff); CAPTURE(t.joined, joined); CAPTURE(t.start, start);
+ CAPTURE(t.nonspace, nonspace); CAPTURE(t.numeric, numeric); CAPTURE(t.ri, ri); CAPTURE(t.at, at);
+ OUT_APPEND(0); /* LB2 */
+ for (IDX i = 1; i < NCOUNT(L(codes)); i = i + 1) {
+ CHARGE(ROUND_COST);
+ OUT_APPEND(CALLED(FN(decide)(x, &t, i)));
+ }
+ if (NCOUNT(L(codes)) > 0) OUT_APPEND(2); /* LB3 */
+ OUT_EMIT(got);
+ LINE_END;
+ return true;
+}
+
+#undef END
+#undef NEXT_UNIT
+#undef AKSARA
+#undef PI
+#undef PF
+#undef EAST