1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
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
|