@bldrs-ai/conway 1.599.1551 → 1.603.1553
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/compiled/examples/browser-bundled.cjs +4 -3
- package/compiled/examples/cli-bundled.cjs +4 -3
- package/compiled/examples/cli-step-bundled.cjs +4 -3
- package/compiled/examples/validator-bundled.cjs +4 -3
- package/compiled/src/parsing/parsing_buffer.d.ts.map +1 -1
- package/compiled/src/parsing/parsing_buffer.js +14 -2
- package/compiled/src/parsing/parsing_buffer_real.test.d.ts +2 -0
- package/compiled/src/parsing/parsing_buffer_real.test.d.ts.map +1 -0
- package/compiled/src/parsing/parsing_buffer_real.test.js +94 -0
- package/compiled/src/version/version.js +1 -1
- package/compiled/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -30,7 +30,7 @@ var import_node_process = require("node:process");
|
|
|
30
30
|
var readline = __toESM(require("node:readline"), 1);
|
|
31
31
|
|
|
32
32
|
// compiled/src/version/version.js
|
|
33
|
-
var versionString = "Conway v1.
|
|
33
|
+
var versionString = "Conway v1.603.1553";
|
|
34
34
|
|
|
35
35
|
// compiled/dependencies/conway-geom/interface/conway_geometry.js
|
|
36
36
|
var wasmType = "";
|
|
@@ -1401,6 +1401,7 @@ var integerParser = integer_parser_default.Instance;
|
|
|
1401
1401
|
var realParser = real_parser_default.Instance;
|
|
1402
1402
|
var hexParser = hex_parser_default.Instance;
|
|
1403
1403
|
var RADIX_LUT_SIZE = 64;
|
|
1404
|
+
var RADIX_LUT_MAX_INDEX = RADIX_LUT_SIZE - 1;
|
|
1404
1405
|
var radixLUT = new Float64Array(RADIX_LUT_SIZE);
|
|
1405
1406
|
{
|
|
1406
1407
|
let radixMultiplier = 1;
|
|
@@ -1748,12 +1749,12 @@ var ParsingBuffer = class {
|
|
|
1748
1749
|
return primary;
|
|
1749
1750
|
}
|
|
1750
1751
|
while (decimals < 0) {
|
|
1751
|
-
const radixLutEntry = Math.min(-decimals,
|
|
1752
|
+
const radixLutEntry = Math.min(-decimals, RADIX_LUT_MAX_INDEX);
|
|
1752
1753
|
decimals += radixLutEntry;
|
|
1753
1754
|
primary /= radixLUT[radixLutEntry];
|
|
1754
1755
|
}
|
|
1755
1756
|
while (decimals > 0) {
|
|
1756
|
-
const radixLutEntry = Math.min(decimals,
|
|
1757
|
+
const radixLutEntry = Math.min(decimals, RADIX_LUT_MAX_INDEX);
|
|
1757
1758
|
decimals -= radixLutEntry;
|
|
1758
1759
|
primary *= radixLUT[radixLutEntry];
|
|
1759
1760
|
}
|
|
@@ -14985,7 +14985,7 @@ ${t5.join("\n")}` : "";
|
|
|
14985
14985
|
var import_process = require("process");
|
|
14986
14986
|
|
|
14987
14987
|
// compiled/src/version/version.js
|
|
14988
|
-
var versionString = "Conway v1.
|
|
14988
|
+
var versionString = "Conway v1.603.1553";
|
|
14989
14989
|
|
|
14990
14990
|
// compiled/dependencies/conway-geom/interface/conway_geometry.js
|
|
14991
14991
|
function pThreadsAllowed() {
|
|
@@ -17260,6 +17260,7 @@ var integerParser = integer_parser_default.Instance;
|
|
|
17260
17260
|
var realParser = real_parser_default.Instance;
|
|
17261
17261
|
var hexParser = hex_parser_default.Instance;
|
|
17262
17262
|
var RADIX_LUT_SIZE = 64;
|
|
17263
|
+
var RADIX_LUT_MAX_INDEX = RADIX_LUT_SIZE - 1;
|
|
17263
17264
|
var radixLUT = new Float64Array(RADIX_LUT_SIZE);
|
|
17264
17265
|
{
|
|
17265
17266
|
let radixMultiplier = 1;
|
|
@@ -17607,12 +17608,12 @@ var ParsingBuffer = class {
|
|
|
17607
17608
|
return primary;
|
|
17608
17609
|
}
|
|
17609
17610
|
while (decimals < 0) {
|
|
17610
|
-
const radixLutEntry = Math.min(-decimals,
|
|
17611
|
+
const radixLutEntry = Math.min(-decimals, RADIX_LUT_MAX_INDEX);
|
|
17611
17612
|
decimals += radixLutEntry;
|
|
17612
17613
|
primary /= radixLUT[radixLutEntry];
|
|
17613
17614
|
}
|
|
17614
17615
|
while (decimals > 0) {
|
|
17615
|
-
const radixLutEntry = Math.min(decimals,
|
|
17616
|
+
const radixLutEntry = Math.min(decimals, RADIX_LUT_MAX_INDEX);
|
|
17616
17617
|
decimals -= radixLutEntry;
|
|
17617
17618
|
primary *= radixLUT[radixLutEntry];
|
|
17618
17619
|
}
|
|
@@ -15507,6 +15507,7 @@ var integerParser = integer_parser_default.Instance;
|
|
|
15507
15507
|
var realParser = real_parser_default.Instance;
|
|
15508
15508
|
var hexParser = hex_parser_default.Instance;
|
|
15509
15509
|
var RADIX_LUT_SIZE = 64;
|
|
15510
|
+
var RADIX_LUT_MAX_INDEX = RADIX_LUT_SIZE - 1;
|
|
15510
15511
|
var radixLUT = new Float64Array(RADIX_LUT_SIZE);
|
|
15511
15512
|
{
|
|
15512
15513
|
let radixMultiplier = 1;
|
|
@@ -15854,12 +15855,12 @@ var ParsingBuffer = class {
|
|
|
15854
15855
|
return primary;
|
|
15855
15856
|
}
|
|
15856
15857
|
while (decimals < 0) {
|
|
15857
|
-
const radixLutEntry = Math.min(-decimals,
|
|
15858
|
+
const radixLutEntry = Math.min(-decimals, RADIX_LUT_MAX_INDEX);
|
|
15858
15859
|
decimals += radixLutEntry;
|
|
15859
15860
|
primary /= radixLUT[radixLutEntry];
|
|
15860
15861
|
}
|
|
15861
15862
|
while (decimals > 0) {
|
|
15862
|
-
const radixLutEntry = Math.min(decimals,
|
|
15863
|
+
const radixLutEntry = Math.min(decimals, RADIX_LUT_MAX_INDEX);
|
|
15863
15864
|
decimals -= radixLutEntry;
|
|
15864
15865
|
primary *= radixLUT[radixLutEntry];
|
|
15865
15866
|
}
|
|
@@ -15963,7 +15964,7 @@ var ParsingBuffer = class {
|
|
|
15963
15964
|
};
|
|
15964
15965
|
|
|
15965
15966
|
// compiled/src/version/version.js
|
|
15966
|
-
var versionString = "Conway v1.
|
|
15967
|
+
var versionString = "Conway v1.603.1553";
|
|
15967
15968
|
|
|
15968
15969
|
// compiled/dependencies/conway-geom/interface/conway_geometry.js
|
|
15969
15970
|
function pThreadsAllowed() {
|
|
@@ -944,7 +944,7 @@ var EntityTypesIfcCount = 909;
|
|
|
944
944
|
var entity_types_ifc_gen_default = EntityTypesIfc;
|
|
945
945
|
|
|
946
946
|
// compiled/src/version/version.js
|
|
947
|
-
var versionString = "Conway v1.
|
|
947
|
+
var versionString = "Conway v1.603.1553";
|
|
948
948
|
|
|
949
949
|
// compiled/dependencies/conway-geom/interface/conway_geometry.js
|
|
950
950
|
var wasmType = "";
|
|
@@ -2315,6 +2315,7 @@ var integerParser = integer_parser_default.Instance;
|
|
|
2315
2315
|
var realParser = real_parser_default.Instance;
|
|
2316
2316
|
var hexParser = hex_parser_default.Instance;
|
|
2317
2317
|
var RADIX_LUT_SIZE = 64;
|
|
2318
|
+
var RADIX_LUT_MAX_INDEX = RADIX_LUT_SIZE - 1;
|
|
2318
2319
|
var radixLUT = new Float64Array(RADIX_LUT_SIZE);
|
|
2319
2320
|
{
|
|
2320
2321
|
let radixMultiplier = 1;
|
|
@@ -2662,12 +2663,12 @@ var ParsingBuffer = class {
|
|
|
2662
2663
|
return primary;
|
|
2663
2664
|
}
|
|
2664
2665
|
while (decimals < 0) {
|
|
2665
|
-
const radixLutEntry = Math.min(-decimals,
|
|
2666
|
+
const radixLutEntry = Math.min(-decimals, RADIX_LUT_MAX_INDEX);
|
|
2666
2667
|
decimals += radixLutEntry;
|
|
2667
2668
|
primary /= radixLUT[radixLutEntry];
|
|
2668
2669
|
}
|
|
2669
2670
|
while (decimals > 0) {
|
|
2670
|
-
const radixLutEntry = Math.min(decimals,
|
|
2671
|
+
const radixLutEntry = Math.min(decimals, RADIX_LUT_MAX_INDEX);
|
|
2671
2672
|
decimals -= radixLutEntry;
|
|
2672
2673
|
primary *= radixLUT[radixLutEntry];
|
|
2673
2674
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parsing_buffer.d.ts","sourceRoot":"","sources":["../../../src/parsing/parsing_buffer.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,gBAAgB,CAAA;AAKvC,OAAO,EACL,YAAY,EACZ,uBAAuB,IAAI,qBAAqB,EACjD,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"parsing_buffer.d.ts","sourceRoot":"","sources":["../../../src/parsing/parsing_buffer.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,6 +12,8 @@ const integerParser = IntegerParser.Instance;
|
|
|
12
12
|
const realParser = RealParser.Instance;
|
|
13
13
|
const hexParser = HexParser.Instance;
|
|
14
14
|
const RADIX_LUT_SIZE = 64;
|
|
15
|
+
// Largest index the LUT actually holds; see readReal's scaling loops.
|
|
16
|
+
const RADIX_LUT_MAX_INDEX = RADIX_LUT_SIZE - 1;
|
|
15
17
|
const radixLUT = new Float64Array(RADIX_LUT_SIZE);
|
|
16
18
|
{
|
|
17
19
|
let radixMultiplier = 1;
|
|
@@ -478,14 +480,24 @@ export default class ParsingBuffer {
|
|
|
478
480
|
return primary;
|
|
479
481
|
}
|
|
480
482
|
while (decimals < 0) {
|
|
481
|
-
|
|
483
|
+
// RADIX_LUT_MAX_INDEX, not RADIX_LUT_SIZE: radixLUT is a Float64Array of
|
|
484
|
+
// exactly RADIX_LUT_SIZE entries, so index RADIX_LUT_SIZE is out of
|
|
485
|
+
// bounds and a typed-array read there yields `undefined`, not a throw —
|
|
486
|
+
// `primary /= undefined` is NaN. Any real whose total decimal shift
|
|
487
|
+
// reached 64 (1.0E-63 with one fractional digit, 1.5E308, and 306
|
|
488
|
+
// direction/coordinate literals in Orbiter_v1.1_Gear_7.5.step) parsed
|
|
489
|
+
// as NaN and carried that silently into placements and geometry.
|
|
490
|
+
// Clamping to the last valid entry only changes inputs that used to be
|
|
491
|
+
// NaN: for a shift below 64 both clamps return the shift itself.
|
|
492
|
+
const radixLutEntry = Math.min(-decimals, RADIX_LUT_MAX_INDEX);
|
|
482
493
|
decimals += radixLutEntry;
|
|
483
494
|
// Note, we need to use division here not a multiply
|
|
484
495
|
// by inverse to get the matching rounding mode behaviour.
|
|
485
496
|
primary /= radixLUT[radixLutEntry];
|
|
486
497
|
}
|
|
487
498
|
while (decimals > 0) {
|
|
488
|
-
|
|
499
|
+
// See the note on the negative-exponent loop above.
|
|
500
|
+
const radixLutEntry = Math.min(decimals, RADIX_LUT_MAX_INDEX);
|
|
489
501
|
decimals -= radixLutEntry;
|
|
490
502
|
primary *= radixLUT[radixLutEntry];
|
|
491
503
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parsing_buffer_real.test.d.ts","sourceRoot":"","sources":["../../../src/parsing/parsing_buffer_real.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { describe, expect, test } from "@jest/globals";
|
|
2
|
+
import ParsingBuffer from "./parsing_buffer.js";
|
|
3
|
+
/**
|
|
4
|
+
* Parse one STEP/IFC real literal through the same entry point the entity
|
|
5
|
+
* parsers use.
|
|
6
|
+
*
|
|
7
|
+
* A trailing space stands in for the delimiter a real always has after it in
|
|
8
|
+
* a STEP file; readReal reads up to it and leaves the cursor there.
|
|
9
|
+
*
|
|
10
|
+
* @param literal The literal to parse, exactly as it appears in a file.
|
|
11
|
+
* @return {number | undefined} What readReal made of it.
|
|
12
|
+
*/
|
|
13
|
+
function readReal(literal) {
|
|
14
|
+
const data = new TextEncoder().encode(`${literal} `);
|
|
15
|
+
return new ParsingBuffer(data).readReal();
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Relative difference between a parsed value and the runtime's own decimal
|
|
19
|
+
* conversion of the same literal.
|
|
20
|
+
*
|
|
21
|
+
* readReal scales the mantissa against a power-of-ten table rather than
|
|
22
|
+
* deferring to `Number()`, so it is correctly rounded only to within a few
|
|
23
|
+
* ULP. That accuracy contract is long-standing and is not what these tests
|
|
24
|
+
* are about; they are about literals that used to come back NaN.
|
|
25
|
+
*
|
|
26
|
+
* @param literal The literal to parse and to use as the reference.
|
|
27
|
+
* @return {number} The relative error, or Infinity if the parse is not finite.
|
|
28
|
+
*/
|
|
29
|
+
function relativeErrorAgainstRuntime(literal) {
|
|
30
|
+
const got = readReal(literal);
|
|
31
|
+
const expected = Number(literal);
|
|
32
|
+
if (typeof got !== "number" || !Number.isFinite(got)) {
|
|
33
|
+
return Infinity;
|
|
34
|
+
}
|
|
35
|
+
if (expected === 0) {
|
|
36
|
+
return Math.abs(got);
|
|
37
|
+
}
|
|
38
|
+
return Math.abs((got - expected) / expected);
|
|
39
|
+
}
|
|
40
|
+
// A total decimal shift of 64 — fractional digits plus exponent, not the
|
|
41
|
+
// exponent alone — is the boundary the radix table's last index sits on.
|
|
42
|
+
// readReal used to clamp the per-iteration shift to RADIX_LUT_SIZE, and
|
|
43
|
+
// radixLUT[RADIX_LUT_SIZE] is one past the end of a Float64Array, which reads
|
|
44
|
+
// `undefined` rather than throwing; dividing by that yields NaN silently. 306
|
|
45
|
+
// direction and coordinate values in Orbiter_v1.1_Gear_7.5.step parsed that
|
|
46
|
+
// way, putting NaN into every placement built from them (bldrs-ai/conway#589).
|
|
47
|
+
const TOLERANCE = 1e-12;
|
|
48
|
+
const IN_RANGE = [
|
|
49
|
+
"0.1",
|
|
50
|
+
"-1.5E-8",
|
|
51
|
+
"1.0E-50",
|
|
52
|
+
"9.86076131526265E-32",
|
|
53
|
+
"4.37905770101505E-47",
|
|
54
|
+
];
|
|
55
|
+
// '1.0' contributes one fractional digit, so E-63 is a shift of exactly 64:
|
|
56
|
+
// the first literal that used to be NaN. The last four are real values taken
|
|
57
|
+
// from corpus models.
|
|
58
|
+
const PAST_THE_TABLE = [
|
|
59
|
+
"1.0E-63",
|
|
60
|
+
"1.0E-64",
|
|
61
|
+
"1.0E-65",
|
|
62
|
+
"1.33564029830467E-63",
|
|
63
|
+
"-1.94469227207812E-62",
|
|
64
|
+
"3.52475474722604E-62",
|
|
65
|
+
"5.25674630405262E-61",
|
|
66
|
+
];
|
|
67
|
+
// The positive-exponent loop carries the same clamp, so it had the same
|
|
68
|
+
// boundary: 1.0E+64 was the largest that survived. 5.0E-324 is the smallest
|
|
69
|
+
// denormal, which scaling has to reach without passing through NaN.
|
|
70
|
+
const LARGE_AND_DENORMAL = [
|
|
71
|
+
"1.0E+64",
|
|
72
|
+
"1.0E+65",
|
|
73
|
+
"1.5E308",
|
|
74
|
+
"5.0E-324",
|
|
75
|
+
];
|
|
76
|
+
describe("ParsingBuffer.readReal", () => {
|
|
77
|
+
test.each([...IN_RANGE, ...PAST_THE_TABLE, ...LARGE_AND_DENORMAL])("parses %s to the same value the runtime does", (literal) => {
|
|
78
|
+
expect(Number.isFinite(readReal(literal))).toBe(true);
|
|
79
|
+
expect(relativeErrorAgainstRuntime(literal))
|
|
80
|
+
.toBeLessThanOrEqual(TOLERANCE);
|
|
81
|
+
});
|
|
82
|
+
test("scales past the radix table in more than one step", () => {
|
|
83
|
+
// A shift of 200 is three trips through the loop, which is what proves
|
|
84
|
+
// the clamp is a chunk size and not a ceiling on the exponent.
|
|
85
|
+
expect(relativeErrorAgainstRuntime("1.0E-200"))
|
|
86
|
+
.toBeLessThanOrEqual(TOLERANCE);
|
|
87
|
+
expect(relativeErrorAgainstRuntime("1.0E+200"))
|
|
88
|
+
.toBeLessThanOrEqual(TOLERANCE);
|
|
89
|
+
});
|
|
90
|
+
test("still overflows and underflows where a double must", () => {
|
|
91
|
+
expect(readReal("1.0E+400")).toBe(Infinity);
|
|
92
|
+
expect(readReal("1.0E-400")).toBe(0);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
// only the first segment (major) is meaningful and is the one CI carries forward.
|
|
6
6
|
// Must stay in `vN.N.N` shape: the CI stamp regex, scripts/updateVersion.mjs, and
|
|
7
7
|
// statistics.ts all match `v\d+\.\d+\.\d+`.
|
|
8
|
-
const versionString = 'Conway v1.
|
|
8
|
+
const versionString = 'Conway v1.603.1553';
|
|
9
9
|
export { versionString };
|