Public
Edited
Sep 18, 2024
Importers
Insert cell
Insert cell
viewof filesToUpload = Inputs.file({
title: "a class file",
description: "class file",
accept: "*",
multiple: false
})
Insert cell
Insert cell
hello = FileAttachment("Hello.class")
Insert cell
cafebabe.length

Insert cell
Insert cell
classFile(0, cafebabe)
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
classFile = createConstantInfoParser("cafebabe", [
[expectP(u4be).toBe(0xcafebabe), "magic"],
[u2be, "minor_version"],
[u2be, "major_version"],
[constant_pool, "constant_pool"],
[u2be, "access_flags"],
[u2be, "this_class"],
[u2be, "super_class"],
[
flatMapParser(u2be, (lengthValue) =>
applyNTimes(u2be, lengthValue.value.value)
),
"interfaces"
],
[
flatMapParser(u2be, (lengthValueEnum) =>
applyNTimes(parseFieldInfo, lengthValueEnum.value.value)
),
"fields"
],
[
flatMapParser(u2be, (lengthValueEnum) =>
applyNTimes(parseMethodInfo, lengthValueEnum.value.value)
),
"methods"
],
[
flatMapParser(u2be, (lengthValueEnum) =>
applyNTimes(parseAttributeInfo, lengthValueEnum.value.value)
),
"attributes"
]
])
Insert cell
mapParser(u1, (_) => [_])(0, new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7])) //flatMapParser(u1.map,)
Insert cell
flatMapParser(u1, function (s) {
return mapParser(acceptAndDoNothing, (_) => s);
})(0, cafebabe)
Insert cell
parseConstantClassInfo = createConstantInfoParser("ConstantClassInfo", [
[u2be, "name_index"]
])
Insert cell
parseConstantFieldrefInfo = createConstantInfoParser("ConstantFieldrefInfo", [
[u2be, "class_index"],
[u2be, "name_and_type_index"]
])
Insert cell
parseConstantInterfaceMethodrefInfo = createConstantInfoParser(
"ConstantInterfaceMethodrefInfo",
[
[u2be, "class_index"],
[u2be, "name_and_type_index"]
]
)
Insert cell
parseConstantIntegerInfo = createConstantInfoParser("ConstantIntegerInfo ", [
[u4be, "bytes"]
])
Insert cell
parseConstantFloatInfo = createConstantInfoParser("ConstantFloatInfo", [
[u4be, "bytes"]
])
Insert cell
parseConstantDoubleInfo = createConstantInfoParser("ConstantDoubleInfo", [
[u4be, "high_bytes"],
[u4be, "low_bytes"]
])
Insert cell
parseConstantNameAndTypeInfo = createConstantInfoParser(
"ConstantNameAndTypeInfo",
[
[u2be, "name_index"],
[u2be, "descriptor_index"]
]
)
Insert cell
parseConstantUtf8Info = flatMapParser(u2be, (lengthValue) => {
return mapParser(takeN(lengthValue.value.value), (buffer) => ({
tag: "ConstantUtf8Info",
value: {
start: buffer.value.start,
end: buffer.value.end,
len: lengthValue.value.value,
value: new TextDecoder().decode(buffer.value.value)
}
}));
})
Insert cell
parseConstantLongInfo = createConstantInfoParser("ConstantLongInfo", [
[u4be, "high_bytes"],
[u4be, "low_bytes"]
])
Insert cell
parseConstantStringInfo = createConstantInfoParser("ConstantStringInfo", [
[u2be, "string_index"]
])
Insert cell
// Define constant info parsers for other types
parseConstantMethodHandleInfo = createConstantInfoParser(
"ConstantMethodHandleInfo",
[
[u1, "reference_kind"],
[u2be, "reference_index"]
]
)
Insert cell
parseConstantMethodTypeInfo = createConstantInfoParser(
"ConstantMethodTypeInfo",
[[u2be, "descriptor_index"]]
)
Insert cell
parseConstantInvokeDynamicInfo = createConstantInfoParser(
"ConstantInvokeDynamicInfo",
[
[u2be, "bootstrap_method_attr_index"],
[u2be, "name_and_type_index"]
]
)
Insert cell
parseConstantMethodrefInfo = createConstantInfoParser("ConstantMethodrefInfo", [
[u2be, "class_index"],
[u2be, "name_and_type_index"]
])
Insert cell
// Define the mapping from tags to parser functions
tagToParserMap = ({
7: parseConstantClassInfo,
9: parseConstantFieldrefInfo,
10: parseConstantMethodrefInfo,
11: parseConstantInterfaceMethodrefInfo,
8: parseConstantStringInfo,
3: parseConstantIntegerInfo,
4: parseConstantFloatInfo,
5: parseConstantLongInfo,
6: parseConstantDoubleInfo,
12: parseConstantNameAndTypeInfo,
1: parseConstantUtf8Info,
15: parseConstantMethodHandleInfo,
16: parseConstantMethodTypeInfo,
18: parseConstantInvokeDynamicInfo
})
Insert cell
parseCpInfo = flatMapParser(u1, (tagEnum) => {
const tag = tagEnum.value.value;
const parser = tagToParserMap[tag];
if (!parser) {
// Return a Result.error if there's no parser for the tag
return (index, bytes) =>
Result.error(`parseCpInfo: No parser found for tag: ${tag}`);
}
return (index, bytes) => {
// After parsing the tag, parse the associated info using the selected parser function
return parser(index, bytes) /*.okMap((info) => ({
nextIndex: info.nextIndex,
value: {
tag,
value: info.value.value
}
}))*/;
};
})
Insert cell
parseFieldInfo = createConstantInfoParser("FieldInfo", [
[u2be, "access_flags"],
[u2be, "name_index"],
[u2be, "descriptor_index"],
[
flatMapParser(u2be, (lengthValue) =>
applyNTimes(parseAttributeInfo, lengthValue.value.value)
),
"attributes"
]
])
Insert cell
parseAttributeInfo = createConstantInfoParser("AttributeInfo", [
[u2be, "attribute_name_index"],
[flatMapParser(u4be, (lengthValue) => takeN(lengthValue.value.value)), "info"]
])
Insert cell
parseMethodInfo = createConstantInfoParser("MethodInfo",[
[u2be, "access_flags"],
[u2be, "name_index"],
[u2be, "descriptor_index"],
[
flatMapParser(u2be, (lengthValue) => applyNTimes(parseAttributeInfo, lengthValue.value.value)
),
"attributes"
]
])
Insert cell
import { importGlobalAsEsm } from "@kreijstal/import-global-as-esm"
Insert cell
module = importGlobalAsEsm(
//"https://gist.githubusercontent.com/Kreijstal/f0297ee88d71974cc2fb60ff348ad301/raw/b700e92b39ad34514d609443cf9a7cb4c0e627ae/binaryparsercombinator.js"
"https://gist.githubusercontent.com/Kreijstal/f0297ee88d71974cc2fb60ff348ad301/raw/3edda16608de43f9478511b0997b3af28a0a4201/binaryparsercombinator.js"
)
Insert cell
ParseEnum = module.ParseEnum
Insert cell
flatMapParser = module.flatMapParser
Insert cell
createConstantInfoParser = module.createConstantInfoParser
Insert cell
u2be = module.u2be
Insert cell
applyNTimes = module.applyNTimes
Insert cell
u4be = module.u4be
Insert cell
takeN = module.takeN
Insert cell
Result = module.Result
Insert cell
u1 = module.u1
Insert cell
mapParser = module.mapParser
Insert cell
expectP = module.expectP
Insert cell
parseWhile = module.parseWhile
Insert cell
reduceParseResults = module.reduceParseResults
Insert cell
acceptAndDoNothing = module.acceptAndDoNothing
Insert cell
orParser = module.orParser
Insert cell
ByteSlice = module.ByteSlice
Insert cell
concatP = module.concatP
Insert cell
chainMapParser = module.chainMapParser
Insert cell
chainParser = module.chainParser
Insert cell
//Java forced me to do this, see this shit? Yeah that's the obtuse way to parse it, in retrospect it could've been done easier. (Challengeable idea)
constant_pool = flatMapParser(u2be, (lengthValueParseEnum) => {
//(parseCpInfo, lengthValue.value.value - 1);
return parseWhile(
parseCpInfo,
(result) => {
console.log("what is this", result);
return (
result.result.isOk() && result.acc < lengthValueParseEnum.value.value
);
},
(acc, p, cI, b) => {
var pa = p(cI, b);
if (pa.isOk()) {
//pa:Result<ParseOk<value:Enum(loc)>>
if (
["ConstantLongInfo", "ConstantDoubleInfo"].includes(
pa.value.value.tag
)
) {
return {
enumValue: acc.enumValue
.concat(pa.value.value)
.concat(ParseEnum.empty(pa.value.nextIndex)),
result: pa,
acc: acc.acc + 2
};
} else {
return {
enumValue: acc.enumValue.concat(pa.value.value),
result: pa,
acc: acc.acc + 1
};
}
} else {
return {
enumValue: acc.enumValue,
result: pa,
acc: acc.acc
};
}
},
{ enumValue: ParseEnum.empty(0), result: null, acc: 1 },
(_) => {
return Result.ok({
value: _.enumValue,
nextIndex: _.result.value.nextIndex
});
}
);
})
Insert cell
repeatWhileConcat(
ensureConcat(u1),
(_) => (console.log(_), _.value.value.length < 5)
)(0, [1, 2, 3, 4, 5, 6, 7, 8, 9])
Insert cell
/**
* Repeatedly applies a given parser and concatenates its results until the callback condition is false.
* @param {Parser} parser - The parser to apply repeatedly.
* @param {(currentResult: ParseEnum) => boolean} conditionFn - A callback that determines whether to continue based on the current results.
* @returns {Parser} - A parser that repeats the given parser and concatenates results while the condition is true.
*/
function repeatWhileConcat(parser, conditionFn) {
return function (index, bytes) {
let currentIndex = index;
const results = [];

// Initial using the enum with an empty array to maintain the format expected by `conditionFn`
let currentConcatEnum = new ParseEnum(
"concat",
new ByteSlice(index, index, function () {
return [];
})
);

// Continue looping until the condition function returns false
while (true) {
const result = parser(currentIndex, bytes);

// Stop and return an error if the parser fails
if (result.isErr()) {
return result;
}

const { nextIndex, value } = result.unwrap();
currentIndex = nextIndex;

// Flatten the result before concatenating
if (value.tag === "concat" && Array.isArray(value.value.value)) {
results.push(...value.value.value);
} else {
results.push(value);
}

// Update the currentConcatEnum with new results
currentConcatEnum = new ParseEnum(
"concat",
new ByteSlice(index, currentIndex, function () {
return results;
})
);

// Call the condition function
if (!conditionFn(currentConcatEnum)) {
break;
}
}

return Result.ok({ nextIndex: currentIndex, value: currentConcatEnum });
};
}
Insert cell
/**
* Ensures that the result of a parser is always a `ParseEnum` with a "concat" tag.
* If the original parser result is not a "concat", it wraps it into a "concat" `ParseEnum`.
* If it is already a "concat", it returns it unchanged.
* @param {Parser} parser - The parser to be normalized to always return a "concat" `ParseEnum`.
* @returns {Parser} - A parser that always returns a "concat" `ParseEnum`.
*/
function ensureConcat(parser) {
return mapParser(parser, function (value) {
// If the result value is already a concat, return it unchanged
if (value.tag === "concat") {
return value;
}

// If the result value is not a concat, wrap it in a new concat `ParseEnum`
return new ParseEnum(
"concat",
new ByteSlice(value.value.start, value.value.end, function () {
return [value];
})
);
});
}
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