Skip to content
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

Suggestion: Allow customizing the code emitter. #2727

Closed
zpdDG4gta8XKpMCd opened this issue Apr 12, 2015 · 10 comments
Closed

Suggestion: Allow customizing the code emitter. #2727

zpdDG4gta8XKpMCd opened this issue Apr 12, 2015 · 10 comments
Labels
API Relates to the public API for TypeScript Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. Suggestion An idea for TypeScript

Comments

@zpdDG4gta8XKpMCd
Copy link

Since doing even simple inlining is out of scope of TypeScript, please allow extensions to the code emitter, so that there is a way to get JavaScript other than what is officially endorsed..

@mhegazy mhegazy added Suggestion An idea for TypeScript API Relates to the public API for TypeScript Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. labels Apr 12, 2015
@mhegazy
Copy link
Contributor

mhegazy commented Apr 12, 2015

We have got this request a lot lately. We need a design for extensiblity for the emitter.

@fdecampredon
Copy link

If we could also get parser extensibility, or at least ast transformation at the same time it could be cool :) ( see: https://github.com/benjamn/recast)

@zpdDG4gta8XKpMCd
Copy link
Author

I think at the very least the API needs to provide the following:

  • be able to introduce additional data required for running a custom transformation
  • override any transformation from the TS code model to JS code model (by providing JS AST as a result)
  • inside the transformation, to identify the current piece of the TS code model
  • inside the transformation, to identify a placeholder for the JS code model
  • inside the transformation, to query TS code mode relative to the current location (ancestors, siblings, children)
  • inside the transformation, to query the JS code model relative to the current location
  • inside the transformation, being able to query the additional data using the knowledge of the current location

@CyrusNajmabadi
Copy link
Contributor

Note that this sort of extensibility is quite difficult to provide. The Roslyn team looked into this and found it to be too difficult to provide in any form. The problems include (and must be addressed by any proposal), but are not limited to:

  1. How do you ensure the extension does not break invariants that the compiler expects? For example, will the extension do something that breaks incremental parsing. Will it break how the compiler expects symbols to be created/behave, etc. etc.
  2. How do you ensure that the extension does not break debugging scenarios?
  3. How do you ensure that the extension has all the necessary information and entry points it needs to function properly?
  4. How do you provide all those extension points without hurting perf for the mainline case where people are not using extensions?
  5. How do you deal with back compat? If we change how we do part of the compiler, can we even support that extensibility point anymore?

Looking at the JSX work, for example, we can see how difficult this would be. There would need to be some way for an extension to add new AST types and kinds. But that means that so much additonal code in the system would now need to become aware of these kinds. It needs to fix up the scanner, but that involves invasive work of specific scanner functions. It needs to go into very specific places in the parser to change how they work. It needs to go into the incremental parser to address the issues there. And we haven't even gotten to all the LS features that would likely need to be updated to handle JSX features properly.

Ideally, instead of asking for extensibility, one would come with a use case where they wanted to extend the compiler. They should then show how they'd like to do that in the form of an extension, rather than by manipulating the compiler/LS source directly. Then we could see about the viability of such an extensibility API and ensure that we had satisfactory answers to the above questions (and more).

@CyrusNajmabadi
Copy link
Contributor

This is a good example of where this gets difficult:

inside the transformation, to query the JS code model relative to the current location

Right now there is no JS code model (though i'd personally like one). So we'd need to provide some way to get a JS code model. Then we have the following design problem:

  1. Do we compile in the mainline case using that JS code model? If so, then that would be nice, as the compiler and extensions would be using the same system. But it may come with an unacceptable perf cost.
  2. Do we compile in the mainline case as we do today (without a code model), but expose a code model system for extensions? If we do, then we're effectively maintaining two entirely different sets of code. That's likely an unacceptable maintenance burden.

@Aleksey-Bykov I'm with Mohamed on this. We need a proposal for this feature. Ideally something that addresses all your bullet points, and all the points i listed in the previous post. If such a proposal can be made, and we can do things like measure the perf impact, then we can decide how to go forward. Thanks!

@zpdDG4gta8XKpMCd
Copy link
Author

As a least painful start all that needs to be done is to:

  1. Define and expose a public interface of the emitter.
  2. Have a way to get an instance of the original emitter.
  3. Be able to inject an object implementing the emitter interface (or a factory for such object) back to the compiler

In addition to what's above it would also be nice to:

  1. Add a command line option pointing to a javascript file that:
    • will be run in the nodejs execution context
    • has to export a single function that
      • gets an original emitter
      • returns a custom one which may or may not be based on the original.

@zpdDG4gta8XKpMCd
Copy link
Author

I wish I could pass these guys as parameters rather than having them hardcoded:
https://github.com/Microsoft/TypeScript/blob/bb4aa2c4897431048695f435e99e2410f92043c8/src/compiler/emitter.ts#L165-L172

            /** Emit a node */
            let emit = emitNodeWithoutSourceMap;

            /** Called just before starting emit of a node */
            let emitStart = function (node: Node) { };

            /** Called once the emit of the node is done */
            let emitEnd = function (node: Node) { };

Is there any chance you would allow customizing them?

@mhegazy
Copy link
Contributor

mhegazy commented Aug 10, 2015

@Aleksey-Bykov we are looking into changing how we emit to a more transformation based approach. no ETA at the moment. but when it happens it should allow for more flexibility in extending the emitter functionality.

@qballer
Copy link

qballer commented Dec 15, 2016

@mhegazy any news?

@mhegazy
Copy link
Contributor

mhegazy commented Feb 2, 2017

This is tracked by: #13765, #13764 and #13763. (#13761 is already in, and #13825 is in progress).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API Relates to the public API for TypeScript Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

6 participants