Skip to content

Resolve structural issue with exception handling in IRFactory #967

@tuchida

Description

@tuchida

In the example below, one can see that the IRFactory throws a ParserException when in this case a SyntaxException ought to be thrown.

Further down comment #967 (comment) points to a fix that results in the proper Error being thrown, but proper location info is missing.

These issues ought to be fixed, possibly requiring the refactoring of the IRFactory as suggested below

#853 (comment)
If I evaluate 1=1, I will expect only JavaScript error, but Java exception will be thrown.

$ java -jar buildGradle/libs/rhino-1.7.14-SNAPSHOT.jar
Rhino 1.7.14-SNAPSHOT 2021 06 29
js> 1=1
js: line 1: Invalid assignment left-hand side.
js: 
js: ^
Exception in thread "main" org.mozilla.javascript.Parser$ParserException
	at org.mozilla.javascript.Parser.reportError(Parser.java:329)
	at org.mozilla.javascript.Parser.reportError(Parser.java:315)
	at org.mozilla.javascript.Parser.reportError(Parser.java:310)
	at org.mozilla.javascript.IRFactory.createAssignment(IRFactory.java:2309)
	at org.mozilla.javascript.IRFactory.transformAssignment(IRFactory.java:448)
	at org.mozilla.javascript.IRFactory.transform(IRFactory.java:222)
	at org.mozilla.javascript.IRFactory.transformExprStmt(IRFactory.java:559)
	at org.mozilla.javascript.IRFactory.transform(IRFactory.java:219)
	at org.mozilla.javascript.IRFactory.transformScript(IRFactory.java:1133)
	at org.mozilla.javascript.IRFactory.transform(IRFactory.java:201)
	at org.mozilla.javascript.IRFactory.transformTree(IRFactory.java:121)
	at org.mozilla.javascript.Context.parse(Context.java:2437)
	at org.mozilla.javascript.Context.compileImpl(Context.java:2354)
	at org.mozilla.javascript.Context.compileString(Context.java:1368)
	at org.mozilla.javascript.Context.compileString(Context.java:1356)
	at org.mozilla.javascript.tools.shell.Main.processSource(Main.java:495)
	at org.mozilla.javascript.tools.shell.Main.processFiles(Main.java:181)
	at org.mozilla.javascript.tools.shell.Main$IProxy.run(Main.java:101)
	at org.mozilla.javascript.Context.call(Context.java:534)
	at org.mozilla.javascript.ContextFactory.call(ContextFactory.java:472)
	at org.mozilla.javascript.tools.shell.Main.exec(Main.java:163)
	at org.mozilla.javascript.tools.shell.Main.main(Main.java:138)

Parser$ParserException is private class. There is something strange about this being thrown out of Parser.

There are probably two problems with this. (I'm sorry if I'm wrong.)

1. IRFactory inheritance of Parser

This makes it difficult to know where to catch the Parser$ParserException.
I felt that IRFactory inheritance of Parser was an anti-pattern of Code reuse via inheritance.

2. Reanalyzing the entire AST.

Rhino parser seems to work as follows.

  1. Parser make AST from source code.
  2. Within IRFactory, Decompiler reverts the all AST to source code.
  3. IRFactory and Parser will reanalyze the source code.

The syntax of ECMAScript is ambiguous and some things need to be reanalyzed.
https://262.ecma-international.org/12.0/#sec-syntactic-grammar

In certain cases, in order to avoid ambiguities, the syntactic grammar uses generalized productions that permit token sequences that do not form a valid ECMAScript Script or Module. For example, this technique is used for object literals and object destructuring patterns. In such cases a more restrictive supplemental grammar is provided that further restricts the acceptable token sequences. Typically, an early error rule will then define an error condition if "P is not covering an N", where P is a Parse Node (an instance of the generalized production) and N is a nonterminal from the supplemental grammar. Here, the sequence of tokens originally matched by P is parsed again using N as the goal symbol. (If N takes grammatical parameters, then they are set to the same values used when P was originally parsed.) An error occurs if the sequence of tokens cannot be parsed as a single instance of N, with no tokens left over. Subsequently, algorithms access the result of the parse using a phrase of the form "the N that is covered by P". This will always be a Parse Node (an instance of N, unique for a given P), since any parsing failure would have been detected by an early error rule.

However, it should only be necessary to reanalyze the grammar that write "cover".

P is not covering an N

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugIssues considered a bug

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions