/*
* #%~
* 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.funcvalues;
import java.util.LinkedList;
import java.util.List;
import org.overture.ast.types.AFunctionType;
import org.overture.ast.types.PType;
import org.overture.codegen.ir.IRConstants;
import org.overture.codegen.ir.SPatternIR;
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.AFormalParamLocalParamIR;
import org.overture.codegen.ir.declarations.AInterfaceDeclIR;
import org.overture.codegen.ir.declarations.AMethodDeclIR;
import org.overture.codegen.ir.expressions.AAnonymousClassExpIR;
import org.overture.codegen.ir.expressions.ALambdaExpIR;
import org.overture.codegen.ir.expressions.AMethodInstantiationExpIR;
import org.overture.codegen.ir.expressions.SVarExpIR;
import org.overture.codegen.ir.patterns.AIdentifierPatternIR;
import org.overture.codegen.ir.statements.ABlockStmIR;
import org.overture.codegen.ir.statements.AReturnStmIR;
import org.overture.codegen.ir.types.AInterfaceTypeIR;
import org.overture.codegen.ir.types.AMethodTypeIR;
import org.overture.codegen.ir.types.ATemplateTypeIR;
import org.overture.codegen.trans.assistants.TransAssistantIR;
public class FuncValTrans extends DepthFirstAnalysisAdaptor
{
private TransAssistantIR transformationAssistant;
private FuncValAssistant functionValueAssistant;
private FuncValPrefixes funcValPrefixes;
public FuncValTrans(TransAssistantIR transformationAssistant,
FuncValAssistant functionValueAssistant,
FuncValPrefixes funcValPrefixes)
{
this.transformationAssistant = transformationAssistant;
this.functionValueAssistant = functionValueAssistant;
this.funcValPrefixes = funcValPrefixes;
}
public FuncValAssistant getFunctionValueAssistant()
{
return functionValueAssistant;
}
@Override
public void inAMethodTypeIR(AMethodTypeIR node) throws AnalysisException
{
if (node.parent() instanceof AMethodDeclIR)
{
return;
}
if (node.parent() instanceof SVarExpIR)
{
return;
}
if (node.parent() instanceof AMethodInstantiationExpIR)
{
return;
}
PType vdmType = node.getEquivalent();
if (!(vdmType instanceof AFunctionType))
{
// vdmType == null:
// Can be the case if the default constructor in the IR AST has been manually
// constructed. In this case it is not needed to construct the
// interface
// vdmType can also be an operation type, but operations cannot be used as values
return;
}
AInterfaceDeclIR info = functionValueAssistant.findInterface(node);
if (info == null)
{
info = consInterface(node);
functionValueAssistant.registerInterface(info);
}
}
@Override
public void inALambdaExpIR(ALambdaExpIR node) throws AnalysisException
{
AMethodTypeIR methodType = (AMethodTypeIR) node.getType().clone();
AInterfaceDeclIR lambdaInterface = functionValueAssistant.findInterface(methodType);
if (lambdaInterface == null)
{
@SuppressWarnings("unchecked")
List<? extends AFormalParamLocalParamIR> formalParams = (List<? extends AFormalParamLocalParamIR>) node.getParams().clone();
lambdaInterface = consInterface(methodType, formalParams);
functionValueAssistant.registerInterface(lambdaInterface);
}
LinkedList<AFormalParamLocalParamIR> params = node.getParams();
AInterfaceTypeIR classType = new AInterfaceTypeIR();
classType.setName(lambdaInterface.getName());
AMethodDeclIR lambdaDecl = lambdaInterface.getMethodSignatures().get(0).clone();
for (int i = 0; i < params.size(); i++)
{
AFormalParamLocalParamIR paramLocalDeclIR = params.get(i);
STypeIR paramType = paramLocalDeclIR.getType();
SPatternIR pattern = paramLocalDeclIR.getPattern();
classType.getTypes().add(paramType.clone());
lambdaDecl.getFormalParams().get(i).setType(paramType.clone());
lambdaDecl.getFormalParams().get(i).setPattern(pattern.clone());
}
classType.getTypes().add(methodType.getResult().clone());
lambdaDecl.getMethodType().setResult(methodType.getResult().clone());
AReturnStmIR lambdaReturn = new AReturnStmIR();
lambdaReturn.setExp(node.getExp().clone());
ABlockStmIR lambdaBody = new ABlockStmIR();
lambdaBody.getStatements().add(lambdaReturn);
lambdaDecl.setAbstract(false);
lambdaDecl.setBody(lambdaBody);
AAnonymousClassExpIR classExp = new AAnonymousClassExpIR();
classExp.setType(classType);
classExp.getMethods().add(lambdaDecl);
transformationAssistant.replaceNodeWithRecursively(node, classExp, this);
}
private AInterfaceDeclIR consInterface(AMethodTypeIR methodType)
{
List<AFormalParamLocalParamIR> params = new LinkedList<AFormalParamLocalParamIR>();
List<STypeIR> paramTypes = methodType.getParams();
for (int i = 0; i < paramTypes.size(); i++)
{
STypeIR paramType = paramTypes.get(i);
AFormalParamLocalParamIR param = new AFormalParamLocalParamIR();
String nextParamName = funcValPrefixes.param() + (i + 1);
AIdentifierPatternIR idPattern = new AIdentifierPatternIR();
idPattern.setName(nextParamName);
param.setType(paramType.clone());
param.setPattern(idPattern);
params.add(param);
}
return consInterface(methodType, params);
}
private AInterfaceDeclIR consInterface(AMethodTypeIR methodType,
List<? extends AFormalParamLocalParamIR> params)
{
AInterfaceDeclIR methodTypeInterface = new AInterfaceDeclIR();
methodTypeInterface.setPackage(null);
methodTypeInterface.setName(transformationAssistant.getInfo().getTempVarNameGen().nextVarName(funcValPrefixes.funcInterface()));
AMethodDeclIR evalMethod = new AMethodDeclIR();
evalMethod.setImplicit(false);
evalMethod.setAbstract(true);
evalMethod.setAccess(IRConstants.PUBLIC);
evalMethod.setBody(null);
evalMethod.setIsConstructor(false);
evalMethod.setMethodType(methodType.clone());
evalMethod.setName(funcValPrefixes.evalMethod());
evalMethod.setStatic(false);
AMethodTypeIR evalMethodType = new AMethodTypeIR();
for (int i = 0; i < params.size(); i++)
{
ATemplateTypeIR templateType = new ATemplateTypeIR();
templateType.setName(funcValPrefixes.templateType() + (i + 1));
AFormalParamLocalParamIR formalParam = new AFormalParamLocalParamIR();
formalParam.setType(templateType);
formalParam.setPattern(params.get(i).getPattern().clone());
evalMethod.getFormalParams().add(formalParam);
methodTypeInterface.getTemplateTypes().add(templateType.clone());
evalMethodType.getParams().add(templateType.clone());
}
methodTypeInterface.getMethodSignatures().add(evalMethod);
ATemplateTypeIR templateTypeResult = new ATemplateTypeIR();
templateTypeResult.setName(funcValPrefixes.templateType()
+ (methodType.getParams().size() + 1));
methodTypeInterface.getTemplateTypes().add(templateTypeResult);
evalMethodType.setResult(templateTypeResult.clone());
evalMethod.setMethodType(evalMethodType);
return methodTypeInterface;
}
}