Skip to content

Commit 3be097e

Browse files
committed
Merge github.com:brownplt/pyret-lang into lang
2 parents b127329 + 162c5bf commit 3be097e

6 files changed

Lines changed: 135 additions & 1127 deletions

File tree

lang/.github/workflows/build-and-test.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ jobs:
2727

2828
- name: run tests
2929
run: make all-pyret-test
30-
30+
31+
- name: run jsnums tests
32+
run: make jsnums-test
33+
3134
deploy-trigger:
3235
needs: build
3336
uses: ./.github/workflows/deploy-trigger.yml

lang/src/js/base/js-numbers.js

Lines changed: 63 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -212,82 +212,101 @@ define("pyret-base/js/js-numbers", function() {
212212

213213

214214
// isPyretNumber: any -> boolean
215-
// Returns true if the thing is a pyretnum
215+
// Pure predicate. Raw JS numbers must be integers (the fixnum
216+
// representation) to count as pyretnums; non-integer JS numbers
217+
// are not valid pyretnums and return false.
216218
var isPyretNumber = function(thing) {
217-
return (typeof(thing) === 'number'
218-
|| (thing instanceof Rational ||
219-
thing instanceof Roughnum ||
220-
thing instanceof BigInteger));
219+
if (typeof(thing) === 'number') return Number.isInteger(thing);
220+
return (thing instanceof Rational ||
221+
thing instanceof Roughnum ||
222+
thing instanceof BigInteger);
223+
};
224+
225+
// assertPyretNumber: contract check for entry-point operations that
226+
// require a pyretnum. Throws a domainError for clearly wrong types
227+
// (string, null, etc.). For non-integer JS numbers, logs to
228+
// console.error rather than throwing — we don't yet have full
229+
// coverage of all call sites that may pass these in, and an
230+
// exception in the wild from existing code we haven't audited would
231+
// be worse than the current lax behavior. Flip the non-integer
232+
// branch to errbacks.throwDomainError once we're confident.
233+
var assertPyretNumber = function(thing, callerName) {
234+
if (typeof thing === 'number') {
235+
if (!Number.isInteger(thing)) {
236+
console.error(
237+
'js-numbers ' + callerName +
238+
': non-integer JS number leaked into pyretnum: ' + thing,
239+
new Error('stack').stack);
240+
}
241+
return;
242+
}
243+
if (thing instanceof Rational ||
244+
thing instanceof Roughnum ||
245+
thing instanceof BigInteger) {
246+
return;
247+
}
248+
errbacks.throwDomainError(
249+
callerName + ': arg ' + thing + ' is not a number.');
221250
};
222251

223252
// isRational: pyretnum -> boolean
224253
var isRational = function(n) {
225-
return (typeof(n) === 'number' ||
226-
(isPyretNumber(n) && n.isRational()));
254+
if (!isPyretNumber(n)) return false;
255+
if (typeof(n) === 'number') return true;
256+
return n.isRational();
227257
};
228258

229259
var isExact = isRational;
230260

231261
// isReal: pyretnum -> boolean
232262
var isReal = function(n) {
233-
return (typeof(n) === 'number' ||
234-
(isPyretNumber(n) && n.isReal()));
263+
if (!isPyretNumber(n)) return false;
264+
if (typeof(n) === 'number') return true;
265+
return n.isReal();
235266
};
236267

237268
// isInteger: pyretnum -> boolean
238269
var isInteger = function(n) {
239-
if (typeof(n) === 'number') return Number.isInteger(n);
240-
if (isPyretNumber(n)) return n.isInteger();
241-
return false;
270+
if (!isPyretNumber(n)) return false;
271+
if (typeof(n) === 'number') return true;
272+
return n.isInteger();
242273
};
243274

244275
var isRoughnum = function(n) {
245-
if (typeof(n) === 'number') {
246-
return false;
247-
} else {
248-
return (isPyretNumber(n) && n.isRoughnum());
249-
}
276+
if (!isPyretNumber(n)) return false;
277+
if (typeof(n) === 'number') return false;
278+
return n.isRoughnum();
250279
};
251280

252281
var isPositive = function(n) {
253-
if (typeof(n) === 'number') {
254-
return n > 0;
255-
} else {
256-
return (isPyretNumber(n) && n.isPositive());
257-
}
282+
if (!isPyretNumber(n)) return false;
283+
if (typeof(n) === 'number') return n > 0;
284+
return n.isPositive();
258285
};
259286

260287
var isNonPositive = function(n) {
261-
if (typeof(n) === 'number') {
262-
return n <= 0;
263-
} else {
264-
return (isPyretNumber(n) && n.isNonPositive());
265-
}
288+
if (!isPyretNumber(n)) return false;
289+
if (typeof(n) === 'number') return n <= 0;
290+
return n.isNonPositive();
266291
};
267292

268293
var isNegative = function(n) {
269-
if (typeof(n) === 'number') {
270-
return n < 0;
271-
} else {
272-
return (isPyretNumber(n) && n.isNegative());
273-
}
294+
if (!isPyretNumber(n)) return false;
295+
if (typeof(n) === 'number') return n < 0;
296+
return n.isNegative();
274297
};
275298

276299
var isNonNegative = function(n) {
277-
if (typeof(n) === 'number') {
278-
return n >= 0;
279-
} else {
280-
return (isPyretNumber(n) && n.isNonNegative());
281-
}
300+
if (!isPyretNumber(n)) return false;
301+
if (typeof(n) === 'number') return n >= 0;
302+
return n.isNonNegative();
282303
};
283304

284305
// toFixnum: pyretnum -> javascript-number
285306
var toFixnum = function(n) {
286-
if (typeof(n) === 'number')
287-
return n;
288-
if (isPyretNumber(n))
289-
return n.toFixnum();
290-
errbacks.throwDomainError('toFixnum: arg ' + n + ' is not a number.');
307+
assertPyretNumber(n, 'toFixnum');
308+
if (typeof(n) === 'number') return n;
309+
return n.toFixnum();
291310
};
292311

293312
// toRational: pyretnum -> pyretnum
@@ -875,14 +894,14 @@ define("pyret-base/js/js-numbers", function() {
875894
return atan(divide(y, x));
876895
} else { // x > 0, y < 0, 4th qdt
877896
// atan(y/x) is the 4th qdt and negative, so make it positive by adding 2pi
878-
return add(atan(divide(y, x)), 2*Math.PI);
897+
return add(atan(divide(y, x)), Roughnum.makeInstance(2*Math.PI));
879898
}
880899
} else { // x < 0
881900
// either x < 0, y >= 0 (2nd qdt), in which case
882901
// atan(y/x) must be reflected from 4th to 2nd qdt, by adding pi
883902
// or x < 0, y < 0 (3rd qdt), in which case
884903
// atan(y/x) must be reflected from 1st to 3rd qdt, again by adding pi
885-
return add(atan(divide(y, x)), Math.PI);
904+
return add(atan(divide(y, x)), Roughnum.makeInstance(Math.PI));
886905
}
887906
};
888907

lang/src/js/trove/charts-lib.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2880,14 +2880,14 @@
28802880
function recomputePoints(func, samplePoints, then) {
28812881
return RUNTIME.safeCall(() => {
28822882
return RUNTIME.raw_array_map(RUNTIME.makeFunction((sample) => {
2883-
return RUNTIME.execThunk(RUNTIME.makeFunction(() => func.app(sample)));
2883+
return RUNTIME.execThunk(RUNTIME.makeFunction(() => func.app(jsnums.fromFixnum(sample))));
28842884
}), samplePoints);
28852885
}, (funcVals) => {
28862886
const dataValues = [];
28872887
funcVals.forEach((result, idx) => {
28882888
cases(RUNTIME.ffi.isEither, 'Either', result, {
28892889
left: (value) => dataValues.push({
2890-
x: toFixnum(samplePoints[idx]),
2890+
x: samplePoints[idx],
28912891
y: toFixnum(value)
28922892
}),
28932893
right: () => {}
@@ -3316,8 +3316,8 @@
33163316
}
33173317
// Reflect the updated values back into the globalOptions,
33183318
// so that they'll be picked up by the initial computation of function plots
3319-
globalOptions['x-min'] = RUNTIME.ffi.makeSome(clippedDomain[0]);
3320-
globalOptions['x-max'] = RUNTIME.ffi.makeSome(clippedDomain[1]);
3319+
globalOptions['x-min'] = RUNTIME.ffi.makeSome(jsnums.fromFixnum(clippedDomain[0]));
3320+
globalOptions['x-max'] = RUNTIME.ffi.makeSome(jsnums.fromFixnum(clippedDomain[1]));
33213321
return RUNTIME.safeCall(
33223322
() => makeFunctionPlots(clippedDomain),
33233323
(functionPlots) => composeCharts(globalOptions, clippedDomain, {

lang/src/js/trove/filesystem-internal.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@
5757
async function stat(p) {
5858
const stats = await fsp.stat(p);
5959
return {
60-
ctime: stats.ctimeMs,
61-
mtime: stats.mtimeMs,
60+
ctime: Math.floor(stats.ctimeMs),
61+
mtime: Math.floor(stats.mtimeMs),
6262
size: stats.size,
6363
native: stats
6464
};

lang/src/js/trove/image-lib.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1387,8 +1387,6 @@
13871387
var PointPolygonImage = function(vertices, style, color) {
13881388
BaseImage.call(this);
13891389
for (var v = 0; v < vertices.length; v++) {
1390-
vertices[v].x = jsnums.toFixnum(vertices[v].x);
1391-
vertices[v].y = jsnums.toFixnum(vertices[v].y);
13921390
vertices[v].y *= -1;
13931391
}
13941392

0 commit comments

Comments
 (0)