1#![doc = include_str!("readme.md")]
2use oak_core::source::{SourceBuffer, ToSource};
3#[cfg(feature = "oak-pretty-print")]
4use oak_pretty_print::{AsDocument, Document};
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7use std::{string::String, vec::Vec};
8
9#[derive(Clone, Debug)]
11#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
12pub struct JasmRoot {
13 pub class: JasmClass,
14}
15
16impl ToSource for JasmRoot {
17 fn to_source(&self, buffer: &mut SourceBuffer) {
18 self.class.to_source(buffer)
19 }
20}
21
22#[cfg(feature = "oak-pretty-print")]
23impl AsDocument for JasmRoot {
24 fn as_document(&self) -> Document<'_> {
25 self.class.as_document()
26 }
27}
28
29#[derive(Clone, Debug)]
31#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
32pub struct JasmClass {
33 pub modifiers: Vec<String>,
35 pub name: String,
37 pub version: Option<String>,
39 pub methods: Vec<JasmMethod>,
41 pub fields: Vec<JasmField>,
43 pub source_file: Option<String>,
45}
46
47impl ToSource for JasmClass {
48 fn to_source(&self, buffer: &mut SourceBuffer) {
49 if let Some(source) = &self.source_file {
50 buffer.push(".source ");
51 buffer.push(source);
52 buffer.push("\n")
53 }
54 buffer.push(".class ");
55 for modifier in &self.modifiers {
56 buffer.push(modifier);
57 buffer.push(" ")
58 }
59 buffer.push(&self.name);
60 buffer.push("\n");
61 if let Some(version) = &self.version {
62 buffer.push(".version ");
63 buffer.push(version);
64 buffer.push("\n")
65 }
66 buffer.push("\n");
67 for field in &self.fields {
68 field.to_source(buffer);
69 buffer.push("\n")
70 }
71 for method in &self.methods {
72 method.to_source(buffer);
73 buffer.push("\n")
74 }
75 }
76}
77
78#[cfg(feature = "oak-pretty-print")]
79impl AsDocument for JasmClass {
80 fn as_document(&self) -> Document<'_> {
81 let mut docs = Vec::new();
82 if let Some(source) = &self.source_file {
83 docs.push(Document::Text(format!(".source {}\n", source).into()))
84 }
85 let mut class_line = vec![Document::Text(".class ".into())];
86 for modifier in &self.modifiers {
87 class_line.push(Document::Text(modifier.clone().into()));
88 class_line.push(Document::Text(" ".into()))
89 }
90 class_line.push(Document::Text(self.name.clone().into()));
91 docs.push(Document::Concat(class_line));
92 docs.push(Document::Line);
93
94 if let Some(version) = &self.version {
95 docs.push(Document::Text(format!(".version {}\n", version).into()))
96 }
97 docs.push(Document::Line);
98
99 for field in &self.fields {
100 docs.push(field.as_document());
101 docs.push(Document::Line)
102 }
103 for method in &self.methods {
104 docs.push(method.as_document());
105 docs.push(Document::Line)
106 }
107 Document::Concat(docs)
108 }
109}
110
111#[derive(Clone, Debug)]
113#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
114pub struct JasmMethod {
115 pub modifiers: Vec<String>,
117 pub name_and_descriptor: String,
119 pub stack_size: Option<u32>,
121 pub locals_count: Option<u32>,
123 pub instructions: Vec<JasmInstruction>,
125}
126
127impl ToSource for JasmMethod {
128 fn to_source(&self, buffer: &mut SourceBuffer) {
129 buffer.push(".method ");
130 for modifier in &self.modifiers {
131 buffer.push(modifier);
132 buffer.push(" ")
133 }
134 buffer.push(&self.name_and_descriptor);
135 buffer.push("\n");
136 if let Some(stack) = self.stack_size {
137 buffer.push(" .limit stack ");
138 buffer.push(&stack.to_string());
139 buffer.push("\n")
140 }
141 if let Some(locals) = self.locals_count {
142 buffer.push(" .limit locals ");
143 buffer.push(&locals.to_string());
144 buffer.push("\n")
145 }
146 for inst in &self.instructions {
147 buffer.push(" ");
148 inst.to_source(buffer);
149 buffer.push("\n")
150 }
151 buffer.push(".end method")
152 }
153}
154
155#[cfg(feature = "oak-pretty-print")]
156impl AsDocument for JasmMethod {
157 fn as_document(&self) -> Document<'_> {
158 let mut docs = Vec::new();
159 let mut method_line = vec![Document::Text(".method ".into())];
160 for modifier in &self.modifiers {
161 method_line.push(Document::Text(modifier.clone().into()));
162 method_line.push(Document::Text(" ".into()))
163 }
164 method_line.push(Document::Text(self.name_and_descriptor.clone().into()));
165 docs.push(Document::Concat(method_line));
166 docs.push(Document::Line);
167
168 let mut body = Vec::new();
169 if let Some(stack) = self.stack_size {
170 body.push(Document::Text(format!(".limit stack {}\n", stack).into()))
171 }
172 if let Some(locals) = self.locals_count {
173 body.push(Document::Text(format!(".limit locals {}\n", locals).into()))
174 }
175 for inst in &self.instructions {
176 body.push(inst.as_document());
177 body.push(Document::Line)
178 }
179
180 docs.push(Document::indent(Document::Concat(body)));
181 docs.push(Document::Text(".end method".into()));
182 Document::Concat(docs)
183 }
184}
185
186#[derive(Clone, Debug)]
188#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
189pub struct JasmField {
190 pub modifiers: Vec<String>,
192 pub name_and_descriptor: String,
194}
195
196impl ToSource for JasmField {
197 fn to_source(&self, buffer: &mut SourceBuffer) {
198 buffer.push(".field ");
199 for modifier in &self.modifiers {
200 buffer.push(modifier);
201 buffer.push(" ")
202 }
203 buffer.push(&self.name_and_descriptor)
204 }
205}
206
207#[cfg(feature = "oak-pretty-print")]
208impl AsDocument for JasmField {
209 fn as_document(&self) -> Document<'_> {
210 let mut docs = vec![Document::Text(".field ".into())];
211 for modifier in &self.modifiers {
212 docs.push(Document::Text(modifier.clone().into()));
213 docs.push(Document::Text(" ".into()))
214 }
215 docs.push(Document::Text(self.name_and_descriptor.clone().into()));
216 Document::Concat(docs)
217 }
218}
219
220#[derive(Clone, Debug)]
222#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
223pub enum JasmInstruction {
224 Simple(String),
226 WithArgument { instruction: String, argument: String },
228 MethodCall { instruction: String, method_ref: String },
230 FieldAccess { instruction: String, field_ref: String },
232}
233
234impl ToSource for JasmInstruction {
235 fn to_source(&self, buffer: &mut SourceBuffer) {
236 match self {
237 JasmInstruction::Simple(s) => buffer.push(s),
238 JasmInstruction::WithArgument { instruction, argument } => {
239 buffer.push(instruction);
240 buffer.push(" ");
241 buffer.push(argument)
242 }
243 JasmInstruction::MethodCall { instruction, method_ref } => {
244 buffer.push(instruction);
245 buffer.push(" ");
246 buffer.push(method_ref)
247 }
248 JasmInstruction::FieldAccess { instruction, field_ref } => {
249 buffer.push(instruction);
250 buffer.push(" ");
251 buffer.push(field_ref)
252 }
253 }
254 }
255}
256
257#[cfg(feature = "oak-pretty-print")]
258impl AsDocument for JasmInstruction {
259 fn as_document(&self) -> Document<'_> {
260 match self {
261 JasmInstruction::Simple(s) => Document::Text(s.clone().into()),
262 JasmInstruction::WithArgument { instruction, argument } => Document::Concat(vec![Document::Text(instruction.clone().into()), Document::Text(" ".into()), Document::Text(argument.clone().into())]),
263 JasmInstruction::MethodCall { instruction, method_ref } => Document::Concat(vec![Document::Text(instruction.clone().into()), Document::Text(" ".into()), Document::Text(method_ref.clone().into())]),
264 JasmInstruction::FieldAccess { instruction, field_ref } => Document::Concat(vec![Document::Text(instruction.clone().into()), Document::Text(" ".into()), Document::Text(field_ref.clone().into())]),
265 }
266 }
267}