Creating JVM language [PART 18] - Fields

Sources

Syntax

The syntax is simplified version of Java’s. You can specify type and name of a field.
There are no are no modifiers and keywords like ‘static’,’volatile’,’transient’ etc. I am trying to keep it simple so far.

Fields{intfieldstart{field=5printfield}}

Grammar changes

Until now, you could only define methods in class body scope.
It’s time to introduce fields:

classBody:field*function*;field:typename;

I also added assign statement for already defined variables:

assignment:nameEQUALSexpression;

Why I have not implemented assign statement for so long?

To make use of fields you have to assign them to something. Turns out
I have not yet implemented such a basic thing as assignment statement for already declared variables.
Why haven’t I done that? Well It was kind of on purpose.

The reason behind it is I would like the variables to be constant (immutable).
Assigning means changing state - changing state lead to many issues (synchronization,side effects,memory leaks).

Have you ever read a Java code and that looks something like this:

StufftrustMeIWontModifyYourArg(SomeObjectarg){...999linesofcodearg=null;//or some other nasty hidden stuff...another999linesofcode}

By reading the signature you probably thought to yourself - “hmmm… does this method modify argument? Well, it does not
have a final modifier but most of us (Java programmers) neglect it. Judging by it’s name it should not modify my args so let’s just use it.”

Two hours later you randomly get NullPointerException somewhere else in your code. The method modified
your argument.

If you have no side effects in your methods you can easily make them parallel
without worrying about synchronization issues and other nasty stuff. Such methods does
not have a state = there are no side effects! The easiest way to achieve
lack of side effects is to use values (constant variables) only.

Reading field

owner internal name (if the field is owned by com.yourcompany.Car then it’d be “com/yourcompany/Car”)

publicclassReferenceExpressionGenerator{//constructor and fieldspublicvoidgenerate(FieldReferencefieldReference){StringvarName=fieldReference.geName();Typetype=fieldReference.getType();StringownerInternalName=fieldReference.getOwnerInternalName();Stringdescriptor=type.getDescriptor();methodVisitor.visitVarInsn(Opcodes.ALOAD,0);methodVisitor.visitFieldInsn(Opcodes.GETFIELD,ownerInternalName,varName,descriptor);}}

ALOAD,0 - gets “this” object which is local variable at index 0. Non-static methods have “this” reference by default at index 0 in local variables.

GETFIELD - opcode for reading field.

Assigning to field

publicclassAssignmentStatementGenerator{//constructor and fieldspublicvoidgenerate(Assignmentassignment){StringvarName=assignment.getVarName();Expressionexpression=assignment.getExpression();Typetype=expression.getType();if(scope.isLocalVariableExists(varName)){intindex=scope.getLocalVariableIndex(varName);methodVisitor.visitVarInsn(type.getStoreVariableOpcode(),index);return;}Fieldfield=scope.getField(varName);Stringdescriptor=field.getType().getDescriptor();methodVisitor.visitVarInsn(Opcodes.ALOAD,0);expression.accept(expressionGenerator);methodVisitor.visitFieldInsn(Opcodes.PUTFIELD,field.getOwnerInternalName(),field.getName(),descriptor);}

The local variables have priority over fields if there is ambiguity. If you declared
local variable named exactly like a field you wouldn’t want to
reference field but a variable, right? That is why the local variables are searched first.

The PUTFIELD opcode is similar to GETFIELD but pops additional item off the stack -
the result of expression to be assigned into field.