Ask questionsUsing swc for embedded-js parsing
Hello: I'm trying to build a parser for embedded JS, where the JS code exists within some other text. Currently, I'm using it as suggested in the source code:
let cm = Arc::new(SourceMap::new(FilePathMapping::empty()));
let fm = cm.new_source_file(
FileName::Custom(fname),
source,
);
However, I am unable to get the error reporting, and the generated source map to reflect the actual lines where the source is. Is there a way to get that done? If this functionality is not available, I would be willing to help with adding this functionality.
PS: Kudos on the elegant design of the parser; especially appreciate the Fold trait.
Answer
questions
rmanoka
@kdy1 I checked out TRACK_DIAGNOSTICS; unfortunately, it does not seem to solve my issue. In the crate, it is only called during emit_db which means it will anyway print the error messages (with incorrect line numbers when used with embedded-js use case described above).
One hack that works is to take the DiagnosticBuilder returned by the parser in case of error; then manually modify each of the primary_spans. Here is a snippet to do so:
let cm = Arc::new(SourceMap::new(FilePathMapping::empty()));
let handler = Handler::with_tty_emitter(ColorConfig::Auto, true, false, Some(cm.clone()));
let session = Session { handler: &handler };
// The real file (with embedded js code)
let true_fm = cm.new_source_file(
FileName::Custom("true.js".into()),
"Some other text\nfunction foo {}".into(),
);
// The byte offset where js code begins (provided by outer parser)
let byte_offset = BytePos(16);
// The js source
let fm = cm.new_source_file(
FileName::Custom("test.js".into()),
"function foo {}".into(),
);
let mut parser = Parser::new(
session,
Syntax::Es(Default::default()),
SourceFileInput::from(&*fm),
None, // Disable comments
);
let module = parser
.parse_module()
.map_err(|mut e| {
let m_span = &e.span;
let mut out_spans = vec![];
for span in m_span.primary_spans() {
let data = span.data();
let mut lo = data.lo;
let mut hi = data.hi;
lo = lo - fm.start_pos + true_fm.start_pos + byt
hi = hi - fm.start_pos + true_fm.start_pos + byt
let new_span = Span::new(lo, hi, data.ctxt);
out_spans.push(new_span);
}
e.set_span(out_spans);
e.emit();
()
})
.expect("failed to parse module");
With this code, it gives me the nice error messages that the crate already produces, but with correct line numbers:
error: Expected LParen, got Some(LBrace)
--> <true.js>:2:14
|
2 | function foo {}
| ^
Regarding your reply above:
Yes, but I prefer returning
Vec<Error>.
The current error messages printed by the crate are quite informative, and neat; some way to still print these even with Vec<Error> would be great.
Also, all this still doesn't help with the output source-map that is generated. That would also have to be transformed manually (waiting on #349 to try this). Overall, I am okay with this for an interim solution. Pls. feel free to close this issue if you would like to.