/*
* #%~
* VDM Code Generator
* %%
* Copyright (C) 2008 - 2014 Overture
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #~%
*/
package org.overture.codegen.trans.patterns;
import java.util.LinkedList;
import java.util.List;
import org.apache.log4j.Logger;
import org.overture.codegen.ir.INode;
import org.overture.codegen.ir.PIR;
import org.overture.codegen.ir.SExpIR;
import org.overture.codegen.ir.SPatternIR;
import org.overture.codegen.ir.SStmIR;
import org.overture.codegen.ir.STypeIR;
import org.overture.codegen.ir.analysis.AnalysisException;
import org.overture.codegen.ir.analysis.DepthFirstAnalysisAdaptor;
import org.overture.codegen.ir.declarations.AFieldDeclIR;
import org.overture.codegen.ir.declarations.AFormalParamLocalParamIR;
import org.overture.codegen.ir.declarations.AMethodDeclIR;
import org.overture.codegen.ir.declarations.ARecordDeclIR;
import org.overture.codegen.ir.declarations.AVarDeclIR;
import org.overture.codegen.ir.expressions.ABoolLiteralExpIR;
import org.overture.codegen.ir.expressions.ACastUnaryExpIR;
import org.overture.codegen.ir.expressions.ACharLiteralExpIR;
import org.overture.codegen.ir.expressions.AEqualsBinaryExpIR;
import org.overture.codegen.ir.expressions.AFieldExpIR;
import org.overture.codegen.ir.expressions.AFieldNumberExpIR;
import org.overture.codegen.ir.expressions.AIdentifierVarExpIR;
import org.overture.codegen.ir.expressions.AInstanceofExpIR;
import org.overture.codegen.ir.expressions.AIntLiteralExpIR;
import org.overture.codegen.ir.expressions.ANotUnaryExpIR;
import org.overture.codegen.ir.expressions.APatternMatchRuntimeErrorExpIR;
import org.overture.codegen.ir.expressions.AQuoteLiteralExpIR;
import org.overture.codegen.ir.expressions.ARealLiteralExpIR;
import org.overture.codegen.ir.expressions.ATupleCompatibilityExpIR;
import org.overture.codegen.ir.expressions.AUndefinedExpIR;
import org.overture.codegen.ir.expressions.SVarExpIR;
import org.overture.codegen.ir.patterns.ABoolPatternIR;
import org.overture.codegen.ir.patterns.ACharPatternIR;
import org.overture.codegen.ir.patterns.AIdentifierPatternIR;
import org.overture.codegen.ir.patterns.AIgnorePatternIR;
import org.overture.codegen.ir.patterns.AIntPatternIR;
import org.overture.codegen.ir.patterns.ANullPatternIR;
import org.overture.codegen.ir.patterns.AQuotePatternIR;
import org.overture.codegen.ir.patterns.ARealPatternIR;
import org.overture.codegen.ir.patterns.ARecordPatternIR;
import org.overture.codegen.ir.patterns.AStringPatternIR;
import org.overture.codegen.ir.patterns.ATuplePatternIR;
import org.overture.codegen.ir.statements.AAssignToExpStmIR;
import org.overture.codegen.ir.statements.ABlockStmIR;
import org.overture.codegen.ir.statements.ACaseAltStmStmIR;
import org.overture.codegen.ir.statements.ACasesStmIR;
import org.overture.codegen.ir.statements.AContinueStmIR;
import org.overture.codegen.ir.statements.AForAllStmIR;
import org.overture.codegen.ir.statements.AIfStmIR;
import org.overture.codegen.ir.statements.ALocalPatternAssignmentStmIR;
import org.overture.codegen.ir.statements.ARaiseErrorStmIR;
import org.overture.codegen.ir.types.ABoolBasicTypeIR;
import org.overture.codegen.ir.types.ACharBasicTypeIR;
import org.overture.codegen.ir.types.AErrorTypeIR;
import org.overture.codegen.ir.types.ARecordTypeIR;
import org.overture.codegen.ir.types.ASeqSeqTypeIR;
import org.overture.codegen.ir.types.ATupleTypeIR;
import org.overture.codegen.ir.types.AUnionTypeIR;
import org.overture.codegen.ir.types.AUnknownTypeIR;
import org.overture.codegen.trans.DeclarationTag;
import org.overture.codegen.trans.IterationVarPrefixes;
import org.overture.codegen.trans.assistants.TransAssistantIR;
public class PatternTrans extends DepthFirstAnalysisAdaptor
{
private TransAssistantIR transAssistant;
private PatternVarPrefixes config;
private IterationVarPrefixes iteVarPrefixes;
private String casesExpNamePrefix;
private Logger log = Logger.getLogger(this.getClass().getName());
public PatternTrans(IterationVarPrefixes iteVarPrefixes,
TransAssistantIR transAssistant, PatternVarPrefixes config,
String casesExpNamePrefix)
{
this.transAssistant = transAssistant;
this.iteVarPrefixes = iteVarPrefixes;
this.config = config;
this.casesExpNamePrefix = casesExpNamePrefix;
}
@Override
public void caseALocalPatternAssignmentStmIR(
ALocalPatternAssignmentStmIR node) throws AnalysisException
{
AVarDeclIR nextElementDecl = node.getNextElementDecl();
SPatternIR pattern = nextElementDecl.getPattern();
if (pattern instanceof AIdentifierPatternIR)
{
return;
}
if (pattern instanceof AIgnorePatternIR)
{
AIdentifierPatternIR idPattern = getIdPattern(config.getIgnorePatternPrefix());
transAssistant.replaceNodeWith(node.getTarget(), idPattern);
transAssistant.replaceNodeWith(pattern, idPattern.clone());
return;
}
DeclarationTag tag = fetchTag(node);
ABlockStmIR replacementBlock = consPatternHandlingInIterationBlock(nextElementDecl, tag, node.getExp());
transAssistant.replaceNodeWith(node, replacementBlock);
}
@Override
public void caseACasesStmIR(ACasesStmIR node) throws AnalysisException
{
List<ACaseAltStmStmIR> nodeCases = node.getCases();
SPatternIR firstOriginal = nodeCases.get(0).getPattern().clone();
ABlockStmIR replacementBlock = new ABlockStmIR();
String expName = transAssistant.getInfo().getTempVarNameGen().nextVarName(casesExpNamePrefix);
SExpIR exp = node.getExp();
if (!(node.getExp() instanceof SVarExpIR))
{
AVarDeclIR expVarDecl = transAssistant.getInfo().getDeclAssistant().consLocalVarDecl(node.getExp().getType().clone(), transAssistant.getInfo().getPatternAssistant().consIdPattern(expName), node.getExp().clone());
replacementBlock.getLocalDefs().add(expVarDecl);
exp = transAssistant.getInfo().getExpAssistant().consIdVar(expName, node.getExp().getType().clone());
}
List<PatternInfo> patternInfo = extractFromCases(nodeCases, exp);
PatternBlockData patternData = new PatternBlockData(MismatchHandling.NONE);
List<ABlockStmIR> blocks = consPatternHandlingBlockCases(patternInfo, patternData);
replacementBlock.getStatements().add(blocks.get(0));
ANotUnaryExpIR notSuccess = transAssistant.getInfo().getExpAssistant().negate(patternData.getSuccessVar());
AIfStmIR ifStm = new AIfStmIR();
ABlockStmIR enclosingIf = new ABlockStmIR();
enclosingIf.getStatements().add(ifStm);
replacementBlock.getStatements().add(enclosingIf);
ifStm.setIfExp(notSuccess);
AIfStmIR nextCase = ifStm;
if (nodeCases.size() > 1)
{
ifStm.setElseStm(nodeCases.get(0).getResult().clone());
nextCase = new AIfStmIR();
enclosingIf = new ABlockStmIR();
ifStm.setThenStm(enclosingIf);
enclosingIf.getStatements().add(nextCase);
// All cases except for the first and the last
for (int i = 1; i < nodeCases.size() - 1; i++)
{
enclosingIf.getStatements().addFirst(blocks.get(i));
enclosingIf = new ABlockStmIR();
ACaseAltStmStmIR currentCase = nodeCases.get(i);
nextCase.setIfExp(notSuccess.clone());
nextCase.setElseStm(currentCase.getResult().clone());
AIfStmIR tmp = new AIfStmIR();
enclosingIf.getStatements().add(tmp);
nextCase.setThenStm(enclosingIf);
nextCase = tmp;
}
} else
{
APatternMatchRuntimeErrorExpIR matchFail = new APatternMatchRuntimeErrorExpIR();
matchFail.setType(new AErrorTypeIR());
matchFail.setMessage(config.getMatchFailedMessage(firstOriginal));
ARaiseErrorStmIR noMatchStm = new ARaiseErrorStmIR();
noMatchStm.setError(matchFail);
ifStm.setElseStm(noMatchStm);
}
enclosingIf.getStatements().addFirst(blocks.get(blocks.size() - 1));
nextCase.setIfExp(patternData.getSuccessVar().clone());
nextCase.setThenStm(nodeCases.get(nodeCases.size()
- 1).getResult().clone());
if (node.getOthers() != null)
{
nextCase.setElseStm(node.getOthers().clone());
}
transAssistant.replaceNodeWith(node, replacementBlock);
ifStm.apply(this);
}
@Override
public void caseAMethodDeclIR(AMethodDeclIR node) throws AnalysisException
{
List<PatternInfo> patternInfo = extractFromParams(node.getFormalParams());
if (!node.getAbstract() && node.getBody() != null)
{
ABlockStmIR patternHandlingBlock = consPatternHandlingBlock(patternInfo);
ABlockStmIR newBody = new ABlockStmIR();
newBody.getStatements().add(patternHandlingBlock);
SStmIR oldBody = node.getBody();
transAssistant.replaceNodeWith(oldBody, newBody);
newBody.getStatements().add(oldBody);
newBody.apply(this);
} else
{
for (AFormalParamLocalParamIR param : node.getFormalParams())
{
SPatternIR paramPattern = param.getPattern();
if (!(paramPattern instanceof AIdentifierPatternIR))
{
String prefix = config.getName(param.getPattern().getClass());
if (prefix != null)
{
AIdentifierPatternIR idPattern = getIdPattern(prefix);
transAssistant.replaceNodeWith(param.getPattern(), idPattern);
} else
{
log.error("Could not find prefix for pattern: "
+ paramPattern);
}
}
}
}
}
@Override
public void caseABlockStmIR(ABlockStmIR node) throws AnalysisException
{
boolean taggedBlock = false;
for (int i = 0; i < node.getLocalDefs().size(); i++)
{
AVarDeclIR dec = node.getLocalDefs().get(i);
if (dec.getTag() != null)
{
taggedBlock = true;
DeclarationTag tag = fetchTag(dec);
if (tag.isDeclared() || !(dec instanceof AVarDeclIR))
{
continue;
}
AVarDeclIR nextElementDecl = (AVarDeclIR) dec;
SPatternIR pattern = nextElementDecl.getPattern();
if (pattern instanceof AIdentifierPatternIR)
{
continue;
}
// TODO: Make it such that the successer var is passed on (multiple binds)
ABlockStmIR patternHandlingBlock = consPatternHandlingInIterationBlock(nextElementDecl, tag, nextElementDecl.getExp());
List<SStmIR> stms = new LinkedList<SStmIR>();
stms.addAll(patternHandlingBlock.getStatements());
stms.addAll(node.getStatements());
node.setStatements(stms);
dec.apply(this);
}
}
if (!taggedBlock)
{
List<PatternInfo> patternInfo = extractFromLocalDefs(node.getLocalDefs());
if (!patternInfo.isEmpty())
{
List<DeclBlockPair> declBlockPairs = consPatternHandlingBlocksSeparate(node.getLocalDefs(), patternInfo);
for (int i = 0; i < declBlockPairs.size(); i++)
{
DeclBlockPair currentDeclBlockPair = declBlockPairs.get(i);
if (currentDeclBlockPair.getNextDecl() != null)
{
// The pattern handling block must be put before the
// enclosing statement of the next declaration
SStmIR stm = transAssistant.getEnclosingStm(currentDeclBlockPair.getNextDecl(), "block statement pattern handling");
ABlockStmIR block = new ABlockStmIR();
transAssistant.replaceNodeWith(stm, block);
block.getStatements().add(currentDeclBlockPair.getBlock());
block.getStatements().add(stm);
} else
{
// If there is no next declaration the current declaration
// must be the last declaration of the block statement
INode parent = currentDeclBlockPair.getDecl().parent();
if (parent instanceof ABlockStmIR)
{
ABlockStmIR enc = (ABlockStmIR) parent;
enc.getStatements().addFirst(currentDeclBlockPair.getBlock());
} else
{
log.error("Expected parent of current declaration to be a block statement but got: "
+ parent
+ ". Pattern handling block could not be added.");
}
}
}
}
}
for (SStmIR stm : node.getStatements())
{
stm.apply(this);
}
}
@Override
public void caseAForAllStmIR(AForAllStmIR node) throws AnalysisException
{
SPatternIR pattern = node.getPattern();
if (pattern instanceof AIdentifierPatternIR)
{
node.getExp().apply(this);
node.getBody().apply(this);
return;
}
if (pattern instanceof AIgnorePatternIR)
{
AIdentifierPatternIR idPattern = getIdPattern(config.getIgnorePatternPrefix());
transAssistant.replaceNodeWith(pattern, idPattern);
}
PatternBlockData patternData = new PatternBlockData(MismatchHandling.LOOP_CONTINUE);
patternData.setPattern(pattern);
ABlockStmIR declBlock = new ABlockStmIR();
patternData.setDeclBlock(declBlock);
ABlockStmIR patternHandlingBlock = consPatternCheck(false, pattern, transAssistant.getInfo().getTypeAssistant().findElementType(node.getExp().getType().clone()), patternData, null);
if (patternHandlingBlock != null)
{
declBlock.getStatements().addFirst(patternHandlingBlock);
}
declBlock.getStatements().add(node.getBody().clone());
transAssistant.replaceNodeWith(node.getBody(), declBlock);
node.getExp().apply(this);
node.getBody().apply(this);
}
private ABlockStmIR consPatternHandlingInIterationBlock(
AVarDeclIR nextElementDecl, DeclarationTag tag, SExpIR assignedExp)
{
PatternInfo declInfo = extractPatternInfo(nextElementDecl);
ABlockStmIR declBlockTmp = new ABlockStmIR();
PatternBlockData data = new PatternBlockData(declInfo.getPattern(), declBlockTmp, MismatchHandling.LOOP_CONTINUE);
AVarDeclIR successVarDecl = tag.getSuccessVarDecl();
if (successVarDecl != null)
{
SPatternIR successVarDeclPattern = successVarDecl.getPattern();
if (successVarDeclPattern instanceof AIdentifierPatternIR)
{
AIdentifierPatternIR idPattern = (AIdentifierPatternIR) successVarDeclPattern;
data.setSuccessVarDecl(successVarDecl.clone());
AIdentifierVarExpIR successVar = transAssistant.consSuccessVar(idPattern.getName());
data.setSuccessVar(successVar);
} else
{
log.error("Expected success variable declaration to use an identifier pattern. Got: "
+ successVarDeclPattern);
}
}
List<PatternInfo> patternInfo = new LinkedList<PatternInfo>();
patternInfo.add(declInfo);
ABlockStmIR replacementBlock = new ABlockStmIR();
replacementBlock.getStatements().add(consPatternCheck(false, declInfo.getPattern(), declInfo.getType(), data, declInfo.getActualValue()));
replacementBlock.getStatements().addAll(declBlockTmp.getStatements());
ABlockStmIR enclosingBlock = nextElementDecl.getAncestor(ABlockStmIR.class);
enclosingBlock.getLocalDefs().addAll(declBlockTmp.getLocalDefs());
AVarDeclIR nextDeclCopy = nextElementDecl.clone();
if (tag == null || !tag.isDeclared())
{
replacementBlock.getLocalDefs().addFirst(nextDeclCopy);
} else
{
SPatternIR nextDeclPattern = nextDeclCopy.getPattern();
if (nextDeclPattern instanceof AIdentifierPatternIR)
{
AIdentifierVarExpIR varExp = new AIdentifierVarExpIR();
varExp.setType(nextDeclCopy.getType());
varExp.setIsLocal(true);
varExp.setIsLambda(false);
varExp.setName(((AIdentifierPatternIR) nextDeclPattern).getName());
AAssignToExpStmIR assignment = new AAssignToExpStmIR();
assignment.setTarget(varExp);
assignment.setExp(assignedExp.clone());
replacementBlock.getStatements().addFirst(assignment);
} else
{
log.error("Expected the declaration to have its pattern transformed into an identifier pattern. Got: "
+ nextDeclPattern);
}
}
return replacementBlock;
}
private List<ABlockStmIR> consPatternHandlingBlockCases(
List<PatternInfo> patternInfo, PatternBlockData patternData)
{
List<ABlockStmIR> patternHandlingBlocks = new LinkedList<ABlockStmIR>();
for (PatternInfo currentInfo : patternInfo)
{
SPatternIR currentPattern = currentInfo.getPattern();
ABlockStmIR nextPatternBlock = new ABlockStmIR();
patternData.setDeclBlock(nextPatternBlock);
// Use same success variable
patternData.setPattern(currentPattern);
if (currentPattern instanceof AIdentifierPatternIR)
{
nextPatternBlock.getStatements().add(consIdVarDeclaration(currentInfo, currentPattern));
initSuccessVar(patternData, this.transAssistant.getInfo().getExpAssistant().consBoolLiteral(true), nextPatternBlock);
} else if (currentPattern instanceof AIgnorePatternIR)
{
initSuccessVar(patternData, this.transAssistant.getInfo().getExpAssistant().consBoolLiteral(true), nextPatternBlock);
} else
{
STypeIR currentType = currentInfo.getType();
SExpIR currentActualValue = currentInfo.getActualValue();
boolean declareVarPattern = true;
ABlockStmIR patternCheck = consPatternCheck(declareVarPattern, currentPattern, currentType, patternData, currentActualValue);
patternCheck.getLocalDefs().addAll(nextPatternBlock.getLocalDefs());
nextPatternBlock = patternCheck;
}
patternHandlingBlocks.add(nextPatternBlock);
}
return patternHandlingBlocks;
}
private ABlockStmIR consIdVarDeclaration(PatternInfo currentInfo,
SPatternIR currentPattern)
{
AIdentifierPatternIR idPattern = (AIdentifierPatternIR) currentPattern;
AVarDeclIR idPatternDecl = transAssistant.getInfo().getDeclAssistant().consLocalVarDecl(currentInfo.getType().clone(), idPattern.clone(), currentInfo.getActualValue().clone());
ABlockStmIR wrappingStatement = new ABlockStmIR();
wrappingStatement.getLocalDefs().add(idPatternDecl);
return wrappingStatement;
}
private ABlockStmIR consPatternHandlingBlock(List<PatternInfo> patternInfo)
{
ABlockStmIR topBlock = new ABlockStmIR();
for (PatternInfo info : patternInfo)
{
SPatternIR currentPattern = info.getPattern();
if (!basicCaseHandled(currentPattern))
{
ABlockStmIR currentDeclBlock = new ABlockStmIR();
ABlockStmIR patternHandlingBlock = consPatternCheck(currentPattern, info.getType(), info.getActualValue(), currentDeclBlock);
currentDeclBlock.getStatements().addFirst(patternHandlingBlock);
topBlock.getStatements().add(currentDeclBlock);
}
}
return topBlock;
}
private List<DeclBlockPair> consPatternHandlingBlocksSeparate(
List<AVarDeclIR> decls, List<PatternInfo> patternInfo)
{
List<DeclBlockPair> blocks = new LinkedList<DeclBlockPair>();
for (int i = 0; i < patternInfo.size(); i++)
{
PatternInfo info = patternInfo.get(i);
if (!basicCaseHandled(info.getPattern()))
{
ABlockStmIR currentDeclBlock = new ABlockStmIR();
ABlockStmIR patternHandlingBlock = consPatternCheck(info.getPattern(), info.getType(), info.getActualValue(), currentDeclBlock);
currentDeclBlock.getStatements().addFirst(patternHandlingBlock);
AVarDeclIR nextDecl = i < decls.size() - 1 ? decls.get(1 + i)
: null;
DeclBlockPair declBlockPair = new DeclBlockPair(decls.get(i), nextDecl, currentDeclBlock);
blocks.add(declBlockPair);
}
}
return blocks;
}
private boolean basicCaseHandled(SPatternIR currentPattern)
{
if (currentPattern instanceof AIdentifierPatternIR)
{
return true;
} else if (currentPattern instanceof AIgnorePatternIR)
{
AIdentifierPatternIR idPattern = getIdPattern(config.getIgnorePatternPrefix());
transAssistant.replaceNodeWith(currentPattern, idPattern);
return true;
}
return false;
}
private ABlockStmIR consPatternCheck(SPatternIR pattern, STypeIR type,
SExpIR actualValue, ABlockStmIR declBlock)
{
boolean declareVarPattern = false;
PatternBlockData patternData = new PatternBlockData(pattern, declBlock, MismatchHandling.RAISE_ERROR);
return consPatternCheck(declareVarPattern, pattern, type, patternData, actualValue);
}
private ABlockStmIR consPatternCheck(boolean declarePatternVar,
SPatternIR pattern, STypeIR type, PatternBlockData patternData,
SExpIR actualValue)
{
if (pattern instanceof ABoolPatternIR)
{
ABoolPatternIR boolPattern = (ABoolPatternIR) pattern;
Boolean value = boolPattern.getValue();
ABoolLiteralExpIR consBoolLiteral = transAssistant.getInfo().getExpAssistant().consBoolLiteral(value);
return consSimplePatternCheck(declarePatternVar, boolPattern, consBoolLiteral, patternData, actualValue);
} else if (pattern instanceof ACharPatternIR)
{
ACharPatternIR charPattern = (ACharPatternIR) pattern;
Character value = charPattern.getValue();
ACharLiteralExpIR charLiteral = transAssistant.getInfo().getExpAssistant().consCharLiteral(value);
return consSimplePatternCheck(declarePatternVar, charPattern, charLiteral, patternData, actualValue);
} else if (pattern instanceof AIntPatternIR)
{
AIntPatternIR intPattern = (AIntPatternIR) pattern;
Long value = intPattern.getValue();
AIntLiteralExpIR intLit = transAssistant.getInfo().getExpAssistant().consIntLiteral(value);
return consSimplePatternCheck(declarePatternVar, intPattern, intLit, patternData, actualValue);
} else if (pattern instanceof ANullPatternIR)
{
return consSimplePatternCheck(declarePatternVar, pattern, transAssistant.getInfo().getExpAssistant().consNullExp(), patternData, actualValue);
} else if (pattern instanceof AQuotePatternIR)
{
AQuotePatternIR quotePattern = (AQuotePatternIR) pattern;
String value = quotePattern.getValue();
AQuoteLiteralExpIR quoteLit = transAssistant.getInfo().getExpAssistant().consQuoteLiteral(value);
return consSimplePatternCheck(declarePatternVar, pattern, quoteLit, patternData, actualValue);
} else if (pattern instanceof ARealPatternIR)
{
ARealPatternIR realPattern = (ARealPatternIR) pattern;
Double value = realPattern.getValue();
ARealLiteralExpIR realLit = transAssistant.getInfo().getExpAssistant().consRealLiteral(value);
return consSimplePatternCheck(declarePatternVar, realPattern, realLit, patternData, actualValue);
} else if (pattern instanceof AStringPatternIR)
{
AStringPatternIR stringPattern = (AStringPatternIR) pattern;
String value = stringPattern.getValue();
SExpIR stringValue = null;
if (transAssistant.getInfo().getSettings().getCharSeqAsString())
{
stringValue = transAssistant.getInfo().getExpAssistant().consStringLiteral(value, false);
} else
{
ASeqSeqTypeIR seqType = new ASeqSeqTypeIR();
seqType.setEmpty(false);
seqType.setSeqOf(new ACharBasicTypeIR());
stringValue = transAssistant.getInfo().getExpAssistant().consCharSequence(seqType, value);
}
return consSimplePatternCheck(declarePatternVar, stringPattern, stringValue, patternData, actualValue);
} else if (pattern instanceof ATuplePatternIR)
{
ATuplePatternIR tuplePattern = (ATuplePatternIR) pattern;
if (type instanceof ATupleTypeIR)
{
ATupleTypeIR tupleType = (ATupleTypeIR) type;
return consTuplePatternCheck(declarePatternVar, tuplePattern, tupleType, patternData, actualValue, false);
} else if (type instanceof AUnionTypeIR)
{
return consUnionTypedTuplePatternCheck(declarePatternVar, (AUnionTypeIR) type, patternData, actualValue, tuplePattern);
} else
{
log.error("Expected tuple type or union type. Got: " + type);
}
} else if (pattern instanceof ARecordPatternIR)
{
ARecordPatternIR recordPattern = (ARecordPatternIR) pattern;
ARecordTypeIR recordType = (ARecordTypeIR) recordPattern.getType();
if (type instanceof ARecordTypeIR)
{
return consRecordPatternCheck(declarePatternVar, recordPattern, recordType, patternData, actualValue, checkRecordPattern(actualValue));
} else if (type instanceof AUnionTypeIR)
{
return consRecordPatternCheck(declarePatternVar, recordPattern, recordType, patternData, actualValue, true);
} else
{
log.error("Expected record type or union type. Got: " + type);
}
}
return null;
}
private ABlockStmIR consUnionTypedTuplePatternCheck(
boolean declarePatternVar, AUnionTypeIR unionType,
PatternBlockData patternData, SExpIR actualValue,
ATuplePatternIR tuplePattern)
{
ATupleTypeIR resTupleType = transAssistant.getInfo().getPatternAssistant().getTupleType(unionType, tuplePattern);
ABlockStmIR tuplePatternCheck = consTuplePatternCheck(declarePatternVar, tuplePattern, resTupleType, patternData, actualValue, true);
AInstanceofExpIR instanceCheck = new AInstanceofExpIR();
instanceCheck.setType(new ABoolBasicTypeIR());
instanceCheck.setCheckedType(patternData.getRootPatternVar().getType().clone());
instanceCheck.setExp(patternData.getRootPatternVar().clone());
AIfStmIR typeCheck = new AIfStmIR();
typeCheck.setIfExp(instanceCheck);
typeCheck.setThenStm(tuplePatternCheck);
ABlockStmIR block = new ABlockStmIR();
block.getStatements().add(typeCheck);
return block;
}
private ABlockStmIR consRecordPatternCheck(boolean declarePattern,
ARecordPatternIR recordPattern, ARecordTypeIR recordType,
PatternBlockData patternData, SExpIR actualValue,
boolean checkRecordType)
{
AIdentifierPatternIR idPattern = getIdPattern(config.getName(recordPattern.getClass()));
AIdentifierVarExpIR recordPatternVar = new AIdentifierVarExpIR();
recordPatternVar.setType(recordType.clone());
recordPatternVar.setName(idPattern.getName());
recordPatternVar.setIsLambda(false);
recordPatternVar.setIsLocal(true);
patternData.setRootPatternVar(recordPatternVar);
if (!declarePattern)
{
actualValue = recordPatternVar;
}
ABlockStmIR recordPatternBlock = initPattern(declarePattern, recordPattern, recordType, actualValue, idPattern);
ARecordDeclIR record = transAssistant.getInfo().getAssistantManager().getDeclAssistant().findRecord(transAssistant.getInfo().getClasses(), recordType);
if (patternData.getSuccessVarDecl() == null)
{
consSuccessVarCheck(recordPattern, patternData);
}
mismatchHandling(recordPattern, patternData);
initSuccessVar(patternData, transAssistant.getInfo().getExpAssistant().consBoolLiteral(true), recordPatternBlock);
List<STypeIR> types = new LinkedList<STypeIR>();
for (AFieldDeclIR currentField : record.getFields())
{
types.add(currentField.getType());
}
ABlockStmIR fieldCheckBlock = consFieldCheckBlock(patternData, recordPatternVar, recordPattern.getPatterns(), types, checkRecordType
&& !declarePattern);
recordPatternBlock.getStatements().add(fieldCheckBlock);
if (checkRecordType)
{
AInstanceofExpIR instanceOfExp = new AInstanceofExpIR();
instanceOfExp.setType(new ABoolBasicTypeIR());
instanceOfExp.setExp(actualValue.clone());
instanceOfExp.setCheckedType(recordType.clone());
AIfStmIR ifStm = new AIfStmIR();
ifStm.setIfExp(instanceOfExp);
ifStm.setThenStm(recordPatternBlock);
AAssignToExpStmIR setFalse = new AAssignToExpStmIR();
setFalse.setTarget(patternData.getSuccessVar().clone());
setFalse.setExp(transAssistant.getInfo().getExpAssistant().consBoolLiteral(false));
ifStm.setElseStm(setFalse);
ABlockStmIR wrappingBlock = new ABlockStmIR();
wrappingBlock.getStatements().add(ifStm);
return wrappingBlock;
}
return recordPatternBlock;
}
@SuppressWarnings("unchecked")
private ABlockStmIR consTuplePatternCheck(boolean declarePatternVar,
ATuplePatternIR tuplePattern, ATupleTypeIR tupleType,
PatternBlockData patternData, SExpIR actualValue, boolean cast)
{
AIdentifierPatternIR idPattern = getIdPattern(config.getName(tuplePattern.getClass()));
ABlockStmIR tuplePatternBlock = initPattern(declarePatternVar, tuplePattern, tupleType, actualValue, idPattern);
AIdentifierVarExpIR tuplePatternVar = new AIdentifierVarExpIR();
tuplePatternVar.setType(tupleType.clone());
tuplePatternVar.setName(idPattern.getName());
tuplePatternVar.setIsLambda(false);
tuplePatternVar.setIsLocal(true);
patternData.setRootPatternVar(tuplePatternVar);
ATupleCompatibilityExpIR tupleCheck = new ATupleCompatibilityExpIR();
tupleCheck.setType(new ABoolBasicTypeIR());
if (!cast)
{
tupleCheck.setTuple(tuplePatternVar.clone());
} else
{
ACastUnaryExpIR castTuple = new ACastUnaryExpIR();
castTuple.setType(tupleType.clone());
castTuple.setExp(tuplePatternVar.clone());
tupleCheck.setTuple(castTuple);
}
tupleCheck.setTypes((List<? extends STypeIR>) tupleType.getTypes().clone());
if (patternData.getSuccessVarDecl() == null)
{
consSuccessVarCheck(tuplePattern, patternData);
}
mismatchHandling(tuplePattern, patternData);
initSuccessVar(patternData, tupleCheck, tuplePatternBlock);
LinkedList<SPatternIR> patterns = tuplePattern.getPatterns();
LinkedList<STypeIR> types = tupleType.getTypes();
AIfStmIR fieldSizeCheck = new AIfStmIR();
fieldSizeCheck.setIfExp(patternData.getSuccessVar().clone());
fieldSizeCheck.setThenStm(consFieldCheckBlock(patternData, tuplePatternVar, patterns, types, cast));
tuplePatternBlock.getStatements().add(fieldSizeCheck);
return tuplePatternBlock;
}
private void consSuccessVarCheck(SPatternIR pattern,
PatternBlockData patternData)
{
String successVarName = this.transAssistant.getInfo().getTempVarNameGen().nextVarName(iteVarPrefixes.success());
SExpIR init = null;
if (!patternData.IsRootPattern(pattern))
{
init = transAssistant.getInfo().getExpAssistant().consBoolLiteral(pattern instanceof ATuplePatternIR
? false : true);
init.setType(new ABoolBasicTypeIR());
} else
{
init = new AUndefinedExpIR();
init.setType(new AUnknownTypeIR());
}
AVarDeclIR successVarDecl = transAssistant.consDecl(successVarName, new ABoolBasicTypeIR(), init);
patternData.setSuccessVarDecl(successVarDecl);
AIdentifierVarExpIR successVar = transAssistant.consSuccessVar(successVarName);
patternData.setSuccessVar(successVar);
patternData.getDeclBlock().getLocalDefs().add(successVarDecl);
}
private void mismatchHandling(SPatternIR pattern,
PatternBlockData patternData)
{
if (!patternData.IsRootPattern(pattern))
{
return;
}
if (patternData.getMismatchHandling() == MismatchHandling.RAISE_ERROR)
{
APatternMatchRuntimeErrorExpIR matchFail = new APatternMatchRuntimeErrorExpIR();
matchFail.setType(new AErrorTypeIR());
matchFail.setMessage(config.getMatchFailedMessage(pattern));
ARaiseErrorStmIR noMatchStm = new ARaiseErrorStmIR();
noMatchStm.setError(matchFail);
AIfStmIR consMismatchCheck = consMismatchCheck(patternData.getSuccessVar(), noMatchStm);
patternData.getDeclBlock().getStatements().add(consMismatchCheck);
} else if (patternData.getMismatchHandling() == MismatchHandling.LOOP_CONTINUE)
{
AIfStmIR consMismatchCheck = consMismatchCheck(patternData.getSuccessVar(), new AContinueStmIR());
patternData.getDeclBlock().getStatements().add(consMismatchCheck);
}
}
private AIfStmIR consMismatchCheck(AIdentifierVarExpIR successVar,
SStmIR noMatchStm)
{
AIfStmIR ifCheck = new AIfStmIR();
ifCheck.setIfExp(transAssistant.consBoolCheck(successVar.getName(), true));
ifCheck.setThenStm(noMatchStm);
return ifCheck;
}
private void initSuccessVar(PatternBlockData patternData, SExpIR initExp,
ABlockStmIR patternBlock)
{
if (patternData.getSuccessVarDecl().getExp() instanceof AUndefinedExpIR)
{
patternData.getSuccessVarDecl().setExp(initExp);
} else
{
AAssignToExpStmIR successVarAssignment = new AAssignToExpStmIR();
successVarAssignment.setTarget(patternData.getSuccessVar().clone());
successVarAssignment.setExp(initExp);
patternBlock.getStatements().add(successVarAssignment);
}
}
private ABlockStmIR initPattern(boolean declare, SPatternIR pattern,
STypeIR type, SExpIR actualValue, AIdentifierPatternIR idPattern)
{
ABlockStmIR patternBlock = new ABlockStmIR();
if (declare)
{
AVarDeclIR patternDecl = transAssistant.getInfo().getDeclAssistant().consLocalVarDecl(type.clone(), idPattern.clone(), actualValue.clone());
patternBlock.getLocalDefs().add(patternDecl);
} else
{
transAssistant.replaceNodeWith(pattern, idPattern);
}
return patternBlock;
}
private ABlockStmIR consFieldCheckBlock(PatternBlockData patternData,
AIdentifierVarExpIR patternVar, List<SPatternIR> patterns,
List<STypeIR> types, boolean cast)
{
ABlockStmIR thenPart = new ABlockStmIR();
ABlockStmIR topBlock = thenPart;
for (int i = 0; i < patterns.size(); i++)
{
SPatternIR currentPattern = patterns.get(i);
STypeIR currentType = types.get(i);
if (skipPattern(currentPattern))
{
continue;
} else
{
SExpIR actualValue = consFieldValueToMatch(patternVar, i, currentType, cast);
if (currentPattern instanceof AIdentifierPatternIR)
{
AAssignToExpStmIR localAssignment = declareAndAssignIdVarAssignment(patternData.getDeclBlock(), currentPattern, currentType, actualValue);
thenPart.getStatements().add(localAssignment);
} else
{
ABlockStmIR patternBlock = consPatternBlock(patternData, currentPattern, currentType, actualValue, cast);
if (patternBlock != null)
{
thenPart.getStatements().add(patternBlock);
// The tuple/record pattern have more field patterns to be generated.
// Check the success variable and add a new nesting level
if (morePatternsToGenerate(patterns, i))
{
AIfStmIR successVarCheck = new AIfStmIR();
successVarCheck.setIfExp(patternData.getSuccessVar().clone());
thenPart.getStatements().add(successVarCheck);
ABlockStmIR newThenPart = new ABlockStmIR();
successVarCheck.setThenStm(newThenPart);
thenPart = newThenPart;
}
}
}
}
}
return topBlock;
}
private boolean skipPattern(SPatternIR pattern)
{
return pattern instanceof AIgnorePatternIR;
}
private boolean morePatternsToGenerate(List<SPatternIR> patterns,
int currentPatternIndex)
{
int nextPatternIndex = currentPatternIndex + 1;
for (int i = nextPatternIndex; i < patterns.size(); i++)
{
SPatternIR nextPattern = patterns.get(i);
if (!skipPattern(nextPattern))
{
return true;
}
}
return false;
}
private ABlockStmIR consPatternBlock(PatternBlockData patternData,
SPatternIR currentPattern, STypeIR currentType, SExpIR actualValue,
boolean cast)
{
ABlockStmIR patternBlock = null;
if (currentPattern instanceof ATuplePatternIR)
{
ATuplePatternIR nextTuplePattern = (ATuplePatternIR) currentPattern;
ATupleTypeIR nextTupleType = (ATupleTypeIR) currentType;
patternBlock = consTuplePatternCheck(true, nextTuplePattern, nextTupleType, patternData, actualValue, cast);
} else if (currentPattern instanceof ARecordPatternIR)
{
ARecordPatternIR nextRecordPattern = (ARecordPatternIR) currentPattern;
ARecordTypeIR nextRecordType = (ARecordTypeIR) nextRecordPattern.getType();
boolean checkRecordPattern = checkRecordPattern(actualValue);
patternBlock = consRecordPatternCheck(true, nextRecordPattern, nextRecordType, patternData, actualValue, checkRecordPattern);
} else
{
patternBlock = consPatternCheck(true, currentPattern, currentType, patternData, actualValue);
}
return patternBlock;
}
private SExpIR consFieldValueToMatch(AIdentifierVarExpIR patternVar,
int fieldNumber, STypeIR currentType, boolean cast)
{
if (patternVar.getType() instanceof ATupleTypeIR)
{
return consTupleFieldExp(patternVar, fieldNumber, currentType, cast);
} else if (patternVar.getType() instanceof ARecordTypeIR)
{
return consRecFieldExp(patternVar, fieldNumber, currentType, cast);
}
return null;
}
private AAssignToExpStmIR declareAndAssignIdVarAssignment(
ABlockStmIR declBlock, SPatternIR currentPattern,
STypeIR currentType, SExpIR valueToMatch)
{
AIdentifierPatternIR currentId = (AIdentifierPatternIR) currentPattern;
AVarDeclIR idVarDecl = transAssistant.getInfo().getDeclAssistant().consLocalVarDecl(currentType.clone(), currentPattern.clone(), new AUndefinedExpIR());
declBlock.getLocalDefs().add(idVarDecl);
AIdentifierVarExpIR var = new AIdentifierVarExpIR();
var.setType(currentType.clone());
var.setName(currentId.getName());
var.setIsLocal(true);
var.setIsLambda(false);
AAssignToExpStmIR localAssignment = new AAssignToExpStmIR();
localAssignment.setTarget(var);
localAssignment.setExp(valueToMatch);
return localAssignment;
}
private <T> ABlockStmIR consSimplePatternCheck(boolean declarePatternVar,
SPatternIR pattern, SExpIR valueToMatch,
PatternBlockData patternData, SExpIR actualValue)
{
// Example:
// Number intPattern_2 = 1L;
// Boolean success_2 = intPattern_2.longValue() == 1L;
AIdentifierPatternIR idPattern = getIdPattern(config.getName(pattern.getClass()));
transAssistant.replaceNodeWith(pattern, idPattern);
ABlockStmIR block = new ABlockStmIR();
if (declarePatternVar)
{
AVarDeclIR patternDecl = transAssistant.getInfo().getDeclAssistant().consLocalVarDecl(actualValue.getType().clone(), idPattern.clone(), actualValue.clone());
block.getLocalDefs().add(patternDecl);
}
AIdentifierVarExpIR var = new AIdentifierVarExpIR();
var.setType(valueToMatch.getType().clone());
var.setName(idPattern.getName());
var.setIsLambda(false);
var.setIsLocal(true);
patternData.setRootPatternVar(var);
AEqualsBinaryExpIR check = new AEqualsBinaryExpIR();
check.setType(new ABoolBasicTypeIR());
check.setLeft(var);
check.setRight(valueToMatch);
if (patternData.getSuccessVarDecl() == null)
{
consSuccessVarCheck(pattern, patternData);
}
mismatchHandling(pattern, patternData);
initSuccessVar(patternData, check, block);
return block;
}
public List<PatternInfo> extractFromLocalDefs(List<AVarDeclIR> localDefs)
{
List<PatternInfo> patternInfo = new LinkedList<PatternInfo>();
for (AVarDeclIR decl : localDefs)
{
PatternInfo currentInfo = extractPatternInfo(decl);
patternInfo.add(currentInfo);
}
return patternInfo;
}
private PatternInfo extractPatternInfo(AVarDeclIR decl)
{
STypeIR type = decl.getType();
SPatternIR pattern = decl.getPattern();
SExpIR actualValue = decl.getExp();
return new PatternInfo(type, pattern, actualValue);
}
public List<PatternInfo> extractFromParams(
List<AFormalParamLocalParamIR> params)
{
List<PatternInfo> patternInfo = new LinkedList<PatternInfo>();
for (AFormalParamLocalParamIR param : params)
{
STypeIR type = param.getType();
SPatternIR pattern = param.getPattern();
patternInfo.add(new PatternInfo(type, pattern, null));
}
return patternInfo;
}
public List<PatternInfo> extractFromCases(List<ACaseAltStmStmIR> cases,
SExpIR exp)
{
List<PatternInfo> patternInfo = new LinkedList<PatternInfo>();
for (ACaseAltStmStmIR alt : cases)
{
patternInfo.add(new PatternInfo(alt.getPatternType(), alt.getPattern(), exp));
}
return patternInfo;
}
private AIdentifierPatternIR getIdPattern(String namePrefix)
{
String name = transAssistant.getInfo().getTempVarNameGen().nextVarName(namePrefix);
AIdentifierPatternIR idPattern = new AIdentifierPatternIR();
idPattern.setName(name);
return idPattern;
}
private AFieldNumberExpIR consTupleFieldExp(
AIdentifierVarExpIR tuplePatternVar, int i, STypeIR currentType,
boolean cast)
{
AFieldNumberExpIR fieldNumberExp = new AFieldNumberExpIR();
fieldNumberExp.setType(currentType.clone());
if (!cast)
{
fieldNumberExp.setTuple(tuplePatternVar.clone());
} else
{
ACastUnaryExpIR castedExp = new ACastUnaryExpIR();
castedExp.setType(tuplePatternVar.getType().clone());
castedExp.setExp(tuplePatternVar.clone());
fieldNumberExp.setTuple(castedExp);
}
fieldNumberExp.setField(new Long(1 + i));
return fieldNumberExp;
}
private SExpIR consRecFieldExp(AIdentifierVarExpIR patternVar, int i,
STypeIR currentType, boolean cast)
{
ARecordTypeIR recordType = (ARecordTypeIR) patternVar.getType();
AFieldDeclIR recordField = transAssistant.getInfo().getAssistantManager().getDeclAssistant().getFieldDecl(transAssistant.getInfo().getClasses(), recordType, i);
String fieldName = recordField.getName();
AFieldExpIR fieldExp = consRecFieldExp(patternVar, currentType, fieldName);
if (cast)
{
ACastUnaryExpIR casted = new ACastUnaryExpIR();
casted.setType(recordType.clone());
casted.setExp(fieldExp.getObject());
fieldExp.setObject(casted);
}
return fieldExp;
}
private AFieldExpIR consRecFieldExp(AIdentifierVarExpIR patternVar,
STypeIR currentType, String fieldName)
{
AFieldExpIR fieldExp = new AFieldExpIR();
fieldExp.setType(currentType.clone());
fieldExp.setObject(patternVar.clone());
fieldExp.setMemberName(fieldName);
return fieldExp;
}
private DeclarationTag fetchTag(PIR node)
{
if (node != null)
{
Object tag = node.getTag();
if (tag instanceof DeclarationTag)
{
return (DeclarationTag) tag;
}
}
log.error("Could not fetch declaration tag from pattern assignment: "
+ node);
return null;
}
private boolean checkRecordPattern(SExpIR actualValue)
{
return actualValue != null
&& actualValue.getType() instanceof AUnionTypeIR;
}
}