The current implementation has a stack-based error message detection mechanism that does not interact with the lexer and parser. (I did not have enough time to finish and implement the CtxNode.) Therefore, using listeners would make changing error messages and where they go much more straightforward. ANTLR provides this mechanism as an interface; in fact, there is a syntaxError() method that applies to both the lexer and parser, which we can override to display error messages the way we want to. (It also receives a reference to the parser, which means that we can query it about the state of the lexer and parser.)
Grammar
The syntax is more similar to that of Java 11. I also added a new loop construct
for {
...
}
that represents an infinite loop. Also, I suggest using annotations rather than #pragma declarations to indicate when something is not native to the language. Annotations can be placed anywhere in the code, which means that every node in the AST could be annotated. Here is an example of how we could write a native ProcessJ library:
import @Static(check = out) java.lang.System.*;
public println(string s) {
@Check out.println(s);
}
public println(int i) {
@Check out.println(i);
}
public println(char c) {
@Check out.println(c);
}
...
In order to type check non-native code, @Static would instruct the compiler to look through the system class for the output print stream object, so that we could gather information from its println method through Java's reflection API. We could then use this library in a ProcessJ program as follows:
import std.io;
public void main(string...args) {
println("Hello World!");
}
Here is another example of how something non-native could be type checked. For instance, consider the following ProcessJ code:
We could gather information during compilation rather than letting the Java compiler (and possibly the runtime when using external types) handle it since we are using the println version of Java.
ANTLR instead of CUP
The main key points behind using ANTLR are:
The current implementation has a stack-based error message detection mechanism that does not interact with the lexer and parser. (I did not have enough time to finish and implement the
CtxNode
.) Therefore, using listeners would make changing error messages and where they go much more straightforward. ANTLR provides this mechanism as an interface; in fact, there is asyntaxError()
method that applies to both the lexer and parser, which we can override to display error messages the way we want to. (It also receives a reference to the parser, which means that we can query it about the state of the lexer and parser.)Grammar
The syntax is more similar to that of Java 11. I also added a new loop construct
that represents an infinite loop. Also, I suggest using annotations rather than
#pragma
declarations to indicate when something is not native to the language. Annotations can be placed anywhere in the code, which means that every node in the AST could be annotated. Here is an example of how we could write a native ProcessJ library:In order to type check non-native code,
@Static
would instruct the compiler to look through thesystem
class for the output print stream object, so that we could gather information from itsprintln
method through Java's reflection API. We could then use this library in a ProcessJ program as follows:Here is another example of how something non-native could be type checked. For instance, consider the following ProcessJ code:
We could gather information during compilation rather than letting the Java compiler (and possibly the runtime when using external types) handle it since we are using the
println
version of Java.Proposed grammar