use super::SwcGenerator;
use crate::parser::*;
use crate::codegen::swc_decorator::*;
use crate::codegen::decorated_ast::*;
impl SwcGenerator {
pub(super) fn gen_plugin(&mut self, plugin: &PluginDecl) {
for item in &plugin.body {
if let PluginItem::Struct(s) = item {
self.gen_struct(s);
}
}
for item in &plugin.body {
if let PluginItem::Enum(e) = item {
self.gen_enum(e);
}
}
let state_struct = plugin.body.iter().find_map(|item| {
if let PluginItem::Struct(s) = item {
if s.name == "State" {
return Some(s);
}
}
None
});
self.emit_line(&format!("pub struct {} {{", plugin.name));
self.indent += 1;
if state_struct.is_some() {
self.emit_line("pub state: State,");
} else {
self.emit_line("// Plugin state");
}
self.indent -= 1;
self.emit_line("}");
self.emit_line("");
self.emit_line(&format!("impl {} {{", plugin.name));
self.indent += 1;
self.emit_line("pub fn new() -> Self {");
self.indent += 1;
if let Some(state) = state_struct {
self.emit_line("Self {");
self.indent += 1;
self.emit_line("state: State {");
self.indent += 1;
for field in &state.fields {
let default_value = self.get_default_value_for_type(&field.ty);
self.emit_line(&format!("{}: {},", field.name, default_value));
}
self.indent -= 1;
self.emit_line("},");
self.indent -= 1;
self.emit_line("}");
} else {
self.emit_line("Self {}");
}
self.indent -= 1;
self.emit_line("}");
for item in &plugin.body {
if let PluginItem::Function(f) = item {
if !self.is_visitor_method(f) {
self.emit_line("");
self.gen_helper_function(f);
}
}
}
self.indent -= 1;
self.emit_line("}");
self.emit_line("");
self.emit_line(&format!("impl VisitMut for {} {{", plugin.name));
self.indent += 1;
for item in &plugin.body {
if let PluginItem::Function(f) = item {
if self.is_visitor_method(f) {
self.gen_visitor_method(f);
}
}
}
self.indent -= 1;
self.emit_line("}");
}
pub(super) fn gen_writer(&mut self, writer: &WriterDecl) {
self.is_writer = true;
let mut pre_hook: Option<&FnDecl> = None;
let mut exit_hook: Option<&FnDecl> = None;
let mut methods = Vec::new();
let mut structs = Vec::new();
for item in &writer.body {
match item {
PluginItem::PreHook(f) => pre_hook = Some(f),
PluginItem::ExitHook(f) => exit_hook = Some(f),
PluginItem::Function(f) => {
if f.name == "init" && pre_hook.is_none() {
pre_hook = Some(f);
} else if f.name == "finish" && exit_hook.is_none() {
exit_hook = Some(f);
} else {
methods.push(f);
}
},
PluginItem::Struct(s) => structs.push(s),
_ => {}
}
}
self.emit_line("use swc_ecma_visit::Visit;");
self.emit_line("");
let state_struct = structs.iter().find(|s| s.name == "State").cloned();
for struct_decl in &structs {
if struct_decl.name != "State" {
self.gen_struct(struct_decl);
self.emit_line("");
}
}
self.emit_line(&format!("pub struct {} {{", writer.name));
self.indent += 1;
self.emit_line("output: String,");
self.emit_line("indent_level: usize,");
if let Some(state) = state_struct {
for field in &state.fields {
let rust_type = self.type_to_rust(&field.ty);
self.emit_line(&format!("{}: {},", field.name, rust_type));
}
}
self.indent -= 1;
self.emit_line("}");
self.emit_line("");
self.emit_line(&format!("impl {} {{", writer.name));
self.indent += 1;
self.emit_line("pub fn new() -> Self {");
self.indent += 1;
self.emit_line("Self {");
self.indent += 1;
self.emit_line("output: String::new(),");
self.emit_line("indent_level: 0,");
if let Some(state) = state_struct {
for field in &state.fields {
let default_value = self.get_default_value_for_type(&field.ty);
self.emit_line(&format!("{}: {},", field.name, default_value));
}
}
self.indent -= 1;
self.emit_line("}");
self.indent -= 1;
self.emit_line("}");
self.emit_line("");
self.emit_line("fn append(&mut self, s: &str) {");
self.indent += 1;
self.emit_line("self.output.push_str(s);");
self.indent -= 1;
self.emit_line("}");
self.emit_line("");
self.emit_line("fn newline(&mut self) {");
self.indent += 1;
self.emit_line("self.output.push('\\n');");
self.indent -= 1;
self.emit_line("}");
self.emit_line("");
self.emit_line("fn indent(&mut self) {");
self.indent += 1;
self.emit_line("self.indent_level += 1;");
self.indent -= 1;
self.emit_line("}");
self.emit_line("");
self.emit_line("fn dedent(&mut self) {");
self.indent += 1;
self.emit_line("self.indent_level -= 1;");
self.indent -= 1;
self.emit_line("}");
self.emit_line("");
if let Some(exit_fn) = exit_hook {
self.emit_line("/// Finalize output (from exit hook)");
self.emit_line("pub fn finish(mut self) -> String {");
self.indent += 1;
self.gen_block(&exit_fn.body);
self.emit_line("self.output");
self.indent -= 1;
self.emit_line("}");
} else {
self.emit_line("pub fn finish(self) -> String {");
self.indent += 1;
self.emit_line("self.output");
self.indent -= 1;
self.emit_line("}");
}
self.emit_line("");
if pre_hook.is_some() {
self.emit_line("// Note: pre() hook not supported in SWC (no source access)");
self.emit_line("");
}
for method in &methods {
if !method.name.starts_with("visit_") {
self.gen_helper_function(method);
self.emit_line("");
}
}
self.indent -= 1;
self.emit_line("}");
self.emit_line("");
self.emit_line(&format!("impl Visit for {} {{", writer.name));
self.indent += 1;
for method in methods {
if method.name.starts_with("visit_") {
self.gen_visit_method(method);
}
}
self.indent -= 1;
self.emit_line("}");
}
pub(super) fn gen_decorated_plugin(&mut self, plugin: &DecoratedPlugin) {
self.emit_line(&format!("pub struct {} {{}}", plugin.name));
self.emit_line("");
self.emit_line(&format!("impl {} {{", plugin.name));
self.indent += 1;
self.emit_indent();
self.emit_line("pub fn new() -> Self { Self {} }");
self.indent -= 1;
self.emit_line("}");
self.emit_line("");
self.emit_line(&format!("impl VisitMut for {} {{", plugin.name));
self.indent += 1;
for item in &plugin.body {
match item {
DecoratedPluginItem::Function(func) => {
self.gen_decorated_visitor_method(func);
}
_ => {
}
}
}
self.indent -= 1;
self.emit_line("}");
}
pub(super) fn gen_decorated_writer(&mut self, writer: &DecoratedWriter) {
self.emit_line(&format!("// TODO: Decorated writer {}", writer.name));
}
pub(super) fn gen_module(&mut self, module: &ModuleDecl) {
self.emit_line("//! Generated by ReluxScript compiler");
self.emit_line("//! Do not edit manually");
self.emit_line("");
for item in &module.items {
if let PluginItem::Struct(s) = item {
self.gen_struct(s);
}
}
for item in &module.items {
if let PluginItem::Enum(e) = item {
self.gen_enum(e);
}
}
for item in &module.items {
if let PluginItem::Function(f) = item {
self.gen_helper_function(f);
self.emit_line("");
}
}
}
}