@mavrykdynamics/taquito-michel-codec
Version:
Michelson parser/validator/formatter
129 lines (128 loc) • 4.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.scan = exports.Literal = exports.ScanError = void 0;
const taquito_core_1 = require("@mavrykdynamics/taquito-core");
/**
* @category Error
* @description Error that indicates a failure when performing the scan step when parsing Michelson
*/
class ScanError extends taquito_core_1.TaquitoError {
constructor(src, idx, message) {
super();
this.src = src;
this.idx = idx;
this.message = message;
this.name = 'ScanError';
}
}
exports.ScanError = ScanError;
var Literal;
(function (Literal) {
Literal[Literal["Comment"] = 0] = "Comment";
Literal[Literal["Number"] = 1] = "Number";
Literal[Literal["String"] = 2] = "String";
Literal[Literal["Bytes"] = 3] = "Bytes";
Literal[Literal["Ident"] = 4] = "Ident";
})(Literal || (exports.Literal = Literal = {}));
const isSpace = new RegExp('\\s');
const isIdentStart = new RegExp('[:@%_A-Za-z]');
const isIdent = new RegExp('[@%_\\.A-Za-z0-9]');
const isDigit = new RegExp('[0-9]');
const isHex = new RegExp('[0-9a-fA-F]');
function* scan(src, scanComments = false) {
let i = 0;
while (i < src.length) {
// Skip space
while (i < src.length && isSpace.test(src[i])) {
i++;
}
if (i === src.length) {
return;
}
const s = src[i];
const start = i;
if (isIdentStart.test(s)) {
// Identifier
i++;
while (i < src.length && isIdent.test(src[i])) {
i++;
}
yield { t: Literal.Ident, v: src.slice(start, i), first: start, last: i };
}
else if (src.length - i > 1 && src.substring(i, i + 2) === '0x') {
// Bytes
i += 2;
while (i < src.length && isHex.test(src[i])) {
i++;
}
if (((i - start) & 1) !== 0) {
throw new ScanError(src, i, 'Bytes literal length is expected to be power of two');
}
yield { t: Literal.Bytes, v: src.slice(start, i), first: start, last: i };
}
else if (isDigit.test(s) || s === '-') {
// Number
if (s === '-') {
i++;
}
const ii = i;
while (i < src.length && isDigit.test(src[i])) {
i++;
}
if (ii === i) {
throw new ScanError(src, i, 'Number literal is too short');
}
yield { t: Literal.Number, v: src.slice(start, i), first: start, last: i };
}
else if (s === '"') {
// String
i++;
let esc = false;
for (; i < src.length && (esc || src[i] !== '"'); i++) {
if (!esc && src[i] === '\\') {
esc = true;
}
else {
esc = false;
}
}
if (i === src.length) {
throw new ScanError(src, i, 'Unterminated string literal');
}
i++;
yield { t: Literal.String, v: src.slice(start, i), first: start, last: i };
}
else if (s === '#') {
// Comment
i++;
while (i < src.length && src[i] !== '\n') {
i++;
}
if (scanComments) {
yield { t: Literal.Comment, v: src.slice(start, i), first: start, last: i };
}
}
else if (src.length - i > 1 && src.substring(i, i + 2) === '/*') {
// C style comment
i += 2;
while (i < src.length && !(src.length - i > 1 && src.substring(i, i + 2) === '*/')) {
i++;
}
if (i === src.length) {
throw new ScanError(src, i, 'Unterminated C style comment');
}
i += 2;
if (scanComments) {
yield { t: Literal.Comment, v: src.slice(start, i), first: start, last: i };
}
}
else if (s === '(' || s === ')' || s === '{' || s === '}' || s === ';') {
i++;
yield { t: s, v: s, first: start, last: i };
}
else {
throw new ScanError(src, i, `Invalid character at offset ${i}: \`${s}'`);
}
}
}
exports.scan = scan;