Skip to content

Commit

Permalink
Refactor file parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
overlookmotel committed May 5, 2024
1 parent 05ca458 commit 0dedfc3
Showing 1 changed file with 79 additions and 56 deletions.
135 changes: 79 additions & 56 deletions crates/oxc_traverse/scripts/lib/parse.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,69 +3,92 @@ import {join as pathJoin} from 'path';
import {fileURLToPath} from 'url';
import assert from 'assert';

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

/**
* Parse type defs from Rust files.
*/
export default async function getTypesFromCode() {
const codeDirPath = pathJoin(fileURLToPath(import.meta.url), '../../../../oxc_ast/src/ast/');
const filenames = ['js.rs', 'jsx.rs', 'literal.rs', 'ts.rs'];

// Parse type defs from Rust files
const types = Object.create(null);
for (const filename of filenames) {
const code = await readFile(`${codeDirPath}${filename}`, 'utf8'),
lines = code.split(/\r?\n/);
for (let i = 0; i < lines.length; i++) {
if (lines[i] === '#[visited_node]') {
let match;
while (true) {
match = lines[++i].match(/^pub (enum|struct) (.+?)(<'a>)? \{/);
if (match) break;
}
const [, kind, name, lifetimeStr] = match,
hasLifetime = !!lifetimeStr;
const itemLines = [];
while (true) {
const line = lines[++i].replace(/\/\/.*$/, '').replace(/\s+/g, ' ').trim();
if (line === '}') break;
if (line !== '') itemLines.push(line);
}
for (const filename of FILENAMES) {
const code = await readFile(`${codeDirPath}${filename}`, 'utf8');
parseFile(code, filename, types);
}
return types;
}

function parseFile(code, filename, types) {
const lines = code.split(/\r?\n/);
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
if (lines[lineIndex] !== '#[visited_node]') continue;

let match;
while (true) {
match = lines[++lineIndex].match(/^pub (enum|struct) (.+?)(<'a>)? \{/);
if (match) break;
}
const [, kind, name, lifetimeStr] = match,
hasLifetime = !!lifetimeStr,
startLineIndex = lineIndex;

const itemLines = [];
while (true) {
const line = lines[++lineIndex].replace(/\/\/.*$/, '').replace(/\s+/g, ' ').trim();
if (line === '}') break;
if (line !== '') itemLines.push(line);
}

if (kind === 'enum') {
const variants = [],
inherits = [];
for (const line of itemLines) {
const match = line.match(/^(.+?)\((.+?)\)(?: ?= ?(\d+))?,$/);
if (match) {
let [, name, type, discriminant] = match;
type = type.replace(/<'a>/g, '').replace(/<'a,\s*/g, '<');
discriminant = discriminant ? +discriminant : null;
variants.push({name, type, discriminant});
} else {
const match2 = line.match(/^@inherit ([A-Za-z]+)$/);
assert(match2, `Cannot parse line ${i} in '${filename}' as enum variant: '${line}'`);
inherits.push(match2[1]);
}
}
types[name] = {kind: 'enum', name, hasLifetime, variants, inherits};
} else {
const fields = [];
for (let i = 0; i < itemLines.length; i++) {
const line = itemLines[i];
if (line.startsWith('#[')) {
while (!itemLines[i].endsWith(']')) {
i++;
}
continue;
}
if (kind === 'enum') {
types[name] = parseEnum(name, hasLifetime, itemLines, filename, startLineIndex);
} else {
types[name] = parseStruct(name, hasLifetime, itemLines, filename, startLineIndex);
}
}
}

const match = line.match(/^pub ((?:r#)?([a-z_]+)): (.+),(?: ?\/\/.+)?$/);
assert(match, `Cannot parse line ${i} in '${filename}' as struct field: '${line}'`);
const [, rawName, name, rawType] = match,
type = rawType.replace(/<'a>/g, '').replace(/<'a, ?/g, '<');
fields.push({name, type, rawName, rawType});
}
types[name] = {kind: 'struct', name, hasLifetime, fields};
}
function parseEnum(name, hasLifetime, lines, filename, startLineIndex) {
const variants = [],
inherits = [];
for (const [lineIndex, line] of lines.entries()) {
const match = line.match(/^(.+?)\((.+?)\)(?: ?= ?(\d+))?,$/);
if (match) {
const [, name, rawType, discriminantStr] = match,
type = rawType.replace(/<'a>/g, '').replace(/<'a,\s*/g, '<'),
discriminant = discriminantStr ? +discriminantStr : null;
variants.push({name, type, rawType, discriminant});
} else {
const match2 = line.match(/^@inherit ([A-Za-z]+)$/);
assert(
match2,
`Cannot parse line ${startLineIndex + lineIndex} in '${filename}' as enum variant: '${line}'`
);
inherits.push(match2[1]);
}
}
return {kind: 'enum', name, hasLifetime, variants, inherits};
}

function parseStruct(name, hasLifetime, lines, filename, startLineIndex) {
const fields = [];
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (line.startsWith('#[')) {
while (!lines[i].endsWith(']')) {
i++;
}
continue;
}

const match = line.match(/^pub ((?:r#)?([a-z_]+)): (.+),$/);
assert(
match,
`Cannot parse line ${startLineIndex + i} in '${filename}' as struct field: '${line}'`
);
const [, rawName, name, rawType] = match,
type = rawType.replace(/<'a>/g, '').replace(/<'a, ?/g, '<');
fields.push({name, type, rawName, rawType});
}
return types;
return {kind: 'struct', name, hasLifetime, fields};
}

0 comments on commit 0dedfc3

Please sign in to comment.