usethesource / flybytes

Flybytes is an intermediate language between JVM bytecode and software languages (DSLs, PLs), for compilation and decompilation.
BSD 2-Clause "Simplified" License
16 stars 6 forks source link

Null tests in Flybytes #24

Closed bys1 closed 1 year ago

bys1 commented 1 year ago

In the ClassCompiler class, I found references to the Exp constructors null and nonnull, with the former having a check for getArity() == 0 to return a null expression in that case and a null check otherwise. However, in the syntax, the null() constructor always has an arity of 0 and the nonnull constructor does not exist. Are these missing constructors in the syntax?

jurgenvinju commented 1 year ago

I will have to check my memory by looking back in the git history, but I believe these are remnants of my exploration for the design of the syntax, that I later removed.

JVM Bytecode has IFNULL but Java's conditions only have boolean conditions. I started with having the first also in flybytes, but when I later "closed the abstraction" it didn't make sense anymore. The current compiler optimizes to uses of IFNULL from eq(x, null()) by a simple instruction selection table, making the syntax of flybytes much more java/scala-like.

jurgenvinju commented 1 year ago

Thanks for reporting this btw. I'll check my story and remove the remnants if it checks out.

jurgenvinju commented 1 year ago
// this is called directly from matching "nonnull" as an Exp in the syntax tree
private IConstructor isNonNullTest(IConstructor arg, Builder<IConstructor> thenPart, Builder<IConstructor> elsePart, LeveledLabel joinLabel, int line) {
            expr(arg, line);
            return invertedConditionalFlow(0, Opcodes.IFNULL, thenPart, elsePart, joinLabel, line);
        }

// here `ne(x, null)` is translated to a low-level non-null check and eq similarly:
        private IConstructor neExp(IConstructor lhs, IConstructor rhs, Builder<IConstructor> thenPart, Builder<IConstructor> elsePart, LeveledLabel joinLabel, int line) {
            if (lhs.getConstructorType().getName().equals("null")) {
                return isNonNullTest(rhs, thenPart, elsePart, joinLabel, line);
            }
            else if (rhs.getConstructorType().getName().equals("null")) {
                return isNonNullTest(lhs, thenPart, elsePart, joinLabel, line);
            }

    ...

So yes, the short-hand was removed from the syntax definition, while still the same optimal code will be generated if you use eq(null(), someThing) or ne(someThing, null()). I'll remove the dead code.