-
Bug
-
Resolution: Won't Fix
-
P4
-
None
-
9, 9.0.4, 10
-
generic
-
generic
FULL PRODUCT VERSION :
java version "10-ea" 2018-03-20
Java(TM) SE Runtime Environment 18.3 (build 10-ea+39)
Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10-ea+39, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.3.9600]
(c) 2013 Microsoft Corporation. All rights reserved.
A DESCRIPTION OF THE PROBLEM :
Classes mentioned here are specifically from the package jdk.nashorn.api.tree.
The Parser class allows for the creation of a fully initialized CompilationUnitTree based on a provided source script. The resulting hierarchical structure of Tree nodes represents the syntax tree of the provided source script
This classification of the syntactical components of a parsed script falls short between two design ideas. On one hand it's designed to provide access to individual grammatical components of the source script. On the other hand it conceptualizes the resulting compilation unit, which is the begin state of the script runtime before evaluation of the compiled script begins.
If the documentation of the classes involved in this design is to be the lead in determining what this api is designed for, the hierarchical structure of the tree is to represent specifically an Abstract Syntax Tree(AST). This means the tree result of the parsing stage is specifically to represent the code as-is and conforming to the syntactical grammar defined in the ECMA spec. This would be a depature from the idea that this tree structure could represent a Concrete Syntax Tree, which chronologically exists after the compilation stage.
I've included within the source code a list of issues for the case of purely following the design of an AST, ranging from bugs to design flaws. By no means is this complete, but it should pave the way for a solid start.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the provided source script.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The following output:
1;
"2";
"2"
true
true
(({}));
(({}))
class D{}
getClassTail
getName
true
true
false
extends E
false
extends F
false
extends (G)
false
extends (H)
2
2
false
false
false
false
false
false
true
true
ACTUAL -
1
2
2
false
false
(({}))
{}
class D
getClassElements
getClassHeritage
getConstructor
getName
false
false
true
E
true
F
true
G
true
H
1
1
true
true
true
true
true
true
false
false
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import jdk.nashorn.api.tree.*;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Random;
public class Main {
public static void main(String[] args) {
Parser p = jdk.nashorn.api.tree.Parser.create("--language=es6");//ECMA-262 6.0
String code;
CompilationUnitTree compilationTree;
Tree tree;
/**
* Expression Statement (13.5): missing semicolon between start-end positions
*/
code = "1;";
compilationTree = p.parse("1.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ExpressionStatementTree(Impl)
System.out.println(code.substring((int)tree.getStartPosition(),(int)tree.getEndPosition()));
//expected: the following string value
//1;
//actual: the following string value
//1
/**
* String Literals (11.8.4): missing surrounding quotes between start-end positions
*/
code = "\"2\";";
compilationTree = p.parse("2.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ExpressionStatementTree(Impl)
System.out.println(code.substring((int)tree.getStartPosition(),(int)tree.getEndPosition()));
//expected: the following string value
//"2";
//actual: the following string value
//2
tree = ((ExpressionStatementTree) tree).getExpression();//Actual type: LiteralTree(Impl)
System.out.println(code.substring((int)tree.getStartPosition(),(int)tree.getEndPosition()));
//expected: the following string value
//"2"
//actual: the following string value
//2
/**
* Function Definitions (14.1): function body incorrectly includes the first curly brace between start-end positions
*/
code = "function c(){};";
compilationTree = p.parse("3.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: FunctionDeclarationTree(Impl)
tree = ((FunctionDeclarationTree)tree).getBody();
System.out.println("".equals(code.substring((int)tree.getStartPosition(),(int)tree.getEndPosition())));
//expected: empty string value
//actual: the following string value
//{
/**
* Function Calls (12.3.4): getter for Arguments returns not a Tree implementation that is an encapsulating node for the arguments
*/
code = "Object();";
compilationTree = p.parse("4.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ExpressionStatementTree(Impl)
tree = ((ExpressionStatementTree)tree).getExpression();//Actual type: FunctionCallTree(Impl)
System.out.println(Tree.class.isAssignableFrom(((FunctionCallTree)tree).getArguments().getClass()));
//expected: an instance of an implementation of Tree
//actual: a java.util.Arraylist instance representing the Arguments
/**
* Primary Expression (12.2): no nodes present in the tree structure to represent instances of a ParenthesizedExpression
*/
code = "(({}));";
compilationTree = p.parse("5.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ExpressionStatementTree(Impl)
System.out.println(code.substring((int)tree.getStartPosition(),(int)tree.getEndPosition()));
//expected: the following string value
//(({}));
//actual: the following string value
//(({}))
tree = ((ExpressionStatementTree)tree).getExpression();//Actual type: ObjectLiteralTree(Impl)
//expected: an instance of an implementation of Tree that represents a ParenthesizedExpression
//actual: a jdk.nashorn.api.tree.ObjectLiteralTree instance
System.out.println(code.substring((int)tree.getStartPosition(),(int)tree.getEndPosition()));
//The following "expected & actual" assume the local variable "tree" holds an instance of a Tree that represents a ParenthesizedExpression
//expected: the following string value
//(({}))
//actual: the following string value
//{}
//Following this logic, the outer "ParenthesizedExpressionTree" instance would wrap an inner "ParenthesizedExpressionTree" instance, which in turn would wrap the ObjectLiteralTree instance
/**
* Class Definitions (14.5): end position of ClassDeclaration incorrectly excludes the class body
*/
code = "class D{};";
compilationTree = p.parse("5.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ClassDeclarationTree(Impl)
System.out.println(code.substring((int)tree.getStartPosition(),(int)tree.getEndPosition()));
//expected: the following string value
//class D{}
//actual: the following string value
//class D
/**
* Class Definitions (14.5): Tree implementations for representing a specific type of Class Definition
* - have no getter present for getting a tree implementation representing a ClassTail to encapsulate ClassHeritage and (curly bracket wrapped) ClassBody
* - have a getter for getting the constructor node, but no such syntactical definition exists, it is only defined within static semantics.
* - Sidenote: The getter for the constructor returns a non-null value when no actual constructor is present.
*/
Arrays.stream(new Class[]{ClassDeclarationTree.class,ClassExpressionTree.class}[new Random().nextInt(2)].getDeclaredMethods())
.map(Method::getName)
.sorted(String.CASE_INSENSITIVE_ORDER)
.forEach(System.out::println);
//expected: the following string values
//getClassTail
//getName
//actual: the following string values
//getClassElements
//getClassHeritage
//getConstructor
//getName
/**
* Class Definitions (14.5): getter for ClassBody returns not a Tree implementation that is an encapsulating node
*
* Note: if the previously described case about ClassTail has been resolved, this case would change from this:
* //((ClassDeclarationTree) tree).getClassElements()
* //((ClassExpressionTree) tree).getClassElements()
* to this:
* //((ClassDeclarationTree) tree).getClassTail().getClassElements()
* //((ClassExpressionTree) tree).getClassTail().getClassElements()
*/
code = "class E{};";
compilationTree = p.parse("6.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ClassDeclarationTree(Impl)
System.out.println(Tree.class.isAssignableFrom(((ClassDeclarationTree) tree).getClassElements().getClass()));
//expected: an instance of an implementation of Tree
//actual: a java.util.Arraylist instance representing a ClassBody
code = "(class F{});";
compilationTree = p.parse("7.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ExpressionStatementTree(Impl)
tree = ((ExpressionStatementTree) tree).getExpression();//Actual type: ClassExpressionTree(Impl)
System.out.println(Tree.class.isAssignableFrom(((ClassExpressionTree) tree).getClassElements().getClass()));
//expected: an instance of an implementation of Tree
//actual: a java.util.Arraylist instance representing a ClassBody
/**
* Class Definitions (14.5): getter for ClassHeritage returns not an implementation of Tree that representing a ClassHeritage (which is syntactically comprised of the keyword "extends", a space token and a LeftHandSideExpression)
*
* Note: if the previously described case about ClassTail has been resolved, these case implementations would change from this:
* //((ClassDeclarationTree) tree).getClassHeritage()
* //((ClassExpressionTree) tree).getClassHeritage()
* to this:
* //((ClassDeclarationTree) tree).getClassTail().getClassHeritage()
* //((ClassExpressionTree) tree).getClassTail().getClassHeritage()
*/
code = "class G extends E{};";
compilationTree = p.parse("8.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ClassDeclarationTree(Impl)
tree = ((ClassDeclarationTree) tree).getClassHeritage();//Actual type: IdentifierTree(Impl)
System.out.println(IdentifierTree.class.isAssignableFrom(tree.getClass()));
//expected: an instance of an implementation of Tree representing a ClassHeritage which wraps an instance of IdentifierTree(Impl)
//actual: an instance of IdentifierTree(Impl)
System.out.println(code.substring((int)tree.getStartPosition(),(int)tree.getEndPosition()));
//expected: the following string value
//extends E
//actual: the following string value
//E
code = "(class H extends F{});";
compilationTree = p.parse("9.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ExpressionStatementTree(Impl)
tree = ((ExpressionStatementTree) tree).getExpression();//Actual type: ClassExpressionTree(Impl)
tree = ((ClassExpressionTree) tree).getClassHeritage();//Actual type: IdentifierTree(Impl)
System.out.println(IdentifierTree.class.isAssignableFrom(tree.getClass()));
//expected: an instance of an implementation of Tree representing a ClassHeritage which wraps an instance of IdentifierTree(Impl)
//actual: an instance of IdentifierTree(Impl)
System.out.println(code.substring((int)tree.getStartPosition(),(int)tree.getEndPosition()));
//expected: the following string value
//extends F
//actual: the following string value
//F
code = "class I extends (G){};";
compilationTree = p.parse("10.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type:
tree = ((ClassDeclarationTree) tree).getClassHeritage();//Actual type: IdentifierTree(Impl)
System.out.println(IdentifierTree.class.isAssignableFrom(tree.getClass()));
//expected: an instance of an implementation of Tree representing a ClassHeritage, which wraps an instance an implementation of Tree representing a ParenthesizedExpression, which in turn wraps an instance of IdentifierTree(Impl)
//actual: an instance of IdentifierTree(Impl)
System.out.println(code.substring((int)tree.getStartPosition(),(int)tree.getEndPosition()));
//expected: the following string value
//extends (G)
//actual: the following string value
//G
code = "(class J extends (H){});";
compilationTree = p.parse("11.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ExpressionStatementTree(Impl)
tree = ((ExpressionStatementTree) tree).getExpression();//Actual type: ClassExpressionTree(Impl)
tree = ((ClassExpressionTree) tree).getClassHeritage();//Actual type: IdentifierTree(Impl)
System.out.println(IdentifierTree.class.isAssignableFrom(tree.getClass()));
//expected: an instance of an implementation of Tree representing a ClassHeritage, which wraps an instance an implementation of Tree representing a ParenthesizedExpression, which in turn wraps an instance of IdentifierTree(Impl)
//actual: an instance of IdentifierTree(Impl)
System.out.println(code.substring((int)tree.getStartPosition(),(int)tree.getEndPosition()));
//expected: the following string value
//extends (H)
//actual: the following string value
//H
/**
* Class Definitions (14.5): ClassElements are instances of PropertyTree, a class which attempts to represent getter/setter properties as a single syntax tree node which is syntactically not how they exist.
*
* Note: if the previously described case about ClassTail has been resolved, this case would change from this:
* //((ClassDeclarationTree) tree).getClassElements()
* //((ClassExpressionTree) tree).getClassElements()
* to this:
* //((ClassDeclarationTree) tree).getClassTail().getClassElements()
* //((ClassExpressionTree) tree).getClassTail().getClassElements()
*
* Addendum: There are multiple issues with the current implementation as well, mostly in the case of a property holding a setter/getter combination
* - the start-end position are incorrect when requested from a PropertyTree: the end position ends with the first MethodDefinition
* - the design is counter intuitive as 2 properties can "contain" each other when for example first 2 getters and then 2 corresponding setters are defined.
* - the reference to the BindingIdentifier (or PropertyTree.getKey() which returns a IdentifierTree in the current design) can only ever refer to one definition, even though the BindingIdentifier is syntactically present twice.
*/
code = "class M{set a(b){} get a(){}};";
compilationTree = p.parse("14.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ClassDeclarationTree(Impl)
System.out.println(((ClassDeclarationTree) tree).getClassElements().size());//Actual type: ArrayList
//expected: the following int value
//2
//actual: the following int value
//1
code = "(class N{set a(b){} get a(){}});";
compilationTree = p.parse("15.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ExpressionStatementTree(Impl)
tree = ((ExpressionStatementTree) tree).getExpression();//Actual type: ClassExpressionTree(Impl)
System.out.println(((ClassExpressionTree) tree).getClassElements().size());//Actual type: ArrayList
//expected: the following int value
//2
//actual: the following int value
//1
/**
* Getter/Setter functions in a Class Definition and Object literal : missing identity node for name (null is returned instead)
*/
code = "class O{set a(b){} get a(){}};";
compilationTree = p.parse("16.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ClassDeclarationTree(Impl)
tree = ((ClassDeclarationTree) tree).getClassElements().get(0);//Actual type: PropertyTree(Impl)
System.out.println(null == ((PropertyTree)tree).getGetter().getName());
//expected: not a null value
//actual: a null value
System.out.println(null == ((PropertyTree)tree).getSetter().getName());
//expected: a IdentifierTree value
//actual: a null value
code = "(class P{set a(b){} get a(){}});";
compilationTree = p.parse("17.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ExpressionStatementTree(Impl)
tree = ((ExpressionStatementTree) tree).getExpression();//Actual type: ClassExpressionTree(Impl)
tree = ((ClassExpressionTree) tree).getClassElements().get(0);//Actual type: PropertyTree(Impl)
System.out.println(null == ((PropertyTree)tree).getGetter().getName());
//expected: not a null value
//actual: a null value
System.out.println(null == ((PropertyTree)tree).getSetter().getName());
//expected: a IdentifierTree value
//actual: a null value
code = "({get a(){}, set a(b){}});";
compilationTree = p.parse("18.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ExpressionStatementTree(Impl)
tree = ((ExpressionStatementTree) tree).getExpression();//Actual type: ObjectLiteralTree(Impl)
tree = ((ObjectLiteralTree) tree).getProperties().get(0);//Actual type: PropertyTree(Impl)
System.out.println(null == ((PropertyTree)tree).getGetter().getName());
//expected: not a null value
//actual: a null value
System.out.println(null == ((PropertyTree)tree).getSetter().getName());
//expected: a IdentifierTree value
//actual: a null value
/**
* Function Definitions (14.1) : FunctionExpression has incorrect start/end positions (both point between the parameters and the body)
*/
code = "(function(){});";
compilationTree = p.parse("19.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ExpressionStatementTree(Impl)
tree = ((ExpressionStatementTree)tree).getExpression();//Actual type: FunctionExpressionTree(Impl)
System.out.println("function(){}".equals(code.substring((int)tree.getStartPosition(),(int)tree.getEndPosition())));
//expected: the following string value
//function(){}
//actual: empty string value
/**
* Function Calls (14.1): getter for FormalParameters returns not a Tree implementation that is an encapsulating node for the arguments
*/
code = "function Q(){};";
compilationTree = p.parse("20.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ExpressionStatementTree(Impl)
System.out.println(Tree.class.isAssignableFrom(((FunctionDeclarationTree)tree).getParameters().getClass()));
//expected: an instance of an implementation of Tree
//actual: a java.util.Arraylist instance representing the parameters
}
}
---------- END SOURCE ----------
java version "10-ea" 2018-03-20
Java(TM) SE Runtime Environment 18.3 (build 10-ea+39)
Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10-ea+39, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.3.9600]
(c) 2013 Microsoft Corporation. All rights reserved.
A DESCRIPTION OF THE PROBLEM :
Classes mentioned here are specifically from the package jdk.nashorn.api.tree.
The Parser class allows for the creation of a fully initialized CompilationUnitTree based on a provided source script. The resulting hierarchical structure of Tree nodes represents the syntax tree of the provided source script
This classification of the syntactical components of a parsed script falls short between two design ideas. On one hand it's designed to provide access to individual grammatical components of the source script. On the other hand it conceptualizes the resulting compilation unit, which is the begin state of the script runtime before evaluation of the compiled script begins.
If the documentation of the classes involved in this design is to be the lead in determining what this api is designed for, the hierarchical structure of the tree is to represent specifically an Abstract Syntax Tree(AST). This means the tree result of the parsing stage is specifically to represent the code as-is and conforming to the syntactical grammar defined in the ECMA spec. This would be a depature from the idea that this tree structure could represent a Concrete Syntax Tree, which chronologically exists after the compilation stage.
I've included within the source code a list of issues for the case of purely following the design of an AST, ranging from bugs to design flaws. By no means is this complete, but it should pave the way for a solid start.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the provided source script.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The following output:
1;
"2";
"2"
true
true
(({}));
(({}))
class D{}
getClassTail
getName
true
true
false
extends E
false
extends F
false
extends (G)
false
extends (H)
2
2
false
false
false
false
false
false
true
true
ACTUAL -
1
2
2
false
false
(({}))
{}
class D
getClassElements
getClassHeritage
getConstructor
getName
false
false
true
E
true
F
true
G
true
H
1
1
true
true
true
true
true
true
false
false
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import jdk.nashorn.api.tree.*;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Random;
public class Main {
public static void main(String[] args) {
Parser p = jdk.nashorn.api.tree.Parser.create("--language=es6");//ECMA-262 6.0
String code;
CompilationUnitTree compilationTree;
Tree tree;
/**
* Expression Statement (13.5): missing semicolon between start-end positions
*/
code = "1;";
compilationTree = p.parse("1.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ExpressionStatementTree(Impl)
System.out.println(code.substring((int)tree.getStartPosition(),(int)tree.getEndPosition()));
//expected: the following string value
//1;
//actual: the following string value
//1
/**
* String Literals (11.8.4): missing surrounding quotes between start-end positions
*/
code = "\"2\";";
compilationTree = p.parse("2.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ExpressionStatementTree(Impl)
System.out.println(code.substring((int)tree.getStartPosition(),(int)tree.getEndPosition()));
//expected: the following string value
//"2";
//actual: the following string value
//2
tree = ((ExpressionStatementTree) tree).getExpression();//Actual type: LiteralTree(Impl)
System.out.println(code.substring((int)tree.getStartPosition(),(int)tree.getEndPosition()));
//expected: the following string value
//"2"
//actual: the following string value
//2
/**
* Function Definitions (14.1): function body incorrectly includes the first curly brace between start-end positions
*/
code = "function c(){};";
compilationTree = p.parse("3.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: FunctionDeclarationTree(Impl)
tree = ((FunctionDeclarationTree)tree).getBody();
System.out.println("".equals(code.substring((int)tree.getStartPosition(),(int)tree.getEndPosition())));
//expected: empty string value
//actual: the following string value
//{
/**
* Function Calls (12.3.4): getter for Arguments returns not a Tree implementation that is an encapsulating node for the arguments
*/
code = "Object();";
compilationTree = p.parse("4.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ExpressionStatementTree(Impl)
tree = ((ExpressionStatementTree)tree).getExpression();//Actual type: FunctionCallTree(Impl)
System.out.println(Tree.class.isAssignableFrom(((FunctionCallTree)tree).getArguments().getClass()));
//expected: an instance of an implementation of Tree
//actual: a java.util.Arraylist instance representing the Arguments
/**
* Primary Expression (12.2): no nodes present in the tree structure to represent instances of a ParenthesizedExpression
*/
code = "(({}));";
compilationTree = p.parse("5.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ExpressionStatementTree(Impl)
System.out.println(code.substring((int)tree.getStartPosition(),(int)tree.getEndPosition()));
//expected: the following string value
//(({}));
//actual: the following string value
//(({}))
tree = ((ExpressionStatementTree)tree).getExpression();//Actual type: ObjectLiteralTree(Impl)
//expected: an instance of an implementation of Tree that represents a ParenthesizedExpression
//actual: a jdk.nashorn.api.tree.ObjectLiteralTree instance
System.out.println(code.substring((int)tree.getStartPosition(),(int)tree.getEndPosition()));
//The following "expected & actual" assume the local variable "tree" holds an instance of a Tree that represents a ParenthesizedExpression
//expected: the following string value
//(({}))
//actual: the following string value
//{}
//Following this logic, the outer "ParenthesizedExpressionTree" instance would wrap an inner "ParenthesizedExpressionTree" instance, which in turn would wrap the ObjectLiteralTree instance
/**
* Class Definitions (14.5): end position of ClassDeclaration incorrectly excludes the class body
*/
code = "class D{};";
compilationTree = p.parse("5.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ClassDeclarationTree(Impl)
System.out.println(code.substring((int)tree.getStartPosition(),(int)tree.getEndPosition()));
//expected: the following string value
//class D{}
//actual: the following string value
//class D
/**
* Class Definitions (14.5): Tree implementations for representing a specific type of Class Definition
* - have no getter present for getting a tree implementation representing a ClassTail to encapsulate ClassHeritage and (curly bracket wrapped) ClassBody
* - have a getter for getting the constructor node, but no such syntactical definition exists, it is only defined within static semantics.
* - Sidenote: The getter for the constructor returns a non-null value when no actual constructor is present.
*/
Arrays.stream(new Class[]{ClassDeclarationTree.class,ClassExpressionTree.class}[new Random().nextInt(2)].getDeclaredMethods())
.map(Method::getName)
.sorted(String.CASE_INSENSITIVE_ORDER)
.forEach(System.out::println);
//expected: the following string values
//getClassTail
//getName
//actual: the following string values
//getClassElements
//getClassHeritage
//getConstructor
//getName
/**
* Class Definitions (14.5): getter for ClassBody returns not a Tree implementation that is an encapsulating node
*
* Note: if the previously described case about ClassTail has been resolved, this case would change from this:
* //((ClassDeclarationTree) tree).getClassElements()
* //((ClassExpressionTree) tree).getClassElements()
* to this:
* //((ClassDeclarationTree) tree).getClassTail().getClassElements()
* //((ClassExpressionTree) tree).getClassTail().getClassElements()
*/
code = "class E{};";
compilationTree = p.parse("6.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ClassDeclarationTree(Impl)
System.out.println(Tree.class.isAssignableFrom(((ClassDeclarationTree) tree).getClassElements().getClass()));
//expected: an instance of an implementation of Tree
//actual: a java.util.Arraylist instance representing a ClassBody
code = "(class F{});";
compilationTree = p.parse("7.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ExpressionStatementTree(Impl)
tree = ((ExpressionStatementTree) tree).getExpression();//Actual type: ClassExpressionTree(Impl)
System.out.println(Tree.class.isAssignableFrom(((ClassExpressionTree) tree).getClassElements().getClass()));
//expected: an instance of an implementation of Tree
//actual: a java.util.Arraylist instance representing a ClassBody
/**
* Class Definitions (14.5): getter for ClassHeritage returns not an implementation of Tree that representing a ClassHeritage (which is syntactically comprised of the keyword "extends", a space token and a LeftHandSideExpression)
*
* Note: if the previously described case about ClassTail has been resolved, these case implementations would change from this:
* //((ClassDeclarationTree) tree).getClassHeritage()
* //((ClassExpressionTree) tree).getClassHeritage()
* to this:
* //((ClassDeclarationTree) tree).getClassTail().getClassHeritage()
* //((ClassExpressionTree) tree).getClassTail().getClassHeritage()
*/
code = "class G extends E{};";
compilationTree = p.parse("8.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ClassDeclarationTree(Impl)
tree = ((ClassDeclarationTree) tree).getClassHeritage();//Actual type: IdentifierTree(Impl)
System.out.println(IdentifierTree.class.isAssignableFrom(tree.getClass()));
//expected: an instance of an implementation of Tree representing a ClassHeritage which wraps an instance of IdentifierTree(Impl)
//actual: an instance of IdentifierTree(Impl)
System.out.println(code.substring((int)tree.getStartPosition(),(int)tree.getEndPosition()));
//expected: the following string value
//extends E
//actual: the following string value
//E
code = "(class H extends F{});";
compilationTree = p.parse("9.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ExpressionStatementTree(Impl)
tree = ((ExpressionStatementTree) tree).getExpression();//Actual type: ClassExpressionTree(Impl)
tree = ((ClassExpressionTree) tree).getClassHeritage();//Actual type: IdentifierTree(Impl)
System.out.println(IdentifierTree.class.isAssignableFrom(tree.getClass()));
//expected: an instance of an implementation of Tree representing a ClassHeritage which wraps an instance of IdentifierTree(Impl)
//actual: an instance of IdentifierTree(Impl)
System.out.println(code.substring((int)tree.getStartPosition(),(int)tree.getEndPosition()));
//expected: the following string value
//extends F
//actual: the following string value
//F
code = "class I extends (G){};";
compilationTree = p.parse("10.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type:
tree = ((ClassDeclarationTree) tree).getClassHeritage();//Actual type: IdentifierTree(Impl)
System.out.println(IdentifierTree.class.isAssignableFrom(tree.getClass()));
//expected: an instance of an implementation of Tree representing a ClassHeritage, which wraps an instance an implementation of Tree representing a ParenthesizedExpression, which in turn wraps an instance of IdentifierTree(Impl)
//actual: an instance of IdentifierTree(Impl)
System.out.println(code.substring((int)tree.getStartPosition(),(int)tree.getEndPosition()));
//expected: the following string value
//extends (G)
//actual: the following string value
//G
code = "(class J extends (H){});";
compilationTree = p.parse("11.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ExpressionStatementTree(Impl)
tree = ((ExpressionStatementTree) tree).getExpression();//Actual type: ClassExpressionTree(Impl)
tree = ((ClassExpressionTree) tree).getClassHeritage();//Actual type: IdentifierTree(Impl)
System.out.println(IdentifierTree.class.isAssignableFrom(tree.getClass()));
//expected: an instance of an implementation of Tree representing a ClassHeritage, which wraps an instance an implementation of Tree representing a ParenthesizedExpression, which in turn wraps an instance of IdentifierTree(Impl)
//actual: an instance of IdentifierTree(Impl)
System.out.println(code.substring((int)tree.getStartPosition(),(int)tree.getEndPosition()));
//expected: the following string value
//extends (H)
//actual: the following string value
//H
/**
* Class Definitions (14.5): ClassElements are instances of PropertyTree, a class which attempts to represent getter/setter properties as a single syntax tree node which is syntactically not how they exist.
*
* Note: if the previously described case about ClassTail has been resolved, this case would change from this:
* //((ClassDeclarationTree) tree).getClassElements()
* //((ClassExpressionTree) tree).getClassElements()
* to this:
* //((ClassDeclarationTree) tree).getClassTail().getClassElements()
* //((ClassExpressionTree) tree).getClassTail().getClassElements()
*
* Addendum: There are multiple issues with the current implementation as well, mostly in the case of a property holding a setter/getter combination
* - the start-end position are incorrect when requested from a PropertyTree: the end position ends with the first MethodDefinition
* - the design is counter intuitive as 2 properties can "contain" each other when for example first 2 getters and then 2 corresponding setters are defined.
* - the reference to the BindingIdentifier (or PropertyTree.getKey() which returns a IdentifierTree in the current design) can only ever refer to one definition, even though the BindingIdentifier is syntactically present twice.
*/
code = "class M{set a(b){} get a(){}};";
compilationTree = p.parse("14.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ClassDeclarationTree(Impl)
System.out.println(((ClassDeclarationTree) tree).getClassElements().size());//Actual type: ArrayList
//expected: the following int value
//2
//actual: the following int value
//1
code = "(class N{set a(b){} get a(){}});";
compilationTree = p.parse("15.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ExpressionStatementTree(Impl)
tree = ((ExpressionStatementTree) tree).getExpression();//Actual type: ClassExpressionTree(Impl)
System.out.println(((ClassExpressionTree) tree).getClassElements().size());//Actual type: ArrayList
//expected: the following int value
//2
//actual: the following int value
//1
/**
* Getter/Setter functions in a Class Definition and Object literal : missing identity node for name (null is returned instead)
*/
code = "class O{set a(b){} get a(){}};";
compilationTree = p.parse("16.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ClassDeclarationTree(Impl)
tree = ((ClassDeclarationTree) tree).getClassElements().get(0);//Actual type: PropertyTree(Impl)
System.out.println(null == ((PropertyTree)tree).getGetter().getName());
//expected: not a null value
//actual: a null value
System.out.println(null == ((PropertyTree)tree).getSetter().getName());
//expected: a IdentifierTree value
//actual: a null value
code = "(class P{set a(b){} get a(){}});";
compilationTree = p.parse("17.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ExpressionStatementTree(Impl)
tree = ((ExpressionStatementTree) tree).getExpression();//Actual type: ClassExpressionTree(Impl)
tree = ((ClassExpressionTree) tree).getClassElements().get(0);//Actual type: PropertyTree(Impl)
System.out.println(null == ((PropertyTree)tree).getGetter().getName());
//expected: not a null value
//actual: a null value
System.out.println(null == ((PropertyTree)tree).getSetter().getName());
//expected: a IdentifierTree value
//actual: a null value
code = "({get a(){}, set a(b){}});";
compilationTree = p.parse("18.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ExpressionStatementTree(Impl)
tree = ((ExpressionStatementTree) tree).getExpression();//Actual type: ObjectLiteralTree(Impl)
tree = ((ObjectLiteralTree) tree).getProperties().get(0);//Actual type: PropertyTree(Impl)
System.out.println(null == ((PropertyTree)tree).getGetter().getName());
//expected: not a null value
//actual: a null value
System.out.println(null == ((PropertyTree)tree).getSetter().getName());
//expected: a IdentifierTree value
//actual: a null value
/**
* Function Definitions (14.1) : FunctionExpression has incorrect start/end positions (both point between the parameters and the body)
*/
code = "(function(){});";
compilationTree = p.parse("19.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ExpressionStatementTree(Impl)
tree = ((ExpressionStatementTree)tree).getExpression();//Actual type: FunctionExpressionTree(Impl)
System.out.println("function(){}".equals(code.substring((int)tree.getStartPosition(),(int)tree.getEndPosition())));
//expected: the following string value
//function(){}
//actual: empty string value
/**
* Function Calls (14.1): getter for FormalParameters returns not a Tree implementation that is an encapsulating node for the arguments
*/
code = "function Q(){};";
compilationTree = p.parse("20.js", code, System.out::println);
tree = compilationTree.getSourceElements().get(0);//Actual type: ExpressionStatementTree(Impl)
System.out.println(Tree.class.isAssignableFrom(((FunctionDeclarationTree)tree).getParameters().getClass()));
//expected: an instance of an implementation of Tree
//actual: a java.util.Arraylist instance representing the parameters
}
}
---------- END SOURCE ----------