Skip to content

Commit 3ed0ccc

Browse files
committed
Resolve space properly
1 parent 1010948 commit 3ed0ccc

File tree

4 files changed

+40
-7
lines changed

4 files changed

+40
-7
lines changed

feature/if.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,11 @@ export const block = () =>
1111
export const body = () =>
1212
space() !== 123 ? expr(STATEMENT + .5) : (skip(), expr(STATEMENT - .5, 125) || null);
1313

14-
// Check for `else` after optional semicolon (use parse.space to consume comments)
14+
// Check for `else` after optional semicolon
1515
const checkElse = () => {
1616
const from = idx;
17-
const sp = parse.space || space;
18-
if (sp() === SEMI) skip();
19-
sp();
17+
if (space() === SEMI) skip();
18+
space();
2019
if (word('else')) return skip(4), true;
2120
return seek(from), false;
2221
};

parse.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,13 @@ export let idx, cur,
5151
)
5252
) token = newNode;
5353

54-
if (end) cc == end ? idx++ : err('Unclosed ' + String.fromCharCode(end - (end > 42 ? 2 : 1)));
54+
if (end) cc == end ? (idx++, end === 125 && parse.asi && (parse.newline = true)) : err('Unclosed ' + String.fromCharCode(end - (end > 42 ? 2 : 1)));
5555

5656
return token;
5757
},
5858

5959
// skip space chars, return first non-space character
60-
space = parse.space = (cc, from = idx) => {
60+
space = (cc, from = idx) => {
6161
while ((cc = cur.charCodeAt(idx)) <= SPACE) {
6262
if (parse.asi && cc === 10) parse.newline = true
6363
idx++
@@ -143,6 +143,14 @@ export let idx, cur,
143143
(seek(idx + l), (r = map()) ? loc(r, from) : seek(from), r) ||
144144
prev?.(a, curPrec, curOp);
145145

146+
// Keep parse.space overrides in sync with the exported binding used by features.
147+
Object.defineProperty(parse, 'space', {
148+
configurable: true,
149+
enumerable: true,
150+
get: () => space,
151+
set: fn => (space = fn)
152+
});
153+
146154
// === Compile: AST → Evaluator ===
147155

148156

test/feature/async-class.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ test('numbers: bigint', () => {
110110
is(parse('123n'), [, 123n]);
111111
is(parse('1_000n'), [, 1000n]);
112112
is(parse('0n'), [, 0n]);
113+
// prefixed bigint
114+
is(parse('0xFFn'), [, 0xFFn]);
115+
is(parse('0o77n'), [, 0o77n]);
116+
is(parse('0b101n'), [, 0b101n]);
117+
is(parse('0x1_ABCn'), [, 0x1ABCn]);
113118
});
114119

115120
test('meta: import.meta', () => {

test/justin.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import test, { is, throws } from 'tst'
55
import { parse, nary, binary, unary } from '../justin.js'
6-
import { compile, operator } from '../parse.js'
6+
import { compile, operator, cur, idx, seek } from '../parse.js'
77

88
const justin = s => compile(parse(s))
99

@@ -121,6 +121,27 @@ test('justin: optional chaining', () => {
121121
is(justin('a?.b?.(arg)?.[c] ?. d')({ a: { b: d => [, , { d }] }, arg: 1, c: 2 }), 1)
122122
})
123123

124+
test('justin: parse.space override reaches feature handlers', () => {
125+
const prevSpace = parse.space
126+
127+
parse.space = () => {
128+
for (let cc; (cc = prevSpace()); ) {
129+
if (cc !== 35) return cc
130+
let i = idx + 1
131+
while (cur[i] && cur.charCodeAt(i) !== 10) i++
132+
seek(i)
133+
}
134+
return 0
135+
}
136+
137+
try {
138+
is(parse('a?.# custom\n[1]'), ['?.[]', 'a', [, 1]])
139+
is(justin('a?.# custom\n[1]')({ a: [, 2] }), 2)
140+
} finally {
141+
parse.space = prevSpace
142+
}
143+
})
144+
124145
test('justin: nullish coalescing', () => {
125146
is(parse('a ?? b'), ['??', 'a', 'b'])
126147
is(justin('a ?? b')({ a: null, b: 'default' }), 'default')

0 commit comments

Comments
 (0)