/**
  * Applies the <b>(SEND-SKIP)</b> rule to the <code>pNode</code> using the <code>pContext</code>.
  *
  * @param pContext The big step proof pContext.
  * @param pNode The node to apply the <b>(SEND-SKIP)</b> rule to.
  */
 public void applySendSkip(BigStepProofContext pContext, BigStepProofNode pNode) {
   Send send = (Send) pNode.getExpression();
   Row row = (Row) send.getE();
   if (!row.isValue()) {
     throw new IllegalArgumentException("Can not apply SEND-SKIP"); // $NON-NLS-1$
   }
   Expression[] rowExpressions = row.getExpressions();
   Identifier methodName;
   if (rowExpressions[0] instanceof Method) {
     Method method = (Method) rowExpressions[0];
     methodName = method.getId();
   } else if (rowExpressions[0] instanceof CurriedMethod) {
     CurriedMethod curriedMethod = (CurriedMethod) rowExpressions[0];
     methodName = curriedMethod.getIdentifiers()[0];
   } else {
     throw new IllegalArgumentException("Can not apply SEND-SKIP"); // $NON-NLS-1$
   }
   boolean definedLater = false;
   for (int i = 1; i < row.getExpressions().length; i++) {
     Expression rowChild = rowExpressions[i];
     if ((rowChild instanceof Method) && (((Method) rowChild).getId().equals(send.getId()))) {
       definedLater = true;
       break;
     } else if ((rowChild instanceof CurriedMethod)
         && (((CurriedMethod) rowChild).getIdentifiers()[0].equals(send.getId()))) {
       definedLater = true;
       break;
     }
   }
   if ((definedLater) || (!(send.getId().equals(methodName)))) {
     pContext.addProofNode(pNode, new Send(row.tailRow(), send.getId()));
   } else {
     throw new IllegalArgumentException("Can not apply SEND-SKIP"); // $NON-NLS-1$
   }
 }
 /**
  * Applies the <b>(ATTR)</b> rule to the <code>pNode</code> using the <code>pContext</code>.
  *
  * @param pContext The big step proof pContext.
  * @param pNode The node to apply the <b>(ATTR)</b> rule to.
  */
 public void applyAttr(BigStepProofContext pContext, BigStepProofNode pNode) {
   Row row = (Row) pNode.getExpression();
   Expression[] rowExpressions = row.getExpressions();
   Attribute attribute = (Attribute) rowExpressions[0];
   pContext.addProofNode(pNode, attribute.getE());
   pContext.addProofNode(pNode, row.tailRow());
 }
 /**
  * Applies the <b>(OMEGA)</b> rule to the <code>pNode</code> using the <code>pContext</code>.
  *
  * @param pContext The big step proof pContext.
  * @param pNode The node to apply the <b>(OMEGA)</b> rule to.
  */
 public void applyOmega(BigStepProofContext pContext, BigStepProofNode pNode) {
   Row row = (Row) pNode.getExpression();
   if (!row.isValue()) {
     throw new IllegalArgumentException("Can not apply OMEGA"); // $NON-NLS-1$
   }
   pContext.setProofNodeResult(pNode, row);
 }
 /**
  * Applies the <b>(OBJECT)</b> rule to the <code>pNode</code> using the <code>pContext</code>.
  *
  * @param pContext The big step proof pContext.
  * @param pNode The node to apply the <b>(OBJECT)</b> rule to.
  */
 public void applyObject(BigStepProofContext pContext, BigStepProofNode pNode) {
   ObjectExpr objectExpr = (ObjectExpr) pNode.getExpression();
   Row row = objectExpr.getRow();
   if (row.isValue()) {
     throw new IllegalArgumentException("Can not apply OBJECT"); // $NON-NLS-1$
   }
   pContext.addProofNode(pNode, row);
 }
 /**
  * Applies the <b>(METHOD)</b> rule to the <code>pNode</code> using the <code>pContext</code>.
  *
  * @param pContext The big step proof pContext.
  * @param pNode The node to apply the <b>(METHOD)</b> rule to.
  */
 public void applyMethod(BigStepProofContext pContext, BigStepProofNode pNode) {
   Row row = (Row) pNode.getExpression();
   Expression[] rowExpressions = row.getExpressions();
   if ((!(rowExpressions[0] instanceof Method))
       && (!(rowExpressions[0] instanceof CurriedMethod))) {
     throw new IllegalArgumentException("Can not apply METHOD"); // $NON-NLS-1$
   }
   pContext.addProofNode(pNode, row.tailRow());
 }
 /**
  * Applies the <b>(EMPTY)</b> rule to the
  * <code>node</node> using the <code>context</code>.
  *
  * @param context the minimal typing proof context.
  * @param pNode the minimal typing proof node.
  */
 public void applyEmpty(MinimalTypingProofContext context, MinimalTypingProofNode pNode) {
   MinimalTypingExpressionProofNode node = (MinimalTypingExpressionProofNode) pNode;
   Row row = (Row) node.getExpression();
   Expression[] expressions = row.getExpressions();
   if (expressions.length == 0) {
     // set the type of this node
     context.setNodeType(node, new RowType(new Identifier[0], new MonoType[0]));
     return;
   }
   throw new IllegalArgumentException(
       Messages.getString("MinimalTypingException.8")); // $NON-NLS-1$
 }
 /**
  * Applies the <b>(ATTR)</b> rule to the
  * <code>node</node> using the <code>context</code>.
  *
  * @param context the minimal typing proof context.
  * @param pNode the minimal typing proof node.
  */
 public void applyAttr(MinimalTypingProofContext context, MinimalTypingProofNode pNode) {
   MinimalTypingExpressionProofNode node = (MinimalTypingExpressionProofNode) pNode;
   Row row = (Row) node.getExpression();
   if (row.getExpressions().length > 0 && row.getExpressions()[0] instanceof Attribute) {
     Attribute attr = (Attribute) row.getExpressions()[0];
     TypeEnvironment environment = node.getEnvironment();
     // generate new child node
     context.addProofNode(node, environment, attr.getE());
     return;
   }
   throw new ClassCastException();
 }
 /**
  * Updates the <code>node</code> to which <b>(METHOD)</b> was applied previously.
  *
  * @param pContext The big step proof context.
  * @param pNode The node to update according to <b>(METHOD)</b>.
  */
 public void updateMethod(BigStepProofContext pContext, BigStepProofNode pNode) {
   if ((pNode.getChildCount() == 1) && (pNode.getChildAt(0).isProven())) {
     Row row = (Row) pNode.getExpression();
     Row childRow = (Row) pNode.getChildAt(0).getResult().getValue();
     Expression[] newRowExpressions = new Expression[row.getExpressions().length];
     newRowExpressions[0] = row.getExpressions()[0];
     for (int i = 1; i < newRowExpressions.length; i++) {
       newRowExpressions[i] = childRow.getExpressions()[i - 1];
     }
     pContext.setProofNodeResult(pNode, new Row(newRowExpressions));
   }
 }
 /**
  * Applies the <b>(METHOD-SUBSUME)</b> rule to the
  * <code>node</node> using the <code>context</code>.
  *
  * @param context the minimal typing proof context.
  * @param pNode the minimal typing proof node.
  */
 public void applyMethodSubsume(MinimalTypingProofContext context, MinimalTypingProofNode pNode) {
   MinimalTypingExpressionProofNode node = (MinimalTypingExpressionProofNode) pNode;
   Row row = (Row) node.getExpression();
   if (row.getExpressions().length > 0
       && ((row.getExpressions()[0] instanceof Method)
           || (row.getExpressions()[0] instanceof CurriedMethod))) {
     Identifier self = new Identifier("self", Identifier.Set.SELF); // $NON-NLS-1$
     // generate new child node
     context.addProofNode(node, node.getEnvironment(), self);
     return;
   }
   throw new ClassCastException("expression is not instance of Method"); // $NON-NLS-1$
 }
 /**
  * Updates the <code>node</code> to which <b>(SEND)</b> was applied previously.
  *
  * @param pContext The big step proof context.
  * @param pNode The node to update according to <b>(SEND)</b>.
  */
 public void updateSend(BigStepProofContext pContext, BigStepProofNode pNode) {
   if ((pNode.getChildCount() == 1) && (pNode.getChildAt(0).isProven())) {
     Send send = (Send) pNode.getExpression();
     ObjectExpr objectExpr = (ObjectExpr) pNode.getChildAt(0).getResult().getValue();
     Row row = objectExpr.getRow();
     Expression newRow;
     newRow = row.substitute(objectExpr.getId(), objectExpr);
     pContext.addProofNode(pNode, new Send(newRow, send.getId()));
   } else if ((pNode.getChildCount() == 2)
       && (pNode.getChildAt(0).isProven())
       && (pNode.getChildAt(1).isProven())) {
     pContext.setProofNodeResult(pNode, pNode.getChildAt(1).getResult());
   }
 }
 /**
  * Applies the <b>(SEND-ATTR)</b> rule to the <code>pNode</code> using the <code>pContext</code>.
  *
  * @param pContext The big step proof pContext.
  * @param pNode The node to apply the <b>(SEND-ATTR)</b> rule to.
  */
 public void applySendAttr(BigStepProofContext pContext, BigStepProofNode pNode) {
   Send send = (Send) pNode.getExpression();
   Row row = (Row) send.getE();
   if (!row.isValue()) {
     throw new IllegalArgumentException("Can not apply SEND-ATTR"); // $NON-NLS-1$
   }
   Expression[] rowExpressions = row.getExpressions();
   Attribute attribute = (Attribute) rowExpressions[0];
   Expression[] newRowExpressions = new Expression[row.getExpressions().length - 1];
   for (int i = 0; i < newRowExpressions.length; i++) {
     newRowExpressions[i] = rowExpressions[i + 1].substitute(attribute.getId(), attribute.getE());
   }
   pContext.addProofNode(pNode, new Send(new Row(newRowExpressions), send.getId()));
 }
 /**
  * Updates the <code>node</code> to which <b>(ATTR)</b> was applied previously.
  *
  * @param pContext The big step proof context.
  * @param pNode The node to update according to <b>(ATTR)</b>.
  */
 public void updateAttr(BigStepProofContext pContext, BigStepProofNode pNode) {
   if ((pNode.getChildCount() == 2)
       && (pNode.getChildAt(0).isProven())
       && (pNode.getChildAt(1).isProven())) {
     Row row = (Row) pNode.getExpression();
     Expression childExpression = pNode.getChildAt(0).getResult().getValue();
     Row childRow = (Row) pNode.getChildAt(1).getResult().getValue();
     Attribute attribute = (Attribute) row.getExpressions()[0];
     Expression[] newRowExpressions = new Expression[row.getExpressions().length];
     Attribute newAttribute = new Attribute(attribute.getId(), childExpression);
     newRowExpressions[0] = newAttribute;
     for (int i = 1; i < newRowExpressions.length; i++) {
       newRowExpressions[i] = childRow.getExpressions()[i - 1];
     }
     pContext.setProofNodeResult(pNode, new Row(newRowExpressions));
   }
 }
 /**
  * Applies the <b>(SEND-EXEC)</b> rule to the <code>pNode</code> using the <code>pContext</code>.
  *
  * @param pContext The big step proof pContext.
  * @param pNode The node to apply the <b>(SEND-EXEC)</b> rule to.
  */
 public void applySendExec(BigStepProofContext pContext, BigStepProofNode pNode) {
   Send send = (Send) pNode.getExpression();
   Row row = (Row) send.getE();
   if (!row.isValue()) {
     throw new IllegalArgumentException("Can not apply SEND-EXEC"); // $NON-NLS-1$
   }
   Expression[] rowExpressions = row.getExpressions();
   Identifier methodName;
   Expression methodExpression;
   if (rowExpressions[0] instanceof Method) {
     Method method = (Method) rowExpressions[0];
     methodExpression = method.getE();
     methodName = method.getId();
   } else if (rowExpressions[0] instanceof CurriedMethod) {
     CurriedMethod curriedMethod = (CurriedMethod) rowExpressions[0];
     methodExpression = curriedMethod.getE();
     Identifier[] identifiers = curriedMethod.getIdentifiers();
     MonoType[] types = curriedMethod.getTypes();
     for (int i = identifiers.length - 1; i > 0; i--) {
       methodExpression = new Lambda(identifiers[i], types[i], methodExpression);
     }
     methodName = identifiers[0];
   } else {
     throw new IllegalArgumentException("Can not apply SEND-EXEC"); // $NON-NLS-1$
   }
   if (!(send.getId().equals(methodName))) {
     throw new IllegalArgumentException("Can not apply SEND-EXEC"); // $NON-NLS-1$
   }
   boolean definedLater = false;
   for (int i = 1; i < row.getExpressions().length; i++) {
     Expression rowChild = rowExpressions[i];
     if ((rowChild instanceof Method) && (((Method) rowChild).getId().equals(send.getId()))) {
       definedLater = true;
       break;
     } else if ((rowChild instanceof CurriedMethod)
         && (((CurriedMethod) rowChild).getIdentifiers()[0].equals(send.getId()))) {
       definedLater = true;
       break;
     }
   }
   if (!definedLater) {
     pContext.addProofNode(pNode, methodExpression);
   } else {
     throw new IllegalArgumentException("Can not apply SEND-EXEC"); // $NON-NLS-1$
   }
 }
 /**
  * Updates the <code>node</code> to which <b>(ATTR)</b> was applied previously.
  *
  * @param context the minimal typing proof context.
  * @param pNode the node to update according to <b>(ATTR)</b>.
  */
 public void updateAttr(MinimalTypingProofContext context, MinimalTypingProofNode pNode) {
   MinimalTypingExpressionProofNode node = (MinimalTypingExpressionProofNode) pNode;
   if (node.getChildCount() == 1 && node.getFirstChild().isFinished()) {
     Row rowExpression = (Row) node.getExpression();
     Attribute attr = (Attribute) rowExpression.getExpressions()[0];
     TypeEnvironment environment = node.getEnvironment();
     // Create the tailRow and add it as Expression of a new Child
     Expression[] expressions = ((Row) node.getExpression()).getExpressions();
     Expression[] tailRow = new Expression[expressions.length - 1];
     for (int i = 1; i < expressions.length; i++) {
       tailRow[i - 1] = expressions[i];
     }
     Row row = new Row(tailRow);
     // generate new child node
     context.addProofNode(
         node, environment.extend(attr.getId(), node.getFirstChild().getType()), row);
   }
   if (node.getChildCount() == 2 && node.getChildAt(1).isFinished()) {
     // set the type of this node
     context.setNodeType(node, node.getChildAt(1).getType());
   }
 }
 /**
  * Updates the <code>node</code> to which <b>(METHOD-SUBSUME)</b> was applied previously.
  *
  * @param context the minimal typing proof context.
  * @param pNode the node to update according to <b>(METHOD-SUBSUME)</b>.
  */
 public void updateMethodSubsume(MinimalTypingProofContext context, MinimalTypingProofNode pNode) {
   MinimalTypingExpressionProofNode node = (MinimalTypingExpressionProofNode) pNode;
   Row row = (Row) node.getExpression();
   if (node.getChildCount() == 1 && node.getFirstChild().isFinished()) {
     if (row.getExpressions()[0] instanceof Method) {
       Method method = (Method) row.getExpressions()[0];
       // generate new child node
       context.addProofNode(node, node.getEnvironment(), method.getE());
     } else {
       CurriedMethod curriedMethod = (CurriedMethod) row.getExpressions()[0];
       Expression curriedMethodE = curriedMethod.getE();
       MonoType[] types = curriedMethod.getTypes();
       Identifier[] identifiers = curriedMethod.getIdentifiers();
       for (int n = identifiers.length - 1; n > 0; --n) {
         curriedMethodE = new Lambda(identifiers[n], types[n], curriedMethodE);
       }
       // generate new child node
       context.addProofNode(pNode, node.getEnvironment(), curriedMethodE);
     }
   } else if (node.getChildCount() == 2 && node.getChildAt(1).isFinished()) {
     // Create the tailRow and add it as Expression of a new Child
     Expression[] expressions = ((Row) node.getExpression()).getExpressions();
     Expression[] tailRow = new Expression[expressions.length - 1];
     for (int i = 1; i < expressions.length; i++) {
       tailRow[i - 1] = expressions[i];
     }
     Row newRow = new Row(tailRow);
     // generate new child node
     context.addProofNode(node, node.getEnvironment(), newRow);
   } else if (node.getChildCount() == 3 && node.getChildAt(2).isFinished()) {
     Expression expression = row.getExpressions()[0];
     MonoType type = node.getFirstChild().getType();
     // if type is a rec type, unfold to get a object type
     if (type instanceof RecType) {
       RecType rec = (RecType) type;
       type = rec.getTau().substitute(rec.getTypeName(), rec);
     }
     ObjectType object = (ObjectType) type;
     RowType rowType = (RowType) object.getPhi();
     Identifier[] identifiers = rowType.getIdentifiers();
     MonoType[] types2 = rowType.getTypes();
     if (expression instanceof Method) {
       Identifier m =
           (expression instanceof Method
               ? ((Method) expression).getId()
               : ((CurriedMethod) expression).getIdentifiers()[0]);
       MonoType tau = null;
       for (int i = 0; i < identifiers.length; i++) {
         if (m.equals(identifiers[i])) {
           tau = types2[i];
           break;
         }
       }
       if (tau == null)
         throw new RuntimeException(
             MessageFormat.format(
                 Messages.getString("MinimalTypingException.2"), m.toString())); // $NON-NLS-1$
       // generate new child node
       context.addProofNode(node, tau, node.getChildAt(1).getType());
     } else {
       CurriedMethod method = (CurriedMethod) expression;
       Identifier m = method.getIdentifiers()[0];
       type = types2[rowType.getIndexOfIdentifier(m)];
       MonoType[] types = method.getTypes();
       MonoType childType = node.getChildAt(1).getType();
       while (childType instanceof ArrowType) {
         childType = ((ArrowType) childType).getTau2();
       }
       ArrowType arrow = new ArrowType(types[types.length - 1], childType);
       for (int i = types.length - 2; i > 1; i--) {
         arrow = new ArrowType(types[i], arrow);
       }
       // generate new child node
       context.addProofNode(node, arrow, type);
     }
   } else if (node.getChildCount() == 4 && node.getChildAt(3).isFinished()) {
     Expression expression = row.getExpressions()[0];
     MonoType type = node.getChildAt(1).getType();
     while (type instanceof ArrowType) {
       type = ((ArrowType) type).getTau2();
     }
     MonoType type2 =
         (expression instanceof Method
             ? ((Method) expression).getTau()
             : ((CurriedMethod) expression).getTypes()[0]);
     if (type2 != null)
       // generate new child node
       context.addProofNode(node, type, type2);
     else {
       Identifier[] ids = new Identifier[1];
       ids[0] =
           (expression instanceof Method
               ? ((Method) expression).getIdentifiers()[0]
               : ((CurriedMethod) expression).getIdentifiers()[0]);
       MonoType[] types = {node.getChildAt(1).getType()};
       RowType rowType = new RowType(ids, types);
       RowType phi = (RowType) node.getChildAt(2).getType();
       rowType = RowType.union(rowType, phi);
       // set the type of this node
       context.setNodeType(node, rowType);
     }
   } else if (node.getChildCount() == 5 && node.getChildAt(4).isFinished()) {
     Expression expression = row.getExpressions()[0];
     Identifier[] ids = new Identifier[1];
     ids[0] =
         (expression instanceof Method
             ? ((Method) expression).getIdentifiers()[0]
             : ((CurriedMethod) expression).getIdentifiers()[0]);
     MonoType[] types = {node.getChildAt(1).getType()};
     RowType rowType = new RowType(ids, types);
     RowType phi = (RowType) node.getChildAt(2).getType();
     rowType = RowType.union(rowType, phi);
     // set the type of this node
     context.setNodeType(node, rowType);
   }
 }