Search in sources :

Example 1 with BindingIfStatement

use of dyvilx.tools.compiler.ast.statement.BindingIfStatement in project Dyvil by Dyvil.

the class OptionalChainAware method nullCoalescing.

static IValue nullCoalescing(IValue lhs, IValue rhs) {
    BindingIfStatement bindingIf;
    if (lhs instanceof BindingIfStatement && (bindingIf = (BindingIfStatement) lhs).getElse() == NullValue.NULL) {
        // safe bet that the rhs used to be an optional chain
        // this branch is actually an optimization and technically not necessary, but it is very common
        // to use the null coalescing operator after an optional chain.
        final IValue then = bindingIf.getThen();
        if (NullableType.isNullable(then.getType())) {
            // Perform the following transformation:
            // if let $0 = oldReceiver { $0.oldAccess } else null
            // becomes
            // if (let $0 = oldReceiver, let $1 = $0.oldAccess) { $1 } else { <rhs> }
            final Variable var = newVar(bindingIf.getPosition(), then);
            bindingIf.addVariable(var);
            bindingIf.setThen(new FieldAccess(var));
        }
        // if the then branch of the old binding if is not nullable, we simply set the rhs
        bindingIf.setElse(rhs);
        return bindingIf;
    }
    // the lhs was not an optional chain, so we set up an impromptu null coalescing inline implementation
    final SourcePosition position = lhs.getPosition();
    // let l = <lhs>
    final Variable var = newVar(position, lhs);
    // if let l = <lhs> { l } else { <rhs> }
    bindingIf = new BindingIfStatement(position);
    bindingIf.addVariable(var);
    bindingIf.setThen(new FieldAccess(var));
    bindingIf.setElse(rhs);
    return bindingIf;
}
Also used : BindingIfStatement(dyvilx.tools.compiler.ast.statement.BindingIfStatement) IValue(dyvilx.tools.compiler.ast.expression.IValue) Variable(dyvilx.tools.compiler.ast.field.Variable) SourcePosition(dyvil.source.position.SourcePosition) FieldAccess(dyvilx.tools.compiler.ast.expression.access.FieldAccess)

Example 2 with BindingIfStatement

use of dyvilx.tools.compiler.ast.statement.BindingIfStatement in project Dyvil by Dyvil.

the class IfStatementParser method addDataMember.

@Override
public void addDataMember(IVariable dataMember) {
    BindingIfStatement statement;
    if (!(this.statement instanceof BindingIfStatement)) {
        this.statement = statement = new BindingIfStatement(this.statement.getPosition());
    } else {
        statement = (BindingIfStatement) this.statement;
    }
    this.lastVariable = dataMember;
    statement.addVariable(dataMember);
}
Also used : BindingIfStatement(dyvilx.tools.compiler.ast.statement.BindingIfStatement)

Example 3 with BindingIfStatement

use of dyvilx.tools.compiler.ast.statement.BindingIfStatement in project Dyvil by Dyvil.

the class OptionalChainAware method transform.

static IValue transform(OptionalChainAware oca) {
    // oca = receiver?.access
    // <- oco ->
    final IValue oco = oca.getReceiver();
    if (oco == null || oco.valueTag() != IValue.OPTIONAL_CHAIN) {
        // no transformation needed as it is actually not an optional chain
        return oca;
    }
    final SourcePosition position = oca.getPosition();
    final IValue receiver = ((OptionalChainOperator) oco).getReceiver();
    // receiver is now the actual receiver of the optional chain operator
    BindingIfStatement bindingIf;
    if (receiver instanceof BindingIfStatement && (bindingIf = (BindingIfStatement) receiver).getElse() == NullValue.NULL) {
        // safe bet that the receiver used to be an optional chain
        // Perform the following transformation (the entire statement is the receiver):
        // if let $0 = oldReceiver { $0.oldAccess } else null
        // becomes
        // if (let $0 = oldReceiver, let $1 = $0.oldAccess) { $1.access } else null
        final Variable var = newVar(position, bindingIf.getThen());
        bindingIf.addVariable(var);
        oca.setReceiver(new FieldAccess(var));
        bindingIf.setThen(oca);
        return bindingIf;
    }
    // oca = receiver?.access, and receiver is not an optional chain
    // receiver?.access
    // becomes
    // if let $0 = receiver { $0.access } else null
    final Variable var = newVar(position, receiver);
    bindingIf = new BindingIfStatement(position);
    bindingIf.addVariable(var);
    oca.setReceiver(new FieldAccess(var));
    bindingIf.setThen(oca);
    bindingIf.setElse(NullValue.NULL);
    return bindingIf;
}
Also used : BindingIfStatement(dyvilx.tools.compiler.ast.statement.BindingIfStatement) IValue(dyvilx.tools.compiler.ast.expression.IValue) Variable(dyvilx.tools.compiler.ast.field.Variable) SourcePosition(dyvil.source.position.SourcePosition) FieldAccess(dyvilx.tools.compiler.ast.expression.access.FieldAccess)

Aggregations

BindingIfStatement (dyvilx.tools.compiler.ast.statement.BindingIfStatement)3 SourcePosition (dyvil.source.position.SourcePosition)2 IValue (dyvilx.tools.compiler.ast.expression.IValue)2 FieldAccess (dyvilx.tools.compiler.ast.expression.access.FieldAccess)2 Variable (dyvilx.tools.compiler.ast.field.Variable)2