Class SyntheticMethodCallBuilder

java.lang.Object
org.ek9lang.compiler.phase7.synthesis.support.SyntheticMethodCallBuilder

public final class SyntheticMethodCallBuilder extends Object
Fluent builder for generating method and constructor call IR instructions.

Replaces the 6+ overloaded generateMethodCall methods and generateConstructorCall variants with a self-documenting fluent API.

Method call examples:

// No-arg method call
new SyntheticMethodCallBuilder(typeLinkage)
    .on(target, targetType)
    .method("_isSet")
    .returning(booleanType)
    .into(resultVar)
    .build(ctx);

// Single-arg method call
new SyntheticMethodCallBuilder(typeLinkage)
    .on(target, targetType)
    .method("_eq")
    .arg(otherVar, otherType)
    .returning(booleanType)
    .into(resultVar)
    .build(ctx);

// Trait call (invokeinterface)
new SyntheticMethodCallBuilder(typeLinkage)
    .on(fieldVar, traitType)
    .method("_isSet")
    .returning(booleanType)
    .traitCall()
    .into(resultVar)
    .build(ctx);

// Void method call (no result variable)
new SyntheticMethodCallBuilder(typeLinkage)
    .on(target, targetType)
    .method("_unSet")
    .returning(voidType)
    .buildVoid(ctx);

// Super call (uses invokespecial, not invokevirtual)
new SyntheticMethodCallBuilder(typeLinkage)
    .onSuper(superType)
    .method("_eq")
    .arg(paramVar, superType)
    .returning(booleanType)
    .into(resultVar)
    .build(ctx);

// Static call
new SyntheticMethodCallBuilder(typeLinkage)
    .onStatic(stringType)
    .method("_of")
    .arg(primitiveVar, "java.lang.String")
    .returning(stringType)
    .into(resultVar)
    .build(ctx);

Constructor call examples:

// No-arg constructor
new SyntheticMethodCallBuilder(typeLinkage).forConstructor()
    .type(booleanType)
    .into(resultVar)
    .build(ctx);

// Constructor with args
new SyntheticMethodCallBuilder(typeLinkage).forConstructor()
    .type(bitsType)
    .arg(emptyStringVar, stringType)
    .into(resultVar)
    .build(ctx);

The builder handles CALL + RETAIN + SCOPE_REGISTER automatically, skipping memory management for primitive return types (boolean, int, void).

  • Constructor Details

    • SyntheticMethodCallBuilder

      public SyntheticMethodCallBuilder(TypeLinkage typeLinkage)
      A builder for a method call; forConstructor() makes it a constructor call.
      Parameters:
      typeLinkage - THE answer to "is the type this call names externally linked" (isExternTarget)
  • Method Details

    • forConstructor

      public SyntheticMethodCallBuilder forConstructor()
      Make this a constructor call (<init>); call it first, before the type and arguments.
      Returns:
      This builder
    • on

      public SyntheticMethodCallBuilder on(String target, String targetType)
      Set the target object and its type for an instance method call.

      The call will use invokevirtual unless traitCall() or onSuper(String) is used.

      Parameters:
      target - The variable to call the method on (e.g., "this", "param", a temp)
      targetType - The fully qualified type name of the target
      Returns:
      This builder
    • on

      public SyntheticMethodCallBuilder on(String target, ISymbol targetTypeSymbol)
      The same target, but named by its resolved SYMBOL so the dispatch flag can be derived from it.

      The builder otherwise holds only a type NAME, and so had to decide isVirtualCall from the call SHAPE alone - which made every this.m() virtual, including on closed types. A closed enum's synthesised _inc() rendered this._isSet() as virtual while the same operator on the same type rendered non-virtual everywhere else. Openness is a property of the type, so pass the symbol wherever the caller holds one; sites that do not are left on the shape-only answer rather than being given a fabricated default.

      Parameters:
      target - The variable to call the method on
      targetTypeSymbol - The target's type as a resolved symbol - supplies BOTH the emitted name and the dispatch flag, so the two cannot disagree
      Returns:
      This builder
    • onSuper

      public SyntheticMethodCallBuilder onSuper(String superType)
      Set the target as "super" for a super method call.

      Super calls use invokespecial (not invokevirtual) to bypass virtual dispatch.

      Parameters:
      superType - The fully qualified type name of the super class
      Returns:
      This builder
    • onStatic

      public SyntheticMethodCallBuilder onStatic(String staticType)
      Set up for a static method call (no target object).
      Parameters:
      staticType - The fully qualified type name containing the static method
      Returns:
      This builder
    • type

      public SyntheticMethodCallBuilder type(String typeName)
      Set the type for a constructor call.
      Parameters:
      typeName - The fully qualified type name to construct
      Returns:
      This builder
    • method

      public SyntheticMethodCallBuilder method(String name)
      Set the method name to call.
      Parameters:
      name - The method name (e.g., "_eq", "_cmp", "_isSet")
      Returns:
      This builder
    • arg

      public SyntheticMethodCallBuilder arg(String argVar, String argType)
      Add a single argument to the method call.
      Parameters:
      argVar - The argument variable name
      argType - The fully qualified type of the argument
      Returns:
      This builder
    • args

      public SyntheticMethodCallBuilder args(List<String> argVars, List<String> argTypes)
      Add multiple arguments to the method call.
      Parameters:
      argVars - The argument variable names
      argTypes - The fully qualified types of the arguments
      Returns:
      This builder
    • returning

      public SyntheticMethodCallBuilder returning(String type)
      Set the return type of the method.
      Parameters:
      type - The fully qualified return type name
      Returns:
      This builder
    • into

      Set the variable to store the result into.
      Parameters:
      var - The result variable name
      Returns:
      This builder
    • traitCall

      public SyntheticMethodCallBuilder traitCall()
      Mark this as a trait call (uses invokeinterface instead of invokevirtual).
      Returns:
      This builder
    • boundToNamedType

      public SyntheticMethodCallBuilder boundToNamedType()
      Run the NAMED type's own implementation, even when the receiver's class overrides it (D38) - see CallDetails. Needs the target as a SYMBOL (on(String, ISymbol)): only a call that would otherwise dispatch (an open type) is marked; a call to a closed type is already bound to it, so it is left as it is.
      Returns:
      This builder
    • traitCallIf

      public SyntheticMethodCallBuilder traitCallIf(boolean condition)
      Mark this as a trait call only when the condition holds - use when the receiver may or may not be a trait (e.g. a field whose type is a trait needs INVOKEINTERFACE, otherwise INVOKEVIRTUAL). Pass TraitCall.requiredForValue(field).
      Parameters:
      condition - true if the receiver type is a trait
      Returns:
      This builder
    • build

      public List<IRInstr> build(SynthesisScope ctx)
      Build the IR instructions for this call using a SynthesisScope context.

      Generates CALL + RETAIN + SCOPE_REGISTER for non-primitive return types. For primitive return types (boolean, int), only CALL is generated.

      Parameters:
      ctx - The synthesis scope providing debugInfo and scopeId
      Returns:
      List of IR instructions for the call
    • build

      public List<IRInstr> build(DebugInfo debugInfo, String scopeId)
      Build the IR instructions for this call using explicit debugInfo and scopeId.
      Parameters:
      debugInfo - Debug information for the instructions
      scopeId - Current scope ID for memory management
      Returns:
      List of IR instructions for the call
    • buildCall

      public IRInstr buildCall(DebugInfo debugInfo)
      The call instruction alone, for a caller that states the result's owner itself.
      Parameters:
      debugInfo - debug information
      Returns:
      the CALL or CALL_STATIC
    • buildReturning

      public List<IRInstr> buildReturning(String returnVariable, SynthesisScope ctx)
      Build the call and hand its result straight to the returning variable: the result is made for rtn and nothing else, so it is moved there (OwnershipStatements.returnFresh(String, String, DebugInfo)) rather than registered with the scope and copied. Nothing may read the result after this.
      Parameters:
      returnVariable - the returning variable, empty here
      ctx - the synthesis scope providing debugInfo and scopeId
      Returns:
      the call and the move into the returning variable
    • buildReturning

      public List<IRInstr> buildReturning(String returnVariable, DebugInfo debugInfo, String scopeId)
      buildReturning(String, SynthesisScope) with explicit debugInfo and scopeId.
    • buildVoid

      public List<IRInstr> buildVoid(SynthesisScope ctx)
      Build the IR instructions for a void method call using a SynthesisScope context.

      Equivalent to setting resultVar to null and building. No RETAIN or SCOPE_REGISTER is emitted.

      Parameters:
      ctx - The synthesis scope providing debugInfo and scopeId
      Returns:
      List of IR instructions for the void call
    • buildVoid

      public List<IRInstr> buildVoid(DebugInfo debugInfo, String scopeId)
      Build the IR instructions for a void method call using explicit debugInfo and scopeId.

      Equivalent to setting resultVar to null and building. No RETAIN or SCOPE_REGISTER is emitted.

      Parameters:
      debugInfo - Debug information for the instructions
      scopeId - Current scope ID for memory management
      Returns:
      List of IR instructions for the void call