tunnelvisionlabs / antlr4ts

Optimized TypeScript target for ANTLR 4
Other
628 stars 107 forks source link

TypeError: Class constructor Lexer cannot be invoked without 'new' #326

Open fdeitelhoff opened 7 years ago

fdeitelhoff commented 7 years ago

I'm having trouble setting up the TypeScript target for ANTLR4 in my NodeJS + Angular environment.

The automatic generation from my grammars are working fine, but the following problem occurred in my code:

ERROR TypeError: Class constructor Lexer cannot be invoked without 'new'
    at new SimplexLexer (SimplexLexer.ts:111)
    at AppComponent.webpackJsonp.../../../../../src/app/app.component.ts.AppComponent.handler (app.component.ts:23)
    at Object.eval [as handleEvent] (AppComponent.html:1)
    at handleEvent (core.es5.js:12047)
    at callWithDebugContext (core.es5.js:13506)
    at Object.debugHandleEvent [as handleEvent] (core.es5.js:13094)
    at dispatchEvent (core.es5.js:8659)
    at core.es5.js:9270
    at HTMLButtonElement.<anonymous> (platform-browser.es5.js:2668)
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:424)

At this time I'm doing just this:

import { ANTLRInputStream, CommonTokenStream } from 'antlr4ts';
import { SimplexLexer } from './../simplex/grammar/SimplexLexer';
import { SimplexParser } from './../simplex/grammar/SimplexParser';

const inputStream = new ANTLRInputStream('text');
const simplexLexer = new SimplexLexer(inputStream);

I've tried various ways of generating code from my grammar files. The current solution looks like this:

"antlr4ts": "cd src/simplex/grammar/ && antlr4ts -listener -lib . SimplexParser.g4 SimplexLexer.g4"

Is there a fix or something? I think I will switch to the JavaScript target in the meantime because I think it is working.

Edit: Ok, I have to revert the statement that the JavaScript target works. Looks like I run into some problems within my TypeScript environment and the generated JavaScript target. :(

fdeitelhoff commented 7 years ago

Another update:

I changed the target to "ES6" and the errors are gone.

But there are new ones. :) For example "SimplexContext is not defined". (Simplex is my grammar). I found out that if I move the complete SimplexParser from the SimplexParser.ts at the bottom of the generated file, everything works fine. TypeScript is much more restrictive on the order of types within a file (my guess).

Is this a problem on my side or do we have to modify the TypeScript generation process?

BurtHarris commented 7 years ago

Thanks for reporting this Fabian. So far we've only been testing with an ES6 target: specifically Node.JS is the only environment tested to date. Are you trying to build for browser execution? That's on our future goals list.

I've just come back from a vacation, and will have more time to look this over shortly, particularly the second problem you've reported, which sound strange. If you could share a source-code snapshot I could reproduce this with, I'll have a look, probably today.

BurtHarris commented 7 years ago

@fdeitelhoff, I've not been able to reproduce the SimplexContext is not defined message, but guess you may be having problems with the tsc options. Here's a minimal tsconfig.json that should work:

{
  "compilerOptions": {
    "target": "es2015",                 /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
    "module": "commonjs",               /* Specify module code generation: 'commonjs', 'amd', 'system', 'umd' or 'es2015'. */
    "lib": ["es2015"],                  /* Specify library files to be included in the compilation:  */
    "sourceMap": true,                  /* Generates corresponding '.map' file. */
    "strict": true,                     /* Enable all strict type-checking options. */
    "experimentalDecorators": true      /* Enables experimental support for ES7 decorators. */
  }
}
fdeitelhoff commented 7 years ago

@BurtHarris Thanks for the info. This is my configuration at the moment:

{
  "compileOnSave": false,
  "compilerOptions": {
    "outDir": "./dist/out-tsc",
    "baseUrl": "src",
    "sourceMap": true,
    "declaration": false,
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es6",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2016",
      "dom"
    ]
  }
}

Not quite sure if the es6 and es2016 are actually good to solve my previous error message or if this can cause other problems.

Update: I still get the SimplexContext is not defined error with all targets pointing to es2015.

BurtHarris commented 7 years ago

@fdeitelhoff, Can you please share a repository that demonstrates the SimplexContext is not defined message?

P.S. I've just discovered some incompatibilities with TypeScript@2.4.1, not sure if that's involved.

fdeitelhoff commented 7 years ago

@BurtHarris You can use my "real" test repository: https://github.com/fdeitelhoff/Simplex-Game-Web

A clone and npm install should do the magic. There's a npm script that creates the grammar.

I'm currently on a conference and don't have the time & space to provide a special repository. But maybe you can reproduce the error with the "real" test repository.

Thank you for your help so far! Very appreciated.

BurtHarris commented 7 years ago

@fdeitelhoff Thanks, I've started looking (and learning.) No special repo needed, I'm interested in what you are doing.

For me, npm install generated no errors. I also tried npm run build and npm start both of which looks successful as well. Chrome against localhost:4200 seems to give a functional editor.

I dropped a try.ts into src with the following content, still no errors:

import { ANTLRInputStream, CommonTokenStream } from 'antlr4ts';
import { SimplexLexer } from './simplex/gen/SimplexLexer';
import { SimplexParser } from './simplex/gen/SimplexParser';

const inputStream = new ANTLRInputStream('text');
const simplexLexer = new SimplexLexer(inputStream);

Still no error. How do I reproduce the "SimplexContext is not defined" message?

fdeitelhoff commented 7 years ago

@BurtHarris Oh sorry. I manually corrected the generated Simplex ANTLR4 code that's already in the repository.

Try this command to generate a new set of files: npm run antlr4ts

In the generated files there's the error.

BurtHarris commented 7 years ago

@fdeitelhoff . My mistake on the tsconfig issue.

I've opened #329 - Update codgen templates to supporess TSLint warnings to suppress the TSLint errors in our generated code that your example points up. I've Temporarily suppressed them using // tslint:disable, but I've still not seen that SimplexContext is not defined message.

In Visual Studio Code's "Output" window for "tslint", I see this warning. Could you be mistaking a lint error for a compiler error? I've not found TypeScript to require declaration before use!

[Info  - 8:19:38 AM] Linter is running.
Warning: The 'no-use-before-declare' rule requires type checking

P.S. In Visual Studio Code's "Problems" windows, after running npm build, I am now seeing 251 errors in \dist\assets\monaco-editor\Monaco.d.ts, starting with:

file: 'file:///c%3A/code/Simplex-Game-Web/dist/assets/monaco-editor/monaco.d.ts'
severity: 'Error'
message: 'Duplicate identifier 'Emitter'.'
at: '30,18'
source: 'ts'

P.S: I left you a private message on https://gitter.im

fdeitelhoff commented 7 years ago

@BurtHarris Okay, weird. If I'm generating the new files with npm run antlr4ts and starting the application with npm run I got the error. But I got it within the browser, not within VS Code or somewhere else!

simplex-error

BurtHarris commented 7 years ago

Hmm, I don't know much about webpack, it's on my reading list... Could this have something to do with that?

fdeitelhoff commented 7 years ago

@BurtHarris Sorry, late reply. I'm not into webpack that much, too. It is possible that the packing is the source of the problem. But hard to say in the current scenario.

But I assume that you've reproduced the error? Just to conform that I'm not stupid. :)

BurtHarris commented 7 years ago

Frankly I don't remember if I've reproduced the error right now, but I'll take a look again.

fdeitelhoff commented 7 years ago

@BurtHarris No problem. Don't worry and don't hurry. :)

My language is 99% fixed so there's no real need to generate it over and over again. Therefore the manual fix is fine for me.

But we should investigate in more detail if we might think this could be a general problem.

BurtHarris commented 7 years ago

Update: the original problem, message saying TypeError: Class constructor Lexer cannot be invoked without 'new' is caused by a mismatch between the code generation target we used for building the antlr4ts runtime (which was es2015) and occurs when its called from code transpiled using the default target (which is es5).

JavaScript native class support is used when the target is es2015, and those native classes can't be extended using the code TypeScript generates when target is es5!

marjan-georgiev commented 6 years ago

@BurtHarris is there any way to fix the Class constructor Lexer cannot be invoked without 'new' without changing the target to es2015? We are using angular 4.x, and it is currently not supporting es2015 as a build target. (https://github.com/angular/angular/issues/15127)

I would be open to manually changing the generated antlr files if that would help.

BurtHarris commented 6 years ago

@marjan-georgiev, frankly I don't know.

Supporting multiple targets in a complex TypeScript package like this seems like something there should be best practices on, but as of now I'm not sure what they are. I think it's tied into supporting browser-based execution, and I've simply not done browser coding for ten years or more. If you're an Angular user, you may have a better idea on how to do this than I do, can you point to any articles explaining how to do so?

pluthraarkin commented 6 years ago

Are there any updates on es5 support for antlr4ts? We also need it for our project.

BurtHarris commented 6 years ago

Sorry, I think both Sam and I have been busy with other matters. We could really use at least one more developer who has skills and interest to contribute some to the project. ES5 support I think is within reach, but I've got very little browser experience and that seems to be where it's really needed.

sjkillen commented 5 years ago

I also get this error and my tsconfig.json target is "esnext". I've tracked the error down to something from babel.js, which in my setup runs after typescript in webpack.json. Babel seems to be performing the super call to Lexer incorrectly. For now, I fixed the error by removing all babel plugins that affect classes (for me this was just the "env" preset)

v3rb0s3 commented 5 years ago

I'm encountering this issue as well. I'm using the most basic setup imaginable, with nothing installed but node.js (12.2.0), typescript (3.3.1), and antlr4ts (0.5.0-alpha.3), and a minimalistic grammar. I don't specifically care about the target, and have tried various ones (es5, es6, es2015, es2018) without success. Does anybody have a hint what I need to do to make this work?

sarod commented 5 years ago

I'm using babel with preset-typescript and I have the same " Class constructor Lexer cannot be invoked without 'new'" error

sharwell commented 5 years ago

@v3rb0s3 Can you provide an example project to reproduce this?

sdiguana commented 5 years ago

I've just spent the last several evenings on the same issue (" Class constructor Lexer cannot be invoked without 'new'" error). As @Spensaur-K mentioned, babel is breaking the super() call for the lexer.

I've changed the following things to finally get it resolved:

  1. tsconfig.json for my parser was set to target: es2015, module: es2015
  2. babel presets were altered as follows: browsers: [">0.5%", "not ie 11", "not op_mini all", "not samsung 4" ]

Item 1 may not be required, e.g. leaving commonjs as the module type (antlr4ts still is commonjs, hence why i think my modules being changed isn't the real solution). Item 2 i think is because babel is going too far back in time, something is getting garbled in the transpiling. the browsers list was to ensure all supported arrows so they wouldn't get downgraded to functions. i figured if arrows are supported, whatever else needed to be is too.

for reference my project is browser facing. If i run unit tests in mocha, i have to set modules to commonjs. then back to es2015 for the web project.

BurtHarris commented 5 years ago

@sdiguana, that sounds big. Can you share a repro where you have it working in a browser based context. I would like to understand in more detail what you accomplished. We can certainly have typescript generate both the commonjs and es2015 module formats into separate directories by having two different tsconfig.json files.

sdiguana commented 5 years ago

@BurtHarris Let me know if this is enough information: I have two projects, one is the antlr based calculator, the second is a Nuxt.js based website. I build the calculator and then drop the es6 module js files into the browser's project at the moment. There is a dependency on antlr4ts for the browser project.

ANTLR Calculator project: Use Module: CommonJS for testing with mocha Use Module: ES2015 for sending to browser project

Calculator: https://github.com/sdiguana/XCalc

relevant web project details: XCalc.vue nuxt.config.js I pushed the existing calculator onto my site so you can play with it if you like.

a few notes: . the calculator was used to teach myself antlr and typescript... so it needs some work before its more than a toy . for the browser project, if the above isn't enough i can clean the API keys and pass it to you privately. . im still not certain that building my antlr project as es2015 is required. at present, if i don't, i get exports is not defined issues on the browser project. However antlr4ts is in commonjs, and the project understands it, hence why i think i just haven't spent enough time rooting around in my own settings to make it so i can build commonjs too. . as noted previously, i suspect that the babel settings i listed above solve the invalid super() call.

BurtHarris commented 5 years ago

I'll have a look, thanks.

crainsaw commented 4 years ago

In my case I was able to solve the issue by explicitly defining the tsconfig file for ts-jest in the jest config. In my case in the package.json:

{
  // [...]
  "jest": {
    "globals": {
      "ts-jest": {
        "tsConfig": "test/tsconfig.json"
      }
    }
  }
}

It seems that ts-jest ignored my tsconfig file in which I already had specified es2015 as a build target. My tsconfig for my tests test/tsconfig.json looks like that:

{
  "include": [
    "./**/*"
  ],
  "extends": "../tsconfig_base",
  "references": [
        { "path": "../antlr_ts_build/" },
        { "path": "../src/" }
  ],
  "compilerOptions": {
    // strictPropertyInitialization need to be disabled when using antlr4ts and variables (otherwise build will fail)
    "strictPropertyInitialization": false
  }
}

With tsconfig_base.json beeing in my root folder with the following options set:

"compilerOptions": {
    "target": "es2015",
    "module": "commonjs",
    "lib": ["ES2015"],
}

I hope it helps anybody.

albanx commented 2 years ago

if you use an old version of ts-jest, use this config (tsConfigFile):

{
  "jest": {
    "globals": {
      "ts-jest": {
        "tsConfigFile": "test/tsconfig.json"
      }
    }
  }
}

Make sure the test/tsconfig.json has the target set to es5. This worked for me.