/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * * @format */ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _HermesParserDecodeUTF8String = _interopRequireDefault(require("./HermesParserDecodeUTF8String")); var _HermesParserNodeDeserializers = _interopRequireDefault(require("./HermesParserNodeDeserializers")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } class HermesParserDeserializer { // Matches StoredComment::Kind enum in JSLexer.h // Matches TokenType enum in HermesParserJSSerializer.h constructor(programBuffer, positionBuffer, positionBufferSize, wasmParser, options) { this.programBufferIdx = void 0; this.positionBufferIdx = void 0; this.positionBufferSize = void 0; this.locMap = void 0; this.HEAPU8 = void 0; this.HEAPU32 = void 0; this.HEAPF64 = void 0; this.options = void 0; this.commentTypes = ['CommentLine', 'CommentBlock', 'InterpreterDirective']; this.tokenTypes = ['Boolean', 'Identifier', 'Keyword', 'Null', 'Numeric', 'BigInt', 'Punctuator', 'String', 'RegularExpression', 'Template', 'JSXText']; // Program and position buffer are memory addresses, so we must convert // into indices into HEAPU32 (an array of 4-byte integers). this.programBufferIdx = programBuffer / 4; this.positionBufferIdx = positionBuffer / 4; this.positionBufferSize = positionBufferSize; this.locMap = {}; this.HEAPU8 = wasmParser.HEAPU8; this.HEAPU32 = wasmParser.HEAPU32; this.HEAPF64 = wasmParser.HEAPF64; this.options = options; } /** * Consume and return the next 4 bytes in the program buffer. */ next() { const num = this.HEAPU32[this.programBufferIdx++]; return num; } deserialize() { const program = { type: 'Program', loc: this.addEmptyLoc(), body: this.deserializeNodeList(), comments: this.deserializeComments() }; if (this.options.tokens === true) { program.tokens = this.deserializeTokens(); } this.fillLocs(); return program; } /** * Booleans are serialized as a single 4-byte integer. */ deserializeBoolean() { return Boolean(this.next()); } /** * Numbers are serialized directly into program buffer, taking up 8 bytes * preceded by 4 bytes of alignment padding if necessary. */ deserializeNumber() { let floatIdx; // Numbers are aligned on 8-byte boundaries, so skip padding if we are at // an odd index into the 4-byte aligned program buffer. if (this.programBufferIdx % 2 === 0) { floatIdx = this.programBufferIdx / 2; this.programBufferIdx += 2; } else { floatIdx = (this.programBufferIdx + 1) / 2; this.programBufferIdx += 3; } return this.HEAPF64[floatIdx]; } /** * Strings are serialized as a 4-byte pointer into the heap, followed * by their size as a 4-byte integer. The size is only present if the * pointer is non-null. */ deserializeString() { const ptr = this.next(); if (ptr === 0) { return null; } const size = this.next(); return (0, _HermesParserDecodeUTF8String.default)(ptr, size, this.HEAPU8); } /** * Nodes are serialized as a 4-byte integer denoting their node kind, * followed by a 4-byte loc ID, followed by serialized node properties. * * If the node kind is 0 the node is null, otherwise the node kind - 1 is an * index into the array of node deserialization functions. */ deserializeNode() { const nodeType = this.next(); if (nodeType === 0) { return null; } const nodeDeserializer = _HermesParserNodeDeserializers.default[nodeType - 1].bind(this); return nodeDeserializer(); } /** * Node lists are serialized as a 4-byte integer denoting the number of * elements in the list, followed by the serialized elements. */ deserializeNodeList() { const size = this.next(); const nodeList = []; for (let i = 0; i < size; i++) { nodeList.push(this.deserializeNode()); } return nodeList; } /** * Comments are serialized as a node list, where each comment is serialized * as a 4-byte integer denoting comment type, followed by a 4-byte value * denoting the loc ID, followed by a serialized string for the comment value. */ deserializeComments() { const size = this.next(); const comments = []; for (let i = 0; i < size; i++) { const commentType = this.commentTypes[this.next()]; const loc = this.addEmptyLoc(); const value = this.deserializeString(); comments.push({ type: commentType, loc, value }); } return comments; } deserializeTokens() { const size = this.next(); const tokens = []; for (let i = 0; i < size; i++) { const tokenType = this.tokenTypes[this.next()]; const loc = this.addEmptyLoc(); const value = this.deserializeString(); tokens.push({ type: tokenType, loc, value }); } return tokens; } /** * While deserializing the AST locations are represented by * a 4-byte loc ID. This is used to create a map of loc IDs to empty loc * objects that are filled after the AST has been deserialized. */ addEmptyLoc() { // $FlowExpectedError const loc = {}; this.locMap[this.next()] = loc; return loc; } /** * Positions are serialized as a loc ID which denotes which loc it is associated with, * followed by kind which denotes whether it is a start or end position, * followed by line, column, and offset (4-bytes each). */ fillLocs() { for (let i = 0; i < this.positionBufferSize; i++) { const locId = this.HEAPU32[this.positionBufferIdx++]; const kind = this.HEAPU32[this.positionBufferIdx++]; const line = this.HEAPU32[this.positionBufferIdx++]; const column = this.HEAPU32[this.positionBufferIdx++]; const offset = this.HEAPU32[this.positionBufferIdx++]; const loc = this.locMap[locId]; if (kind === 0) { loc.start = { line, column }; loc.rangeStart = offset; } else { loc.end = { line, column }; loc.rangeEnd = offset; } } } } exports.default = HermesParserDeserializer;