Code review comment: Still, I am a bit unclear about this approach. As I understood what we have to do is, if first arg and expr are the same, we need to desugar either first arg or expr. If the first arg desugared via QueryDesugar it becomes a new node. So after the L:6411 can't we just assign `invocation.expr = invocation.requiredArgs.get(0)` if isExprAndRequiredArgSame is true and remove rest of the changes?  Please check whether this works.

Code before review:
private BLangBlockStmt desugarForeachToWhile(BLangForeach foreach, BLangSimpleVariableDef varDef) {
BVarSymbol iteratorSymbol = varDef.var.symbol;
BVarSymbol resultSymbol = new BVarSymbol(0, names.fromString("$result$"), this.env.scope.owner.pkgID,
foreach.nillableResultType, this.env.scope.owner, foreach.pos,
VIRTUAL);
BLangSimpleVariableDef resultVariableDefinition = getIteratorNextVariableDefinition(foreach.pos,
foreach.nillableResultType, iteratorSymbol, resultSymbol);
BLangSimpleVarRef resultReferenceInWhile = ASTBuilderUtil.createVariableRef(foreach.pos, resultSymbol);
BLangStatementExpression statementExpression = ASTBuilderUtil.createStatementExpression(
resultVariableDefinition, resultReferenceInWhile);
statementExpression.setBType(foreach.nillableResultType);
BLangType userDefineType = getUserDefineTypeNode(foreach.resultType);
BLangTypeTestExpr typeTestExpr = ASTBuilderUtil
.createTypeTestExpr(foreach.pos, statementExpression, userDefineType);
BLangWhile whileNode = (BLangWhile) TreeBuilder.createWhileNode();
whileNode.pos = foreach.pos;
whileNode.expr = typeTestExpr;
whileNode.body = foreach.body;
VariableDefinitionNode variableDefinitionNode = foreach.variableDefinitionNode;
BLangFieldBasedAccess valueAccessExpr = getValueAccessExpression(foreach.pos, foreach.varType, resultSymbol);
BLangExpression expr = valueAccessExpr.expr;
valueAccessExpr.expr = addConversionExprIfRequired(expr, symTable.mapAllType);
variableDefinitionNode.getVariable()
.setInitialExpression(addConversionExprIfRequired(valueAccessExpr, foreach.varType));
whileNode.body.stmts.add(0, (BLangStatement) variableDefinitionNode);
BLangBlockStmt blockNode = ASTBuilderUtil.createBlockStmt(foreach.pos);
blockNode.addStatement(varDef);
blockNode.addStatement(whileNode);
return blockNode;
}
private BLangType getUserDefineTypeNode(BType type) {
BLangUserDefinedType recordType =
new BLangUserDefinedType(ASTBuilderUtil.createIdentifier(null, ""),
ASTBuilderUtil.createIdentifier(null, ""));
recordType.setBType(type);
return recordType;
}
@Override
public void visit(BLangWhile whileNode) {
if (whileNode.onFailClause != null) {
BLangOnFailClause onFailClause = whileNode.onFailClause;
whileNode.onFailClause = null;
whileNode.body.failureBreakMode = BLangBlockStmt.FailureBreakMode.NOT_BREAKABLE;
BLangDo doStmt = wrapStatementWithinDo(whileNode.pos, whileNode, onFailClause);
result = rewrite(doStmt, env);
} else {
whileNode.expr = rewriteExpr(whileNode.expr);
whileNode.body = rewrite(whileNode.body, env);
result = whileNode;
}
}
private BLangDo wrapStatementWithinDo(Location location, BLangStatement statement,
BLangOnFailClause onFailClause) {
BLangDo bLDo = (BLangDo) TreeBuilder.createDoNode();
BLangBlockStmt doBlock = ASTBuilderUtil.createBlockStmt(location);
doBlock.scope = new Scope(env.scope.owner);
bLDo.body = doBlock;
bLDo.pos = location;
bLDo.onFailClause = onFailClause;
bLDo.body.failureBreakMode = BLangBlockStmt.FailureBreakMode.BREAK_TO_OUTER_BLOCK;
doBlock.stmts.add(statement);
return bLDo;
}
@Override
public void visit(BLangLock lockNode) {
BLangOnFailClause currentOnFailClause = this.onFailClause;
BLangBlockStmt blockStmt = ASTBuilderUtil.createBlockStmt(lockNode.pos);
if (lockNode.onFailClause != null) {
blockStmt.failureBreakMode = BLangBlockStmt.FailureBreakMode.BREAK_TO_OUTER_BLOCK;
rewrite(lockNode.onFailClause, env);
}
BLangLockStmt lockStmt = new BLangLockStmt(lockNode.pos);
blockStmt.addStatement(lockStmt);
enclLocks.push(lockStmt);
BLangLiteral nilLiteral = ASTBuilderUtil.createLiteral(lockNode.pos, symTable.nilType, Names.NIL_VALUE);
BType nillableError = BUnionType.create(null, symTable.errorType, symTable.nilType);
BLangStatementExpression statementExpression = createStatementExpression(lockNode.body, nilLiteral);
statementExpression.setBType(symTable.nilType);
BLangTrapExpr trapExpr = (BLangTrapExpr) TreeBuilder.createTrapExpressionNode();
trapExpr.setBType(nillableError);
trapExpr.expr = statementExpression;
BVarSymbol nillableErrorVarSymbol = new BVarSymbol(0, names.fromString("$errorResult"),
this.env.scope.owner.pkgID, nillableError,
this.env.scope.owner, lockNode.pos, VIRTUAL);
BLangSimpleVariable simpleVariable = ASTBuilderUtil.createVariable(lockNode.pos, "$errorResult",
nillableError, trapExpr,
nillableErrorVarSymbol);
BLangSimpleVariableDef simpleVariableDef = ASTBuilderUtil.createVariableDef(lockNode.pos, simpleVariable);
blockStmt.addStatement(simpleVariableDef);
BLangUnLockStmt unLockStmt = new BLangUnLockStmt(lockNode.pos);
unLockStmt.relatedLock = lockStmt;
blockStmt.addStatement(unLockStmt);
BLangSimpleVarRef varRef = ASTBuilderUtil.createVariableRef(lockNode.pos, nillableErrorVarSymbol);
BLangBlockStmt ifBody = ASTBuilderUtil.createBlockStmt(lockNode.pos);
BLangPanic panicNode = (BLangPanic) TreeBuilder.createPanicNode();
panicNode.pos = lockNode.pos;
panicNode.expr = addConversionExprIfRequired(varRef, symTable.errorType);
ifBody.addStatement(panicNode);
BLangTypeTestExpr isErrorTest =
ASTBuilderUtil.createTypeTestExpr(lockNode.pos, varRef, getErrorTypeNode());
isErrorTest.setBType(symTable.booleanType);
BLangIf ifelse = ASTBuilderUtil.createIfElseStmt(lockNode.pos, isErrorTest, ifBody, null);
blockStmt.addStatement(ifelse);
result = rewrite(blockStmt, env);
enclLocks.pop();
this.onFailClause = currentOnFailClause;
}
@Override
public void visit(BLangLockStmt lockStmt) {
result = lockStmt;
}
@Override
public void visit(BLangUnLockStmt unLockStmt) {
result = unLockStmt;
}
private BLangOnFailClause createTrxInternalOnFail(Location pos, BLangSimpleVarRef shouldPanicRef,
BLangSimpleVarRef shouldRetryRef) {
BLangOnFailClause trxOnFailClause = (BLangOnFailClause) TreeBuilder.createOnFailClauseNode();
trxOnFailClause.pos = pos;
trxOnFailClause.body = ASTBuilderUtil.createBlockStmt(pos);
trxOnFailClause.body.scope = new Scope(env.scope.owner);
trxOnFailClause.isInternal = true;
BVarSymbol trxOnFailErrorSym = new BVarSymbol(0, names.fromString("$trxError$"),
env.scope.owner.pkgID, symTable.errorType, env.scope.owner, pos, VIRTUAL);
BLangSimpleVariable trxOnFailError = ASTBuilderUtil.createVariable(pos,
"$trxError$", symTable.errorType, null, trxOnFailErrorSym);
trxOnFailClause.variableDefinitionNode = ASTBuilderUtil.createVariableDef(pos,
trxOnFailError);
trxOnFailClause.body.scope.define(trxOnFailErrorSym.name, trxOnFailErrorSym);
transactionDesugar.createRollbackIfFailed(pos, trxOnFailClause.body, trxOnFailErrorSym,
trxBlockId, shouldRetryRef);
BLangGroupExpr shouldNotPanic = new BLangGroupExpr();
shouldNotPanic.setBType(symTable.booleanType);
shouldNotPanic.expression = createNotBinaryExpression(pos, shouldPanicRef);
BLangSimpleVarRef caughtError =  ASTBuilderUtil.createVariableRef(pos, trxOnFailErrorSym);
BLangBlockStmt failBlock = ASTBuilderUtil.createBlockStmt(pos);
BLangPanic panicNode = (BLangPanic) TreeBuilder.createPanicNode();
panicNode.pos = pos;
panicNode.expr = caughtError;
BLangIf exitIf = ASTBuilderUtil.createIfElseStmt(pos, shouldNotPanic, failBlock, panicNode);
trxOnFailClause.body.stmts.add(exitIf);
BLangFail failStmt = (BLangFail) TreeBuilder.createFailNode();
failStmt.pos = pos;
failStmt.expr = caughtError;
failBlock.stmts.add(failStmt);
trxOnFailClause.bodyContainsFail = true;
return trxOnFailClause;
}
@Override
public void visit(BLangTransaction transactionNode) {
if (transactionNode.onFailClause != null) {
BLangOnFailClause onFailClause = transactionNode.onFailClause;
transactionNode.onFailClause = null;
transactionNode.transactionBody.failureBreakMode = BLangBlockStmt.FailureBreakMode.NOT_BREAKABLE;
BLangDo doStmt = wrapStatementWithinDo(transactionNode.pos, transactionNode, onFailClause);
result = rewrite(doStmt, env);
} else {
BLangLiteral currentTrxBlockId = this.trxBlockId;
String uniqueId = String.valueOf(++transactionBlockCount);
this.trxBlockId = ASTBuilderUtil.createLiteral(transactionNode.pos, symTable.stringType, uniqueId);
boolean currShouldReturnErrors = this.shouldReturnErrors;
this.shouldReturnErrors = true;
BLangOnFailClause currOnFailClause = this.onFailClause;
BLangLiteral falseLiteral = ASTBuilderUtil.createLiteral(transactionNode.pos, symTable.booleanType, false);
BVarSymbol shouldPanicVarSymbol = new BVarSymbol(0, names.fromString("$shouldPanic$"),
env.scope.owner.pkgID, symTable.booleanType, this.env.scope.owner, transactionNode.pos, VIRTUAL);
shouldPanicVarSymbol.closure = true;
BLangSimpleVariable shouldPanicVariable = ASTBuilderUtil.createVariable(transactionNode.pos,
"$shouldPanic$", symTable.booleanType, falseLiteral, shouldPanicVarSymbol);
BLangSimpleVariableDef shouldPanicDef = ASTBuilderUtil.createVariableDef(transactionNode.pos,
shouldPanicVariable);
BLangSimpleVarRef shouldPanicRef = ASTBuilderUtil.createVariableRef(transactionNode.pos,
shouldPanicVarSymbol);
BLangOnFailClause trxInternalOnFail = createTrxInternalOnFail(transactionNode.pos, shouldPanicRef,
this.shouldRetryRef);
enclosingShouldPanic.put(trxInternalOnFail, shouldPanicRef);
boolean userDefinedOnFailAvbl = this.onFailClause != null;
analyzeOnFailClause(trxInternalOnFail, transactionNode.transactionBody);
BLangBlockStmt transactionStmtBlock =
transactionDesugar.rewrite(transactionNode, trxBlockId, env, uniqueId);
transactionStmtBlock.stmts.add(0, shouldPanicDef);
transactionStmtBlock.scope.define(shouldPanicVarSymbol.name, shouldPanicVarSymbol);
transactionStmtBlock.failureBreakMode = userDefinedOnFailAvbl ?
BLangBlockStmt.FailureBreakMode.NOT_BREAKABLE :
BLangBlockStmt.FailureBreakMode.BREAK_TO_OUTER_BLOCK;
result = rewrite(transactionStmtBlock, this.env);
this.shouldReturnErrors = currShouldReturnErrors;
this.trxBlockId = currentTrxBlockId;
swapAndResetEnclosingOnFail(currOnFailClause);
}
}
@Override
public void visit(BLangRollback rollbackNode) {
BLangBlockStmt rollbackStmtExpr = transactionDesugar.desugar(rollbackNode, trxBlockId, this.shouldRetryRef);
result = rewrite(rollbackStmtExpr, env);
}
private BLangOnFailClause createRetryInternalOnFail(Location pos,
BLangSimpleVarRef retryResultRef,
BLangSimpleVarRef retryManagerRef,
BLangSimpleVarRef shouldRetryRef,
BLangSimpleVarRef continueLoopRef,
BLangSimpleVarRef returnResult) {
BLangOnFailClause internalOnFail = (BLangOnFailClause) TreeBuilder.createOnFailClauseNode();
internalOnFail.pos = pos;
internalOnFail.body = ASTBuilderUtil.createBlockStmt(pos);
internalOnFail.body.scope = new Scope(env.scope.owner);
BVarSymbol caughtErrorSym = new BVarSymbol(0, names.fromString("$caughtError$"),
env.scope.owner.pkgID, symTable.errorType, env.scope.owner, pos, VIRTUAL);
BLangSimpleVariable caughtError = ASTBuilderUtil.createVariable(pos,
"$caughtError$", symTable.errorType, null, caughtErrorSym);
internalOnFail.variableDefinitionNode = ASTBuilderUtil.createVariableDef(pos,
caughtError);
env.scope.define(caughtErrorSym.name, caughtErrorSym);
BLangSimpleVarRef caughtErrorRef = ASTBuilderUtil.createVariableRef(pos, caughtErrorSym);
BLangAssignment errorAssignment = ASTBuilderUtil.createAssignmentStmt(pos, retryResultRef, caughtErrorRef);
internalOnFail.body.stmts.add(errorAssignment);
BLangAssignment continueLoopTrue = ASTBuilderUtil.createAssignmentStmt(pos, continueLoopRef,
ASTBuilderUtil.createLiteral(pos, symTable.booleanType, true));
internalOnFail.body.stmts.add(continueLoopTrue);
BLangInvocation shouldRetryInvocation = createRetryManagerShouldRetryInvocation(pos,
retryManagerRef, caughtErrorRef);
BLangAssignment shouldRetryAssignment = ASTBuilderUtil.createAssignmentStmt(pos, shouldRetryRef,
shouldRetryInvocation);
internalOnFail.body.stmts.add(shouldRetryAssignment);
BLangGroupExpr shouldNotRetryCheck = new BLangGroupExpr();
shouldNotRetryCheck.setBType(symTable.booleanType);
shouldNotRetryCheck.expression = createNotBinaryExpression(pos, shouldRetryRef);
BLangGroupExpr exitCheck = new BLangGroupExpr();
exitCheck.setBType(symTable.booleanType);
exitCheck.expression = shouldNotRetryCheck;
BLangBlockStmt exitLogicBlock = ASTBuilderUtil.createBlockStmt(pos);
BLangIf exitIf = ASTBuilderUtil.createIfElseStmt(pos, exitCheck, exitLogicBlock, null);
if (this.onFailClause != null) {
BLangFail failStmt = (BLangFail) TreeBuilder.createFailNode();
failStmt.pos = pos;
failStmt.expr = retryResultRef;
exitLogicBlock.stmts.add(failStmt);
internalOnFail.bodyContainsFail = true;
internalOnFail.body.stmts.add(exitIf);
BLangContinue loopContinueStmt = (BLangContinue) TreeBuilder.createContinueNode();
loopContinueStmt.pos = pos;
internalOnFail.body.stmts.add(loopContinueStmt);
} else {
BLangAssignment returnErrorTrue = ASTBuilderUtil.createAssignmentStmt(pos, returnResult,
ASTBuilderUtil.createLiteral(pos, symTable.booleanType, true));
exitLogicBlock.stmts.add(returnErrorTrue);
internalOnFail.body.stmts.add(exitIf);
}
return internalOnFail;
}
BLangUnaryExpr createNotBinaryExpression(Location pos, BLangExpression expression) {
List<BType> paramTypes = new ArrayList<>();
paramTypes.add(symTable.booleanType);
BInvokableType type = new BInvokableType(paramTypes, symTable.booleanType,
null);
BOperatorSymbol notOperatorSymbol = new BOperatorSymbol(
names.fromString(OperatorKind.NOT.value()), symTable.rootPkgSymbol.pkgID, type, symTable.rootPkgSymbol,
symTable.builtinPos, VIRTUAL);
return ASTBuilderUtil.createUnaryExpr(pos, expression, symTable.booleanType,
OperatorKind.NOT, notOperatorSymbol);
}
BLangLambdaFunction createLambdaFunction(Location pos, String functionNamePrefix,
List<BLangSimpleVariable> lambdaFunctionVariable,
TypeNode returnType, BLangFunctionBody lambdaBody) {
BLangLambdaFunction lambdaFunction = (BLangLambdaFunction) TreeBuilder.createLambdaFunctionNode();
BLangFunction func =
ASTBuilderUtil.createFunction(pos, functionNamePrefix + UNDERSCORE + lambdaFunctionCount++);
lambdaFunction.function = func;
func.requiredParams.addAll(lambdaFunctionVariable);
func.setReturnTypeNode(returnType);
func.desugaredReturnType = true;
defineFunction(func, env.enclPkg);
lambdaFunctionVariable = func.requiredParams;
func.body = lambdaBody;
func.desugared = false;
lambdaFunction.pos = pos;
List<BType> paramTypes = new ArrayList<>();
lambdaFunctionVariable.forEach(variable -> paramTypes.add(variable.symbol.type));
lambdaFunction.setBType(new BInvokableType(paramTypes, func.symbol.type.getReturnType(),
null));
return lambdaFunction;
}
protected BLangLambdaFunction createLambdaFunction(Location pos, String functionNamePrefix,
List<BLangSimpleVariable> lambdaFunctionVariable,
TypeNode returnType, List<BLangStatement> fnBodyStmts,
SymbolEnv env, Scope bodyScope) {
BLangBlockFunctionBody body = (BLangBlockFunctionBody) TreeBuilder.createBlockFunctionBodyNode();
body.scope = bodyScope;
SymbolEnv bodyEnv = SymbolEnv.createFuncBodyEnv(body, env);
body.stmts = rewriteStmt(fnBodyStmts, bodyEnv);
return createLambdaFunction(pos, functionNamePrefix, lambdaFunctionVariable, returnType, body);
}
private void defineFunction(BLangFunction funcNode, BLangPackage targetPkg) {
final BPackageSymbol packageSymbol = targetPkg.symbol;
final SymbolEnv packageEnv = this.symTable.pkgEnvMap.get(packageSymbol);
symbolEnter.defineNode(funcNode, packageEnv);
packageEnv.enclPkg.functions.add(funcNode);
packageEnv.enclPkg.topLevelNodes.add(funcNode);
}
@Override
public void visit(BLangForkJoin forkJoin) {
result = forkJoin;
}
@Override
public void visit(BLangLiteral literalExpr) {
if (literalExpr.getBType().tag == TypeTags.ARRAY
&& ((BArrayType) literalExpr.getBType()).eType.tag == TypeTags.BYTE) {
result = rewriteBlobLiteral(literalExpr);
return;
}
result = literalExpr;
}
private BLangNode rewriteBlobLiteral(BLangLiteral literalExpr) {
String[] result = getBlobTextValue((String) literalExpr.value);
byte[] values;
if (BASE_64.equals(result[0])) {
values = Base64.getDecoder().decode(result[1].getBytes(StandardCharsets.UTF_8));
} else {
values = hexStringToByteArray(result[1]);
}
BLangArrayLiteral arrayLiteralNode = (BLangArrayLiteral) TreeBuilder.createArrayLiteralExpressionNode();
arrayLiteralNode.setBType(literalExpr.getBType());
arrayLiteralNode.pos = literalExpr.pos;
arrayLiteralNode.exprs = new ArrayList<>();
for (byte b : values) {
arrayLiteralNode.exprs.add(createByteLiteral(literalExpr.pos, b));
}
return arrayLiteralNode;
}
private String[] getBlobTextValue(String blobLiteralNodeText) {
String nodeText = blobLiteralNodeText.replace("\t", "").replace("\n", "").replace("\r", "")
.replace(" ", "");
String[] result = new String[2];
result[0] = nodeText.substring(0, nodeText.indexOf('`'));
result[1] = nodeText.substring(nodeText.indexOf('`') + 1, nodeText.lastIndexOf('`'));
return result;
}
private static byte[] hexStringToByteArray(String str) {
int len = str.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(str.charAt(i), 16) << 4) + Character.digit(str.charAt(i + 1), 16));
}
return data;
}
@Override
public void visit(BLangListConstructorSpreadOpExpr listConstructorSpreadOpExpr) {
listConstructorSpreadOpExpr.expr = rewriteExpr(listConstructorSpreadOpExpr.expr);
result = listConstructorSpreadOpExpr;
}
@Override
public void visit(BLangListConstructorExpr listConstructor) {
listConstructor.exprs = rewriteExprs(listConstructor.exprs);
BLangExpression expr;
BType listConstructorType = Types.getReferredType(listConstructor.getBType());
if (listConstructorType.tag == TypeTags.TUPLE) {
expr = new BLangTupleLiteral(listConstructor.pos, listConstructor.exprs, listConstructor.getBType());
result = rewriteExpr(expr);
} else if (listConstructorType.tag == TypeTags.JSON) {
expr = new BLangJSONArrayLiteral(listConstructor.exprs, new BArrayType(listConstructor.getBType()));
result = rewriteExpr(expr);
} else if (getElementType(listConstructorType).tag == TypeTags.JSON) {
expr = new BLangJSONArrayLiteral(listConstructor.exprs, listConstructor.getBType());
result = rewriteExpr(expr);
} else if (listConstructorType.tag == TypeTags.TYPEDESC) {
final BLangTypedescExpr typedescExpr = new BLangTypedescExpr();
typedescExpr.resolvedType = listConstructor.typedescType;
typedescExpr.setBType(symTable.typeDesc);
result = rewriteExpr(typedescExpr);
} else {
expr = new BLangArrayLiteral(listConstructor.pos, listConstructor.exprs, listConstructor.getBType());
result = rewriteExpr(expr);
}
}
@Override
public void visit(BLangTableConstructorExpr tableConstructorExpr) {
rewriteExprs(tableConstructorExpr.recordLiteralList);
result = tableConstructorExpr;
}
@Override
public void visit(BLangArrayLiteral arrayLiteral) {
arrayLiteral.exprs = rewriteExprs(arrayLiteral.exprs);
BType arrayLiteralType = Types.getReferredType(arrayLiteral.getBType());
if (arrayLiteralType.tag == TypeTags.JSON) {
result = new BLangJSONArrayLiteral(arrayLiteral.exprs, new BArrayType(arrayLiteral.getBType()));
return;
} else if (getElementType(arrayLiteralType).tag == TypeTags.JSON) {
result = new BLangJSONArrayLiteral(arrayLiteral.exprs, arrayLiteral.getBType());
return;
}
result = arrayLiteral;
}
@Override
public void visit(BLangTupleLiteral tupleLiteral) {
if (tupleLiteral.isTypedescExpr) {
final BLangTypedescExpr typedescExpr = new BLangTypedescExpr();
typedescExpr.resolvedType = tupleLiteral.typedescType;
typedescExpr.setBType(symTable.typeDesc);
result = rewriteExpr(typedescExpr);
return;
}
List<BLangExpression> exprs = tupleLiteral.exprs;
BTupleType tupleType = (BTupleType) tupleLiteral.getBType();
List<BType> tupleMemberTypes = tupleType.tupleTypes;
int tupleMemberTypeSize = tupleMemberTypes.size();
int tupleExprSize = exprs.size();
boolean isInRestType = false;
int i = 0;
for (BLangExpression expr: exprs) {
if (expr.getKind() == NodeKind.LIST_CONSTRUCTOR_SPREAD_OP) {
BType spreadOpType = ((BLangListConstructorSpreadOpExpr) expr).expr.getBType();
spreadOpType = Types.getReferredType(spreadOpType);
if (spreadOpType.tag == TypeTags.ARRAY) {
BArrayType spreadOpBArray = (BArrayType) spreadOpType;
if (spreadOpBArray.size >= 0) {
i += spreadOpBArray.size;
continue;
}
} else {
BTupleType spreadOpTuple = (BTupleType) spreadOpType;
if (types.isFixedLengthTuple(spreadOpTuple)) {
i += spreadOpTuple.tupleTypes.size();
continue;
}
}
isInRestType = true;
continue;
}
BType expType = expr.impConversionExpr == null ? expr.getBType() : expr.impConversionExpr.getBType();
BType targetType = tupleType.restType;
if (!isInRestType && i < tupleMemberTypeSize) {
targetType = tupleMemberTypes.get(i);
}
types.setImplicitCastExpr(expr, expType, targetType);
i++;
}
tupleLiteral.exprs = rewriteExprs(tupleLiteral.exprs);
result = tupleLiteral;
}
@Override
public void visit(BLangGroupExpr groupExpr) {
result = rewriteExpr(groupExpr.expression);
}
@Override
public void visit(BLangRecordLiteral recordLiteral) {
List<RecordLiteralNode.RecordField> fields =  recordLiteral.fields;
fields.sort((v1, v2) -> Boolean.compare(isComputedKey(v1), isComputedKey(v2)));
result = rewriteExpr(rewriteMappingConstructor(recordLiteral));
}
@Override
public void visit(BLangSimpleVarRef varRefExpr) {
BLangSimpleVarRef genVarRefExpr = varRefExpr;
if (varRefExpr.pkgSymbol != null && varRefExpr.pkgSymbol.tag == SymTag.XMLNS) {
BLangXMLQName qnameExpr = new BLangXMLQName(varRefExpr.variableName);
qnameExpr.nsSymbol = (BXMLNSSymbol) varRefExpr.pkgSymbol;
qnameExpr.localname = varRefExpr.variableName;
qnameExpr.prefix = varRefExpr.pkgAlias;
qnameExpr.namespaceURI = qnameExpr.nsSymbol.namespaceURI;
qnameExpr.isUsedInXML = false;
qnameExpr.pos = varRefExpr.pos;
qnameExpr.setBType(symTable.stringType);
result = qnameExpr;
return;
}
if (varRefExpr.symbol == null) {
result = varRefExpr;
return;
}
if ((varRefExpr.symbol.tag & SymTag.VARIABLE) == SymTag.VARIABLE) {
BVarSymbol varSymbol = (BVarSymbol) varRefExpr.symbol;
if (varSymbol.originalSymbol != null) {
varRefExpr.symbol = varSymbol.originalSymbol;
}
}
BType type = varRefExpr.getBType();
BSymbol ownerSymbol = varRefExpr.symbol.owner;
if ((varRefExpr.symbol.tag & SymTag.FUNCTION) == SymTag.FUNCTION &&
Types.getReferredType(varRefExpr.symbol.type).tag == TypeTags.INVOKABLE) {
genVarRefExpr = new BLangFunctionVarRef((BVarSymbol) varRefExpr.symbol);
} else if ((varRefExpr.symbol.tag & SymTag.TYPE) == SymTag.TYPE &&
!((varRefExpr.symbol.tag & SymTag.CONSTANT) == SymTag.CONSTANT)) {
genVarRefExpr = new BLangTypeLoad(varRefExpr.symbol);
if (varRefExpr.symbol.tag == SymTag.TYPE_DEF) {
type = ((BTypeDefinitionSymbol) varRefExpr.symbol).referenceType;
}
} else if ((ownerSymbol.tag & SymTag.INVOKABLE) == SymTag.INVOKABLE ||
(ownerSymbol.tag & SymTag.LET) == SymTag.LET) {
genVarRefExpr = new BLangLocalVarRef((BVarSymbol) varRefExpr.symbol);
} else if ((ownerSymbol.tag & SymTag.STRUCT) == SymTag.STRUCT) {
genVarRefExpr = new BLangFieldVarRef((BVarSymbol) varRefExpr.symbol);
} else if ((ownerSymbol.tag & SymTag.PACKAGE) == SymTag.PACKAGE ||
(ownerSymbol.tag & SymTag.SERVICE) == SymTag.SERVICE) {
if ((varRefExpr.symbol.tag & SymTag.CONSTANT) == SymTag.CONSTANT) {
BConstantSymbol constSymbol = (BConstantSymbol) varRefExpr.symbol;
BType referredType = Types.getReferredType(constSymbol.literalType);
if (referredType.tag <= TypeTags.BOOLEAN || referredType.tag == TypeTags.NIL) {
BLangLiteral literal = ASTBuilderUtil.createLiteral(varRefExpr.pos, constSymbol.literalType,
constSymbol.value.value);
result = rewriteExpr(addConversionExprIfRequired(literal, varRefExpr.getBType()));
return;
}
}
genVarRefExpr = new BLangPackageVarRef((BVarSymbol) varRefExpr.symbol);
if (!enclLocks.isEmpty()) {
BVarSymbol symbol = (BVarSymbol) varRefExpr.symbol;
BLangLockStmt lockStmt = enclLocks.peek();
lockStmt.addLockVariable(symbol);
lockStmt.addLockVariable(this.globalVariablesDependsOn.getOrDefault(symbol, new HashSet<>()));
}
}
genVarRefExpr.setBType(type);
genVarRefExpr.pos = varRefExpr.pos;
if ((varRefExpr.isLValue)
|| genVarRefExpr.symbol.name.equals(IGNORE)) {
genVarRefExpr.isLValue = varRefExpr.isLValue;
genVarRefExpr.setBType(varRefExpr.symbol.type);
result = genVarRefExpr;
return;
}
genVarRefExpr.isLValue = varRefExpr.isLValue;
BType targetType = genVarRefExpr.getBType();
genVarRefExpr.setBType(genVarRefExpr.symbol.type);
BLangExpression expression = addConversionExprIfRequired(genVarRefExpr, targetType);
result = expression.impConversionExpr != null ? expression.impConversionExpr : expression;
}
@Override
public void visit(BLangFieldBasedAccess.BLangNSPrefixedFieldBasedAccess nsPrefixedFieldBasedAccess) {
rewriteFieldBasedAccess(nsPrefixedFieldBasedAccess);
}
private void rewriteFieldBasedAccess(BLangFieldBasedAccess fieldAccessExpr) {
if (safeNavigate(fieldAccessExpr)) {
result = rewriteExpr(rewriteSafeNavigationExpr(fieldAccessExpr));
return;
}
BLangAccessExpression targetVarRef = fieldAccessExpr;
BType varRefType = types.getTypeWithEffectiveIntersectionTypes(fieldAccessExpr.expr.getBType());
fieldAccessExpr.expr = rewriteExpr(fieldAccessExpr.expr);
if (!types.isSameType(fieldAccessExpr.expr.getBType(), varRefType)) {
fieldAccessExpr.expr = addConversionExprIfRequired(fieldAccessExpr.expr, varRefType);
}
BLangLiteral stringLit = createStringLiteral(fieldAccessExpr.field.pos,
StringEscapeUtils.unescapeJava(fieldAccessExpr.field.value));
BType refType = Types.getReferredType(varRefType);
int varRefTypeTag = refType.tag;
if (varRefTypeTag == TypeTags.OBJECT ||
(varRefTypeTag == TypeTags.UNION &&
((BUnionType) refType).getMemberTypes().iterator().next().tag == TypeTags.OBJECT)) {
if (fieldAccessExpr.symbol != null && fieldAccessExpr.symbol.type.tag == TypeTags.INVOKABLE &&
((fieldAccessExpr.symbol.flags & Flags.ATTACHED) == Flags.ATTACHED)) {
result = rewriteObjectMemberAccessAsField(fieldAccessExpr);
return;
} else {
boolean isStoreOnCreation = fieldAccessExpr.isStoreOnCreation;
if (!isStoreOnCreation && varRefTypeTag == TypeTags.OBJECT && env.enclInvokable != null) {
BInvokableSymbol originalFuncSymbol = ((BLangFunction) env.enclInvokable).originalFuncSymbol;
BObjectTypeSymbol objectTypeSymbol = (BObjectTypeSymbol) refType.tsymbol;
BAttachedFunction initializerFunc = objectTypeSymbol.initializerFunc;
BAttachedFunction generatedInitializerFunc = objectTypeSymbol.generatedInitializerFunc;
if ((generatedInitializerFunc != null && originalFuncSymbol == generatedInitializerFunc.symbol) ||
(initializerFunc != null && originalFuncSymbol == initializerFunc.symbol)) {
isStoreOnCreation = true;
}
}
targetVarRef = new BLangStructFieldAccessExpr(fieldAccessExpr.pos, fieldAccessExpr.expr, stringLit,
(BVarSymbol) fieldAccessExpr.symbol, false,
isStoreOnCreation);
}
} else if (varRefTypeTag == TypeTags.RECORD ||
(varRefTypeTag == TypeTags.UNION &&
((BUnionType) refType).getMemberTypes().iterator().next().tag == TypeTags.RECORD)) {
if (fieldAccessExpr.symbol != null && fieldAccessExpr.symbol.type.tag == TypeTags.INVOKABLE
&& ((fieldAccessExpr.symbol.flags & Flags.ATTACHED) == Flags.ATTACHED)) {
targetVarRef = new BLangStructFunctionVarRef(fieldAccessExpr.expr, (BVarSymbol) fieldAccessExpr.symbol);
} else {
targetVarRef = new BLangStructFieldAccessExpr(fieldAccessExpr.pos, fieldAccessExpr.expr, stringLit,
(BVarSymbol) fieldAccessExpr.symbol, false, fieldAccessExpr.isStoreOnCreation);
}
} else if (types.isLax(refType)) {
if (!(refType.tag == TypeTags.XML || refType.tag == TypeTags.XML_ELEMENT)) {
if (refType.tag == TypeTags.MAP && TypeTags.isXMLTypeTag(((BMapType) refType).constraint.tag)) {
result = rewriteExpr(rewriteLaxMapAccess(fieldAccessExpr));
return;
}
fieldAccessExpr.expr = addConversionExprIfRequired(fieldAccessExpr.expr, symTable.jsonType);
targetVarRef = new BLangJSONAccessExpr(fieldAccessExpr.pos, fieldAccessExpr.expr, stringLit);
} else {
BLangInvocation xmlAccessInvocation = rewriteXMLAttributeOrElemNameAccess(fieldAccessExpr);
xmlAccessInvocation.setBType(fieldAccessExpr.getBType());
result = xmlAccessInvocation;
return;
}
} else if (varRefTypeTag == TypeTags.MAP) {
targetVarRef = new BLangMapAccessExpr(fieldAccessExpr.pos, fieldAccessExpr.expr, stringLit,
fieldAccessExpr.isStoreOnCreation);
} else if (TypeTags.isXMLTypeTag(varRefTypeTag)) {
targetVarRef = new BLangXMLAccessExpr(fieldAccessExpr.pos, fieldAccessExpr.expr, stringLit,
fieldAccessExpr.fieldKind);
}
targetVarRef.isLValue = fieldAccessExpr.isLValue;
targetVarRef.setBType(fieldAccessExpr.getBType());
targetVarRef.optionalFieldAccess = fieldAccessExpr.optionalFieldAccess;
result = targetVarRef;
}
@Override
public void visit(BLangFieldBasedAccess fieldAccessExpr) {
rewriteFieldBasedAccess(fieldAccessExpr);
}
private BLangNode rewriteObjectMemberAccessAsField(BLangFieldBasedAccess fieldAccessExpr) {
Location pos = fieldAccessExpr.pos;
BInvokableSymbol originalMemberFuncSymbol = (BInvokableSymbol) fieldAccessExpr.symbol;
BLangFunction func = (BLangFunction) TreeBuilder.createFunctionNode();
String funcName = "$anon$method$delegate$" + originalMemberFuncSymbol.name.value + "$" + lambdaFunctionCount++;
BInvokableSymbol funcSymbol = new BInvokableSymbol(SymTag.INVOKABLE, (Flags.ANONYMOUS | Flags.LAMBDA),
Names.fromString(funcName), env.enclPkg.packageID,
originalMemberFuncSymbol.type, env.scope.owner, pos,
VIRTUAL);
funcSymbol.retType = originalMemberFuncSymbol.retType;
funcSymbol.bodyExist = true;
funcSymbol.params = new ArrayList<>();
funcSymbol.scope = new Scope(funcSymbol);
func.pos = pos;
func.name = createIdentifier(pos, funcName);
func.flagSet.add(Flag.LAMBDA);
func.flagSet.add(Flag.ANONYMOUS);
func.body = (BLangBlockFunctionBody) TreeBuilder.createBlockFunctionBodyNode();
func.symbol = funcSymbol;
func.setBType(funcSymbol.type);
func.closureVarSymbols = new LinkedHashSet<>();
BLangExpression receiver = fieldAccessExpr.expr;
BLangSimpleVariableDef intermediateObjDef = null;
if (receiver.getKind() == NodeKind.SIMPLE_VARIABLE_REF) {
BSymbol receiverSymbol = ((BLangVariableReference) receiver).symbol;
receiverSymbol.closure = true;
func.closureVarSymbols.add(new ClosureVarSymbol(receiverSymbol, pos));
} else {
BLangSimpleVariableDef varDef = createVarDef("$$temp$obj$" + annonVarCount++, receiver.getBType(),
receiver, pos);
intermediateObjDef = varDef;
varDef.var.symbol.closure = true;
env.scope.define(varDef.var.symbol.name, varDef.var.symbol);
BLangSimpleVarRef variableRef = createVariableRef(pos, varDef.var.symbol);
func.closureVarSymbols.add(new ClosureVarSymbol(varDef.var.symbol, pos));
receiver = variableRef;
}
ArrayList<BLangExpression> requiredArgs = new ArrayList<>();
for (BVarSymbol param : originalMemberFuncSymbol.params) {
BLangSimpleVariable fParam = (BLangSimpleVariable) TreeBuilder.createSimpleVariableNode();
fParam.symbol = new BVarSymbol(0, param.name, env.enclPkg.packageID, param.type,  funcSymbol, pos,
VIRTUAL);
fParam.pos = pos;
fParam.name = createIdentifier(pos, param.name.value);
fParam.setBType(param.type);
func.requiredParams.add(fParam);
funcSymbol.params.add(fParam.symbol);
funcSymbol.scope.define(fParam.symbol.name, fParam.symbol);
BLangSimpleVarRef paramRef = createVariableRef(pos, fParam.symbol);
requiredArgs.add(paramRef);
}
ArrayList<BLangExpression> restArgs = new ArrayList<>();
if (originalMemberFuncSymbol.restParam != null) {
BLangSimpleVariable restParam = (BLangSimpleVariable) TreeBuilder.createSimpleVariableNode();
func.restParam = restParam;
BVarSymbol restSym = originalMemberFuncSymbol.restParam;
restParam.name = ASTBuilderUtil.createIdentifier(pos, restSym.name.value);
restParam.symbol = new BVarSymbol(0, restSym.name, env.enclPkg.packageID, restSym.type, funcSymbol, pos,
VIRTUAL);
restParam.pos = pos;
restParam.setBType(restSym.type);
funcSymbol.restParam = restParam.symbol;
funcSymbol.scope.define(restParam.symbol.name, restParam.symbol);
BLangSimpleVarRef restArg = createVariableRef(pos, restParam.symbol);
BLangRestArgsExpression restArgExpr = new BLangRestArgsExpression();
restArgExpr.expr = restArg;
restArgExpr.pos = pos;
restArgExpr.setBType(restSym.type);
restArgExpr.expectedType = restArgExpr.getBType();
restArgs.add(restArgExpr);
}
BLangIdentifier field = fieldAccessExpr.field;
BLangReturn retStmt = (BLangReturn) TreeBuilder.createReturnNode();
retStmt.expr = createObjectMethodInvocation(
receiver, field, fieldAccessExpr.symbol, requiredArgs, restArgs);
((BLangBlockFunctionBody) func.body).addStatement(retStmt);
BLangLambdaFunction lambdaFunction = (BLangLambdaFunction) TreeBuilder.createLambdaFunctionNode();
lambdaFunction.function = func;
lambdaFunction.capturedClosureEnv = env.createClone();
env.enclPkg.functions.add(func);
env.enclPkg.topLevelNodes.add(func);
lambdaFunction.parent = env.enclInvokable;
lambdaFunction.setBType(func.getBType());
if (intermediateObjDef == null) {
return rewrite(lambdaFunction, env);
} else {
BLangStatementExpression expr = createStatementExpression(intermediateObjDef, rewrite(lambdaFunction, env));
expr.setBType(lambdaFunction.getBType());
return rewrite(expr, env);
}
}
private BLangInvocation createObjectMethodInvocation(BLangExpression receiver, BLangIdentifier field,
BSymbol invocableSymbol,
List<BLangExpression> requiredArgs,
List<BLangExpression> restArgs) {
BLangInvocation invocationNode = (BLangInvocation) TreeBuilder.createInvocationNode();
invocationNode.name = field;
invocationNode.pkgAlias = (BLangIdentifier) TreeBuilder.createIdentifierNode();
invocationNode.expr = receiver;
invocationNode.symbol = invocableSymbol;
invocationNode.setBType(((BInvokableType) invocableSymbol.type).retType);
invocationNode.requiredArgs = requiredArgs;
invocationNode.restArgs = restArgs;
return invocationNode;
}
private BLangStatementExpression rewriteLaxMapAccess(BLangFieldBasedAccess fieldAccessExpr) {
BLangStatementExpression statementExpression = new BLangStatementExpression();
BLangBlockStmt block = new BLangBlockStmt();
statementExpression.stmt = block;
BUnionType fieldAccessType = BUnionType.create(null, fieldAccessExpr.getBType(), symTable.errorType);
Location pos = fieldAccessExpr.pos;
BLangSimpleVariableDef result = createVarDef("$mapAccessResult$", fieldAccessType, null, pos);
block.addStatement(result);
BLangSimpleVarRef resultRef = ASTBuilderUtil.createVariableRef(pos, result.var.symbol);
resultRef.setBType(fieldAccessType);
statementExpression.setBType(fieldAccessType);
BLangLiteral mapIndex = ASTBuilderUtil.createLiteral(
fieldAccessExpr.field.pos, symTable.stringType, fieldAccessExpr.field.value);
BLangMapAccessExpr mapAccessExpr = new BLangMapAccessExpr(pos, fieldAccessExpr.expr, mapIndex);
BUnionType xmlOrNil = BUnionType.create(null, fieldAccessExpr.getBType(), symTable.nilType);
mapAccessExpr.setBType(xmlOrNil);
BLangSimpleVariableDef mapResult = createVarDef("$mapAccess", xmlOrNil, mapAccessExpr, pos);
BLangSimpleVarRef mapResultRef = ASTBuilderUtil.createVariableRef(pos, mapResult.var.symbol);
block.addStatement(mapResult);
BLangIf ifStmt = ASTBuilderUtil.createIfStmt(pos, block);
BLangIsLikeExpr isLikeNilExpr = createIsLikeExpression(pos, mapResultRef, symTable.nilType);
ifStmt.expr = isLikeNilExpr;
BLangBlockStmt resultNilBody = new BLangBlockStmt();
ifStmt.body = resultNilBody;
BLangBlockStmt resultHasValueBody = new BLangBlockStmt();
ifStmt.elseStmt = resultHasValueBody;
BLangErrorConstructorExpr errorConstructorExpr =
(BLangErrorConstructorExpr) TreeBuilder.createErrorConstructorExpressionNode();
BSymbol symbol = symResolver.lookupMainSpaceSymbolInPackage(errorConstructorExpr.pos, env,
names.fromString(""), names.fromString("error"));
errorConstructorExpr.setBType(symbol.type);
List<BLangExpression> positionalArgs = new ArrayList<>();
List<BLangNamedArgsExpression> namedArgs = new ArrayList<>();
positionalArgs.add(createStringLiteral(pos, "{" + RuntimeConstants.MAP_LANG_LIB + "}InvalidKey"));
BLangNamedArgsExpression message = new BLangNamedArgsExpression();
message.name = ASTBuilderUtil.createIdentifier(pos, "key");
message.expr = createStringLiteral(pos, fieldAccessExpr.field.value);
namedArgs.add(message);
errorConstructorExpr.positionalArgs = positionalArgs;
errorConstructorExpr.namedArgs = namedArgs;
BLangSimpleVariableDef errorDef =
createVarDef("$_invalid_key_error", symTable.errorType, errorConstructorExpr, pos);
resultNilBody.addStatement(errorDef);
BLangSimpleVarRef errorRef = ASTBuilderUtil.createVariableRef(pos, errorDef.var.symbol);
BLangAssignment errorVarAssignment = ASTBuilderUtil.createAssignmentStmt(pos, resultNilBody);
errorVarAssignment.varRef = resultRef;
errorVarAssignment.expr = errorRef;
BLangAssignment mapResultAssignment = ASTBuilderUtil.createAssignmentStmt(
pos, resultHasValueBody);
mapResultAssignment.varRef = resultRef;
mapResultAssignment.expr = mapResultRef;
statementExpression.expr = resultRef;
return statementExpression;
}
private BLangInvocation rewriteXMLAttributeOrElemNameAccess(BLangFieldBasedAccess fieldAccessExpr) {
ArrayList<BLangExpression> args = new ArrayList<>();
String fieldName = fieldAccessExpr.field.value;
if (fieldAccessExpr.fieldKind == FieldKind.WITH_NS) {
BLangFieldBasedAccess.BLangNSPrefixedFieldBasedAccess nsPrefixAccess =
(BLangFieldBasedAccess.BLangNSPrefixedFieldBasedAccess) fieldAccessExpr;
fieldName = createExpandedQName(nsPrefixAccess.nsSymbol.namespaceURI, fieldName);
}
if (fieldName.equals("_")) {
return createLanglibXMLInvocation(fieldAccessExpr.pos, XML_INTERNAL_GET_ELEMENT_NAME_NIL_LIFTING,
fieldAccessExpr.expr, new ArrayList<>(), new ArrayList<>());
}
BLangLiteral attributeNameLiteral = createStringLiteral(fieldAccessExpr.field.pos, fieldName);
args.add(attributeNameLiteral);
args.add(isOptionalAccessToLiteral(fieldAccessExpr));
return createLanglibXMLInvocation(fieldAccessExpr.pos, XML_INTERNAL_GET_ATTRIBUTE, fieldAccessExpr.expr, args,
new ArrayList<>());
}
private BLangExpression isOptionalAccessToLiteral(BLangFieldBasedAccess fieldAccessExpr) {
return rewrite(
createLiteral(fieldAccessExpr.pos, symTable.booleanType, fieldAccessExpr.isOptionalFieldAccess()), env);
}
private String createExpandedQName(String nsURI, String localName) {
return "{" + nsURI + "}" + localName;
}
@Override
public void visit(BLangIndexBasedAccess indexAccessExpr) {
if (safeNavigate(indexAccessExpr)) {
result = rewriteExpr(rewriteSafeNavigationExpr(indexAccessExpr));
return;
}
BLangIndexBasedAccess targetVarRef = indexAccessExpr;
indexAccessExpr.indexExpr = rewriteExpr(indexAccessExpr.indexExpr);
BType effectiveType = types.getTypeWithEffectiveIntersectionTypes(indexAccessExpr.expr.getBType());
BType varRefType = Types.getReferredType(effectiveType);
indexAccessExpr.expr = rewriteExpr(indexAccessExpr.expr);
if (!types.isSameType(indexAccessExpr.expr.getBType(), varRefType)) {
indexAccessExpr.expr = addConversionExprIfRequired(indexAccessExpr.expr, varRefType);
}
if (varRefType.tag == TypeTags.MAP) {
targetVarRef = new BLangMapAccessExpr(indexAccessExpr.pos, indexAccessExpr.expr,
indexAccessExpr.indexExpr, indexAccessExpr.isStoreOnCreation);
} else if (types.isSubTypeOfMapping(types.getSafeType(varRefType, true, false))) {
targetVarRef = new BLangStructFieldAccessExpr(indexAccessExpr.pos, indexAccessExpr.expr,
indexAccessExpr.indexExpr,
(BVarSymbol) indexAccessExpr.symbol, false);
} else if (types.isSubTypeOfList(varRefType)) {
targetVarRef = new BLangArrayAccessExpr(indexAccessExpr.pos, indexAccessExpr.expr,
indexAccessExpr.indexExpr);
} else if (TypeTags.isXMLTypeTag(varRefType.tag)) {
targetVarRef = new BLangXMLAccessExpr(indexAccessExpr.pos, indexAccessExpr.expr,
indexAccessExpr.indexExpr);
} else if (types.isAssignable(varRefType, symTable.stringType)) {
indexAccessExpr.expr = addConversionExprIfRequired(indexAccessExpr.expr, symTable.stringType);
targetVarRef = new BLangStringAccessExpr(indexAccessExpr.pos, indexAccessExpr.expr,
indexAccessExpr.indexExpr);
} else if (varRefType.tag == TypeTags.TABLE) {
targetVarRef = new BLangTableAccessExpr(indexAccessExpr.pos, indexAccessExpr.expr,
indexAccessExpr.indexExpr);
}
targetVarRef.isLValue = indexAccessExpr.isLValue;
targetVarRef.setBType(indexAccessExpr.getBType());
result = targetVarRef;
}
@Override
public void visit(BLangInvocation iExpr) {
rewriteInvocation(iExpr, false);
}
@Override
public void visit(BLangErrorConstructorExpr errorConstructorExpr) {
if (errorConstructorExpr.positionalArgs.size() == 1) {
errorConstructorExpr.positionalArgs.add(createNilLiteral());
}
errorConstructorExpr.positionalArgs.set(1,
addConversionExprIfRequired(errorConstructorExpr.positionalArgs.get(1), symTable.errorType));
rewriteExprs(errorConstructorExpr.positionalArgs);
BLangExpression errorDetail;
BLangRecordLiteral recordLiteral = ASTBuilderUtil.createEmptyRecordLiteral(errorConstructorExpr.pos,
((BErrorType) Types.getReferredType(errorConstructorExpr.getBType())).detailType);
if (errorConstructorExpr.namedArgs.isEmpty()) {
errorDetail = visitCloneReadonly(rewriteExpr(recordLiteral), recordLiteral.getBType());
} else {
for (BLangNamedArgsExpression namedArg : errorConstructorExpr.namedArgs) {
BLangRecordLiteral.BLangRecordKeyValueField member = new BLangRecordLiteral.BLangRecordKeyValueField();
member.key = new BLangRecordLiteral.BLangRecordKey(ASTBuilderUtil.createLiteral(namedArg.name.pos,
symTable.stringType, namedArg.name.value));
if (Types.getReferredType(recordLiteral.getBType()).tag == TypeTags.RECORD) {
member.valueExpr = addConversionExprIfRequired(namedArg.expr, symTable.anyType);
} else {
member.valueExpr = addConversionExprIfRequired(namedArg.expr, namedArg.expr.getBType());
}
recordLiteral.fields.add(member);
}
errorDetail = visitCloneReadonly(rewriteExpr(recordLiteral),
((BErrorType) Types.getReferredType(errorConstructorExpr.getBType())).detailType);
}
errorConstructorExpr.errorDetail = errorDetail;
result = errorConstructorExpr;
}
@Override
public void visit(BLangInvocation.BLangActionInvocation actionInvocation) {
if (!actionInvocation.async && actionInvocation.invokedInsideTransaction) {
transactionDesugar.startTransactionCoordinatorOnce(env, actionInvocation.pos);
}
if (actionInvocation.async && Symbols.isFlagOn(actionInvocation.symbol.type.flags, Flags.ISOLATED)) {
addStrandAnnotationWithThreadAny(actionInvocation);
}
rewriteInvocation(actionInvocation, actionInvocation.async);
}
private void addStrandAnnotationWithThreadAny(BLangInvocation.BLangActionInvocation actionInvocation) {
if (this.strandAnnotAttachement == null) {
BLangPackage pkgNode = env.enclPkg;
List<BLangTypeDefinition> prevTypeDefinitions = new ArrayList<>(pkgNode.typeDefinitions);
this.strandAnnotAttachement =
annotationDesugar.createStrandAnnotationWithThreadAny(actionInvocation.pos, env);
addInitFunctionForRecordTypeNodeInTypeDef(pkgNode, prevTypeDefinitions);
}
actionInvocation.addAnnotationAttachment(this.strandAnnotAttachement);
((BInvokableSymbol) actionInvocation.symbol)
.addAnnotation(this.strandAnnotAttachement.annotationAttachmentSymbol);
}
private void rewriteInvocation(BLangInvocation invocation, boolean async) {
BLangInvocation invRef = invocation;
if (!enclLocks.isEmpty()) {
BLangLockStmt lock = enclLocks.peek();
lock.lockVariables.addAll(((BInvokableSymbol) invocation.symbol).dependentGlobalVars);
}
reorderArguments(invocation);
boolean isExprAndRequiredArgSame = !invocation.requiredArgs.isEmpty() &&
invocation.requiredArgs.get(0) == invocation.expr;
rewriteExprs(invocation.requiredArgs);
BLangExpression firstRequiredArg = isExprAndRequiredArgSame ? invocation.requiredArgs.get(0) : null;
fixStreamTypeCastsInInvocationParams(invocation);
fixNonRestArgTypeCastInTypeParamInvocation(invocation);
rewriteExprs(invocation.restArgs);
annotationDesugar.defineStatementAnnotations(invocation.annAttachments, invocation.pos,
invocation.symbol.pkgID, invocation.symbol.owner, env);
if (invocation.functionPointerInvocation) {
visitFunctionPointerInvocation(invocation);
return;
}
invocation.expr = isExprAndRequiredArgSame ? firstRequiredArg : invocation.expr;
invocation.expr = rewriteExpr(invocation.expr);
result = invRef;
BInvokableSymbol invSym = (BInvokableSymbol) invocation.symbol;
if (Symbols.isFlagOn(invSym.retType.flags, Flags.PARAMETERIZED)) {
BType retType = unifier.build(invSym.retType);
invocation.setBType(invocation.async ? new BFutureType(TypeTags.FUTURE, retType, null) : retType);
}
if (invocation.expr == null) {
fixTypeCastInTypeParamInvocation(invocation, invRef);
if (invocation.exprSymbol == null) {
return;
}
invocation.expr = ASTBuilderUtil.createVariableRef(invocation.pos, invocation.exprSymbol);
invocation.expr = rewriteExpr(invocation.expr);
}
switch (Types.getReferredType(invocation.expr.getBType()).tag) {
case TypeTags.OBJECT:
case TypeTags.RECORD:
if (!invocation.langLibInvocation) {
List<BLangExpression> argExprs = new ArrayList<>(invocation.requiredArgs);
argExprs.add(0, invocation.expr);
BLangAttachedFunctionInvocation attachedFunctionInvocation =
new BLangAttachedFunctionInvocation(invocation.pos, argExprs, invocation.restArgs,
invocation.symbol, invocation.getBType(),
invocation.expr, async);
attachedFunctionInvocation.name = invocation.name;
attachedFunctionInvocation.annAttachments = invocation.annAttachments;
result = invRef = attachedFunctionInvocation;
}
break;
}
if (invocation.objectInitMethod && Symbols.isFlagOn(invocation.expr.getBType().flags, Flags.OBJECT_CTOR)) {
BObjectType initializingObject = (BObjectType) invocation.expr.getBType();
BLangClassDefinition classDef = initializingObject.classDef;
if (classDef.hasClosureVars) {
OCEDynamicEnvironmentData oceEnvData = initializingObject.classDef.oceEnvData;
if (oceEnvData.attachedFunctionInvocation == null) {
oceEnvData.attachedFunctionInvocation = (BLangAttachedFunctionInvocation) result;
}
}
}
fixTypeCastInTypeParamInvocation(invocation, invRef);
}
private void fixNonRestArgTypeCastInTypeParamInvocation(BLangInvocation iExpr) {
if (!iExpr.langLibInvocation) {
return;
}
List<BLangExpression> requiredArgs = iExpr.requiredArgs;
List<BVarSymbol> params = ((BInvokableSymbol) iExpr.symbol).params;
for (int i = 0; i < requiredArgs.size(); i++) {
requiredArgs.set(i, addConversionExprIfRequired(requiredArgs.get(i), params.get(i).type));
}
}
/* This function is a workaround and need improvement
*  Notes for improvement :
*    1. Both arguments are same.
*    2. Due to current type param logic we put type param flag on the original type.
*    3. Error type having Cloneable type with type param flag, change expression type by this code.
*    4. using error type is a problem as Cloneable type is an typeparm eg: ExprBodiedFunctionTest
*       added never to CloneableType type param
*       @typeParam type
*       CloneableType Cloneable|never;
*
*/
private void fixTypeCastInTypeParamInvocation(BLangInvocation iExpr, BLangInvocation genIExpr) {
var returnTypeOfInvokable = ((BInvokableSymbol) iExpr.symbol).retType;
if (!iExpr.langLibInvocation && !TypeParamAnalyzer.containsTypeParam(returnTypeOfInvokable)) {
return;
}
BType originalInvType = genIExpr.getBType();
if (!genIExpr.async) {
genIExpr.setBType(returnTypeOfInvokable);
}
this.result = addConversionExprIfRequired(genIExpr, originalInvType);
}
private void fixStreamTypeCastsInInvocationParams(BLangInvocation iExpr) {
List<BLangExpression> requiredArgs = iExpr.requiredArgs;
List<BVarSymbol> params = ((BInvokableSymbol) iExpr.symbol).params;
if (!params.isEmpty()) {
for (int i = 0; i < requiredArgs.size(); i++) {
BVarSymbol param = params.get(i);
if (Types.getReferredType(param.type).tag == TypeTags.STREAM) {
requiredArgs.set(i, addConversionExprIfRequired(requiredArgs.get(i), param.type));
}
}
}
}
private BLangLiteral createNilLiteral() {
BLangLiteral literal = (BLangLiteral) TreeBuilder.createLiteralExpression();
literal.value = null;
literal.setBType(symTable.nilType);
return literal;
}
public void visit(BLangTypeInit typeInitExpr) {
if (Types.getReferredType(typeInitExpr.getBType()).tag == TypeTags.STREAM) {
result = rewriteExpr(desugarStreamTypeInit(typeInitExpr));
} else {
result = rewrite(desugarObjectTypeInit(typeInitExpr), env);
}
}
private BLangStatementExpression desugarObjectTypeInit(BLangTypeInit typeInitExpr) {
typeInitExpr.desugared = true;
BLangBlockStmt blockStmt = ASTBuilderUtil.createBlockStmt(typeInitExpr.pos);
BType objType = getObjectType(typeInitExpr.getBType());
BLangSimpleVariableDef objVarDef = createVarDef("$obj$", objType, typeInitExpr, typeInitExpr.pos);
objVarDef.var.name.pos = symTable.builtinPos;
BLangSimpleVarRef objVarRef = ASTBuilderUtil.createVariableRef(typeInitExpr.pos, objVarDef.var.symbol);
blockStmt.addStatement(objVarDef);
BLangInvocation typeInitInvocation = typeInitExpr.initInvocation;
typeInitInvocation.exprSymbol = objVarDef.var.symbol;
typeInitInvocation.symbol = ((BObjectTypeSymbol) objType.tsymbol).generatedInitializerFunc.symbol;
typeInitInvocation.objectInitMethod = true;
if (Types.getReferredType(typeInitInvocation.getBType()).tag == TypeTags.NIL) {
BLangExpressionStmt initInvExpr = ASTBuilderUtil.createExpressionStmt(typeInitExpr.pos, blockStmt);
initInvExpr.expr = typeInitInvocation;
typeInitInvocation.name.value = GENERATED_INIT_SUFFIX.value;
BLangStatementExpression stmtExpr = createStatementExpression(blockStmt, objVarRef);
stmtExpr.setBType(objVarRef.symbol.type);
return stmtExpr;
}
BLangSimpleVariableDef initInvRetValVarDef = createVarDef("$temp$", typeInitInvocation.getBType(),
typeInitInvocation, typeInitExpr.pos);
blockStmt.addStatement(initInvRetValVarDef);
BLangSimpleVariableDef resultVarDef = createVarDef("$result$", typeInitExpr.getBType(), null, typeInitExpr.pos);
blockStmt.addStatement(resultVarDef);
BLangSimpleVarRef initRetValVarRefInCondition =
ASTBuilderUtil.createVariableRef(symTable.builtinPos, initInvRetValVarDef.var.symbol);
BLangBlockStmt thenStmt = ASTBuilderUtil.createBlockStmt(symTable.builtinPos);
BLangTypeTestExpr isErrorTest =
ASTBuilderUtil.createTypeTestExpr(symTable.builtinPos, initRetValVarRefInCondition, getErrorTypeNode());
isErrorTest.setBType(symTable.booleanType);
BLangSimpleVarRef thenInitRetValVarRef =
ASTBuilderUtil.createVariableRef(symTable.builtinPos, initInvRetValVarDef.var.symbol);
BLangSimpleVarRef thenResultVarRef =
ASTBuilderUtil.createVariableRef(symTable.builtinPos, resultVarDef.var.symbol);
BLangAssignment errAssignment =
ASTBuilderUtil.createAssignmentStmt(symTable.builtinPos, thenResultVarRef, thenInitRetValVarRef);
thenStmt.addStatement(errAssignment);
BLangSimpleVarRef elseResultVarRef =
ASTBuilderUtil.createVariableRef(symTable.builtinPos, resultVarDef.var.symbol);
BLangAssignment objAssignment =
ASTBuilderUtil.createAssignmentStmt(symTable.builtinPos, elseResultVarRef, objVarRef);
BLangBlockStmt elseStmt = ASTBuilderUtil.createBlockStmt(symTable.builtinPos);
elseStmt.addStatement(objAssignment);
BLangIf ifelse = ASTBuilderUtil.createIfElseStmt(symTable.builtinPos, isErrorTest, thenStmt, elseStmt);
blockStmt.addStatement(ifelse);
BLangSimpleVarRef resultVarRef =
ASTBuilderUtil.createVariableRef(symTable.builtinPos, resultVarDef.var.symbol);
BLangStatementExpression stmtExpr = createStatementExpression(blockStmt, resultVarRef);
stmtExpr.setBType(resultVarRef.symbol.type);
return stmtExpr;
}
private BLangInvocation desugarStreamTypeInit(BLangTypeInit typeInitExpr) {
BInvokableSymbol symbol = (BInvokableSymbol) symTable.langInternalModuleSymbol.scope
.lookup(Names.CONSTRUCT_STREAM).symbol;
BType constraintType = ((BStreamType) typeInitExpr.getBType()).constraint;
BType constraintTdType = new BTypedescType(constraintType, symTable.typeDesc.tsymbol);
BLangTypedescExpr constraintTdExpr = new BLangTypedescExpr();
constraintTdExpr.resolvedType = constraintType;
constraintTdExpr.setBType(constraintTdType);
BType completionType = ((BStreamType) typeInitExpr.getBType()).completionType;
BType completionTdType = new BTypedescType(completionType, symTable.typeDesc.tsymbol);
BLangTypedescExpr completionTdExpr = new BLangTypedescExpr();
completionTdExpr.resolvedType = completionType;
completionTdExpr.setBType(completionTdType);
List<BLangExpression> args = new ArrayList<>(Lists.of(constraintTdExpr, completionTdExpr));
if (!typeInitExpr.argsExpr.isEmpty()) {
args.add(typeInitExpr.argsExpr.get(0));
}
BLangInvocation streamConstructInvocation = ASTBuilderUtil.createInvocationExprForMethod(
typeInitExpr.pos, symbol, args, symResolver);
streamConstructInvocation.setBType(new BStreamType(TypeTags.STREAM, constraintType, completionType, null));
return streamConstructInvocation;
}
private BLangSimpleVariableDef createVarDef(String name, BType type, BLangExpression expr,
Location location) {
BSymbol objSym = symResolver.lookupSymbolInMainSpace(env, names.fromString(name));
if (objSym == null || objSym == symTable.notFoundSymbol) {
objSym = new BVarSymbol(0, names.fromString(name), this.env.scope.owner.pkgID, type,
this.env.scope.owner, location, VIRTUAL);
}
BLangSimpleVariable objVar = ASTBuilderUtil.createVariable(location, name, type, expr, (BVarSymbol) objSym);
BLangSimpleVariableDef objVarDef = ASTBuilderUtil.createVariableDef(location);
objVarDef.var = objVar;
objVarDef.setBType(objVar.getBType());
return objVarDef;
}
private BType getObjectType(BType bType) {
BType type = Types.getReferredType(bType);
if (type.tag == TypeTags.OBJECT) {
return type;
} else if (type.tag == TypeTags.UNION) {
return ((BUnionType) type).getMemberTypes().stream()
.filter(t -> t.tag == TypeTags.OBJECT)
.findFirst()
.orElse(symTable.noType);
}
throw new IllegalStateException("None object type '" + type.toString() + "' found in object init context");
}
BLangErrorType getErrorTypeNode() {
BLangErrorType errorTypeNode = (BLangErrorType) TreeBuilder.createErrorTypeNode();
errorTypeNode.setBType(symTable.errorType);
errorTypeNode.pos = symTable.builtinPos;
return errorTypeNode;
}
BLangErrorType getErrorOrNillTypeNode() {
BLangErrorType errorTypeNode = (BLangErrorType) TreeBuilder.createErrorTypeNode();
errorTypeNode.setBType(symTable.errorOrNilType);
return errorTypeNode;
}
@Override
public void visit(BLangTernaryExpr ternaryExpr) {
/*
* First desugar to if-else:
*
* T $result$;
* if () {
*    $result$ = thenExpr;
* } else {
*    $result$ = elseExpr;
* }
*
*/
BLangSimpleVariableDef resultVarDef =
createVarDef("$ternary_result$", ternaryExpr.getBType(), null, ternaryExpr.pos);
BLangBlockStmt thenBody = ASTBuilderUtil.createBlockStmt(ternaryExpr.pos);
BLangBlockStmt elseBody = ASTBuilderUtil.createBlockStmt(ternaryExpr.pos);
BLangSimpleVarRef thenResultVarRef = ASTBuilderUtil.createVariableRef(ternaryExpr.pos, resultVarDef.var.symbol);
BLangAssignment thenAssignment =
ASTBuilderUtil.createAssignmentStmt(ternaryExpr.pos, thenResultVarRef, ternaryExpr.thenExpr);
thenBody.addStatement(thenAssignment);
BLangSimpleVarRef elseResultVarRef = ASTBuilderUtil.createVariableRef(ternaryExpr.pos, resultVarDef.var.symbol);
BLangAssignment elseAssignment =
ASTBuilderUtil.createAssignmentStmt(ternaryExpr.pos, elseResultVarRef, ternaryExpr.elseExpr);
elseBody.addStatement(elseAssignment);
BLangSimpleVarRef resultVarRef = ASTBuilderUtil.createVariableRef(ternaryExpr.pos, resultVarDef.var.symbol);
BLangIf ifElse = ASTBuilderUtil.createIfElseStmt(ternaryExpr.pos, ternaryExpr.expr, thenBody, elseBody);
BLangBlockStmt blockStmt = ASTBuilderUtil.createBlockStmt(ternaryExpr.pos, Lists.of(resultVarDef, ifElse));
BLangStatementExpression stmtExpr = createStatementExpression(blockStmt, resultVarRef);
stmtExpr.setBType(ternaryExpr.getBType());
result = rewriteExpr(stmtExpr);
}
@Override
public void visit(BLangWaitExpr waitExpr) {
if (waitExpr.getExpression().getKind() == NodeKind.BINARY_EXPR) {
waitExpr.exprList = collectAllBinaryExprs((BLangBinaryExpr) waitExpr.getExpression(), new ArrayList<>());
} else {
waitExpr.exprList = Collections.singletonList(rewriteExpr(waitExpr.getExpression()));
}
result = waitExpr;
}
private List<BLangExpression> collectAllBinaryExprs(BLangBinaryExpr binaryExpr, List<BLangExpression> exprs) {
visitBinaryExprOfWait(binaryExpr.lhsExpr, exprs);
visitBinaryExprOfWait(binaryExpr.rhsExpr, exprs);
return exprs;
}
private void visitBinaryExprOfWait(BLangExpression expr, List<BLangExpression> exprs) {
if (expr.getKind() == NodeKind.BINARY_EXPR) {
collectAllBinaryExprs((BLangBinaryExpr) expr, exprs);
} else {
expr = rewriteExpr(expr);
exprs.add(expr);
}
}
@Override
public void visit(BLangWaitForAllExpr waitExpr) {
waitExpr.keyValuePairs.forEach(keyValue -> {
if (keyValue.valueExpr != null) {
keyValue.valueExpr = rewriteExpr(keyValue.valueExpr);
} else {
keyValue.keyExpr = rewriteExpr(keyValue.keyExpr);
}
});
BLangExpression expr = new BLangWaitForAllExpr.BLangWaitLiteral(waitExpr.keyValuePairs, waitExpr.getBType());
expr.pos = waitExpr.pos;
result = rewriteExpr(expr);
}
@Override
public void visit(BLangTrapExpr trapExpr) {
trapExpr.expr = rewriteExpr(trapExpr.expr);
if (Types.getReferredType(trapExpr.expr.getBType()).tag != TypeTags.NIL) {
trapExpr.expr = addConversionExprIfRequired(trapExpr.expr, trapExpr.getBType());
}
result = trapExpr;
}
@Override
public void visit(BLangBinaryExpr binaryExpr) {
if (isNullableBinaryExpr(binaryExpr)) {
BLangStatementExpression stmtExpr = createStmtExprForNullableBinaryExpr(binaryExpr);
result = rewrite(stmtExpr, env);
return;
}
if (binaryExpr.opKind == OperatorKind.HALF_OPEN_RANGE || binaryExpr.opKind == OperatorKind.CLOSED_RANGE) {
BLangExpression lhsExpr = binaryExpr.lhsExpr;
BLangExpression rhsExpr = binaryExpr.rhsExpr;
lhsExpr = createTypeCastExpr(lhsExpr, symTable.intType);
rhsExpr = createTypeCastExpr(rhsExpr, symTable.intType);
if (binaryExpr.opKind == OperatorKind.HALF_OPEN_RANGE) {
rhsExpr = getModifiedIntRangeEndExpr(rhsExpr);
}
result = rewriteExpr(replaceWithIntRange(binaryExpr.pos, lhsExpr, rhsExpr));
return;
}
if (binaryExpr.opKind == OperatorKind.AND || binaryExpr.opKind == OperatorKind.OR) {
visitBinaryLogicalExpr(binaryExpr);
return;
}
OperatorKind binaryOpKind = binaryExpr.opKind;
if (binaryOpKind == OperatorKind.ADD || binaryOpKind == OperatorKind.SUB ||
binaryOpKind == OperatorKind.MUL || binaryOpKind == OperatorKind.DIV ||
binaryOpKind == OperatorKind.MOD || binaryOpKind == OperatorKind.BITWISE_AND ||
binaryOpKind == OperatorKind.BITWISE_OR || binaryOpKind == OperatorKind.BITWISE_XOR) {
checkByteTypeIncompatibleOperations(binaryExpr);
}
binaryExpr.lhsExpr = rewriteExpr(binaryExpr.lhsExpr);
binaryExpr.rhsExpr = rewriteExpr(binaryExpr.rhsExpr);
result = binaryExpr;
int rhsExprTypeTag = Types.getReferredType(binaryExpr.rhsExpr.getBType()).tag;
int lhsExprTypeTag = Types.getReferredType(binaryExpr.lhsExpr.getBType()).tag;
if (rhsExprTypeTag != lhsExprTypeTag && (binaryExpr.opKind == OperatorKind.EQUAL ||
binaryExpr.opKind == OperatorKind.NOT_EQUAL ||
binaryExpr.opKind == OperatorKind.REF_EQUAL ||
binaryExpr.opKind == OperatorKind.REF_NOT_EQUAL)) {
if (TypeTags.isIntegerTypeTag(lhsExprTypeTag) && rhsExprTypeTag == TypeTags.BYTE) {
binaryExpr.rhsExpr = createTypeCastExpr(binaryExpr.rhsExpr, symTable.intType);
return;
}
if (lhsExprTypeTag == TypeTags.BYTE && TypeTags.isIntegerTypeTag(rhsExprTypeTag)) {
binaryExpr.lhsExpr = createTypeCastExpr(binaryExpr.lhsExpr, symTable.intType);
return;
}
}
boolean isBinaryShiftOperator = symResolver.isBinaryShiftOperator(binaryOpKind);
boolean isArithmeticOperator = symResolver.isArithmeticOperator(binaryOpKind);
if (lhsExprTypeTag == rhsExprTypeTag) {
if (!isBinaryShiftOperator && !isArithmeticOperator) {
return;
}
if (types.isValueType(binaryExpr.lhsExpr.getBType())) {
return;
}
}
if (binaryExpr.opKind == OperatorKind.ADD && TypeTags.isStringTypeTag(lhsExprTypeTag) &&
(rhsExprTypeTag == TypeTags.XML || rhsExprTypeTag == TypeTags.XML_TEXT)) {
binaryExpr.lhsExpr = ASTBuilderUtil.createXMLTextLiteralNode(binaryExpr, binaryExpr.lhsExpr,
binaryExpr.lhsExpr.pos, symTable.xmlType);
return;
}
if (binaryExpr.opKind == OperatorKind.ADD && TypeTags.isStringTypeTag(rhsExprTypeTag) &&
(lhsExprTypeTag == TypeTags.XML || lhsExprTypeTag == TypeTags.XML_TEXT)) {
binaryExpr.rhsExpr = ASTBuilderUtil.createXMLTextLiteralNode(binaryExpr, binaryExpr.rhsExpr,
binaryExpr.rhsExpr.pos, symTable.xmlType);
return;
}
if (lhsExprTypeTag == TypeTags.DECIMAL) {
binaryExpr.rhsExpr = createTypeCastExpr(binaryExpr.rhsExpr, binaryExpr.lhsExpr.getBType());
return;
}
if (rhsExprTypeTag == TypeTags.DECIMAL) {
binaryExpr.lhsExpr = createTypeCastExpr(binaryExpr.lhsExpr, binaryExpr.rhsExpr.getBType());
return;
}
if (lhsExprTypeTag == TypeTags.FLOAT) {
binaryExpr.rhsExpr = createTypeCastExpr(binaryExpr.rhsExpr, binaryExpr.lhsExpr.getBType());
return;
}
if (rhsExprTypeTag == TypeTags.FLOAT) {
binaryExpr.lhsExpr = createTypeCastExpr(binaryExpr.lhsExpr, binaryExpr.rhsExpr.getBType());
return;
}
if (isArithmeticOperator) {
createTypeCastExprForArithmeticExpr(binaryExpr, lhsExprTypeTag, rhsExprTypeTag);
return;
}
if (isBinaryShiftOperator) {
createTypeCastExprForBinaryShiftExpr(binaryExpr, lhsExprTypeTag, rhsExprTypeTag);
return;
}
if (symResolver.isBinaryComparisonOperator(binaryOpKind)) {
createTypeCastExprForRelationalExpr(binaryExpr, lhsExprTypeTag, rhsExprTypeTag);
}
}
private BLangStatementExpression createStmtExprForNullableBinaryExpr(BLangBinaryExpr binaryExpr) {
/*
* int? x = 3;
* int? y = 5;
* int? z = x + y;
* Above is desugared to
* int? $result$;
*
* int? $lhsExprVar$ = x;
* int? $rhsExprVar$ = y;
* if (lhsVar is () or rhsVar is ()) {
*    $result$ = ();
* } else {
*    $result$ = $lhsExprVar$ + $rhsExprVar$;
* }
* int z = $result$;
*/
BLangBlockStmt blockStmt = ASTBuilderUtil.createBlockStmt(binaryExpr.pos);
BUnionType exprBType = (BUnionType) binaryExpr.getBType();
BType nonNilType = exprBType.getMemberTypes().iterator().next();
boolean isArithmeticOperator = symResolver.isArithmeticOperator(binaryExpr.opKind);
boolean isShiftOperator = symResolver.isBinaryShiftOperator(binaryExpr.opKind);
boolean isBitWiseOperator = !isArithmeticOperator && !isShiftOperator;
BType rhsType = nonNilType;
if (isBitWiseOperator) {
if (binaryExpr.rhsExpr.getBType().isNullable()) {
rhsType = types.getSafeType(binaryExpr.rhsExpr.getBType(), true, false);
} else {
rhsType = binaryExpr.rhsExpr.getBType();
}
}
BType lhsType = nonNilType;
if (isBitWiseOperator) {
if (binaryExpr.lhsExpr.getBType().isNullable()) {
lhsType = types.getSafeType(binaryExpr.lhsExpr.getBType(), true, false);
} else {
lhsType = binaryExpr.lhsExpr.getBType();
}
}
if (binaryExpr.lhsExpr.getBType().isNullable()) {
binaryExpr.lhsExpr = rewriteExpr(binaryExpr.lhsExpr);
}
BLangSimpleVariableDef tempVarDef = createVarDef("result",
binaryExpr.getBType(), null, binaryExpr.pos);
BLangSimpleVarRef tempVarRef = ASTBuilderUtil.createVariableRef(binaryExpr.pos, tempVarDef.var.symbol);
blockStmt.addStatement(tempVarDef);
BLangSimpleVariableDef lhsVarDef = createVarDef("$lhsExprVar$", binaryExpr.lhsExpr.getBType(),
binaryExpr.lhsExpr, binaryExpr.pos);
BLangSimpleVarRef lhsVarRef = ASTBuilderUtil.createVariableRef(binaryExpr.pos, lhsVarDef.var.symbol);
blockStmt.addStatement(lhsVarDef);
BLangSimpleVariableDef rhsVarDef = createVarDef("$rhsExprVar$", binaryExpr.rhsExpr.getBType(),
binaryExpr.rhsExpr, binaryExpr.pos);
BLangSimpleVarRef rhsVarRef = ASTBuilderUtil.createVariableRef(binaryExpr.pos, rhsVarDef.var.symbol);
blockStmt.addStatement(rhsVarDef);
BLangTypeTestExpr typeTestExprOne = createTypeCheckExpr(binaryExpr.pos, lhsVarRef, getNillTypeNode());
typeTestExprOne.setBType(symTable.booleanType);
BLangTypeTestExpr typeTestExprTwo = createTypeCheckExpr(binaryExpr.pos, rhsVarRef, getNillTypeNode());
typeTestExprTwo.setBType(symTable.booleanType);
BLangBinaryExpr ifBlockCondition = ASTBuilderUtil.createBinaryExpr(binaryExpr.pos, typeTestExprOne,
typeTestExprTwo, symTable.booleanType, OperatorKind.OR, binaryExpr.opSymbol);
BLangBlockStmt ifBody = ASTBuilderUtil.createBlockStmt(binaryExpr.pos);
BLangAssignment bLangAssignmentIf = ASTBuilderUtil.createAssignmentStmt(binaryExpr.pos, ifBody);
bLangAssignmentIf.varRef = tempVarRef;
bLangAssignmentIf.expr = createNilLiteral();
BLangBlockStmt elseBody = ASTBuilderUtil.createBlockStmt(binaryExpr.pos);
BLangAssignment bLangAssignmentElse = ASTBuilderUtil.createAssignmentStmt(binaryExpr.pos, elseBody);
bLangAssignmentElse.varRef = tempVarRef;
BLangBinaryExpr newBinaryExpr = ASTBuilderUtil.createBinaryExpr(binaryExpr.pos, lhsVarRef, rhsVarRef,
nonNilType, binaryExpr.opKind, binaryExpr.opSymbol);
newBinaryExpr.lhsExpr = createTypeCastExpr(lhsVarRef, lhsType);
newBinaryExpr.rhsExpr = createTypeCastExpr(rhsVarRef, rhsType);
bLangAssignmentElse.expr = newBinaryExpr;
BLangIf ifStatement = ASTBuilderUtil.createIfStmt(binaryExpr.pos, blockStmt);
ifStatement.expr = ifBlockCondition;
ifStatement.body = ifBody;
ifStatement.elseStmt = elseBody;
BLangStatementExpression stmtExpr = ASTBuilderUtil.createStatementExpression(blockStmt, tempVarRef);
stmtExpr.setBType(binaryExpr.getBType());
return stmtExpr;
}
private boolean isNullableBinaryExpr(BLangBinaryExpr binaryExpr) {
if ((binaryExpr.lhsExpr.getBType() != null && binaryExpr.rhsExpr.getBType() != null) &&
(binaryExpr.rhsExpr.getBType().isNullable() ||
binaryExpr.lhsExpr.getBType().isNullable())) {
switch (binaryExpr.getOperatorKind()) {
case ADD:
case SUB:
case MUL:
case DIV:
case MOD:
case BITWISE_LEFT_SHIFT:
case BITWISE_RIGHT_SHIFT:
case BITWISE_UNSIGNED_RIGHT_SHIFT:
case BITWISE_AND:
case BITWISE_OR:
case BITWISE_XOR:
return true;
}
}
return false;
}
private void createTypeCastExprForArithmeticExpr(BLangBinaryExpr binaryExpr, int lhsExprTypeTag,
int rhsExprTypeTag) {
if ((TypeTags.isIntegerTypeTag(lhsExprTypeTag) && TypeTags.isIntegerTypeTag(rhsExprTypeTag)) ||
(TypeTags.isStringTypeTag(lhsExprTypeTag) && TypeTags.isStringTypeTag(rhsExprTypeTag)) ||
(TypeTags.isXMLTypeTag(lhsExprTypeTag) && TypeTags.isXMLTypeTag(rhsExprTypeTag))) {
return;
}
if (TypeTags.isXMLTypeTag(lhsExprTypeTag) && !TypeTags.isXMLTypeTag(rhsExprTypeTag)) {
if (types.checkTypeContainString(binaryExpr.rhsExpr.getBType())) {
binaryExpr.rhsExpr = ASTBuilderUtil.createXMLTextLiteralNode(binaryExpr, binaryExpr.rhsExpr,
binaryExpr.rhsExpr.pos, symTable.xmlType);
return;
}
binaryExpr.rhsExpr = createTypeCastExpr(binaryExpr.rhsExpr, symTable.xmlType);
return;
}
if (TypeTags.isXMLTypeTag(rhsExprTypeTag) && !TypeTags.isXMLTypeTag(lhsExprTypeTag)) {
if (types.checkTypeContainString(binaryExpr.lhsExpr.getBType())) {
binaryExpr.lhsExpr = ASTBuilderUtil.createXMLTextLiteralNode(binaryExpr, binaryExpr.lhsExpr,
binaryExpr.rhsExpr.pos, symTable.xmlType);
return;
}
binaryExpr.lhsExpr = createTypeCastExpr(binaryExpr.lhsExpr, symTable.xmlType);
return;
}
binaryExpr.lhsExpr = createTypeCastExpr(binaryExpr.lhsExpr, binaryExpr.getBType());
binaryExpr.rhsExpr = createTypeCastExpr(binaryExpr.rhsExpr, binaryExpr.getBType());
}
private void createTypeCastExprForBinaryShiftExpr(BLangBinaryExpr binaryExpr, int lhsExprTypeTag,
int rhsExprTypeTag) {
boolean isLhsIntegerType = TypeTags.isIntegerTypeTag(lhsExprTypeTag);
boolean isRhsIntegerType = TypeTags.isIntegerTypeTag(rhsExprTypeTag);
if (isLhsIntegerType || lhsExprTypeTag == TypeTags.BYTE) {
if (isRhsIntegerType || rhsExprTypeTag == TypeTags.BYTE) {
return;
}
binaryExpr.rhsExpr = createTypeCastExpr(binaryExpr.rhsExpr, symTable.intType);
return;
}
if (isRhsIntegerType || rhsExprTypeTag == TypeTags.BYTE) {
binaryExpr.lhsExpr = createTypeCastExpr(binaryExpr.lhsExpr, symTable.intType);
return;
}
binaryExpr.lhsExpr = createTypeCastExpr(binaryExpr.lhsExpr, symTable.intType);
binaryExpr.rhsExpr = createTypeCastExpr(binaryExpr.rhsExpr, symTable.intType);
}
private void createTypeCastExprForRelationalExpr(BLangBinaryExpr binaryExpr, int lhsExprTypeTag,
int rhsExprTypeTag) {
boolean isLhsIntegerType = TypeTags.isIntegerTypeTag(lhsExprTypeTag);
boolean isRhsIntegerType = TypeTags.isIntegerTypeTag(rhsExprTypeTag);
if ((isLhsIntegerType && isRhsIntegerType) || (lhsExprTypeTag == TypeTags.BYTE &&
rhsExprTypeTag == TypeTags.BYTE)) {
return;
}
if (isLhsIntegerType && !isRhsIntegerType) {
binaryExpr.rhsExpr = createTypeCastExpr(binaryExpr.rhsExpr, symTable.intType);
return;
}
if (!isLhsIntegerType && isRhsIntegerType) {
binaryExpr.lhsExpr = createTypeCastExpr(binaryExpr.lhsExpr, symTable.intType);
return;
}
if (lhsExprTypeTag == TypeTags.BYTE || rhsExprTypeTag == TypeTags.BYTE) {
binaryExpr.rhsExpr = createTypeCastExpr(binaryExpr.rhsExpr, symTable.intType);
binaryExpr.lhsExpr = createTypeCastExpr(binaryExpr.lhsExpr, symTable.intType);
return;
}
boolean isLhsStringType = TypeTags.isStringTypeTag(lhsExprTypeTag);
boolean isRhsStringType = TypeTags.isStringTypeTag(rhsExprTypeTag);
if (isLhsStringType && isRhsStringType) {
return;
}
if (isLhsStringType && !isRhsStringType) {
binaryExpr.rhsExpr = createTypeCastExpr(binaryExpr.rhsExpr, symTable.stringType);
return;
}
if (!isLhsStringType && isRhsStringType) {
binaryExpr.lhsExpr = createTypeCastExpr(binaryExpr.lhsExpr, symTable.stringType);
}
}
private BLangInvocation replaceWithIntRange(Location location, BLangExpression lhsExpr,
BLangExpression rhsExpr) {
BInvokableSymbol symbol = (BInvokableSymbol) symTable.langInternalModuleSymbol.scope
.lookup(Names.CREATE_INT_RANGE).symbol;
BLangInvocation createIntRangeInvocation = ASTBuilderUtil.createInvocationExprForMethod(location, symbol,
new ArrayList<>(Lists.of(lhsExpr, rhsExpr)), symResolver);
createIntRangeInvocation.setBType(symTable.intRangeType);
return createIntRangeInvocation;
}
private void checkByteTypeIncompatibleOperations(BLangBinaryExpr binaryExpr) {
if (binaryExpr.expectedType == null) {
return;
}
int rhsExprTypeTag = Types.getReferredType(binaryExpr.rhsExpr.getBType()).tag;
int lhsExprTypeTag = Types.getReferredType(binaryExpr.lhsExpr.getBType()).tag;
if (rhsExprTypeTag != TypeTags.BYTE && lhsExprTypeTag != TypeTags.BYTE) {
return;
}
int resultTypeTag = binaryExpr.expectedType.tag;
if (resultTypeTag == TypeTags.INT) {
if (rhsExprTypeTag == TypeTags.BYTE) {
binaryExpr.rhsExpr = addConversionExprIfRequired(binaryExpr.rhsExpr, symTable.intType);
}
if (lhsExprTypeTag == TypeTags.BYTE) {
binaryExpr.lhsExpr = addConversionExprIfRequired(binaryExpr.lhsExpr, symTable.intType);
}
}
}
/**
* This method checks whether given binary expression is related to shift operation.
* If its true, then both lhs and rhs of the binary expression will be converted to 'int' type.
* <p>
* byte a = 12;
* byte b = 34;
* int i = 234;
* int j = -4;
* <p>
* true: where binary expression's expected type is 'int'
* int i1 = a >> b;
* int i2 = a << b;
* int i3 = a >> i;
* int i4 = a << i;
* int i5 = i >> j;
* int i6 = i << j;
*/
private boolean isBitwiseShiftOperation(BLangBinaryExpr binaryExpr) {
return binaryExpr.opKind == OperatorKind.BITWISE_LEFT_SHIFT ||
binaryExpr.opKind == OperatorKind.BITWISE_RIGHT_SHIFT ||
binaryExpr.opKind == OperatorKind.BITWISE_UNSIGNED_RIGHT_SHIFT;
}
public void visit(BLangElvisExpr elvisExpr) {
Location pos = elvisExpr.pos;
String resultVarName = "_$result$_";
BType resultType = elvisExpr.getBType();
BLangSimpleVariable resultVar =
ASTBuilderUtil.createVariable(pos, resultVarName, resultType, null,
new BVarSymbol(0, names.fromString(resultVarName),
this.env.scope.owner.pkgID, resultType,
this.env.scope.owner, pos, VIRTUAL));
BLangSimpleVariableDef resultVarDef = ASTBuilderUtil.createVariableDef(pos, resultVar);
resultVarDef.desugared = true;
BLangSimpleVarRef resultVarRef = ASTBuilderUtil.createVariableRef(pos, resultVar.symbol);
String lhsResultVarName = GEN_VAR_PREFIX.value;
BLangSimpleVariable lhsResultVar =
ASTBuilderUtil.createVariable(pos, lhsResultVarName, elvisExpr.lhsExpr.getBType(), elvisExpr.lhsExpr,
new BVarSymbol(0, names.fromString(lhsResultVarName),
this.env.scope.owner.pkgID, elvisExpr.lhsExpr.getBType(),
this.env.scope.owner, elvisExpr.pos, VIRTUAL));
BLangSimpleVariableDef lhsResultVarDef = ASTBuilderUtil.createVariableDef(pos, lhsResultVar);
BLangSimpleVarRef lhsResultVarRef = ASTBuilderUtil.createVariableRef(pos, lhsResultVar.symbol);
BLangAssignment nilAssignment = ASTBuilderUtil.createAssignmentStmt(pos, resultVarRef, elvisExpr.rhsExpr);
BLangBlockStmt ifBody = ASTBuilderUtil.createBlockStmt(pos);
ifBody.addStatement(nilAssignment);
BLangAssignment notNilAssignment = ASTBuilderUtil.createAssignmentStmt(pos, resultVarRef,
createTypeCastExpr(lhsResultVarRef, resultType));
BLangBlockStmt elseBody = ASTBuilderUtil.createBlockStmt(pos);
elseBody.addStatement(notNilAssignment);
BLangIf ifStmt = ASTBuilderUtil.createIfElseStmt(pos,
createTypeCheckExpr(pos, lhsResultVarRef, getNillTypeNode()), ifBody, elseBody);
BLangBlockStmt blockStmt = ASTBuilderUtil.createBlockStmt(pos, new ArrayList<>() {{
add(resultVarDef);
add(lhsResultVarDef);
add(ifStmt);
}});
BLangStatementExpression stmtExpr = ASTBuilderUtil.createStatementExpression(blockStmt, resultVarRef);
stmtExpr.setBType(resultType);
result = rewriteExpr(stmtExpr);
}
@Override
public void visit(BLangUnaryExpr unaryExpr) {
if (isNullableUnaryExpr(unaryExpr)) {
BLangStatementExpression statementExpression = createStmtExprForNilableUnaryExpr(unaryExpr);
result = rewrite(statementExpression, env);
return;
}
if (OperatorKind.BITWISE_COMPLEMENT == unaryExpr.operator) {
rewriteBitwiseComplementOperator(unaryExpr);
return;
}
OperatorKind opKind = unaryExpr.operator;
if (opKind == OperatorKind.ADD || opKind == OperatorKind.SUB) {
createTypeCastExprForUnaryPlusAndMinus(unaryExpr);
}
unaryExpr.expr = rewriteExpr(unaryExpr.expr);
result = unaryExpr;
}
private void createTypeCastExprForUnaryPlusAndMinus(BLangUnaryExpr unaryExpr) {
BLangExpression expr = unaryExpr.expr;
if (TypeTags.isIntegerTypeTag(expr.getBType().tag)) {
return;
}
unaryExpr.expr = createTypeCastExpr(expr, unaryExpr.getBType());
}
/**
* This method desugar a bitwise complement (~) unary expressions into a bitwise xor binary expression as below.
* Example : ~a  -> a ^ -1;
* ~ 11110011 -> 00001100
* 11110011 ^ 11111111 -> 00001100
*
* @param unaryExpr the bitwise complement expression
*/
private void rewriteBitwiseComplementOperator(BLangUnaryExpr unaryExpr) {
final Location pos = unaryExpr.pos;
final BLangBinaryExpr binaryExpr = (BLangBinaryExpr) TreeBuilder.createBinaryExpressionNode();
binaryExpr.pos = pos;
binaryExpr.opKind = OperatorKind.BITWISE_XOR;
binaryExpr.lhsExpr = unaryExpr.expr;
if (TypeTags.BYTE == Types.getReferredType(unaryExpr.getBType()).tag) {
binaryExpr.setBType(symTable.byteType);
binaryExpr.rhsExpr = ASTBuilderUtil.createLiteral(pos, symTable.byteType, 0xffL);
binaryExpr.opSymbol = (BOperatorSymbol) symResolver.resolveBinaryOperator(OperatorKind.BITWISE_XOR,
symTable.byteType, symTable.byteType);
} else {
binaryExpr.setBType(symTable.intType);
binaryExpr.rhsExpr = ASTBuilderUtil.createLiteral(pos, symTable.intType, -1L);
binaryExpr.opSymbol = (BOperatorSymbol) symResolver.resolveBinaryOperator(OperatorKind.BITWISE_XOR,
symTable.intType, symTable.intType);
}
result = rewriteExpr(binaryExpr);
}
private BLangStatementExpression createStmtExprForNilableUnaryExpr(BLangUnaryExpr unaryExpr) {
/*
* int? x = 3;
* int? y = +x;
*
*
* Above is desugared to
* int? $result$;
* if (x is ()) {
*    $result$ = ();
* } else {
*    $result$ = +x;
* }
* int y = $result$
*/
BLangBlockStmt blockStmt = ASTBuilderUtil.createBlockStmt(unaryExpr.pos);
BUnionType exprBType = (BUnionType) unaryExpr.getBType();
BType nilLiftType = exprBType.getMemberTypes().iterator().next();
unaryExpr.expr = rewriteExpr(unaryExpr.expr);
BLangSimpleVariableDef tempVarDef = createVarDef("$result",
unaryExpr.getBType(), createNilLiteral(), unaryExpr.pos);
BLangSimpleVarRef tempVarRef = ASTBuilderUtil.createVariableRef(unaryExpr.pos, tempVarDef.var.symbol);
blockStmt.addStatement(tempVarDef);
BLangTypeTestExpr typeTestExpr = createTypeCheckExpr(unaryExpr.pos, unaryExpr.expr,
getNillTypeNode());
typeTestExpr.setBType(symTable.booleanType);
BLangBlockStmt ifBody = ASTBuilderUtil.createBlockStmt(unaryExpr.pos);
BLangAssignment bLangAssignmentIf = ASTBuilderUtil.createAssignmentStmt(unaryExpr.pos, ifBody);
bLangAssignmentIf.varRef = tempVarRef;
bLangAssignmentIf.expr = createNilLiteral();
BLangBlockStmt elseBody = ASTBuilderUtil.createBlockStmt(unaryExpr.pos);
BLangAssignment bLangAssignmentElse = ASTBuilderUtil.createAssignmentStmt(unaryExpr.pos, elseBody);
bLangAssignmentElse.varRef = tempVarRef;
BLangExpression expr = createTypeCastExpr(unaryExpr.expr, nilLiftType);
bLangAssignmentElse.expr = ASTBuilderUtil.createUnaryExpr(unaryExpr.pos, expr,
nilLiftType, unaryExpr.operator, unaryExpr.opSymbol);
BLangIf ifStatement = ASTBuilderUtil.createIfStmt(unaryExpr.pos, blockStmt);
ifStatement.expr = typeTestExpr;
ifStatement.body = ifBody;
ifStatement.elseStmt = elseBody;
BLangStatementExpression stmtExpr = ASTBuilderUtil.createStatementExpression(blockStmt, tempVarRef);
stmtExpr.setBType(unaryExpr.getBType());
return stmtExpr;
}
private boolean isNullableUnaryExpr(BLangUnaryExpr unaryExpr) {
if (unaryExpr.getBType() != null && unaryExpr.getBType().isNullable()) {
switch (unaryExpr.operator) {
case ADD:
case SUB:
case BITWISE_COMPLEMENT:
return true;
}
}
return false;
}
@Override
public void visit(BLangTypeConversionExpr conversionExpr) {
if (conversionExpr.typeNode == null && !conversionExpr.annAttachments.isEmpty()) {
result = rewriteExpr(conversionExpr.expr);
return;
}
BType targetType = conversionExpr.targetType;
conversionExpr.typeNode = rewrite(conversionExpr.typeNode, env);
conversionExpr.expr = rewriteExpr(conversionExpr.expr);
result = conversionExpr;
}
@Override
public void visit(BLangLambdaFunction bLangLambdaFunction) {
if (!env.enclPkg.lambdaFunctions.contains(bLangLambdaFunction)) {
env.enclPkg.lambdaFunctions.add(bLangLambdaFunction);
}
result = bLangLambdaFunction;
}
@Override
public void visit(BLangArrowFunction bLangArrowFunction) {
BLangFunction bLangFunction = (BLangFunction) TreeBuilder.createFunctionNode();
bLangFunction.setName(bLangArrowFunction.functionName);
BLangLambdaFunction lambdaFunction = (BLangLambdaFunction) TreeBuilder.createLambdaFunctionNode();
lambdaFunction.pos = bLangArrowFunction.pos;
bLangFunction.addFlag(Flag.LAMBDA);
lambdaFunction.function = bLangFunction;
BLangValueType returnType = (BLangValueType) TreeBuilder.createValueTypeNode();
returnType.setBType(bLangArrowFunction.body.expr.getBType());
bLangFunction.setReturnTypeNode(returnType);
bLangFunction.setBody(populateArrowExprBodyBlock(bLangArrowFunction));
bLangArrowFunction.params.forEach(bLangFunction::addParameter);
lambdaFunction.parent = bLangArrowFunction.parent;
lambdaFunction.setBType(bLangArrowFunction.funcType);
BLangFunction funcNode = lambdaFunction.function;
BInvokableSymbol funcSymbol = Symbols.createFunctionSymbol(Flags.asMask(funcNode.flagSet),
new Name(funcNode.name.value),
new Name(funcNode.name.originalValue),
env.enclPkg.symbol.pkgID,
bLangArrowFunction.funcType,
env.enclEnv.enclVarSym, true,
bLangArrowFunction.pos, VIRTUAL);
funcSymbol.originalName = new Name(funcNode.name.originalValue);
SymbolEnv invokableEnv = SymbolEnv.createFunctionEnv(funcNode, funcSymbol.scope, env);
defineInvokableSymbol(funcNode, funcSymbol, invokableEnv);
List<BVarSymbol> paramSymbols = funcNode.requiredParams.stream().peek(varNode -> {
Scope enclScope = invokableEnv.scope;
varNode.symbol.kind = SymbolKind.FUNCTION;
varNode.symbol.owner = invokableEnv.scope.owner;
enclScope.define(varNode.symbol.name, varNode.symbol);
}).map(varNode -> varNode.symbol).collect(Collectors.toList());
funcSymbol.params = paramSymbols;
funcSymbol.restParam = getRestSymbol(funcNode);
funcSymbol.retType = funcNode.returnTypeNode.getBType();
List<BType> paramTypes = paramSymbols.stream().map(paramSym -> paramSym.type).collect(Collectors.toList());
funcNode.setBType(
new BInvokableType(paramTypes, getRestType(funcSymbol), funcNode.returnTypeNode.getBType(), null));
lambdaFunction.function.pos = bLangArrowFunction.pos;
lambdaFunction.function.body.pos = bLangArrowFunction.pos;
lambdaFunction.capturedClosureEnv = env;
rewrite(lambdaFunction.function, env);
env.enclPkg.addFunction(lambdaFunction.function);
result = rewriteExpr(lambdaFunction);
}
private void defineInvokableSymbol(BLangInvokableNode invokableNode, BInvokableSymbol funcSymbol,
SymbolEnv invokableEnv) {
invokableNode.symbol = funcSymbol;
funcSymbol.scope = new Scope(funcSymbol);
invokableEnv.scope = funcSymbol.scope;
}
@Override
public void visit(BLangXMLQName xmlQName) {
result = xmlQName;
}
@Override
public void visit(BLangXMLAttribute xmlAttribute) {
xmlAttribute.name = rewriteExpr(xmlAttribute.name);
xmlAttribute.value = rewriteExpr(xmlAttribute.value);
result = xmlAttribute;
}
@Override
public void visit(BLangXMLElementLiteral xmlElementLiteral) {
xmlElementLiteral.attributes = rewriteExprs(xmlElementLiteral.attributes);
Iterator<BLangXMLAttribute> attributesItr = xmlElementLiteral.attributes.iterator();
while (attributesItr.hasNext()) {
BLangXMLAttribute attribute = attributesItr.next();
if (!attribute.isNamespaceDeclr) {
continue;
}
BLangXMLNS xmlns;
if ((xmlElementLiteral.scope.owner.tag & SymTag.PACKAGE) == SymTag.PACKAGE) {
xmlns = new BLangPackageXMLNS();
} else {
xmlns = new BLangLocalXMLNS();
}
xmlns.namespaceURI = attribute.value.concatExpr;
xmlns.prefix = ((BLangXMLQName) attribute.name).localname;
xmlns.symbol = attribute.symbol;
xmlElementLiteral.inlineNamespaces.add(xmlns);
}
List<BLangXMLNS> prevInlineNamespaces = this.inlineXMLNamespaces;
if (isVisitingQuery && this.inlineXMLNamespaces != null) {
xmlElementLiteral.inlineNamespaces.addAll(this.inlineXMLNamespaces);
}
this.inlineXMLNamespaces = xmlElementLiteral.inlineNamespaces;
xmlElementLiteral.startTagName = rewriteExpr(xmlElementLiteral.startTagName);
xmlElementLiteral.endTagName = rewriteExpr(xmlElementLiteral.endTagName);
xmlElementLiteral.modifiedChildren = rewriteExprs(xmlElementLiteral.modifiedChildren);
this.inlineXMLNamespaces = prevInlineNamespaces;
result = xmlElementLiteral;
}
@Override
public void visit(BLangXMLSequenceLiteral xmlSequenceLiteral) {
for (BLangExpression xmlItem : xmlSequenceLiteral.xmlItems) {
rewriteExpr(xmlItem);
}
result = xmlSequenceLiteral;
}
@Override
public void visit(BLangXMLTextLiteral xmlTextLiteral) {
xmlTextLiteral.concatExpr = rewriteExpr(constructStringTemplateConcatExpression(xmlTextLiteral.textFragments));
result = xmlTextLiteral;
}
@Override
public void visit(BLangXMLCommentLiteral xmlCommentLiteral) {
xmlCommentLiteral.concatExpr = rewriteExpr(
constructStringTemplateConcatExpression(xmlCommentLiteral.textFragments));
result = xmlCommentLiteral;
}
@Override
public void visit(BLangXMLProcInsLiteral xmlProcInsLiteral) {
xmlProcInsLiteral.target = rewriteExpr(xmlProcInsLiteral.target);
xmlProcInsLiteral.dataConcatExpr =
rewriteExpr(constructStringTemplateConcatExpression(xmlProcInsLiteral.dataFragments));
result = xmlProcInsLiteral;
}
@Override
public void visit(BLangXMLQuotedString xmlQuotedString) {
xmlQuotedString.concatExpr = rewriteExpr(
constructStringTemplateConcatExpression(xmlQuotedString.textFragments));
result = xmlQuotedString;
}
@Override
public void visit(BLangStringTemplateLiteral stringTemplateLiteral) {
result = rewriteExpr(constructStringTemplateConcatExpression(stringTemplateLiteral.exprs));
}
/**
* The raw template literal gets desugared to a type init expression. For each literal, a new object class type
* def is generated from the object type. The type init expression creates an instance of this generated object
* type. For example, consider the following statements:
*      string name = "Pubudu";
*      'object:RawTemplate rt = `Hello ${name}!`;
*
* The raw template literal above is desugared to:
*      type RawTemplate$Impl$0 object {
*          public string[] strings = ["Hello ", "!"];
*          public (any|error)[] insertions;
*
*          function init((any|error)[] insertions) {
*              self.insertions = insertions;
*          }
*      };
*
*
*      'object:RawTemplate rt = new RawTemplate$Impl$0([name]);
*
* @param rawTemplateLiteral The raw template literal to be desugared.
*/
@Override
public void visit(BLangRawTemplateLiteral rawTemplateLiteral) {
Location pos = rawTemplateLiteral.pos;
BObjectType objType = (BObjectType) Types.getReferredType(rawTemplateLiteral.getBType());
BLangClassDefinition objClassDef =
desugarTemplateLiteralObjectTypedef(rawTemplateLiteral.strings, objType, pos);
BObjectType classObjType = (BObjectType) objClassDef.getBType();
BVarSymbol insertionsSym = classObjType.fields.get("insertions").symbol;
BLangListConstructorExpr insertionsList = ASTBuilderUtil.createListConstructorExpr(pos, insertionsSym.type);
insertionsList.exprs.addAll(rawTemplateLiteral.insertions);
insertionsList.expectedType = insertionsSym.type;
BLangTypeInit typeNewExpr = ASTBuilderUtil.createEmptyTypeInit(pos, classObjType);
typeNewExpr.argsExpr.add(insertionsList);
typeNewExpr.initInvocation.argExprs.add(insertionsList);
typeNewExpr.initInvocation.requiredArgs.add(insertionsList);
result = rewriteExpr(typeNewExpr);
}
/**
* This method desugars a raw template literal object class for the provided raw template object type as follows.
* A literal defined as 'object:RawTemplate rt = `Hello ${name}!`;
* is desugared to,
*      type $anonType$0 object {
*          public string[] strings = ["Hello ", "!"];
*          public (any|error)[] insertions;
*
*          function init((any|error)[] insertions) {
*              self.insertions = insertions;
*          }
*      };
* @param strings    The string portions of the literal
* @param objectType The abstract object type for which an object class needs to be generated
* @param pos        The diagnostic position info for the type node
* @return Returns the generated concrete object class def
*/
private BLangClassDefinition desugarTemplateLiteralObjectTypedef(List<BLangLiteral> strings, BObjectType objectType,
Location pos) {
BObjectTypeSymbol tSymbol = (BObjectTypeSymbol) objectType.tsymbol;
Name objectClassName = names.fromString(
anonModelHelper.getNextRawTemplateTypeKey(env.enclPkg.packageID, tSymbol.name));
BObjectTypeSymbol classTSymbol = Symbols.createClassSymbol(tSymbol.flags, objectClassName,
env.enclPkg.packageID, null, env.enclPkg.symbol,
pos, VIRTUAL, false);
classTSymbol.flags |= Flags.CLASS;
BObjectType objectClassType = new BObjectType(classTSymbol, classTSymbol.flags);
objectClassType.fields = objectType.fields;
classTSymbol.type = objectClassType;
objectClassType.typeIdSet.add(objectType.typeIdSet);
BLangClassDefinition classDef = TypeDefBuilderHelper.createClassDef(pos, classTSymbol, env);
classDef.name = ASTBuilderUtil.createIdentifier(pos, objectClassType.tsymbol.name.value);
BType stringsType = objectClassType.fields.get("strings").symbol.type;
BLangListConstructorExpr stringsList = ASTBuilderUtil.createListConstructorExpr(pos, stringsType);
stringsList.exprs.addAll(strings);
stringsList.expectedType = stringsType;
classDef.fields.get(0).expr = stringsList;
BLangFunction userDefinedInitFunction = createUserDefinedObjectInitFn(classDef, env);
classDef.initFunction = userDefinedInitFunction;
env.enclPkg.functions.add(userDefinedInitFunction);
env.enclPkg.topLevelNodes.add(userDefinedInitFunction);
BLangFunction tempGeneratedInitFunction = createGeneratedInitializerFunction(classDef, env);
tempGeneratedInitFunction.clonedEnv = SymbolEnv.createFunctionEnv(tempGeneratedInitFunction,
tempGeneratedInitFunction.symbol.scope, env);
SemanticAnalyzer.AnalyzerData data = new SemanticAnalyzer.AnalyzerData(env);
this.semanticAnalyzer.analyzeNode(tempGeneratedInitFunction, data);
classDef.generatedInitFunction = tempGeneratedInitFunction;
env.enclPkg.functions.add(classDef.generatedInitFunction);
env.enclPkg.topLevelNodes.add(classDef.generatedInitFunction);
return rewrite(classDef, env);
}
/**
* Creates a user-defined init() method for the provided object type node. If there are fields without default
* values specified in the type node, this will add parameters for those fields in the init() method and assign the
* param values to the respective fields in the method body.
*
* @param classDefn The object type node for which the init() method is generated
* @param env            The symbol env for the object type node
* @return The generated init() method
*/
private BLangFunction createUserDefinedObjectInitFn(BLangClassDefinition classDefn, SymbolEnv env) {
BLangFunction initFunction =
TypeDefBuilderHelper.createInitFunctionForStructureType(classDefn.pos, classDefn.symbol, env,
names, Names.USER_DEFINED_INIT_SUFFIX,
symTable, classDefn.getBType());
BObjectTypeSymbol typeSymbol = ((BObjectTypeSymbol) classDefn.getBType().tsymbol);
typeSymbol.initializerFunc = new BAttachedFunction(Names.USER_DEFINED_INIT_SUFFIX, initFunction.symbol,
(BInvokableType) initFunction.getBType(), classDefn.pos);
classDefn.initFunction = initFunction;
initFunction.returnTypeNode.setBType(symTable.nilType);
BLangBlockFunctionBody initFuncBody = (BLangBlockFunctionBody) initFunction.body;
BInvokableType initFnType = (BInvokableType) initFunction.getBType();
for (BLangSimpleVariable field : classDefn.fields) {
if (field.expr != null) {
continue;
}
BVarSymbol fieldSym = field.symbol;
BVarSymbol paramSym = new BVarSymbol(Flags.FINAL, fieldSym.name, this.env.scope.owner.pkgID, fieldSym.type,
initFunction.symbol, classDefn.pos, VIRTUAL);
BLangSimpleVariable param = ASTBuilderUtil.createVariable(classDefn.pos, fieldSym.name.value,
fieldSym.type, null, paramSym);
param.flagSet.add(Flag.FINAL);
initFunction.symbol.scope.define(paramSym.name, paramSym);
initFunction.symbol.params.add(paramSym);
initFnType.paramTypes.add(param.getBType());
initFunction.requiredParams.add(param);
BLangSimpleVarRef paramRef = ASTBuilderUtil.createVariableRef(initFunction.pos, paramSym);
BLangAssignment fieldInit = createStructFieldUpdate(initFunction, paramRef, fieldSym, field.getBType(),
initFunction.receiver.symbol, field.name);
initFuncBody.addStatement(fieldInit);
}
return initFunction;
}
@Override
public void visit(BLangWorkerSend workerSendNode) {
workerSendNode.expr = visitCloneInvocation(rewriteExpr(workerSendNode.expr), workerSendNode.expr.getBType());
result = workerSendNode;
}
@Override
public void visit(BLangWorkerSyncSendExpr syncSendExpr) {
syncSendExpr.expr = visitCloneInvocation(rewriteExpr(syncSendExpr.expr), syncSendExpr.expr.getBType());
result = syncSendExpr;
}
@Override
public void visit(BLangWorkerReceive workerReceiveNode) {
result = workerReceiveNode;
}
@Override
public void visit(BLangWorkerFlushExpr workerFlushExpr) {
workerFlushExpr.workerIdentifierList = workerFlushExpr.cachedWorkerSendStmts
.stream().map(send -> send.workerIdentifier).distinct().collect(Collectors.toList());
result = workerFlushExpr;
}
@Override
public void visit(BLangTransactionalExpr transactionalExpr) {
BInvokableSymbol isTransactionalSymbol =
(BInvokableSymbol) transactionDesugar.getInternalTransactionModuleInvokableSymbol(IS_TRANSACTIONAL);
result = ASTBuilderUtil
.createInvocationExprMethod(transactionalExpr.pos, isTransactionalSymbol, Collections.emptyList(),
Collections.emptyList(), symResolver);
}
@Override
public void visit(BLangCommitExpr commitExpr) {
BLangStatementExpression stmtExpr = transactionDesugar.desugar(commitExpr, env);
result = rewriteExpr(stmtExpr);
}
@Override
public void visit(BLangFail failNode) {
if (this.onFailClause != null && !this.isVisitingQuery) {
if (this.onFailClause.bodyContainsFail) {
result = rewriteNestedOnFail(this.onFailClause, failNode);
} else {
result = createOnFailInvocation(onFailClause, failNode);
}
} else {
BLangReturn stmt = ASTBuilderUtil.createReturnStmt(failNode.pos, rewrite(failNode.expr, env));
stmt.desugared = true;
result = stmt;
}
}
@Override
public void visit(BLangLocalVarRef localVarRef) {
result = localVarRef;
}
@Override
public void visit(BLangFieldVarRef fieldVarRef) {
result = fieldVarRef;
}
@Override
public void visit(BLangPackageVarRef packageVarRef) {
result = packageVarRef;
}
@Override
public void visit(BLangFunctionVarRef functionVarRef) {
result = functionVarRef;
}
@Override
public void visit(BLangStructFieldAccessExpr fieldAccessExpr) {
result = fieldAccessExpr;
}
@Override
public void visit(BLangStructFunctionVarRef functionVarRef) {
result = functionVarRef;
}
@Override
public void visit(BLangMapAccessExpr mapKeyAccessExpr) {
result = mapKeyAccessExpr;
}
@Override
public void visit(BLangArrayAccessExpr arrayIndexAccessExpr) {
result = arrayIndexAccessExpr;
}
@Override
public void visit(BLangTupleAccessExpr arrayIndexAccessExpr) {
result = arrayIndexAccessExpr;
}
@Override
public void visit(BLangTableAccessExpr tableKeyAccessExpr) {
result = tableKeyAccessExpr;
}
@Override
public void visit(BLangMapLiteral mapLiteral) {
result = mapLiteral;
}
@Override
public void visit(BLangStructLiteral structLiteral) {
result = structLiteral;
}
@Override
public void visit(BLangWaitForAllExpr.BLangWaitLiteral waitLiteral) {
result = waitLiteral;
}
@Override
public void visit(BLangXMLElementAccess xmlElementAccess) {
xmlElementAccess.expr = rewriteExpr(xmlElementAccess.expr);
ArrayList<BLangExpression> filters = expandFilters(xmlElementAccess.filters);
BLangInvocation invocationNode = createLanglibXMLInvocation(xmlElementAccess.pos, XML_INTERNAL_GET_ELEMENTS,
xmlElementAccess.expr, new ArrayList<>(), filters);
result = rewriteExpr(invocationNode);
}
private ArrayList<BLangExpression> expandFilters(List<BLangXMLElementFilter> filters) {
Map<Name, BXMLNSSymbol> nameBXMLNSSymbolMap = symResolver.resolveAllNamespaces(env);
BXMLNSSymbol defaultNSSymbol = nameBXMLNSSymbolMap.get(names.fromString(XMLConstants.DEFAULT_NS_PREFIX));
String defaultNS = defaultNSSymbol != null ? defaultNSSymbol.namespaceURI : null;
ArrayList<BLangExpression> args = new ArrayList<>();
for (BLangXMLElementFilter filter : filters) {
BSymbol nsSymbol = symResolver.lookupSymbolInPrefixSpace(env, names.fromString(filter.namespace));
if (nsSymbol == symTable.notFoundSymbol) {
if (defaultNS != null && !filter.name.equals("*")) {
String expandedName = createExpandedQName(defaultNS, filter.name);
args.add(createStringLiteral(filter.elemNamePos, expandedName));
} else {
args.add(createStringLiteral(filter.elemNamePos, filter.name));
}
} else {
BXMLNSSymbol bxmlnsSymbol = (BXMLNSSymbol) nsSymbol;
String expandedName = createExpandedQName(bxmlnsSymbol.namespaceURI, filter.name);
BLangLiteral stringLiteral = createStringLiteral(filter.elemNamePos, expandedName);
args.add(stringLiteral);
}
}
return args;
}
private BLangInvocation createLanglibXMLInvocation(Location pos, String functionName,
BLangExpression invokeOnExpr,
ArrayList<BLangExpression> args,
ArrayList<BLangExpression> restArgs) {
invokeOnExpr = rewriteExpr(invokeOnExpr);
BLangInvocation invocationNode = (BLangInvocation) TreeBuilder.createInvocationNode();
invocationNode.pos = pos;
BLangIdentifier name = (BLangIdentifier) TreeBuilder.createIdentifierNode();
name.setLiteral(false);
name.setValue(functionName);
name.pos = pos;
invocationNode.name = name;
invocationNode.pkgAlias = (BLangIdentifier) TreeBuilder.createIdentifierNode();
invocationNode.expr = invokeOnExpr;
invocationNode.symbol = symResolver.lookupLangLibMethod(symTable.xmlType, names.fromString(functionName), env);
ArrayList<BLangExpression> requiredArgs = new ArrayList<>();
requiredArgs.add(invokeOnExpr);
requiredArgs.addAll(args);
invocationNode.requiredArgs = requiredArgs;
invocationNode.restArgs = rewriteExprs(restArgs);
invocationNode.setBType(((BInvokableType) invocationNode.symbol.type).getReturnType());
invocationNode.langLibInvocation = true;
return invocationNode;
}
@Override
public void visit(BLangXMLNavigationAccess xmlNavigation) {
xmlNavigation.expr = rewriteExpr(xmlNavigation.expr);
xmlNavigation.childIndex = rewriteExpr(xmlNavigation.childIndex);
ArrayList<BLangExpression> filters = expandFilters(xmlNavigation.filters);
if (xmlNavigation.navAccessType == XMLNavigationAccess.NavAccessType.DESCENDANTS) {
BLangInvocation invocationNode = createLanglibXMLInvocation(xmlNavigation.pos,
XML_INTERNAL_SELECT_DESCENDANTS, xmlNavigation.expr, new ArrayList<>(), filters);
result = rewriteExpr(invocationNode);
} else if (xmlNavigation.navAccessType == XMLNavigationAccess.NavAccessType.CHILDREN) {
BLangInvocation invocationNode = createLanglibXMLInvocation(xmlNavigation.pos, XML_INTERNAL_CHILDREN,
xmlNavigation.expr, new ArrayList<>(), new ArrayList<>());
result = rewriteExpr(invocationNode);
} else {
BLangExpression childIndexExpr;
if (xmlNavigation.childIndex == null) {
childIndexExpr = new BLangLiteral(Long.valueOf(-1), symTable.intType);
} else {
childIndexExpr = xmlNavigation.childIndex;
}
ArrayList<BLangExpression> args = new ArrayList<>();
args.add(rewriteExpr(childIndexExpr));
BLangInvocation invocationNode = createLanglibXMLInvocation(xmlNavigation.pos,
XML_INTERNAL_GET_FILTERED_CHILDREN_FLAT, xmlNavigation.expr, args, filters);
result = rewriteExpr(invocationNode);
}
}
@Override
public void visit(BLangIsAssignableExpr assignableExpr) {
assignableExpr.lhsExpr = rewriteExpr(assignableExpr.lhsExpr);
result = assignableExpr;
}
@Override
public void visit(BFunctionPointerInvocation fpInvocation) {
result = fpInvocation;
}
@Override
public void visit(BLangTypedescExpr typedescExpr) {
typedescExpr.typeNode = rewrite(typedescExpr.typeNode, env);
result = typedescExpr;
}
@Override
public void visit(BLangRestArgsExpression bLangVarArgsExpression) {
result = rewriteExpr(bLangVarArgsExpression.expr);
}
@Override
public void visit(BLangNamedArgsExpression bLangNamedArgsExpression) {
bLangNamedArgsExpression.expr = rewriteExpr(bLangNamedArgsExpression.expr);
result = bLangNamedArgsExpression.expr;
}
@Override
public void visit(BLangCheckedExpr checkedExpr) {
visitCheckAndCheckPanicExpr(checkedExpr, false);
}
@Override
public void visit(BLangCheckPanickedExpr checkedExpr) {
visitCheckAndCheckPanicExpr(checkedExpr, true);
}
private void visitCheckAndCheckPanicExpr(BLangCheckedExpr checkedExpr, boolean isCheckPanic) {
if (checkedExpr.isRedundantChecking) {
result = rewriteExpr(checkedExpr.expr);
return;
}
Location pos = checkedExpr.pos;
String resultVarName = "_$result$_";
BType resultType = checkedExpr.getBType();
BLangSimpleVariable resultVar =
ASTBuilderUtil.createVariable(pos, resultVarName, resultType, null,
new BVarSymbol(0, names.fromString(resultVarName),
this.env.scope.owner.pkgID, resultType,
this.env.scope.owner, pos, VIRTUAL));
BLangSimpleVariableDef resultVarDef = ASTBuilderUtil.createVariableDef(pos, resultVar);
resultVarDef.desugared = true;
BLangSimpleVarRef resultVarRef = ASTBuilderUtil.createVariableRef(pos, resultVar.symbol);
String checkedExprVarName = GEN_VAR_PREFIX.value;
BType checkedExprType = checkedExpr.expr.getBType();
BLangSimpleVariable checkedExprVar =
ASTBuilderUtil.createVariable(pos, checkedExprVarName, checkedExprType,
checkedExpr.expr, new BVarSymbol(0, names.fromString(checkedExprVarName),
this.env.scope.owner.pkgID, checkedExprType,
this.env.scope.owner, pos, VIRTUAL));
BLangSimpleVariableDef checkedExprVarDef = ASTBuilderUtil.createVariableDef(pos, checkedExprVar);
BLangSimpleVarRef checkedExprVarRef = ASTBuilderUtil.createVariableRef(pos, checkedExprVar.symbol);
BLangAssignment successAssignment = ASTBuilderUtil.createAssignmentStmt(pos, resultVarRef,
createTypeCastExpr(checkedExprVarRef, resultType));
BLangBlockStmt ifBody = ASTBuilderUtil.createBlockStmt(pos);
ifBody.addStatement(successAssignment);
BLangBlockStmt elseBody = getSafeErrorAssignment(pos, checkedExprVarRef, this.env.enclInvokable.symbol,
checkedExpr.equivalentErrorTypeList, isCheckPanic);
BLangValueType checkedExprTypeNode = (BLangValueType) TreeBuilder.createValueTypeNode();
checkedExprTypeNode.setBType(resultType);
checkedExprTypeNode.typeKind = resultType.getKind();
BLangIf ifStmt = ASTBuilderUtil.createIfElseStmt(pos,
createTypeCheckExpr(pos, checkedExprVarRef, checkedExprTypeNode), ifBody, elseBody);
BLangBlockStmt blockStmt = ASTBuilderUtil.createBlockStmt(pos, new ArrayList<>() {{
add(resultVarDef);
add(checkedExprVarDef);
add(ifStmt);
}});
BLangStatementExpression stmtExpr = ASTBuilderUtil.createStatementExpression(blockStmt, resultVarRef);
stmtExpr.setBType(resultType);
result = rewriteExpr(stmtExpr);
}
@Override
public void visit(BLangServiceConstructorExpr serviceConstructorExpr) {
final BLangTypeInit typeInit = ASTBuilderUtil.createEmptyTypeInit(serviceConstructorExpr.pos,
serviceConstructorExpr.serviceNode.serviceClass.symbol.type);
serviceConstructorExpr.serviceNode.annAttachments.forEach(attachment ->  rewrite(attachment, env));
result = rewriteExpr(typeInit);
}
@Override
public void visit(BLangObjectConstructorExpression bLangObjectConstructorExpression) {
visit(bLangObjectConstructorExpression.classNode);
bLangObjectConstructorExpression.classNode.annAttachments.forEach(attachment -> rewrite(attachment, env));
result = rewriteExpr(bLangObjectConstructorExpression.typeInit);
}
@Override
public void visit(BLangAnnotAccessExpr annotAccessExpr) {
BLangBinaryExpr binaryExpr = (BLangBinaryExpr) TreeBuilder.createBinaryExpressionNode();
binaryExpr.pos = annotAccessExpr.pos;
binaryExpr.opKind = OperatorKind.ANNOT_ACCESS;
binaryExpr.lhsExpr = annotAccessExpr.expr;
binaryExpr.rhsExpr = ASTBuilderUtil.createLiteral(annotAccessExpr.pkgAlias.pos, symTable.stringType,
annotAccessExpr.annotationSymbol.bvmAlias());
binaryExpr.setBType(annotAccessExpr.getBType());
binaryExpr.opSymbol = new BOperatorSymbol(names.fromString(OperatorKind.ANNOT_ACCESS.value()), null,
new BInvokableType(Lists.of(binaryExpr.lhsExpr.getBType(),
binaryExpr.rhsExpr.getBType()),
annotAccessExpr.getBType(), null), null,
symTable.builtinPos, VIRTUAL);
result = rewriteExpr(binaryExpr);
}
@Override
public void visit(BLangTypeTestExpr typeTestExpr) {
BLangExpression expr = typeTestExpr.expr;
if (types.isValueType(expr.getBType())) {
expr = addConversionExprIfRequired(expr, symTable.anyType);
}
if (typeTestExpr.isNegation) {
BLangTypeTestExpr bLangTypeTestExpr = ASTBuilderUtil.createTypeTestExpr(typeTestExpr.pos,
typeTestExpr.expr, typeTestExpr.typeNode);
BLangGroupExpr bLangGroupExpr = (BLangGroupExpr) TreeBuilder.createGroupExpressionNode();
bLangGroupExpr.expression = bLangTypeTestExpr;
bLangGroupExpr.setBType(typeTestExpr.getBType());
BLangUnaryExpr unaryExpr = ASTBuilderUtil.createUnaryExpr(typeTestExpr.pos, bLangGroupExpr,
typeTestExpr.getBType(),
OperatorKind.NOT, null);
result = rewriteExpr(unaryExpr);
return;
}
typeTestExpr.expr = rewriteExpr(expr);
typeTestExpr.typeNode = rewrite(typeTestExpr.typeNode, env);
result = typeTestExpr;
}
@Override
public void visit(BLangIsLikeExpr isLikeExpr) {
isLikeExpr.expr = rewriteExpr(isLikeExpr.expr);
result = isLikeExpr;
}
@Override
public void visit(BLangStatementExpression bLangStatementExpression) {
bLangStatementExpression.expr = rewriteExpr(bLangStatementExpression.expr);
bLangStatementExpression.stmt = rewrite(bLangStatementExpression.stmt, env);
result = bLangStatementExpression;
}
@Override
public void visit(BLangQueryExpr queryExpr) {
boolean prevIsVisitingQuery = this.isVisitingQuery;
this.isVisitingQuery = true;
BLangStatementExpression stmtExpr = queryDesugar.desugar(queryExpr, env, getVisibleXMLNSStmts(env));
result = rewrite(stmtExpr, env);
this.isVisitingQuery = prevIsVisitingQuery;
}
List<BLangStatement> getVisibleXMLNSStmts(SymbolEnv env) {
Map<Name, BXMLNSSymbol> nameBXMLNSSymbolMap = symResolver.resolveAllNamespaces(env);
return nameBXMLNSSymbolMap.keySet().stream()
.map(key -> this.stmtsToBePropagatedToQuery.get(key))
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
@Override
public void visit(BLangQueryAction queryAction) {
boolean prevIsVisitingQuery = this.isVisitingQuery;
this.isVisitingQuery = true;
BLangStatementExpression stmtExpr = queryDesugar.desugar(queryAction, env, getVisibleXMLNSStmts(env));
result = rewrite(stmtExpr, env);
this.isVisitingQuery = prevIsVisitingQuery;
}
@Override
public void visit(BLangJSONArrayLiteral jsonArrayLiteral) {
jsonArrayLiteral.exprs = rewriteExprs(jsonArrayLiteral.exprs);
result = jsonArrayLiteral;
}
@Override
public void visit(BLangConstant constant) {
BConstantSymbol constSymbol = constant.symbol;
BType refType = Types.getReferredType(constSymbol.literalType);
if (refType.tag <= TypeTags.BOOLEAN || refType.tag == TypeTags.NIL) {
if (refType.tag != TypeTags.NIL && (constSymbol.value == null ||
constSymbol.value.value == null)) {
throw new IllegalStateException();
}
BLangLiteral literal = ASTBuilderUtil.createLiteral(constant.expr.pos, constSymbol.literalType,
constSymbol.value.value);
constant.expr = rewriteExpr(literal);
} else {
constant.expr = rewriteExpr(constant.expr);
}
constant.annAttachments.forEach(attachment ->  rewrite(attachment, env));
result = constant;
}
@Override
public void visit(BLangIgnoreExpr ignoreExpr) {
result = ignoreExpr;
}
@Override
public void visit(BLangDynamicArgExpr dynamicParamExpr) {
dynamicParamExpr.conditionalArgument = rewriteExpr(dynamicParamExpr.conditionalArgument);
dynamicParamExpr.condition = rewriteExpr(dynamicParamExpr.condition);
result = dynamicParamExpr;
}
@Override
public void visit(BLangConstRef constantRef) {
result = ASTBuilderUtil.createLiteral(constantRef.pos, constantRef.getBType(), constantRef.value);
}
BLangSimpleVariableDef getIteratorVariableDefinition(Location pos, BVarSymbol collectionSymbol,
BInvokableSymbol iteratorInvokableSymbol,
boolean isIteratorFuncFromLangLib) {
BLangSimpleVarRef dataReference = ASTBuilderUtil.createVariableRef(pos, collectionSymbol);
BLangInvocation iteratorInvocation = (BLangInvocation) TreeBuilder.createInvocationNode();
iteratorInvocation.pos = pos;
iteratorInvocation.expr = dataReference;
iteratorInvocation.symbol = iteratorInvokableSymbol;
iteratorInvocation.setBType(iteratorInvokableSymbol.retType);
iteratorInvocation.argExprs = Lists.of(dataReference);
iteratorInvocation.requiredArgs = iteratorInvocation.argExprs;
iteratorInvocation.langLibInvocation = isIteratorFuncFromLangLib;
BVarSymbol iteratorSymbol = new BVarSymbol(0, names.fromString("$iterator$"), this.env.scope.owner.pkgID,
iteratorInvokableSymbol.retType, this.env.scope.owner, pos, VIRTUAL);
BLangSimpleVariable iteratorVariable = ASTBuilderUtil.createVariable(pos, "$iterator$",
iteratorInvokableSymbol.retType, iteratorInvocation, iteratorSymbol);
return ASTBuilderUtil.createVariableDef(pos, iteratorVariable);
}
BLangSimpleVariableDef getIteratorNextVariableDefinition(Location pos, BType nillableResultType,
BVarSymbol iteratorSymbol,
BVarSymbol resultSymbol) {
BLangInvocation nextInvocation = createIteratorNextInvocation(pos, iteratorSymbol);
BLangSimpleVariable resultVariable = ASTBuilderUtil.createVariable(pos, "$result$",
nillableResultType, nextInvocation, resultSymbol);
return ASTBuilderUtil.createVariableDef(pos, resultVariable);
}
BLangInvocation createIteratorNextInvocation(Location pos, BVarSymbol iteratorSymbol) {
BLangIdentifier nextIdentifier = ASTBuilderUtil.createIdentifier(pos, "next");
BLangSimpleVarRef iteratorReferenceInNext = ASTBuilderUtil.createVariableRef(pos, iteratorSymbol);
BInvokableSymbol nextFuncSymbol =
getNextFunc((BObjectType) Types.getReferredType(iteratorSymbol.type)).symbol;
BLangInvocation nextInvocation = (BLangInvocation) TreeBuilder.createInvocationNode();
nextInvocation.pos = pos;
nextInvocation.name = nextIdentifier;
nextInvocation.expr = iteratorReferenceInNext;
nextInvocation.requiredArgs = Lists.of(ASTBuilderUtil.createVariableRef(pos, iteratorSymbol));
nextInvocation.argExprs = nextInvocation.requiredArgs;
nextInvocation.symbol = nextFuncSymbol;
nextInvocation.setBType(nextFuncSymbol.retType);
return nextInvocation;
}
private BAttachedFunction getNextFunc(BObjectType iteratorType) {
BObjectTypeSymbol iteratorSymbol = (BObjectTypeSymbol) iteratorType.tsymbol;
for (BAttachedFunction bAttachedFunction : iteratorSymbol.attachedFuncs) {
if (bAttachedFunction.funcName.value.equals("next")) {
return bAttachedFunction;
}
}
return null;
}
BLangFieldBasedAccess getValueAccessExpression(Location location, BType varType,
BVarSymbol resultSymbol) {
return getFieldAccessExpression(location, "value", varType, resultSymbol);
}
BLangFieldBasedAccess getFieldAccessExpression(Location pos, String fieldName, BType varType,
BVarSymbol resultSymbol) {
BLangSimpleVarRef resultReferenceInVariableDef = ASTBuilderUtil.createVariableRef(pos, resultSymbol);
BLangIdentifier valueIdentifier = ASTBuilderUtil.createIdentifier(pos, fieldName);
BLangFieldBasedAccess fieldBasedAccessExpression =
ASTBuilderUtil.createFieldAccessExpr(resultReferenceInVariableDef, valueIdentifier);
fieldBasedAccessExpression.pos = pos;
fieldBasedAccessExpression.setBType(varType);
fieldBasedAccessExpression.originalType = fieldBasedAccessExpression.getBType();
return fieldBasedAccessExpression;
}
private BlockFunctionBodyNode populateArrowExprBodyBlock(BLangArrowFunction bLangArrowFunction) {
BlockFunctionBodyNode blockNode = TreeBuilder.createBlockFunctionBodyNode();
BLangReturn returnNode = (BLangReturn) TreeBuilder.createReturnNode();
returnNode.pos = bLangArrowFunction.body.expr.pos;
returnNode.setExpression(bLangArrowFunction.body.expr);
blockNode.addStatement(returnNode);
return blockNode;
}
protected BLangInvocation createInvocationNode(String functionName, List<BLangExpression> args, BType retType) {
BLangInvocation invocationNode = (BLangInvocation) TreeBuilder.createInvocationNode();
BLangIdentifier name = (BLangIdentifier) TreeBuilder.createIdentifierNode();
name.setLiteral(false);
name.setValue(functionName);
invocationNode.name = name;
invocationNode.pkgAlias = (BLangIdentifier) TreeBuilder.createIdentifierNode();
invocationNode.symbol = symTable.rootScope.lookup(new Name(functionName)).symbol;
invocationNode.setBType(retType);
invocationNode.requiredArgs = args;
return invocationNode;
}
private BLangInvocation createLangLibInvocationNode(String functionName,
BLangExpression onExpr,
List<BLangExpression> args,
BType retType,
Location pos) {
BLangInvocation invocationNode = (BLangInvocation) TreeBuilder.createInvocationNode();
invocationNode.pos = pos;
BLangIdentifier name = (BLangIdentifier) TreeBuilder.createIdentifierNode();
name.setLiteral(false);
name.setValue(functionName);
name.pos = pos;
invocationNode.name = name;
invocationNode.pkgAlias = (BLangIdentifier) TreeBuilder.createIdentifierNode();
invocationNode.expr = onExpr;
invocationNode.symbol = symResolver.lookupLangLibMethod(onExpr.getBType(), names.fromString(functionName), env);
ArrayList<BLangExpression> requiredArgs = new ArrayList<>();
requiredArgs.add(onExpr);
requiredArgs.addAll(args);
invocationNode.requiredArgs = requiredArgs;
invocationNode.setBType(retType != null ? retType : ((BInvokableSymbol) invocationNode.symbol).retType);
invocationNode.langLibInvocation = true;
return invocationNode;
}
private BLangInvocation createLangLibInvocationNode(String functionName,
List<BLangExpression> args,
BType retType,
Location pos) {
BLangInvocation invocationNode = (BLangInvocation) TreeBuilder.createInvocationNode();
invocationNode.pos = pos;
BLangIdentifier name = (BLangIdentifier) TreeBuilder.createIdentifierNode();
name.setLiteral(false);
name.setValue(functionName);
name.pos = pos;
invocationNode.name = name;
invocationNode.pkgAlias = (BLangIdentifier) TreeBuilder.createIdentifierNode();
invocationNode.symbol = symResolver.lookupMethodInModule(symTable.langInternalModuleSymbol,
names.fromString(functionName), env);
ArrayList<BLangExpression> requiredArgs = new ArrayList<>();
requiredArgs.addAll(args);
invocationNode.requiredArgs = requiredArgs;
invocationNode.setBType(retType != null ? retType : ((BInvokableSymbol) invocationNode.symbol).retType);
invocationNode.langLibInvocation = true;
return invocationNode;
}
private BLangArrayLiteral createArrayLiteralExprNode() {
BLangArrayLiteral expr = (BLangArrayLiteral) TreeBuilder.createArrayLiteralExpressionNode();
expr.exprs = new ArrayList<>();
expr.setBType(new BArrayType(symTable.anyType));
return expr;
}
private void visitFunctionPointerInvocation(BLangInvocation iExpr) {
BLangValueExpression expr;
if (iExpr.expr == null) {
expr = new BLangSimpleVarRef();
} else {
BLangFieldBasedAccess fieldBasedAccess = new BLangFieldBasedAccess();
fieldBasedAccess.expr = iExpr.expr;
fieldBasedAccess.field = iExpr.name;
expr = fieldBasedAccess;
}
expr.symbol = iExpr.symbol;
expr.setBType(iExpr.symbol.type);
BLangExpression rewritten = rewriteExpr(expr);
result = new BFunctionPointerInvocation(iExpr, rewritten);
}
private BLangExpression visitCloneInvocation(BLangExpression expr, BType lhsType) {
if (types.isValueType(expr.getBType())) {
return expr;
}
if (expr.getBType().tag == TypeTags.ERROR) {
return expr;
}
BLangInvocation cloneInvok = createLangLibInvocationNode("clone", expr, new ArrayList<>(), null, expr.pos);
return addConversionExprIfRequired(cloneInvok, lhsType);
}
private BLangExpression visitCloneReadonly(BLangExpression expr, BType lhsType) {
if (types.isValueType(expr.getBType())) {
return expr;
}
if (expr.getBType().tag == TypeTags.ERROR) {
return expr;
}
BLangInvocation cloneInvok = createLangLibInvocationNode("cloneReadOnly", expr, new ArrayList<>(),
expr.getBType(),
expr.pos);
return addConversionExprIfRequired(cloneInvok, lhsType);
}
@SuppressWarnings("unchecked")
<E extends BLangNode> E rewrite(E node, SymbolEnv env) {
if (node == null) {
return null;
}
if (node.desugared) {
return node;
}
SymbolEnv previousEnv = this.env;
this.env = env;
node.accept(this);
BLangNode resultNode = this.result;
this.result = null;
resultNode.desugared = true;
this.env = previousEnv;
return (E) resultNode;
}
@SuppressWarnings("unchecked")
<E extends BLangExpression> E rewriteExpr(E node) {
if (node == null) {
return null;
}
if (node.desugared) {
return node;
}
BLangExpression expr = node;
if (node.impConversionExpr != null) {
expr = node.impConversionExpr;
node.impConversionExpr = null;
}
expr.accept(this);
BLangNode resultNode = this.result;
this.result = null;
resultNode.desugared = true;
return (E) resultNode;
}
@SuppressWarnings("unchecked")
<E extends BLangStatement> E rewrite(E statement, SymbolEnv env) {
if (statement == null) {
return null;
}
BLangStatement stmt = (BLangStatement) rewrite((BLangNode) statement, env);
return (E) stmt;
}
private <E extends BLangStatement> List<E> rewriteStmt(List<E> nodeList, SymbolEnv env) {
for (int i = 0; i < nodeList.size(); i++) {
nodeList.set(i, rewrite(nodeList.get(i), env));
}
return nodeList;
}
private <E extends BLangNode> List<E> rewrite(List<E> nodeList, SymbolEnv env) {
for (int i = 0; i < nodeList.size(); i++) {
nodeList.set(i, rewrite(nodeList.get(i), env));
}
return nodeList;
}
private <E extends BLangExpression> List<E> rewriteExprs(List<E> nodeList) {
for (int i = 0; i < nodeList.size(); i++) {
nodeList.set(i, rewriteExpr(nodeList.get(i)));
}
return nodeList;
}
private BLangLiteral createStringLiteral(Location pos, String value) {
BLangLiteral stringLit = new BLangLiteral(value, symTable.stringType);
stringLit.pos = pos;
return stringLit;
}
private BLangLiteral createIntLiteral(long value) {
BLangLiteral literal = (BLangLiteral) TreeBuilder.createLiteralExpression();
literal.value = value;
literal.setBType(symTable.intType);
return literal;
}
private BLangLiteral createByteLiteral(Location pos, Byte value) {
BLangLiteral byteLiteral = new BLangLiteral(Byte.toUnsignedInt(value), symTable.byteType);
byteLiteral.pos = pos;
return byteLiteral;
}
private BLangExpression createTypeCastExpr(BLangExpression expr, BType targetType) {
if (types.isSameType(expr.getBType(), targetType)) {
return expr;
}
BLangTypeConversionExpr conversionExpr = (BLangTypeConversionExpr) TreeBuilder.createTypeConversionNode();
conversionExpr.pos = expr.pos;
conversionExpr.expr = expr;
conversionExpr.setBType(targetType);
conversionExpr.targetType = targetType;
conversionExpr.internal = true;
return conversionExpr;
}
private BType getElementType(BType bType) {
BType type = Types.getReferredType(bType);
if (type.tag != TypeTags.ARRAY) {
return bType;
}
return getElementType(((BArrayType) type).getElementType());
}
private void addReturnIfNotPresent(BLangInvokableNode invokableNode) {
if (Symbols.isNative(invokableNode.symbol) ||
(invokableNode.hasBody() && invokableNode.body.getKind() != NodeKind.BLOCK_FUNCTION_BODY)) {
return;
}
BLangBlockFunctionBody funcBody = (BLangBlockFunctionBody) invokableNode.body;
if (invokableNode.symbol.type.getReturnType().isNullable() && (funcBody.stmts.size() < 1
|| funcBody.stmts.get(funcBody.stmts.size() - 1).getKind() != NodeKind.RETURN)) {
Location invPos = invokableNode.pos;
Location returnStmtPos;
if (invokableNode.name.value.contains(GENERATED_INIT_SUFFIX.value)) {
returnStmtPos = null;
} else {
returnStmtPos = new BLangDiagnosticLocation(invPos.lineRange().filePath(),
invPos.lineRange().endLine().line(),
invPos.lineRange().endLine().line(),
invPos.lineRange().startLine().offset(),
invPos.lineRange().startLine().offset(), 0, 0);
}
BLangReturn returnStmt = ASTBuilderUtil.createNilReturnStmt(returnStmtPos, symTable.nilType);
funcBody.addStatement(returnStmt);
}
}
/**
* Reorder the invocation arguments to match the original function signature.
*
* @param iExpr Function invocation expressions to reorder the arguments
*/
private void reorderArguments(BLangInvocation iExpr) {
BSymbol symbol = iExpr.symbol;
if (symbol == null || Types.getReferredType(symbol.type).tag != TypeTags.INVOKABLE) {
return;
}
BInvokableSymbol invokableSymbol = (BInvokableSymbol) symbol;
List<BLangExpression> restArgs = iExpr.restArgs;
int originalRequiredArgCount = iExpr.requiredArgs.size();
BLangSimpleVarRef varargRef = null;
BLangBlockStmt blockStmt = null;
BType varargVarType = null;
int restArgCount = restArgs.size();
if (restArgCount > 0 &&
restArgs.get(restArgCount - 1).getKind() == NodeKind.REST_ARGS_EXPR &&
originalRequiredArgCount < invokableSymbol.params.size()) {
BLangExpression expr = ((BLangRestArgsExpression) restArgs.get(restArgCount - 1)).expr;
Location varargExpPos = expr.pos;
varargVarType = expr.getBType();
String varargVarName = DESUGARED_VARARG_KEY + UNDERSCORE + this.varargCount++;
BVarSymbol varargVarSymbol = new BVarSymbol(0, names.fromString(varargVarName), this.env.scope.owner.pkgID,
varargVarType, this.env.scope.owner, varargExpPos, VIRTUAL);
varargRef = ASTBuilderUtil.createVariableRef(varargExpPos, varargVarSymbol);
BLangSimpleVariable var = createVariable(varargExpPos, varargVarName, varargVarType, expr, varargVarSymbol);
BLangSimpleVariableDef varDef = ASTBuilderUtil.createVariableDef(varargExpPos);
varDef.var = var;
varDef.setBType(varargVarType);
blockStmt = createBlockStmt(varargExpPos);
blockStmt.stmts.add(varDef);
}
if (!invokableSymbol.params.isEmpty()) {
reorderNamedArgs(iExpr, invokableSymbol, varargRef);
}
if (restArgCount == 0 || restArgs.get(restArgCount - 1).getKind() != NodeKind.REST_ARGS_EXPR) {
if (invokableSymbol.restParam == null) {
return;
}
BLangArrayLiteral arrayLiteral = (BLangArrayLiteral) TreeBuilder.createArrayLiteralExpressionNode();
List<BLangExpression> exprs = new ArrayList<>();
BArrayType arrayType = (BArrayType) invokableSymbol.restParam.type;
BType elemType = arrayType.eType;
for (BLangExpression restArg : restArgs) {
exprs.add(addConversionExprIfRequired(restArg, elemType));
}
arrayLiteral.exprs = exprs;
arrayLiteral.setBType(arrayType);
if (restArgCount != 0) {
iExpr.restArgs = new ArrayList<>();
}
iExpr.restArgs.add(arrayLiteral);
return;
}
if (restArgCount == 1 && restArgs.get(0).getKind() == NodeKind.REST_ARGS_EXPR) {
if (iExpr.requiredArgs.size() == originalRequiredArgCount) {
return;
}
BLangExpression firstNonRestArg = iExpr.requiredArgs.remove(0);
BLangStatementExpression stmtExpression = createStatementExpression(blockStmt, firstNonRestArg);
stmtExpression.setBType(firstNonRestArg.getBType());
iExpr.requiredArgs.add(0, stmtExpression);
if (invokableSymbol.restParam == null) {
restArgs.remove(0);
return;
}
BLangRestArgsExpression restArgsExpression = (BLangRestArgsExpression) restArgs.remove(0);
BArrayType restParamType = (BArrayType) invokableSymbol.restParam.type;
if (Types.getReferredType(restArgsExpression.getBType()).tag == TypeTags.RECORD) {
BLangExpression expr = ASTBuilderUtil.createEmptyArrayLiteral(invokableSymbol.pos, restParamType);
restArgs.add(expr);
return;
}
Location pos = restArgsExpression.pos;
BLangArrayLiteral newArrayLiteral = createArrayLiteralExprNode();
newArrayLiteral.setBType(restParamType);
String name = DESUGARED_VARARG_KEY + UNDERSCORE + this.varargCount++;
BVarSymbol varSymbol = new BVarSymbol(0, names.fromString(name), this.env.scope.owner.pkgID,
restParamType, this.env.scope.owner, pos, VIRTUAL);
BLangSimpleVarRef arrayVarRef = ASTBuilderUtil.createVariableRef(pos, varSymbol);
BLangSimpleVariable var = createVariable(pos, name, restParamType, newArrayLiteral, varSymbol);
BLangSimpleVariableDef varDef = ASTBuilderUtil.createVariableDef(pos);
varDef.var = var;
varDef.setBType(restParamType);
BLangLiteral startIndex = createIntLiteral(invokableSymbol.params.size() - originalRequiredArgCount);
BLangInvocation lengthInvocation = createLengthInvocation(pos, varargRef);
BLangInvocation intRangeInvocation = replaceWithIntRange(pos, startIndex,
getModifiedIntRangeEndExpr(lengthInvocation));
BLangForeach foreach = (BLangForeach) TreeBuilder.createForeachNode();
foreach.pos = pos;
foreach.collection = intRangeInvocation;
types.setForeachTypedBindingPatternType(foreach);
final BLangSimpleVariable foreachVariable = ASTBuilderUtil.createVariable(pos, "$foreach$i",
foreach.varType);
foreachVariable.symbol = new BVarSymbol(0, names.fromIdNode(foreachVariable.name),
this.env.scope.owner.pkgID, foreachVariable.getBType(),
this.env.scope.owner, pos, VIRTUAL);
BLangSimpleVarRef foreachVarRef = ASTBuilderUtil.createVariableRef(pos, foreachVariable.symbol);
foreach.variableDefinitionNode = ASTBuilderUtil.createVariableDef(pos, foreachVariable);
foreach.isDeclaredWithVar = true;
BLangBlockStmt foreachBody = ASTBuilderUtil.createBlockStmt(pos);
BLangIndexBasedAccess valueExpr = ASTBuilderUtil.createIndexAccessExpr(varargRef, foreachVarRef);
BType refType = Types.getReferredType(varargVarType);
if (refType.tag == TypeTags.ARRAY) {
BArrayType arrayType = (BArrayType) refType;
if (arrayType.state == BArrayState.CLOSED &&
arrayType.size == (iExpr.requiredArgs.size() - originalRequiredArgCount)) {
valueExpr.setBType(restParamType.eType);
} else {
valueExpr.setBType(arrayType.eType);
}
} else {
valueExpr.setBType(symTable.anyOrErrorType);
}
BLangExpression pushExpr = addConversionExprIfRequired(valueExpr, restParamType.eType);
BLangExpressionStmt expressionStmt = createExpressionStmt(pos, foreachBody);
BLangInvocation pushInvocation = createLangLibInvocationNode(PUSH_LANGLIB_METHOD, arrayVarRef,
List.of(pushExpr),
restParamType, pos);
pushInvocation.restArgs.add(pushInvocation.requiredArgs.remove(1));
expressionStmt.expr = pushInvocation;
foreach.body = foreachBody;
BLangBlockStmt newArrayBlockStmt = createBlockStmt(pos);
newArrayBlockStmt.addStatement(varDef);
newArrayBlockStmt.addStatement(foreach);
BLangStatementExpression newArrayStmtExpression = createStatementExpression(newArrayBlockStmt, arrayVarRef);
newArrayStmtExpression.setBType(restParamType);
restArgs.add(addConversionExprIfRequired(newArrayStmtExpression, restParamType));
return;
}
BArrayType restParamType = (BArrayType) invokableSymbol.restParam.type;
BLangArrayLiteral arrayLiteral = (BLangArrayLiteral) TreeBuilder.createArrayLiteralExpressionNode();
arrayLiteral.setBType(restParamType);
BType elemType = restParamType.eType;
Location pos = restArgs.get(0).pos;
List<BLangExpression> exprs = new ArrayList<>();
for (int i = 0; i < restArgCount - 1; i++) {
exprs.add(addConversionExprIfRequired(restArgs.get(i), elemType));
}
arrayLiteral.exprs = exprs;
BLangRestArgsExpression pushRestArgsExpr = (BLangRestArgsExpression) TreeBuilder.createVarArgsNode();
pushRestArgsExpr.pos = pos;
pushRestArgsExpr.expr = restArgs.remove(restArgCount - 1);
String name = DESUGARED_VARARG_KEY + UNDERSCORE + this.varargCount++;
BVarSymbol varSymbol = new BVarSymbol(0, names.fromString(name), this.env.scope.owner.pkgID, restParamType,
this.env.scope.owner, pos, VIRTUAL);
BLangSimpleVarRef arrayVarRef = ASTBuilderUtil.createVariableRef(pos, varSymbol);
BLangSimpleVariable var = createVariable(pos, name, restParamType, arrayLiteral, varSymbol);
BLangSimpleVariableDef varDef = ASTBuilderUtil.createVariableDef(pos);
varDef.var = var;
varDef.setBType(restParamType);
BLangBlockStmt pushBlockStmt = createBlockStmt(pos);
pushBlockStmt.stmts.add(varDef);
BLangExpressionStmt expressionStmt = createExpressionStmt(pos, pushBlockStmt);
BLangInvocation pushInvocation = createLangLibInvocationNode(PUSH_LANGLIB_METHOD, arrayVarRef,
new ArrayList<BLangExpression>() {{
add(pushRestArgsExpr);
}}, restParamType, pos);
pushInvocation.restArgs.add(pushInvocation.requiredArgs.remove(1));
expressionStmt.expr = pushInvocation;
BLangStatementExpression stmtExpression = createStatementExpression(pushBlockStmt, arrayVarRef);
stmtExpression.setBType(restParamType);
iExpr.restArgs = new ArrayList<BLangExpression>(1) {{ add(stmtExpression); }};
}
private void reorderNamedArgs(BLangInvocation iExpr, BInvokableSymbol invokableSymbol, BLangExpression varargRef) {
List<BLangExpression> args = new ArrayList<>();
Map<String, BLangExpression> namedArgs = new LinkedHashMap<>();
iExpr.requiredArgs.stream()
.filter(expr -> expr.getKind() == NodeKind.NAMED_ARGS_EXPR)
.forEach(expr -> namedArgs.put(((NamedArgNode) expr).getName().value, expr));
List<BVarSymbol> params = invokableSymbol.params;
List<BLangRecordLiteral> incRecordLiterals = new ArrayList<>();
BLangRecordLiteral incRecordParamAllowAdditionalFields = null;
int varargIndex = 0;
BType varargType = null;
boolean tupleTypedVararg = false;
if (varargRef != null) {
varargType = Types.getReferredType(varargRef.getBType());
tupleTypedVararg = varargType.tag == TypeTags.TUPLE;
}
for (int i = 0; i < params.size(); i++) {
BVarSymbol param = params.get(i);
if (iExpr.requiredArgs.size() > i && iExpr.requiredArgs.get(i).getKind() != NodeKind.NAMED_ARGS_EXPR) {
args.add(iExpr.requiredArgs.get(i));
} else if (namedArgs.containsKey(param.name.value)) {
args.add(namedArgs.remove(param.name.value));
} else if (param.getFlags().contains(Flag.INCLUDED)) {
BLangRecordLiteral recordLiteral = (BLangRecordLiteral) TreeBuilder.createRecordLiteralNode();
BType paramType = param.type;
recordLiteral.setBType(paramType);
args.add(recordLiteral);
incRecordLiterals.add(recordLiteral);
if (((BRecordType) Types.getReferredType(paramType)).restFieldType != symTable.noType) {
incRecordParamAllowAdditionalFields = recordLiteral;
}
} else if (varargRef == null) {
BLangExpression expr = new BLangIgnoreExpr();
expr.setBType(param.type);
args.add(expr);
} else {
if (Types.getReferredType(varargRef.getBType()).tag == TypeTags.RECORD) {
if (param.isDefaultable) {
BLangInvocation hasKeyInvocation = createLangLibInvocationNode(HAS_KEY, varargRef,
List.of(createStringLiteral(param.pos, param.name.value)), null, varargRef.pos);
BLangExpression indexExpr = rewriteExpr(createStringLiteral(param.pos, param.name.value));
BLangIndexBasedAccess memberAccessExpr =
ASTBuilderUtil.createMemberAccessExprNode(param.type, varargRef, indexExpr);
BLangExpression ignoreExpr = ASTBuilderUtil.createIgnoreExprNode(param.type);
BLangTernaryExpr ternaryExpr = ASTBuilderUtil.createTernaryExprNode(param.type,
hasKeyInvocation, memberAccessExpr, ignoreExpr);
args.add(ASTBuilderUtil.createDynamicParamExpression(hasKeyInvocation, ternaryExpr));
} else {
BLangFieldBasedAccess fieldBasedAccessExpression =
ASTBuilderUtil.createFieldAccessExpr(varargRef,
ASTBuilderUtil.createIdentifier(param.pos, param.name.value));
fieldBasedAccessExpression.setBType(param.type);
args.add(fieldBasedAccessExpression);
}
} else {
BLangExpression indexExpr = rewriteExpr(createIntLiteral(varargIndex));
BType memberAccessExprType = tupleTypedVararg ?
((BTupleType) varargType).tupleTypes.get(varargIndex) : ((BArrayType) varargType).eType;
args.add(addConversionExprIfRequired(ASTBuilderUtil.createMemberAccessExprNode(memberAccessExprType,
varargRef, indexExpr), param.type));
varargIndex++;
}
}
}
if (namedArgs.size() > 0) {
setFieldsForIncRecordLiterals(namedArgs, incRecordLiterals, incRecordParamAllowAdditionalFields);
}
iExpr.requiredArgs = args;
}
private void setFieldsForIncRecordLiterals(Map<String, BLangExpression> namedArgs,
List<BLangRecordLiteral> incRecordLiterals,
BLangRecordLiteral incRecordParamAllowAdditionalFields) {
for (String name : namedArgs.keySet()) {
boolean isAdditionalField = true;
BLangNamedArgsExpression expr = (BLangNamedArgsExpression) namedArgs.get(name);
for (BLangRecordLiteral recordLiteral : incRecordLiterals) {
LinkedHashMap<String, BField> fields =
((BRecordType) Types.getReferredType(recordLiteral.getBType())).fields;
if (fields.containsKey(name) &&
Types.getReferredType(fields.get(name).type).tag != TypeTags.NEVER) {
isAdditionalField = false;
createAndAddRecordFieldForIncRecordLiteral(recordLiteral, expr);
break;
}
}
if (isAdditionalField) {
createAndAddRecordFieldForIncRecordLiteral(incRecordParamAllowAdditionalFields, expr);
}
}
}
private void createAndAddRecordFieldForIncRecordLiteral(BLangRecordLiteral recordLiteral,
BLangNamedArgsExpression expr) {
BLangSimpleVarRef varRef = new BLangSimpleVarRef();
varRef.variableName = expr.name;
BLangRecordLiteral.BLangRecordKeyValueField recordKeyValueField = ASTBuilderUtil.
createBLangRecordKeyValue(varRef, expr.expr);
recordLiteral.fields.add(recordKeyValueField);
}
private BLangBlockStmt getSafeErrorAssignment(Location location, BLangSimpleVarRef ref,
BSymbol invokableSymbol,
List<BType> equivalentErrorTypes,
boolean isCheckPanicExpr) {
BType enclosingFuncReturnType = Types.getReferredType(((BInvokableType) invokableSymbol.type).retType);
Set<BType> returnTypeSet = enclosingFuncReturnType.tag == TypeTags.UNION ?
((BUnionType) enclosingFuncReturnType).getMemberTypes() :
new LinkedHashSet<>() {{
add(enclosingFuncReturnType);
}};
boolean returnOnError = equivalentErrorTypes.stream()
.allMatch(errorType -> returnTypeSet.stream()
.anyMatch(retType -> types.isAssignable(errorType, retType)));
String patternFailureCaseVarName = GEN_VAR_PREFIX.value + "t_failure";
BLangSimpleVariable errorVar =
ASTBuilderUtil.createVariable(location, patternFailureCaseVarName, symTable.errorType,
createTypeCastExpr(ref, symTable.errorType),
new BVarSymbol(0, names.fromString(patternFailureCaseVarName),
this.env.scope.owner.pkgID, symTable.errorType,
this.env.scope.owner, location, VIRTUAL));
BLangBlockStmt blockStmt = ASTBuilderUtil.createBlockStmt(location);
BLangSimpleVariableDef errorVarDef = ASTBuilderUtil.createVariableDef(location, errorVar);
blockStmt.addStatement(errorVarDef);
BLangVariableReference errorVarRef = ASTBuilderUtil.createVariableRef(location, errorVar.symbol);
if (!isCheckPanicExpr && (returnOnError || this.onFailClause != null)) {
BLangFail failStmt = (BLangFail) TreeBuilder.createFailNode();
failStmt.pos = location;
failStmt.expr = errorVarRef;
blockStmt.addStatement(failStmt);
if (returnOnError && this.shouldReturnErrors) {
BLangReturn errorReturn = ASTBuilderUtil.createReturnStmt(location, rewrite(errorVarRef, env));
errorReturn.desugared = true;
failStmt.exprStmt = errorReturn;
}
} else {
BLangPanic panicNode = (BLangPanic) TreeBuilder.createPanicNode();
panicNode.pos = location;
panicNode.expr = errorVarRef;
blockStmt.addStatement(panicNode);
}
return blockStmt;
}
BLangExpression addConversionExprIfRequired(BLangExpression expr, BType lhsType) {
if (lhsType.tag == TypeTags.NONE) {
return expr;
}
BType rhsType = expr.getBType();
if (types.isSameType(rhsType, lhsType)) {
return expr;
}
types.setImplicitCastExpr(expr, rhsType, lhsType);
if (expr.impConversionExpr != null) {
BLangExpression impConversionExpr = expr.impConversionExpr;
expr.impConversionExpr = null;
return impConversionExpr;
}
if (lhsType.tag == TypeTags.JSON && rhsType.tag == TypeTags.NIL) {
return expr;
}
if (lhsType.tag == TypeTags.NIL && rhsType.isNullable()) {
return expr;
}
if (lhsType.tag == TypeTags.ARRAY && rhsType.tag == TypeTags.TUPLE) {
return expr;
}
BLangTypeConversionExpr conversionExpr = (BLangTypeConversionExpr)
TreeBuilder.createTypeConversionNode();
conversionExpr.expr = expr;
conversionExpr.targetType = lhsType;
conversionExpr.setBType(lhsType);
conversionExpr.pos = expr.pos;
conversionExpr.checkTypes = false;
conversionExpr.internal = true;
return conversionExpr;
}
private BType getStructuredBindingPatternType(BLangVariable bindingPatternVariable) {
if (NodeKind.TUPLE_VARIABLE == bindingPatternVariable.getKind()) {
BLangTupleVariable tupleVariable = (BLangTupleVariable) bindingPatternVariable;
List<BType> memberTypes = new ArrayList<>();
for (int i = 0; i < tupleVariable.memberVariables.size(); i++) {
memberTypes.add(getStructuredBindingPatternType(tupleVariable.memberVariables.get(i)));
}
BTupleType tupleType = new BTupleType(memberTypes);
if (tupleVariable.restVariable != null) {
BArrayType restArrayType = (BArrayType) getStructuredBindingPatternType(tupleVariable.restVariable);
tupleType.restType = restArrayType.eType;
}
return tupleType;
}
if (NodeKind.RECORD_VARIABLE == bindingPatternVariable.getKind()) {
BLangRecordVariable recordVariable = (BLangRecordVariable) bindingPatternVariable;
BRecordTypeSymbol recordSymbol =
Symbols.createRecordSymbol(0, names.fromString("$anonRecordType$" + UNDERSCORE + recordCount++),
env.enclPkg.symbol.pkgID, null, env.scope.owner, recordVariable.pos,
VIRTUAL);
recordSymbol.initializerFunc = createRecordInitFunc();
recordSymbol.scope = new Scope(recordSymbol);
recordSymbol.scope.define(
names.fromString(recordSymbol.name.value + "." + recordSymbol.initializerFunc.funcName.value),
recordSymbol.initializerFunc.symbol);
LinkedHashMap<String, BField> fields = new LinkedHashMap<>();
List<BLangSimpleVariable> typeDefFields = new ArrayList<>();
for (int i = 0; i < recordVariable.variableList.size(); i++) {
String fieldNameStr = recordVariable.variableList.get(i).key.value;
Name fieldName = names.fromString(fieldNameStr);
BType fieldType = getStructuredBindingPatternType(
recordVariable.variableList.get(i).valueBindingPattern);
BVarSymbol fieldSymbol = new BVarSymbol(Flags.REQUIRED, fieldName, env.enclPkg.symbol.pkgID, fieldType,
recordSymbol, bindingPatternVariable.pos, VIRTUAL);
fields.put(fieldName.value, new BField(fieldName, bindingPatternVariable.pos, fieldSymbol));
typeDefFields.add(ASTBuilderUtil.createVariable(null, fieldNameStr, fieldType, null, fieldSymbol));
recordSymbol.scope.define(fieldName, fieldSymbol);
}
BRecordType recordVarType = new BRecordType(recordSymbol);
recordVarType.fields = fields;
recordVarType.restFieldType = recordVariable.restParam != null ?
((BRecordType) recordVariable.restParam.getBType()).restFieldType :
symTable.anydataType;
recordSymbol.type = recordVarType;
recordVarType.tsymbol = recordSymbol;
BLangRecordTypeNode recordTypeNode = TypeDefBuilderHelper.createRecordTypeNode(typeDefFields,
recordVarType,
bindingPatternVariable.pos);
recordTypeNode.initFunction =
rewrite(TypeDefBuilderHelper.createInitFunctionForRecordType(recordTypeNode, env, names, symTable),
env);
TypeDefBuilderHelper.createTypeDefinitionForTSymbol(recordVarType, recordSymbol, recordTypeNode, env);
return recordVarType;
}
if (NodeKind.ERROR_VARIABLE == bindingPatternVariable.getKind()) {
BLangErrorVariable errorVariable = (BLangErrorVariable) bindingPatternVariable;
BErrorTypeSymbol errorTypeSymbol = new BErrorTypeSymbol(
SymTag.ERROR,
Flags.PUBLIC,
names.fromString("$anonErrorType$" + UNDERSCORE + errorCount++),
env.enclPkg.symbol.pkgID,
null, null, errorVariable.pos, VIRTUAL);
BType detailType;
if ((errorVariable.detail == null || errorVariable.detail.isEmpty()) && errorVariable.restDetail != null) {
detailType = symTable.detailType;
} else {
detailType = createDetailType(errorVariable.detail, errorVariable.restDetail, errorCount++,
errorVariable.pos);
BLangRecordTypeNode recordTypeNode = createRecordTypeNode(errorVariable, (BRecordType) detailType);
recordTypeNode.initFunction = TypeDefBuilderHelper
.createInitFunctionForRecordType(recordTypeNode, env, names, symTable);
TypeDefBuilderHelper.createTypeDefinitionForTSymbol(detailType, detailType.tsymbol,
recordTypeNode, env);
}
BErrorType errorType = new BErrorType(errorTypeSymbol, detailType);
errorTypeSymbol.type = errorType;
TypeDefBuilderHelper.createTypeDefinitionForTSymbol(errorType, errorTypeSymbol,
createErrorTypeNode(errorType), env);
return errorType;
}
return bindingPatternVariable.getBType();
}
private BLangRecordTypeNode createRecordTypeNode(BLangErrorVariable errorVariable, BRecordType detailType) {
List<BLangSimpleVariable> fieldList = new ArrayList<>();
for (BLangErrorVariable.BLangErrorDetailEntry field : errorVariable.detail) {
BVarSymbol symbol = field.valueBindingPattern.symbol;
if (symbol == null) {
symbol = new BVarSymbol(Flags.PUBLIC, names.fromString(field.key.value + "$"),
this.env.enclPkg.packageID, symTable.pureType, null,
field.valueBindingPattern.pos, VIRTUAL);
}
BLangSimpleVariable fieldVar = ASTBuilderUtil.createVariable(
field.valueBindingPattern.pos,
symbol.name.value,
field.valueBindingPattern.getBType(),
field.valueBindingPattern.expr,
symbol);
fieldList.add(fieldVar);
}
return TypeDefBuilderHelper.createRecordTypeNode(fieldList, detailType, errorVariable.pos);
}
private BType createDetailType(List<BLangErrorVariable.BLangErrorDetailEntry> detail,
BLangSimpleVariable restDetail, int errorNo, Location pos) {
BRecordType detailRecordType = createAnonRecordType(pos);
if (restDetail == null) {
detailRecordType.sealed = true;
}
for (BLangErrorVariable.BLangErrorDetailEntry detailEntry : detail) {
Name fieldName = names.fromIdNode(detailEntry.key);
BType fieldType = getStructuredBindingPatternType(detailEntry.valueBindingPattern);
BVarSymbol fieldSym = new BVarSymbol(Flags.PUBLIC, fieldName, detailRecordType.tsymbol.pkgID, fieldType,
detailRecordType.tsymbol, detailEntry.key.pos, VIRTUAL);
detailRecordType.fields.put(fieldName.value, new BField(fieldName, detailEntry.key.pos, fieldSym));
detailRecordType.tsymbol.scope.define(fieldName, fieldSym);
}
return detailRecordType;
}
private BRecordType createAnonRecordType(Location pos) {
BRecordTypeSymbol detailRecordTypeSymbol = new BRecordTypeSymbol(
SymTag.RECORD,
Flags.PUBLIC,
names.fromString(anonModelHelper.getNextRecordVarKey(env.enclPkg.packageID)),
env.enclPkg.symbol.pkgID, null, null, pos, VIRTUAL);
detailRecordTypeSymbol.initializerFunc = createRecordInitFunc();
detailRecordTypeSymbol.scope = new Scope(detailRecordTypeSymbol);
detailRecordTypeSymbol.scope.define(
names.fromString(detailRecordTypeSymbol.name.value + "." +
detailRecordTypeSymbol.initializerFunc.funcName.value),
detailRecordTypeSymbol.initializerFunc.symbol);
BRecordType detailRecordType = new BRecordType(detailRecordTypeSymbol);
detailRecordType.restFieldType = symTable.anydataType;
return detailRecordType;
}
private BAttachedFunction createRecordInitFunc() {
BInvokableType bInvokableType = new BInvokableType(new ArrayList<>(), symTable.nilType, null);
BInvokableSymbol initFuncSymbol = Symbols.createFunctionSymbol(
Flags.PUBLIC, Names.EMPTY, Names.EMPTY, env.enclPkg.symbol.pkgID, bInvokableType, env.scope.owner,
false, symTable.builtinPos, VIRTUAL);
initFuncSymbol.retType = symTable.nilType;
return new BAttachedFunction(Names.INIT_FUNCTION_SUFFIX, initFuncSymbol, bInvokableType, symTable.builtinPos);
}
BLangErrorType createErrorTypeNode(BErrorType errorType) {
BLangErrorType errorTypeNode = (BLangErrorType) TreeBuilder.createErrorTypeNode();
errorTypeNode.setBType(errorType);
return errorTypeNode;
}
private BLangExpression createBinaryExpression(Location pos, BLangSimpleVarRef varRef,
BLangExpression expression) {
BLangBinaryExpr binaryExpr;
if (NodeKind.GROUP_EXPR == expression.getKind()) {
return createBinaryExpression(pos, varRef, ((BLangGroupExpr) expression).expression);
}
if (NodeKind.BINARY_EXPR == expression.getKind()) {
binaryExpr = (BLangBinaryExpr) expression;
BLangExpression lhsExpr = createBinaryExpression(pos, varRef, binaryExpr.lhsExpr);
BLangExpression rhsExpr = createBinaryExpression(pos, varRef, binaryExpr.rhsExpr);
binaryExpr = ASTBuilderUtil.createBinaryExpr(pos, lhsExpr, rhsExpr, symTable.booleanType, OperatorKind.OR,
(BOperatorSymbol) symResolver
.resolveBinaryOperator(OperatorKind.OR, symTable.booleanType, symTable.booleanType));
} else if (expression.getKind() == NodeKind.SIMPLE_VARIABLE_REF
&& ((BLangSimpleVarRef) expression).variableName.value.equals(IGNORE.value)) {
BLangValueType anyType = (BLangValueType) TreeBuilder.createValueTypeNode();
anyType.setBType(symTable.anyType);
anyType.typeKind = TypeKind.ANY;
return ASTBuilderUtil.createTypeTestExpr(pos, varRef, anyType);
} else {
binaryExpr = ASTBuilderUtil
.createBinaryExpr(pos, varRef, expression, symTable.booleanType, OperatorKind.EQUAL, null);
BSymbol opSymbol = symResolver.resolveBinaryOperator(OperatorKind.EQUAL, varRef.getBType(),
expression.getBType());
if (opSymbol == symTable.notFoundSymbol) {
opSymbol = symResolver
.getBinaryEqualityForTypeSets(OperatorKind.EQUAL, symTable.anydataType, expression.getBType(),
binaryExpr, env);
}
binaryExpr.opSymbol = (BOperatorSymbol) opSymbol;
}
return binaryExpr;
}
private BLangIsLikeExpr createIsLikeExpression(Location pos, BLangExpression expr, BType type) {
return ASTBuilderUtil.createIsLikeExpr(pos, expr, ASTBuilderUtil.createTypeNode(type), symTable.booleanType);
}
private BLangAssignment createAssignmentStmt(BLangSimpleVariable variable) {
BLangSimpleVarRef varRef = (BLangSimpleVarRef) TreeBuilder.createSimpleVariableReferenceNode();
varRef.pos = variable.pos;
varRef.variableName = variable.name;
varRef.symbol = variable.symbol;
varRef.setBType(variable.getBType());
BLangAssignment assignmentStmt = (BLangAssignment) TreeBuilder.createAssignmentNode();
assignmentStmt.expr = variable.expr;
assignmentStmt.pos = variable.pos;
assignmentStmt.setVariable(varRef);
return assignmentStmt;
}
private BLangAssignment createStructFieldUpdate(BLangFunction function, BLangSimpleVariable variable,
BVarSymbol selfSymbol) {
return createStructFieldUpdate(function, variable.expr, variable.symbol, variable.getBType(), selfSymbol,
variable.name);
}
private BLangAssignment createStructFieldUpdate(BLangFunction function, BLangExpression expr,
BVarSymbol fieldSymbol, BType fieldType, BVarSymbol selfSymbol,
BLangIdentifier fieldName) {
BLangSimpleVarRef selfVarRef = ASTBuilderUtil.createVariableRef(function.pos, selfSymbol);
BLangFieldBasedAccess fieldAccess = ASTBuilderUtil.createFieldAccessExpr(selfVarRef, fieldName);
fieldAccess.symbol = fieldSymbol;
fieldAccess.setBType(fieldType);
fieldAccess.isStoreOnCreation = true;
BLangAssignment assignmentStmt = (BLangAssignment) TreeBuilder.createAssignmentNode();
assignmentStmt.expr = expr;
assignmentStmt.pos = function.pos;
assignmentStmt.setVariable(fieldAccess);
SymbolEnv initFuncEnv = SymbolEnv.createFunctionEnv(function, function.symbol.scope, env);
return rewrite(assignmentStmt, initFuncEnv);
}
private boolean safeNavigate(BLangAccessExpression accessExpr) {
if (accessExpr.isLValue || accessExpr.expr == null) {
return false;
}
if (accessExpr.errorSafeNavigation || accessExpr.nilSafeNavigation) {
return true;
}
NodeKind kind = accessExpr.expr.getKind();
if (kind == NodeKind.FIELD_BASED_ACCESS_EXPR ||
kind == NodeKind.INDEX_BASED_ACCESS_EXPR) {
return safeNavigate((BLangAccessExpression) accessExpr.expr);
}
return false;
}
private BLangExpression rewriteSafeNavigationExpr(BLangAccessExpression accessExpr) {
BType originalExprType = accessExpr.getBType();
String matchTempResultVarName = GEN_VAR_PREFIX.value + "temp_result";
BLangSimpleVariable tempResultVar =
ASTBuilderUtil.createVariable(accessExpr.pos, matchTempResultVarName, accessExpr.getBType(), null,
new BVarSymbol(0, names.fromString(matchTempResultVarName),
this.env.scope.owner.pkgID, accessExpr.getBType(),
this.env.scope.owner, accessExpr.pos, VIRTUAL));
BLangSimpleVariableDef tempResultVarDef = ASTBuilderUtil.createVariableDef(accessExpr.pos, tempResultVar);
BLangVariableReference tempResultVarRef =
ASTBuilderUtil.createVariableRef(accessExpr.pos, tempResultVar.symbol);
handleSafeNavigation(accessExpr, accessExpr.getBType(), tempResultVar);
BLangMatchStatement matchStmt = this.matchStmtStack.firstElement();
BLangBlockStmt blockStmt =
ASTBuilderUtil.createBlockStmt(accessExpr.pos, Lists.of(tempResultVarDef, matchStmt));
BLangStatementExpression stmtExpression = createStatementExpression(blockStmt, tempResultVarRef);
stmtExpression.setBType(originalExprType);
this.matchStmtStack = new Stack<>();
this.accessExprStack = new Stack<>();
this.successClause = null;
this.safeNavigationAssignment = null;
return stmtExpression;
}
private void handleSafeNavigation(BLangAccessExpression accessExpr, BType type, BLangSimpleVariable tempResultVar) {
if (accessExpr.expr == null) {
return;
}
NodeKind kind = accessExpr.expr.getKind();
if (kind == NodeKind.FIELD_BASED_ACCESS_EXPR || kind == NodeKind.INDEX_BASED_ACCESS_EXPR) {
handleSafeNavigation((BLangAccessExpression) accessExpr.expr, type, tempResultVar);
}
if (!(accessExpr.errorSafeNavigation || accessExpr.nilSafeNavigation)) {
BType originalType = Types.getReferredType(accessExpr.originalType);
if (TypeTags.isXMLTypeTag(originalType.tag) || isMapJson(originalType)) {
accessExpr.setBType(BUnionType.create(null, originalType, symTable.errorType));
} else {
accessExpr.setBType(originalType);
}
if (this.safeNavigationAssignment != null) {
this.safeNavigationAssignment.expr = addConversionExprIfRequired(accessExpr, tempResultVar.getBType());
}
return;
}
/*
* If the field access is a safe navigation, create a match expression.
* Then chain the current expression as the success-pattern of the parent
* match expr, if available.
* eg:
* x but {              <--- parent match expr
*   error e => e,
*   T t => t.y but {   <--- current expr
*      error e => e,
*      R r => r.z
*   }
* }
*/
BLangExpression matchExpr = accessExpr.expr;
BType matchExprType = accessExpr.expr.getBType();
Location pos = accessExpr.pos;
BLangMatchStatement matchStmt = ASTBuilderUtil.createMatchStatement(matchExpr, pos);
boolean isAllTypesRecords = false;
LinkedHashSet<BType> memTypes = new LinkedHashSet<>();
BType referredType = Types.getReferredType(matchExpr.getBType());
if (referredType.tag == TypeTags.UNION) {
memTypes = new LinkedHashSet<>(((BUnionType) referredType).getMemberTypes());
isAllTypesRecords = isAllTypesAreRecordsInUnion(memTypes);
}
if (accessExpr.nilSafeNavigation) {
matchStmt.addMatchClause(getMatchNullClause(matchExpr, tempResultVar));
matchStmt.setBType(type);
memTypes.remove(symTable.nilType);
}
if (accessExpr.errorSafeNavigation) {
matchStmt.addMatchClause(getMatchErrorClause(matchExpr, tempResultVar));
matchStmt.setBType(type);
matchStmt.pos = pos;
memTypes.remove(symTable.errorType);
}
BLangMatchClause successClause = null;
Name field = getFieldName(accessExpr);
if (field == Names.EMPTY) {
successClause = getSuccessPatternClause(matchExprType, matchExpr, accessExpr, tempResultVar,
accessExpr.errorSafeNavigation);
matchStmt.addMatchClause(successClause);
pushToMatchStatementStack(matchStmt, successClause, pos);
return;
}
if (isAllTypesRecords) {
for (BType memberType : memTypes) {
BRecordType recordType = (BRecordType) Types.getReferredType(memberType);
if (recordType.fields.containsKey(field.value) || !recordType.sealed) {
successClause = getSuccessPatternClause(memberType, matchExpr, accessExpr, tempResultVar,
accessExpr.errorSafeNavigation);
matchStmt.addMatchClause(successClause);
}
}
matchStmt.addMatchClause(getMatchAllAndNilReturnClause(matchExpr, tempResultVar));
pushToMatchStatementStack(matchStmt, successClause, pos);
return;
}
successClause = getSuccessPatternClause(matchExprType, matchExpr, accessExpr, tempResultVar,
accessExpr.errorSafeNavigation);
matchStmt.addMatchClause(successClause);
pushToMatchStatementStack(matchStmt, successClause, pos);
}
private boolean isMapJson(BType originalType) {
return originalType.tag == TypeTags.MAP && ((BMapType) originalType).getConstraint().tag == TypeTags.JSON;
}
private void pushToMatchStatementStack(BLangMatchStatement matchStmt, BLangMatchClause successClause,
Location pos) {
this.matchStmtStack.push(matchStmt);
if (this.successClause != null) {
this.successClause.blockStmt = ASTBuilderUtil.createBlockStmt(pos, this.env.scope, Lists.of(matchStmt));
}
this.successClause = successClause;
}
private Name getFieldName(BLangAccessExpression accessExpr) {
Name field = Names.EMPTY;
if (accessExpr.getKind() == NodeKind.FIELD_BASED_ACCESS_EXPR) {
field = new Name(((BLangFieldBasedAccess) accessExpr).field.value);
} else if (accessExpr.getKind() == NodeKind.INDEX_BASED_ACCESS_EXPR) {
BLangExpression indexBasedExpression = ((BLangIndexBasedAccess) accessExpr).indexExpr;
if (indexBasedExpression.getKind() == NodeKind.LITERAL) {
field = new Name(((BLangLiteral) indexBasedExpression).value.toString());
}
}
return field;
}
private boolean isAllTypesAreRecordsInUnion(LinkedHashSet<BType> memTypes) {
for (BType memType : memTypes) {
int typeTag = Types.getReferredType(memType).tag;
if (typeTag != TypeTags.RECORD && typeTag != TypeTags.ERROR && typeTag != TypeTags.NIL) {
return false;
}
}
return true;
}
private BLangMatchClause getMatchErrorClause(BLangExpression matchExpr, BLangSimpleVariable tempResultVar) {
String errorPatternVarName = GEN_VAR_PREFIX.value + "t_match_error";
Location pos = matchExpr.pos;
BVarSymbol errorPatternVarSymbol = new BVarSymbol(0, Names.fromString(errorPatternVarName),
this.env.scope.owner.pkgID, symTable.anyOrErrorType, this.env.scope.owner, pos, VIRTUAL);
BLangCaptureBindingPattern captureBindingPattern =
ASTBuilderUtil.createCaptureBindingPattern(errorPatternVarSymbol, errorPatternVarName);
BLangVarBindingPatternMatchPattern varBindingPatternMatchPattern =
ASTBuilderUtil.createVarBindingPatternMatchPattern(captureBindingPattern, matchExpr);
BLangSimpleVarRef assignmentRhsExpr = ASTBuilderUtil.createVariableRef(pos, errorPatternVarSymbol);
BLangVariableReference tempResultVarRef = ASTBuilderUtil.createVariableRef(pos, tempResultVar.symbol);
BLangAssignment assignmentStmt =
ASTBuilderUtil.createAssignmentStmt(pos, tempResultVarRef, assignmentRhsExpr);
BLangBlockStmt clauseBody = ASTBuilderUtil.createBlockStmt(pos, this.env.scope, Lists.of(assignmentStmt));
BLangExpression matchGuard = ASTBuilderUtil.createTypeTestExpr(pos, assignmentRhsExpr, getErrorTypeNode());
matchGuard.setBType(symTable.booleanType);
return ASTBuilderUtil.createMatchClause(matchExpr, clauseBody, matchGuard, varBindingPatternMatchPattern);
}
private BLangMatchClause getMatchNullClause(BLangExpression matchExpr, BLangSimpleVariable tempResultVar) {
String nullPatternVarName = GEN_VAR_PREFIX.value + "t_match_null";
Location pos = matchExpr.pos;
BVarSymbol nullPatternVarSymbol = new BVarSymbol(0, Names.fromString(nullPatternVarName),
this.env.scope.owner.pkgID, symTable.anyOrErrorType, this.env.scope.owner, pos, VIRTUAL);
BLangCaptureBindingPattern captureBindingPattern =
ASTBuilderUtil.createCaptureBindingPattern(nullPatternVarSymbol, nullPatternVarName);
BLangVarBindingPatternMatchPattern varBindingPatternMatchPattern =
ASTBuilderUtil.createVarBindingPatternMatchPattern(captureBindingPattern, matchExpr);
BLangSimpleVarRef assignmentRhsExpr = ASTBuilderUtil.createVariableRef(pos, nullPatternVarSymbol);
BLangVariableReference tempResultVarRef = ASTBuilderUtil.createVariableRef(pos, tempResultVar.symbol);
BLangAssignment assignmentStmt =
ASTBuilderUtil.createAssignmentStmt(pos, tempResultVarRef, assignmentRhsExpr);
BLangBlockStmt clauseBody = ASTBuilderUtil.createBlockStmt(pos, this.env.scope, Lists.of(assignmentStmt));
BLangExpression matchGuard = ASTBuilderUtil.createTypeTestExpr(pos, assignmentRhsExpr, getNillTypeNode());
matchGuard.setBType(symTable.booleanType);
return ASTBuilderUtil.createMatchClause(matchExpr, clauseBody, matchGuard, varBindingPatternMatchPattern);
}
private BLangMatchClause getMatchAllAndNilReturnClause(BLangExpression matchExpr,
BLangSimpleVariable tempResultVar) {
Location pos = matchExpr.pos;
BLangVariableReference tempResultVarRef = ASTBuilderUtil.createVariableRef(pos, tempResultVar.symbol);
BLangAssignment assignmentStmt =
ASTBuilderUtil.createAssignmentStmt(pos, tempResultVarRef, createLiteral(pos, symTable.nilType,
Names.NIL_VALUE));
BLangBlockStmt clauseBody = ASTBuilderUtil.createBlockStmt(pos, this.env.scope, Lists.of(assignmentStmt));
BLangWildCardMatchPattern wildCardMatchPattern = ASTBuilderUtil.createWildCardMatchPattern(matchExpr);
wildCardMatchPattern.setBType(symTable.anyType);
return ASTBuilderUtil.createMatchClause(matchExpr, clauseBody, null, wildCardMatchPattern);
}
private BLangMatchClause getSuccessPatternClause(BType type, BLangExpression matchExpr,
BLangAccessExpression accessExpr,
BLangSimpleVariable tempResultVar, boolean liftError) {
type = types.getSafeType(type, true, liftError);
String successPatternVarName = GEN_VAR_PREFIX.value + "t_match_success";
Location pos = accessExpr.pos;
BVarSymbol  successPatternSymbol;
if (Types.getReferredType(type).tag == TypeTags.INVOKABLE) {
successPatternSymbol = new BInvokableSymbol(SymTag.VARIABLE, 0, Names.fromString(successPatternVarName),
this.env.scope.owner.pkgID, symTable.anyOrErrorType, this.env.scope.owner, pos, VIRTUAL);
} else {
successPatternSymbol = new BVarSymbol(0, Names.fromString(successPatternVarName),
this.env.scope.owner.pkgID, symTable.anyOrErrorType, this.env.scope.owner, pos, VIRTUAL);
}
BLangSimpleVariable successPatternVar = ASTBuilderUtil.createVariable(accessExpr.pos, successPatternVarName,
type, null, successPatternSymbol);
BLangSimpleVarRef successPatternVarRef = ASTBuilderUtil.createVariableRef(accessExpr.pos,
successPatternVar.symbol);
BLangCaptureBindingPattern captureBindingPattern =
ASTBuilderUtil.createCaptureBindingPattern(successPatternSymbol, successPatternVarName);
BLangVarBindingPatternMatchPattern varBindingPatternMatchPattern =
ASTBuilderUtil.createVarBindingPatternMatchPattern(captureBindingPattern, matchExpr);
BLangAccessExpression tempAccessExpr = nodeCloner.cloneNode(accessExpr);
if (accessExpr.getKind() == NodeKind.INDEX_BASED_ACCESS_EXPR) {
((BLangIndexBasedAccess) tempAccessExpr).indexExpr = ((BLangIndexBasedAccess) accessExpr).indexExpr;
}
if (accessExpr instanceof BLangFieldBasedAccess.BLangNSPrefixedFieldBasedAccess) {
((BLangFieldBasedAccess.BLangNSPrefixedFieldBasedAccess) tempAccessExpr).nsSymbol =
((BLangFieldBasedAccess.BLangNSPrefixedFieldBasedAccess) accessExpr).nsSymbol;
}
tempAccessExpr.expr = addConversionExprIfRequired(successPatternVarRef, type);
tempAccessExpr.errorSafeNavigation = false;
tempAccessExpr.nilSafeNavigation = false;
accessExpr.cloneRef = null;
if (TypeTags.isXMLTypeTag(Types.getReferredType(tempAccessExpr.expr.getBType()).tag)) {
tempAccessExpr.setBType(BUnionType.create(null, accessExpr.originalType, symTable.errorType,
symTable.nilType));
} else {
tempAccessExpr.setBType(accessExpr.originalType);
}
tempAccessExpr.optionalFieldAccess = accessExpr.optionalFieldAccess;
BLangVariableReference tempResultVarRef =
ASTBuilderUtil.createVariableRef(accessExpr.pos, tempResultVar.symbol);
BLangExpression assignmentRhsExpr = addConversionExprIfRequired(tempAccessExpr, tempResultVarRef.getBType());
BLangAssignment assignmentStmt =
ASTBuilderUtil.createAssignmentStmt(accessExpr.pos, tempResultVarRef, assignmentRhsExpr);
BLangBlockStmt clauseBody = ASTBuilderUtil.createBlockStmt(accessExpr.pos, this.env.scope,
Lists.of(assignmentStmt));
BLangExpression matchGuard = ASTBuilderUtil.createTypeTestExpr(pos, successPatternVarRef, createTypeNode(type));
matchGuard.setBType(symTable.booleanType);
return ASTBuilderUtil.createMatchClause(matchExpr, clauseBody, matchGuard, varBindingPatternMatchPattern);
}
BLangValueType getNillTypeNode() {
BLangValueType nillTypeNode = (BLangValueType) TreeBuilder.createValueTypeNode();
nillTypeNode.typeKind = TypeKind.NIL;
nillTypeNode.setBType(symTable.nilType);
return nillTypeNode;
}
BLangValueType createTypeNode(BType type) {
BLangValueType typeNode = (BLangValueType) TreeBuilder.createValueTypeNode();
typeNode.typeKind = type.getKind();
typeNode.setBType(type);
return typeNode;
}
private BLangValueExpression cloneExpression(BLangExpression expr) {
switch (expr.getKind()) {
case SIMPLE_VARIABLE_REF:
return ASTBuilderUtil.createVariableRef(expr.pos, ((BLangSimpleVarRef) expr).symbol);
case FIELD_BASED_ACCESS_EXPR:
case INDEX_BASED_ACCESS_EXPR:
return cloneAccessExpr((BLangAccessExpression) expr);
default:
throw new IllegalStateException();
}
}
private BLangAccessExpression cloneAccessExpr(BLangAccessExpression originalAccessExpr) {
if (originalAccessExpr.expr == null) {
return originalAccessExpr;
}
BLangExpression varRef;
NodeKind kind = originalAccessExpr.expr.getKind();
if (kind == NodeKind.FIELD_BASED_ACCESS_EXPR || kind == NodeKind.INDEX_BASED_ACCESS_EXPR) {
varRef = cloneAccessExpr((BLangAccessExpression) originalAccessExpr.expr);
} else {
varRef = cloneExpression(originalAccessExpr.expr);
}
varRef.setBType(types.getSafeType(originalAccessExpr.expr.getBType(), true, false));
BLangAccessExpression accessExpr;
switch (originalAccessExpr.getKind()) {
case FIELD_BASED_ACCESS_EXPR:
accessExpr = ASTBuilderUtil.createFieldAccessExpr(varRef,
((BLangFieldBasedAccess) originalAccessExpr).field);
break;
case INDEX_BASED_ACCESS_EXPR:
accessExpr = ASTBuilderUtil.createIndexAccessExpr(varRef,
((BLangIndexBasedAccess) originalAccessExpr).indexExpr);
break;
default:
throw new IllegalStateException();
}
accessExpr.originalType = originalAccessExpr.originalType;
accessExpr.pos = originalAccessExpr.pos;
accessExpr.isLValue = originalAccessExpr.isLValue;
accessExpr.symbol = originalAccessExpr.symbol;
accessExpr.errorSafeNavigation = false;
accessExpr.nilSafeNavigation = false;
accessExpr.setBType(originalAccessExpr.originalType);
return accessExpr;
}
private BLangBinaryExpr getModifiedIntRangeStartExpr(BLangExpression expr) {
BLangLiteral constOneLiteral = ASTBuilderUtil.createLiteral(expr.pos, symTable.intType, 1L);
return ASTBuilderUtil.createBinaryExpr(expr.pos, expr, constOneLiteral, symTable.intType, OperatorKind.ADD,
(BOperatorSymbol) symResolver.resolveBinaryOperator(OperatorKind.ADD,
symTable.intType,
symTable.intType));
}
private BLangBinaryExpr getModifiedIntRangeEndExpr(BLangExpression expr) {
BLangLiteral constOneLiteral = ASTBuilderUtil.createLiteral(expr.pos, symTable.intType, 1L);
return ASTBuilderUtil.createBinaryExpr(expr.pos, expr, constOneLiteral, symTable.intType, OperatorKind.SUB,
(BOperatorSymbol) symResolver.resolveBinaryOperator(OperatorKind.SUB,
symTable.intType,
symTable.intType));
}
private BLangLiteral getBooleanLiteral(boolean value) {
BLangLiteral literal = (BLangLiteral) TreeBuilder.createLiteralExpression();
literal.value = value;
literal.setBType(symTable.booleanType);
literal.pos = symTable.builtinPos;
return literal;
}
private boolean isDefaultableMappingType(BType type) {
switch (types.getSafeType(type, true, false).tag) {
case TypeTags.JSON:
case TypeTags.MAP:
case TypeTags.RECORD:
return true;
case TypeTags.TYPEREFDESC:
return isDefaultableMappingType(Types.getReferredType(type));
default:
return false;
}
}
private BLangFunction createInitFunctionForClassDefn(BLangClassDefinition classDefinition, SymbolEnv env) {
BType returnType = symTable.nilType;
if (classDefinition.initFunction != null) {
returnType = classDefinition.initFunction.getBType().getReturnType();
}
BLangFunction initFunction =
TypeDefBuilderHelper.createInitFunctionForStructureType(null, classDefinition.symbol,
env, names, GENERATED_INIT_SUFFIX,
classDefinition.getBType(), returnType);
BObjectTypeSymbol typeSymbol = ((BObjectTypeSymbol) classDefinition.getBType().tsymbol);
typeSymbol.generatedInitializerFunc = new BAttachedFunction(GENERATED_INIT_SUFFIX, initFunction.symbol,
(BInvokableType) initFunction.getBType(), null);
classDefinition.generatedInitFunction = initFunction;
initFunction.returnTypeNode.setBType(returnType);
return rewrite(initFunction, env);
}
private void visitBinaryLogicalExpr(BLangBinaryExpr binaryExpr) {
/*
* Desugar (lhsExpr && rhsExpr) to following if-else:
*
* logical AND:
* -------------
* T $result$;
* if (lhsExpr) {
*    $result$ = rhsExpr;
* } else {
*    $result$ = false;
* }
*
* logical OR:
* -------------
* T $result$;
* if (lhsExpr) {
*    $result$ = true;
* } else {
*    $result$ = rhsExpr;
* }
*
*/
BLangSimpleVariableDef resultVarDef = createVarDef("$result$", binaryExpr.getBType(), null,
symTable.builtinPos);
BLangBlockStmt thenBody = ASTBuilderUtil.createBlockStmt(binaryExpr.pos);
BLangBlockStmt elseBody = ASTBuilderUtil.createBlockStmt(binaryExpr.pos);
BLangSimpleVarRef thenResultVarRef = ASTBuilderUtil.createVariableRef(symTable.builtinPos,
resultVarDef.var.symbol);
BLangExpression thenResult;
if (binaryExpr.opKind == OperatorKind.AND) {
thenResult = binaryExpr.rhsExpr;
} else {
thenResult = getBooleanLiteral(true);
}
BLangAssignment thenAssignment =
ASTBuilderUtil.createAssignmentStmt(binaryExpr.pos, thenResultVarRef, thenResult);
thenBody.addStatement(thenAssignment);
BLangExpression elseResult;
BLangSimpleVarRef elseResultVarRef = ASTBuilderUtil.createVariableRef(symTable.builtinPos,
resultVarDef.var.symbol);
if (binaryExpr.opKind == OperatorKind.AND) {
elseResult = getBooleanLiteral(false);
} else {
elseResult = binaryExpr.rhsExpr;
}
BLangAssignment elseAssignment =
ASTBuilderUtil.createAssignmentStmt(binaryExpr.pos, elseResultVarRef, elseResult);
elseBody.addStatement(elseAssignment);
BLangSimpleVarRef resultVarRef = ASTBuilderUtil.createVariableRef(binaryExpr.pos, resultVarDef.var.symbol);
BLangIf ifElse = ASTBuilderUtil.createIfElseStmt(binaryExpr.pos, binaryExpr.lhsExpr, thenBody, elseBody);
BLangBlockStmt blockStmt = ASTBuilderUtil.createBlockStmt(binaryExpr.pos, Lists.of(resultVarDef, ifElse));
BLangStatementExpression stmtExpr = createStatementExpression(blockStmt, resultVarRef);
stmtExpr.setBType(binaryExpr.getBType());
result = rewriteExpr(stmtExpr);
}
protected boolean isMappingOrObjectConstructorOrObjInit(BLangExpression expression) {
switch (expression.getKind()) {
case TYPE_INIT_EXPR:
case RECORD_LITERAL_EXPR:
case OBJECT_CTOR_EXPRESSION:
return true;
case CHECK_EXPR:
return isMappingOrObjectConstructorOrObjInit(((BLangCheckedExpr) expression).expr);
case TYPE_CONVERSION_EXPR:
return isMappingOrObjectConstructorOrObjInit(((BLangTypeConversionExpr) expression).expr);
default:
return false;
}
}
private BType getRestType(BInvokableSymbol invokableSymbol) {
if (invokableSymbol != null && invokableSymbol.restParam != null) {
return invokableSymbol.restParam.type;
}
return null;
}
private BType getRestType(BLangFunction function) {
if (function != null && function.restParam != null) {
return function.restParam.getBType();
}
return null;
}
private BVarSymbol getRestSymbol(BLangFunction function) {
if (function != null && function.restParam != null) {
return function.restParam.symbol;
}
return null;
}
private boolean isComputedKey(RecordLiteralNode.RecordField field) {
if (!field.isKeyValueField()) {
return false;
}
return ((BLangRecordLiteral.BLangRecordKeyValueField) field).key.computedKey;
}
private BLangRecordLiteral rewriteMappingConstructor(BLangRecordLiteral mappingConstructorExpr) {
List<RecordLiteralNode.RecordField> fields = mappingConstructorExpr.fields;
BType type = mappingConstructorExpr.getBType();
Location pos = mappingConstructorExpr.pos;
List<RecordLiteralNode.RecordField> rewrittenFields = new ArrayList<>(fields.size());
for (RecordLiteralNode.RecordField field : fields) {
if (field.isKeyValueField()) {
BLangRecordLiteral.BLangRecordKeyValueField keyValueField =
(BLangRecordLiteral.BLangRecordKeyValueField) field;
BLangRecordLiteral.BLangRecordKey key = keyValueField.key;
BLangExpression origKey = key.expr;
BLangExpression keyExpr;
if (key.computedKey) {
keyExpr = origKey;
} else {
keyExpr = origKey.getKind() == NodeKind.SIMPLE_VARIABLE_REF ? createStringLiteral(pos,
StringEscapeUtils.unescapeJava(((BLangSimpleVarRef) origKey).variableName.value)) :
((BLangLiteral) origKey);
}
BLangRecordLiteral.BLangRecordKeyValueField rewrittenField =
ASTBuilderUtil.createBLangRecordKeyValue(rewriteExpr(keyExpr),
rewriteExpr(keyValueField.valueExpr));
rewrittenField.pos = keyValueField.pos;
rewrittenField.key.pos = key.pos;
rewrittenFields.add(rewrittenField);
} else if (field.getKind() == NodeKind.SIMPLE_VARIABLE_REF) {
BLangSimpleVarRef varRefField = (BLangSimpleVarRef) field;
rewrittenFields.add(ASTBuilderUtil.createBLangRecordKeyValue(
rewriteExpr(createStringLiteral(pos,
StringEscapeUtils.unescapeJava(varRefField.variableName.value))),
rewriteExpr(varRefField)));
} else {
BLangRecordLiteral.BLangRecordSpreadOperatorField spreadOpField =
(BLangRecordLiteral.BLangRecordSpreadOperatorField) field;
spreadOpField.expr = rewriteExpr(spreadOpField.expr);
rewrittenFields.add(spreadOpField);
}
}
fields.clear();
BType refType = Types.getReferredType(type);
return refType.tag == TypeTags.RECORD ?
new BLangStructLiteral(pos, type, refType.tsymbol, rewrittenFields) :
new BLangMapLiteral(pos, type, rewrittenFields);
}
protected void addTransactionInternalModuleImport() {
if (!env.enclPkg.packageID.equals(PackageID.TRANSACTION_INTERNAL)) {
BLangImportPackage importDcl = (BLangImportPackage) TreeBuilder.createImportPackageNode();
List<BLangIdentifier> pkgNameComps = new ArrayList<>();
pkgNameComps.add(ASTBuilderUtil.createIdentifier(env.enclPkg.pos, Names.TRANSACTION.value));
importDcl.pkgNameComps = pkgNameComps;
importDcl.pos = env.enclPkg.symbol.pos;
importDcl.orgName = ASTBuilderUtil.createIdentifier(env.enclPkg.pos, Names.BALLERINA_INTERNAL_ORG.value);
importDcl.alias = ASTBuilderUtil.createIdentifier(env.enclPkg.pos, "trx");
importDcl.version = ASTBuilderUtil.createIdentifier(env.enclPkg.pos, "");
importDcl.symbol = symTable.internalTransactionModuleSymbol;
env.enclPkg.imports.add(importDcl);
env.enclPkg.symbol.imports.add(importDcl.symbol);
}
}
}

Line under review: BLangExpression firstRequiredArg = isExprAndRequiredArgSame ? invocation.requiredArgs.get(0) : null;

Code after addressing the review:
private BLangBlockStmt desugarForeachToWhile(BLangForeach foreach, BLangSimpleVariableDef varDef) {
BVarSymbol iteratorSymbol = varDef.var.symbol;
BVarSymbol resultSymbol = new BVarSymbol(0, names.fromString("$result$"), this.env.scope.owner.pkgID,
foreach.nillableResultType, this.env.scope.owner, foreach.pos,
VIRTUAL);
BLangSimpleVariableDef resultVariableDefinition = getIteratorNextVariableDefinition(foreach.pos,
foreach.nillableResultType, iteratorSymbol, resultSymbol);
BLangSimpleVarRef resultReferenceInWhile = ASTBuilderUtil.createVariableRef(foreach.pos, resultSymbol);
BLangStatementExpression statementExpression = ASTBuilderUtil.createStatementExpression(
resultVariableDefinition, resultReferenceInWhile);
statementExpression.setBType(foreach.nillableResultType);
BLangType userDefineType = getUserDefineTypeNode(foreach.resultType);
BLangTypeTestExpr typeTestExpr = ASTBuilderUtil
.createTypeTestExpr(foreach.pos, statementExpression, userDefineType);
BLangWhile whileNode = (BLangWhile) TreeBuilder.createWhileNode();
whileNode.pos = foreach.pos;
whileNode.expr = typeTestExpr;
whileNode.body = foreach.body;
VariableDefinitionNode variableDefinitionNode = foreach.variableDefinitionNode;
BLangFieldBasedAccess valueAccessExpr = getValueAccessExpression(foreach.pos, foreach.varType, resultSymbol);
BLangExpression expr = valueAccessExpr.expr;
valueAccessExpr.expr = addConversionExprIfRequired(expr, symTable.mapAllType);
variableDefinitionNode.getVariable()
.setInitialExpression(addConversionExprIfRequired(valueAccessExpr, foreach.varType));
whileNode.body.stmts.add(0, (BLangStatement) variableDefinitionNode);
BLangBlockStmt blockNode = ASTBuilderUtil.createBlockStmt(foreach.pos);
blockNode.addStatement(varDef);
blockNode.addStatement(whileNode);
return blockNode;
}
private BLangType getUserDefineTypeNode(BType type) {
BLangUserDefinedType recordType =
new BLangUserDefinedType(ASTBuilderUtil.createIdentifier(null, ""),
ASTBuilderUtil.createIdentifier(null, ""));
recordType.setBType(type);
return recordType;
}
@Override
public void visit(BLangWhile whileNode) {
if (whileNode.onFailClause != null) {
BLangOnFailClause onFailClause = whileNode.onFailClause;
whileNode.onFailClause = null;
whileNode.body.failureBreakMode = BLangBlockStmt.FailureBreakMode.NOT_BREAKABLE;
BLangDo doStmt = wrapStatementWithinDo(whileNode.pos, whileNode, onFailClause);
result = rewrite(doStmt, env);
} else {
whileNode.expr = rewriteExpr(whileNode.expr);
whileNode.body = rewrite(whileNode.body, env);
result = whileNode;
}
}
private BLangDo wrapStatementWithinDo(Location location, BLangStatement statement,
BLangOnFailClause onFailClause) {
BLangDo bLDo = (BLangDo) TreeBuilder.createDoNode();
BLangBlockStmt doBlock = ASTBuilderUtil.createBlockStmt(location);
doBlock.scope = new Scope(env.scope.owner);
bLDo.body = doBlock;
bLDo.pos = location;
bLDo.onFailClause = onFailClause;
bLDo.body.failureBreakMode = BLangBlockStmt.FailureBreakMode.BREAK_TO_OUTER_BLOCK;
doBlock.stmts.add(statement);
return bLDo;
}
@Override
public void visit(BLangLock lockNode) {
BLangOnFailClause currentOnFailClause = this.onFailClause;
BLangBlockStmt blockStmt = ASTBuilderUtil.createBlockStmt(lockNode.pos);
if (lockNode.onFailClause != null) {
blockStmt.failureBreakMode = BLangBlockStmt.FailureBreakMode.BREAK_TO_OUTER_BLOCK;
rewrite(lockNode.onFailClause, env);
}
BLangLockStmt lockStmt = new BLangLockStmt(lockNode.pos);
blockStmt.addStatement(lockStmt);
enclLocks.push(lockStmt);
BLangLiteral nilLiteral = ASTBuilderUtil.createLiteral(lockNode.pos, symTable.nilType, Names.NIL_VALUE);
BType nillableError = BUnionType.create(null, symTable.errorType, symTable.nilType);
BLangStatementExpression statementExpression = createStatementExpression(lockNode.body, nilLiteral);
statementExpression.setBType(symTable.nilType);
BLangTrapExpr trapExpr = (BLangTrapExpr) TreeBuilder.createTrapExpressionNode();
trapExpr.setBType(nillableError);
trapExpr.expr = statementExpression;
BVarSymbol nillableErrorVarSymbol = new BVarSymbol(0, names.fromString("$errorResult"),
this.env.scope.owner.pkgID, nillableError,
this.env.scope.owner, lockNode.pos, VIRTUAL);
BLangSimpleVariable simpleVariable = ASTBuilderUtil.createVariable(lockNode.pos, "$errorResult",
nillableError, trapExpr,
nillableErrorVarSymbol);
BLangSimpleVariableDef simpleVariableDef = ASTBuilderUtil.createVariableDef(lockNode.pos, simpleVariable);
blockStmt.addStatement(simpleVariableDef);
BLangUnLockStmt unLockStmt = new BLangUnLockStmt(lockNode.pos);
unLockStmt.relatedLock = lockStmt;
blockStmt.addStatement(unLockStmt);
BLangSimpleVarRef varRef = ASTBuilderUtil.createVariableRef(lockNode.pos, nillableErrorVarSymbol);
BLangBlockStmt ifBody = ASTBuilderUtil.createBlockStmt(lockNode.pos);
BLangPanic panicNode = (BLangPanic) TreeBuilder.createPanicNode();
panicNode.pos = lockNode.pos;
panicNode.expr = addConversionExprIfRequired(varRef, symTable.errorType);
ifBody.addStatement(panicNode);
BLangTypeTestExpr isErrorTest =
ASTBuilderUtil.createTypeTestExpr(lockNode.pos, varRef, getErrorTypeNode());
isErrorTest.setBType(symTable.booleanType);
BLangIf ifelse = ASTBuilderUtil.createIfElseStmt(lockNode.pos, isErrorTest, ifBody, null);
blockStmt.addStatement(ifelse);
result = rewrite(blockStmt, env);
enclLocks.pop();
this.onFailClause = currentOnFailClause;
}
@Override
public void visit(BLangLockStmt lockStmt) {
result = lockStmt;
}
@Override
public void visit(BLangUnLockStmt unLockStmt) {
result = unLockStmt;
}
private BLangOnFailClause createTrxInternalOnFail(Location pos, BLangSimpleVarRef shouldPanicRef,
BLangSimpleVarRef shouldRetryRef) {
BLangOnFailClause trxOnFailClause = (BLangOnFailClause) TreeBuilder.createOnFailClauseNode();
trxOnFailClause.pos = pos;
trxOnFailClause.body = ASTBuilderUtil.createBlockStmt(pos);
trxOnFailClause.body.scope = new Scope(env.scope.owner);
trxOnFailClause.isInternal = true;
BVarSymbol trxOnFailErrorSym = new BVarSymbol(0, names.fromString("$trxError$"),
env.scope.owner.pkgID, symTable.errorType, env.scope.owner, pos, VIRTUAL);
BLangSimpleVariable trxOnFailError = ASTBuilderUtil.createVariable(pos,
"$trxError$", symTable.errorType, null, trxOnFailErrorSym);
trxOnFailClause.variableDefinitionNode = ASTBuilderUtil.createVariableDef(pos,
trxOnFailError);
trxOnFailClause.body.scope.define(trxOnFailErrorSym.name, trxOnFailErrorSym);
transactionDesugar.createRollbackIfFailed(pos, trxOnFailClause.body, trxOnFailErrorSym,
trxBlockId, shouldRetryRef);
BLangGroupExpr shouldNotPanic = new BLangGroupExpr();
shouldNotPanic.setBType(symTable.booleanType);
shouldNotPanic.expression = createNotBinaryExpression(pos, shouldPanicRef);
BLangSimpleVarRef caughtError =  ASTBuilderUtil.createVariableRef(pos, trxOnFailErrorSym);
BLangBlockStmt failBlock = ASTBuilderUtil.createBlockStmt(pos);
BLangPanic panicNode = (BLangPanic) TreeBuilder.createPanicNode();
panicNode.pos = pos;
panicNode.expr = caughtError;
BLangIf exitIf = ASTBuilderUtil.createIfElseStmt(pos, shouldNotPanic, failBlock, panicNode);
trxOnFailClause.body.stmts.add(exitIf);
BLangFail failStmt = (BLangFail) TreeBuilder.createFailNode();
failStmt.pos = pos;
failStmt.expr = caughtError;
failBlock.stmts.add(failStmt);
trxOnFailClause.bodyContainsFail = true;
return trxOnFailClause;
}
@Override
public void visit(BLangTransaction transactionNode) {
if (transactionNode.onFailClause != null) {
BLangOnFailClause onFailClause = transactionNode.onFailClause;
transactionNode.onFailClause = null;
transactionNode.transactionBody.failureBreakMode = BLangBlockStmt.FailureBreakMode.NOT_BREAKABLE;
BLangDo doStmt = wrapStatementWithinDo(transactionNode.pos, transactionNode, onFailClause);
result = rewrite(doStmt, env);
} else {
BLangLiteral currentTrxBlockId = this.trxBlockId;
String uniqueId = String.valueOf(++transactionBlockCount);
this.trxBlockId = ASTBuilderUtil.createLiteral(transactionNode.pos, symTable.stringType, uniqueId);
boolean currShouldReturnErrors = this.shouldReturnErrors;
this.shouldReturnErrors = true;
BLangOnFailClause currOnFailClause = this.onFailClause;
BLangLiteral falseLiteral = ASTBuilderUtil.createLiteral(transactionNode.pos, symTable.booleanType, false);
BVarSymbol shouldPanicVarSymbol = new BVarSymbol(0, names.fromString("$shouldPanic$"),
env.scope.owner.pkgID, symTable.booleanType, this.env.scope.owner, transactionNode.pos, VIRTUAL);
shouldPanicVarSymbol.closure = true;
BLangSimpleVariable shouldPanicVariable = ASTBuilderUtil.createVariable(transactionNode.pos,
"$shouldPanic$", symTable.booleanType, falseLiteral, shouldPanicVarSymbol);
BLangSimpleVariableDef shouldPanicDef = ASTBuilderUtil.createVariableDef(transactionNode.pos,
shouldPanicVariable);
BLangSimpleVarRef shouldPanicRef = ASTBuilderUtil.createVariableRef(transactionNode.pos,
shouldPanicVarSymbol);
BLangOnFailClause trxInternalOnFail = createTrxInternalOnFail(transactionNode.pos, shouldPanicRef,
this.shouldRetryRef);
enclosingShouldPanic.put(trxInternalOnFail, shouldPanicRef);
boolean userDefinedOnFailAvbl = this.onFailClause != null;
analyzeOnFailClause(trxInternalOnFail, transactionNode.transactionBody);
BLangBlockStmt transactionStmtBlock =
transactionDesugar.rewrite(transactionNode, trxBlockId, env, uniqueId);
transactionStmtBlock.stmts.add(0, shouldPanicDef);
transactionStmtBlock.scope.define(shouldPanicVarSymbol.name, shouldPanicVarSymbol);
transactionStmtBlock.failureBreakMode = userDefinedOnFailAvbl ?
BLangBlockStmt.FailureBreakMode.NOT_BREAKABLE :
BLangBlockStmt.FailureBreakMode.BREAK_TO_OUTER_BLOCK;
result = rewrite(transactionStmtBlock, this.env);
this.shouldReturnErrors = currShouldReturnErrors;
this.trxBlockId = currentTrxBlockId;
swapAndResetEnclosingOnFail(currOnFailClause);
}
}
@Override
public void visit(BLangRollback rollbackNode) {
BLangBlockStmt rollbackStmtExpr = transactionDesugar.desugar(rollbackNode, trxBlockId, this.shouldRetryRef);
result = rewrite(rollbackStmtExpr, env);
}
private BLangOnFailClause createRetryInternalOnFail(Location pos,
BLangSimpleVarRef retryResultRef,
BLangSimpleVarRef retryManagerRef,
BLangSimpleVarRef shouldRetryRef,
BLangSimpleVarRef continueLoopRef,
BLangSimpleVarRef returnResult) {
BLangOnFailClause internalOnFail = (BLangOnFailClause) TreeBuilder.createOnFailClauseNode();
internalOnFail.pos = pos;
internalOnFail.body = ASTBuilderUtil.createBlockStmt(pos);
internalOnFail.body.scope = new Scope(env.scope.owner);
BVarSymbol caughtErrorSym = new BVarSymbol(0, names.fromString("$caughtError$"),
env.scope.owner.pkgID, symTable.errorType, env.scope.owner, pos, VIRTUAL);
BLangSimpleVariable caughtError = ASTBuilderUtil.createVariable(pos,
"$caughtError$", symTable.errorType, null, caughtErrorSym);
internalOnFail.variableDefinitionNode = ASTBuilderUtil.createVariableDef(pos,
caughtError);
env.scope.define(caughtErrorSym.name, caughtErrorSym);
BLangSimpleVarRef caughtErrorRef = ASTBuilderUtil.createVariableRef(pos, caughtErrorSym);
BLangAssignment errorAssignment = ASTBuilderUtil.createAssignmentStmt(pos, retryResultRef, caughtErrorRef);
internalOnFail.body.stmts.add(errorAssignment);
BLangAssignment continueLoopTrue = ASTBuilderUtil.createAssignmentStmt(pos, continueLoopRef,
ASTBuilderUtil.createLiteral(pos, symTable.booleanType, true));
internalOnFail.body.stmts.add(continueLoopTrue);
BLangInvocation shouldRetryInvocation = createRetryManagerShouldRetryInvocation(pos,
retryManagerRef, caughtErrorRef);
BLangAssignment shouldRetryAssignment = ASTBuilderUtil.createAssignmentStmt(pos, shouldRetryRef,
shouldRetryInvocation);
internalOnFail.body.stmts.add(shouldRetryAssignment);
BLangGroupExpr shouldNotRetryCheck = new BLangGroupExpr();
shouldNotRetryCheck.setBType(symTable.booleanType);
shouldNotRetryCheck.expression = createNotBinaryExpression(pos, shouldRetryRef);
BLangGroupExpr exitCheck = new BLangGroupExpr();
exitCheck.setBType(symTable.booleanType);
exitCheck.expression = shouldNotRetryCheck;
BLangBlockStmt exitLogicBlock = ASTBuilderUtil.createBlockStmt(pos);
BLangIf exitIf = ASTBuilderUtil.createIfElseStmt(pos, exitCheck, exitLogicBlock, null);
if (this.onFailClause != null) {
BLangFail failStmt = (BLangFail) TreeBuilder.createFailNode();
failStmt.pos = pos;
failStmt.expr = retryResultRef;
exitLogicBlock.stmts.add(failStmt);
internalOnFail.bodyContainsFail = true;
internalOnFail.body.stmts.add(exitIf);
BLangContinue loopContinueStmt = (BLangContinue) TreeBuilder.createContinueNode();
loopContinueStmt.pos = pos;
internalOnFail.body.stmts.add(loopContinueStmt);
} else {
BLangAssignment returnErrorTrue = ASTBuilderUtil.createAssignmentStmt(pos, returnResult,
ASTBuilderUtil.createLiteral(pos, symTable.booleanType, true));
exitLogicBlock.stmts.add(returnErrorTrue);
internalOnFail.body.stmts.add(exitIf);
}
return internalOnFail;
}
BLangUnaryExpr createNotBinaryExpression(Location pos, BLangExpression expression) {
List<BType> paramTypes = new ArrayList<>();
paramTypes.add(symTable.booleanType);
BInvokableType type = new BInvokableType(paramTypes, symTable.booleanType,
null);
BOperatorSymbol notOperatorSymbol = new BOperatorSymbol(
names.fromString(OperatorKind.NOT.value()), symTable.rootPkgSymbol.pkgID, type, symTable.rootPkgSymbol,
symTable.builtinPos, VIRTUAL);
return ASTBuilderUtil.createUnaryExpr(pos, expression, symTable.booleanType,
OperatorKind.NOT, notOperatorSymbol);
}
BLangLambdaFunction createLambdaFunction(Location pos, String functionNamePrefix,
List<BLangSimpleVariable> lambdaFunctionVariable,
TypeNode returnType, BLangFunctionBody lambdaBody) {
BLangLambdaFunction lambdaFunction = (BLangLambdaFunction) TreeBuilder.createLambdaFunctionNode();
BLangFunction func =
ASTBuilderUtil.createFunction(pos, functionNamePrefix + UNDERSCORE + lambdaFunctionCount++);
lambdaFunction.function = func;
func.requiredParams.addAll(lambdaFunctionVariable);
func.setReturnTypeNode(returnType);
func.desugaredReturnType = true;
defineFunction(func, env.enclPkg);
lambdaFunctionVariable = func.requiredParams;
func.body = lambdaBody;
func.desugared = false;
lambdaFunction.pos = pos;
List<BType> paramTypes = new ArrayList<>();
lambdaFunctionVariable.forEach(variable -> paramTypes.add(variable.symbol.type));
lambdaFunction.setBType(new BInvokableType(paramTypes, func.symbol.type.getReturnType(),
null));
return lambdaFunction;
}
protected BLangLambdaFunction createLambdaFunction(Location pos, String functionNamePrefix,
List<BLangSimpleVariable> lambdaFunctionVariable,
TypeNode returnType, List<BLangStatement> fnBodyStmts,
SymbolEnv env, Scope bodyScope) {
BLangBlockFunctionBody body = (BLangBlockFunctionBody) TreeBuilder.createBlockFunctionBodyNode();
body.scope = bodyScope;
SymbolEnv bodyEnv = SymbolEnv.createFuncBodyEnv(body, env);
body.stmts = rewriteStmt(fnBodyStmts, bodyEnv);
return createLambdaFunction(pos, functionNamePrefix, lambdaFunctionVariable, returnType, body);
}
private void defineFunction(BLangFunction funcNode, BLangPackage targetPkg) {
final BPackageSymbol packageSymbol = targetPkg.symbol;
final SymbolEnv packageEnv = this.symTable.pkgEnvMap.get(packageSymbol);
symbolEnter.defineNode(funcNode, packageEnv);
packageEnv.enclPkg.functions.add(funcNode);
packageEnv.enclPkg.topLevelNodes.add(funcNode);
}
@Override
public void visit(BLangForkJoin forkJoin) {
result = forkJoin;
}
@Override
public void visit(BLangLiteral literalExpr) {
if (literalExpr.getBType().tag == TypeTags.ARRAY
&& ((BArrayType) literalExpr.getBType()).eType.tag == TypeTags.BYTE) {
result = rewriteBlobLiteral(literalExpr);
return;
}
result = literalExpr;
}
private BLangNode rewriteBlobLiteral(BLangLiteral literalExpr) {
String[] result = getBlobTextValue((String) literalExpr.value);
byte[] values;
if (BASE_64.equals(result[0])) {
values = Base64.getDecoder().decode(result[1].getBytes(StandardCharsets.UTF_8));
} else {
values = hexStringToByteArray(result[1]);
}
BLangArrayLiteral arrayLiteralNode = (BLangArrayLiteral) TreeBuilder.createArrayLiteralExpressionNode();
arrayLiteralNode.setBType(literalExpr.getBType());
arrayLiteralNode.pos = literalExpr.pos;
arrayLiteralNode.exprs = new ArrayList<>();
for (byte b : values) {
arrayLiteralNode.exprs.add(createByteLiteral(literalExpr.pos, b));
}
return arrayLiteralNode;
}
private String[] getBlobTextValue(String blobLiteralNodeText) {
String nodeText = blobLiteralNodeText.replace("\t", "").replace("\n", "").replace("\r", "")
.replace(" ", "");
String[] result = new String[2];
result[0] = nodeText.substring(0, nodeText.indexOf('`'));
result[1] = nodeText.substring(nodeText.indexOf('`') + 1, nodeText.lastIndexOf('`'));
return result;
}
private static byte[] hexStringToByteArray(String str) {
int len = str.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(str.charAt(i), 16) << 4) + Character.digit(str.charAt(i + 1), 16));
}
return data;
}
@Override
public void visit(BLangListConstructorSpreadOpExpr listConstructorSpreadOpExpr) {
listConstructorSpreadOpExpr.expr = rewriteExpr(listConstructorSpreadOpExpr.expr);
result = listConstructorSpreadOpExpr;
}
@Override
public void visit(BLangListConstructorExpr listConstructor) {
listConstructor.exprs = rewriteExprs(listConstructor.exprs);
BLangExpression expr;
BType listConstructorType = Types.getReferredType(listConstructor.getBType());
if (listConstructorType.tag == TypeTags.TUPLE) {
expr = new BLangTupleLiteral(listConstructor.pos, listConstructor.exprs, listConstructor.getBType());
result = rewriteExpr(expr);
} else if (listConstructorType.tag == TypeTags.JSON) {
expr = new BLangJSONArrayLiteral(listConstructor.exprs, new BArrayType(listConstructor.getBType()));
result = rewriteExpr(expr);
} else if (getElementType(listConstructorType).tag == TypeTags.JSON) {
expr = new BLangJSONArrayLiteral(listConstructor.exprs, listConstructor.getBType());
result = rewriteExpr(expr);
} else if (listConstructorType.tag == TypeTags.TYPEDESC) {
final BLangTypedescExpr typedescExpr = new BLangTypedescExpr();
typedescExpr.resolvedType = listConstructor.typedescType;
typedescExpr.setBType(symTable.typeDesc);
result = rewriteExpr(typedescExpr);
} else {
expr = new BLangArrayLiteral(listConstructor.pos, listConstructor.exprs, listConstructor.getBType());
result = rewriteExpr(expr);
}
}
@Override
public void visit(BLangTableConstructorExpr tableConstructorExpr) {
rewriteExprs(tableConstructorExpr.recordLiteralList);
result = tableConstructorExpr;
}
@Override
public void visit(BLangArrayLiteral arrayLiteral) {
arrayLiteral.exprs = rewriteExprs(arrayLiteral.exprs);
BType arrayLiteralType = Types.getReferredType(arrayLiteral.getBType());
if (arrayLiteralType.tag == TypeTags.JSON) {
result = new BLangJSONArrayLiteral(arrayLiteral.exprs, new BArrayType(arrayLiteral.getBType()));
return;
} else if (getElementType(arrayLiteralType).tag == TypeTags.JSON) {
result = new BLangJSONArrayLiteral(arrayLiteral.exprs, arrayLiteral.getBType());
return;
}
result = arrayLiteral;
}
@Override
public void visit(BLangTupleLiteral tupleLiteral) {
if (tupleLiteral.isTypedescExpr) {
final BLangTypedescExpr typedescExpr = new BLangTypedescExpr();
typedescExpr.resolvedType = tupleLiteral.typedescType;
typedescExpr.setBType(symTable.typeDesc);
result = rewriteExpr(typedescExpr);
return;
}
List<BLangExpression> exprs = tupleLiteral.exprs;
BTupleType tupleType = (BTupleType) tupleLiteral.getBType();
List<BType> tupleMemberTypes = tupleType.tupleTypes;
int tupleMemberTypeSize = tupleMemberTypes.size();
int tupleExprSize = exprs.size();
boolean isInRestType = false;
int i = 0;
for (BLangExpression expr: exprs) {
if (expr.getKind() == NodeKind.LIST_CONSTRUCTOR_SPREAD_OP) {
BType spreadOpType = ((BLangListConstructorSpreadOpExpr) expr).expr.getBType();
spreadOpType = Types.getReferredType(spreadOpType);
if (spreadOpType.tag == TypeTags.ARRAY) {
BArrayType spreadOpBArray = (BArrayType) spreadOpType;
if (spreadOpBArray.size >= 0) {
i += spreadOpBArray.size;
continue;
}
} else {
BTupleType spreadOpTuple = (BTupleType) spreadOpType;
if (types.isFixedLengthTuple(spreadOpTuple)) {
i += spreadOpTuple.tupleTypes.size();
continue;
}
}
isInRestType = true;
continue;
}
BType expType = expr.impConversionExpr == null ? expr.getBType() : expr.impConversionExpr.getBType();
BType targetType = tupleType.restType;
if (!isInRestType && i < tupleMemberTypeSize) {
targetType = tupleMemberTypes.get(i);
}
types.setImplicitCastExpr(expr, expType, targetType);
i++;
}
tupleLiteral.exprs = rewriteExprs(tupleLiteral.exprs);
result = tupleLiteral;
}
@Override
public void visit(BLangGroupExpr groupExpr) {
result = rewriteExpr(groupExpr.expression);
}
@Override
public void visit(BLangRecordLiteral recordLiteral) {
List<RecordLiteralNode.RecordField> fields =  recordLiteral.fields;
fields.sort((v1, v2) -> Boolean.compare(isComputedKey(v1), isComputedKey(v2)));
result = rewriteExpr(rewriteMappingConstructor(recordLiteral));
}
@Override
public void visit(BLangSimpleVarRef varRefExpr) {
BLangSimpleVarRef genVarRefExpr = varRefExpr;
if (varRefExpr.pkgSymbol != null && varRefExpr.pkgSymbol.tag == SymTag.XMLNS) {
BLangXMLQName qnameExpr = new BLangXMLQName(varRefExpr.variableName);
qnameExpr.nsSymbol = (BXMLNSSymbol) varRefExpr.pkgSymbol;
qnameExpr.localname = varRefExpr.variableName;
qnameExpr.prefix = varRefExpr.pkgAlias;
qnameExpr.namespaceURI = qnameExpr.nsSymbol.namespaceURI;
qnameExpr.isUsedInXML = false;
qnameExpr.pos = varRefExpr.pos;
qnameExpr.setBType(symTable.stringType);
result = qnameExpr;
return;
}
if (varRefExpr.symbol == null) {
result = varRefExpr;
return;
}
if ((varRefExpr.symbol.tag & SymTag.VARIABLE) == SymTag.VARIABLE) {
BVarSymbol varSymbol = (BVarSymbol) varRefExpr.symbol;
if (varSymbol.originalSymbol != null) {
varRefExpr.symbol = varSymbol.originalSymbol;
}
}
BType type = varRefExpr.getBType();
BSymbol ownerSymbol = varRefExpr.symbol.owner;
if ((varRefExpr.symbol.tag & SymTag.FUNCTION) == SymTag.FUNCTION &&
Types.getReferredType(varRefExpr.symbol.type).tag == TypeTags.INVOKABLE) {
genVarRefExpr = new BLangFunctionVarRef((BVarSymbol) varRefExpr.symbol);
} else if ((varRefExpr.symbol.tag & SymTag.TYPE) == SymTag.TYPE &&
!((varRefExpr.symbol.tag & SymTag.CONSTANT) == SymTag.CONSTANT)) {
genVarRefExpr = new BLangTypeLoad(varRefExpr.symbol);
if (varRefExpr.symbol.tag == SymTag.TYPE_DEF) {
type = ((BTypeDefinitionSymbol) varRefExpr.symbol).referenceType;
}
} else if ((ownerSymbol.tag & SymTag.INVOKABLE) == SymTag.INVOKABLE ||
(ownerSymbol.tag & SymTag.LET) == SymTag.LET) {
genVarRefExpr = new BLangLocalVarRef((BVarSymbol) varRefExpr.symbol);
} else if ((ownerSymbol.tag & SymTag.STRUCT) == SymTag.STRUCT) {
genVarRefExpr = new BLangFieldVarRef((BVarSymbol) varRefExpr.symbol);
} else if ((ownerSymbol.tag & SymTag.PACKAGE) == SymTag.PACKAGE ||
(ownerSymbol.tag & SymTag.SERVICE) == SymTag.SERVICE) {
if ((varRefExpr.symbol.tag & SymTag.CONSTANT) == SymTag.CONSTANT) {
BConstantSymbol constSymbol = (BConstantSymbol) varRefExpr.symbol;
BType referredType = Types.getReferredType(constSymbol.literalType);
if (referredType.tag <= TypeTags.BOOLEAN || referredType.tag == TypeTags.NIL) {
BLangLiteral literal = ASTBuilderUtil.createLiteral(varRefExpr.pos, constSymbol.literalType,
constSymbol.value.value);
result = rewriteExpr(addConversionExprIfRequired(literal, varRefExpr.getBType()));
return;
}
}
genVarRefExpr = new BLangPackageVarRef((BVarSymbol) varRefExpr.symbol);
if (!enclLocks.isEmpty()) {
BVarSymbol symbol = (BVarSymbol) varRefExpr.symbol;
BLangLockStmt lockStmt = enclLocks.peek();
lockStmt.addLockVariable(symbol);
lockStmt.addLockVariable(this.globalVariablesDependsOn.getOrDefault(symbol, new HashSet<>()));
}
}
genVarRefExpr.setBType(type);
genVarRefExpr.pos = varRefExpr.pos;
if ((varRefExpr.isLValue)
|| genVarRefExpr.symbol.name.equals(IGNORE)) {
genVarRefExpr.isLValue = varRefExpr.isLValue;
genVarRefExpr.setBType(varRefExpr.symbol.type);
result = genVarRefExpr;
return;
}
genVarRefExpr.isLValue = varRefExpr.isLValue;
BType targetType = genVarRefExpr.getBType();
genVarRefExpr.setBType(genVarRefExpr.symbol.type);
BLangExpression expression = addConversionExprIfRequired(genVarRefExpr, targetType);
result = expression.impConversionExpr != null ? expression.impConversionExpr : expression;
}
@Override
public void visit(BLangFieldBasedAccess.BLangNSPrefixedFieldBasedAccess nsPrefixedFieldBasedAccess) {
rewriteFieldBasedAccess(nsPrefixedFieldBasedAccess);
}
private void rewriteFieldBasedAccess(BLangFieldBasedAccess fieldAccessExpr) {
if (safeNavigate(fieldAccessExpr)) {
result = rewriteExpr(rewriteSafeNavigationExpr(fieldAccessExpr));
return;
}
BLangAccessExpression targetVarRef = fieldAccessExpr;
BType varRefType = types.getTypeWithEffectiveIntersectionTypes(fieldAccessExpr.expr.getBType());
fieldAccessExpr.expr = rewriteExpr(fieldAccessExpr.expr);
if (!types.isSameType(fieldAccessExpr.expr.getBType(), varRefType)) {
fieldAccessExpr.expr = addConversionExprIfRequired(fieldAccessExpr.expr, varRefType);
}
BLangLiteral stringLit = createStringLiteral(fieldAccessExpr.field.pos,
StringEscapeUtils.unescapeJava(fieldAccessExpr.field.value));
BType refType = Types.getReferredType(varRefType);
int varRefTypeTag = refType.tag;
if (varRefTypeTag == TypeTags.OBJECT ||
(varRefTypeTag == TypeTags.UNION &&
((BUnionType) refType).getMemberTypes().iterator().next().tag == TypeTags.OBJECT)) {
if (fieldAccessExpr.symbol != null && fieldAccessExpr.symbol.type.tag == TypeTags.INVOKABLE &&
((fieldAccessExpr.symbol.flags & Flags.ATTACHED) == Flags.ATTACHED)) {
result = rewriteObjectMemberAccessAsField(fieldAccessExpr);
return;
} else {
boolean isStoreOnCreation = fieldAccessExpr.isStoreOnCreation;
if (!isStoreOnCreation && varRefTypeTag == TypeTags.OBJECT && env.enclInvokable != null) {
BInvokableSymbol originalFuncSymbol = ((BLangFunction) env.enclInvokable).originalFuncSymbol;
BObjectTypeSymbol objectTypeSymbol = (BObjectTypeSymbol) refType.tsymbol;
BAttachedFunction initializerFunc = objectTypeSymbol.initializerFunc;
BAttachedFunction generatedInitializerFunc = objectTypeSymbol.generatedInitializerFunc;
if ((generatedInitializerFunc != null && originalFuncSymbol == generatedInitializerFunc.symbol) ||
(initializerFunc != null && originalFuncSymbol == initializerFunc.symbol)) {
isStoreOnCreation = true;
}
}
targetVarRef = new BLangStructFieldAccessExpr(fieldAccessExpr.pos, fieldAccessExpr.expr, stringLit,
(BVarSymbol) fieldAccessExpr.symbol, false,
isStoreOnCreation);
}
} else if (varRefTypeTag == TypeTags.RECORD ||
(varRefTypeTag == TypeTags.UNION &&
((BUnionType) refType).getMemberTypes().iterator().next().tag == TypeTags.RECORD)) {
if (fieldAccessExpr.symbol != null && fieldAccessExpr.symbol.type.tag == TypeTags.INVOKABLE
&& ((fieldAccessExpr.symbol.flags & Flags.ATTACHED) == Flags.ATTACHED)) {
targetVarRef = new BLangStructFunctionVarRef(fieldAccessExpr.expr, (BVarSymbol) fieldAccessExpr.symbol);
} else {
targetVarRef = new BLangStructFieldAccessExpr(fieldAccessExpr.pos, fieldAccessExpr.expr, stringLit,
(BVarSymbol) fieldAccessExpr.symbol, false, fieldAccessExpr.isStoreOnCreation);
}
} else if (types.isLax(refType)) {
if (!(refType.tag == TypeTags.XML || refType.tag == TypeTags.XML_ELEMENT)) {
if (refType.tag == TypeTags.MAP && TypeTags.isXMLTypeTag(((BMapType) refType).constraint.tag)) {
result = rewriteExpr(rewriteLaxMapAccess(fieldAccessExpr));
return;
}
fieldAccessExpr.expr = addConversionExprIfRequired(fieldAccessExpr.expr, symTable.jsonType);
targetVarRef = new BLangJSONAccessExpr(fieldAccessExpr.pos, fieldAccessExpr.expr, stringLit);
} else {
BLangInvocation xmlAccessInvocation = rewriteXMLAttributeOrElemNameAccess(fieldAccessExpr);
xmlAccessInvocation.setBType(fieldAccessExpr.getBType());
result = xmlAccessInvocation;
return;
}
} else if (varRefTypeTag == TypeTags.MAP) {
targetVarRef = new BLangMapAccessExpr(fieldAccessExpr.pos, fieldAccessExpr.expr, stringLit,
fieldAccessExpr.isStoreOnCreation);
} else if (TypeTags.isXMLTypeTag(varRefTypeTag)) {
targetVarRef = new BLangXMLAccessExpr(fieldAccessExpr.pos, fieldAccessExpr.expr, stringLit,
fieldAccessExpr.fieldKind);
}
targetVarRef.isLValue = fieldAccessExpr.isLValue;
targetVarRef.setBType(fieldAccessExpr.getBType());
targetVarRef.optionalFieldAccess = fieldAccessExpr.optionalFieldAccess;
result = targetVarRef;
}
@Override
public void visit(BLangFieldBasedAccess fieldAccessExpr) {
rewriteFieldBasedAccess(fieldAccessExpr);
}
private BLangNode rewriteObjectMemberAccessAsField(BLangFieldBasedAccess fieldAccessExpr) {
Location pos = fieldAccessExpr.pos;
BInvokableSymbol originalMemberFuncSymbol = (BInvokableSymbol) fieldAccessExpr.symbol;
BLangFunction func = (BLangFunction) TreeBuilder.createFunctionNode();
String funcName = "$anon$method$delegate$" + originalMemberFuncSymbol.name.value + "$" + lambdaFunctionCount++;
BInvokableSymbol funcSymbol = new BInvokableSymbol(SymTag.INVOKABLE, (Flags.ANONYMOUS | Flags.LAMBDA),
Names.fromString(funcName), env.enclPkg.packageID,
originalMemberFuncSymbol.type, env.scope.owner, pos,
VIRTUAL);
funcSymbol.retType = originalMemberFuncSymbol.retType;
funcSymbol.bodyExist = true;
funcSymbol.params = new ArrayList<>();
funcSymbol.scope = new Scope(funcSymbol);
func.pos = pos;
func.name = createIdentifier(pos, funcName);
func.flagSet.add(Flag.LAMBDA);
func.flagSet.add(Flag.ANONYMOUS);
func.body = (BLangBlockFunctionBody) TreeBuilder.createBlockFunctionBodyNode();
func.symbol = funcSymbol;
func.setBType(funcSymbol.type);
func.closureVarSymbols = new LinkedHashSet<>();
BLangExpression receiver = fieldAccessExpr.expr;
BLangSimpleVariableDef intermediateObjDef = null;
if (receiver.getKind() == NodeKind.SIMPLE_VARIABLE_REF) {
BSymbol receiverSymbol = ((BLangVariableReference) receiver).symbol;
receiverSymbol.closure = true;
func.closureVarSymbols.add(new ClosureVarSymbol(receiverSymbol, pos));
} else {
BLangSimpleVariableDef varDef = createVarDef("$$temp$obj$" + annonVarCount++, receiver.getBType(),
receiver, pos);
intermediateObjDef = varDef;
varDef.var.symbol.closure = true;
env.scope.define(varDef.var.symbol.name, varDef.var.symbol);
BLangSimpleVarRef variableRef = createVariableRef(pos, varDef.var.symbol);
func.closureVarSymbols.add(new ClosureVarSymbol(varDef.var.symbol, pos));
receiver = variableRef;
}
ArrayList<BLangExpression> requiredArgs = new ArrayList<>();
for (BVarSymbol param : originalMemberFuncSymbol.params) {
BLangSimpleVariable fParam = (BLangSimpleVariable) TreeBuilder.createSimpleVariableNode();
fParam.symbol = new BVarSymbol(0, param.name, env.enclPkg.packageID, param.type,  funcSymbol, pos,
VIRTUAL);
fParam.pos = pos;
fParam.name = createIdentifier(pos, param.name.value);
fParam.setBType(param.type);
func.requiredParams.add(fParam);
funcSymbol.params.add(fParam.symbol);
funcSymbol.scope.define(fParam.symbol.name, fParam.symbol);
BLangSimpleVarRef paramRef = createVariableRef(pos, fParam.symbol);
requiredArgs.add(paramRef);
}
ArrayList<BLangExpression> restArgs = new ArrayList<>();
if (originalMemberFuncSymbol.restParam != null) {
BLangSimpleVariable restParam = (BLangSimpleVariable) TreeBuilder.createSimpleVariableNode();
func.restParam = restParam;
BVarSymbol restSym = originalMemberFuncSymbol.restParam;
restParam.name = ASTBuilderUtil.createIdentifier(pos, restSym.name.value);
restParam.symbol = new BVarSymbol(0, restSym.name, env.enclPkg.packageID, restSym.type, funcSymbol, pos,
VIRTUAL);
restParam.pos = pos;
restParam.setBType(restSym.type);
funcSymbol.restParam = restParam.symbol;
funcSymbol.scope.define(restParam.symbol.name, restParam.symbol);
BLangSimpleVarRef restArg = createVariableRef(pos, restParam.symbol);
BLangRestArgsExpression restArgExpr = new BLangRestArgsExpression();
restArgExpr.expr = restArg;
restArgExpr.pos = pos;
restArgExpr.setBType(restSym.type);
restArgExpr.expectedType = restArgExpr.getBType();
restArgs.add(restArgExpr);
}
BLangIdentifier field = fieldAccessExpr.field;
BLangReturn retStmt = (BLangReturn) TreeBuilder.createReturnNode();
retStmt.expr = createObjectMethodInvocation(
receiver, field, fieldAccessExpr.symbol, requiredArgs, restArgs);
((BLangBlockFunctionBody) func.body).addStatement(retStmt);
BLangLambdaFunction lambdaFunction = (BLangLambdaFunction) TreeBuilder.createLambdaFunctionNode();
lambdaFunction.function = func;
lambdaFunction.capturedClosureEnv = env.createClone();
env.enclPkg.functions.add(func);
env.enclPkg.topLevelNodes.add(func);
lambdaFunction.parent = env.enclInvokable;
lambdaFunction.setBType(func.getBType());
if (intermediateObjDef == null) {
return rewrite(lambdaFunction, env);
} else {
BLangStatementExpression expr = createStatementExpression(intermediateObjDef, rewrite(lambdaFunction, env));
expr.setBType(lambdaFunction.getBType());
return rewrite(expr, env);
}
}
private BLangInvocation createObjectMethodInvocation(BLangExpression receiver, BLangIdentifier field,
BSymbol invocableSymbol,
List<BLangExpression> requiredArgs,
List<BLangExpression> restArgs) {
BLangInvocation invocationNode = (BLangInvocation) TreeBuilder.createInvocationNode();
invocationNode.name = field;
invocationNode.pkgAlias = (BLangIdentifier) TreeBuilder.createIdentifierNode();
invocationNode.expr = receiver;
invocationNode.symbol = invocableSymbol;
invocationNode.setBType(((BInvokableType) invocableSymbol.type).retType);
invocationNode.requiredArgs = requiredArgs;
invocationNode.restArgs = restArgs;
return invocationNode;
}
private BLangStatementExpression rewriteLaxMapAccess(BLangFieldBasedAccess fieldAccessExpr) {
BLangStatementExpression statementExpression = new BLangStatementExpression();
BLangBlockStmt block = new BLangBlockStmt();
statementExpression.stmt = block;
BUnionType fieldAccessType = BUnionType.create(null, fieldAccessExpr.getBType(), symTable.errorType);
Location pos = fieldAccessExpr.pos;
BLangSimpleVariableDef result = createVarDef("$mapAccessResult$", fieldAccessType, null, pos);
block.addStatement(result);
BLangSimpleVarRef resultRef = ASTBuilderUtil.createVariableRef(pos, result.var.symbol);
resultRef.setBType(fieldAccessType);
statementExpression.setBType(fieldAccessType);
BLangLiteral mapIndex = ASTBuilderUtil.createLiteral(
fieldAccessExpr.field.pos, symTable.stringType, fieldAccessExpr.field.value);
BLangMapAccessExpr mapAccessExpr = new BLangMapAccessExpr(pos, fieldAccessExpr.expr, mapIndex);
BUnionType xmlOrNil = BUnionType.create(null, fieldAccessExpr.getBType(), symTable.nilType);
mapAccessExpr.setBType(xmlOrNil);
BLangSimpleVariableDef mapResult = createVarDef("$mapAccess", xmlOrNil, mapAccessExpr, pos);
BLangSimpleVarRef mapResultRef = ASTBuilderUtil.createVariableRef(pos, mapResult.var.symbol);
block.addStatement(mapResult);
BLangIf ifStmt = ASTBuilderUtil.createIfStmt(pos, block);
BLangIsLikeExpr isLikeNilExpr = createIsLikeExpression(pos, mapResultRef, symTable.nilType);
ifStmt.expr = isLikeNilExpr;
BLangBlockStmt resultNilBody = new BLangBlockStmt();
ifStmt.body = resultNilBody;
BLangBlockStmt resultHasValueBody = new BLangBlockStmt();
ifStmt.elseStmt = resultHasValueBody;
BLangErrorConstructorExpr errorConstructorExpr =
(BLangErrorConstructorExpr) TreeBuilder.createErrorConstructorExpressionNode();
BSymbol symbol = symResolver.lookupMainSpaceSymbolInPackage(errorConstructorExpr.pos, env,
names.fromString(""), names.fromString("error"));
errorConstructorExpr.setBType(symbol.type);
List<BLangExpression> positionalArgs = new ArrayList<>();
List<BLangNamedArgsExpression> namedArgs = new ArrayList<>();
positionalArgs.add(createStringLiteral(pos, "{" + RuntimeConstants.MAP_LANG_LIB + "}InvalidKey"));
BLangNamedArgsExpression message = new BLangNamedArgsExpression();
message.name = ASTBuilderUtil.createIdentifier(pos, "key");
message.expr = createStringLiteral(pos, fieldAccessExpr.field.value);
namedArgs.add(message);
errorConstructorExpr.positionalArgs = positionalArgs;
errorConstructorExpr.namedArgs = namedArgs;
BLangSimpleVariableDef errorDef =
createVarDef("$_invalid_key_error", symTable.errorType, errorConstructorExpr, pos);
resultNilBody.addStatement(errorDef);
BLangSimpleVarRef errorRef = ASTBuilderUtil.createVariableRef(pos, errorDef.var.symbol);
BLangAssignment errorVarAssignment = ASTBuilderUtil.createAssignmentStmt(pos, resultNilBody);
errorVarAssignment.varRef = resultRef;
errorVarAssignment.expr = errorRef;
BLangAssignment mapResultAssignment = ASTBuilderUtil.createAssignmentStmt(
pos, resultHasValueBody);
mapResultAssignment.varRef = resultRef;
mapResultAssignment.expr = mapResultRef;
statementExpression.expr = resultRef;
return statementExpression;
}
private BLangInvocation rewriteXMLAttributeOrElemNameAccess(BLangFieldBasedAccess fieldAccessExpr) {
ArrayList<BLangExpression> args = new ArrayList<>();
String fieldName = fieldAccessExpr.field.value;
if (fieldAccessExpr.fieldKind == FieldKind.WITH_NS) {
BLangFieldBasedAccess.BLangNSPrefixedFieldBasedAccess nsPrefixAccess =
(BLangFieldBasedAccess.BLangNSPrefixedFieldBasedAccess) fieldAccessExpr;
fieldName = createExpandedQName(nsPrefixAccess.nsSymbol.namespaceURI, fieldName);
}
if (fieldName.equals("_")) {
return createLanglibXMLInvocation(fieldAccessExpr.pos, XML_INTERNAL_GET_ELEMENT_NAME_NIL_LIFTING,
fieldAccessExpr.expr, new ArrayList<>(), new ArrayList<>());
}
BLangLiteral attributeNameLiteral = createStringLiteral(fieldAccessExpr.field.pos, fieldName);
args.add(attributeNameLiteral);
args.add(isOptionalAccessToLiteral(fieldAccessExpr));
return createLanglibXMLInvocation(fieldAccessExpr.pos, XML_INTERNAL_GET_ATTRIBUTE, fieldAccessExpr.expr, args,
new ArrayList<>());
}
private BLangExpression isOptionalAccessToLiteral(BLangFieldBasedAccess fieldAccessExpr) {
return rewrite(
createLiteral(fieldAccessExpr.pos, symTable.booleanType, fieldAccessExpr.isOptionalFieldAccess()), env);
}
private String createExpandedQName(String nsURI, String localName) {
return "{" + nsURI + "}" + localName;
}
@Override
public void visit(BLangIndexBasedAccess indexAccessExpr) {
if (safeNavigate(indexAccessExpr)) {
result = rewriteExpr(rewriteSafeNavigationExpr(indexAccessExpr));
return;
}
BLangIndexBasedAccess targetVarRef = indexAccessExpr;
indexAccessExpr.indexExpr = rewriteExpr(indexAccessExpr.indexExpr);
BType effectiveType = types.getTypeWithEffectiveIntersectionTypes(indexAccessExpr.expr.getBType());
BType varRefType = Types.getReferredType(effectiveType);
indexAccessExpr.expr = rewriteExpr(indexAccessExpr.expr);
if (!types.isSameType(indexAccessExpr.expr.getBType(), varRefType)) {
indexAccessExpr.expr = addConversionExprIfRequired(indexAccessExpr.expr, varRefType);
}
if (varRefType.tag == TypeTags.MAP) {
targetVarRef = new BLangMapAccessExpr(indexAccessExpr.pos, indexAccessExpr.expr,
indexAccessExpr.indexExpr, indexAccessExpr.isStoreOnCreation);
} else if (types.isSubTypeOfMapping(types.getSafeType(varRefType, true, false))) {
targetVarRef = new BLangStructFieldAccessExpr(indexAccessExpr.pos, indexAccessExpr.expr,
indexAccessExpr.indexExpr,
(BVarSymbol) indexAccessExpr.symbol, false);
} else if (types.isSubTypeOfList(varRefType)) {
targetVarRef = new BLangArrayAccessExpr(indexAccessExpr.pos, indexAccessExpr.expr,
indexAccessExpr.indexExpr);
} else if (TypeTags.isXMLTypeTag(varRefType.tag)) {
targetVarRef = new BLangXMLAccessExpr(indexAccessExpr.pos, indexAccessExpr.expr,
indexAccessExpr.indexExpr);
} else if (types.isAssignable(varRefType, symTable.stringType)) {
indexAccessExpr.expr = addConversionExprIfRequired(indexAccessExpr.expr, symTable.stringType);
targetVarRef = new BLangStringAccessExpr(indexAccessExpr.pos, indexAccessExpr.expr,
indexAccessExpr.indexExpr);
} else if (varRefType.tag == TypeTags.TABLE) {
targetVarRef = new BLangTableAccessExpr(indexAccessExpr.pos, indexAccessExpr.expr,
indexAccessExpr.indexExpr);
}
targetVarRef.isLValue = indexAccessExpr.isLValue;
targetVarRef.setBType(indexAccessExpr.getBType());
result = targetVarRef;
}
@Override
public void visit(BLangInvocation iExpr) {
rewriteInvocation(iExpr, false);
}
@Override
public void visit(BLangErrorConstructorExpr errorConstructorExpr) {
if (errorConstructorExpr.positionalArgs.size() == 1) {
errorConstructorExpr.positionalArgs.add(createNilLiteral());
}
errorConstructorExpr.positionalArgs.set(1,
addConversionExprIfRequired(errorConstructorExpr.positionalArgs.get(1), symTable.errorType));
rewriteExprs(errorConstructorExpr.positionalArgs);
BLangExpression errorDetail;
BLangRecordLiteral recordLiteral = ASTBuilderUtil.createEmptyRecordLiteral(errorConstructorExpr.pos,
((BErrorType) Types.getReferredType(errorConstructorExpr.getBType())).detailType);
if (errorConstructorExpr.namedArgs.isEmpty()) {
errorDetail = visitCloneReadonly(rewriteExpr(recordLiteral), recordLiteral.getBType());
} else {
for (BLangNamedArgsExpression namedArg : errorConstructorExpr.namedArgs) {
BLangRecordLiteral.BLangRecordKeyValueField member = new BLangRecordLiteral.BLangRecordKeyValueField();
member.key = new BLangRecordLiteral.BLangRecordKey(ASTBuilderUtil.createLiteral(namedArg.name.pos,
symTable.stringType, namedArg.name.value));
if (Types.getReferredType(recordLiteral.getBType()).tag == TypeTags.RECORD) {
member.valueExpr = addConversionExprIfRequired(namedArg.expr, symTable.anyType);
} else {
member.valueExpr = addConversionExprIfRequired(namedArg.expr, namedArg.expr.getBType());
}
recordLiteral.fields.add(member);
}
errorDetail = visitCloneReadonly(rewriteExpr(recordLiteral),
((BErrorType) Types.getReferredType(errorConstructorExpr.getBType())).detailType);
}
errorConstructorExpr.errorDetail = errorDetail;
result = errorConstructorExpr;
}
@Override
public void visit(BLangInvocation.BLangActionInvocation actionInvocation) {
if (!actionInvocation.async && actionInvocation.invokedInsideTransaction) {
transactionDesugar.startTransactionCoordinatorOnce(env, actionInvocation.pos);
}
if (actionInvocation.async && Symbols.isFlagOn(actionInvocation.symbol.type.flags, Flags.ISOLATED)) {
addStrandAnnotationWithThreadAny(actionInvocation);
}
rewriteInvocation(actionInvocation, actionInvocation.async);
}
private void addStrandAnnotationWithThreadAny(BLangInvocation.BLangActionInvocation actionInvocation) {
if (this.strandAnnotAttachement == null) {
BLangPackage pkgNode = env.enclPkg;
List<BLangTypeDefinition> prevTypeDefinitions = new ArrayList<>(pkgNode.typeDefinitions);
this.strandAnnotAttachement =
annotationDesugar.createStrandAnnotationWithThreadAny(actionInvocation.pos, env);
addInitFunctionForRecordTypeNodeInTypeDef(pkgNode, prevTypeDefinitions);
}
actionInvocation.addAnnotationAttachment(this.strandAnnotAttachement);
((BInvokableSymbol) actionInvocation.symbol)
.addAnnotation(this.strandAnnotAttachement.annotationAttachmentSymbol);
}
private void rewriteInvocation(BLangInvocation invocation, boolean async) {
BLangInvocation invRef = invocation;
if (!enclLocks.isEmpty()) {
BLangLockStmt lock = enclLocks.peek();
lock.lockVariables.addAll(((BInvokableSymbol) invocation.symbol).dependentGlobalVars);
}
reorderArguments(invocation);
rewriteExprs(invocation.requiredArgs);
if (invocation.langLibInvocation && !invocation.requiredArgs.isEmpty()) {
invocation.expr = invocation.requiredArgs.get(0);
} else {
invocation.expr = rewriteExpr(invocation.expr);
}
fixStreamTypeCastsInInvocationParams(invocation);
fixNonRestArgTypeCastInTypeParamInvocation(invocation);
rewriteExprs(invocation.restArgs);
annotationDesugar.defineStatementAnnotations(invocation.annAttachments, invocation.pos,
invocation.symbol.pkgID, invocation.symbol.owner, env);
if (invocation.functionPointerInvocation) {
visitFunctionPointerInvocation(invocation);
return;
}
result = invRef;
BInvokableSymbol invSym = (BInvokableSymbol) invocation.symbol;
if (Symbols.isFlagOn(invSym.retType.flags, Flags.PARAMETERIZED)) {
BType retType = unifier.build(invSym.retType);
invocation.setBType(invocation.async ? new BFutureType(TypeTags.FUTURE, retType, null) : retType);
}
if (invocation.expr == null) {
fixTypeCastInTypeParamInvocation(invocation, invRef);
if (invocation.exprSymbol == null) {
return;
}
invocation.expr = ASTBuilderUtil.createVariableRef(invocation.pos, invocation.exprSymbol);
invocation.expr = rewriteExpr(invocation.expr);
}
switch (Types.getReferredType(invocation.expr.getBType()).tag) {
case TypeTags.OBJECT:
case TypeTags.RECORD:
if (!invocation.langLibInvocation) {
List<BLangExpression> argExprs = new ArrayList<>(invocation.requiredArgs);
argExprs.add(0, invocation.expr);
BLangAttachedFunctionInvocation attachedFunctionInvocation =
new BLangAttachedFunctionInvocation(invocation.pos, argExprs, invocation.restArgs,
invocation.symbol, invocation.getBType(),
invocation.expr, async);
attachedFunctionInvocation.name = invocation.name;
attachedFunctionInvocation.annAttachments = invocation.annAttachments;
result = invRef = attachedFunctionInvocation;
}
break;
}
if (invocation.objectInitMethod && Symbols.isFlagOn(invocation.expr.getBType().flags, Flags.OBJECT_CTOR)) {
BObjectType initializingObject = (BObjectType) invocation.expr.getBType();
BLangClassDefinition classDef = initializingObject.classDef;
if (classDef.hasClosureVars) {
OCEDynamicEnvironmentData oceEnvData = initializingObject.classDef.oceEnvData;
if (oceEnvData.attachedFunctionInvocation == null) {
oceEnvData.attachedFunctionInvocation = (BLangAttachedFunctionInvocation) result;
}
}
}
fixTypeCastInTypeParamInvocation(invocation, invRef);
}
private void fixNonRestArgTypeCastInTypeParamInvocation(BLangInvocation iExpr) {
if (!iExpr.langLibInvocation) {
return;
}
List<BLangExpression> requiredArgs = iExpr.requiredArgs;
List<BVarSymbol> params = ((BInvokableSymbol) iExpr.symbol).params;
for (int i = 0; i < requiredArgs.size(); i++) {
requiredArgs.set(i, addConversionExprIfRequired(requiredArgs.get(i), params.get(i).type));
}
}
/* This function is a workaround and need improvement
*  Notes for improvement :
*    1. Both arguments are same.
*    2. Due to current type param logic we put type param flag on the original type.
*    3. Error type having Cloneable type with type param flag, change expression type by this code.
*    4. using error type is a problem as Cloneable type is an typeparm eg: ExprBodiedFunctionTest
*       added never to CloneableType type param
*       @typeParam type
*       CloneableType Cloneable|never;
*
*/
private void fixTypeCastInTypeParamInvocation(BLangInvocation iExpr, BLangInvocation genIExpr) {
var returnTypeOfInvokable = ((BInvokableSymbol) iExpr.symbol).retType;
if (!iExpr.langLibInvocation && !TypeParamAnalyzer.containsTypeParam(returnTypeOfInvokable)) {
return;
}
BType originalInvType = genIExpr.getBType();
if (!genIExpr.async) {
genIExpr.setBType(returnTypeOfInvokable);
}
this.result = addConversionExprIfRequired(genIExpr, originalInvType);
}
private void fixStreamTypeCastsInInvocationParams(BLangInvocation iExpr) {
List<BLangExpression> requiredArgs = iExpr.requiredArgs;
List<BVarSymbol> params = ((BInvokableSymbol) iExpr.symbol).params;
if (!params.isEmpty()) {
for (int i = 0; i < requiredArgs.size(); i++) {
BVarSymbol param = params.get(i);
if (Types.getReferredType(param.type).tag == TypeTags.STREAM) {
requiredArgs.set(i, addConversionExprIfRequired(requiredArgs.get(i), param.type));
}
}
}
}
private BLangLiteral createNilLiteral() {
BLangLiteral literal = (BLangLiteral) TreeBuilder.createLiteralExpression();
literal.value = null;
literal.setBType(symTable.nilType);
return literal;
}
public void visit(BLangTypeInit typeInitExpr) {
if (Types.getReferredType(typeInitExpr.getBType()).tag == TypeTags.STREAM) {
result = rewriteExpr(desugarStreamTypeInit(typeInitExpr));
} else {
result = rewrite(desugarObjectTypeInit(typeInitExpr), env);
}
}
private BLangStatementExpression desugarObjectTypeInit(BLangTypeInit typeInitExpr) {
typeInitExpr.desugared = true;
BLangBlockStmt blockStmt = ASTBuilderUtil.createBlockStmt(typeInitExpr.pos);
BType objType = getObjectType(typeInitExpr.getBType());
BLangSimpleVariableDef objVarDef = createVarDef("$obj$", objType, typeInitExpr, typeInitExpr.pos);
objVarDef.var.name.pos = symTable.builtinPos;
BLangSimpleVarRef objVarRef = ASTBuilderUtil.createVariableRef(typeInitExpr.pos, objVarDef.var.symbol);
blockStmt.addStatement(objVarDef);
BLangInvocation typeInitInvocation = typeInitExpr.initInvocation;
typeInitInvocation.exprSymbol = objVarDef.var.symbol;
typeInitInvocation.symbol = ((BObjectTypeSymbol) objType.tsymbol).generatedInitializerFunc.symbol;
typeInitInvocation.objectInitMethod = true;
if (Types.getReferredType(typeInitInvocation.getBType()).tag == TypeTags.NIL) {
BLangExpressionStmt initInvExpr = ASTBuilderUtil.createExpressionStmt(typeInitExpr.pos, blockStmt);
initInvExpr.expr = typeInitInvocation;
typeInitInvocation.name.value = GENERATED_INIT_SUFFIX.value;
BLangStatementExpression stmtExpr = createStatementExpression(blockStmt, objVarRef);
stmtExpr.setBType(objVarRef.symbol.type);
return stmtExpr;
}
BLangSimpleVariableDef initInvRetValVarDef = createVarDef("$temp$", typeInitInvocation.getBType(),
typeInitInvocation, typeInitExpr.pos);
blockStmt.addStatement(initInvRetValVarDef);
BLangSimpleVariableDef resultVarDef = createVarDef("$result$", typeInitExpr.getBType(), null, typeInitExpr.pos);
blockStmt.addStatement(resultVarDef);
BLangSimpleVarRef initRetValVarRefInCondition =
ASTBuilderUtil.createVariableRef(symTable.builtinPos, initInvRetValVarDef.var.symbol);
BLangBlockStmt thenStmt = ASTBuilderUtil.createBlockStmt(symTable.builtinPos);
BLangTypeTestExpr isErrorTest =
ASTBuilderUtil.createTypeTestExpr(symTable.builtinPos, initRetValVarRefInCondition, getErrorTypeNode());
isErrorTest.setBType(symTable.booleanType);
BLangSimpleVarRef thenInitRetValVarRef =
ASTBuilderUtil.createVariableRef(symTable.builtinPos, initInvRetValVarDef.var.symbol);
BLangSimpleVarRef thenResultVarRef =
ASTBuilderUtil.createVariableRef(symTable.builtinPos, resultVarDef.var.symbol);
BLangAssignment errAssignment =
ASTBuilderUtil.createAssignmentStmt(symTable.builtinPos, thenResultVarRef, thenInitRetValVarRef);
thenStmt.addStatement(errAssignment);
BLangSimpleVarRef elseResultVarRef =
ASTBuilderUtil.createVariableRef(symTable.builtinPos, resultVarDef.var.symbol);
BLangAssignment objAssignment =
ASTBuilderUtil.createAssignmentStmt(symTable.builtinPos, elseResultVarRef, objVarRef);
BLangBlockStmt elseStmt = ASTBuilderUtil.createBlockStmt(symTable.builtinPos);
elseStmt.addStatement(objAssignment);
BLangIf ifelse = ASTBuilderUtil.createIfElseStmt(symTable.builtinPos, isErrorTest, thenStmt, elseStmt);
blockStmt.addStatement(ifelse);
BLangSimpleVarRef resultVarRef =
ASTBuilderUtil.createVariableRef(symTable.builtinPos, resultVarDef.var.symbol);
BLangStatementExpression stmtExpr = createStatementExpression(blockStmt, resultVarRef);
stmtExpr.setBType(resultVarRef.symbol.type);
return stmtExpr;
}
private BLangInvocation desugarStreamTypeInit(BLangTypeInit typeInitExpr) {
BInvokableSymbol symbol = (BInvokableSymbol) symTable.langInternalModuleSymbol.scope
.lookup(Names.CONSTRUCT_STREAM).symbol;
BType constraintType = ((BStreamType) typeInitExpr.getBType()).constraint;
BType constraintTdType = new BTypedescType(constraintType, symTable.typeDesc.tsymbol);
BLangTypedescExpr constraintTdExpr = new BLangTypedescExpr();
constraintTdExpr.resolvedType = constraintType;
constraintTdExpr.setBType(constraintTdType);
BType completionType = ((BStreamType) typeInitExpr.getBType()).completionType;
BType completionTdType = new BTypedescType(completionType, symTable.typeDesc.tsymbol);
BLangTypedescExpr completionTdExpr = new BLangTypedescExpr();
completionTdExpr.resolvedType = completionType;
completionTdExpr.setBType(completionTdType);
List<BLangExpression> args = new ArrayList<>(Lists.of(constraintTdExpr, completionTdExpr));
if (!typeInitExpr.argsExpr.isEmpty()) {
args.add(typeInitExpr.argsExpr.get(0));
}
BLangInvocation streamConstructInvocation = ASTBuilderUtil.createInvocationExprForMethod(
typeInitExpr.pos, symbol, args, symResolver);
streamConstructInvocation.setBType(new BStreamType(TypeTags.STREAM, constraintType, completionType, null));
return streamConstructInvocation;
}
private BLangSimpleVariableDef createVarDef(String name, BType type, BLangExpression expr,
Location location) {
BSymbol objSym = symResolver.lookupSymbolInMainSpace(env, names.fromString(name));
if (objSym == null || objSym == symTable.notFoundSymbol) {
objSym = new BVarSymbol(0, names.fromString(name), this.env.scope.owner.pkgID, type,
this.env.scope.owner, location, VIRTUAL);
}
BLangSimpleVariable objVar = ASTBuilderUtil.createVariable(location, name, type, expr, (BVarSymbol) objSym);
BLangSimpleVariableDef objVarDef = ASTBuilderUtil.createVariableDef(location);
objVarDef.var = objVar;
objVarDef.setBType(objVar.getBType());
return objVarDef;
}
private BType getObjectType(BType bType) {
BType type = Types.getReferredType(bType);
if (type.tag == TypeTags.OBJECT) {
return type;
} else if (type.tag == TypeTags.UNION) {
return ((BUnionType) type).getMemberTypes().stream()
.filter(t -> t.tag == TypeTags.OBJECT)
.findFirst()
.orElse(symTable.noType);
}
throw new IllegalStateException("None object type '" + type.toString() + "' found in object init context");
}
BLangErrorType getErrorTypeNode() {
BLangErrorType errorTypeNode = (BLangErrorType) TreeBuilder.createErrorTypeNode();
errorTypeNode.setBType(symTable.errorType);
errorTypeNode.pos = symTable.builtinPos;
return errorTypeNode;
}
BLangErrorType getErrorOrNillTypeNode() {
BLangErrorType errorTypeNode = (BLangErrorType) TreeBuilder.createErrorTypeNode();
errorTypeNode.setBType(symTable.errorOrNilType);
return errorTypeNode;
}
@Override
public void visit(BLangTernaryExpr ternaryExpr) {
/*
* First desugar to if-else:
*
* T $result$;
* if () {
*    $result$ = thenExpr;
* } else {
*    $result$ = elseExpr;
* }
*
*/
BLangSimpleVariableDef resultVarDef =
createVarDef("$ternary_result$", ternaryExpr.getBType(), null, ternaryExpr.pos);
BLangBlockStmt thenBody = ASTBuilderUtil.createBlockStmt(ternaryExpr.pos);
BLangBlockStmt elseBody = ASTBuilderUtil.createBlockStmt(ternaryExpr.pos);
BLangSimpleVarRef thenResultVarRef = ASTBuilderUtil.createVariableRef(ternaryExpr.pos, resultVarDef.var.symbol);
BLangAssignment thenAssignment =
ASTBuilderUtil.createAssignmentStmt(ternaryExpr.pos, thenResultVarRef, ternaryExpr.thenExpr);
thenBody.addStatement(thenAssignment);
BLangSimpleVarRef elseResultVarRef = ASTBuilderUtil.createVariableRef(ternaryExpr.pos, resultVarDef.var.symbol);
BLangAssignment elseAssignment =
ASTBuilderUtil.createAssignmentStmt(ternaryExpr.pos, elseResultVarRef, ternaryExpr.elseExpr);
elseBody.addStatement(elseAssignment);
BLangSimpleVarRef resultVarRef = ASTBuilderUtil.createVariableRef(ternaryExpr.pos, resultVarDef.var.symbol);
BLangIf ifElse = ASTBuilderUtil.createIfElseStmt(ternaryExpr.pos, ternaryExpr.expr, thenBody, elseBody);
BLangBlockStmt blockStmt = ASTBuilderUtil.createBlockStmt(ternaryExpr.pos, Lists.of(resultVarDef, ifElse));
BLangStatementExpression stmtExpr = createStatementExpression(blockStmt, resultVarRef);
stmtExpr.setBType(ternaryExpr.getBType());
result = rewriteExpr(stmtExpr);
}
@Override
public void visit(BLangWaitExpr waitExpr) {
if (waitExpr.getExpression().getKind() == NodeKind.BINARY_EXPR) {
waitExpr.exprList = collectAllBinaryExprs((BLangBinaryExpr) waitExpr.getExpression(), new ArrayList<>());
} else {
waitExpr.exprList = Collections.singletonList(rewriteExpr(waitExpr.getExpression()));
}
result = waitExpr;
}
private List<BLangExpression> collectAllBinaryExprs(BLangBinaryExpr binaryExpr, List<BLangExpression> exprs) {
visitBinaryExprOfWait(binaryExpr.lhsExpr, exprs);
visitBinaryExprOfWait(binaryExpr.rhsExpr, exprs);
return exprs;
}
private void visitBinaryExprOfWait(BLangExpression expr, List<BLangExpression> exprs) {
if (expr.getKind() == NodeKind.BINARY_EXPR) {
collectAllBinaryExprs((BLangBinaryExpr) expr, exprs);
} else {
expr = rewriteExpr(expr);
exprs.add(expr);
}
}
@Override
public void visit(BLangWaitForAllExpr waitExpr) {
waitExpr.keyValuePairs.forEach(keyValue -> {
if (keyValue.valueExpr != null) {
keyValue.valueExpr = rewriteExpr(keyValue.valueExpr);
} else {
keyValue.keyExpr = rewriteExpr(keyValue.keyExpr);
}
});
BLangExpression expr = new BLangWaitForAllExpr.BLangWaitLiteral(waitExpr.keyValuePairs, waitExpr.getBType());
expr.pos = waitExpr.pos;
result = rewriteExpr(expr);
}
@Override
public void visit(BLangTrapExpr trapExpr) {
trapExpr.expr = rewriteExpr(trapExpr.expr);
if (Types.getReferredType(trapExpr.expr.getBType()).tag != TypeTags.NIL) {
trapExpr.expr = addConversionExprIfRequired(trapExpr.expr, trapExpr.getBType());
}
result = trapExpr;
}
@Override
public void visit(BLangBinaryExpr binaryExpr) {
if (isNullableBinaryExpr(binaryExpr)) {
BLangStatementExpression stmtExpr = createStmtExprForNullableBinaryExpr(binaryExpr);
result = rewrite(stmtExpr, env);
return;
}
if (binaryExpr.opKind == OperatorKind.HALF_OPEN_RANGE || binaryExpr.opKind == OperatorKind.CLOSED_RANGE) {
BLangExpression lhsExpr = binaryExpr.lhsExpr;
BLangExpression rhsExpr = binaryExpr.rhsExpr;
lhsExpr = createTypeCastExpr(lhsExpr, symTable.intType);
rhsExpr = createTypeCastExpr(rhsExpr, symTable.intType);
if (binaryExpr.opKind == OperatorKind.HALF_OPEN_RANGE) {
rhsExpr = getModifiedIntRangeEndExpr(rhsExpr);
}
result = rewriteExpr(replaceWithIntRange(binaryExpr.pos, lhsExpr, rhsExpr));
return;
}
if (binaryExpr.opKind == OperatorKind.AND || binaryExpr.opKind == OperatorKind.OR) {
visitBinaryLogicalExpr(binaryExpr);
return;
}
OperatorKind binaryOpKind = binaryExpr.opKind;
if (binaryOpKind == OperatorKind.ADD || binaryOpKind == OperatorKind.SUB ||
binaryOpKind == OperatorKind.MUL || binaryOpKind == OperatorKind.DIV ||
binaryOpKind == OperatorKind.MOD || binaryOpKind == OperatorKind.BITWISE_AND ||
binaryOpKind == OperatorKind.BITWISE_OR || binaryOpKind == OperatorKind.BITWISE_XOR) {
checkByteTypeIncompatibleOperations(binaryExpr);
}
binaryExpr.lhsExpr = rewriteExpr(binaryExpr.lhsExpr);
binaryExpr.rhsExpr = rewriteExpr(binaryExpr.rhsExpr);
result = binaryExpr;
int rhsExprTypeTag = Types.getReferredType(binaryExpr.rhsExpr.getBType()).tag;
int lhsExprTypeTag = Types.getReferredType(binaryExpr.lhsExpr.getBType()).tag;
if (rhsExprTypeTag != lhsExprTypeTag && (binaryExpr.opKind == OperatorKind.EQUAL ||
binaryExpr.opKind == OperatorKind.NOT_EQUAL ||
binaryExpr.opKind == OperatorKind.REF_EQUAL ||
binaryExpr.opKind == OperatorKind.REF_NOT_EQUAL)) {
if (TypeTags.isIntegerTypeTag(lhsExprTypeTag) && rhsExprTypeTag == TypeTags.BYTE) {
binaryExpr.rhsExpr = createTypeCastExpr(binaryExpr.rhsExpr, symTable.intType);
return;
}
if (lhsExprTypeTag == TypeTags.BYTE && TypeTags.isIntegerTypeTag(rhsExprTypeTag)) {
binaryExpr.lhsExpr = createTypeCastExpr(binaryExpr.lhsExpr, symTable.intType);
return;
}
}
boolean isBinaryShiftOperator = symResolver.isBinaryShiftOperator(binaryOpKind);
boolean isArithmeticOperator = symResolver.isArithmeticOperator(binaryOpKind);
if (lhsExprTypeTag == rhsExprTypeTag) {
if (!isBinaryShiftOperator && !isArithmeticOperator) {
return;
}
if (types.isValueType(binaryExpr.lhsExpr.getBType())) {
return;
}
}
if (binaryExpr.opKind == OperatorKind.ADD && TypeTags.isStringTypeTag(lhsExprTypeTag) &&
(rhsExprTypeTag == TypeTags.XML || rhsExprTypeTag == TypeTags.XML_TEXT)) {
binaryExpr.lhsExpr = ASTBuilderUtil.createXMLTextLiteralNode(binaryExpr, binaryExpr.lhsExpr,
binaryExpr.lhsExpr.pos, symTable.xmlType);
return;
}
if (binaryExpr.opKind == OperatorKind.ADD && TypeTags.isStringTypeTag(rhsExprTypeTag) &&
(lhsExprTypeTag == TypeTags.XML || lhsExprTypeTag == TypeTags.XML_TEXT)) {
binaryExpr.rhsExpr = ASTBuilderUtil.createXMLTextLiteralNode(binaryExpr, binaryExpr.rhsExpr,
binaryExpr.rhsExpr.pos, symTable.xmlType);
return;
}
if (lhsExprTypeTag == TypeTags.DECIMAL) {
binaryExpr.rhsExpr = createTypeCastExpr(binaryExpr.rhsExpr, binaryExpr.lhsExpr.getBType());
return;
}
if (rhsExprTypeTag == TypeTags.DECIMAL) {
binaryExpr.lhsExpr = createTypeCastExpr(binaryExpr.lhsExpr, binaryExpr.rhsExpr.getBType());
return;
}
if (lhsExprTypeTag == TypeTags.FLOAT) {
binaryExpr.rhsExpr = createTypeCastExpr(binaryExpr.rhsExpr, binaryExpr.lhsExpr.getBType());
return;
}
if (rhsExprTypeTag == TypeTags.FLOAT) {
binaryExpr.lhsExpr = createTypeCastExpr(binaryExpr.lhsExpr, binaryExpr.rhsExpr.getBType());
return;
}
if (isArithmeticOperator) {
createTypeCastExprForArithmeticExpr(binaryExpr, lhsExprTypeTag, rhsExprTypeTag);
return;
}
if (isBinaryShiftOperator) {
createTypeCastExprForBinaryShiftExpr(binaryExpr, lhsExprTypeTag, rhsExprTypeTag);
return;
}
if (symResolver.isBinaryComparisonOperator(binaryOpKind)) {
createTypeCastExprForRelationalExpr(binaryExpr, lhsExprTypeTag, rhsExprTypeTag);
}
}
private BLangStatementExpression createStmtExprForNullableBinaryExpr(BLangBinaryExpr binaryExpr) {
/*
* int? x = 3;
* int? y = 5;
* int? z = x + y;
* Above is desugared to
* int? $result$;
*
* int? $lhsExprVar$ = x;
* int? $rhsExprVar$ = y;
* if (lhsVar is () or rhsVar is ()) {
*    $result$ = ();
* } else {
*    $result$ = $lhsExprVar$ + $rhsExprVar$;
* }
* int z = $result$;
*/
BLangBlockStmt blockStmt = ASTBuilderUtil.createBlockStmt(binaryExpr.pos);
BUnionType exprBType = (BUnionType) binaryExpr.getBType();
BType nonNilType = exprBType.getMemberTypes().iterator().next();
boolean isArithmeticOperator = symResolver.isArithmeticOperator(binaryExpr.opKind);
boolean isShiftOperator = symResolver.isBinaryShiftOperator(binaryExpr.opKind);
boolean isBitWiseOperator = !isArithmeticOperator && !isShiftOperator;
BType rhsType = nonNilType;
if (isBitWiseOperator) {
if (binaryExpr.rhsExpr.getBType().isNullable()) {
rhsType = types.getSafeType(binaryExpr.rhsExpr.getBType(), true, false);
} else {
rhsType = binaryExpr.rhsExpr.getBType();
}
}
BType lhsType = nonNilType;
if (isBitWiseOperator) {
if (binaryExpr.lhsExpr.getBType().isNullable()) {
lhsType = types.getSafeType(binaryExpr.lhsExpr.getBType(), true, false);
} else {
lhsType = binaryExpr.lhsExpr.getBType();
}
}
if (binaryExpr.lhsExpr.getBType().isNullable()) {
binaryExpr.lhsExpr = rewriteExpr(binaryExpr.lhsExpr);
}
BLangSimpleVariableDef tempVarDef = createVarDef("result",
binaryExpr.getBType(), null, binaryExpr.pos);
BLangSimpleVarRef tempVarRef = ASTBuilderUtil.createVariableRef(binaryExpr.pos, tempVarDef.var.symbol);
blockStmt.addStatement(tempVarDef);
BLangSimpleVariableDef lhsVarDef = createVarDef("$lhsExprVar$", binaryExpr.lhsExpr.getBType(),
binaryExpr.lhsExpr, binaryExpr.pos);
BLangSimpleVarRef lhsVarRef = ASTBuilderUtil.createVariableRef(binaryExpr.pos, lhsVarDef.var.symbol);
blockStmt.addStatement(lhsVarDef);
BLangSimpleVariableDef rhsVarDef = createVarDef("$rhsExprVar$", binaryExpr.rhsExpr.getBType(),
binaryExpr.rhsExpr, binaryExpr.pos);
BLangSimpleVarRef rhsVarRef = ASTBuilderUtil.createVariableRef(binaryExpr.pos, rhsVarDef.var.symbol);
blockStmt.addStatement(rhsVarDef);
BLangTypeTestExpr typeTestExprOne = createTypeCheckExpr(binaryExpr.pos, lhsVarRef, getNillTypeNode());
typeTestExprOne.setBType(symTable.booleanType);
BLangTypeTestExpr typeTestExprTwo = createTypeCheckExpr(binaryExpr.pos, rhsVarRef, getNillTypeNode());
typeTestExprTwo.setBType(symTable.booleanType);
BLangBinaryExpr ifBlockCondition = ASTBuilderUtil.createBinaryExpr(binaryExpr.pos, typeTestExprOne,
typeTestExprTwo, symTable.booleanType, OperatorKind.OR, binaryExpr.opSymbol);
BLangBlockStmt ifBody = ASTBuilderUtil.createBlockStmt(binaryExpr.pos);
BLangAssignment bLangAssignmentIf = ASTBuilderUtil.createAssignmentStmt(binaryExpr.pos, ifBody);
bLangAssignmentIf.varRef = tempVarRef;
bLangAssignmentIf.expr = createNilLiteral();
BLangBlockStmt elseBody = ASTBuilderUtil.createBlockStmt(binaryExpr.pos);
BLangAssignment bLangAssignmentElse = ASTBuilderUtil.createAssignmentStmt(binaryExpr.pos, elseBody);
bLangAssignmentElse.varRef = tempVarRef;
BLangBinaryExpr newBinaryExpr = ASTBuilderUtil.createBinaryExpr(binaryExpr.pos, lhsVarRef, rhsVarRef,
nonNilType, binaryExpr.opKind, binaryExpr.opSymbol);
newBinaryExpr.lhsExpr = createTypeCastExpr(lhsVarRef, lhsType);
newBinaryExpr.rhsExpr = createTypeCastExpr(rhsVarRef, rhsType);
bLangAssignmentElse.expr = newBinaryExpr;
BLangIf ifStatement = ASTBuilderUtil.createIfStmt(binaryExpr.pos, blockStmt);
ifStatement.expr = ifBlockCondition;
ifStatement.body = ifBody;
ifStatement.elseStmt = elseBody;
BLangStatementExpression stmtExpr = ASTBuilderUtil.createStatementExpression(blockStmt, tempVarRef);
stmtExpr.setBType(binaryExpr.getBType());
return stmtExpr;
}
private boolean isNullableBinaryExpr(BLangBinaryExpr binaryExpr) {
if ((binaryExpr.lhsExpr.getBType() != null && binaryExpr.rhsExpr.getBType() != null) &&
(binaryExpr.rhsExpr.getBType().isNullable() ||
binaryExpr.lhsExpr.getBType().isNullable())) {
switch (binaryExpr.getOperatorKind()) {
case ADD:
case SUB:
case MUL:
case DIV:
case MOD:
case BITWISE_LEFT_SHIFT:
case BITWISE_RIGHT_SHIFT:
case BITWISE_UNSIGNED_RIGHT_SHIFT:
case BITWISE_AND:
case BITWISE_OR:
case BITWISE_XOR:
return true;
}
}
return false;
}
private void createTypeCastExprForArithmeticExpr(BLangBinaryExpr binaryExpr, int lhsExprTypeTag,
int rhsExprTypeTag) {
if ((TypeTags.isIntegerTypeTag(lhsExprTypeTag) && TypeTags.isIntegerTypeTag(rhsExprTypeTag)) ||
(TypeTags.isStringTypeTag(lhsExprTypeTag) && TypeTags.isStringTypeTag(rhsExprTypeTag)) ||
(TypeTags.isXMLTypeTag(lhsExprTypeTag) && TypeTags.isXMLTypeTag(rhsExprTypeTag))) {
return;
}
if (TypeTags.isXMLTypeTag(lhsExprTypeTag) && !TypeTags.isXMLTypeTag(rhsExprTypeTag)) {
if (types.checkTypeContainString(binaryExpr.rhsExpr.getBType())) {
binaryExpr.rhsExpr = ASTBuilderUtil.createXMLTextLiteralNode(binaryExpr, binaryExpr.rhsExpr,
binaryExpr.rhsExpr.pos, symTable.xmlType);
return;
}
binaryExpr.rhsExpr = createTypeCastExpr(binaryExpr.rhsExpr, symTable.xmlType);
return;
}
if (TypeTags.isXMLTypeTag(rhsExprTypeTag) && !TypeTags.isXMLTypeTag(lhsExprTypeTag)) {
if (types.checkTypeContainString(binaryExpr.lhsExpr.getBType())) {
binaryExpr.lhsExpr = ASTBuilderUtil.createXMLTextLiteralNode(binaryExpr, binaryExpr.lhsExpr,
binaryExpr.rhsExpr.pos, symTable.xmlType);
return;
}
binaryExpr.lhsExpr = createTypeCastExpr(binaryExpr.lhsExpr, symTable.xmlType);
return;
}
binaryExpr.lhsExpr = createTypeCastExpr(binaryExpr.lhsExpr, binaryExpr.getBType());
binaryExpr.rhsExpr = createTypeCastExpr(binaryExpr.rhsExpr, binaryExpr.getBType());
}
private void createTypeCastExprForBinaryShiftExpr(BLangBinaryExpr binaryExpr, int lhsExprTypeTag,
int rhsExprTypeTag) {
boolean isLhsIntegerType = TypeTags.isIntegerTypeTag(lhsExprTypeTag);
boolean isRhsIntegerType = TypeTags.isIntegerTypeTag(rhsExprTypeTag);
if (isLhsIntegerType || lhsExprTypeTag == TypeTags.BYTE) {
if (isRhsIntegerType || rhsExprTypeTag == TypeTags.BYTE) {
return;
}
binaryExpr.rhsExpr = createTypeCastExpr(binaryExpr.rhsExpr, symTable.intType);
return;
}
if (isRhsIntegerType || rhsExprTypeTag == TypeTags.BYTE) {
binaryExpr.lhsExpr = createTypeCastExpr(binaryExpr.lhsExpr, symTable.intType);
return;
}
binaryExpr.lhsExpr = createTypeCastExpr(binaryExpr.lhsExpr, symTable.intType);
binaryExpr.rhsExpr = createTypeCastExpr(binaryExpr.rhsExpr, symTable.intType);
}
private void createTypeCastExprForRelationalExpr(BLangBinaryExpr binaryExpr, int lhsExprTypeTag,
int rhsExprTypeTag) {
boolean isLhsIntegerType = TypeTags.isIntegerTypeTag(lhsExprTypeTag);
boolean isRhsIntegerType = TypeTags.isIntegerTypeTag(rhsExprTypeTag);
if ((isLhsIntegerType && isRhsIntegerType) || (lhsExprTypeTag == TypeTags.BYTE &&
rhsExprTypeTag == TypeTags.BYTE)) {
return;
}
if (isLhsIntegerType && !isRhsIntegerType) {
binaryExpr.rhsExpr = createTypeCastExpr(binaryExpr.rhsExpr, symTable.intType);
return;
}
if (!isLhsIntegerType && isRhsIntegerType) {
binaryExpr.lhsExpr = createTypeCastExpr(binaryExpr.lhsExpr, symTable.intType);
return;
}
if (lhsExprTypeTag == TypeTags.BYTE || rhsExprTypeTag == TypeTags.BYTE) {
binaryExpr.rhsExpr = createTypeCastExpr(binaryExpr.rhsExpr, symTable.intType);
binaryExpr.lhsExpr = createTypeCastExpr(binaryExpr.lhsExpr, symTable.intType);
return;
}
boolean isLhsStringType = TypeTags.isStringTypeTag(lhsExprTypeTag);
boolean isRhsStringType = TypeTags.isStringTypeTag(rhsExprTypeTag);
if (isLhsStringType && isRhsStringType) {
return;
}
if (isLhsStringType && !isRhsStringType) {
binaryExpr.rhsExpr = createTypeCastExpr(binaryExpr.rhsExpr, symTable.stringType);
return;
}
if (!isLhsStringType && isRhsStringType) {
binaryExpr.lhsExpr = createTypeCastExpr(binaryExpr.lhsExpr, symTable.stringType);
}
}
private BLangInvocation replaceWithIntRange(Location location, BLangExpression lhsExpr,
BLangExpression rhsExpr) {
BInvokableSymbol symbol = (BInvokableSymbol) symTable.langInternalModuleSymbol.scope
.lookup(Names.CREATE_INT_RANGE).symbol;
BLangInvocation createIntRangeInvocation = ASTBuilderUtil.createInvocationExprForMethod(location, symbol,
new ArrayList<>(Lists.of(lhsExpr, rhsExpr)), symResolver);
createIntRangeInvocation.setBType(symTable.intRangeType);
return createIntRangeInvocation;
}
private void checkByteTypeIncompatibleOperations(BLangBinaryExpr binaryExpr) {
if (binaryExpr.expectedType == null) {
return;
}
int rhsExprTypeTag = Types.getReferredType(binaryExpr.rhsExpr.getBType()).tag;
int lhsExprTypeTag = Types.getReferredType(binaryExpr.lhsExpr.getBType()).tag;
if (rhsExprTypeTag != TypeTags.BYTE && lhsExprTypeTag != TypeTags.BYTE) {
return;
}
int resultTypeTag = binaryExpr.expectedType.tag;
if (resultTypeTag == TypeTags.INT) {
if (rhsExprTypeTag == TypeTags.BYTE) {
binaryExpr.rhsExpr = addConversionExprIfRequired(binaryExpr.rhsExpr, symTable.intType);
}
if (lhsExprTypeTag == TypeTags.BYTE) {
binaryExpr.lhsExpr = addConversionExprIfRequired(binaryExpr.lhsExpr, symTable.intType);
}
}
}
/**
* This method checks whether given binary expression is related to shift operation.
* If its true, then both lhs and rhs of the binary expression will be converted to 'int' type.
* <p>
* byte a = 12;
* byte b = 34;
* int i = 234;
* int j = -4;
* <p>
* true: where binary expression's expected type is 'int'
* int i1 = a >> b;
* int i2 = a << b;
* int i3 = a >> i;
* int i4 = a << i;
* int i5 = i >> j;
* int i6 = i << j;
*/
private boolean isBitwiseShiftOperation(BLangBinaryExpr binaryExpr) {
return binaryExpr.opKind == OperatorKind.BITWISE_LEFT_SHIFT ||
binaryExpr.opKind == OperatorKind.BITWISE_RIGHT_SHIFT ||
binaryExpr.opKind == OperatorKind.BITWISE_UNSIGNED_RIGHT_SHIFT;
}
public void visit(BLangElvisExpr elvisExpr) {
Location pos = elvisExpr.pos;
String resultVarName = "_$result$_";
BType resultType = elvisExpr.getBType();
BLangSimpleVariable resultVar =
ASTBuilderUtil.createVariable(pos, resultVarName, resultType, null,
new BVarSymbol(0, names.fromString(resultVarName),
this.env.scope.owner.pkgID, resultType,
this.env.scope.owner, pos, VIRTUAL));
BLangSimpleVariableDef resultVarDef = ASTBuilderUtil.createVariableDef(pos, resultVar);
resultVarDef.desugared = true;
BLangSimpleVarRef resultVarRef = ASTBuilderUtil.createVariableRef(pos, resultVar.symbol);
String lhsResultVarName = GEN_VAR_PREFIX.value;
BLangSimpleVariable lhsResultVar =
ASTBuilderUtil.createVariable(pos, lhsResultVarName, elvisExpr.lhsExpr.getBType(), elvisExpr.lhsExpr,
new BVarSymbol(0, names.fromString(lhsResultVarName),
this.env.scope.owner.pkgID, elvisExpr.lhsExpr.getBType(),
this.env.scope.owner, elvisExpr.pos, VIRTUAL));
BLangSimpleVariableDef lhsResultVarDef = ASTBuilderUtil.createVariableDef(pos, lhsResultVar);
BLangSimpleVarRef lhsResultVarRef = ASTBuilderUtil.createVariableRef(pos, lhsResultVar.symbol);
BLangAssignment nilAssignment = ASTBuilderUtil.createAssignmentStmt(pos, resultVarRef, elvisExpr.rhsExpr);
BLangBlockStmt ifBody = ASTBuilderUtil.createBlockStmt(pos);
ifBody.addStatement(nilAssignment);
BLangAssignment notNilAssignment = ASTBuilderUtil.createAssignmentStmt(pos, resultVarRef,
createTypeCastExpr(lhsResultVarRef, resultType));
BLangBlockStmt elseBody = ASTBuilderUtil.createBlockStmt(pos);
elseBody.addStatement(notNilAssignment);
BLangIf ifStmt = ASTBuilderUtil.createIfElseStmt(pos,
createTypeCheckExpr(pos, lhsResultVarRef, getNillTypeNode()), ifBody, elseBody);
BLangBlockStmt blockStmt = ASTBuilderUtil.createBlockStmt(pos, new ArrayList<>() {{
add(resultVarDef);
add(lhsResultVarDef);
add(ifStmt);
}});
BLangStatementExpression stmtExpr = ASTBuilderUtil.createStatementExpression(blockStmt, resultVarRef);
stmtExpr.setBType(resultType);
result = rewriteExpr(stmtExpr);
}
@Override
public void visit(BLangUnaryExpr unaryExpr) {
if (isNullableUnaryExpr(unaryExpr)) {
BLangStatementExpression statementExpression = createStmtExprForNilableUnaryExpr(unaryExpr);
result = rewrite(statementExpression, env);
return;
}
if (OperatorKind.BITWISE_COMPLEMENT == unaryExpr.operator) {
rewriteBitwiseComplementOperator(unaryExpr);
return;
}
OperatorKind opKind = unaryExpr.operator;
if (opKind == OperatorKind.ADD || opKind == OperatorKind.SUB) {
createTypeCastExprForUnaryPlusAndMinus(unaryExpr);
}
unaryExpr.expr = rewriteExpr(unaryExpr.expr);
result = unaryExpr;
}
private void createTypeCastExprForUnaryPlusAndMinus(BLangUnaryExpr unaryExpr) {
BLangExpression expr = unaryExpr.expr;
if (TypeTags.isIntegerTypeTag(expr.getBType().tag)) {
return;
}
unaryExpr.expr = createTypeCastExpr(expr, unaryExpr.getBType());
}
/**
* This method desugar a bitwise complement (~) unary expressions into a bitwise xor binary expression as below.
* Example : ~a  -> a ^ -1;
* ~ 11110011 -> 00001100
* 11110011 ^ 11111111 -> 00001100
*
* @param unaryExpr the bitwise complement expression
*/
private void rewriteBitwiseComplementOperator(BLangUnaryExpr unaryExpr) {
final Location pos = unaryExpr.pos;
final BLangBinaryExpr binaryExpr = (BLangBinaryExpr) TreeBuilder.createBinaryExpressionNode();
binaryExpr.pos = pos;
binaryExpr.opKind = OperatorKind.BITWISE_XOR;
binaryExpr.lhsExpr = unaryExpr.expr;
if (TypeTags.BYTE == Types.getReferredType(unaryExpr.getBType()).tag) {
binaryExpr.setBType(symTable.byteType);
binaryExpr.rhsExpr = ASTBuilderUtil.createLiteral(pos, symTable.byteType, 0xffL);
binaryExpr.opSymbol = (BOperatorSymbol) symResolver.resolveBinaryOperator(OperatorKind.BITWISE_XOR,
symTable.byteType, symTable.byteType);
} else {
binaryExpr.setBType(symTable.intType);
binaryExpr.rhsExpr = ASTBuilderUtil.createLiteral(pos, symTable.intType, -1L);
binaryExpr.opSymbol = (BOperatorSymbol) symResolver.resolveBinaryOperator(OperatorKind.BITWISE_XOR,
symTable.intType, symTable.intType);
}
result = rewriteExpr(binaryExpr);
}
private BLangStatementExpression createStmtExprForNilableUnaryExpr(BLangUnaryExpr unaryExpr) {
/*
* int? x = 3;
* int? y = +x;
*
*
* Above is desugared to
* int? $result$;
* if (x is ()) {
*    $result$ = ();
* } else {
*    $result$ = +x;
* }
* int y = $result$
*/
BLangBlockStmt blockStmt = ASTBuilderUtil.createBlockStmt(unaryExpr.pos);
BUnionType exprBType = (BUnionType) unaryExpr.getBType();
BType nilLiftType = exprBType.getMemberTypes().iterator().next();
unaryExpr.expr = rewriteExpr(unaryExpr.expr);
BLangSimpleVariableDef tempVarDef = createVarDef("$result",
unaryExpr.getBType(), createNilLiteral(), unaryExpr.pos);
BLangSimpleVarRef tempVarRef = ASTBuilderUtil.createVariableRef(unaryExpr.pos, tempVarDef.var.symbol);
blockStmt.addStatement(tempVarDef);
BLangTypeTestExpr typeTestExpr = createTypeCheckExpr(unaryExpr.pos, unaryExpr.expr,
getNillTypeNode());
typeTestExpr.setBType(symTable.booleanType);
BLangBlockStmt ifBody = ASTBuilderUtil.createBlockStmt(unaryExpr.pos);
BLangAssignment bLangAssignmentIf = ASTBuilderUtil.createAssignmentStmt(unaryExpr.pos, ifBody);
bLangAssignmentIf.varRef = tempVarRef;
bLangAssignmentIf.expr = createNilLiteral();
BLangBlockStmt elseBody = ASTBuilderUtil.createBlockStmt(unaryExpr.pos);
BLangAssignment bLangAssignmentElse = ASTBuilderUtil.createAssignmentStmt(unaryExpr.pos, elseBody);
bLangAssignmentElse.varRef = tempVarRef;
BLangExpression expr = createTypeCastExpr(unaryExpr.expr, nilLiftType);
bLangAssignmentElse.expr = ASTBuilderUtil.createUnaryExpr(unaryExpr.pos, expr,
nilLiftType, unaryExpr.operator, unaryExpr.opSymbol);
BLangIf ifStatement = ASTBuilderUtil.createIfStmt(unaryExpr.pos, blockStmt);
ifStatement.expr = typeTestExpr;
ifStatement.body = ifBody;
ifStatement.elseStmt = elseBody;
BLangStatementExpression stmtExpr = ASTBuilderUtil.createStatementExpression(blockStmt, tempVarRef);
stmtExpr.setBType(unaryExpr.getBType());
return stmtExpr;
}
private boolean isNullableUnaryExpr(BLangUnaryExpr unaryExpr) {
if (unaryExpr.getBType() != null && unaryExpr.getBType().isNullable()) {
switch (unaryExpr.operator) {
case ADD:
case SUB:
case BITWISE_COMPLEMENT:
return true;
}
}
return false;
}
@Override
public void visit(BLangTypeConversionExpr conversionExpr) {
if (conversionExpr.typeNode == null && !conversionExpr.annAttachments.isEmpty()) {
result = rewriteExpr(conversionExpr.expr);
return;
}
BType targetType = conversionExpr.targetType;
conversionExpr.typeNode = rewrite(conversionExpr.typeNode, env);
conversionExpr.expr = rewriteExpr(conversionExpr.expr);
result = conversionExpr;
}
@Override
public void visit(BLangLambdaFunction bLangLambdaFunction) {
if (!env.enclPkg.lambdaFunctions.contains(bLangLambdaFunction)) {
env.enclPkg.lambdaFunctions.add(bLangLambdaFunction);
}
result = bLangLambdaFunction;
}
@Override
public void visit(BLangArrowFunction bLangArrowFunction) {
BLangFunction bLangFunction = (BLangFunction) TreeBuilder.createFunctionNode();
bLangFunction.setName(bLangArrowFunction.functionName);
BLangLambdaFunction lambdaFunction = (BLangLambdaFunction) TreeBuilder.createLambdaFunctionNode();
lambdaFunction.pos = bLangArrowFunction.pos;
bLangFunction.addFlag(Flag.LAMBDA);
lambdaFunction.function = bLangFunction;
BLangValueType returnType = (BLangValueType) TreeBuilder.createValueTypeNode();
returnType.setBType(bLangArrowFunction.body.expr.getBType());
bLangFunction.setReturnTypeNode(returnType);
bLangFunction.setBody(populateArrowExprBodyBlock(bLangArrowFunction));
bLangArrowFunction.params.forEach(bLangFunction::addParameter);
lambdaFunction.parent = bLangArrowFunction.parent;
lambdaFunction.setBType(bLangArrowFunction.funcType);
BLangFunction funcNode = lambdaFunction.function;
BInvokableSymbol funcSymbol = Symbols.createFunctionSymbol(Flags.asMask(funcNode.flagSet),
new Name(funcNode.name.value),
new Name(funcNode.name.originalValue),
env.enclPkg.symbol.pkgID,
bLangArrowFunction.funcType,
env.enclEnv.enclVarSym, true,
bLangArrowFunction.pos, VIRTUAL);
funcSymbol.originalName = new Name(funcNode.name.originalValue);
SymbolEnv invokableEnv = SymbolEnv.createFunctionEnv(funcNode, funcSymbol.scope, env);
defineInvokableSymbol(funcNode, funcSymbol, invokableEnv);
List<BVarSymbol> paramSymbols = funcNode.requiredParams.stream().peek(varNode -> {
Scope enclScope = invokableEnv.scope;
varNode.symbol.kind = SymbolKind.FUNCTION;
varNode.symbol.owner = invokableEnv.scope.owner;
enclScope.define(varNode.symbol.name, varNode.symbol);
}).map(varNode -> varNode.symbol).collect(Collectors.toList());
funcSymbol.params = paramSymbols;
funcSymbol.restParam = getRestSymbol(funcNode);
funcSymbol.retType = funcNode.returnTypeNode.getBType();
List<BType> paramTypes = paramSymbols.stream().map(paramSym -> paramSym.type).collect(Collectors.toList());
funcNode.setBType(
new BInvokableType(paramTypes, getRestType(funcSymbol), funcNode.returnTypeNode.getBType(), null));
lambdaFunction.function.pos = bLangArrowFunction.pos;
lambdaFunction.function.body.pos = bLangArrowFunction.pos;
lambdaFunction.capturedClosureEnv = env;
rewrite(lambdaFunction.function, env);
env.enclPkg.addFunction(lambdaFunction.function);
result = rewriteExpr(lambdaFunction);
}
private void defineInvokableSymbol(BLangInvokableNode invokableNode, BInvokableSymbol funcSymbol,
SymbolEnv invokableEnv) {
invokableNode.symbol = funcSymbol;
funcSymbol.scope = new Scope(funcSymbol);
invokableEnv.scope = funcSymbol.scope;
}
@Override
public void visit(BLangXMLQName xmlQName) {
result = xmlQName;
}
@Override
public void visit(BLangXMLAttribute xmlAttribute) {
xmlAttribute.name = rewriteExpr(xmlAttribute.name);
xmlAttribute.value = rewriteExpr(xmlAttribute.value);
result = xmlAttribute;
}
@Override
public void visit(BLangXMLElementLiteral xmlElementLiteral) {
xmlElementLiteral.attributes = rewriteExprs(xmlElementLiteral.attributes);
Iterator<BLangXMLAttribute> attributesItr = xmlElementLiteral.attributes.iterator();
while (attributesItr.hasNext()) {
BLangXMLAttribute attribute = attributesItr.next();
if (!attribute.isNamespaceDeclr) {
continue;
}
BLangXMLNS xmlns;
if ((xmlElementLiteral.scope.owner.tag & SymTag.PACKAGE) == SymTag.PACKAGE) {
xmlns = new BLangPackageXMLNS();
} else {
xmlns = new BLangLocalXMLNS();
}
xmlns.namespaceURI = attribute.value.concatExpr;
xmlns.prefix = ((BLangXMLQName) attribute.name).localname;
xmlns.symbol = attribute.symbol;
xmlElementLiteral.inlineNamespaces.add(xmlns);
}
List<BLangXMLNS> prevInlineNamespaces = this.inlineXMLNamespaces;
if (isVisitingQuery && this.inlineXMLNamespaces != null) {
xmlElementLiteral.inlineNamespaces.addAll(this.inlineXMLNamespaces);
}
this.inlineXMLNamespaces = xmlElementLiteral.inlineNamespaces;
xmlElementLiteral.startTagName = rewriteExpr(xmlElementLiteral.startTagName);
xmlElementLiteral.endTagName = rewriteExpr(xmlElementLiteral.endTagName);
xmlElementLiteral.modifiedChildren = rewriteExprs(xmlElementLiteral.modifiedChildren);
this.inlineXMLNamespaces = prevInlineNamespaces;
result = xmlElementLiteral;
}
@Override
public void visit(BLangXMLSequenceLiteral xmlSequenceLiteral) {
for (BLangExpression xmlItem : xmlSequenceLiteral.xmlItems) {
rewriteExpr(xmlItem);
}
result = xmlSequenceLiteral;
}
@Override
public void visit(BLangXMLTextLiteral xmlTextLiteral) {
xmlTextLiteral.concatExpr = rewriteExpr(constructStringTemplateConcatExpression(xmlTextLiteral.textFragments));
result = xmlTextLiteral;
}
@Override
public void visit(BLangXMLCommentLiteral xmlCommentLiteral) {
xmlCommentLiteral.concatExpr = rewriteExpr(
constructStringTemplateConcatExpression(xmlCommentLiteral.textFragments));
result = xmlCommentLiteral;
}
@Override
public void visit(BLangXMLProcInsLiteral xmlProcInsLiteral) {
xmlProcInsLiteral.target = rewriteExpr(xmlProcInsLiteral.target);
xmlProcInsLiteral.dataConcatExpr =
rewriteExpr(constructStringTemplateConcatExpression(xmlProcInsLiteral.dataFragments));
result = xmlProcInsLiteral;
}
@Override
public void visit(BLangXMLQuotedString xmlQuotedString) {
xmlQuotedString.concatExpr = rewriteExpr(
constructStringTemplateConcatExpression(xmlQuotedString.textFragments));
result = xmlQuotedString;
}
@Override
public void visit(BLangStringTemplateLiteral stringTemplateLiteral) {
result = rewriteExpr(constructStringTemplateConcatExpression(stringTemplateLiteral.exprs));
}
/**
* The raw template literal gets desugared to a type init expression. For each literal, a new object class type
* def is generated from the object type. The type init expression creates an instance of this generated object
* type. For example, consider the following statements:
*      string name = "Pubudu";
*      'object:RawTemplate rt = `Hello ${name}!`;
*
* The raw template literal above is desugared to:
*      type RawTemplate$Impl$0 object {
*          public string[] strings = ["Hello ", "!"];
*          public (any|error)[] insertions;
*
*          function init((any|error)[] insertions) {
*              self.insertions = insertions;
*          }
*      };
*
*
*      'object:RawTemplate rt = new RawTemplate$Impl$0([name]);
*
* @param rawTemplateLiteral The raw template literal to be desugared.
*/
@Override
public void visit(BLangRawTemplateLiteral rawTemplateLiteral) {
Location pos = rawTemplateLiteral.pos;
BObjectType objType = (BObjectType) Types.getReferredType(rawTemplateLiteral.getBType());
BLangClassDefinition objClassDef =
desugarTemplateLiteralObjectTypedef(rawTemplateLiteral.strings, objType, pos);
BObjectType classObjType = (BObjectType) objClassDef.getBType();
BVarSymbol insertionsSym = classObjType.fields.get("insertions").symbol;
BLangListConstructorExpr insertionsList = ASTBuilderUtil.createListConstructorExpr(pos, insertionsSym.type);
insertionsList.exprs.addAll(rawTemplateLiteral.insertions);
insertionsList.expectedType = insertionsSym.type;
BLangTypeInit typeNewExpr = ASTBuilderUtil.createEmptyTypeInit(pos, classObjType);
typeNewExpr.argsExpr.add(insertionsList);
typeNewExpr.initInvocation.argExprs.add(insertionsList);
typeNewExpr.initInvocation.requiredArgs.add(insertionsList);
result = rewriteExpr(typeNewExpr);
}
/**
* This method desugars a raw template literal object class for the provided raw template object type as follows.
* A literal defined as 'object:RawTemplate rt = `Hello ${name}!`;
* is desugared to,
*      type $anonType$0 object {
*          public string[] strings = ["Hello ", "!"];
*          public (any|error)[] insertions;
*
*          function init((any|error)[] insertions) {
*              self.insertions = insertions;
*          }
*      };
* @param strings    The string portions of the literal
* @param objectType The abstract object type for which an object class needs to be generated
* @param pos        The diagnostic position info for the type node
* @return Returns the generated concrete object class def
*/
private BLangClassDefinition desugarTemplateLiteralObjectTypedef(List<BLangLiteral> strings, BObjectType objectType,
Location pos) {
BObjectTypeSymbol tSymbol = (BObjectTypeSymbol) objectType.tsymbol;
Name objectClassName = names.fromString(
anonModelHelper.getNextRawTemplateTypeKey(env.enclPkg.packageID, tSymbol.name));
BObjectTypeSymbol classTSymbol = Symbols.createClassSymbol(tSymbol.flags, objectClassName,
env.enclPkg.packageID, null, env.enclPkg.symbol,
pos, VIRTUAL, false);
classTSymbol.flags |= Flags.CLASS;
BObjectType objectClassType = new BObjectType(classTSymbol, classTSymbol.flags);
objectClassType.fields = objectType.fields;
classTSymbol.type = objectClassType;
objectClassType.typeIdSet.add(objectType.typeIdSet);
BLangClassDefinition classDef = TypeDefBuilderHelper.createClassDef(pos, classTSymbol, env);
classDef.name = ASTBuilderUtil.createIdentifier(pos, objectClassType.tsymbol.name.value);
BType stringsType = objectClassType.fields.get("strings").symbol.type;
BLangListConstructorExpr stringsList = ASTBuilderUtil.createListConstructorExpr(pos, stringsType);
stringsList.exprs.addAll(strings);
stringsList.expectedType = stringsType;
classDef.fields.get(0).expr = stringsList;
BLangFunction userDefinedInitFunction = createUserDefinedObjectInitFn(classDef, env);
classDef.initFunction = userDefinedInitFunction;
env.enclPkg.functions.add(userDefinedInitFunction);
env.enclPkg.topLevelNodes.add(userDefinedInitFunction);
BLangFunction tempGeneratedInitFunction = createGeneratedInitializerFunction(classDef, env);
tempGeneratedInitFunction.clonedEnv = SymbolEnv.createFunctionEnv(tempGeneratedInitFunction,
tempGeneratedInitFunction.symbol.scope, env);
SemanticAnalyzer.AnalyzerData data = new SemanticAnalyzer.AnalyzerData(env);
this.semanticAnalyzer.analyzeNode(tempGeneratedInitFunction, data);
classDef.generatedInitFunction = tempGeneratedInitFunction;
env.enclPkg.functions.add(classDef.generatedInitFunction);
env.enclPkg.topLevelNodes.add(classDef.generatedInitFunction);
return rewrite(classDef, env);
}
/**
* Creates a user-defined init() method for the provided object type node. If there are fields without default
* values specified in the type node, this will add parameters for those fields in the init() method and assign the
* param values to the respective fields in the method body.
*
* @param classDefn The object type node for which the init() method is generated
* @param env            The symbol env for the object type node
* @return The generated init() method
*/
private BLangFunction createUserDefinedObjectInitFn(BLangClassDefinition classDefn, SymbolEnv env) {
BLangFunction initFunction =
TypeDefBuilderHelper.createInitFunctionForStructureType(classDefn.pos, classDefn.symbol, env,
names, Names.USER_DEFINED_INIT_SUFFIX,
symTable, classDefn.getBType());
BObjectTypeSymbol typeSymbol = ((BObjectTypeSymbol) classDefn.getBType().tsymbol);
typeSymbol.initializerFunc = new BAttachedFunction(Names.USER_DEFINED_INIT_SUFFIX, initFunction.symbol,
(BInvokableType) initFunction.getBType(), classDefn.pos);
classDefn.initFunction = initFunction;
initFunction.returnTypeNode.setBType(symTable.nilType);
BLangBlockFunctionBody initFuncBody = (BLangBlockFunctionBody) initFunction.body;
BInvokableType initFnType = (BInvokableType) initFunction.getBType();
for (BLangSimpleVariable field : classDefn.fields) {
if (field.expr != null) {
continue;
}
BVarSymbol fieldSym = field.symbol;
BVarSymbol paramSym = new BVarSymbol(Flags.FINAL, fieldSym.name, this.env.scope.owner.pkgID, fieldSym.type,
initFunction.symbol, classDefn.pos, VIRTUAL);
BLangSimpleVariable param = ASTBuilderUtil.createVariable(classDefn.pos, fieldSym.name.value,
fieldSym.type, null, paramSym);
param.flagSet.add(Flag.FINAL);
initFunction.symbol.scope.define(paramSym.name, paramSym);
initFunction.symbol.params.add(paramSym);
initFnType.paramTypes.add(param.getBType());
initFunction.requiredParams.add(param);
BLangSimpleVarRef paramRef = ASTBuilderUtil.createVariableRef(initFunction.pos, paramSym);
BLangAssignment fieldInit = createStructFieldUpdate(initFunction, paramRef, fieldSym, field.getBType(),
initFunction.receiver.symbol, field.name);
initFuncBody.addStatement(fieldInit);
}
return initFunction;
}
@Override
public void visit(BLangWorkerSend workerSendNode) {
workerSendNode.expr = visitCloneInvocation(rewriteExpr(workerSendNode.expr), workerSendNode.expr.getBType());
result = workerSendNode;
}
@Override
public void visit(BLangWorkerSyncSendExpr syncSendExpr) {
syncSendExpr.expr = visitCloneInvocation(rewriteExpr(syncSendExpr.expr), syncSendExpr.expr.getBType());
result = syncSendExpr;
}
@Override
public void visit(BLangWorkerReceive workerReceiveNode) {
result = workerReceiveNode;
}
@Override
public void visit(BLangWorkerFlushExpr workerFlushExpr) {
workerFlushExpr.workerIdentifierList = workerFlushExpr.cachedWorkerSendStmts
.stream().map(send -> send.workerIdentifier).distinct().collect(Collectors.toList());
result = workerFlushExpr;
}
@Override
public void visit(BLangTransactionalExpr transactionalExpr) {
BInvokableSymbol isTransactionalSymbol =
(BInvokableSymbol) transactionDesugar.getInternalTransactionModuleInvokableSymbol(IS_TRANSACTIONAL);
result = ASTBuilderUtil
.createInvocationExprMethod(transactionalExpr.pos, isTransactionalSymbol, Collections.emptyList(),
Collections.emptyList(), symResolver);
}
@Override
public void visit(BLangCommitExpr commitExpr) {
BLangStatementExpression stmtExpr = transactionDesugar.desugar(commitExpr, env);
result = rewriteExpr(stmtExpr);
}
@Override
public void visit(BLangFail failNode) {
if (this.onFailClause != null && !this.isVisitingQuery) {
if (this.onFailClause.bodyContainsFail) {
result = rewriteNestedOnFail(this.onFailClause, failNode);
} else {
result = createOnFailInvocation(onFailClause, failNode);
}
} else {
BLangReturn stmt = ASTBuilderUtil.createReturnStmt(failNode.pos, rewrite(failNode.expr, env));
stmt.desugared = true;
result = stmt;
}
}
@Override
public void visit(BLangLocalVarRef localVarRef) {
result = localVarRef;
}
@Override
public void visit(BLangFieldVarRef fieldVarRef) {
result = fieldVarRef;
}
@Override
public void visit(BLangPackageVarRef packageVarRef) {
result = packageVarRef;
}
@Override
public void visit(BLangFunctionVarRef functionVarRef) {
result = functionVarRef;
}
@Override
public void visit(BLangStructFieldAccessExpr fieldAccessExpr) {
result = fieldAccessExpr;
}
@Override
public void visit(BLangStructFunctionVarRef functionVarRef) {
result = functionVarRef;
}
@Override
public void visit(BLangMapAccessExpr mapKeyAccessExpr) {
result = mapKeyAccessExpr;
}
@Override
public void visit(BLangArrayAccessExpr arrayIndexAccessExpr) {
result = arrayIndexAccessExpr;
}
@Override
public void visit(BLangTupleAccessExpr arrayIndexAccessExpr) {
result = arrayIndexAccessExpr;
}
@Override
public void visit(BLangTableAccessExpr tableKeyAccessExpr) {
result = tableKeyAccessExpr;
}
@Override
public void visit(BLangMapLiteral mapLiteral) {
result = mapLiteral;
}
@Override
public void visit(BLangStructLiteral structLiteral) {
result = structLiteral;
}
@Override
public void visit(BLangWaitForAllExpr.BLangWaitLiteral waitLiteral) {
result = waitLiteral;
}
@Override
public void visit(BLangXMLElementAccess xmlElementAccess) {
xmlElementAccess.expr = rewriteExpr(xmlElementAccess.expr);
ArrayList<BLangExpression> filters = expandFilters(xmlElementAccess.filters);
BLangInvocation invocationNode = createLanglibXMLInvocation(xmlElementAccess.pos, XML_INTERNAL_GET_ELEMENTS,
xmlElementAccess.expr, new ArrayList<>(), filters);
result = rewriteExpr(invocationNode);
}
private ArrayList<BLangExpression> expandFilters(List<BLangXMLElementFilter> filters) {
Map<Name, BXMLNSSymbol> nameBXMLNSSymbolMap = symResolver.resolveAllNamespaces(env);
BXMLNSSymbol defaultNSSymbol = nameBXMLNSSymbolMap.get(names.fromString(XMLConstants.DEFAULT_NS_PREFIX));
String defaultNS = defaultNSSymbol != null ? defaultNSSymbol.namespaceURI : null;
ArrayList<BLangExpression> args = new ArrayList<>();
for (BLangXMLElementFilter filter : filters) {
BSymbol nsSymbol = symResolver.lookupSymbolInPrefixSpace(env, names.fromString(filter.namespace));
if (nsSymbol == symTable.notFoundSymbol) {
if (defaultNS != null && !filter.name.equals("*")) {
String expandedName = createExpandedQName(defaultNS, filter.name);
args.add(createStringLiteral(filter.elemNamePos, expandedName));
} else {
args.add(createStringLiteral(filter.elemNamePos, filter.name));
}
} else {
BXMLNSSymbol bxmlnsSymbol = (BXMLNSSymbol) nsSymbol;
String expandedName = createExpandedQName(bxmlnsSymbol.namespaceURI, filter.name);
BLangLiteral stringLiteral = createStringLiteral(filter.elemNamePos, expandedName);
args.add(stringLiteral);
}
}
return args;
}
private BLangInvocation createLanglibXMLInvocation(Location pos, String functionName,
BLangExpression invokeOnExpr,
ArrayList<BLangExpression> args,
ArrayList<BLangExpression> restArgs) {
invokeOnExpr = rewriteExpr(invokeOnExpr);
BLangInvocation invocationNode = (BLangInvocation) TreeBuilder.createInvocationNode();
invocationNode.pos = pos;
BLangIdentifier name = (BLangIdentifier) TreeBuilder.createIdentifierNode();
name.setLiteral(false);
name.setValue(functionName);
name.pos = pos;
invocationNode.name = name;
invocationNode.pkgAlias = (BLangIdentifier) TreeBuilder.createIdentifierNode();
invocationNode.expr = invokeOnExpr;
invocationNode.symbol = symResolver.lookupLangLibMethod(symTable.xmlType, names.fromString(functionName), env);
ArrayList<BLangExpression> requiredArgs = new ArrayList<>();
requiredArgs.add(invokeOnExpr);
requiredArgs.addAll(args);
invocationNode.requiredArgs = requiredArgs;
invocationNode.restArgs = rewriteExprs(restArgs);
invocationNode.setBType(((BInvokableType) invocationNode.symbol.type).getReturnType());
invocationNode.langLibInvocation = true;
return invocationNode;
}
@Override
public void visit(BLangXMLNavigationAccess xmlNavigation) {
xmlNavigation.expr = rewriteExpr(xmlNavigation.expr);
xmlNavigation.childIndex = rewriteExpr(xmlNavigation.childIndex);
ArrayList<BLangExpression> filters = expandFilters(xmlNavigation.filters);
if (xmlNavigation.navAccessType == XMLNavigationAccess.NavAccessType.DESCENDANTS) {
BLangInvocation invocationNode = createLanglibXMLInvocation(xmlNavigation.pos,
XML_INTERNAL_SELECT_DESCENDANTS, xmlNavigation.expr, new ArrayList<>(), filters);
result = rewriteExpr(invocationNode);
} else if (xmlNavigation.navAccessType == XMLNavigationAccess.NavAccessType.CHILDREN) {
BLangInvocation invocationNode = createLanglibXMLInvocation(xmlNavigation.pos, XML_INTERNAL_CHILDREN,
xmlNavigation.expr, new ArrayList<>(), new ArrayList<>());
result = rewriteExpr(invocationNode);
} else {
BLangExpression childIndexExpr;
if (xmlNavigation.childIndex == null) {
childIndexExpr = new BLangLiteral(Long.valueOf(-1), symTable.intType);
} else {
childIndexExpr = xmlNavigation.childIndex;
}
ArrayList<BLangExpression> args = new ArrayList<>();
args.add(rewriteExpr(childIndexExpr));
BLangInvocation invocationNode = createLanglibXMLInvocation(xmlNavigation.pos,
XML_INTERNAL_GET_FILTERED_CHILDREN_FLAT, xmlNavigation.expr, args, filters);
result = rewriteExpr(invocationNode);
}
}
@Override
public void visit(BLangIsAssignableExpr assignableExpr) {
assignableExpr.lhsExpr = rewriteExpr(assignableExpr.lhsExpr);
result = assignableExpr;
}
@Override
public void visit(BFunctionPointerInvocation fpInvocation) {
result = fpInvocation;
}
@Override
public void visit(BLangTypedescExpr typedescExpr) {
typedescExpr.typeNode = rewrite(typedescExpr.typeNode, env);
result = typedescExpr;
}
@Override
public void visit(BLangRestArgsExpression bLangVarArgsExpression) {
result = rewriteExpr(bLangVarArgsExpression.expr);
}
@Override
public void visit(BLangNamedArgsExpression bLangNamedArgsExpression) {
bLangNamedArgsExpression.expr = rewriteExpr(bLangNamedArgsExpression.expr);
result = bLangNamedArgsExpression.expr;
}
@Override
public void visit(BLangCheckedExpr checkedExpr) {
visitCheckAndCheckPanicExpr(checkedExpr, false);
}
@Override
public void visit(BLangCheckPanickedExpr checkedExpr) {
visitCheckAndCheckPanicExpr(checkedExpr, true);
}
private void visitCheckAndCheckPanicExpr(BLangCheckedExpr checkedExpr, boolean isCheckPanic) {
if (checkedExpr.isRedundantChecking) {
result = rewriteExpr(checkedExpr.expr);
return;
}
Location pos = checkedExpr.pos;
String resultVarName = "_$result$_";
BType resultType = checkedExpr.getBType();
BLangSimpleVariable resultVar =
ASTBuilderUtil.createVariable(pos, resultVarName, resultType, null,
new BVarSymbol(0, names.fromString(resultVarName),
this.env.scope.owner.pkgID, resultType,
this.env.scope.owner, pos, VIRTUAL));
BLangSimpleVariableDef resultVarDef = ASTBuilderUtil.createVariableDef(pos, resultVar);
resultVarDef.desugared = true;
BLangSimpleVarRef resultVarRef = ASTBuilderUtil.createVariableRef(pos, resultVar.symbol);
String checkedExprVarName = GEN_VAR_PREFIX.value;
BType checkedExprType = checkedExpr.expr.getBType();
BLangSimpleVariable checkedExprVar =
ASTBuilderUtil.createVariable(pos, checkedExprVarName, checkedExprType,
checkedExpr.expr, new BVarSymbol(0, names.fromString(checkedExprVarName),
this.env.scope.owner.pkgID, checkedExprType,
this.env.scope.owner, pos, VIRTUAL));
BLangSimpleVariableDef checkedExprVarDef = ASTBuilderUtil.createVariableDef(pos, checkedExprVar);
BLangSimpleVarRef checkedExprVarRef = ASTBuilderUtil.createVariableRef(pos, checkedExprVar.symbol);
BLangAssignment successAssignment = ASTBuilderUtil.createAssignmentStmt(pos, resultVarRef,
createTypeCastExpr(checkedExprVarRef, resultType));
BLangBlockStmt ifBody = ASTBuilderUtil.createBlockStmt(pos);
ifBody.addStatement(successAssignment);
BLangBlockStmt elseBody = getSafeErrorAssignment(pos, checkedExprVarRef, this.env.enclInvokable.symbol,
checkedExpr.equivalentErrorTypeList, isCheckPanic);
BLangValueType checkedExprTypeNode = (BLangValueType) TreeBuilder.createValueTypeNode();
checkedExprTypeNode.setBType(resultType);
checkedExprTypeNode.typeKind = resultType.getKind();
BLangIf ifStmt = ASTBuilderUtil.createIfElseStmt(pos,
createTypeCheckExpr(pos, checkedExprVarRef, checkedExprTypeNode), ifBody, elseBody);
BLangBlockStmt blockStmt = ASTBuilderUtil.createBlockStmt(pos, new ArrayList<>() {{
add(resultVarDef);
add(checkedExprVarDef);
add(ifStmt);
}});
BLangStatementExpression stmtExpr = ASTBuilderUtil.createStatementExpression(blockStmt, resultVarRef);
stmtExpr.setBType(resultType);
result = rewriteExpr(stmtExpr);
}
@Override
public void visit(BLangServiceConstructorExpr serviceConstructorExpr) {
final BLangTypeInit typeInit = ASTBuilderUtil.createEmptyTypeInit(serviceConstructorExpr.pos,
serviceConstructorExpr.serviceNode.serviceClass.symbol.type);
serviceConstructorExpr.serviceNode.annAttachments.forEach(attachment ->  rewrite(attachment, env));
result = rewriteExpr(typeInit);
}
@Override
public void visit(BLangObjectConstructorExpression bLangObjectConstructorExpression) {
visit(bLangObjectConstructorExpression.classNode);
bLangObjectConstructorExpression.classNode.annAttachments.forEach(attachment -> rewrite(attachment, env));
result = rewriteExpr(bLangObjectConstructorExpression.typeInit);
}
@Override
public void visit(BLangAnnotAccessExpr annotAccessExpr) {
BLangBinaryExpr binaryExpr = (BLangBinaryExpr) TreeBuilder.createBinaryExpressionNode();
binaryExpr.pos = annotAccessExpr.pos;
binaryExpr.opKind = OperatorKind.ANNOT_ACCESS;
binaryExpr.lhsExpr = annotAccessExpr.expr;
binaryExpr.rhsExpr = ASTBuilderUtil.createLiteral(annotAccessExpr.pkgAlias.pos, symTable.stringType,
annotAccessExpr.annotationSymbol.bvmAlias());
binaryExpr.setBType(annotAccessExpr.getBType());
binaryExpr.opSymbol = new BOperatorSymbol(names.fromString(OperatorKind.ANNOT_ACCESS.value()), null,
new BInvokableType(Lists.of(binaryExpr.lhsExpr.getBType(),
binaryExpr.rhsExpr.getBType()),
annotAccessExpr.getBType(), null), null,
symTable.builtinPos, VIRTUAL);
result = rewriteExpr(binaryExpr);
}
@Override
public void visit(BLangTypeTestExpr typeTestExpr) {
BLangExpression expr = typeTestExpr.expr;
if (types.isValueType(expr.getBType())) {
expr = addConversionExprIfRequired(expr, symTable.anyType);
}
if (typeTestExpr.isNegation) {
BLangTypeTestExpr bLangTypeTestExpr = ASTBuilderUtil.createTypeTestExpr(typeTestExpr.pos,
typeTestExpr.expr, typeTestExpr.typeNode);
BLangGroupExpr bLangGroupExpr = (BLangGroupExpr) TreeBuilder.createGroupExpressionNode();
bLangGroupExpr.expression = bLangTypeTestExpr;
bLangGroupExpr.setBType(typeTestExpr.getBType());
BLangUnaryExpr unaryExpr = ASTBuilderUtil.createUnaryExpr(typeTestExpr.pos, bLangGroupExpr,
typeTestExpr.getBType(),
OperatorKind.NOT, null);
result = rewriteExpr(unaryExpr);
return;
}
typeTestExpr.expr = rewriteExpr(expr);
typeTestExpr.typeNode = rewrite(typeTestExpr.typeNode, env);
result = typeTestExpr;
}
@Override
public void visit(BLangIsLikeExpr isLikeExpr) {
isLikeExpr.expr = rewriteExpr(isLikeExpr.expr);
result = isLikeExpr;
}
@Override
public void visit(BLangStatementExpression bLangStatementExpression) {
bLangStatementExpression.expr = rewriteExpr(bLangStatementExpression.expr);
bLangStatementExpression.stmt = rewrite(bLangStatementExpression.stmt, env);
result = bLangStatementExpression;
}
@Override
public void visit(BLangQueryExpr queryExpr) {
boolean prevIsVisitingQuery = this.isVisitingQuery;
this.isVisitingQuery = true;
BLangStatementExpression stmtExpr = queryDesugar.desugar(queryExpr, env, getVisibleXMLNSStmts(env));
result = rewrite(stmtExpr, env);
this.isVisitingQuery = prevIsVisitingQuery;
}
List<BLangStatement> getVisibleXMLNSStmts(SymbolEnv env) {
Map<Name, BXMLNSSymbol> nameBXMLNSSymbolMap = symResolver.resolveAllNamespaces(env);
return nameBXMLNSSymbolMap.keySet().stream()
.map(key -> this.stmtsToBePropagatedToQuery.get(key))
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
@Override
public void visit(BLangQueryAction queryAction) {
boolean prevIsVisitingQuery = this.isVisitingQuery;
this.isVisitingQuery = true;
BLangStatementExpression stmtExpr = queryDesugar.desugar(queryAction, env, getVisibleXMLNSStmts(env));
result = rewrite(stmtExpr, env);
this.isVisitingQuery = prevIsVisitingQuery;
}
@Override
public void visit(BLangJSONArrayLiteral jsonArrayLiteral) {
jsonArrayLiteral.exprs = rewriteExprs(jsonArrayLiteral.exprs);
result = jsonArrayLiteral;
}
@Override
public void visit(BLangConstant constant) {
BConstantSymbol constSymbol = constant.symbol;
BType refType = Types.getReferredType(constSymbol.literalType);
if (refType.tag <= TypeTags.BOOLEAN || refType.tag == TypeTags.NIL) {
if (refType.tag != TypeTags.NIL && (constSymbol.value == null ||
constSymbol.value.value == null)) {
throw new IllegalStateException();
}
BLangLiteral literal = ASTBuilderUtil.createLiteral(constant.expr.pos, constSymbol.literalType,
constSymbol.value.value);
constant.expr = rewriteExpr(literal);
} else {
constant.expr = rewriteExpr(constant.expr);
}
constant.annAttachments.forEach(attachment ->  rewrite(attachment, env));
result = constant;
}
@Override
public void visit(BLangIgnoreExpr ignoreExpr) {
result = ignoreExpr;
}
@Override
public void visit(BLangDynamicArgExpr dynamicParamExpr) {
dynamicParamExpr.conditionalArgument = rewriteExpr(dynamicParamExpr.conditionalArgument);
dynamicParamExpr.condition = rewriteExpr(dynamicParamExpr.condition);
result = dynamicParamExpr;
}
@Override
public void visit(BLangConstRef constantRef) {
result = ASTBuilderUtil.createLiteral(constantRef.pos, constantRef.getBType(), constantRef.value);
}
BLangSimpleVariableDef getIteratorVariableDefinition(Location pos, BVarSymbol collectionSymbol,
BInvokableSymbol iteratorInvokableSymbol,
boolean isIteratorFuncFromLangLib) {
BLangSimpleVarRef dataReference = ASTBuilderUtil.createVariableRef(pos, collectionSymbol);
BLangInvocation iteratorInvocation = (BLangInvocation) TreeBuilder.createInvocationNode();
iteratorInvocation.pos = pos;
iteratorInvocation.expr = dataReference;
iteratorInvocation.symbol = iteratorInvokableSymbol;
iteratorInvocation.setBType(iteratorInvokableSymbol.retType);
iteratorInvocation.argExprs = Lists.of(dataReference);
iteratorInvocation.requiredArgs = iteratorInvocation.argExprs;
iteratorInvocation.langLibInvocation = isIteratorFuncFromLangLib;
BVarSymbol iteratorSymbol = new BVarSymbol(0, names.fromString("$iterator$"), this.env.scope.owner.pkgID,
iteratorInvokableSymbol.retType, this.env.scope.owner, pos, VIRTUAL);
BLangSimpleVariable iteratorVariable = ASTBuilderUtil.createVariable(pos, "$iterator$",
iteratorInvokableSymbol.retType, iteratorInvocation, iteratorSymbol);
return ASTBuilderUtil.createVariableDef(pos, iteratorVariable);
}
BLangSimpleVariableDef getIteratorNextVariableDefinition(Location pos, BType nillableResultType,
BVarSymbol iteratorSymbol,
BVarSymbol resultSymbol) {
BLangInvocation nextInvocation = createIteratorNextInvocation(pos, iteratorSymbol);
BLangSimpleVariable resultVariable = ASTBuilderUtil.createVariable(pos, "$result$",
nillableResultType, nextInvocation, resultSymbol);
return ASTBuilderUtil.createVariableDef(pos, resultVariable);
}
BLangInvocation createIteratorNextInvocation(Location pos, BVarSymbol iteratorSymbol) {
BLangIdentifier nextIdentifier = ASTBuilderUtil.createIdentifier(pos, "next");
BLangSimpleVarRef iteratorReferenceInNext = ASTBuilderUtil.createVariableRef(pos, iteratorSymbol);
BInvokableSymbol nextFuncSymbol =
getNextFunc((BObjectType) Types.getReferredType(iteratorSymbol.type)).symbol;
BLangInvocation nextInvocation = (BLangInvocation) TreeBuilder.createInvocationNode();
nextInvocation.pos = pos;
nextInvocation.name = nextIdentifier;
nextInvocation.expr = iteratorReferenceInNext;
nextInvocation.requiredArgs = Lists.of(ASTBuilderUtil.createVariableRef(pos, iteratorSymbol));
nextInvocation.argExprs = nextInvocation.requiredArgs;
nextInvocation.symbol = nextFuncSymbol;
nextInvocation.setBType(nextFuncSymbol.retType);
return nextInvocation;
}
private BAttachedFunction getNextFunc(BObjectType iteratorType) {
BObjectTypeSymbol iteratorSymbol = (BObjectTypeSymbol) iteratorType.tsymbol;
for (BAttachedFunction bAttachedFunction : iteratorSymbol.attachedFuncs) {
if (bAttachedFunction.funcName.value.equals("next")) {
return bAttachedFunction;
}
}
return null;
}
BLangFieldBasedAccess getValueAccessExpression(Location location, BType varType,
BVarSymbol resultSymbol) {
return getFieldAccessExpression(location, "value", varType, resultSymbol);
}
BLangFieldBasedAccess getFieldAccessExpression(Location pos, String fieldName, BType varType,
BVarSymbol resultSymbol) {
BLangSimpleVarRef resultReferenceInVariableDef = ASTBuilderUtil.createVariableRef(pos, resultSymbol);
BLangIdentifier valueIdentifier = ASTBuilderUtil.createIdentifier(pos, fieldName);
BLangFieldBasedAccess fieldBasedAccessExpression =
ASTBuilderUtil.createFieldAccessExpr(resultReferenceInVariableDef, valueIdentifier);
fieldBasedAccessExpression.pos = pos;
fieldBasedAccessExpression.setBType(varType);
fieldBasedAccessExpression.originalType = fieldBasedAccessExpression.getBType();
return fieldBasedAccessExpression;
}
private BlockFunctionBodyNode populateArrowExprBodyBlock(BLangArrowFunction bLangArrowFunction) {
BlockFunctionBodyNode blockNode = TreeBuilder.createBlockFunctionBodyNode();
BLangReturn returnNode = (BLangReturn) TreeBuilder.createReturnNode();
returnNode.pos = bLangArrowFunction.body.expr.pos;
returnNode.setExpression(bLangArrowFunction.body.expr);
blockNode.addStatement(returnNode);
return blockNode;
}
protected BLangInvocation createInvocationNode(String functionName, List<BLangExpression> args, BType retType) {
BLangInvocation invocationNode = (BLangInvocation) TreeBuilder.createInvocationNode();
BLangIdentifier name = (BLangIdentifier) TreeBuilder.createIdentifierNode();
name.setLiteral(false);
name.setValue(functionName);
invocationNode.name = name;
invocationNode.pkgAlias = (BLangIdentifier) TreeBuilder.createIdentifierNode();
invocationNode.symbol = symTable.rootScope.lookup(new Name(functionName)).symbol;
invocationNode.setBType(retType);
invocationNode.requiredArgs = args;
return invocationNode;
}
private BLangInvocation createLangLibInvocationNode(String functionName,
BLangExpression onExpr,
List<BLangExpression> args,
BType retType,
Location pos) {
BLangInvocation invocationNode = (BLangInvocation) TreeBuilder.createInvocationNode();
invocationNode.pos = pos;
BLangIdentifier name = (BLangIdentifier) TreeBuilder.createIdentifierNode();
name.setLiteral(false);
name.setValue(functionName);
name.pos = pos;
invocationNode.name = name;
invocationNode.pkgAlias = (BLangIdentifier) TreeBuilder.createIdentifierNode();
invocationNode.expr = onExpr;
invocationNode.symbol = symResolver.lookupLangLibMethod(onExpr.getBType(), names.fromString(functionName), env);
ArrayList<BLangExpression> requiredArgs = new ArrayList<>();
requiredArgs.add(onExpr);
requiredArgs.addAll(args);
invocationNode.requiredArgs = requiredArgs;
invocationNode.setBType(retType != null ? retType : ((BInvokableSymbol) invocationNode.symbol).retType);
invocationNode.langLibInvocation = true;
return invocationNode;
}
private BLangInvocation createLangLibInvocationNode(String functionName,
List<BLangExpression> args,
BType retType,
Location pos) {
BLangInvocation invocationNode = (BLangInvocation) TreeBuilder.createInvocationNode();
invocationNode.pos = pos;
BLangIdentifier name = (BLangIdentifier) TreeBuilder.createIdentifierNode();
name.setLiteral(false);
name.setValue(functionName);
name.pos = pos;
invocationNode.name = name;
invocationNode.pkgAlias = (BLangIdentifier) TreeBuilder.createIdentifierNode();
invocationNode.symbol = symResolver.lookupMethodInModule(symTable.langInternalModuleSymbol,
names.fromString(functionName), env);
ArrayList<BLangExpression> requiredArgs = new ArrayList<>();
requiredArgs.addAll(args);
invocationNode.requiredArgs = requiredArgs;
invocationNode.setBType(retType != null ? retType : ((BInvokableSymbol) invocationNode.symbol).retType);
invocationNode.langLibInvocation = true;
return invocationNode;
}
private BLangArrayLiteral createArrayLiteralExprNode() {
BLangArrayLiteral expr = (BLangArrayLiteral) TreeBuilder.createArrayLiteralExpressionNode();
expr.exprs = new ArrayList<>();
expr.setBType(new BArrayType(symTable.anyType));
return expr;
}
private void visitFunctionPointerInvocation(BLangInvocation iExpr) {
BLangValueExpression expr;
if (iExpr.expr == null) {
expr = new BLangSimpleVarRef();
} else {
BLangFieldBasedAccess fieldBasedAccess = new BLangFieldBasedAccess();
fieldBasedAccess.expr = iExpr.expr;
fieldBasedAccess.field = iExpr.name;
expr = fieldBasedAccess;
}
expr.symbol = iExpr.symbol;
expr.setBType(iExpr.symbol.type);
BLangExpression rewritten = rewriteExpr(expr);
result = new BFunctionPointerInvocation(iExpr, rewritten);
}
private BLangExpression visitCloneInvocation(BLangExpression expr, BType lhsType) {
if (types.isValueType(expr.getBType())) {
return expr;
}
if (expr.getBType().tag == TypeTags.ERROR) {
return expr;
}
BLangInvocation cloneInvok = createLangLibInvocationNode("clone", expr, new ArrayList<>(), null, expr.pos);
return addConversionExprIfRequired(cloneInvok, lhsType);
}
private BLangExpression visitCloneReadonly(BLangExpression expr, BType lhsType) {
if (types.isValueType(expr.getBType())) {
return expr;
}
if (expr.getBType().tag == TypeTags.ERROR) {
return expr;
}
BLangInvocation cloneInvok = createLangLibInvocationNode("cloneReadOnly", expr, new ArrayList<>(),
expr.getBType(),
expr.pos);
return addConversionExprIfRequired(cloneInvok, lhsType);
}
@SuppressWarnings("unchecked")
<E extends BLangNode> E rewrite(E node, SymbolEnv env) {
if (node == null) {
return null;
}
if (node.desugared) {
return node;
}
SymbolEnv previousEnv = this.env;
this.env = env;
node.accept(this);
BLangNode resultNode = this.result;
this.result = null;
resultNode.desugared = true;
this.env = previousEnv;
return (E) resultNode;
}
@SuppressWarnings("unchecked")
<E extends BLangExpression> E rewriteExpr(E node) {
if (node == null) {
return null;
}
if (node.desugared) {
return node;
}
BLangExpression expr = node;
if (node.impConversionExpr != null) {
expr = node.impConversionExpr;
node.impConversionExpr = null;
}
expr.accept(this);
BLangNode resultNode = this.result;
this.result = null;
resultNode.desugared = true;
return (E) resultNode;
}
@SuppressWarnings("unchecked")
<E extends BLangStatement> E rewrite(E statement, SymbolEnv env) {
if (statement == null) {
return null;
}
BLangStatement stmt = (BLangStatement) rewrite((BLangNode) statement, env);
return (E) stmt;
}
private <E extends BLangStatement> List<E> rewriteStmt(List<E> nodeList, SymbolEnv env) {
for (int i = 0; i < nodeList.size(); i++) {
nodeList.set(i, rewrite(nodeList.get(i), env));
}
return nodeList;
}
private <E extends BLangNode> List<E> rewrite(List<E> nodeList, SymbolEnv env) {
for (int i = 0; i < nodeList.size(); i++) {
nodeList.set(i, rewrite(nodeList.get(i), env));
}
return nodeList;
}
private <E extends BLangExpression> List<E> rewriteExprs(List<E> nodeList) {
for (int i = 0; i < nodeList.size(); i++) {
nodeList.set(i, rewriteExpr(nodeList.get(i)));
}
return nodeList;
}
private BLangLiteral createStringLiteral(Location pos, String value) {
BLangLiteral stringLit = new BLangLiteral(value, symTable.stringType);
stringLit.pos = pos;
return stringLit;
}
private BLangLiteral createIntLiteral(long value) {
BLangLiteral literal = (BLangLiteral) TreeBuilder.createLiteralExpression();
literal.value = value;
literal.setBType(symTable.intType);
return literal;
}
private BLangLiteral createByteLiteral(Location pos, Byte value) {
BLangLiteral byteLiteral = new BLangLiteral(Byte.toUnsignedInt(value), symTable.byteType);
byteLiteral.pos = pos;
return byteLiteral;
}
private BLangExpression createTypeCastExpr(BLangExpression expr, BType targetType) {
if (types.isSameType(expr.getBType(), targetType)) {
return expr;
}
BLangTypeConversionExpr conversionExpr = (BLangTypeConversionExpr) TreeBuilder.createTypeConversionNode();
conversionExpr.pos = expr.pos;
conversionExpr.expr = expr;
conversionExpr.setBType(targetType);
conversionExpr.targetType = targetType;
conversionExpr.internal = true;
return conversionExpr;
}
private BType getElementType(BType bType) {
BType type = Types.getReferredType(bType);
if (type.tag != TypeTags.ARRAY) {
return bType;
}
return getElementType(((BArrayType) type).getElementType());
}
private void addReturnIfNotPresent(BLangInvokableNode invokableNode) {
if (Symbols.isNative(invokableNode.symbol) ||
(invokableNode.hasBody() && invokableNode.body.getKind() != NodeKind.BLOCK_FUNCTION_BODY)) {
return;
}
BLangBlockFunctionBody funcBody = (BLangBlockFunctionBody) invokableNode.body;
if (invokableNode.symbol.type.getReturnType().isNullable() && (funcBody.stmts.size() < 1
|| funcBody.stmts.get(funcBody.stmts.size() - 1).getKind() != NodeKind.RETURN)) {
Location invPos = invokableNode.pos;
Location returnStmtPos;
if (invokableNode.name.value.contains(GENERATED_INIT_SUFFIX.value)) {
returnStmtPos = null;
} else {
returnStmtPos = new BLangDiagnosticLocation(invPos.lineRange().filePath(),
invPos.lineRange().endLine().line(),
invPos.lineRange().endLine().line(),
invPos.lineRange().startLine().offset(),
invPos.lineRange().startLine().offset(), 0, 0);
}
BLangReturn returnStmt = ASTBuilderUtil.createNilReturnStmt(returnStmtPos, symTable.nilType);
funcBody.addStatement(returnStmt);
}
}
/**
* Reorder the invocation arguments to match the original function signature.
*
* @param iExpr Function invocation expressions to reorder the arguments
*/
private void reorderArguments(BLangInvocation iExpr) {
BSymbol symbol = iExpr.symbol;
if (symbol == null || Types.getReferredType(symbol.type).tag != TypeTags.INVOKABLE) {
return;
}
BInvokableSymbol invokableSymbol = (BInvokableSymbol) symbol;
List<BLangExpression> restArgs = iExpr.restArgs;
int originalRequiredArgCount = iExpr.requiredArgs.size();
BLangSimpleVarRef varargRef = null;
BLangBlockStmt blockStmt = null;
BType varargVarType = null;
int restArgCount = restArgs.size();
if (restArgCount > 0 &&
restArgs.get(restArgCount - 1).getKind() == NodeKind.REST_ARGS_EXPR &&
originalRequiredArgCount < invokableSymbol.params.size()) {
BLangExpression expr = ((BLangRestArgsExpression) restArgs.get(restArgCount - 1)).expr;
Location varargExpPos = expr.pos;
varargVarType = expr.getBType();
String varargVarName = DESUGARED_VARARG_KEY + UNDERSCORE + this.varargCount++;
BVarSymbol varargVarSymbol = new BVarSymbol(0, names.fromString(varargVarName), this.env.scope.owner.pkgID,
varargVarType, this.env.scope.owner, varargExpPos, VIRTUAL);
varargRef = ASTBuilderUtil.createVariableRef(varargExpPos, varargVarSymbol);
BLangSimpleVariable var = createVariable(varargExpPos, varargVarName, varargVarType, expr, varargVarSymbol);
BLangSimpleVariableDef varDef = ASTBuilderUtil.createVariableDef(varargExpPos);
varDef.var = var;
varDef.setBType(varargVarType);
blockStmt = createBlockStmt(varargExpPos);
blockStmt.stmts.add(varDef);
}
if (!invokableSymbol.params.isEmpty()) {
reorderNamedArgs(iExpr, invokableSymbol, varargRef);
}
if (restArgCount == 0 || restArgs.get(restArgCount - 1).getKind() != NodeKind.REST_ARGS_EXPR) {
if (invokableSymbol.restParam == null) {
return;
}
BLangArrayLiteral arrayLiteral = (BLangArrayLiteral) TreeBuilder.createArrayLiteralExpressionNode();
List<BLangExpression> exprs = new ArrayList<>();
BArrayType arrayType = (BArrayType) invokableSymbol.restParam.type;
BType elemType = arrayType.eType;
for (BLangExpression restArg : restArgs) {
exprs.add(addConversionExprIfRequired(restArg, elemType));
}
arrayLiteral.exprs = exprs;
arrayLiteral.setBType(arrayType);
if (restArgCount != 0) {
iExpr.restArgs = new ArrayList<>();
}
iExpr.restArgs.add(arrayLiteral);
return;
}
if (restArgCount == 1 && restArgs.get(0).getKind() == NodeKind.REST_ARGS_EXPR) {
if (iExpr.requiredArgs.size() == originalRequiredArgCount) {
return;
}
BLangExpression firstNonRestArg = iExpr.requiredArgs.remove(0);
BLangStatementExpression stmtExpression = createStatementExpression(blockStmt, firstNonRestArg);
stmtExpression.setBType(firstNonRestArg.getBType());
iExpr.requiredArgs.add(0, stmtExpression);
if (invokableSymbol.restParam == null) {
restArgs.remove(0);
return;
}
BLangRestArgsExpression restArgsExpression = (BLangRestArgsExpression) restArgs.remove(0);
BArrayType restParamType = (BArrayType) invokableSymbol.restParam.type;
if (Types.getReferredType(restArgsExpression.getBType()).tag == TypeTags.RECORD) {
BLangExpression expr = ASTBuilderUtil.createEmptyArrayLiteral(invokableSymbol.pos, restParamType);
restArgs.add(expr);
return;
}
Location pos = restArgsExpression.pos;
BLangArrayLiteral newArrayLiteral = createArrayLiteralExprNode();
newArrayLiteral.setBType(restParamType);
String name = DESUGARED_VARARG_KEY + UNDERSCORE + this.varargCount++;
BVarSymbol varSymbol = new BVarSymbol(0, names.fromString(name), this.env.scope.owner.pkgID,
restParamType, this.env.scope.owner, pos, VIRTUAL);
BLangSimpleVarRef arrayVarRef = ASTBuilderUtil.createVariableRef(pos, varSymbol);
BLangSimpleVariable var = createVariable(pos, name, restParamType, newArrayLiteral, varSymbol);
BLangSimpleVariableDef varDef = ASTBuilderUtil.createVariableDef(pos);
varDef.var = var;
varDef.setBType(restParamType);
BLangLiteral startIndex = createIntLiteral(invokableSymbol.params.size() - originalRequiredArgCount);
BLangInvocation lengthInvocation = createLengthInvocation(pos, varargRef);
BLangInvocation intRangeInvocation = replaceWithIntRange(pos, startIndex,
getModifiedIntRangeEndExpr(lengthInvocation));
BLangForeach foreach = (BLangForeach) TreeBuilder.createForeachNode();
foreach.pos = pos;
foreach.collection = intRangeInvocation;
types.setForeachTypedBindingPatternType(foreach);
final BLangSimpleVariable foreachVariable = ASTBuilderUtil.createVariable(pos, "$foreach$i",
foreach.varType);
foreachVariable.symbol = new BVarSymbol(0, names.fromIdNode(foreachVariable.name),
this.env.scope.owner.pkgID, foreachVariable.getBType(),
this.env.scope.owner, pos, VIRTUAL);
BLangSimpleVarRef foreachVarRef = ASTBuilderUtil.createVariableRef(pos, foreachVariable.symbol);
foreach.variableDefinitionNode = ASTBuilderUtil.createVariableDef(pos, foreachVariable);
foreach.isDeclaredWithVar = true;
BLangBlockStmt foreachBody = ASTBuilderUtil.createBlockStmt(pos);
BLangIndexBasedAccess valueExpr = ASTBuilderUtil.createIndexAccessExpr(varargRef, foreachVarRef);
BType refType = Types.getReferredType(varargVarType);
if (refType.tag == TypeTags.ARRAY) {
BArrayType arrayType = (BArrayType) refType;
if (arrayType.state == BArrayState.CLOSED &&
arrayType.size == (iExpr.requiredArgs.size() - originalRequiredArgCount)) {
valueExpr.setBType(restParamType.eType);
} else {
valueExpr.setBType(arrayType.eType);
}
} else {
valueExpr.setBType(symTable.anyOrErrorType);
}
BLangExpression pushExpr = addConversionExprIfRequired(valueExpr, restParamType.eType);
BLangExpressionStmt expressionStmt = createExpressionStmt(pos, foreachBody);
BLangInvocation pushInvocation = createLangLibInvocationNode(PUSH_LANGLIB_METHOD, arrayVarRef,
List.of(pushExpr),
restParamType, pos);
pushInvocation.restArgs.add(pushInvocation.requiredArgs.remove(1));
expressionStmt.expr = pushInvocation;
foreach.body = foreachBody;
BLangBlockStmt newArrayBlockStmt = createBlockStmt(pos);
newArrayBlockStmt.addStatement(varDef);
newArrayBlockStmt.addStatement(foreach);
BLangStatementExpression newArrayStmtExpression = createStatementExpression(newArrayBlockStmt, arrayVarRef);
newArrayStmtExpression.setBType(restParamType);
restArgs.add(addConversionExprIfRequired(newArrayStmtExpression, restParamType));
return;
}
BArrayType restParamType = (BArrayType) invokableSymbol.restParam.type;
BLangArrayLiteral arrayLiteral = (BLangArrayLiteral) TreeBuilder.createArrayLiteralExpressionNode();
arrayLiteral.setBType(restParamType);
BType elemType = restParamType.eType;
Location pos = restArgs.get(0).pos;
List<BLangExpression> exprs = new ArrayList<>();
for (int i = 0; i < restArgCount - 1; i++) {
exprs.add(addConversionExprIfRequired(restArgs.get(i), elemType));
}
arrayLiteral.exprs = exprs;
BLangRestArgsExpression pushRestArgsExpr = (BLangRestArgsExpression) TreeBuilder.createVarArgsNode();
pushRestArgsExpr.pos = pos;
pushRestArgsExpr.expr = restArgs.remove(restArgCount - 1);
String name = DESUGARED_VARARG_KEY + UNDERSCORE + this.varargCount++;
BVarSymbol varSymbol = new BVarSymbol(0, names.fromString(name), this.env.scope.owner.pkgID, restParamType,
this.env.scope.owner, pos, VIRTUAL);
BLangSimpleVarRef arrayVarRef = ASTBuilderUtil.createVariableRef(pos, varSymbol);
BLangSimpleVariable var = createVariable(pos, name, restParamType, arrayLiteral, varSymbol);
BLangSimpleVariableDef varDef = ASTBuilderUtil.createVariableDef(pos);
varDef.var = var;
varDef.setBType(restParamType);
BLangBlockStmt pushBlockStmt = createBlockStmt(pos);
pushBlockStmt.stmts.add(varDef);
BLangExpressionStmt expressionStmt = createExpressionStmt(pos, pushBlockStmt);
BLangInvocation pushInvocation = createLangLibInvocationNode(PUSH_LANGLIB_METHOD, arrayVarRef,
new ArrayList<BLangExpression>() {{
add(pushRestArgsExpr);
}}, restParamType, pos);
pushInvocation.restArgs.add(pushInvocation.requiredArgs.remove(1));
expressionStmt.expr = pushInvocation;
BLangStatementExpression stmtExpression = createStatementExpression(pushBlockStmt, arrayVarRef);
stmtExpression.setBType(restParamType);
iExpr.restArgs = new ArrayList<BLangExpression>(1) {{ add(stmtExpression); }};
}
private void reorderNamedArgs(BLangInvocation iExpr, BInvokableSymbol invokableSymbol, BLangExpression varargRef) {
List<BLangExpression> args = new ArrayList<>();
Map<String, BLangExpression> namedArgs = new LinkedHashMap<>();
iExpr.requiredArgs.stream()
.filter(expr -> expr.getKind() == NodeKind.NAMED_ARGS_EXPR)
.forEach(expr -> namedArgs.put(((NamedArgNode) expr).getName().value, expr));
List<BVarSymbol> params = invokableSymbol.params;
List<BLangRecordLiteral> incRecordLiterals = new ArrayList<>();
BLangRecordLiteral incRecordParamAllowAdditionalFields = null;
int varargIndex = 0;
BType varargType = null;
boolean tupleTypedVararg = false;
if (varargRef != null) {
varargType = Types.getReferredType(varargRef.getBType());
tupleTypedVararg = varargType.tag == TypeTags.TUPLE;
}
for (int i = 0; i < params.size(); i++) {
BVarSymbol param = params.get(i);
if (iExpr.requiredArgs.size() > i && iExpr.requiredArgs.get(i).getKind() != NodeKind.NAMED_ARGS_EXPR) {
args.add(iExpr.requiredArgs.get(i));
} else if (namedArgs.containsKey(param.name.value)) {
args.add(namedArgs.remove(param.name.value));
} else if (param.getFlags().contains(Flag.INCLUDED)) {
BLangRecordLiteral recordLiteral = (BLangRecordLiteral) TreeBuilder.createRecordLiteralNode();
BType paramType = param.type;
recordLiteral.setBType(paramType);
args.add(recordLiteral);
incRecordLiterals.add(recordLiteral);
if (((BRecordType) Types.getReferredType(paramType)).restFieldType != symTable.noType) {
incRecordParamAllowAdditionalFields = recordLiteral;
}
} else if (varargRef == null) {
BLangExpression expr = new BLangIgnoreExpr();
expr.setBType(param.type);
args.add(expr);
} else {
if (Types.getReferredType(varargRef.getBType()).tag == TypeTags.RECORD) {
if (param.isDefaultable) {
BLangInvocation hasKeyInvocation = createLangLibInvocationNode(HAS_KEY, varargRef,
List.of(createStringLiteral(param.pos, param.name.value)), null, varargRef.pos);
BLangExpression indexExpr = rewriteExpr(createStringLiteral(param.pos, param.name.value));
BLangIndexBasedAccess memberAccessExpr =
ASTBuilderUtil.createMemberAccessExprNode(param.type, varargRef, indexExpr);
BLangExpression ignoreExpr = ASTBuilderUtil.createIgnoreExprNode(param.type);
BLangTernaryExpr ternaryExpr = ASTBuilderUtil.createTernaryExprNode(param.type,
hasKeyInvocation, memberAccessExpr, ignoreExpr);
args.add(ASTBuilderUtil.createDynamicParamExpression(hasKeyInvocation, ternaryExpr));
} else {
BLangFieldBasedAccess fieldBasedAccessExpression =
ASTBuilderUtil.createFieldAccessExpr(varargRef,
ASTBuilderUtil.createIdentifier(param.pos, param.name.value));
fieldBasedAccessExpression.setBType(param.type);
args.add(fieldBasedAccessExpression);
}
} else {
BLangExpression indexExpr = rewriteExpr(createIntLiteral(varargIndex));
BType memberAccessExprType = tupleTypedVararg ?
((BTupleType) varargType).tupleTypes.get(varargIndex) : ((BArrayType) varargType).eType;
args.add(addConversionExprIfRequired(ASTBuilderUtil.createMemberAccessExprNode(memberAccessExprType,
varargRef, indexExpr), param.type));
varargIndex++;
}
}
}
if (namedArgs.size() > 0) {
setFieldsForIncRecordLiterals(namedArgs, incRecordLiterals, incRecordParamAllowAdditionalFields);
}
iExpr.requiredArgs = args;
}
private void setFieldsForIncRecordLiterals(Map<String, BLangExpression> namedArgs,
List<BLangRecordLiteral> incRecordLiterals,
BLangRecordLiteral incRecordParamAllowAdditionalFields) {
for (String name : namedArgs.keySet()) {
boolean isAdditionalField = true;
BLangNamedArgsExpression expr = (BLangNamedArgsExpression) namedArgs.get(name);
for (BLangRecordLiteral recordLiteral : incRecordLiterals) {
LinkedHashMap<String, BField> fields =
((BRecordType) Types.getReferredType(recordLiteral.getBType())).fields;
if (fields.containsKey(name) &&
Types.getReferredType(fields.get(name).type).tag != TypeTags.NEVER) {
isAdditionalField = false;
createAndAddRecordFieldForIncRecordLiteral(recordLiteral, expr);
break;
}
}
if (isAdditionalField) {
createAndAddRecordFieldForIncRecordLiteral(incRecordParamAllowAdditionalFields, expr);
}
}
}
private void createAndAddRecordFieldForIncRecordLiteral(BLangRecordLiteral recordLiteral,
BLangNamedArgsExpression expr) {
BLangSimpleVarRef varRef = new BLangSimpleVarRef();
varRef.variableName = expr.name;
BLangRecordLiteral.BLangRecordKeyValueField recordKeyValueField = ASTBuilderUtil.
createBLangRecordKeyValue(varRef, expr.expr);
recordLiteral.fields.add(recordKeyValueField);
}
private BLangBlockStmt getSafeErrorAssignment(Location location, BLangSimpleVarRef ref,
BSymbol invokableSymbol,
List<BType> equivalentErrorTypes,
boolean isCheckPanicExpr) {
BType enclosingFuncReturnType = Types.getReferredType(((BInvokableType) invokableSymbol.type).retType);
Set<BType> returnTypeSet = enclosingFuncReturnType.tag == TypeTags.UNION ?
((BUnionType) enclosingFuncReturnType).getMemberTypes() :
new LinkedHashSet<>() {{
add(enclosingFuncReturnType);
}};
boolean returnOnError = equivalentErrorTypes.stream()
.allMatch(errorType -> returnTypeSet.stream()
.anyMatch(retType -> types.isAssignable(errorType, retType)));
String patternFailureCaseVarName = GEN_VAR_PREFIX.value + "t_failure";
BLangSimpleVariable errorVar =
ASTBuilderUtil.createVariable(location, patternFailureCaseVarName, symTable.errorType,
createTypeCastExpr(ref, symTable.errorType),
new BVarSymbol(0, names.fromString(patternFailureCaseVarName),
this.env.scope.owner.pkgID, symTable.errorType,
this.env.scope.owner, location, VIRTUAL));
BLangBlockStmt blockStmt = ASTBuilderUtil.createBlockStmt(location);
BLangSimpleVariableDef errorVarDef = ASTBuilderUtil.createVariableDef(location, errorVar);
blockStmt.addStatement(errorVarDef);
BLangVariableReference errorVarRef = ASTBuilderUtil.createVariableRef(location, errorVar.symbol);
if (!isCheckPanicExpr && (returnOnError || this.onFailClause != null)) {
BLangFail failStmt = (BLangFail) TreeBuilder.createFailNode();
failStmt.pos = location;
failStmt.expr = errorVarRef;
blockStmt.addStatement(failStmt);
if (returnOnError && this.shouldReturnErrors) {
BLangReturn errorReturn = ASTBuilderUtil.createReturnStmt(location, rewrite(errorVarRef, env));
errorReturn.desugared = true;
failStmt.exprStmt = errorReturn;
}
} else {
BLangPanic panicNode = (BLangPanic) TreeBuilder.createPanicNode();
panicNode.pos = location;
panicNode.expr = errorVarRef;
blockStmt.addStatement(panicNode);
}
return blockStmt;
}
BLangExpression addConversionExprIfRequired(BLangExpression expr, BType lhsType) {
if (lhsType.tag == TypeTags.NONE) {
return expr;
}
BType rhsType = expr.getBType();
if (types.isSameType(rhsType, lhsType)) {
return expr;
}
types.setImplicitCastExpr(expr, rhsType, lhsType);
if (expr.impConversionExpr != null) {
BLangExpression impConversionExpr = expr.impConversionExpr;
expr.impConversionExpr = null;
return impConversionExpr;
}
if (lhsType.tag == TypeTags.JSON && rhsType.tag == TypeTags.NIL) {
return expr;
}
if (lhsType.tag == TypeTags.NIL && rhsType.isNullable()) {
return expr;
}
if (lhsType.tag == TypeTags.ARRAY && rhsType.tag == TypeTags.TUPLE) {
return expr;
}
BLangTypeConversionExpr conversionExpr = (BLangTypeConversionExpr)
TreeBuilder.createTypeConversionNode();
conversionExpr.expr = expr;
conversionExpr.targetType = lhsType;
conversionExpr.setBType(lhsType);
conversionExpr.pos = expr.pos;
conversionExpr.checkTypes = false;
conversionExpr.internal = true;
return conversionExpr;
}
private BType getStructuredBindingPatternType(BLangVariable bindingPatternVariable) {
if (NodeKind.TUPLE_VARIABLE == bindingPatternVariable.getKind()) {
BLangTupleVariable tupleVariable = (BLangTupleVariable) bindingPatternVariable;
List<BType> memberTypes = new ArrayList<>();
for (int i = 0; i < tupleVariable.memberVariables.size(); i++) {
memberTypes.add(getStructuredBindingPatternType(tupleVariable.memberVariables.get(i)));
}
BTupleType tupleType = new BTupleType(memberTypes);
if (tupleVariable.restVariable != null) {
BArrayType restArrayType = (BArrayType) getStructuredBindingPatternType(tupleVariable.restVariable);
tupleType.restType = restArrayType.eType;
}
return tupleType;
}
if (NodeKind.RECORD_VARIABLE == bindingPatternVariable.getKind()) {
BLangRecordVariable recordVariable = (BLangRecordVariable) bindingPatternVariable;
BRecordTypeSymbol recordSymbol =
Symbols.createRecordSymbol(0, names.fromString("$anonRecordType$" + UNDERSCORE + recordCount++),
env.enclPkg.symbol.pkgID, null, env.scope.owner, recordVariable.pos,
VIRTUAL);
recordSymbol.initializerFunc = createRecordInitFunc();
recordSymbol.scope = new Scope(recordSymbol);
recordSymbol.scope.define(
names.fromString(recordSymbol.name.value + "." + recordSymbol.initializerFunc.funcName.value),
recordSymbol.initializerFunc.symbol);
LinkedHashMap<String, BField> fields = new LinkedHashMap<>();
List<BLangSimpleVariable> typeDefFields = new ArrayList<>();
for (int i = 0; i < recordVariable.variableList.size(); i++) {
String fieldNameStr = recordVariable.variableList.get(i).key.value;
Name fieldName = names.fromString(fieldNameStr);
BType fieldType = getStructuredBindingPatternType(
recordVariable.variableList.get(i).valueBindingPattern);
BVarSymbol fieldSymbol = new BVarSymbol(Flags.REQUIRED, fieldName, env.enclPkg.symbol.pkgID, fieldType,
recordSymbol, bindingPatternVariable.pos, VIRTUAL);
fields.put(fieldName.value, new BField(fieldName, bindingPatternVariable.pos, fieldSymbol));
typeDefFields.add(ASTBuilderUtil.createVariable(null, fieldNameStr, fieldType, null, fieldSymbol));
recordSymbol.scope.define(fieldName, fieldSymbol);
}
BRecordType recordVarType = new BRecordType(recordSymbol);
recordVarType.fields = fields;
recordVarType.restFieldType = recordVariable.restParam != null ?
((BRecordType) recordVariable.restParam.getBType()).restFieldType :
symTable.anydataType;
recordSymbol.type = recordVarType;
recordVarType.tsymbol = recordSymbol;
BLangRecordTypeNode recordTypeNode = TypeDefBuilderHelper.createRecordTypeNode(typeDefFields,
recordVarType,
bindingPatternVariable.pos);
recordTypeNode.initFunction =
rewrite(TypeDefBuilderHelper.createInitFunctionForRecordType(recordTypeNode, env, names, symTable),
env);
TypeDefBuilderHelper.createTypeDefinitionForTSymbol(recordVarType, recordSymbol, recordTypeNode, env);
return recordVarType;
}
if (NodeKind.ERROR_VARIABLE == bindingPatternVariable.getKind()) {
BLangErrorVariable errorVariable = (BLangErrorVariable) bindingPatternVariable;
BErrorTypeSymbol errorTypeSymbol = new BErrorTypeSymbol(
SymTag.ERROR,
Flags.PUBLIC,
names.fromString("$anonErrorType$" + UNDERSCORE + errorCount++),
env.enclPkg.symbol.pkgID,
null, null, errorVariable.pos, VIRTUAL);
BType detailType;
if ((errorVariable.detail == null || errorVariable.detail.isEmpty()) && errorVariable.restDetail != null) {
detailType = symTable.detailType;
} else {
detailType = createDetailType(errorVariable.detail, errorVariable.restDetail, errorCount++,
errorVariable.pos);
BLangRecordTypeNode recordTypeNode = createRecordTypeNode(errorVariable, (BRecordType) detailType);
recordTypeNode.initFunction = TypeDefBuilderHelper
.createInitFunctionForRecordType(recordTypeNode, env, names, symTable);
TypeDefBuilderHelper.createTypeDefinitionForTSymbol(detailType, detailType.tsymbol,
recordTypeNode, env);
}
BErrorType errorType = new BErrorType(errorTypeSymbol, detailType);
errorTypeSymbol.type = errorType;
TypeDefBuilderHelper.createTypeDefinitionForTSymbol(errorType, errorTypeSymbol,
createErrorTypeNode(errorType), env);
return errorType;
}
return bindingPatternVariable.getBType();
}
private BLangRecordTypeNode createRecordTypeNode(BLangErrorVariable errorVariable, BRecordType detailType) {
List<BLangSimpleVariable> fieldList = new ArrayList<>();
for (BLangErrorVariable.BLangErrorDetailEntry field : errorVariable.detail) {
BVarSymbol symbol = field.valueBindingPattern.symbol;
if (symbol == null) {
symbol = new BVarSymbol(Flags.PUBLIC, names.fromString(field.key.value + "$"),
this.env.enclPkg.packageID, symTable.pureType, null,
field.valueBindingPattern.pos, VIRTUAL);
}
BLangSimpleVariable fieldVar = ASTBuilderUtil.createVariable(
field.valueBindingPattern.pos,
symbol.name.value,
field.valueBindingPattern.getBType(),
field.valueBindingPattern.expr,
symbol);
fieldList.add(fieldVar);
}
return TypeDefBuilderHelper.createRecordTypeNode(fieldList, detailType, errorVariable.pos);
}
private BType createDetailType(List<BLangErrorVariable.BLangErrorDetailEntry> detail,
BLangSimpleVariable restDetail, int errorNo, Location pos) {
BRecordType detailRecordType = createAnonRecordType(pos);
if (restDetail == null) {
detailRecordType.sealed = true;
}
for (BLangErrorVariable.BLangErrorDetailEntry detailEntry : detail) {
Name fieldName = names.fromIdNode(detailEntry.key);
BType fieldType = getStructuredBindingPatternType(detailEntry.valueBindingPattern);
BVarSymbol fieldSym = new BVarSymbol(Flags.PUBLIC, fieldName, detailRecordType.tsymbol.pkgID, fieldType,
detailRecordType.tsymbol, detailEntry.key.pos, VIRTUAL);
detailRecordType.fields.put(fieldName.value, new BField(fieldName, detailEntry.key.pos, fieldSym));
detailRecordType.tsymbol.scope.define(fieldName, fieldSym);
}
return detailRecordType;
}
private BRecordType createAnonRecordType(Location pos) {
BRecordTypeSymbol detailRecordTypeSymbol = new BRecordTypeSymbol(
SymTag.RECORD,
Flags.PUBLIC,
names.fromString(anonModelHelper.getNextRecordVarKey(env.enclPkg.packageID)),
env.enclPkg.symbol.pkgID, null, null, pos, VIRTUAL);
detailRecordTypeSymbol.initializerFunc = createRecordInitFunc();
detailRecordTypeSymbol.scope = new Scope(detailRecordTypeSymbol);
detailRecordTypeSymbol.scope.define(
names.fromString(detailRecordTypeSymbol.name.value + "." +
detailRecordTypeSymbol.initializerFunc.funcName.value),
detailRecordTypeSymbol.initializerFunc.symbol);
BRecordType detailRecordType = new BRecordType(detailRecordTypeSymbol);
detailRecordType.restFieldType = symTable.anydataType;
return detailRecordType;
}
private BAttachedFunction createRecordInitFunc() {
BInvokableType bInvokableType = new BInvokableType(new ArrayList<>(), symTable.nilType, null);
BInvokableSymbol initFuncSymbol = Symbols.createFunctionSymbol(
Flags.PUBLIC, Names.EMPTY, Names.EMPTY, env.enclPkg.symbol.pkgID, bInvokableType, env.scope.owner,
false, symTable.builtinPos, VIRTUAL);
initFuncSymbol.retType = symTable.nilType;
return new BAttachedFunction(Names.INIT_FUNCTION_SUFFIX, initFuncSymbol, bInvokableType, symTable.builtinPos);
}
BLangErrorType createErrorTypeNode(BErrorType errorType) {
BLangErrorType errorTypeNode = (BLangErrorType) TreeBuilder.createErrorTypeNode();
errorTypeNode.setBType(errorType);
return errorTypeNode;
}
private BLangExpression createBinaryExpression(Location pos, BLangSimpleVarRef varRef,
BLangExpression expression) {
BLangBinaryExpr binaryExpr;
if (NodeKind.GROUP_EXPR == expression.getKind()) {
return createBinaryExpression(pos, varRef, ((BLangGroupExpr) expression).expression);
}
if (NodeKind.BINARY_EXPR == expression.getKind()) {
binaryExpr = (BLangBinaryExpr) expression;
BLangExpression lhsExpr = createBinaryExpression(pos, varRef, binaryExpr.lhsExpr);
BLangExpression rhsExpr = createBinaryExpression(pos, varRef, binaryExpr.rhsExpr);
binaryExpr = ASTBuilderUtil.createBinaryExpr(pos, lhsExpr, rhsExpr, symTable.booleanType, OperatorKind.OR,
(BOperatorSymbol) symResolver
.resolveBinaryOperator(OperatorKind.OR, symTable.booleanType, symTable.booleanType));
} else if (expression.getKind() == NodeKind.SIMPLE_VARIABLE_REF
&& ((BLangSimpleVarRef) expression).variableName.value.equals(IGNORE.value)) {
BLangValueType anyType = (BLangValueType) TreeBuilder.createValueTypeNode();
anyType.setBType(symTable.anyType);
anyType.typeKind = TypeKind.ANY;
return ASTBuilderUtil.createTypeTestExpr(pos, varRef, anyType);
} else {
binaryExpr = ASTBuilderUtil
.createBinaryExpr(pos, varRef, expression, symTable.booleanType, OperatorKind.EQUAL, null);
BSymbol opSymbol = symResolver.resolveBinaryOperator(OperatorKind.EQUAL, varRef.getBType(),
expression.getBType());
if (opSymbol == symTable.notFoundSymbol) {
opSymbol = symResolver
.getBinaryEqualityForTypeSets(OperatorKind.EQUAL, symTable.anydataType, expression.getBType(),
binaryExpr, env);
}
binaryExpr.opSymbol = (BOperatorSymbol) opSymbol;
}
return binaryExpr;
}
private BLangIsLikeExpr createIsLikeExpression(Location pos, BLangExpression expr, BType type) {
return ASTBuilderUtil.createIsLikeExpr(pos, expr, ASTBuilderUtil.createTypeNode(type), symTable.booleanType);
}
private BLangAssignment createAssignmentStmt(BLangSimpleVariable variable) {
BLangSimpleVarRef varRef = (BLangSimpleVarRef) TreeBuilder.createSimpleVariableReferenceNode();
varRef.pos = variable.pos;
varRef.variableName = variable.name;
varRef.symbol = variable.symbol;
varRef.setBType(variable.getBType());
BLangAssignment assignmentStmt = (BLangAssignment) TreeBuilder.createAssignmentNode();
assignmentStmt.expr = variable.expr;
assignmentStmt.pos = variable.pos;
assignmentStmt.setVariable(varRef);
return assignmentStmt;
}
private BLangAssignment createStructFieldUpdate(BLangFunction function, BLangSimpleVariable variable,
BVarSymbol selfSymbol) {
return createStructFieldUpdate(function, variable.expr, variable.symbol, variable.getBType(), selfSymbol,
variable.name);
}
private BLangAssignment createStructFieldUpdate(BLangFunction function, BLangExpression expr,
BVarSymbol fieldSymbol, BType fieldType, BVarSymbol selfSymbol,
BLangIdentifier fieldName) {
BLangSimpleVarRef selfVarRef = ASTBuilderUtil.createVariableRef(function.pos, selfSymbol);
BLangFieldBasedAccess fieldAccess = ASTBuilderUtil.createFieldAccessExpr(selfVarRef, fieldName);
fieldAccess.symbol = fieldSymbol;
fieldAccess.setBType(fieldType);
fieldAccess.isStoreOnCreation = true;
BLangAssignment assignmentStmt = (BLangAssignment) TreeBuilder.createAssignmentNode();
assignmentStmt.expr = expr;
assignmentStmt.pos = function.pos;
assignmentStmt.setVariable(fieldAccess);
SymbolEnv initFuncEnv = SymbolEnv.createFunctionEnv(function, function.symbol.scope, env);
return rewrite(assignmentStmt, initFuncEnv);
}
private boolean safeNavigate(BLangAccessExpression accessExpr) {
if (accessExpr.isLValue || accessExpr.expr == null) {
return false;
}
if (accessExpr.errorSafeNavigation || accessExpr.nilSafeNavigation) {
return true;
}
NodeKind kind = accessExpr.expr.getKind();
if (kind == NodeKind.FIELD_BASED_ACCESS_EXPR ||
kind == NodeKind.INDEX_BASED_ACCESS_EXPR) {
return safeNavigate((BLangAccessExpression) accessExpr.expr);
}
return false;
}
private BLangExpression rewriteSafeNavigationExpr(BLangAccessExpression accessExpr) {
BType originalExprType = accessExpr.getBType();
String matchTempResultVarName = GEN_VAR_PREFIX.value + "temp_result";
BLangSimpleVariable tempResultVar =
ASTBuilderUtil.createVariable(accessExpr.pos, matchTempResultVarName, accessExpr.getBType(), null,
new BVarSymbol(0, names.fromString(matchTempResultVarName),
this.env.scope.owner.pkgID, accessExpr.getBType(),
this.env.scope.owner, accessExpr.pos, VIRTUAL));
BLangSimpleVariableDef tempResultVarDef = ASTBuilderUtil.createVariableDef(accessExpr.pos, tempResultVar);
BLangVariableReference tempResultVarRef =
ASTBuilderUtil.createVariableRef(accessExpr.pos, tempResultVar.symbol);
handleSafeNavigation(accessExpr, accessExpr.getBType(), tempResultVar);
BLangMatchStatement matchStmt = this.matchStmtStack.firstElement();
BLangBlockStmt blockStmt =
ASTBuilderUtil.createBlockStmt(accessExpr.pos, Lists.of(tempResultVarDef, matchStmt));
BLangStatementExpression stmtExpression = createStatementExpression(blockStmt, tempResultVarRef);
stmtExpression.setBType(originalExprType);
this.matchStmtStack = new Stack<>();
this.accessExprStack = new Stack<>();
this.successClause = null;
this.safeNavigationAssignment = null;
return stmtExpression;
}
private void handleSafeNavigation(BLangAccessExpression accessExpr, BType type, BLangSimpleVariable tempResultVar) {
if (accessExpr.expr == null) {
return;
}
NodeKind kind = accessExpr.expr.getKind();
if (kind == NodeKind.FIELD_BASED_ACCESS_EXPR || kind == NodeKind.INDEX_BASED_ACCESS_EXPR) {
handleSafeNavigation((BLangAccessExpression) accessExpr.expr, type, tempResultVar);
}
if (!(accessExpr.errorSafeNavigation || accessExpr.nilSafeNavigation)) {
BType originalType = Types.getReferredType(accessExpr.originalType);
if (TypeTags.isXMLTypeTag(originalType.tag) || isMapJson(originalType)) {
accessExpr.setBType(BUnionType.create(null, originalType, symTable.errorType));
} else {
accessExpr.setBType(originalType);
}
if (this.safeNavigationAssignment != null) {
this.safeNavigationAssignment.expr = addConversionExprIfRequired(accessExpr, tempResultVar.getBType());
}
return;
}
/*
* If the field access is a safe navigation, create a match expression.
* Then chain the current expression as the success-pattern of the parent
* match expr, if available.
* eg:
* x but {              <--- parent match expr
*   error e => e,
*   T t => t.y but {   <--- current expr
*      error e => e,
*      R r => r.z
*   }
* }
*/
BLangExpression matchExpr = accessExpr.expr;
BType matchExprType = accessExpr.expr.getBType();
Location pos = accessExpr.pos;
BLangMatchStatement matchStmt = ASTBuilderUtil.createMatchStatement(matchExpr, pos);
boolean isAllTypesRecords = false;
LinkedHashSet<BType> memTypes = new LinkedHashSet<>();
BType referredType = Types.getReferredType(matchExpr.getBType());
if (referredType.tag == TypeTags.UNION) {
memTypes = new LinkedHashSet<>(((BUnionType) referredType).getMemberTypes());
isAllTypesRecords = isAllTypesAreRecordsInUnion(memTypes);
}
if (accessExpr.nilSafeNavigation) {
matchStmt.addMatchClause(getMatchNullClause(matchExpr, tempResultVar));
matchStmt.setBType(type);
memTypes.remove(symTable.nilType);
}
if (accessExpr.errorSafeNavigation) {
matchStmt.addMatchClause(getMatchErrorClause(matchExpr, tempResultVar));
matchStmt.setBType(type);
matchStmt.pos = pos;
memTypes.remove(symTable.errorType);
}
BLangMatchClause successClause = null;
Name field = getFieldName(accessExpr);
if (field == Names.EMPTY) {
successClause = getSuccessPatternClause(matchExprType, matchExpr, accessExpr, tempResultVar,
accessExpr.errorSafeNavigation);
matchStmt.addMatchClause(successClause);
pushToMatchStatementStack(matchStmt, successClause, pos);
return;
}
if (isAllTypesRecords) {
for (BType memberType : memTypes) {
BRecordType recordType = (BRecordType) Types.getReferredType(memberType);
if (recordType.fields.containsKey(field.value) || !recordType.sealed) {
successClause = getSuccessPatternClause(memberType, matchExpr, accessExpr, tempResultVar,
accessExpr.errorSafeNavigation);
matchStmt.addMatchClause(successClause);
}
}
matchStmt.addMatchClause(getMatchAllAndNilReturnClause(matchExpr, tempResultVar));
pushToMatchStatementStack(matchStmt, successClause, pos);
return;
}
successClause = getSuccessPatternClause(matchExprType, matchExpr, accessExpr, tempResultVar,
accessExpr.errorSafeNavigation);
matchStmt.addMatchClause(successClause);
pushToMatchStatementStack(matchStmt, successClause, pos);
}
private boolean isMapJson(BType originalType) {
return originalType.tag == TypeTags.MAP && ((BMapType) originalType).getConstraint().tag == TypeTags.JSON;
}
private void pushToMatchStatementStack(BLangMatchStatement matchStmt, BLangMatchClause successClause,
Location pos) {
this.matchStmtStack.push(matchStmt);
if (this.successClause != null) {
this.successClause.blockStmt = ASTBuilderUtil.createBlockStmt(pos, this.env.scope, Lists.of(matchStmt));
}
this.successClause = successClause;
}
private Name getFieldName(BLangAccessExpression accessExpr) {
Name field = Names.EMPTY;
if (accessExpr.getKind() == NodeKind.FIELD_BASED_ACCESS_EXPR) {
field = new Name(((BLangFieldBasedAccess) accessExpr).field.value);
} else if (accessExpr.getKind() == NodeKind.INDEX_BASED_ACCESS_EXPR) {
BLangExpression indexBasedExpression = ((BLangIndexBasedAccess) accessExpr).indexExpr;
if (indexBasedExpression.getKind() == NodeKind.LITERAL) {
field = new Name(((BLangLiteral) indexBasedExpression).value.toString());
}
}
return field;
}
private boolean isAllTypesAreRecordsInUnion(LinkedHashSet<BType> memTypes) {
for (BType memType : memTypes) {
int typeTag = Types.getReferredType(memType).tag;
if (typeTag != TypeTags.RECORD && typeTag != TypeTags.ERROR && typeTag != TypeTags.NIL) {
return false;
}
}
return true;
}
private BLangMatchClause getMatchErrorClause(BLangExpression matchExpr, BLangSimpleVariable tempResultVar) {
String errorPatternVarName = GEN_VAR_PREFIX.value + "t_match_error";
Location pos = matchExpr.pos;
BVarSymbol errorPatternVarSymbol = new BVarSymbol(0, Names.fromString(errorPatternVarName),
this.env.scope.owner.pkgID, symTable.anyOrErrorType, this.env.scope.owner, pos, VIRTUAL);
BLangCaptureBindingPattern captureBindingPattern =
ASTBuilderUtil.createCaptureBindingPattern(errorPatternVarSymbol, errorPatternVarName);
BLangVarBindingPatternMatchPattern varBindingPatternMatchPattern =
ASTBuilderUtil.createVarBindingPatternMatchPattern(captureBindingPattern, matchExpr);
BLangSimpleVarRef assignmentRhsExpr = ASTBuilderUtil.createVariableRef(pos, errorPatternVarSymbol);
BLangVariableReference tempResultVarRef = ASTBuilderUtil.createVariableRef(pos, tempResultVar.symbol);
BLangAssignment assignmentStmt =
ASTBuilderUtil.createAssignmentStmt(pos, tempResultVarRef, assignmentRhsExpr);
BLangBlockStmt clauseBody = ASTBuilderUtil.createBlockStmt(pos, this.env.scope, Lists.of(assignmentStmt));
BLangExpression matchGuard = ASTBuilderUtil.createTypeTestExpr(pos, assignmentRhsExpr, getErrorTypeNode());
matchGuard.setBType(symTable.booleanType);
return ASTBuilderUtil.createMatchClause(matchExpr, clauseBody, matchGuard, varBindingPatternMatchPattern);
}
private BLangMatchClause getMatchNullClause(BLangExpression matchExpr, BLangSimpleVariable tempResultVar) {
String nullPatternVarName = GEN_VAR_PREFIX.value + "t_match_null";
Location pos = matchExpr.pos;
BVarSymbol nullPatternVarSymbol = new BVarSymbol(0, Names.fromString(nullPatternVarName),
this.env.scope.owner.pkgID, symTable.anyOrErrorType, this.env.scope.owner, pos, VIRTUAL);
BLangCaptureBindingPattern captureBindingPattern =
ASTBuilderUtil.createCaptureBindingPattern(nullPatternVarSymbol, nullPatternVarName);
BLangVarBindingPatternMatchPattern varBindingPatternMatchPattern =
ASTBuilderUtil.createVarBindingPatternMatchPattern(captureBindingPattern, matchExpr);
BLangSimpleVarRef assignmentRhsExpr = ASTBuilderUtil.createVariableRef(pos, nullPatternVarSymbol);
BLangVariableReference tempResultVarRef = ASTBuilderUtil.createVariableRef(pos, tempResultVar.symbol);
BLangAssignment assignmentStmt =
ASTBuilderUtil.createAssignmentStmt(pos, tempResultVarRef, assignmentRhsExpr);
BLangBlockStmt clauseBody = ASTBuilderUtil.createBlockStmt(pos, this.env.scope, Lists.of(assignmentStmt));
BLangExpression matchGuard = ASTBuilderUtil.createTypeTestExpr(pos, assignmentRhsExpr, getNillTypeNode());
matchGuard.setBType(symTable.booleanType);
return ASTBuilderUtil.createMatchClause(matchExpr, clauseBody, matchGuard, varBindingPatternMatchPattern);
}
private BLangMatchClause getMatchAllAndNilReturnClause(BLangExpression matchExpr,
BLangSimpleVariable tempResultVar) {
Location pos = matchExpr.pos;
BLangVariableReference tempResultVarRef = ASTBuilderUtil.createVariableRef(pos, tempResultVar.symbol);
BLangAssignment assignmentStmt =
ASTBuilderUtil.createAssignmentStmt(pos, tempResultVarRef, createLiteral(pos, symTable.nilType,
Names.NIL_VALUE));
BLangBlockStmt clauseBody = ASTBuilderUtil.createBlockStmt(pos, this.env.scope, Lists.of(assignmentStmt));
BLangWildCardMatchPattern wildCardMatchPattern = ASTBuilderUtil.createWildCardMatchPattern(matchExpr);
wildCardMatchPattern.setBType(symTable.anyType);
return ASTBuilderUtil.createMatchClause(matchExpr, clauseBody, null, wildCardMatchPattern);
}
private BLangMatchClause getSuccessPatternClause(BType type, BLangExpression matchExpr,
BLangAccessExpression accessExpr,
BLangSimpleVariable tempResultVar, boolean liftError) {
type = types.getSafeType(type, true, liftError);
String successPatternVarName = GEN_VAR_PREFIX.value + "t_match_success";
Location pos = accessExpr.pos;
BVarSymbol  successPatternSymbol;
if (Types.getReferredType(type).tag == TypeTags.INVOKABLE) {
successPatternSymbol = new BInvokableSymbol(SymTag.VARIABLE, 0, Names.fromString(successPatternVarName),
this.env.scope.owner.pkgID, symTable.anyOrErrorType, this.env.scope.owner, pos, VIRTUAL);
} else {
successPatternSymbol = new BVarSymbol(0, Names.fromString(successPatternVarName),
this.env.scope.owner.pkgID, symTable.anyOrErrorType, this.env.scope.owner, pos, VIRTUAL);
}
BLangSimpleVariable successPatternVar = ASTBuilderUtil.createVariable(accessExpr.pos, successPatternVarName,
type, null, successPatternSymbol);
BLangSimpleVarRef successPatternVarRef = ASTBuilderUtil.createVariableRef(accessExpr.pos,
successPatternVar.symbol);
BLangCaptureBindingPattern captureBindingPattern =
ASTBuilderUtil.createCaptureBindingPattern(successPatternSymbol, successPatternVarName);
BLangVarBindingPatternMatchPattern varBindingPatternMatchPattern =
ASTBuilderUtil.createVarBindingPatternMatchPattern(captureBindingPattern, matchExpr);
BLangAccessExpression tempAccessExpr = nodeCloner.cloneNode(accessExpr);
if (accessExpr.getKind() == NodeKind.INDEX_BASED_ACCESS_EXPR) {
((BLangIndexBasedAccess) tempAccessExpr).indexExpr = ((BLangIndexBasedAccess) accessExpr).indexExpr;
}
if (accessExpr instanceof BLangFieldBasedAccess.BLangNSPrefixedFieldBasedAccess) {
((BLangFieldBasedAccess.BLangNSPrefixedFieldBasedAccess) tempAccessExpr).nsSymbol =
((BLangFieldBasedAccess.BLangNSPrefixedFieldBasedAccess) accessExpr).nsSymbol;
}
tempAccessExpr.expr = addConversionExprIfRequired(successPatternVarRef, type);
tempAccessExpr.errorSafeNavigation = false;
tempAccessExpr.nilSafeNavigation = false;
accessExpr.cloneRef = null;
if (TypeTags.isXMLTypeTag(Types.getReferredType(tempAccessExpr.expr.getBType()).tag)) {
tempAccessExpr.setBType(BUnionType.create(null, accessExpr.originalType, symTable.errorType,
symTable.nilType));
} else {
tempAccessExpr.setBType(accessExpr.originalType);
}
tempAccessExpr.optionalFieldAccess = accessExpr.optionalFieldAccess;
BLangVariableReference tempResultVarRef =
ASTBuilderUtil.createVariableRef(accessExpr.pos, tempResultVar.symbol);
BLangExpression assignmentRhsExpr = addConversionExprIfRequired(tempAccessExpr, tempResultVarRef.getBType());
BLangAssignment assignmentStmt =
ASTBuilderUtil.createAssignmentStmt(accessExpr.pos, tempResultVarRef, assignmentRhsExpr);
BLangBlockStmt clauseBody = ASTBuilderUtil.createBlockStmt(accessExpr.pos, this.env.scope,
Lists.of(assignmentStmt));
BLangExpression matchGuard = ASTBuilderUtil.createTypeTestExpr(pos, successPatternVarRef, createTypeNode(type));
matchGuard.setBType(symTable.booleanType);
return ASTBuilderUtil.createMatchClause(matchExpr, clauseBody, matchGuard, varBindingPatternMatchPattern);
}
BLangValueType getNillTypeNode() {
BLangValueType nillTypeNode = (BLangValueType) TreeBuilder.createValueTypeNode();
nillTypeNode.typeKind = TypeKind.NIL;
nillTypeNode.setBType(symTable.nilType);
return nillTypeNode;
}
BLangValueType createTypeNode(BType type) {
BLangValueType typeNode = (BLangValueType) TreeBuilder.createValueTypeNode();
typeNode.typeKind = type.getKind();
typeNode.setBType(type);
return typeNode;
}
private BLangValueExpression cloneExpression(BLangExpression expr) {
switch (expr.getKind()) {
case SIMPLE_VARIABLE_REF:
return ASTBuilderUtil.createVariableRef(expr.pos, ((BLangSimpleVarRef) expr).symbol);
case FIELD_BASED_ACCESS_EXPR:
case INDEX_BASED_ACCESS_EXPR:
return cloneAccessExpr((BLangAccessExpression) expr);
default:
throw new IllegalStateException();
}
}
private BLangAccessExpression cloneAccessExpr(BLangAccessExpression originalAccessExpr) {
if (originalAccessExpr.expr == null) {
return originalAccessExpr;
}
BLangExpression varRef;
NodeKind kind = originalAccessExpr.expr.getKind();
if (kind == NodeKind.FIELD_BASED_ACCESS_EXPR || kind == NodeKind.INDEX_BASED_ACCESS_EXPR) {
varRef = cloneAccessExpr((BLangAccessExpression) originalAccessExpr.expr);
} else {
varRef = cloneExpression(originalAccessExpr.expr);
}
varRef.setBType(types.getSafeType(originalAccessExpr.expr.getBType(), true, false));
BLangAccessExpression accessExpr;
switch (originalAccessExpr.getKind()) {
case FIELD_BASED_ACCESS_EXPR:
accessExpr = ASTBuilderUtil.createFieldAccessExpr(varRef,
((BLangFieldBasedAccess) originalAccessExpr).field);
break;
case INDEX_BASED_ACCESS_EXPR:
accessExpr = ASTBuilderUtil.createIndexAccessExpr(varRef,
((BLangIndexBasedAccess) originalAccessExpr).indexExpr);
break;
default:
throw new IllegalStateException();
}
accessExpr.originalType = originalAccessExpr.originalType;
accessExpr.pos = originalAccessExpr.pos;
accessExpr.isLValue = originalAccessExpr.isLValue;
accessExpr.symbol = originalAccessExpr.symbol;
accessExpr.errorSafeNavigation = false;
accessExpr.nilSafeNavigation = false;
accessExpr.setBType(originalAccessExpr.originalType);
return accessExpr;
}
private BLangBinaryExpr getModifiedIntRangeStartExpr(BLangExpression expr) {
BLangLiteral constOneLiteral = ASTBuilderUtil.createLiteral(expr.pos, symTable.intType, 1L);
return ASTBuilderUtil.createBinaryExpr(expr.pos, expr, constOneLiteral, symTable.intType, OperatorKind.ADD,
(BOperatorSymbol) symResolver.resolveBinaryOperator(OperatorKind.ADD,
symTable.intType,
symTable.intType));
}
private BLangBinaryExpr getModifiedIntRangeEndExpr(BLangExpression expr) {
BLangLiteral constOneLiteral = ASTBuilderUtil.createLiteral(expr.pos, symTable.intType, 1L);
return ASTBuilderUtil.createBinaryExpr(expr.pos, expr, constOneLiteral, symTable.intType, OperatorKind.SUB,
(BOperatorSymbol) symResolver.resolveBinaryOperator(OperatorKind.SUB,
symTable.intType,
symTable.intType));
}
private BLangLiteral getBooleanLiteral(boolean value) {
BLangLiteral literal = (BLangLiteral) TreeBuilder.createLiteralExpression();
literal.value = value;
literal.setBType(symTable.booleanType);
literal.pos = symTable.builtinPos;
return literal;
}
private boolean isDefaultableMappingType(BType type) {
switch (types.getSafeType(type, true, false).tag) {
case TypeTags.JSON:
case TypeTags.MAP:
case TypeTags.RECORD:
return true;
case TypeTags.TYPEREFDESC:
return isDefaultableMappingType(Types.getReferredType(type));
default:
return false;
}
}
private BLangFunction createInitFunctionForClassDefn(BLangClassDefinition classDefinition, SymbolEnv env) {
BType returnType = symTable.nilType;
if (classDefinition.initFunction != null) {
returnType = classDefinition.initFunction.getBType().getReturnType();
}
BLangFunction initFunction =
TypeDefBuilderHelper.createInitFunctionForStructureType(null, classDefinition.symbol,
env, names, GENERATED_INIT_SUFFIX,
classDefinition.getBType(), returnType);
BObjectTypeSymbol typeSymbol = ((BObjectTypeSymbol) classDefinition.getBType().tsymbol);
typeSymbol.generatedInitializerFunc = new BAttachedFunction(GENERATED_INIT_SUFFIX, initFunction.symbol,
(BInvokableType) initFunction.getBType(), null);
classDefinition.generatedInitFunction = initFunction;
initFunction.returnTypeNode.setBType(returnType);
return rewrite(initFunction, env);
}
private void visitBinaryLogicalExpr(BLangBinaryExpr binaryExpr) {
/*
* Desugar (lhsExpr && rhsExpr) to following if-else:
*
* logical AND:
* -------------
* T $result$;
* if (lhsExpr) {
*    $result$ = rhsExpr;
* } else {
*    $result$ = false;
* }
*
* logical OR:
* -------------
* T $result$;
* if (lhsExpr) {
*    $result$ = true;
* } else {
*    $result$ = rhsExpr;
* }
*
*/
BLangSimpleVariableDef resultVarDef = createVarDef("$result$", binaryExpr.getBType(), null,
symTable.builtinPos);
BLangBlockStmt thenBody = ASTBuilderUtil.createBlockStmt(binaryExpr.pos);
BLangBlockStmt elseBody = ASTBuilderUtil.createBlockStmt(binaryExpr.pos);
BLangSimpleVarRef thenResultVarRef = ASTBuilderUtil.createVariableRef(symTable.builtinPos,
resultVarDef.var.symbol);
BLangExpression thenResult;
if (binaryExpr.opKind == OperatorKind.AND) {
thenResult = binaryExpr.rhsExpr;
} else {
thenResult = getBooleanLiteral(true);
}
BLangAssignment thenAssignment =
ASTBuilderUtil.createAssignmentStmt(binaryExpr.pos, thenResultVarRef, thenResult);
thenBody.addStatement(thenAssignment);
BLangExpression elseResult;
BLangSimpleVarRef elseResultVarRef = ASTBuilderUtil.createVariableRef(symTable.builtinPos,
resultVarDef.var.symbol);
if (binaryExpr.opKind == OperatorKind.AND) {
elseResult = getBooleanLiteral(false);
} else {
elseResult = binaryExpr.rhsExpr;
}
BLangAssignment elseAssignment =
ASTBuilderUtil.createAssignmentStmt(binaryExpr.pos, elseResultVarRef, elseResult);
elseBody.addStatement(elseAssignment);
BLangSimpleVarRef resultVarRef = ASTBuilderUtil.createVariableRef(binaryExpr.pos, resultVarDef.var.symbol);
BLangIf ifElse = ASTBuilderUtil.createIfElseStmt(binaryExpr.pos, binaryExpr.lhsExpr, thenBody, elseBody);
BLangBlockStmt blockStmt = ASTBuilderUtil.createBlockStmt(binaryExpr.pos, Lists.of(resultVarDef, ifElse));
BLangStatementExpression stmtExpr = createStatementExpression(blockStmt, resultVarRef);
stmtExpr.setBType(binaryExpr.getBType());
result = rewriteExpr(stmtExpr);
}
protected boolean isMappingOrObjectConstructorOrObjInit(BLangExpression expression) {
switch (expression.getKind()) {
case TYPE_INIT_EXPR:
case RECORD_LITERAL_EXPR:
case OBJECT_CTOR_EXPRESSION:
return true;
case CHECK_EXPR:
return isMappingOrObjectConstructorOrObjInit(((BLangCheckedExpr) expression).expr);
case TYPE_CONVERSION_EXPR:
return isMappingOrObjectConstructorOrObjInit(((BLangTypeConversionExpr) expression).expr);
default:
return false;
}
}
private BType getRestType(BInvokableSymbol invokableSymbol) {
if (invokableSymbol != null && invokableSymbol.restParam != null) {
return invokableSymbol.restParam.type;
}
return null;
}
private BType getRestType(BLangFunction function) {
if (function != null && function.restParam != null) {
return function.restParam.getBType();
}
return null;
}
private BVarSymbol getRestSymbol(BLangFunction function) {
if (function != null && function.restParam != null) {
return function.restParam.symbol;
}
return null;
}
private boolean isComputedKey(RecordLiteralNode.RecordField field) {
if (!field.isKeyValueField()) {
return false;
}
return ((BLangRecordLiteral.BLangRecordKeyValueField) field).key.computedKey;
}
private BLangRecordLiteral rewriteMappingConstructor(BLangRecordLiteral mappingConstructorExpr) {
List<RecordLiteralNode.RecordField> fields = mappingConstructorExpr.fields;
BType type = mappingConstructorExpr.getBType();
Location pos = mappingConstructorExpr.pos;
List<RecordLiteralNode.RecordField> rewrittenFields = new ArrayList<>(fields.size());
for (RecordLiteralNode.RecordField field : fields) {
if (field.isKeyValueField()) {
BLangRecordLiteral.BLangRecordKeyValueField keyValueField =
(BLangRecordLiteral.BLangRecordKeyValueField) field;
BLangRecordLiteral.BLangRecordKey key = keyValueField.key;
BLangExpression origKey = key.expr;
BLangExpression keyExpr;
if (key.computedKey) {
keyExpr = origKey;
} else {
keyExpr = origKey.getKind() == NodeKind.SIMPLE_VARIABLE_REF ? createStringLiteral(pos,
StringEscapeUtils.unescapeJava(((BLangSimpleVarRef) origKey).variableName.value)) :
((BLangLiteral) origKey);
}
BLangRecordLiteral.BLangRecordKeyValueField rewrittenField =
ASTBuilderUtil.createBLangRecordKeyValue(rewriteExpr(keyExpr),
rewriteExpr(keyValueField.valueExpr));
rewrittenField.pos = keyValueField.pos;
rewrittenField.key.pos = key.pos;
rewrittenFields.add(rewrittenField);
} else if (field.getKind() == NodeKind.SIMPLE_VARIABLE_REF) {
BLangSimpleVarRef varRefField = (BLangSimpleVarRef) field;
rewrittenFields.add(ASTBuilderUtil.createBLangRecordKeyValue(
rewriteExpr(createStringLiteral(pos,
StringEscapeUtils.unescapeJava(varRefField.variableName.value))),
rewriteExpr(varRefField)));
} else {
BLangRecordLiteral.BLangRecordSpreadOperatorField spreadOpField =
(BLangRecordLiteral.BLangRecordSpreadOperatorField) field;
spreadOpField.expr = rewriteExpr(spreadOpField.expr);
rewrittenFields.add(spreadOpField);
}
}
fields.clear();
BType refType = Types.getReferredType(type);
return refType.tag == TypeTags.RECORD ?
new BLangStructLiteral(pos, type, refType.tsymbol, rewrittenFields) :
new BLangMapLiteral(pos, type, rewrittenFields);
}
protected void addTransactionInternalModuleImport() {
if (!env.enclPkg.packageID.equals(PackageID.TRANSACTION_INTERNAL)) {
BLangImportPackage importDcl = (BLangImportPackage) TreeBuilder.createImportPackageNode();
List<BLangIdentifier> pkgNameComps = new ArrayList<>();
pkgNameComps.add(ASTBuilderUtil.createIdentifier(env.enclPkg.pos, Names.TRANSACTION.value));
importDcl.pkgNameComps = pkgNameComps;
importDcl.pos = env.enclPkg.symbol.pos;
importDcl.orgName = ASTBuilderUtil.createIdentifier(env.enclPkg.pos, Names.BALLERINA_INTERNAL_ORG.value);
importDcl.alias = ASTBuilderUtil.createIdentifier(env.enclPkg.pos, "trx");
importDcl.version = ASTBuilderUtil.createIdentifier(env.enclPkg.pos, "");
importDcl.symbol = symTable.internalTransactionModuleSymbol;
env.enclPkg.imports.add(importDcl);
env.enclPkg.symbol.imports.add(importDcl.symbol);
}
}
}