#![doc = include_str!("readme.md")]
use oak_core::source::{SourceBuffer, ToSource};
#[cfg(feature = "oak-pretty-print")]
use oak_pretty_print::Document;
#[cfg(feature = "oak-pretty-print")]
use oak_pretty_print::to_doc::AsDocument;
use std::{string::String, vec::Vec};
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct JasmRoot {
pub class: JasmClass,
}
impl ToSource for JasmRoot {
fn to_source(&self, buffer: &mut SourceBuffer) {
self.class.to_source(buffer)
}
}
#[cfg(feature = "oak-pretty-print")]
impl AsDocument for JasmRoot {
type Params = ();
fn as_document(&self, params: &Self::Params) -> Document<'_> {
self.class.as_document(params)
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct JasmClass {
pub modifiers: Vec<String>,
pub name: String,
pub version: Option<String>,
pub methods: Vec<JasmMethod>,
pub fields: Vec<JasmField>,
pub source_file: Option<String>,
pub super_class: Option<String>,
pub interfaces: Vec<String>,
pub annotations: Vec<String>,
pub attributes: Vec<String>,
}
impl ToSource for JasmClass {
fn to_source(&self, buffer: &mut SourceBuffer) {
if let Some(source) = &self.source_file {
buffer.push(".source ");
buffer.push(source);
buffer.push("\n")
}
if let Some(super_class) = &self.super_class {
buffer.push(".super ");
buffer.push(super_class);
buffer.push("\n")
}
buffer.push(".class ");
for modifier in &self.modifiers {
buffer.push(modifier);
buffer.push(" ")
}
buffer.push(&self.name);
buffer.push("\n");
if let Some(version) = &self.version {
buffer.push(".version ");
buffer.push(version);
buffer.push("\n")
}
for annotation in &self.annotations {
buffer.push(annotation);
buffer.push("\n")
}
for attribute in &self.attributes {
buffer.push(attribute);
buffer.push("\n")
}
for interface in &self.interfaces {
buffer.push(".interface ");
buffer.push(interface);
buffer.push("\n")
}
buffer.push("\n");
for field in &self.fields {
field.to_source(buffer);
buffer.push("\n")
}
for method in &self.methods {
method.to_source(buffer);
buffer.push("\n")
}
}
}
#[cfg(feature = "oak-pretty-print")]
impl AsDocument for JasmClass {
type Params = ();
fn as_document(&self, params: &Self::Params) -> Document<'_> {
let mut docs = Vec::new();
if let Some(source) = &self.source_file {
docs.push(Document::Text(format!(".source {}\n", source).into()))
}
if let Some(super_class) = &self.super_class {
docs.push(Document::Text(format!(".super {}\n", super_class).into()))
}
let mut class_line = vec![Document::Text(".class ".into())];
for modifier in &self.modifiers {
class_line.push(Document::Text(modifier.clone().into()));
class_line.push(Document::Text(" ".into()))
}
class_line.push(Document::Text(self.name.clone().into()));
docs.push(Document::Concat(class_line));
docs.push(Document::Line);
if let Some(version) = &self.version {
docs.push(Document::Text(format!(".version {}\n", version).into()))
}
for annotation in &self.annotations {
docs.push(Document::Text(format!("{}\n", annotation).into()))
}
for attribute in &self.attributes {
docs.push(Document::Text(format!("{}\n", attribute).into()))
}
for interface in &self.interfaces {
docs.push(Document::Text(format!(".interface {}\n", interface).into()))
}
docs.push(Document::Line);
for field in &self.fields {
docs.push(field.as_document(params));
docs.push(Document::Line)
}
for method in &self.methods {
docs.push(method.as_document(params));
docs.push(Document::Line)
}
Document::Concat(docs)
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct JasmMethod {
pub modifiers: Vec<String>,
pub name_and_descriptor: String,
pub stack_size: Option<u32>,
pub locals_count: Option<u32>,
pub instructions: Vec<JasmInstruction>,
pub exception_handlers: Vec<String>,
pub annotations: Vec<String>,
pub attributes: Vec<String>,
}
impl ToSource for JasmMethod {
fn to_source(&self, buffer: &mut SourceBuffer) {
buffer.push(".method ");
for modifier in &self.modifiers {
buffer.push(modifier);
buffer.push(" ")
}
buffer.push(&self.name_and_descriptor);
buffer.push("\n");
for annotation in &self.annotations {
buffer.push(" ");
buffer.push(annotation);
buffer.push("\n")
}
for attribute in &self.attributes {
buffer.push(" ");
buffer.push(attribute);
buffer.push("\n")
}
if let Some(stack) = self.stack_size {
buffer.push(" .limit stack ");
buffer.push(&stack.to_string());
buffer.push("\n")
}
if let Some(locals) = self.locals_count {
buffer.push(" .limit locals ");
buffer.push(&locals.to_string());
buffer.push("\n")
}
for exception_handler in &self.exception_handlers {
buffer.push(" ");
buffer.push(exception_handler);
buffer.push("\n")
}
for inst in &self.instructions {
buffer.push(" ");
inst.to_source(buffer);
buffer.push("\n")
}
buffer.push(".end method")
}
}
#[cfg(feature = "oak-pretty-print")]
impl AsDocument for JasmMethod {
type Params = ();
fn as_document(&self, params: &Self::Params) -> Document<'_> {
let mut docs = Vec::new();
let mut method_line = vec![Document::Text(".method ".into())];
for modifier in &self.modifiers {
method_line.push(Document::Text(modifier.clone().into()));
method_line.push(Document::Text(" ".into()))
}
method_line.push(Document::Text(self.name_and_descriptor.clone().into()));
docs.push(Document::Concat(method_line));
docs.push(Document::Line);
let mut body = Vec::new();
for annotation in &self.annotations {
body.push(Document::Text(format!("{}\n", annotation).into()))
}
for attribute in &self.attributes {
body.push(Document::Text(format!("{}\n", attribute).into()))
}
if let Some(stack) = self.stack_size {
body.push(Document::Text(format!(".limit stack {}\n", stack).into()))
}
if let Some(locals) = self.locals_count {
body.push(Document::Text(format!(".limit locals {}\n", locals).into()))
}
for exception_handler in &self.exception_handlers {
body.push(Document::Text(format!("{}\n", exception_handler).into()))
}
for inst in &self.instructions {
body.push(inst.as_document(params));
body.push(Document::Line)
}
docs.push(Document::indent(Document::Concat(body)));
docs.push(Document::Text(".end method".into()));
Document::Concat(docs)
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct JasmField {
pub modifiers: Vec<String>,
pub name_and_descriptor: String,
pub annotations: Vec<String>,
pub attributes: Vec<String>,
}
impl ToSource for JasmField {
fn to_source(&self, buffer: &mut SourceBuffer) {
for annotation in &self.annotations {
buffer.push(annotation);
buffer.push("\n");
buffer.push(" ")
}
for attribute in &self.attributes {
buffer.push(attribute);
buffer.push("\n");
buffer.push(" ")
}
buffer.push(".field ");
for modifier in &self.modifiers {
buffer.push(modifier);
buffer.push(" ")
}
buffer.push(&self.name_and_descriptor)
}
}
#[cfg(feature = "oak-pretty-print")]
impl AsDocument for JasmField {
type Params = ();
fn as_document(&self, _params: &Self::Params) -> Document<'_> {
let mut docs = Vec::new();
for annotation in &self.annotations {
docs.push(Document::Text(format!("{}\n", annotation).into()));
docs.push(Document::Text(" ".into()))
}
for attribute in &self.attributes {
docs.push(Document::Text(format!("{}\n", attribute).into()));
docs.push(Document::Text(" ".into()))
}
docs.push(Document::Text(".field ".into()));
for modifier in &self.modifiers {
docs.push(Document::Text(modifier.clone().into()));
docs.push(Document::Text(" ".into()))
}
docs.push(Document::Text(self.name_and_descriptor.clone().into()));
Document::Concat(docs)
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum JasmInstruction {
Simple(String),
WithArgument {
instruction: String,
argument: String,
},
MethodCall {
instruction: String,
method_ref: String,
},
FieldAccess {
instruction: String,
field_ref: String,
},
}
impl ToSource for JasmInstruction {
fn to_source(&self, buffer: &mut SourceBuffer) {
match self {
JasmInstruction::Simple(s) => buffer.push(s),
JasmInstruction::WithArgument { instruction, argument } => {
buffer.push(instruction);
buffer.push(" ");
buffer.push(argument)
}
JasmInstruction::MethodCall { instruction, method_ref } => {
buffer.push(instruction);
buffer.push(" ");
buffer.push(method_ref)
}
JasmInstruction::FieldAccess { instruction, field_ref } => {
buffer.push(instruction);
buffer.push(" ");
buffer.push(field_ref)
}
}
}
}
#[cfg(feature = "oak-pretty-print")]
impl AsDocument for JasmInstruction {
type Params = ();
fn as_document(&self, _params: &Self::Params) -> Document<'_> {
match self {
JasmInstruction::Simple(s) => Document::Text(s.clone().into()),
JasmInstruction::WithArgument { instruction, argument } => Document::Concat(vec![Document::Text(instruction.clone().into()), Document::Text(" ".into()), Document::Text(argument.clone().into())]),
JasmInstruction::MethodCall { instruction, method_ref } => Document::Concat(vec![Document::Text(instruction.clone().into()), Document::Text(" ".into()), Document::Text(method_ref.clone().into())]),
JasmInstruction::FieldAccess { instruction, field_ref } => Document::Concat(vec![Document::Text(instruction.clone().into()), Document::Text(" ".into()), Document::Text(field_ref.clone().into())]),
}
}
}