-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtranslate.c
183 lines (142 loc) · 4.21 KB
/
translate.c
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
#include "translate.h"
#include "parse.h"
#include "prob.h"
#include "util.h"
struct ProbCtx initCtx(struct Prob p)
{
if(p.len == 1)
{
p_free(p);
return CONST_CTX(p.low);
}
else
{
return (struct ProbCtx){
.prob = p,
.singleton = false
};
}
}
void freeCtx(struct ProbCtx ctx)
{
if(!ctx.consumed)
p_free(ctx.prob);
}
struct Prob translate(struct ProbCtx *ctx, const struct Die *d)
{
switch(d->op)
{
case INT:
return p_constant(d->constant);
case 'd':
return p_dies(translate(ctx, d->unop));
case '@':
{
if(! ctx)
eprintf("Invalid die expression; '@' outside of match context\n");
if(ctx->singleton)
return p_dup(P_CONST(ctx->val));
if(ctx->consumed)
eprintf("Invalid die expression; '@' uses non-linearly, i.e. twice in the same context\n");
ctx->consumed = true;
return ctx->prob;
}
case '(':
return translate(ctx, d->unop);
case 'x':
return p_muls(translate(ctx, d->biop.l), translate(ctx, d->biop.r));
case '*':
return p_cmuls(translate(ctx, d->biop.l), translate(ctx, d->biop.r));
case '+':
return p_adds(translate(ctx, d->biop.l), translate(ctx, d->biop.r));
case '/':
return p_cdivs(translate(ctx, d->biop.l), translate(ctx, d->biop.r));
case '-':
return p_adds(translate(ctx, d->biop.l), p_negs(translate(ctx, d->biop.r)));
case SLASH_SLASH:
return p_udivs(translate(ctx, d->biop.l), translate(ctx, d->biop.r));
case '^':
case '_':
case DOLLAR_UP:
return p_selects(translate(ctx, d->select.v), d->select.sel, d->select.of, d->op != '_', d->op == DOLLAR_UP);
case UP_BANG:
case UP_DOLLAR:
return p_selects_bust(translate(ctx, d->select.v), d->select.sel, d->select.of, d->select.bust, d->op == UP_DOLLAR);
case '~':
{
struct PatternProb pt = pt_translate(ctx, *d->reroll.pat);
return p_rerolls(translate(ctx, d->reroll.v), pt);
}
case '\\':
{
struct PatternProb pt = pt_translate(ctx, *d->reroll.pat);
return p_sans(translate(ctx, d->reroll.v), pt);
}
case '!':
return p_explodes(translate(ctx, d->unop));
case '$':
return p_explode_ns(translate(ctx, d->explode.v), d->explode.rounds);
case '<':
return p_bool(1.0 - p_leqs(translate(ctx, d->biop.r), translate(ctx, d->biop.l)));
case '>':
return p_bool(1.0 - p_leqs(translate(ctx, d->biop.l), translate(ctx, d->biop.r)));
case LT_EQ:
return p_bool(p_leqs(translate(ctx, d->biop.l), translate(ctx, d->biop.r)));
case GT_EQ:
return p_bool(p_leqs(translate(ctx, d->biop.r), translate(ctx, d->biop.l)));
case '=':
return p_bool(p_eqs(translate(ctx, d->biop.l), translate(ctx, d->biop.r)));
case NEQ:
return p_adds(p_constant(1), p_negs(p_bool(p_eq(translate(ctx, d->biop.l), translate(ctx, d->biop.r)))));
case '?':
return p_coalesces(translate(ctx, d->biop.l), translate(ctx, d->biop.r));
case ':':
return p_terns(translate(ctx, d->ternary.cond), translate(ctx, d->ternary.then), translate(ctx, d->ternary.otherwise));
case UPUP:
return p_maxs(translate(ctx, d->biop.l), translate(ctx, d->biop.r));
case __:
return p_mins(translate(ctx, d->biop.l), translate(ctx, d->biop.r));
case '[':
{
struct Prob running = translate(ctx, d->match.v);
struct Prob result = {};
for (int i = 0; i < d->match.cases; i++)
{
struct PatternProb pt = pt_translate(ctx, d->match.patterns[i]);
struct Prob hit = pt_probs(pt, &running);
pp_free(pt);
double pHit = p_norms(&hit);
if(d->match.actions && pHit > 0.0)
{
struct ProbCtx newCtx = initCtx(hit);
struct Prob action = translate(&newCtx, d->match.actions + i);
result = p_merges(result, action, pHit);
freeCtx(newCtx);
}
else
p_free(hit);
}
double pMiss = p_sum(running);
p_free(running);
if(d->match.actions)
{
if(pMiss == 1.0)
eprintf("Invalid pattern match; All cases are impossible\n");
return p_scales(result, 1.0 / (1.0 - pMiss));
}
else
return p_bool(1.0 - pMiss);
}
default:
eprintf("Invalid die expression; Unknown operator %s\n", tkstr(d->op));
}
}
struct PatternProb pt_translate(struct ProbCtx *ctx, struct Pattern p)
{
struct PatternProb pp = { .op = p.op };
if(p.op)
pp.prob = translate(ctx, &p.die);
else
pp.set = p.set;
return pp;
}