eyeprolog 1.3.41 → 1.3.43
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/README.md +20 -4
- package/examples/book/README.md +1 -1
- package/examples/book/chapter-38/02-look_ahead.pl +1 -1
- package/package.json +1 -1
- package/src/iso-character.js +37 -0
- package/src/iso.js +53 -19
- package/src/parser.js +137 -62
- package/src/program.js +2 -2
- package/src/solver.js +2 -2
- package/src/standard-library.js +1 -1
- package/src/syntax-scan.js +1 -1
- package/test/conformance/ISO-COMPLIANCE.md +31 -6
- package/test/conformance/ISO-IMPLEMENTATION-DEFINED.md +19 -18
- package/test/conformance/ISO-MATRIX.md +7 -5
- package/test/conformance/README.md +7 -5
- package/test/conformance/cases/iso/dcg_module_nonterminal_indicator.pl +1 -1
- package/test/conformance/expected/iso/exceptions_and_flags.pl +1 -1
- package/test/fixtures/README.md +7 -0
- package/test/run-iso-strict.mjs +71 -0
- package/test/run-regression.mjs +13 -6
- package/the-art-of-eyeprolog.md +61 -37
- package/why-eyeprolog.md +17 -13
package/README.md
CHANGED
|
@@ -210,6 +210,14 @@ expansion/`phrase/2-3`; it also removes the EyeProlog `occurs_check` flag,
|
|
|
210
210
|
Normal mode is unchanged and continues to support modules, DCGs, quads,
|
|
211
211
|
libraries, proofs, cleanup-aware control, and the other documented extensions.
|
|
212
212
|
|
|
213
|
+
Strict mode also makes the Part 1 processor-character-set choice explicit: its
|
|
214
|
+
PCS is 7-bit ASCII (U+0000..U+007F), C0 controls and DEL are classified as
|
|
215
|
+
extended layout characters, and the collating-sequence integer of each
|
|
216
|
+
character is its ASCII code. Characters or character codes outside that set
|
|
217
|
+
raise representation errors in strict parsing and character operations. Normal
|
|
218
|
+
mode retains Unicode scalar character data as an implementation-specific
|
|
219
|
+
extension.
|
|
220
|
+
|
|
213
221
|
The auditable processor-requirement checklist lives in
|
|
214
222
|
[`test/conformance/ISO-COMPLIANCE.md`](test/conformance/ISO-COMPLIANCE.md).
|
|
215
223
|
The ISO 5.4 implementation-defined/implementation-specific decision index is
|
|
@@ -221,10 +229,18 @@ newly upgraded cases run directly against the upstream Codex expectation.
|
|
|
221
229
|
EyeProlog does not yet claim independent certification or closure of every
|
|
222
230
|
normative Part 1 requirement.
|
|
223
231
|
|
|
224
|
-
##
|
|
232
|
+
## Module and definite clause grammar compatibility profiles
|
|
233
|
+
|
|
234
|
+
Normal EyeProlog supports the widely used `module/2`, `use_module/1-2`,
|
|
235
|
+
`meta_predicate/1`, and `Module:Goal` interface reflected in later WG17 module
|
|
236
|
+
amendment work. This is a practical module compatibility profile; EyeProlog
|
|
237
|
+
does **not** currently claim a clause-by-clause implementation or certification
|
|
238
|
+
of the complete ISO/IEC 13211-2:2000 module model.
|
|
225
239
|
|
|
226
|
-
|
|
227
|
-
`phrase/2-3`
|
|
240
|
+
Definite clause grammar support follows the ISO/IEC TS 13211-3 grammar-rule and
|
|
241
|
+
`phrase/2-3` model and is exercised by the conformance corpus. As with Part 1,
|
|
242
|
+
that implementation evidence is not an independent certification of every
|
|
243
|
+
Part 3 requirement. For example:
|
|
228
244
|
|
|
229
245
|
```prolog
|
|
230
246
|
sentence --> [hello], noun.
|
|
@@ -254,7 +270,7 @@ EyeProlog also adds 128 public library predicate indicators to its 129-entry ISO
|
|
|
254
270
|
profile. **88 are implemented entirely as ordinary Prolog clauses** in focused
|
|
255
271
|
modules under `src/lib/`; the remaining control predicates and finite-domain
|
|
256
272
|
`library(clpz)` kernel use backtrackable host support.
|
|
257
|
-
They are
|
|
273
|
+
They are ordinary Prolog modules using EyeProlog's documented module compatibility surface, loaded explicitly by purpose, such as
|
|
258
274
|
`library(lists)`, `library(lambda)`, `library(strings)`, `library(aggregate)`, or
|
|
259
275
|
`library(clpz)`.
|
|
260
276
|
Portable text
|
package/examples/book/README.md
CHANGED
|
@@ -234,7 +234,7 @@ npm run generate
|
|
|
234
234
|
## Chapter 38: Language and ISO profile
|
|
235
235
|
|
|
236
236
|
- [01-city.pl](chapter-38/01-city.pl)
|
|
237
|
-
- [02-look_ahead.pl](chapter-38/02-look_ahead.pl) —
|
|
237
|
+
- [02-look_ahead.pl](chapter-38/02-look_ahead.pl) — Part 3-oriented definite clause grammars
|
|
238
238
|
|
|
239
239
|
## Chapter 39: Built-in predicates by programming role
|
|
240
240
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
% From The Art of EyeProlog, Chapter 38 —
|
|
1
|
+
% From The Art of EyeProlog, Chapter 38 — Part 3-oriented definite clause grammars.
|
|
2
2
|
look_ahead(X), [X] --> [X].
|
package/package.json
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// ISO/IEC 13211-1 processor-character-set choices used by --iso-strict.
|
|
2
|
+
//
|
|
3
|
+
// EyeProlog's strict Part 1 profile deliberately chooses a finite PCS so every
|
|
4
|
+
// accepted character has one documented lexical classification and one stable
|
|
5
|
+
// collating-sequence integer. Normal mode keeps the broader Unicode surface as
|
|
6
|
+
// an implementation-specific extension.
|
|
7
|
+
|
|
8
|
+
export class CharacterRepresentationError extends Error {
|
|
9
|
+
constructor(formal = 'representation_error(character)') {
|
|
10
|
+
super(`error(${formal})`);
|
|
11
|
+
this.name = 'CharacterRepresentationError';
|
|
12
|
+
this.formal = formal;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Strict PCS: the 128 ASCII characters U+0000..U+007F. Printable ASCII
|
|
17
|
+
// carries the Part 1 lexical classes; the remaining C0 controls plus DEL are
|
|
18
|
+
// implementation-defined extended layout characters. This lets every ISO
|
|
19
|
+
// octal/hexadecimal character escape in the ASCII range denote a PCS member.
|
|
20
|
+
// The collating-sequence integer is the Unicode/ASCII code point.
|
|
21
|
+
export function isStrictIsoPcsCodePoint(code) {
|
|
22
|
+
return Number.isInteger(code) && code >= 0 && code <= 0x7f;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function isStrictIsoPcsCharacter(character) {
|
|
26
|
+
if (typeof character !== 'string' || Array.from(character).length !== 1) return false;
|
|
27
|
+
return isStrictIsoPcsCodePoint(character.codePointAt(0));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function strictIsoCollatingInteger(character) {
|
|
31
|
+
return isStrictIsoPcsCharacter(character) ? character.codePointAt(0) : null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function assertStrictIsoPcsCharacter(character, formal = 'representation_error(character)') {
|
|
35
|
+
if (!isStrictIsoPcsCharacter(character)) throw new CharacterRepresentationError(formal);
|
|
36
|
+
return character;
|
|
37
|
+
}
|
package/src/iso.js
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
import { formatTermForWrite } from './write.js';
|
|
14
14
|
import { emptyTerminalSequence, expandDcgBody, isListOrPartialList, validateDcgEmbeddedGoals } from './dcg.js';
|
|
15
15
|
import { INVALID_UTF8_SENTINEL } from './io.js';
|
|
16
|
+
import { CharacterRepresentationError, isStrictIsoPcsCharacter, isStrictIsoPcsCodePoint } from './iso-character.js';
|
|
16
17
|
import {
|
|
17
18
|
characterCodeConstantEnd, continuesGraphicToken, isTerminatingFullStop, quotedEscapeEnd,
|
|
18
19
|
} from './syntax-scan.js';
|
|
@@ -662,6 +663,11 @@ function* currentPrologFlagBuiltin({ solver, goal, env }) {
|
|
|
662
663
|
throw new PrologError('domain_error(prolog_flag)', flag);
|
|
663
664
|
}
|
|
664
665
|
for (const [name, definition] of solver.prologFlags) {
|
|
666
|
+
// ISO 7.11.1.1: when bounded=false, max_integer and min_integer have no
|
|
667
|
+
// current value and current_prolog_flag/2 must therefore not enumerate
|
|
668
|
+
// them. The definitions remain registered so attempts to change these
|
|
669
|
+
// non-changeable flags still receive the normal flag error handling.
|
|
670
|
+
if (definition.value == null) continue;
|
|
665
671
|
const next = env.clone();
|
|
666
672
|
if (unify(goal.args[0], atom(name), next) && unify(goal.args[1], definition.value, next)) yield next;
|
|
667
673
|
}
|
|
@@ -772,7 +778,7 @@ function* currentOpBuiltin({ solver, goal, env }) {
|
|
|
772
778
|
}
|
|
773
779
|
}
|
|
774
780
|
|
|
775
|
-
function conversionCharacter(term, env, current = false) {
|
|
781
|
+
function conversionCharacter(term, env, current = false, solver = null) {
|
|
776
782
|
const value = deref(term, env);
|
|
777
783
|
if (value.type === VAR) {
|
|
778
784
|
if (current) return value;
|
|
@@ -782,18 +788,21 @@ function conversionCharacter(term, env, current = false) {
|
|
|
782
788
|
if (current) throw new PrologError('type_error(character)', value);
|
|
783
789
|
throw new PrologError('representation_error(character)');
|
|
784
790
|
}
|
|
791
|
+
if (solver?.isoStrict && !isStrictIsoPcsCharacter(value.name)) {
|
|
792
|
+
throw new PrologError('representation_error(character)', value);
|
|
793
|
+
}
|
|
785
794
|
return value;
|
|
786
795
|
}
|
|
787
796
|
function* charConversionBuiltin({ solver, goal, env }) {
|
|
788
|
-
const input = conversionCharacter(goal.args[0], env);
|
|
789
|
-
const output = conversionCharacter(goal.args[1], env);
|
|
797
|
+
const input = conversionCharacter(goal.args[0], env, false, solver);
|
|
798
|
+
const output = conversionCharacter(goal.args[1], env, false, solver);
|
|
790
799
|
if (input.name === output.name) solver.charConversions.delete(input.name);
|
|
791
800
|
else solver.charConversions.set(input.name, output.name);
|
|
792
801
|
yield env;
|
|
793
802
|
}
|
|
794
803
|
function* currentCharConversionBuiltin({ solver, goal, env }) {
|
|
795
|
-
const input = conversionCharacter(goal.args[0], env, true);
|
|
796
|
-
const output = conversionCharacter(goal.args[1], env, true);
|
|
804
|
+
const input = conversionCharacter(goal.args[0], env, true, solver);
|
|
805
|
+
const output = conversionCharacter(goal.args[1], env, true, solver);
|
|
797
806
|
for (const [from, to] of [...solver.charConversions]) {
|
|
798
807
|
const next = env.clone();
|
|
799
808
|
if (unify(input, atom(from), next) && unify(output, atom(to), next)) yield next;
|
|
@@ -1039,6 +1048,9 @@ function inputUnitBuiltin(name) {
|
|
|
1039
1048
|
throw error;
|
|
1040
1049
|
}
|
|
1041
1050
|
if (unit == null && !peek) stream.pastEnd = true;
|
|
1051
|
+
if (!binary && unit != null && solver.isoStrict && !isStrictIsoPcsCharacter(unit)) {
|
|
1052
|
+
throw new PrologError('representation_error(character)');
|
|
1053
|
+
}
|
|
1042
1054
|
const result = unit == null ? (binary ? numberTerm(-1) : name.endsWith('code') ? numberTerm(-1) : atom('end_of_file'))
|
|
1043
1055
|
: binary ? numberTerm(unit) : name.endsWith('code') ? numberTerm(unit.codePointAt(0)) : atom(unit);
|
|
1044
1056
|
const target = goal.args[goal.arity - 1];
|
|
@@ -1054,6 +1066,9 @@ function outputUnitBuiltin(name) {
|
|
|
1054
1066
|
if (name === 'put_char') {
|
|
1055
1067
|
if (stream.type !== 'text') throw new PrologError('permission_error(output, binary_stream)', streamHandle(stream.id));
|
|
1056
1068
|
if (!oneChar(value)) throw new PrologError('type_error(character)', value);
|
|
1069
|
+
if (solver.isoStrict && !isStrictIsoPcsCharacter(value.name)) {
|
|
1070
|
+
throw new PrologError('representation_error(character)', value);
|
|
1071
|
+
}
|
|
1057
1072
|
solver.io.writeUnit(stream, value.name);
|
|
1058
1073
|
} else {
|
|
1059
1074
|
if ((name === 'put_byte') !== (stream.type === 'binary')) {
|
|
@@ -1063,6 +1078,9 @@ function outputUnitBuiltin(name) {
|
|
|
1063
1078
|
const code = BigInt(value.name);
|
|
1064
1079
|
const max = name === 'put_byte' ? 255n : 0x10ffffn;
|
|
1065
1080
|
if (code < 0n || code > max) throw new PrologError(name === 'put_byte' ? 'type_error(byte)' : 'representation_error(character_code)');
|
|
1081
|
+
if (name === 'put_code' && solver.isoStrict && !isStrictIsoPcsCodePoint(Number(code))) {
|
|
1082
|
+
throw new PrologError('representation_error(character_code)');
|
|
1083
|
+
}
|
|
1066
1084
|
solver.io.writeUnit(stream, name === 'put_byte' ? Number(code) : String.fromCodePoint(Number(code)));
|
|
1067
1085
|
}
|
|
1068
1086
|
yield env;
|
|
@@ -1090,6 +1108,9 @@ function* termTextCandidates(stream, solver) {
|
|
|
1090
1108
|
let quote = null, lineComment = false, blockComment = false;
|
|
1091
1109
|
for (let i = stream.position; i < source.length; i++) {
|
|
1092
1110
|
const ch = source[i], next = source[i + 1];
|
|
1111
|
+
if (solver.isoStrict && !isStrictIsoPcsCodePoint(ch.charCodeAt(0))) {
|
|
1112
|
+
throw new PrologError('representation_error(character)');
|
|
1113
|
+
}
|
|
1093
1114
|
// Text streams preserve invalid UTF-8 bytes as an impossible Unicode
|
|
1094
1115
|
// sentinel. read/1-2 and read_term/2-3 must surface the same character
|
|
1095
1116
|
// representation error as get_char/1-2 instead of misclassifying the
|
|
@@ -1101,7 +1122,7 @@ function* termTextCandidates(stream, solver) {
|
|
|
1101
1122
|
if (blockComment) { if (ch === '*' && next === '/') { blockComment = false; i++; } continue; }
|
|
1102
1123
|
if (quote) {
|
|
1103
1124
|
if (ch === '\\') i = quotedEscapeEnd(source, i);
|
|
1104
|
-
else if (ch !== ' ' && /^[\
|
|
1125
|
+
else if (ch !== ' ' && /^[\u0000-\u001f\u007f]$/.test(ch)) {
|
|
1105
1126
|
// Literal layout characters are not quoted characters (6.4.2.1).
|
|
1106
1127
|
// Surface the lexical error immediately even when there is no later
|
|
1107
1128
|
// full stop; otherwise read/1 would misreport malformed input as EOF.
|
|
@@ -1132,7 +1153,7 @@ function hasNonLayoutRemainder(source, start) {
|
|
|
1132
1153
|
return lastNonLayoutIndex(source, start) >= start;
|
|
1133
1154
|
}
|
|
1134
1155
|
function lastNonLayoutIndex(source, start = 0) {
|
|
1135
|
-
const ignored = /[\
|
|
1156
|
+
const ignored = /[\u0000-\u0020\u007f]+|%[^\n]*(?:\n|$)|\/\*[\s\S]*?\*\//g;
|
|
1136
1157
|
ignored.lastIndex = start;
|
|
1137
1158
|
let cursor = start;
|
|
1138
1159
|
let last = -1;
|
|
@@ -1243,7 +1264,9 @@ function readTermFromStream(stream, solver) {
|
|
|
1243
1264
|
stream.position = candidate.end;
|
|
1244
1265
|
return scopeReadTerm(term);
|
|
1245
1266
|
} catch (error) {
|
|
1246
|
-
if (error instanceof NumberRepresentationError
|
|
1267
|
+
if (error instanceof NumberRepresentationError || error instanceof CharacterRepresentationError) {
|
|
1268
|
+
throw new PrologError(error.formal);
|
|
1269
|
+
}
|
|
1247
1270
|
// A dot inside a graphic operator, such as =.., is only a possible
|
|
1248
1271
|
// terminator. Keep scanning until a complete term parses.
|
|
1249
1272
|
}
|
|
@@ -1505,30 +1528,35 @@ function oneChar(value) {
|
|
|
1505
1528
|
return value.type === ATOM && characters(value.name).length === 1;
|
|
1506
1529
|
}
|
|
1507
1530
|
|
|
1508
|
-
function validCharacterCode(value) {
|
|
1531
|
+
function validCharacterCode(value, solver = null) {
|
|
1509
1532
|
if (value.type !== NUMBER || !isDecimalInteger(value.name)) return false;
|
|
1510
1533
|
const code = BigInt(value.name);
|
|
1511
|
-
|
|
1534
|
+
if (code < 0n || code > 0x10ffffn || (code >= 0xd800n && code <= 0xdfffn)) return false;
|
|
1535
|
+
return !solver?.isoStrict || isStrictIsoPcsCodePoint(Number(code));
|
|
1512
1536
|
}
|
|
1513
1537
|
|
|
1514
|
-
function listToAtomInput(list, env, kind) {
|
|
1538
|
+
function listToAtomInput(list, env, kind, solver = null) {
|
|
1515
1539
|
const { items, tail } = listElements(list, env);
|
|
1516
1540
|
if (tail.type === VAR || items.some((item) => item.type === VAR)) throw new PrologError('instantiation_error');
|
|
1517
1541
|
if (tail.type !== ATOM || tail.name !== '[]') throw new PrologError('type_error(list)', tail);
|
|
1518
1542
|
if (kind === 'chars') {
|
|
1519
1543
|
const invalid = items.find((item) => !oneChar(item));
|
|
1520
1544
|
if (invalid) throw new PrologError('type_error(character)', invalid);
|
|
1545
|
+
if (solver?.isoStrict) {
|
|
1546
|
+
const outsidePcs = items.find((item) => !isStrictIsoPcsCharacter(item.name));
|
|
1547
|
+
if (outsidePcs) throw new PrologError('representation_error(character)', outsidePcs);
|
|
1548
|
+
}
|
|
1521
1549
|
return items.map((item) => item.name).join('');
|
|
1522
1550
|
}
|
|
1523
1551
|
const nonInteger = items.find((item) => item.type !== NUMBER || !isDecimalInteger(item.name));
|
|
1524
1552
|
if (nonInteger) throw new PrologError('type_error(integer)', nonInteger);
|
|
1525
|
-
const invalid = items.find((item) => !validCharacterCode(item));
|
|
1553
|
+
const invalid = items.find((item) => !validCharacterCode(item, solver));
|
|
1526
1554
|
if (invalid) throw new PrologError('representation_error(character_code)');
|
|
1527
1555
|
return items.map((item) => String.fromCodePoint(Number(item.name))).join('');
|
|
1528
1556
|
}
|
|
1529
1557
|
|
|
1530
1558
|
function atomListBuiltin(kind) {
|
|
1531
|
-
return function* ({ goal, env }) {
|
|
1559
|
+
return function* ({ solver, goal, env }) {
|
|
1532
1560
|
const value = deref(goal.args[0], env);
|
|
1533
1561
|
if (value.type !== VAR && value.type !== ATOM) throw new PrologError('type_error(atom)', value);
|
|
1534
1562
|
const list = deref(goal.args[1], env);
|
|
@@ -1541,7 +1569,7 @@ function atomListBuiltin(kind) {
|
|
|
1541
1569
|
}
|
|
1542
1570
|
const invalid = supplied.find((item) => item.type !== VAR &&
|
|
1543
1571
|
(kind === 'chars' ? !oneChar(item) :
|
|
1544
|
-
item.type !== NUMBER || !isDecimalInteger(item.name) || !validCharacterCode(item)));
|
|
1572
|
+
item.type !== NUMBER || !isDecimalInteger(item.name) || !validCharacterCode(item, solver)));
|
|
1545
1573
|
if (invalid) {
|
|
1546
1574
|
if (kind === 'chars') throw new PrologError('type_error(character)', invalid);
|
|
1547
1575
|
if (invalid.type !== NUMBER || !isDecimalInteger(invalid.name)) {
|
|
@@ -1549,26 +1577,32 @@ function atomListBuiltin(kind) {
|
|
|
1549
1577
|
}
|
|
1550
1578
|
throw new PrologError('representation_error(character_code)');
|
|
1551
1579
|
}
|
|
1580
|
+
if (solver.isoStrict && characters(value.name).some((ch) => !isStrictIsoPcsCharacter(ch))) {
|
|
1581
|
+
throw new PrologError('representation_error(character)', value);
|
|
1582
|
+
}
|
|
1552
1583
|
const items = characters(value.name).map((ch) =>
|
|
1553
1584
|
kind === 'chars' ? atom(ch) : numberTerm(ch.codePointAt(0)));
|
|
1554
1585
|
if (unify(goal.args[1], listFromItems(items), next)) yield next;
|
|
1555
1586
|
return;
|
|
1556
1587
|
}
|
|
1557
|
-
if (unify(goal.args[0], atom(listToAtomInput(list, env, kind)), next)) yield next;
|
|
1588
|
+
if (unify(goal.args[0], atom(listToAtomInput(list, env, kind, solver)), next)) yield next;
|
|
1558
1589
|
};
|
|
1559
1590
|
}
|
|
1560
1591
|
const atomCharsBuiltin = atomListBuiltin('chars');
|
|
1561
1592
|
const atomCodesBuiltin = atomListBuiltin('codes');
|
|
1562
1593
|
|
|
1563
|
-
function* charCodeBuiltin({ goal, env }) {
|
|
1594
|
+
function* charCodeBuiltin({ solver, goal, env }) {
|
|
1564
1595
|
const char = deref(goal.args[0], env);
|
|
1565
1596
|
const code = deref(goal.args[1], env);
|
|
1566
1597
|
if (char.type === VAR && code.type === VAR) throw new PrologError('instantiation_error');
|
|
1567
1598
|
if (char.type !== VAR && !oneChar(char)) throw new PrologError('type_error(character)', char);
|
|
1599
|
+
if (char.type === ATOM && solver.isoStrict && !isStrictIsoPcsCharacter(char.name)) {
|
|
1600
|
+
throw new PrologError('representation_error(character)', char);
|
|
1601
|
+
}
|
|
1568
1602
|
if (code.type !== VAR && (code.type !== NUMBER || !isDecimalInteger(code.name))) {
|
|
1569
1603
|
throw new PrologError('type_error(integer)', code);
|
|
1570
1604
|
}
|
|
1571
|
-
if (code.type !== VAR && !validCharacterCode(code)) throw new PrologError('representation_error(character_code)');
|
|
1605
|
+
if (code.type !== VAR && !validCharacterCode(code, solver)) throw new PrologError('representation_error(character_code)');
|
|
1572
1606
|
const next = env.clone();
|
|
1573
1607
|
if (char.type === ATOM) {
|
|
1574
1608
|
if (unify(goal.args[1], numberTerm(char.name.codePointAt(0)), next)) yield next;
|
|
@@ -1578,7 +1612,7 @@ function* charCodeBuiltin({ goal, env }) {
|
|
|
1578
1612
|
function skipNumberLayout(text, start) {
|
|
1579
1613
|
let position = start;
|
|
1580
1614
|
while (true) {
|
|
1581
|
-
while (position < text.length && /[\
|
|
1615
|
+
while (position < text.length && /[\u0000-\u0020\u007f]/.test(text[position])) {
|
|
1582
1616
|
position++;
|
|
1583
1617
|
}
|
|
1584
1618
|
if (text[position] === '%') {
|
|
@@ -1642,7 +1676,7 @@ function parseIsoNumber(text) {
|
|
|
1642
1676
|
// there without separating layout: `/` *can* continue the graphic token,
|
|
1643
1677
|
// and the eager-consumer rule therefore keeps `-/**/1` ill-formed (the
|
|
1644
1678
|
// number_chars continuation corpus case 24).
|
|
1645
|
-
if (/[\
|
|
1679
|
+
if (/[\u0000-\u0020\u007f]/.test(next) || next === '%') {
|
|
1646
1680
|
position = skipNumberLayout(text, position + 1);
|
|
1647
1681
|
sign = '-';
|
|
1648
1682
|
}
|