Skip to content

Commit 762a552

Browse files
committed
split math from std
1 parent 8371a7a commit 762a552

2 files changed

Lines changed: 240 additions & 233 deletions

File tree

src/interpreter/lib/math.ts

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
import { NUM, FN_NATIVE, NULL } from '../value.js';
2+
import { assertNumber, expectAny, assertArray } from '../util.js';
3+
import { AiScriptRuntimeError } from '../../error.js';
4+
import { CryptoGen } from '../../utils/random/CryptoGen.js';
5+
import { GenerateChaCha20Random, GenerateLegacyRandom, GenerateRC4Random } from '../../utils/random/genrng.js';
6+
import type { Value } from '../value.js';
7+
8+
export const stdMath: Record<`Math:${string}`, Value> = {
9+
'Math:Infinity': NUM(Infinity),
10+
11+
'Math:E': NUM(Math.E),
12+
'Math:LN2': NUM(Math.LN2),
13+
'Math:LN10': NUM(Math.LN10),
14+
'Math:LOG2E': NUM(Math.LOG2E),
15+
'Math:LOG10E': NUM(Math.LOG10E),
16+
'Math:PI': NUM(Math.PI),
17+
'Math:SQRT1_2': NUM(Math.SQRT1_2),
18+
'Math:SQRT2': NUM(Math.SQRT2),
19+
20+
'Math:abs': FN_NATIVE(([v]) => {
21+
assertNumber(v);
22+
return NUM(Math.abs(v.value));
23+
}),
24+
25+
'Math:acos': FN_NATIVE(([v]) => {
26+
assertNumber(v);
27+
return NUM(Math.acos(v.value));
28+
}),
29+
30+
'Math:acosh': FN_NATIVE(([v]) => {
31+
assertNumber(v);
32+
return NUM(Math.acosh(v.value));
33+
}),
34+
35+
'Math:asin': FN_NATIVE(([v]) => {
36+
assertNumber(v);
37+
return NUM(Math.asin(v.value));
38+
}),
39+
40+
'Math:asinh': FN_NATIVE(([v]) => {
41+
assertNumber(v);
42+
return NUM(Math.asinh(v.value));
43+
}),
44+
45+
'Math:atan': FN_NATIVE(([v]) => {
46+
assertNumber(v);
47+
return NUM(Math.atan(v.value));
48+
}),
49+
50+
'Math:atanh': FN_NATIVE(([v]) => {
51+
assertNumber(v);
52+
return NUM(Math.atanh(v.value));
53+
}),
54+
55+
'Math:atan2': FN_NATIVE(([y, x]) => {
56+
assertNumber(y);
57+
assertNumber(x);
58+
return NUM(Math.atan2(y.value, x.value));
59+
}),
60+
61+
'Math:cbrt': FN_NATIVE(([v]) => {
62+
assertNumber(v);
63+
return NUM(Math.cbrt(v.value));
64+
}),
65+
66+
'Math:ceil': FN_NATIVE(([v]) => {
67+
assertNumber(v);
68+
return NUM(Math.ceil(v.value));
69+
}),
70+
71+
'Math:clz32': FN_NATIVE(([v]) => {
72+
assertNumber(v);
73+
return NUM(Math.clz32(v.value));
74+
}),
75+
76+
'Math:cos': FN_NATIVE(([v]) => {
77+
assertNumber(v);
78+
return NUM(Math.cos(v.value));
79+
}),
80+
81+
'Math:cosh': FN_NATIVE(([v]) => {
82+
assertNumber(v);
83+
return NUM(Math.cosh(v.value));
84+
}),
85+
86+
'Math:exp': FN_NATIVE(([v]) => {
87+
assertNumber(v);
88+
return NUM(Math.exp(v.value));
89+
}),
90+
91+
'Math:expm1': FN_NATIVE(([v]) => {
92+
assertNumber(v);
93+
return NUM(Math.expm1(v.value));
94+
}),
95+
96+
'Math:floor': FN_NATIVE(([v]) => {
97+
assertNumber(v);
98+
return NUM(Math.floor(v.value));
99+
}),
100+
101+
'Math:fround': FN_NATIVE(([v]) => {
102+
assertNumber(v);
103+
return NUM(Math.fround(v.value));
104+
}),
105+
106+
'Math:hypot': FN_NATIVE(([vs]) => {
107+
assertArray(vs);
108+
const values = [];
109+
for (const v of vs.value) {
110+
assertNumber(v);
111+
values.push(v.value);
112+
}
113+
return NUM(Math.hypot(...values));
114+
}),
115+
116+
'Math:imul': FN_NATIVE(([x, y]) => {
117+
assertNumber(x);
118+
assertNumber(y);
119+
return NUM(Math.imul(x.value, y.value));
120+
}),
121+
122+
'Math:log': FN_NATIVE(([v]) => {
123+
assertNumber(v);
124+
return NUM(Math.log(v.value));
125+
}),
126+
127+
'Math:log1p': FN_NATIVE(([v]) => {
128+
assertNumber(v);
129+
return NUM(Math.log1p(v.value));
130+
}),
131+
132+
'Math:log10': FN_NATIVE(([v]) => {
133+
assertNumber(v);
134+
return NUM(Math.log10(v.value));
135+
}),
136+
137+
'Math:log2': FN_NATIVE(([v]) => {
138+
assertNumber(v);
139+
return NUM(Math.log2(v.value));
140+
}),
141+
142+
'Math:max': FN_NATIVE(([a, b]) => {
143+
assertNumber(a);
144+
assertNumber(b);
145+
return NUM(Math.max(a.value, b.value));
146+
}),
147+
148+
'Math:min': FN_NATIVE(([a, b]) => {
149+
assertNumber(a);
150+
assertNumber(b);
151+
return NUM(Math.min(a.value, b.value));
152+
}),
153+
154+
'Math:pow': FN_NATIVE(([x, y]) => {
155+
assertNumber(x);
156+
assertNumber(y);
157+
return NUM(Math.pow(x.value, y.value));
158+
}),
159+
160+
'Math:round': FN_NATIVE(([v]) => {
161+
assertNumber(v);
162+
return NUM(Math.round(v.value));
163+
}),
164+
165+
'Math:sign': FN_NATIVE(([v]) => {
166+
assertNumber(v);
167+
return NUM(Math.sign(v.value));
168+
}),
169+
170+
'Math:sin': FN_NATIVE(([v]) => {
171+
assertNumber(v);
172+
return NUM(Math.sin(v.value));
173+
}),
174+
175+
'Math:sinh': FN_NATIVE(([v]) => {
176+
assertNumber(v);
177+
return NUM(Math.sinh(v.value));
178+
}),
179+
180+
'Math:sqrt': FN_NATIVE(([v]) => {
181+
assertNumber(v);
182+
const res = Math.sqrt(v.value);
183+
return NUM(res);
184+
}),
185+
186+
'Math:tan': FN_NATIVE(([v]) => {
187+
assertNumber(v);
188+
return NUM(Math.tan(v.value));
189+
}),
190+
191+
'Math:tanh': FN_NATIVE(([v]) => {
192+
assertNumber(v);
193+
return NUM(Math.tanh(v.value));
194+
}),
195+
196+
'Math:trunc': FN_NATIVE(([v]) => {
197+
assertNumber(v);
198+
return NUM(Math.trunc(v.value));
199+
}),
200+
201+
'Math:rnd': FN_NATIVE(([min, max]) => {
202+
if (min && min.type === 'num' && max && max.type === 'num') {
203+
const res = CryptoGen.instance.generateRandomIntegerInRange(min.value, max.value);
204+
return res === null ? NULL : NUM(res);
205+
}
206+
return NUM(CryptoGen.instance.generateNumber0To1());
207+
}),
208+
209+
'Math:gen_rng': FN_NATIVE(async ([seed, options]) => {
210+
expectAny(seed);
211+
const isSecureContext = 'subtle' in crypto;
212+
let algo = isSecureContext ? 'chacha20' : 'rc4_legacy';
213+
if (options?.type === 'obj') {
214+
const v = options.value.get('algorithm');
215+
if (v?.type !== 'str') throw new AiScriptRuntimeError('`options.algorithm` must be string.');
216+
algo = v.value;
217+
}
218+
else if (options?.type !== undefined) {
219+
throw new AiScriptRuntimeError('`options` must be an object if specified.');
220+
}
221+
if (seed.type !== 'num' && seed.type !== 'str' && seed.type !== 'null') throw new AiScriptRuntimeError('`seed` must be either number or string if specified.');
222+
switch (algo) {
223+
case 'rc4_legacy':
224+
return GenerateLegacyRandom(seed);
225+
case 'rc4': {
226+
if (!isSecureContext) throw new AiScriptRuntimeError(`The random algorithm ${algo} cannot be used because \`crypto.subtle\` is not available. Maybe in non-secure context?`);
227+
return GenerateRC4Random(seed);
228+
}
229+
case 'chacha20': {
230+
if (!isSecureContext) throw new AiScriptRuntimeError(`The random algorithm ${algo} cannot be used because \`crypto.subtle\` is not available. Maybe in non-secure context?`);
231+
return await GenerateChaCha20Random(seed);
232+
}
233+
default:
234+
throw new AiScriptRuntimeError('`options.algorithm` must be one of these: `chacha20`, `rc4`, or `rc4_legacy`.');
235+
}
236+
}),
237+
};

0 commit comments

Comments
 (0)