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