Skip to content

Commit

Permalink
repl: Handle unicode escape sequence
Browse files Browse the repository at this point in the history
  • Loading branch information
princejwesley committed Mar 19, 2016
1 parent 0eb3ed5 commit 9a9c021
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 0 deletions.
89 changes: 89 additions & 0 deletions lib/repl.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,46 @@ exports._builtinLibs = ['assert', 'buffer', 'child_process', 'cluster',
const BLOCK_SCOPED_ERROR = 'Block-scoped declarations (let, ' +
'const, function, class) not yet supported outside strict mode';

class LiteralPattern {

constructor(prefix, suffixOrMaxLength) {
this._prefix = prefix;
this._prefixLength = prefix.length;
if (typeof suffixOrMaxLength === 'string') {
this._suffix = suffixOrMaxLength;
this._suffixLength = suffixOrMaxLength.length;
} else {
this._maxLength = suffixOrMaxLength;
}
this.lastIndex = 0;
}

exec(input) {
input = input.substring(this.lastIndex);
const idx = input.indexOf(this._prefix);
if (idx !== -1) {
const start = this._prefixLength + idx;
if (this._suffix) {
input = input.substring(start);
const end = input.indexOf(this._suffix);
if (end !== -1) {
this.lastIndex += start + end + this._suffixLength;
return input.substring(0, end);
}
} else {
this.lastIndex += start + this._maxLength;
return input.substring(this._prefixLength + idx, this._maxLength);
}
}
this.lastIndex = 0;
return null;
}
}

const unicodePointLikePattern = new LiteralPattern('\\u{', '}');
const unicodeLikePattern = new LiteralPattern('\\u', 4);
const hexLikePattern = new LiteralPattern('\\x', 2);
const hexPattern = /^[\da-f]+$/i;

class LineParser {

Expand All @@ -82,17 +122,59 @@ class LineParser {

reset() {
this._literal = null;
this._literalValue = [];
this.shouldFail = false;
this.blockComment = false;
this.regExpLiteral = false;
}

parseEscapePattern(literal, pattern, predicate) {
let codePoint;
while ((codePoint = pattern.exec(literal)) !== null) {
if (!predicate(codePoint)) {
pattern.lastIndex = 0;
return false;
}
}
return true;
}

parseHexSequencePredicate(codePoint) {
return codePoint.length === 2 && hexPattern.test(codePoint);
}

parseUnicodePredicate(codePoint) {
return codePoint.length === 4 && hexPattern.test(codePoint);
}

parseUnicodePointPredicate(codePoint) {
return hexPattern.test(codePoint) && parseInt(codePoint, 16) <= 0x10FFFF;
}

parseEscapeSequence(literal) {
return this.parseEscapePattern(literal,
unicodePointLikePattern,
this.parseUnicodePointPredicate) &&
this.parseEscapePattern(literal,
unicodeLikePattern,
this.parseUnicodePredicate) &&
this.parseEscapePattern(literal,
hexLikePattern,
this.parseHexSequencePredicate);
}

parseLine(line) {
var previous = null;
this.shouldFail = false;
const wasWithinStrLiteral = this._literal !== null;
if (this._literal) {
this._literalValue.push('\n');
}

for (const current of line) {
if (this._literal && current !== this._literal) {
this._literalValue.push(current);
}
if (previous === '\\') {
// valid escaping, skip processing. previous doesn't matter anymore
previous = null;
Expand Down Expand Up @@ -135,6 +217,13 @@ class LineParser {

if (current === this._literal) {
this._literal = null;
const literal = this._literalValue.join('');
this._literalValue = [];

if (!this.parseEscapeSequence(literal)) {
this.shouldFail = true;
break;
}
} else if (current === '\'' || current === '"') {
this._literal = this._literal || current;
}
Expand Down
13 changes: 13 additions & 0 deletions test/parallel/test-repl.js
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,19 @@ function error_test() {
'undefined\n' + prompt_unix },
{ client: client_unix, send: '{ var x = 4; }',
expect: 'undefined\n' + prompt_unix },
// REPL should handle invalid escape sequences
{ client: client_unix, send: "'unicode point \\u{0000000041}'",
expect: "'unicode point A'\n" + prompt_unix },
{ client: client_unix, send: "'unicode \u0041'",
expect: "'unicode A'\n" + prompt_unix },
{ client: client_unix, send: "'hexadecimal \x41'",
expect: "'hexadecimal A'\n" + prompt_unix },
{ client: client_unix, send: "'\\u{10000000041} failure case'",
expect: /^SyntaxError: Unexpected token ILLEGAL/ },
{ client: client_unix, send: "'\\uea failure case'",
expect: /^SyntaxError: Unexpected token ILLEGAL/ },
{ client: client_unix, send: "'\\x1 edge case'",
expect: /^SyntaxError: Unexpected token ILLEGAL/ },
]);
}

Expand Down

0 comments on commit 9a9c021

Please sign in to comment.