Skip to main content

module lang::flybytes::Syntax

rascal-0.34.0
flybytes-0.2.3

Usage

import lang::flybytes::Syntax;

Source code

http://github.com/usethesource/flybytes/blob/main/src/lang/flybytes/Syntax.rsc

Dependencies

import List;

data Class

The top-level compilation unit for flybytes is the class or the interface

data Class (list[Annotation] annotations = [], loc src = |unknown:///|) 
= class(Type \type /* object(str name) */,
set[Modifier] modifiers = {\public()},
Type super = object(),
list[Type] interfaces = [],
list[Field] fields = [],
list[Method] methods = []
//list[Class] children = [],
)
| interface(Type \type /* object(str name) */,
list[Type] interfaces = [],
list[Field] fields = [],
list[Method] methods = []
)
;

data Modifier

data Modifier  
= \public()
| \private()
| \protected()
| \friendly()
| \static()
| \final()
| \synchronized()
| \abstract()
;

data Field

Class fields members have optional initialization expressions.

data Field (list[Annotation] annotations = [], set[Modifier] modifiers = {\private()}, loc src=|unknown:///|) 
= field(Type \type, str name, Exp init = defVal(\type))
;

data Method

Four kinds of methods can be generated

data Method (list[Annotation] annotations = [], loc src=|unknown:///|) 
= method(Signature desc, list[Formal] formals, list[Stat] block, set[Modifier] modifiers = {\public()})
| procedure(Signature desc, list[Formal] formals, list[Instruction] instructions, set[Modifier] modifiers = {\public()})
| method(Signature desc, set[Modifier] modifiers={\abstract(), \public()})
| static(list[Stat] block)
;
  • procedure is a special extension since it contains only JVM bytecode instructions as a body, instead of high-level programming constructs like expressions and statements.
  • one alternative of method is abstract methods, which do not have a body, the other is methods
  • static blocks are also modeled as methods but without a signature.
  • normal static methods are methods with a static Modifier.

The src field is important for stack traces and other debugging features.

function method

Shorthand for directly producing a method with its signature and code block.

Method method(Modifier access, Type ret, str name, list[Formal] formals, list[Stat] block)

data Signature

Method and constructor signatures

data Signature  
= methodDesc(Type \return, str name, list[Type] formals)
| constructorDesc(list[Type] formals)
;

data Type

JVM type symbols

data Type  
= byte()
| boolean()
| short()
| character()
| integer()
| float()
| double()
| long()
| object(str name)
| array(Type arg)
| \void()
| string()
;

data Annotation

data Annotation (RetentionPolicy retention=runtime()) 
= \anno(str annoClass, Type \type, value val, str name = "value")
| \tag(str annoClass)
;

data RetentionPolicy

data RetentionPolicy  
= class()
| runtime()
| source()
;

data Formal

optional init expressions will be used at run-time if null is passed as actual parameter

data Formal  
= var(Type \type, str name, Exp init = defVal(\type))
;

data Stat

Structured programming with statements, OO primitives like new, and JVM monitor blocks and breakpoints

data Stat (loc src = |unknown:///|) 
= \store(str name, Exp \value)
| \decl(Type \type, str name, Exp init = defVal(\type))
| \astore(Exp array, Exp index, Exp arg)
| \do(Exp exp)
| \return()
| \return(Exp arg)
| \putField(Type class, Exp receiver, Type \type, str name, Exp arg)
| \putStatic(Type class, str name, Type \type, Exp arg)
| \if(Exp condition, list[Stat] thenBlock)
| \if(Exp condition, list[Stat] thenBlock, list[Stat] elseBlock)
| \for(list[Stat] init,
Exp condition,
list[Stat] next,
list[Stat] statements, str label = "")
| \block(list[Stat] block, str label = "")
| \break(str label = "")
| \continue(str label = "")
| \while(Exp condition, list[Stat] block, str label = "")
| \doWhile(list[Stat] block, Exp condition, str label = "")
| \throw(Exp arg)
| \monitor(Exp arg, list[Stat] block)
| \acquire(Exp arg)
| \release(Exp arg)
| \try(list[Stat] block, list[Handler] \catch)
| \switch(Exp arg, list[Case] cases, SwitchOption option = lookup(/*for best performance on current JVMs*/))
| invokeSuper(Signature desc, list[Exp] args)
| \asm(list[Instruction] instructions)
;
  • invokeSuper is typically only used as the first statement of a constructor
  • monitor guarantees release of the lock in case of exceptions, break and continue that break out of the block, but only if release and acquire are not used on the same lock object anywhere.
  • asm allows for inling raw bytecode instructions, but please understand that the monitor blocks' semantics can be broken by jumping out of the block unseen.

data SwitchOption

data SwitchOption  
= table()
| lookup()
| auto()
;

data Case

data Case  
= \case(int key, list[Stat] block)
| \default(list[Stat] block)
;

data Handler

data Handler  
= \catch(Type \type, str name, list[Stat] block)
| \finally(list[Stat] block)
;

data Exp

JVM bytecode instructions lifted to the expression level.

data Exp (loc src = |unknown:///|) 
= null()
| \true()
| \false()
| load(str name)
| aload(Exp array, Exp index)
| \const(Type \type, value constant)
| sblock(list[Stat] statements, Exp arg)
| invokeStatic(Type class, Signature desc, list[Exp] args)
| invokeSpecial(Type class, Exp receiver, Signature desc, list[Exp] args)
| invokeVirtual(Type class, Exp receiver, Signature desc, list[Exp] args)
| invokeInterface(Type class, Exp receiver, Signature desc, list[Exp] args)
| invokeDynamic(BootstrapCall handle, Signature desc, list[Exp] args)
| newInstance(Type class, Signature desc, list[Exp] args)
| getField(Type class, Exp receiver, Type \type, str name)
| getStatic(Type class, Type \type, str name)
| instanceof(Exp arg, Type class)
| eq(Exp lhs, Exp rhs)
| ne(Exp lhs, Exp rhs)
| le(Exp lhs, Exp rhs)
| gt(Exp lhs, Exp rhs)
| ge(Exp lhs, Exp rhs)
| lt(Exp lhs, Exp rhs)
| newArray(Type \type, Exp size)
| newInitArray(Type \type, list[Exp] args)
| alength(Exp arg)
| checkcast(Exp arg, Type \type)
| coerce(Type from, Type to, Exp arg)
| shr(Exp lhs, Exp shift)
| shl(Exp lhs, Exp shift)
| ushr(Exp lhs, Exp shift)
| and(Exp lhs, Exp rhs)
| sand(Exp lhs, Exp rhs)
| or(Exp lhs, Exp rhs)
| sor(Exp lhs, Exp rhs)
| xor(Exp lhs, Exp rhs)
| add(Exp lhs, Exp rhs)
| sub(Exp lhs, Exp rhs)
| div(Exp lhs, Exp rhs)
| rem(Exp lhs, Exp rhs)
| mul(Exp lhs, Exp rhs)
| neg(Exp arg)
| inc(str name, int inc)
| cond(Exp condition, Exp thenExp, Exp elseExp)
;

The Exp syntax allows for expression all JVM bytecode expression stackmachine operations but with a nested recursive syntax that is closer to programming languages.

  • with load, name resolution is limited to local variables and parameter names.
  • method invocation always requires the full method signature.
  • field access and update also require the full class name and field name.
  • about invokving methods:
    • invokeStatic must be used when invoking methods with the static modifier.
    • invokeSpecial can be used when no dynamic dispatch is needed, or searching superclasses is required, and you know which class implements the method. Use this to invoke a method for efficiency's sake. The invocation is type-checked at class load time.
    • invokeVirtual should be used if you do need dynamic dispatch, or the method is implemented in a superclass, and this is not a default method of an interface, use this invocation method. You need to be sure the method exists somewhere reachable from the \class reference type. The invocation is type-checked at class load time.
    • invokeInterface is for invoking methods you know only from interfaces, such as default methods. The method can even be absent at runtime in which case this throws a RuntimeException. The type-check occurs at the first invocation at run-time.
    • invokeDynamic is very special. It generates a new call site at run-time using a static "bootstrap" method, then caches the site and invokes it. Depending on the semantics of the bootstrap method the call site has the samen semantics or a different semantics the next time it is invoked.
      • The first type in desc of `invokeDynamic must be the receiver type if the method is not static.
      • The first argument in args is then also the receiver itself and not one of the method's arguments.

data Instruction

The JVM low-level instruction set

data Instruction  
= LABEL(str label)
| LINENUMBER(int line, str label)
| LOCALVARIABLE(str name, Type \type, str \start, str end, int var)
| TRYCATCH(Type \type, str \start, str end, str handler)
| NOP()
| ACONST_NULL()
| ICONST_M1()
| ICONST_0()
| ICONST_1()
| ICONST_2()
| ICONST_3()
| ICONST_4()
| ICONST_5()
| LCONST_0()
| LCONST_1()
| FCONST_0()
| FCONST_1()
| FCONST_2()
| DCONST_0()
| DCONST_1()
| IALOAD()
| LALOAD()
| FALOAD()
| DALOAD()
| AALOAD()
| BALOAD()
| CALOAD()
| SALOAD()
| IASTORE()
| LASTORE()
| FASTORE()
| DASTORE()
| AASTORE()
| BASTORE()
| CASTORE()
| SASTORE()
| POP()
| POP2()
| DUP()
| DUP_X1()
| DUP_X2()
| DUP2()
| DUP2_X1()
| DUP2_X2()
| SWAP()
| IADD()
| LADD()
| FADD()
| DADD()
| ISUB()
| LSUB()
| FSUB()
| DSUB()
| IMUL()
| LMUL()
| FMUL()
| DMUL()
| IDIV()
| LDIV()
| FDIV()
| DDIV()
| IREM()
| LREM()
| FREM()
| DREM()
| INEG()
| LNEG()
| FNEG()
| DNEG()
| ISHL()
| LSHL()
| ISHR()
| LSHR()
| IUSHR()
| LUSHR()
| IAND()
| LAND()
| IOR()
| LOR()
| IXOR()
| LXOR()
| I2L()
| I2F()
| I2D()
| L2I()
| L2F()
| L2D()
| F2I()
| F2L()
| F2D()
| D2I()
| D2L()
| D2F()
| I2B()
| I2C()
| I2S()
| LCMP()
| FCMPL()
| FCMPG()
| DCMPL()
| DCMPG()
| IRETURN()
| LRETURN()
| FRETURN()
| DRETURN()
| ARETURN()
| RETURN()
| ARRAYLENGTH()
| ATHROW()
| MONITORENTER()
| MONITOREXIT()
| ILOAD(int var)
| LLOAD(int var)
| FLOAD(int var)
| DLOAD(int var)
| ALOAD(int var)
| ISTORE(int var)
| LSTORE(int var)
| FSTORE(int var)
| DSTORE(int var)
| ASTORE(int var)
| RET(int var)
| BIPUSH(int val)
| SIPUSH(int val)
| NEWARRAY(Type element)
| LDC(Type \type, value constant)
| IINC(int var, int inc)
| IFEQ(str label)
| IFNE(str label)
| IFLT(str label)
| IFGE(str label)
| IFGT(str label)
| IFLE(str label)
| IF_ICMPEQ(str label)
| IF_ICMPNE(str label)
| IF_ICMPLT(str label)
| IF_ICMPGE(str label)
| IF_ICMPGT(str label)
| IF_ICMPLE(str label)
| IF_ACMPEQ(str label)
| IF_ACMPNE(str label)
| GOTO(str label)
| JSR(str label)
| IFNULL(str label)
| IFNONNULL(str label)
| TABLESWITCH(int min, int max, str defaultLabel, list[str] labels)
| LOOKUPSWITCH(str defaultLabel, list[int] keys, list[str] labels)
| GETSTATIC(Type class, str name, Type \type)
| PUTSTATIC(Type class, str name, Type \type)
| GETFIELD(Type class, str name, Type \type)
| PUTFIELD(Type class, str name, Type \type)
| INVOKEVIRTUAL(Type class, Signature desc, bool isInterface)
| INVOKESPECIAL(Type class, Signature desc, bool isInterface)
| INVOKESTATIC(Type class, Signature desc, bool isInterface)
| INVOKEINTERFACE(Type class, Signature desc, bool isInterface)
| INVOKEDYNAMIC(Signature desc, BootstrapCall handle)
| NEW(Type \type)
| ANEWARRAY(Type \type)
| CHECKCAST(Type \type)
| INSTANCEOF(Type \type)
| MULTIANEWARRAY(Type \type, int numDimensions)
| exp(Exp expression, str label="")
| stat(Stat statement, str label="")
;

function defVal

Exp defVal(boolean())

Exp defVal(integer())

Exp defVal(long())

Exp defVal(byte())

Exp defVal(character())

Exp defVal(short())

Exp defVal(float())

Exp defVal(double())

Exp defVal(object(str _))

Exp defVal(array(Type _))

Exp defVal(string())

function object

Object is the top of the JVMs type system

Type object()

function incr

Generates name+=i;

Stat incr(str name, int i)

function invokeSuper

Generates super(f1, f2); for a given anonymous constructor of type (F1 f1, F2 f2)

Stat invokeSuper(list[Type] formals, list[Exp] args)

function invokeSuper

Generates super();

Stat invokeSuper()

function main

Generates a main method public static final void main(String[] args) { block }

Method main(str args, list[Stat] block)

function method

Short-hand for generating a normal method

Method method(Modifier access, Type ret, str name, list[Formal] args, list[Stat] block)

function method

Short-hand for generating a normal public method

Method method(Type ret, str name, list[Formal] args, list[Stat] block)

function staticMethod

Short-hand for generating a static method

Method staticMethod(Modifier access, Type ret, str name, list[Formal] args, list[Stat] block)

function staticMethod

Short-hand for generating a public static method

Method staticMethod(Type ret, str name, list[Formal] args, list[Stat] block)

function constructor

Short-hand for generating a constructor.

Method constructor(Modifier access, list[Formal] formals, list[Stat] block)

Pitfalls

Don't forgot to generate a super call.

function new

"new" short-hand with parameters

Exp new(Type class, list[Type] argTypes, list[Exp] args)

function new

"new" short-hand, without parameters

Exp new(Type class)

function this

Load the standard "this" reference for every object.

Exp this()

Pitfalls

This works only inside non-static methods and inside constructors

function current

the <current> class refers to the class currently being compiled, for convenience's sake.

Type current()

function getField

Load a field from the currently compiled class

Exp getField(Type \type, str name)

function getStatic

Load a static field from the currently compiled class

Exp getStatic(Type \type, str name)

function putField

Store a field in the currently compiled class

Stat putField(Type \type, str name, Exp arg)

function putStatic

Store a static field in the currently defined class

Stat putStatic(Type \type, str name, Exp arg)

function invokeStatic

Invoke a static method on the currently defined class

Exp invokeStatic(Signature desc, list[Exp] args)

function invokeSpecial

Invoke a method on the currently defined class using invokeSpecial

Exp invokeSpecial(Exp receiver, Signature desc, list[Exp] args)

function invokeVirtual

Invoke a method on the currently defined class using invokeVirtual

Exp invokeVirtual(Exp receiver, Signature desc, list[Exp] args)

function invokeInterface

Invoke a method on the currently defined interface using invokeInterface

Exp invokeInterface(Exp receiver, Signature desc, list[Exp] args)

function iconst

Exp iconst(int i)

function sconst

Exp sconst(int i)

function bconst

Exp bconst(int i)

function cconst

Exp cconst(int i)

function zconst

Exp zconst(bool i)

function jconst

Exp jconst(int i)

function sconst

Exp sconst(str i)

function dconst

Exp dconst(real i)

function fconst

Exp fconst(real i)

data BootstrapCall

A bootstrap handle is a name of a static method (as defined by its host class, its name and its type signature), and a list of "constant" arguments.

data BootstrapCall  
= bootstrap(Type class, Signature desc, list[CallSiteInfo] args)
;

These constant arguments can be used to declare properties of the call site which can then be used by the bootstrap method to define in which way the dynamic call must be resolved. So these argument help to avoid having to define a combinatorially large number of bootstrap methods (one for each call site situation).

It's advisable to use the convenience function below to create a BootstrapCall instance:

  • bootstrap(Type class, str name, list[BootstrapInfo] args)

That function makes sure to line up the additional information in the extra arguments about the call site with the static type of the static bootstrap method.

function bootstrap

generate a bootstrap call with all the required standard parameters, and optionally more.

BootstrapCall bootstrap(Type class, str name, list[CallSiteInfo] args)

Benefits

  • A raw BootstrapCall must return a CallSite and take a MethodHandle.Lookup, a string and a MethodType as the first three parameters.
    This convenience function guarantees that this the true, but allows for adding additional static information about the call site.
  • The types of the additional parameters are inferred automatically from the CallSiteInfo structures, so you do not have to distribute this information during code generation.

Pitfalls

  • the signature of the bootstrap method name in class (which you might have written in Java, or generated in a different part of your compiler) must be the exactly the same as generated here.

function bootstrap

Generate a basic bootstrap caller with only the minimally required information for a dynamic invoke.

BootstrapCall bootstrap(str name, list[CallSiteInfo] args)

Benefits

This is the starting point for any use of invokeDynamic. Get this working first and add additional information later

Pitfalls

Writing bootstrap method implementations is hard.

function bootstrapMethod

Convenience function to use existing BootstrapCall information to generate a fitting bootstrap method to call.

Method bootstrapMethod(BootstrapCall b, list[Stat] body)

This function mirrors the bootstrap function; it generates the method referenced by the output of that function.

Benefits

  • the bootstrap method and the bootstrapCall information have to be aligned perfectly. If you use the pair of functions bootstrapMethod and bootstrap together then this alignment is guaranteed.

Pitfalls

  • generating the body of a bootstrap method can be challenging. It is recommended to first write the example in Java and decompile the resulting method, and copy the result into the body parameter of this function.
  • another solution is to keep the source of the bootstrap method completely in Java, but making sure the signatures keep matching inside the BootstrapCall data. This is usually possible; when the bootstrap method is generic enough.

data CallSiteInfo

data CallSiteInfo  
= stringInfo(str s)
| classInfo(str name)
| integerInfo(int i)
| longInfo(int l)
| floatInfo(real f)
| doubleInfo(real d)
| methodTypeInfo(Signature desc)
| virtualHandle(Type class, str name, Signature desc)
| specialHandle(Type class, str name, Signature desc, Type caller)
| getterHandle(Type class, str name, Type \type)
| setterHandle(Type class, str name, Type \type)
| staticGetterHandle(Type class, str name, Type \type)
| staticSetterHandle(Type class, str name, Type \type)
| constructorHandle(Type class, Signature desc)
;

function callsiteInfoType

Type inference for callsiteInfo parameters to bootstrap methods.

Type callsiteInfoType(stringInfo(_))

Type callsiteInfoType(classInfo(_))

Type callsiteInfoType(integerInfo(_))

Type callsiteInfoType(longInfo(_))

Type callsiteInfoType(floatInfo(_))

Type callsiteInfoType(doubleInfo(_))

Type callsiteInfoType(virtualHandle(_,_,_))

Type callsiteInfoType(specialHandle(_,_,_,_))

Type callsiteInfoType(getterHandle(_,_,_))

Type callsiteInfoType(setterHandle(_,_,_))

Type callsiteInfoType(staticGetterHandle(_,_,_))

Type callsiteInfoType(staticSetterHandle(_,_,_))

Type callsiteInfoType(constructorHandle(_,_))

Type callsiteInfoType(methodTypeInfo(_))