Skip to content

Commit

Permalink
chore(traverse): add JSDoc type hints to JS codegen scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
DonIsaac committed Oct 8, 2024
1 parent a7de052 commit 2696201
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 3 deletions.
4 changes: 4 additions & 0 deletions crates/oxc_traverse/scripts/build.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ await writeToFile('ancestor.rs', generateAncestorsCode(types));
await writeToFile('walk.rs', generateWalkFunctionsCode(types));
await writeToFile('scopes_collector.rs', generateScopesCollectorCode(types));

/**
* @param {string} filename
* @param {string} code
*/
async function writeToFile(filename, code) {
code = `${PREAMBLE}${code}`;
const path = pathJoin(outputDirPath, filename);
Expand Down
3 changes: 3 additions & 0 deletions crates/oxc_traverse/scripts/lib/ancestor.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { camelToSnake, snakeToCamel } from './utils.mjs';

/**
* @param {import('./parse.mjs').Types} types
*/
export default function generateAncestorsCode(types) {
const variantNamesForEnums = Object.create(null);
let ancestorTypeEnumVariants = '',
Expand Down
101 changes: 99 additions & 2 deletions crates/oxc_traverse/scripts/lib/parse.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,64 @@ import { typeAndWrappers } from './utils.mjs';

const FILENAMES = ['js.rs', 'jsx.rs', 'literal.rs', 'ts.rs'];

/**
* @typedef {Record<string, StructType | EnumType>} Types
*/

/**
* @typedef {Object} EnumType
*
* @property {'enum'} kind
* @property {string} name
* @property {string} rawName
* @property {Variant[]} variants
* @property {string[]} inherits
*/

/**
* @typedef {Object} Variant
*
* @property {string} name
* @property {string} typeName
* @property {string} rawTypeName
* @property {string} innerTypeName
* @property {string[]} wrappers
* @property {number | null} discriminant
*/

/**
* @typedef {Object} StructType
*
* @property {'struct'} kind
* @property {string} name
* @property {string} rawName
* @property {Field[]} fields
* @property {ScopeArgs} scopeArgs
*/

/**
* @typedef {Object} Field
*
* @property {string} name
* @property {string} typeName
* @property {string} rawName
* @property {string} rawTypeName
* @property {string} innerTypeName
* @property {string[]} wrappers
*/

/**
* @typedef {Object} ScopeArgs
*
* @property {string} flags
* @property {string | null} strictIf
* @property {string | null} enterScopeBefore
*/

/**
* Parse type defs from Rust files.
*
* @returns {Promise<Types>}
*/
export default async function getTypesFromCode() {
const codeDirPath = pathJoin(fileURLToPath(import.meta.url), '../../../../oxc_ast/src/ast/');
Expand All @@ -20,8 +76,14 @@ export default async function getTypesFromCode() {
}

class Position {
/**
* @param {string} filename
* @param {number} index
*/
constructor(filename, index) {
/** @type {string} */
this.filename = filename;
/** @type {number} */
this.index = index;
}

Expand All @@ -34,13 +96,31 @@ class Position {
}

class Lines {
/**
* @param {string[]} lines
* @param {string} filename
* @param {number} [offset=0]
*/
constructor(lines, filename, offset = 0) {
/** @type {string[]} */
this.lines = lines;

/** @type {string} */
this.filename = filename;

/** @type {number} */
this.offset = offset;

/** @type {number} */
this.index = 0;
}

/**
* @param {string} code
* @param {string} filename
*
* @returns {Lines}
*/
static fromCode(code, filename) {
const lines = code.split(/\r?\n/)
.map(line => line.replace(/\s+/g, ' ').replace(/ ?\/\/.*$/, '').replace(/ $/, ''));
Expand All @@ -54,16 +134,19 @@ class Lines {
current() {
return this.lines[this.index];
}

next() {
return this.lines[this.index++];
}

isEnd() {
return this.index === this.lines.length;
}

position() {
return new Position(this.filename, this.index + this.offset);
}

positionPrevious() {
return new Position(this.filename, this.index + this.offset - 1);
}
Expand Down Expand Up @@ -107,8 +190,13 @@ function parseFile(code, filename, types) {
}
}

/**
* @returns {StructType}
*/
function parseStruct(name, rawName, lines, scopeArgs) {
/** @type {Field[]} */
const fields = [];

while (!lines.isEnd()) {
let isScopeEntry = false, line;
while (!lines.isEnd()) {
Expand Down Expand Up @@ -138,9 +226,15 @@ function parseStruct(name, rawName, lines, scopeArgs) {
return { kind: 'struct', name, rawName, fields, scopeArgs };
}

/**
* @returns {EnumType}
*/
function parseEnum(name, rawName, lines) {
const variants = [],
inherits = [];
/** @type {Variant[]} */
const variants = [];
/** @type {string[]} */
const inherits = [];

while (!lines.isEnd()) {
let line = lines.next();
if (line === '') continue;
Expand Down Expand Up @@ -189,6 +283,9 @@ function parseScopeArgs(lines, scopeArgs) {

const SCOPE_ARGS_KEYS = { flags: 'flags', strict_if: 'strictIf' };

/**
* @returns {ScopeArgs}
*/
function parseScopeArgsStr(argsStr, args, position) {
if (!args) args = { flags: 'ScopeFlags::empty()', strictIf: null, enterScopeBefore: null };

Expand Down
3 changes: 3 additions & 0 deletions crates/oxc_traverse/scripts/lib/scopes_collector.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { camelToSnake } from './utils.mjs';

/**
* @param {import('./parse.mjs').Types} types
*/
export default function generateScopesCollectorCode(types) {
let methods = '';
for (const type of Object.values(types)) {
Expand Down
3 changes: 3 additions & 0 deletions crates/oxc_traverse/scripts/lib/traverse.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { camelToSnake } from './utils.mjs';

/**
* @param {import('./parse.mjs').Types} types
*/
export default function generateTraverseTraitCode(types) {
const typesArr = Object.values(types);
typesArr.push({ name: 'Statements', rawName: "Vec<'a, Statement<'a>>" });
Expand Down
9 changes: 9 additions & 0 deletions crates/oxc_traverse/scripts/lib/utils.mjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/**
* @param {string} name
*/
export function typeAndWrappers(name) {
const wrappers = [];
while (true) {
Expand All @@ -9,6 +12,9 @@ export function typeAndWrappers(name) {
return { name, wrappers };
}

/**
* @param {string} name
*/
export function camelToSnake(name) {
let prefixLen = 1;
for (const prefix of ['TS', 'JSX', 'JS']) {
Expand All @@ -21,6 +27,9 @@ export function camelToSnake(name) {
name.slice(prefixLen).replace(/[A-Z]/g, c => `_${c.toLowerCase()}`);
}

/**
* @param {string} name
*/
export function snakeToCamel(name) {
let prefixLen = 0;
for (const prefix of ['TS', 'JSX', 'JS']) {
Expand Down
24 changes: 23 additions & 1 deletion crates/oxc_traverse/scripts/lib/walk.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import assert from 'assert';
import { camelToSnake, snakeToCamel } from './utils.mjs';

/**
* @typedef {import('./parse.mjs').Types} Types
* @typedef {import('./parse.mjs').StructType} StructType
* @typedef {import('./parse.mjs').EnumType} EnumType
* @typedef {import('./parse.mjs').Field} Field
*/

/**
* @param {Types} types
*/
export default function generateWalkFunctionsCode(types) {
let walkMethods = '';
for (const type of Object.values(types)) {
Expand Down Expand Up @@ -49,7 +59,12 @@ export default function generateWalkFunctionsCode(types) {
`;
}

/**
* @param {StructType} type
* @param {Types} types
*/
function generateWalkForStruct(type, types) {
/** @type {Field | undefined} */
let scopeIdField;
const visitedFields = type.fields.filter(field => {
if (field.name === 'scope_id' && field.typeName === `Cell<Option<ScopeId>>`) {
Expand All @@ -59,7 +74,10 @@ function generateWalkForStruct(type, types) {
});

const { scopeArgs } = type;
let scopeEnterField, enterScopeCode = '', exitScopeCode = '';
/** @type {Field | undefined} */
let scopeEnterField;
let enterScopeCode = '', exitScopeCode = '';

if (scopeArgs && scopeIdField) {
// Get field to enter scope before
const enterFieldName = scopeArgs.enterScopeBefore;
Expand Down Expand Up @@ -204,6 +222,10 @@ function makeFieldCode(field) {
return `(node as *mut u8).add(ancestor::${field.offsetVarName}) as *mut ${field.typeName}`;
}

/**
* @param {EnumType} type
* @param {Types} types
*/
function generateWalkForEnum(type, types) {
const variantCodes = type.variants.map((variant) => {
const variantType = types[variant.innerTypeName];
Expand Down

0 comments on commit 2696201

Please sign in to comment.