Public
Edited
Oct 4, 2024
1 fork
Insert cell
Insert cell
Insert cell
import { file } from "@jashkenas/inputs"
Insert cell
viewof filesToUpload = file({
title: "a class file",
description: "class file",
accept: "*",
multiple: false
})
Insert cell
Insert cell
ClassFile.parse(cafebabe)
Insert cell
Insert cell
function unparseDataStructures(root) {
function formatInstruction(instr) {
if (typeof instr === "string") {
return instr;
} else if (instr.op === "tableswitch") {
// Prioritize tableswitch check
const labelsStr = instr.labels
.map((label) => ` ${label}`)
.join("\n");
return `${instr.op} ${instr.low}\n${labelsStr}\n default : ${instr.defaultLbl}`; // Format tableswitch with labels and default label
} else if (instr.op === "iinc") {
// Handle iinc instruction with arguments
return `${instr.op} ${instr.varnum} ${instr.incr}`;
} else if (instr.op !== undefined && instr.arg !== undefined) {
const argStr = formatInstructionArg(instr.arg);
if (instr.op === "invokeinterface" && instr.count !== undefined) {
return `${instr.op} ${argStr} ${instr.count}`; // Include the count for invokeinterface
} else {
return `${instr.op} ${argStr}`;
}
} else {
return instr.op || "";
}
}

function formatInstructionArg(arg) {
if (typeof arg === "string") {
return arg;
} else if (Array.isArray(arg)) {
// Recursively format each item and join with spaces
return arg.map(formatInstructionArg).join(" ");
} else if (typeof arg === "object") {
// For object arguments, check if it's a sourcefile attribute
if (arg.type === "sourcefile") {
return arg.value; // Return the value directly without further formatting
} else {
// For other object arguments, format their values
return Object.values(arg).map(formatInstructionArg).join(" ");
}
} else {
return String(arg);
}
}

function formatCodeAttribute(attr) {
if (attr.type === "linenumbertable") {
const lines = [
` .linenumbertable`,
...attr.lines.map(
(line) => ` ${line.label} ${line.lineNumber}`
),
` .end linenumbertable`
];
return lines.join("\n");
} else if (attr.type === "localvariabletable") {
const vars = [
` .localvariabletable`,
...attr.vars.map(
(v) =>
` ${v.index} is ${v.name} ${v.descriptor} from ${v.startLbl} to ${v.endLbl}`
),
` .end localvariabletable`
];
return vars.join("\n");
}
// Add more cases as needed
return "";
}

return root.classes
.map((cls) => {
// Include the .version directive if present
const headerLines = [];

if (cls.version && cls.version.length > 0) {
headerLines.push(
`.version ${cls.version[0].major} ${cls.version[0].minor}`
);
}

headerLines.push(`.class ${cls.flags.join(" ")} ${cls.className}`);
headerLines.push(`.super ${cls.superClass}`);

// Handle interfaces
if (cls.interfaces && cls.interfaces.length > 0) {
headerLines.push(
cls.interfaces.map((iface) => `.implements ${iface}`).join("\n")
);
}

// Fields
const fields = cls.items
.filter((item) => item.type === "field")
.map((item) => {
const field = item.field;
return `.field ${field.name} ${field.descriptor};`;
})
.join("\n\n");

// Methods
const methods = cls.items
.filter((item) => item.type === "method")
.map((item) => {
const method = item.method;
const methodHeader = `.method ${method.flags.join(" ")} ${
method.name
} : ${method.descriptor}`;

// Code attribute
const codeAttribute = method.attributes.find(
(attr) => attr.type === "code"
);
let codeSection = "";
if (codeAttribute && codeAttribute.code) {
const codeLines = [
` .code stack ${codeAttribute.code.stackSize} locals ${codeAttribute.code.localsSize}`,
...codeAttribute.code.codeItems.flatMap((ci) => {
let line = "";
if (ci.labelDef) {
line += `${ci.labelDef}`;
}
if (ci.instruction) {
if (line.length > 0) {
line += " ";
}
line += formatInstruction(ci.instruction);
}
if (ci.type === "catch") {
line = ` .catch ${ci.clsref} from ${ci.fromLbl} to ${ci.toLbl} using ${ci.usingLbl}`;
}
return line ? [line] : [];
}),
...codeAttribute.code.attributes.map((attr) =>
formatCodeAttribute(attr)
),
` .end code`
];
codeSection = codeLines.join("\n");
}

// Exceptions
const exceptionsAttribute = method.attributes.find(
(attr) => attr.type === "exceptions"
);
let exceptionsSection = "";
if (exceptionsAttribute) {
exceptionsSection = ` .exceptions ${exceptionsAttribute.exceptions.join(
" "
)}`;
}

return [methodHeader, codeSection, exceptionsSection, `.end method`]
.filter(Boolean)
.join("\n");
})
.join("\n\n");

// Source file
const sourceFileAttribute = cls.items.find(
(item) => item.attribute && item.attribute.type === "sourcefile"
);
let sourceFileLine = "";
if (sourceFileAttribute) {
sourceFileLine = `.sourcefile ${sourceFileAttribute.attribute.value}`;
}

// Combine all parts
return [
headerLines.filter(Boolean).join("\n"),
fields,
methods,
sourceFileLine,
`.end class`
]
.filter(Boolean)
.join("\n");
})
.join("\n\n");
}
Insert cell
s = unparseDataStructures(convertJson(obj.ast, obj.constantPool)) + "\n"
Insert cell
import { Lang } from "@kreijstal/krakatau-parser"
Insert cell
Lang.source_file.tryParse(s)
Insert cell
convertJson(obj.ast, obj.constantPool)
Insert cell
obj = parseClassFile(ClassFile.parse(cafebabe), opcodeNames)
Insert cell
disassemble(obj.ast, obj.constantPool)
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
binary_parserbr = FileAttachment("binary_parserbr.js")
Insert cell
binary_parser = (
await import(
`data:text/javascript;base64,${btoa(
`export default ${await binary_parserbr.text()}`
)}`
)
).default(39)
Insert cell
Parser = binary_parser.Parser
Insert cell
Insert cell
CpInfo = variables.CpInfo
Insert cell
ClassFile = variables.ClassFile
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more