This article is the 16th translation of Creating JVM Language. The inconsistency between the original code and the original code has been corrected in the new code repository. We suggest you refer to the new code repository.
The source code
Github
The OOP and the statics
What are the biggest advantages of object-oriented languages? I personally think polymorphism, how do you implement polymorphism, use inheritance, can you use inheritance in static semantics? Certainly not.
In my opinion, static semantics violate object orientation and should not be used in object orientation. To avoid using polymorphism, you can use singletons.
So why does Java claim to be object-oriented when it is static? I think Java is a historical element that was introduced to cater to the more convenient adoption of Java by C++.
Get rid of the static
Up until the last blog post, static was present in Enkel. Including main methods and other static methods to make it easier to implement other features of the language, such as variables, conditional expressions, loops, and method calls, before transiting to OO.
So let’s implement OO without static.
The main method
The static main method requires Java programmers to write it manually. Enkel deals with it like this:
- Automatically generated by the compiler
- In the main method, an object is created with the default constructor
- The start method is then called
- The programmer needs to provide the start method definition
private Function getGeneratedMainMethod() {
FunctionParameter args = new FunctionParameter("args", BultInType.STRING_ARR, Optional.empty());
FunctionSignature functionSignature = new FunctionSignature("main", Collections.singletonList(args), BultInType.VOID);
ConstructorCall constructorCall = new ConstructorCall(scope.getClassName());
FunctionSignature startFunSignature = new FunctionSignature("start", Collections.emptyList(), BultInType.VOID);
FunctionCall startFunctionCall = new FunctionCall(startFunSignature, Collections.emptyList(), scope.getClassType());
Block block = new Block(new Scope(scope), Arrays.asList(constructorCall,startFunctionCall));
return new Function(functionSignature, block);
}
Copy the code
The start method is non-static, but is actually a variation of the main method.
INVOSTATIC vs INVOKEVIRTUAL
In Part 7, I used INVOKESTATIC for method calls, so it’s time to switch to INVOKEVIRTUAL.
INVOKEVIRTUAL is very different from INVOKESTATIC in that it requires an owner. INVOKESTATIC pushes the owner off the stack first, and then INVOKESTATIC pushes the owner off the stack.
If no owner information is displayed, this is used by default.
//Mapping antlr generated FunctionCallContext to FunctionCall @Override public Expression visitFunctionCall(@NotNull EnkelParser.FunctionCallContext ctx) { //other stuff boolean ownerIsExplicit = ctx.owner ! = null;if(ownerIsExplicit) {
Expression owner = ctx.owner.accept(this);
return new FunctionCall(signature, arguments, owner);
}
ClassType thisType = new ClassType(scope.getClassName());
return new FunctionCall(signature, arguments, new VarReference("this",thisType)); //pass "this" as a owner
}
Copy the code
//Generating bytecode using mapped FunctionCall object
public void generate(FunctionCall functionCall) {
functionCall.getOwner().accept(this); //generate owner (pushses it onto stack)
generateArguments(functionCall); //generate arguments
String functionName = functionCall.getIdentifier();
String methodDescriptor = DescriptorFactory.getMethodDescriptor(functionCall.getSignature());
String ownerDescriptor = functionCall.getOwnerType().getInternalName();
//Consumes owner and arguments off the stack
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, ownerDescriptor, functionName, methodDescriptor, false);
}
Copy the code
The sample
Enkel code:
HelloStart {
start {
print "Hey I am non-static 'start' method"}}Copy the code
Generate bytecode:
public class HelloStart {
public void start();
Code:
0: getstatic #12 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #14 // String Hey I am non-static 'start' method
5: invokevirtual #19 // Method "Ljava/io/PrintStream;" .println:(Ljava/lang/String;) V
8: return
//Constructor
public HelloStart();
Code:
0: aload_0 //get "this"
1: invokespecial #22 // Method java/lang/Object."
":()V - call super
4: return
public static void main(java.lang.String[]);
Code:
0: new #2 // class HelloStart - create new object
3: dup //duplicate new object so that invokespecial does not consumes it
4: invokespecial #25 // Method "
":()V - call constructor
7: invokevirtual #27 // Method start:()V
10: return
}
Copy the code
The corresponding Java class is as follows:
public class HelloStart {
public HelloStart() {
}
public static void main(String[] var0) {
(new HelloStart()).start();
}
public void start() {
System.out.println("Hey I am non-static \'start\' method"); }}Copy the code