1#![doc = include_str!("readme.md")]
2use oak_core::source::{SourceBuffer, ToSource};
3#[cfg(feature = "oak-pretty-print")]
4use oak_pretty_print::{AsDocument, Document};
5use std::{string::String, vec::Vec};
6
7#[derive(Clone, Debug)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub struct JasmRoot {
11 pub class: JasmClass,
13}
14
15impl ToSource for JasmRoot {
16 fn to_source(&self, buffer: &mut SourceBuffer) {
17 self.class.to_source(buffer)
18 }
19}
20
21#[cfg(feature = "oak-pretty-print")]
22impl AsDocument for JasmRoot {
23 fn as_document(&self) -> Document<'_> {
24 self.class.as_document()
25 }
26}
27
28#[derive(Clone, Debug)]
30#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
31pub struct JasmClass {
32 pub modifiers: Vec<String>,
34 pub name: String,
36 pub version: Option<String>,
38 pub methods: Vec<JasmMethod>,
40 pub fields: Vec<JasmField>,
42 pub source_file: Option<String>,
44 pub super_class: Option<String>,
46 pub interfaces: Vec<String>,
48 pub annotations: Vec<String>,
50 pub attributes: Vec<String>,
52}
53
54impl ToSource for JasmClass {
55 fn to_source(&self, buffer: &mut SourceBuffer) {
56 if let Some(source) = &self.source_file {
57 buffer.push(".source ");
58 buffer.push(source);
59 buffer.push("\n")
60 }
61 if let Some(super_class) = &self.super_class {
62 buffer.push(".super ");
63 buffer.push(super_class);
64 buffer.push("\n")
65 }
66 buffer.push(".class ");
67 for modifier in &self.modifiers {
68 buffer.push(modifier);
69 buffer.push(" ")
70 }
71 buffer.push(&self.name);
72 buffer.push("\n");
73 if let Some(version) = &self.version {
74 buffer.push(".version ");
75 buffer.push(version);
76 buffer.push("\n")
77 }
78 for annotation in &self.annotations {
79 buffer.push(annotation);
80 buffer.push("\n")
81 }
82 for attribute in &self.attributes {
83 buffer.push(attribute);
84 buffer.push("\n")
85 }
86 for interface in &self.interfaces {
87 buffer.push(".interface ");
88 buffer.push(interface);
89 buffer.push("\n")
90 }
91 buffer.push("\n");
92 for field in &self.fields {
93 field.to_source(buffer);
94 buffer.push("\n")
95 }
96 for method in &self.methods {
97 method.to_source(buffer);
98 buffer.push("\n")
99 }
100 }
101}
102
103#[cfg(feature = "oak-pretty-print")]
104impl AsDocument for JasmClass {
105 fn as_document(&self) -> Document<'_> {
106 let mut docs = Vec::new();
107 if let Some(source) = &self.source_file {
108 docs.push(Document::Text(format!(".source {}\n", source).into()))
109 }
110 if let Some(super_class) = &self.super_class {
111 docs.push(Document::Text(format!(".super {}\n", super_class).into()))
112 }
113 let mut class_line = vec![Document::Text(".class ".into())];
114 for modifier in &self.modifiers {
115 class_line.push(Document::Text(modifier.clone().into()));
116 class_line.push(Document::Text(" ".into()))
117 }
118 class_line.push(Document::Text(self.name.clone().into()));
119 docs.push(Document::Concat(class_line));
120 docs.push(Document::Line);
121
122 if let Some(version) = &self.version {
123 docs.push(Document::Text(format!(".version {}\n", version).into()))
124 }
125 for annotation in &self.annotations {
126 docs.push(Document::Text(format!("{}\n", annotation).into()))
127 }
128 for attribute in &self.attributes {
129 docs.push(Document::Text(format!("{}\n", attribute).into()))
130 }
131 for interface in &self.interfaces {
132 docs.push(Document::Text(format!(".interface {}\n", interface).into()))
133 }
134 docs.push(Document::Line);
135
136 for field in &self.fields {
137 docs.push(field.as_document());
138 docs.push(Document::Line)
139 }
140 for method in &self.methods {
141 docs.push(method.as_document());
142 docs.push(Document::Line)
143 }
144 Document::Concat(docs)
145 }
146}
147
148#[derive(Clone, Debug)]
150#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
151pub struct JasmMethod {
152 pub modifiers: Vec<String>,
154 pub name_and_descriptor: String,
156 pub stack_size: Option<u32>,
158 pub locals_count: Option<u32>,
160 pub instructions: Vec<JasmInstruction>,
162 pub exception_handlers: Vec<String>,
164 pub annotations: Vec<String>,
166 pub attributes: Vec<String>,
168}
169
170impl ToSource for JasmMethod {
171 fn to_source(&self, buffer: &mut SourceBuffer) {
172 buffer.push(".method ");
173 for modifier in &self.modifiers {
174 buffer.push(modifier);
175 buffer.push(" ")
176 }
177 buffer.push(&self.name_and_descriptor);
178 buffer.push("\n");
179 for annotation in &self.annotations {
180 buffer.push(" ");
181 buffer.push(annotation);
182 buffer.push("\n")
183 }
184 for attribute in &self.attributes {
185 buffer.push(" ");
186 buffer.push(attribute);
187 buffer.push("\n")
188 }
189 if let Some(stack) = self.stack_size {
190 buffer.push(" .limit stack ");
191 buffer.push(&stack.to_string());
192 buffer.push("\n")
193 }
194 if let Some(locals) = self.locals_count {
195 buffer.push(" .limit locals ");
196 buffer.push(&locals.to_string());
197 buffer.push("\n")
198 }
199 for exception_handler in &self.exception_handlers {
200 buffer.push(" ");
201 buffer.push(exception_handler);
202 buffer.push("\n")
203 }
204 for inst in &self.instructions {
205 buffer.push(" ");
206 inst.to_source(buffer);
207 buffer.push("\n")
208 }
209 buffer.push(".end method")
210 }
211}
212
213#[cfg(feature = "oak-pretty-print")]
214impl AsDocument for JasmMethod {
215 fn as_document(&self) -> Document<'_> {
216 let mut docs = Vec::new();
217 let mut method_line = vec![Document::Text(".method ".into())];
218 for modifier in &self.modifiers {
219 method_line.push(Document::Text(modifier.clone().into()));
220 method_line.push(Document::Text(" ".into()))
221 }
222 method_line.push(Document::Text(self.name_and_descriptor.clone().into()));
223 docs.push(Document::Concat(method_line));
224 docs.push(Document::Line);
225
226 let mut body = Vec::new();
227 for annotation in &self.annotations {
228 body.push(Document::Text(format!("{}\n", annotation).into()))
229 }
230 for attribute in &self.attributes {
231 body.push(Document::Text(format!("{}\n", attribute).into()))
232 }
233 if let Some(stack) = self.stack_size {
234 body.push(Document::Text(format!(".limit stack {}\n", stack).into()))
235 }
236 if let Some(locals) = self.locals_count {
237 body.push(Document::Text(format!(".limit locals {}\n", locals).into()))
238 }
239 for exception_handler in &self.exception_handlers {
240 body.push(Document::Text(format!("{}\n", exception_handler).into()))
241 }
242 for inst in &self.instructions {
243 body.push(inst.as_document());
244 body.push(Document::Line)
245 }
246
247 docs.push(Document::indent(Document::Concat(body)));
248 docs.push(Document::Text(".end method".into()));
249 Document::Concat(docs)
250 }
251}
252
253#[derive(Clone, Debug)]
255#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
256pub struct JasmField {
257 pub modifiers: Vec<String>,
259 pub name_and_descriptor: String,
261 pub annotations: Vec<String>,
263 pub attributes: Vec<String>,
265}
266
267impl ToSource for JasmField {
268 fn to_source(&self, buffer: &mut SourceBuffer) {
269 for annotation in &self.annotations {
270 buffer.push(annotation);
271 buffer.push("\n");
272 buffer.push(" ")
273 }
274 for attribute in &self.attributes {
275 buffer.push(attribute);
276 buffer.push("\n");
277 buffer.push(" ")
278 }
279 buffer.push(".field ");
280 for modifier in &self.modifiers {
281 buffer.push(modifier);
282 buffer.push(" ")
283 }
284 buffer.push(&self.name_and_descriptor)
285 }
286}
287
288#[cfg(feature = "oak-pretty-print")]
289impl AsDocument for JasmField {
290 fn as_document(&self) -> Document<'_> {
291 let mut docs = Vec::new();
292 for annotation in &self.annotations {
293 docs.push(Document::Text(format!("{}\n", annotation).into()));
294 docs.push(Document::Text(" ".into()))
295 }
296 for attribute in &self.attributes {
297 docs.push(Document::Text(format!("{}\n", attribute).into()));
298 docs.push(Document::Text(" ".into()))
299 }
300 docs.push(Document::Text(".field ".into()));
301 for modifier in &self.modifiers {
302 docs.push(Document::Text(modifier.clone().into()));
303 docs.push(Document::Text(" ".into()))
304 }
305 docs.push(Document::Text(self.name_and_descriptor.clone().into()));
306 Document::Concat(docs)
307 }
308}
309
310#[derive(Clone, Debug)]
312#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
313pub enum JasmInstruction {
314 Simple(String),
316 WithArgument {
318 instruction: String,
320 argument: String,
322 },
323 MethodCall {
325 instruction: String,
327 method_ref: String,
329 },
330 FieldAccess {
332 instruction: String,
334 field_ref: String,
336 },
337}
338
339impl ToSource for JasmInstruction {
340 fn to_source(&self, buffer: &mut SourceBuffer) {
341 match self {
342 JasmInstruction::Simple(s) => buffer.push(s),
343 JasmInstruction::WithArgument { instruction, argument } => {
344 buffer.push(instruction);
345 buffer.push(" ");
346 buffer.push(argument)
347 }
348 JasmInstruction::MethodCall { instruction, method_ref } => {
349 buffer.push(instruction);
350 buffer.push(" ");
351 buffer.push(method_ref)
352 }
353 JasmInstruction::FieldAccess { instruction, field_ref } => {
354 buffer.push(instruction);
355 buffer.push(" ");
356 buffer.push(field_ref)
357 }
358 }
359 }
360}
361
362#[cfg(feature = "oak-pretty-print")]
363impl AsDocument for JasmInstruction {
364 fn as_document(&self) -> Document<'_> {
365 match self {
366 JasmInstruction::Simple(s) => Document::Text(s.clone().into()),
367 JasmInstruction::WithArgument { instruction, argument } => Document::Concat(vec![Document::Text(instruction.clone().into()), Document::Text(" ".into()), Document::Text(argument.clone().into())]),
368 JasmInstruction::MethodCall { instruction, method_ref } => Document::Concat(vec![Document::Text(instruction.clone().into()), Document::Text(" ".into()), Document::Text(method_ref.clone().into())]),
369 JasmInstruction::FieldAccess { instruction, field_ref } => Document::Concat(vec![Document::Text(instruction.clone().into()), Document::Text(" ".into()), Document::Text(field_ref.clone().into())]),
370 }
371 }
372}