--- /dev/null
+package org.simantics.scl.compiler.elaboration.macros;
+
+import gnu.trove.map.hash.THashMap;
+
+import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext;
+import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
+import org.simantics.scl.compiler.elaboration.expressions.EApply;
+import org.simantics.scl.compiler.elaboration.expressions.ELambda;
+import org.simantics.scl.compiler.elaboration.expressions.ELambdaType;
+import org.simantics.scl.compiler.elaboration.expressions.ESimpleLambda;
+import org.simantics.scl.compiler.elaboration.expressions.Expression;
+import org.simantics.scl.compiler.elaboration.expressions.Variable;
+import org.simantics.scl.compiler.types.TVar;
+import org.simantics.scl.compiler.types.Type;
+
+/**
+ * This is a macro rule that replaces an application with
+ * the definition of the function.
+ * @author Hannu Niemistö
+ */
+public class StandardMacroRule implements MacroRule {
+ Expression baseExpression;
+ int arity;
+
+ public StandardMacroRule() {
+ }
+
+ public void setBaseExpression(Expression baseExpression) {
+ this.baseExpression = baseExpression;
+
+ Expression cur = baseExpression;
+ while(true) {
+ if(cur instanceof ELambdaType) {
+ cur = ((ELambdaType)cur).value;
+ }
+ else if(cur instanceof ELambda) {
+ ELambda lambda = (ELambda)cur;
+ arity += lambda.getCases()[0].getPatterns().length;
+ break;
+ }
+ else if(cur instanceof ESimpleLambda) {
+ ESimpleLambda lambda = (ESimpleLambda)cur;
+ cur = lambda.value;
+ ++arity;
+ }
+ else
+ break;
+ }
+ }
+
+ @Override
+ public Expression apply(SimplificationContext context,
+ Type[] typeParameters, EApply apply) {
+ if(apply.getParameters().length < arity)
+ return null;
+ THashMap<TVar, Type> tvarMap = new THashMap<TVar, Type>();
+ THashMap<Variable, Expression> varMap = new THashMap<Variable, Expression>();
+
+ Expression baseExpr = baseExpression;
+ /*System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
+ TypeUnparsingContext tuc = new TypeUnparsingContext();
+ System.out.println("initial1 = " + baseExpr.toString(tuc));
+ */
+ {
+ int typeParameterId = 0;
+ while(typeParameterId < typeParameters.length) {
+ ELambdaType lambda = (ELambdaType)baseExpr;
+ for(TVar var : lambda.parameters)
+ tvarMap.put(var, typeParameters[typeParameterId++]);
+ baseExpr = lambda.value;
+ }
+ }
+ for(Expression parameter : apply.getParameters()) {
+ if(baseExpr instanceof ELambda)
+ baseExpr = ((ELambda)baseExpr).decomposeMatching();
+ ESimpleLambda lambda = (ESimpleLambda)baseExpr;
+ varMap.put(lambda.parameter, parameter);
+ baseExpr = lambda.value;
+ }
+
+ /*
+
+ System.out.println("initial2 = " + baseExpr.toString(tuc));
+
+ System.out.print("tvarMap={");
+ boolean first = true;
+ for(Map.Entry<TVar, Type> entry : tvarMap.entrySet()) {
+ if(first)
+ first = false;
+ else
+ System.out.print(", ");
+ System.out.print(entry.getKey().toString(tuc));
+ System.out.print(" = ");
+ System.out.print(entry.getValue().toString(tuc));
+ }
+ System.out.println("}");
+ System.out.println("varMap = " + varMap);
+ */
+ baseExpr = baseExpr.replace(new ReplaceContext(tvarMap, varMap, null));
+
+ //System.out.println("final = " + baseExpr.toString(tuc));
+
+ return baseExpr;
+ }
+
+}