-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Sourcemap for JS #7508
Sourcemap for JS #7508
Conversation
I also have locally working tracebacks to Nim source based on those sourcemaps based on their lib, but one can also write a handler that depends only on line directives |
Now, also with support for generation of name nodes so one can hover on variables. I use tokenization of js lines which seems very hacky, but it seems to work for a big file of mine (it seems ok enough for an initial impl, if you can think of a more elegant way which is very probable, please advise me) |
thanks to @treeform for the naming idea, I didn't even realize this is supported by sourcemaps: actually it seems he had the first sourcemaps implementation, but without a PR |
Rebase please. |
Ok, rebased. The postprocess raw js output approach seems complicated , but still simpler than the alternative seems to be big refactoring of jsgen itself(this might be a good idea?) |
compiler/sourcemap.nim
Outdated
type | ||
TokenState = enum Normal, String, Ident, Mangled | ||
|
||
proc tokenize*(line: string): seq[(bool, string)] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know it says "optimize me" but this tokenizer is really easy enough to make lazy. The compiler's lexer module shows how a lexer can be written.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
turned to iterator?
@@ -211,6 +211,8 @@ proc mapType(p: PProc; typ: PType): TJSTypeKind = | |||
if p.target == targetPHP: result = etyObject | |||
else: result = mapType(typ) | |||
|
|||
var mangled = initSet[string]() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sure you find some Context object where this can be put into. Globals make the compiler hard to use as a library.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: i think i can remove that
Certainly, but it's also more work. Your decision. |
8b9ab2a
to
73073d5
Compare
Just rebasing for now, it still needs to be at least optimized |
Ok, @Araq if you don't have objections, I am going to eventually start a refactoring next week like Why including the ES6 modules support? it seems to me that it would be easier to add when we are refactoring the whole backend anyway, but I can try to somehow split it in two PR-s as well AST ->
normal , default mode:
one JS code tree (one module)
es6 modules mode ( `-d:esmodules`):
JS code tree for each module
JS code tree -> [Sourcemap?] -> Raw code |
Fine with me but it will be an interesting discussion of whether to use the existing AST as the "JS code tree" or use a different one. I've spent years on this question and I'm slightly in favour of "use the existing AST" but it is your choice. |
Well honestly I think we don't even need a JS code tree: a list of JS tokens with good enough Nim source location info should be sufficient for generating the sourcemaps. The important thing is just to have this tokens instead of generating text and lex it again which is the hacky part. |
Are there any other benefits from AST->AST here |
Every other transformation is also AST->AST, we have good debugging helpers for these and you can for example run a general optimization pass after "JS code generation", seems it can be useful one day. |
Well, rendering is T -> string, so making codegen AST -> Tokens and rendering Tokens -> string is also sensible. JS AST can be a more powerful abstraction, but this will be an almost complete rewrite of jsgen, compared to splitting generated text into generated tokens in the current jsgen e.g.
Reusing PNode-s might seem easier(but resulting in similar code). However what do we do for js constructs which have no equivalent in PNode-s? |
Well these need to enumerated first, but I always thought of a |
Ok, this might work. verbatim nodes are usually useful I mostly feel like PNode construction is very verbose, something like breeze, but maybe even simpler, based on just autogenerated template shortcuts seem much cleaner to me compared to the newTree/new combo
but probably the con is that it's easier to clash with local variables ? |
The tree construction procs grew into existance without much design and it shows. |
Ok, so the initial AST -> JS code tree -> [Sourcemap?] -> javascript design remains, but with JS code tree based on PNod, I'll push a WIP early to make sure we're on the same track.
So should I add my own set of helpers here, or should I follow the style in the compiler |
@alehander42 I personally prefer the nkAsgn.t(ident"a", nnkIndex.t(ident"b", nnkInfix.t(ident"+", ident"e"))) |
Your own helpers, if they help. |
@krux02 yeah, the
This way you know that the node kinds have a shorter template and that it works in exactly the same way. |
@alehander42 that seems to be a good local solution. But currently I don't think it should go into macros, too many exported function symbols. |
agreed |
@Araq the verbatim node is useful, but it's actually not sufficient: e.g. we generate a ternary if, we need the final repr of the child, but it's still a PNode. One possible hack might be to reuse one TNodeKind for the "JS-only" constructs and additional field/magic string inside which would be a hint to the renderer. (probably I can just use if/else for ternary cond, but the point stays for other JS-only constructs) |
I think this means the JS-AST should get its own type. |
What is stopping this? We all need this. |
@treeform i need to finish the rewrite : i wrote some of the gen -> JavaScript AST part and some of the rendering JavaScript AST part but its a lot of manual work and i just have it in a branch somewhere I am not convinced we need that for sourcemaps: i feel that we can get them even with simpler generation(even with my first patch which just postprocesses source): Javascript AST sounds good but i am not sure if the team wants to maintain and actually write custom passes for it, maybe it's not beneficial enought after all |
Sourcemaps could basically work with some bugs in electron based on analyzing and lexing the raw output of jsgen, I can try to return to this version |
Friendly ping @alehander92. Can we get back to the commit 73073d5 I changed my mind and AST to AST codegen isn't required. The mentioned commit was good enough. |
ok, i'll take a look at it later! |
66bf593
to
997a700
Compare
so:
|
=> see test case here timotheecour#110 |
ah good notes @timotheecour will take a look maybe next week, sorry! |
I am adding support for sourcemaps.
You can pass
--sourceMap:on
and that implies--lineDir:on
.I've fixed some of the linedir for js and I removed some generated comments from
system/jssys.nim
)I am basically adding a new pass that works on the generated source and builds source nodes based on the line directives: that seems to be correct (as jsgen doesn't generate other comments, so if one hasn't emitted // line , it should be ok, and you can emit
#line
in C too).I'll add some tests: for now it seems to work for some files in my project, but I haven't dogfooded it too much. The implementation is based on mozilla's source-map lib