Repair comment reading and trailing comments in pexprs

This commit is contained in:
Tony Garnock-Jones 2024-05-15 10:49:30 +02:00
parent f18ba9c9d4
commit 58ebc93eb5
3 changed files with 36 additions and 21 deletions

View File

@ -165,37 +165,34 @@ export class Reader extends ReaderBase<never> {
} }
readCompound(c: Compound, terminator: string): Compound { readCompound(c: Compound, terminator: string): Compound {
while (true) { while (this.readExpr(c, terminator)) {}
this.state.skipws(); return c;
if (this.state.peek() === terminator) {
this.state.advance();
return c;
}
if (!this.readExpr(c)) {
this.state.error(`Missing "${terminator}"`, this.state.copyPos());
}
}
} }
readSimpleExpr(c: BaseCompound<SimpleExpr>): boolean { readSimpleExpr(c: BaseCompound<SimpleExpr>): boolean {
return this._readInto(c, false); return this._readInto(c, false);
} }
readExpr(c: BaseCompound<Expr>): boolean { readExpr(c: BaseCompound<Expr>, terminator: string | null = null): boolean {
return this._readInto(c as BaseCompound<SimpleExpr> /* yuck */, true); return this._readInto(c as BaseCompound<SimpleExpr> /* yuck */, true, terminator);
} }
_readInto(c: BaseCompound<SimpleExpr>, acceptPunct: boolean): boolean { _checkTerminator(actual: string, expected: string | null, startPos: Position): false {
if (actual === expected) return false;
this.state.error('Unexpected ' + actual, startPos);
}
_readInto(c: BaseCompound<SimpleExpr>, acceptPunct: boolean, terminator: string | null = null): boolean {
while (true) { while (true) {
this.state.skipws(); this.state.skipws();
if (this.state.atEnd()) return false; if (this.state.atEnd() && terminator === null) return false;
const startPos = this.state.copyPos(); const startPos = this.state.copyPos();
const ch = this.state.nextchar(); const ch = this.state.nextchar();
switch (ch) { switch (ch) {
case '"': case '"':
return c.push(this.state.readString('"'), startPos); return c.push(this.state.readString('"'), startPos);
case '|': case '|':
return c.push(Symbol.for(this.state.readString('|')), startPos); return true; return c.push(Symbol.for(this.state.readString('|')), startPos);
case ';': case ';':
if (acceptPunct) { if (acceptPunct) {
return (c as BaseCompound<Expr>).push(new Punct(';'), startPos); return (c as BaseCompound<Expr>).push(new Punct(';'), startPos);
@ -264,9 +261,10 @@ export class Reader extends ReaderBase<never> {
case '<': return c.push(this.readCompound(new Record(), '>'), startPos); case '<': return c.push(this.readCompound(new Record(), '>'), startPos);
case '[': return c.push(this.readCompound(new Sequence(), ']'), startPos); case '[': return c.push(this.readCompound(new Sequence(), ']'), startPos);
case '{': return c.push(this.readCompound(new Block(), '}'), startPos); case '{': return c.push(this.readCompound(new Block(), '}'), startPos);
case '>': this.state.error('Unexpected >', startPos); case ')': return this._checkTerminator(ch, terminator, startPos);
case ']': this.state.error('Unexpected ]', startPos); case '>': return this._checkTerminator(ch, terminator, startPos);
case '}': this.state.error('Unexpected }', startPos); case ']': return this._checkTerminator(ch, terminator, startPos);
case '}': return this._checkTerminator(ch, terminator, startPos);
case ',': case ',':
if (acceptPunct) { if (acceptPunct) {
return (c as BaseCompound<Expr>).push(new Punct(','), startPos); return (c as BaseCompound<Expr>).push(new Punct(','), startPos);

View File

@ -254,10 +254,9 @@ export class ReaderState {
readCommentLine(): string { readCommentLine(): string {
let acc = ''; let acc = '';
while (true) { while (true) {
if (this.atEnd()) return acc;
const c = this.nextchar(); const c = this.nextchar();
if (c === '\n' || c === '\r') { if (c === '\n' || c === '\r') return acc;
return acc;
}
acc = acc + c; acc = acc + c;
} }
} }

View File

@ -25,3 +25,21 @@ describe('basics', () => {
expect(v).is(P(s)); expect(v).is(P(s));
}); });
}); });
describe('trailing comments', () => {
it('basics 1', () => {
const d = new Pexpr.Reader('# a comment with nothing after').nextDocument();
expect(d.annotations?.[d.exprs.length].get(0)?.item).toBe('a comment with nothing after');
});
it('basics 2', () => {
const d = new Pexpr.Reader('# a comment with nothing after\n').nextDocument();
expect(d.annotations?.[d.exprs.length].get(0)?.item).toBe('a comment with nothing after');
});
it('inside a sequence', () => {
const d = new Pexpr.Reader('[\n1\n# a comment with nothing after\n]\n').nextDocument();
const seq = d.get(0)?.item as Pexpr.Compound;
expect(seq.annotations?.[seq.exprs.length].get(0)?.item).toBe('a comment with nothing after');
});
});