use super::SwcGenerator;
use crate::parser::*;
impl SwcGenerator {
pub(super) fn gen_struct(&mut self, s: &StructDecl) {
if self.uses_json {
self.emit_line("#[derive(Debug, Clone, Serialize, Deserialize)]");
} else {
self.emit_line("#[derive(Debug, Clone)]");
}
self.emit_line(&format!("pub struct {} {{", s.name));
self.indent += 1;
for field in &s.fields {
self.emit_indent();
self.emit(&format!("pub {}: {},\n", field.name, self.type_to_rust(&field.ty)));
}
self.indent -= 1;
self.emit_line("}");
self.emit_line("");
}
pub(super) fn gen_enum(&mut self, e: &EnumDecl) {
if self.uses_json {
self.emit_line("#[derive(Debug, Clone, Serialize, Deserialize)]");
} else {
self.emit_line("#[derive(Debug, Clone)]");
}
self.emit_line(&format!("pub enum {} {{", e.name));
self.indent += 1;
for variant in &e.variants {
self.emit_indent();
match &variant.fields {
EnumVariantFields::Tuple(fields) => {
let types: Vec<String> = fields.iter().map(|t| self.type_to_rust(t)).collect();
self.emit(&format!("{}({}),\n", variant.name, types.join(", ")));
}
EnumVariantFields::Struct(named_fields) => {
self.emit(&format!("{} {{\n", variant.name));
self.indent += 1;
for (field_name, field_type) in named_fields {
self.emit_indent();
self.emit(&format!("{}: {},\n", field_name, self.type_to_rust(field_type)));
}
self.indent -= 1;
self.emit_indent();
self.emit("},\n");
}
EnumVariantFields::Unit => {
self.emit(&format!("{},\n", variant.name));
}
}
}
self.indent -= 1;
self.emit_line("}");
self.emit_line("");
}
pub(super) fn gen_helper_function(&mut self, f: &crate::codegen::decorated_ast::DecoratedNestedFnDecl) {
let pub_str = if f.is_pub { "pub " } else { "" };
let has_self = f.params.iter().any(|p| p.name == "self");
if !has_self {
self.associated_functions.insert(f.name.clone());
}
let type_params = if !f.type_params.is_empty() {
let params: Vec<String> = f.type_params.iter().map(|p| p.name.clone()).collect();
format!("<{}>", params.join(", "))
} else {
String::new()
};
let params: Vec<String> = f.params.iter().map(|p| {
format!("{}: {}", p.name, self.type_to_rust(&p.ty))
}).collect();
let ret_type = f.return_type.as_ref()
.map(|t| format!(" -> {}", self.type_to_rust(t)))
.unwrap_or_default();
let where_clause = if !f.where_clause.is_empty() {
let predicates: Vec<String> = f.where_clause.iter().map(|p| {
format!(" {}: {}", p.target, self.type_to_rust(&p.bound))
}).collect();
format!("\nwhere\n{}", predicates.join(",\n"))
} else {
String::new()
};
self.emit_line(&format!("{}fn {}{}({}){}{} {{", pub_str, f.name, type_params, params.join(", "), ret_type, where_clause));
self.indent += 1;
self.type_env.push_scope();
for param in &f.params {
let param_ctx = self.type_from_ast(¶m.ty);
#[cfg(debug_assertions)]
eprintln!("[swc] param {} : {:?} -> swc_type={}",
param.name, param.ty, param_ctx.swc_type);
self.type_env.define(¶m.name, param_ctx);
}
for stmt in &f.body.stmts {
self.gen_decorated_stmt(stmt);
}
self.type_env.pop_scope();
self.indent -= 1;
self.emit_line("}");
}
pub(super) fn gen_codegen_call(&mut self, function_name: &str, args: &[Expr]) {
match function_name {
"generate" => {
if args.is_empty() {
self.emit("String::new()");
return;
}
self.emit("codegen_to_string(");
self.gen_expr(&args[0]);
self.emit(")");
}
"generate_with_options" => {
if args.is_empty() {
self.emit("String::new()");
return;
}
self.emit("codegen_to_string_with_config(");
self.gen_expr(&args[0]);
if args.len() > 1 {
self.emit(", ");
self.gen_codegen_config(&args[1]);
} else {
self.emit(", CodegenConfig::default()");
}
self.emit(")");
}
_ => {
self.emit(&format!("codegen::{}(", function_name));
for (i, arg) in args.iter().enumerate() {
if i > 0 {
self.emit(", ");
}
self.gen_expr(arg);
}
self.emit(")");
}
}
}
pub(super) fn gen_codegen_config(&mut self, options_expr: &Expr) {
if let Expr::StructInit(init) = options_expr {
if init.name == "CodegenOptions" {
self.emit("CodegenConfig { ");
for (field_name, field_value) in &init.fields {
match field_name.as_str() {
"minified" => {
self.emit("minify: ");
self.gen_expr(field_value);
self.emit(", ");
}
"compact" | "semicolons" => {
}
"quotes" => {
}
_ => {
}
}
}
self.emit("..Default::default() }");
return;
}
}
self.emit("CodegenConfig::default()");
}
pub(super) fn gen_parser_module_helpers(&mut self) {
self.emit_line("mod parser {");
self.indent += 1;
self.emit_line("use super::*;");
self.emit_line("");
self.emit_line("pub fn parse_file(path: &str) -> Result<Program, String> {");
self.indent += 1;
self.emit_line("let source_map = Arc::new(SourceMap::default());");
self.emit_line("let code = std::fs::read_to_string(path)");
self.indent += 1;
self.emit_line(".map_err(|e| format!(\"Failed to read file: {}\", e))?;");
self.indent -= 1;
self.emit_line("let file = source_map.new_source_file(");
self.indent += 1;
self.emit_line("FileName::Real(path.into()),");
self.emit_line("code,");
self.indent -= 1;
self.emit_line(");");
self.emit_line("let syntax = Syntax::Typescript(TsConfig {");
self.indent += 1;
self.emit_line("tsx: true,");
self.emit_line("decorators: false,");
self.emit_line("..Default::default()");
self.indent -= 1;
self.emit_line("});");
self.emit_line("let mut parser = Parser::new(syntax, StringInput::from(&*file), None);");
self.emit_line("parser.parse_program()");
self.indent += 1;
self.emit_line(".map_err(|e| format!(\"Parse error: {:?}\", e))");
self.indent -= 1;
self.indent -= 1;
self.emit_line("}");
self.emit_line("");
self.emit_line("pub fn parse(code: &str) -> Result<Program, String> {");
self.indent += 1;
self.emit_line("let source_map = Arc::new(SourceMap::default());");
self.emit_line("let file = source_map.new_source_file(");
self.indent += 1;
self.emit_line("FileName::Anon,");
self.emit_line("code.to_string(),");
self.indent -= 1;
self.emit_line(");");
self.emit_line("let syntax = Syntax::Typescript(TsConfig {");
self.indent += 1;
self.emit_line("tsx: true,");
self.emit_line("decorators: false,");
self.emit_line("..Default::default()");
self.indent -= 1;
self.emit_line("});");
self.emit_line("let mut parser = Parser::new(syntax, StringInput::from(&*file), None);");
self.emit_line("parser.parse_program()");
self.indent += 1;
self.emit_line(".map_err(|e| format!(\"Parse error: {:?}\", e))");
self.indent -= 1;
self.indent -= 1;
self.emit_line("}");
self.emit_line("");
self.emit_line("pub fn parse_with_syntax(code: &str, syntax_type: &str) -> Result<Program, String> {");
self.indent += 1;
self.emit_line("let source_map = Arc::new(SourceMap::default());");
self.emit_line("let file = source_map.new_source_file(");
self.indent += 1;
self.emit_line("FileName::Anon,");
self.emit_line("code.to_string(),");
self.indent -= 1;
self.emit_line(");");
self.emit_line("let syntax = match syntax_type {");
self.indent += 1;
self.emit_line("\"TypeScript\" => Syntax::Typescript(TsConfig {");
self.indent += 1;
self.emit_line("tsx: true,");
self.emit_line("decorators: false,");
self.emit_line("..Default::default()");
self.indent -= 1;
self.emit_line("}),");
self.emit_line("\"JSX\" => Syntax::Es(EsConfig {");
self.indent += 1;
self.emit_line("jsx: true,");
self.emit_line("..Default::default()");
self.indent -= 1;
self.emit_line("}),");
self.emit_line("_ => Syntax::Es(EsConfig::default()),");
self.indent -= 1;
self.emit_line("};");
self.emit_line("let mut parser = Parser::new(syntax, StringInput::from(&*file), None);");
self.emit_line("parser.parse_program()");
self.indent += 1;
self.emit_line(".map_err(|e| format!(\"Parse error: {:?}\", e))");
self.indent -= 1;
self.indent -= 1;
self.emit_line("}");
self.indent -= 1;
self.emit_line("}");
}
pub(super) fn gen_codegen_module_helpers(&mut self) {
self.emit_line("fn codegen_to_string<N: swc_ecma_visit::Node>(node: &N) -> String {");
self.indent += 1;
self.emit_line("let mut buf = vec![];");
self.emit_line("{");
self.indent += 1;
self.emit_line("let cm = Arc::new(SourceMap::default());");
self.emit_line("let mut emitter = Emitter {");
self.indent += 1;
self.emit_line("cfg: CodegenConfig::default(),");
self.emit_line("cm: cm.clone(),");
self.emit_line("comments: None,");
self.emit_line("wr: Box::new(JsWriter::new(cm.clone(), \"\\n\", &mut buf, None)),");
self.indent -= 1;
self.emit_line("};");
self.emit_line("node.emit_with(&mut emitter).unwrap();");
self.indent -= 1;
self.emit_line("}");
self.emit_line("String::from_utf8(buf).unwrap()");
self.indent -= 1;
self.emit_line("}");
self.emit_line("");
self.emit_line("fn codegen_to_string_with_config<N: swc_ecma_visit::Node>(node: &N, cfg: CodegenConfig) -> String {");
self.indent += 1;
self.emit_line("let mut buf = vec![];");
self.emit_line("{");
self.indent += 1;
self.emit_line("let cm = Arc::new(SourceMap::default());");
self.emit_line("let mut emitter = Emitter {");
self.indent += 1;
self.emit_line("cfg,");
self.emit_line("cm: cm.clone(),");
self.emit_line("comments: None,");
self.emit_line("wr: Box::new(JsWriter::new(cm.clone(), \"\\n\", &mut buf, None)),");
self.indent -= 1;
self.emit_line("};");
self.emit_line("node.emit_with(&mut emitter).unwrap();");
self.indent -= 1;
self.emit_line("}");
self.emit_line("String::from_utf8(buf).unwrap()");
self.indent -= 1;
self.emit_line("}");
}
}