The stub for lab 2 uses Java 21,
which admits a more readable alternative to the visitor pattern
suggested in the book.
The following example code shows how you can process an object
exp
of the type type Exp
generated by the
parser defined in the stub.
switch(exp) {
case EInt e -> ... ;
case EDouble e -> ... ;
case EAnd e -> ... ;
case EOr e -> ... ;
...
default -> throw new IllegalStateException("Case for " + e + " is not yet implemented.");
}
On the right hand side of the ->
you can extract
further information from e
,
for example, in the case EAnd e
, you can use the two
operands e.exp_1
and e.exp_2
.
switch
, if used like above produces a Java-expression,
which means that you can use it in assignments:
var typedExpression = switch(exp) { ... }
To define the neccessary datatypes, record
s are very
useful.
You can define a record like this:
public record TypedAnd(TypedExpr e1, TypedExpr e2) {
}
Objects of this type can be constructed with
new TypedAnd(e1,e2)
where e1
and
e2
are TypedExpr
s. For solving the lab, it is
reasonable to define an interface
TypedExpr
with a method which returns the type of an expression:
public interface TypedExpr {
Type type();
}
Where Type
is a datatype for types that needs to be
defined. With this interface, the TypedAnd
from above can
be turned into an implementation like this:
public record TypedAnd(TypedExpr e1, TypedExpr e2) {
Type type() {
return new Type.Bool; // this is what it could look like if you implement basic types as an enum
}
}