Skip to content

Implement transform classes #892

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

Merged
merged 11 commits into from
Oct 16, 2019
Merged

Implement transform classes #892

merged 11 commits into from
Oct 16, 2019

Conversation

dcodeIO
Copy link
Member

@dcodeIO dcodeIO commented Oct 10, 2019

This PR explores an alternative to #866. This is backwards-compatible to transform modules but now also supports classes that are populated with additional utility. On top of that this utilizes ts-node to run transforms written in TS without the need to build them.

@dcodeIO
Copy link
Member Author

dcodeIO commented Oct 10, 2019

This now supports transforms written in TS without the need to build them. Haven't tested in detail, but the example works.

@willemneal
Copy link
Contributor

The reason for building the typescript file was to bundle the transformer. This way you only need to provide one file. Also in situations like the browser it means a required ts-node/typescript dependency.

@MaxGraey
Copy link
Member

For browser you should write on pure JS or transpile to JS from TS offline as usual. Current solution support ts-node optionally.

@MaxGraey
Copy link
Member

typescript allow output to single bundle since 1.8. You don't need webpack for this.

@willemneal
Copy link
Contributor

Ah cool! But still my point is that you if want to develop offline you need the proper types and that's been the headache for me.

@dcodeIO
Copy link
Member Author

dcodeIO commented Oct 11, 2019

Last time I checked outFile had some restrictions that prevented using it with modules. What I'd usually do to bundle a transform is to declare assemblyscript as an external dependency that doesn't become bundled along the module. This way one can have bundles of assemblyscript and the transform that work together without duplicating any code.

Not sure about the types issue you are describing, but if you for example need SourceKind from the AssemblyScript package (as in the example), that'd have to be an import anyway which naturally also provides all the types.

@willemneal
Copy link
Contributor

Okay thanks for the info. I was able to get everything to work with webpack, but tsc is still mad that there are two definitions for primitives, one in portable/index.d.ts and the other in assemblyscript.d.ts. Is there any situation when you would not want to types from portable since we aim to use the assemblyscript type definitions eventually?

@dcodeIO
Copy link
Member Author

dcodeIO commented Oct 11, 2019

I think the portable definitions shouldn't be included there since transforms are TS, not portable AS. Does this come from your tsconfig? If so, try to make it a normal TS project.

@willemneal
Copy link
Contributor

I did, but assemblyscript.d.ts uses definitions from portable. Also the idea in my mind is that these transformers would end up in assemblyscript at some point too so that is why I used the portable definitions.

@dcodeIO
Copy link
Member Author

dcodeIO commented Oct 12, 2019

So I guess ideally we'd inline these in the .d.ts, essentially replacing their occurrences with number etc. directly (or make them otherwise private to the .d.ts (does removing declare there do this?)) - or are there other conflicting definitions?

@willemneal
Copy link
Contributor

If we can always expect that there will be global definitions for the primitives, why can't we just remove it? Wouldn't you always want to have portable or assembly types in your types path?

@dcodeIO
Copy link
Member Author

dcodeIO commented Oct 12, 2019

Wouldn't you always want to have portable or assembly types in your types path?

Not necessarily. There are the following cases to consider:

  1. Transform in JS (no definitions)
  2. Transform in TS (assemblyscript.d.ts)
  3. Transform in portable AS (assemblyscript.d.ts and portable.d.ts)
  4. Transform in AS (assemblyscript.d.ts and assembly.d.ts)

with 3. and 4. being problematic apparently. However, 2. is a valid case as well in which case the .d.ts currently needs the aliases because the compiler itself is portable AS. Hence my suggestion to do a pass over assemblyscript.d.ts replacing all the basic types with their actual alias.

@dcodeIO
Copy link
Member Author

dcodeIO commented Oct 12, 2019

Last commit does that now, that is replace all occurrences of i32, f64 and whatnot with the respective JS types so we don't need the global type declarations anymore. If you'd like to try it out, make sure to run node scripts/build-dts to update.

@willemneal
Copy link
Contributor

Cool that works on my end. Thanks!

@dcodeIO dcodeIO changed the title Transform classes experiment Implement transform classes Oct 14, 2019
@dcodeIO dcodeIO marked this pull request as ready for review October 14, 2019 17:30
@dcodeIO
Copy link
Member Author

dcodeIO commented Oct 14, 2019

Great, let me know if there's something else necessary here, or if it's good to merge.

@dcodeIO dcodeIO mentioned this pull request Oct 14, 2019
@willemneal
Copy link
Contributor

My one last suggestion is to add a postCompile function that passes the binaryen module. This way a custom section could be added or more specific validation can be done, for example testing for floating point numbers.

@dcodeIO
Copy link
Member Author

dcodeIO commented Oct 15, 2019

Alright, added an afterCompile hook that is being called with the Module instance. The examples show how to wrap it in a binaryen.js module. Process continues after modification by verifying the module before emitting it according to compiler options.

It's important to use the exact Binaryen dependency used by asc for this because wrapping like this requires that all the data is in Binaryen's memory already.

@willemneal
Copy link
Contributor

Thanks! Why must the module be rewrapped? I thought that the one passed was already wrapped by the compiler's module class.

@dcodeIO
Copy link
Member Author

dcodeIO commented Oct 15, 2019

It is not ultimately necessary to do that, but I'd imagine that the binaryen.js API is more friendly to consume than the internal C-API wrapper. If the internal API is good enough, one can ofc use that instead. Just note that extending the internal Module class is limited to portable AS and not every feature that might be possible is necessary to include in the compiler. For instance, if a consumer of the internal API finds that they need feature X, but we don't want that to bloat the compiler code, the respective PR might become rejected.

@willemneal
Copy link
Contributor

Ah cool well then it LGTM!

@willemneal
Copy link
Contributor

Oh one last thing, can there be a try catch surrounding the each call to the transform class?

@MaxGraey
Copy link
Member

I guess better if try/catch will be inside afterParse / afterCompile and determine by user. This also make possible catch errors and decide how this handle.

@willemneal
Copy link
Contributor

Yeah but since the current style is to call the callback with the error, it would be good if the transforms can use the callback to check if their error occurred.

@MaxGraey
Copy link
Member

MaxGraey commented Oct 15, 2019

May be better have a possibility interrupt next process and gracefully shutdown compiler like:

class MyTransform extends Transform {
  afterParse(parser: Parser): boolean {
     try {
        ....
        return true // ok
     } catch (e) {
        // handle error
       return false // interrupt and skip next transforms
    }
  }
...
function applyTransform(name, ...args) {
    var result = transforms.every(transform => {
      if (typeof transform[name] === "function") {
         return transform[name](...args));
      }
      return true;
    });
    if (!result) throw new Error(...); // or pass this to return or better shutdown compiler
  }
...

@dcodeIO
Copy link
Member Author

dcodeIO commented Oct 16, 2019

What this now does it to abort compilation on the first transform throwing, and propagates the error to the callback function. In case of the default callback, the exit code will be 1. That sufficient?

@dcodeIO
Copy link
Member Author

dcodeIO commented Oct 16, 2019

Merging so we can generate an updated assemblyscript.d.ts along with the recent Binaryen update. If there's anything else, you know what to do :)

@dcodeIO dcodeIO merged commit 576c295 into master Oct 16, 2019
@willemneal
Copy link
Contributor

Thanks!

@dcodeIO dcodeIO deleted the transform-class branch November 8, 2019 01:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants