求助!关于使用 oxc 来解析并修改 JS 代码时遇到的生命周期相关的问题

97 天前
 youxingzhi

我正在使用 oxc 来解析并修改 JS 代码。

const b = require('b.js')

如上所示,我想给模块名(b.js)加上一个前缀,这个前缀是动态的。

下面是我的代码,代码仓库见这里。现在的问题是 new_name 会在函数执行完后销毁,但是 Atom::from 声明了一个生命周期('a),所以编译器报错:new_name does not live long enough.

怎么解决这个问题呀?跪求大佬指点。

#![allow(clippy::print_stdout)]
use itertools::Itertools;
use oxc_allocator::Allocator;
use oxc_ast::ast::*;
use oxc_codegen::{CodeGenerator, CodegenOptions};
use oxc_parser::Parser;
use oxc_semantic::SemanticBuilder;
use oxc_span::SourceType;
use oxc_traverse::{traverse_mut, Traverse, TraverseCtx};
use std::ops::DerefMut;
use std::{env, path::Path, sync::Arc};

struct MyTransform {
    prefix: String,
}

impl<'a> Traverse<'a> for MyTransform {
    fn enter_call_expression(&mut self, node: &mut CallExpression<'a>, ctx: &mut TraverseCtx<'a>) {
        if node.is_require_call() {
            let argument: &mut Argument<'a> = &mut node.arguments.deref_mut()[0];
            match argument {
                Argument::StringLiteral(string_literal) => {
                    let old_name = string_literal.value.as_str();
                    let new_name = format!("{}{}", self.prefix, old_name);

                    // !!!!!! `new_name` does not live long enough
                    string_literal.value = Atom::from(new_name.as_str());
                }
                _ => {}
            }
        }
    }
}

fn main() -> std::io::Result<()> {
    let name = env::args().nth(1).unwrap_or_else(|| "test.js".to_string());
    let path = Path::new(&name);
    let source_text = Arc::new(std::fs::read_to_string(path)?);
    let source_type = SourceType::from_path(path).unwrap();

    // Memory arena where Semantic and Parser allocate objects
    let allocator = Allocator::default();

    // 1 Parse the source text into an AST
    let parser_ret = Parser::new(&allocator, &source_text, source_type).parse();
    if !parser_ret.errors.is_empty() {
        let error_message: String = parser_ret
            .errors
            .into_iter()
            .map(|error| format!("{:?}", error.with_source_code(Arc::clone(&source_text))))
            .join("\n");
        println!("Parsing failed:\n\n{error_message}",);
        return Ok(());
    }

    let mut program = parser_ret.program;

    // 2 Semantic Analyze
    let semantic = SemanticBuilder::new(&source_text)
        .build_module_record(path, &program)
        // Enable additional syntax checks not performed by the parser
        .with_check_syntax_error(true)
        .build(&program);

    if !semantic.errors.is_empty() {
        let error_message: String = semantic
            .errors
            .into_iter()
            .map(|error| format!("{:?}", error.with_source_code(Arc::clone(&source_text))))
            .join("\n");
        println!("Semantic analysis failed:\n\n{error_message}",);
    }
    let (symbols, scopes) = semantic.semantic.into_symbol_table_and_scope_tree();

    // 3 Transform
    let t = &mut MyTransform {
        prefix: "ayou".to_string(),
    };
    traverse_mut(t, &allocator, &mut program, symbols, scopes);

    // 4 Generate Code
    let new_code = CodeGenerator::new()
        .with_options(CodegenOptions {
            ..CodegenOptions::default()
        })
        .build(&program)
        .code;

    println!("{}", new_code);

    Ok(())
}
1082 次点击
所在节点    Rust
2 条回复
PTLin
97 天前
把出问题的代码改成 string_literal.value = Atom::from_in(new_name, &ctx.ast.allocator);
youxingzhi
97 天前
嗯,谢谢。这样也可以:string_literal.value = ctx.ast.atom(new_name.as_str());

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1083533

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX