use crate::parser::*;
use crate::mapping::{get_node_mapping, get_node_mapping_by_visitor};
use super::swc_decorator::{DecoratedProgram, DecoratedTopLevelDecl, DecoratedPlugin, DecoratedWriter, DecoratedPluginItem, DecoratedFnDecl};
use super::decorated_ast::{DecoratedPattern, DecoratedPatternKind, DecoratedExpr, DecoratedExprKind, DecoratedStmt, DecoratedIfStmt, DecoratedBlock};
mod emit;
mod detection;
mod type_mapping;
mod type_inference;
mod patterns;
mod expressions;
mod statements;
mod structures;
mod visitors;
mod top_level;
pub struct SwcGenerator {
output: String,
indent: usize,
param_renames: std::collections::HashMap<String, String>,
plugin_name: String,
hoisted_visitors: Vec<String>,
captured_vars: std::collections::HashSet<String>,
uses_json: bool,
uses_parser: bool,
uses_codegen: bool,
associated_functions: std::collections::HashSet<String>,
is_writer: bool,
#[allow(dead_code)]
type_env: crate::codegen::type_context::TypeEnvironment,
}
impl SwcGenerator {
pub fn new() -> Self {
Self {
output: String::new(),
indent: 0,
param_renames: std::collections::HashMap::new(),
plugin_name: String::new(),
hoisted_visitors: Vec::new(),
captured_vars: std::collections::HashSet::new(),
uses_json: false,
uses_parser: false,
uses_codegen: false,
associated_functions: std::collections::HashSet::new(),
is_writer: false,
type_env: crate::codegen::type_context::TypeEnvironment::new(),
}
}
pub fn generate(&mut self, program: &Program) -> String {
let (uses_hashmap, uses_hashset) = self.detect_std_collections(program);
for use_stmt in &program.uses {
if use_stmt.path == "json" {
self.uses_json = true;
}
if use_stmt.path == "parser" {
self.uses_parser = true;
}
if use_stmt.path == "codegen" {
self.uses_codegen = true;
}
}
self.emit_line("// Generated by ReluxScript compiler");
self.emit_line("// Do not edit manually");
self.emit_line("");
self.emit_line("use swc_common::{Span, DUMMY_SP, SyntaxContext};");
self.emit_line("use swc_ecma_ast::*;");
self.emit_line("use swc_ecma_visit::{VisitMut, VisitMutWith};");
if uses_hashmap && uses_hashset {
self.emit_line("use std::collections::{HashMap, HashSet};");
} else if uses_hashmap {
self.emit_line("use std::collections::HashMap;");
} else if uses_hashset {
self.emit_line("use std::collections::HashSet;");
}
for use_stmt in &program.uses {
if !use_stmt.path.starts_with("./") && !use_stmt.path.starts_with("../") {
match use_stmt.path.as_str() {
"fs" => {
self.emit_line("use std::fs;");
self.emit_line("use std::path::Path;");
}
"json" => {
self.emit_line("use serde::{Serialize, Deserialize};");
self.emit_line("use serde_json;");
}
"io" => {
self.emit_line("use std::io;");
self.emit_line("use std::io::{Read, Write};");
}
"parser" => {
self.emit_line("use swc_ecma_parser::{Parser, Syntax, TsConfig, StringInput};");
}
"codegen" => {
self.emit_line("use swc_ecma_codegen::{Emitter, text_writer::JsWriter};");
}
_ => {}
}
}
}
self.emit_line("");
match &program.decl {
TopLevelDecl::Plugin(plugin) => {
self.gen_plugin(plugin);
}
TopLevelDecl::Writer(writer) => {
self.gen_writer(writer);
}
TopLevelDecl::Module(module) => {
self.gen_module(module);
}
}
std::mem::take(&mut self.output)
}
pub fn generate_decorated(&mut self, program: &DecoratedProgram) -> String {
self.emit_line("// Generated by ReluxScript compiler (decorated AST)");
self.emit_line("// Do not edit manually");
self.emit_line("");
self.emit_line("use swc_common::{Span, DUMMY_SP, SyntaxContext};");
self.emit_line("use swc_ecma_ast::*;");
self.emit_line("use swc_ecma_visit::{VisitMut, VisitMutWith};");
self.emit_line("");
match &program.decl {
DecoratedTopLevelDecl::Plugin(plugin) => self.gen_decorated_plugin(plugin),
DecoratedTopLevelDecl::Writer(writer) => self.gen_decorated_writer(writer),
DecoratedTopLevelDecl::Undecorated(decl) => {
eprintln!("[WARNING] Falling back to undecorated codegen");
self.emit_line("// TODO: Undecorated top-level declaration");
}
}
std::mem::take(&mut self.output)
}
}