Coverage Report - org.argouml.profile.internal.ocl.EvaluateExpression
 
Classes in this File Line Coverage Branch Coverage Complexity
EvaluateExpression
14%
55/384
5%
14/238
4.111
EvaluateExpression$1
0%
0/9
N/A
4.111
 
 1  
 /* $Id: EvaluateExpression.java 17836 2010-01-12 19:06:55Z linus $
 2  
  *****************************************************************************
 3  
  * Copyright (c) 2009 Contributors - see below
 4  
  * All rights reserved. This program and the accompanying materials
 5  
  * are made available under the terms of the Eclipse Public License v1.0
 6  
  * which accompanies this distribution, and is available at
 7  
  * http://www.eclipse.org/legal/epl-v10.html
 8  
  *
 9  
  * Contributors:
 10  
  *    euluis
 11  
  *****************************************************************************
 12  
  *
 13  
  * Some portions of this file was previously release using the BSD License:
 14  
  */
 15  
 
 16  
 // Copyright (c) 2008 The Regents of the University of California. All
 17  
 // Rights Reserved. Permission to use, copy, modify, and distribute this
 18  
 // software and its documentation without fee, and without a written
 19  
 // agreement is hereby granted, provided that the above copyright notice
 20  
 // and this paragraph appear in all copies. This software program and
 21  
 // documentation are copyrighted by The Regents of the University of
 22  
 // California. The software program and documentation are supplied "AS
 23  
 // IS", without any accompanying services from The Regents. The Regents
 24  
 // does not warrant that the operation of the program will be
 25  
 // uninterrupted or error-free. The end-user understands that the program
 26  
 // was developed for research purposes and is advised not to rely
 27  
 // exclusively on the program for any reason. IN NO EVENT SHALL THE
 28  
 // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
 29  
 // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
 30  
 // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 31  
 // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 32  
 // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
 33  
 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 34  
 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 35  
 // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 36  
 // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
 37  
 // UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 38  
 
 39  
 package org.argouml.profile.internal.ocl;
 40  
 
 41  
 import java.util.ArrayList;
 42  
 import java.util.Collection;
 43  
 import java.util.HashMap;
 44  
 import java.util.HashSet;
 45  
 import java.util.List;
 46  
 import java.util.Map;
 47  
 
 48  
 import org.apache.log4j.Logger;
 49  
 import org.argouml.profile.internal.ocl.uml14.Bag;
 50  
 import org.argouml.profile.internal.ocl.uml14.HashBag;
 51  
 import org.argouml.profile.internal.ocl.uml14.OclEnumLiteral;
 52  
 
 53  
 import tudresden.ocl.parser.analysis.DepthFirstAdapter;
 54  
 import tudresden.ocl.parser.node.AActualParameterList;
 55  
 import tudresden.ocl.parser.node.AAdditiveExpressionTail;
 56  
 import tudresden.ocl.parser.node.AAndLogicalOperator;
 57  
 import tudresden.ocl.parser.node.ABooleanLiteral;
 58  
 import tudresden.ocl.parser.node.ADeclaratorTail;
 59  
 import tudresden.ocl.parser.node.ADivMultiplyOperator;
 60  
 import tudresden.ocl.parser.node.AEmptyFeatureCallParameters;
 61  
 import tudresden.ocl.parser.node.AEnumLiteral;
 62  
 import tudresden.ocl.parser.node.AEqualRelationalOperator;
 63  
 import tudresden.ocl.parser.node.AExpressionListOrRange;
 64  
 import tudresden.ocl.parser.node.AFeatureCall;
 65  
 import tudresden.ocl.parser.node.AFeatureCallParameters;
 66  
 import tudresden.ocl.parser.node.AFeaturePrimaryExpression;
 67  
 import tudresden.ocl.parser.node.AGtRelationalOperator;
 68  
 import tudresden.ocl.parser.node.AGteqRelationalOperator;
 69  
 import tudresden.ocl.parser.node.AIfExpression;
 70  
 import tudresden.ocl.parser.node.AImpliesLogicalOperator;
 71  
 import tudresden.ocl.parser.node.AIntegerLiteral;
 72  
 import tudresden.ocl.parser.node.AIterateDeclarator;
 73  
 import tudresden.ocl.parser.node.ALetExpression;
 74  
 import tudresden.ocl.parser.node.AListExpressionListOrRangeTail;
 75  
 import tudresden.ocl.parser.node.ALiteralCollection;
 76  
 import tudresden.ocl.parser.node.ALogicalExpressionTail;
 77  
 import tudresden.ocl.parser.node.ALtRelationalOperator;
 78  
 import tudresden.ocl.parser.node.ALteqRelationalOperator;
 79  
 import tudresden.ocl.parser.node.AMinusAddOperator;
 80  
 import tudresden.ocl.parser.node.AMinusUnaryOperator;
 81  
 import tudresden.ocl.parser.node.AMultMultiplyOperator;
 82  
 import tudresden.ocl.parser.node.AMultiplicativeExpressionTail;
 83  
 import tudresden.ocl.parser.node.ANEqualRelationalOperator;
 84  
 import tudresden.ocl.parser.node.ANotUnaryOperator;
 85  
 import tudresden.ocl.parser.node.AOrLogicalOperator;
 86  
 import tudresden.ocl.parser.node.APlusAddOperator;
 87  
 import tudresden.ocl.parser.node.APostfixExpressionTail;
 88  
 import tudresden.ocl.parser.node.ARealLiteral;
 89  
 import tudresden.ocl.parser.node.ARelationalExpressionTail;
 90  
 import tudresden.ocl.parser.node.AStandardDeclarator;
 91  
 import tudresden.ocl.parser.node.AStringLiteral;
 92  
 import tudresden.ocl.parser.node.AUnaryUnaryExpression;
 93  
 import tudresden.ocl.parser.node.AXorLogicalOperator;
 94  
 import tudresden.ocl.parser.node.PActualParameterListTail;
 95  
 import tudresden.ocl.parser.node.PDeclaratorTail;
 96  
 import tudresden.ocl.parser.node.PExpression;
 97  
 import tudresden.ocl.parser.node.PExpressionListTail;
 98  
 
 99  
 /**
 100  
  * Evaluates OCL expressions, this class should not depend on the model
 101  
  * subsystem. This adapter assumes the ocl expression is syntatically and
 102  
  * semantically correct.
 103  
  * 
 104  
  * @author maurelio1234
 105  
  */
 106  0
 public class EvaluateExpression extends DepthFirstAdapter {
 107  
 
 108  
     /**
 109  
      * Logger.
 110  
      */
 111  900
     private static final Logger LOG = Logger
 112  
             .getLogger(EvaluateExpression.class);
 113  
 
 114  
     /**
 115  
      * The Variable Table
 116  
      */
 117  93915
     private Map<String, Object> vt = null;
 118  
 
 119  
     /**
 120  
      * Keeps the return value of the visitor
 121  
      */
 122  93915
     private Object val = null;
 123  
 
 124  
     /**
 125  
      * Keeps a forward propagated value
 126  
      */
 127  93915
     private Object fwd = null;
 128  
 
 129  
     /**
 130  
      * The model interpreter
 131  
      */
 132  93915
     private ModelInterpreter interp = null;
 133  
     
 134  
     /**
 135  
      * Constructor
 136  
      * 
 137  
      * @param modelElement self
 138  
      * @param mi model interpreter
 139  
      */
 140  0
     public EvaluateExpression(Object modelElement, ModelInterpreter mi) {
 141  0
         reset(modelElement, mi);
 142  0
     }
 143  
 
 144  
     /**
 145  
      * Constructor
 146  
      * 
 147  
      * @param variableTable the variable table
 148  
      * @param modelInterpreter model interpreter
 149  
      */
 150  
     public EvaluateExpression(Map<String, Object> variableTable, 
 151  93915
             ModelInterpreter modelInterpreter) {
 152  93915
         reset(variableTable, modelInterpreter);
 153  93915
     }
 154  
     
 155  
     /**
 156  
      * Resets the internal state of this adapter
 157  
      * 
 158  
      * @param mi the model interpreter
 159  
      * @param element the model element
 160  
      */
 161  
     public void reset(Object element, ModelInterpreter mi) {        
 162  0
         vt = new HashMap<String, Object>();
 163  0
         vt.put("self", element);
 164  0
         reset(vt, mi);
 165  0
     }
 166  
 
 167  
     /**
 168  
      * @param newVT the variable table
 169  
      * @param mi the model interpreter
 170  
      */
 171  
     public void reset(Map<String, Object> newVT, ModelInterpreter mi) {
 172  93915
         this.interp = mi;
 173  
 
 174  93915
         this.val = null;
 175  93915
         this.fwd = null;
 176  93915
         this.vt = newVT;
 177  93915
     }
 178  
 
 179  
     /**
 180  
      * @return is the invariant ok?
 181  
      */
 182  
     public Object getValue() {
 183  93914
         return val;
 184  
     }
 185  
     
 186  
     /** Interpreter Code * */
 187  
 
 188  
     /*
 189  
      * @see tudresden.ocl.parser.analysis.DepthFirstAdapter#caseAIfExpression(tudresden.ocl.parser.node.AIfExpression)
 190  
      */
 191  
     public void caseAIfExpression(AIfExpression node) {
 192  0
         boolean test = false;
 193  0
         boolean ret = false;
 194  
 
 195  0
         inAIfExpression(node);
 196  0
         if (node.getTIf() != null) {
 197  0
             node.getTIf().apply(this);
 198  
         }
 199  0
         if (node.getIfBranch() != null) {
 200  0
             node.getIfBranch().apply(this);
 201  0
             test = asBoolean(val, node.getIfBranch());
 202  0
             val = null;
 203  
         }
 204  0
         if (node.getTThen() != null) {
 205  0
             node.getTThen().apply(this);
 206  
         }
 207  0
         if (node.getThenBranch() != null) {
 208  0
             node.getThenBranch().apply(this);
 209  0
             if (test) {
 210  0
                 ret = asBoolean(val, node.getThenBranch());
 211  0
                 val = null;
 212  
             }
 213  
         }
 214  0
         if (node.getTElse() != null) {
 215  0
             node.getTElse().apply(this);
 216  
         }
 217  0
         if (node.getElseBranch() != null) {
 218  0
             node.getElseBranch().apply(this);
 219  0
             if (!test) {
 220  0
                 ret = asBoolean(val, node.getThenBranch());
 221  0
                 val = null;
 222  
             }
 223  
         }
 224  0
         if (node.getEndif() != null) {
 225  0
             node.getEndif().apply(this);
 226  
         }
 227  
 
 228  0
         val = ret;
 229  0
         outAIfExpression(node);
 230  0
     }
 231  
 
 232  
     /*
 233  
      * @see tudresden.ocl.parser.analysis.DepthFirstAdapter#caseALogicalExpressionTail(tudresden.ocl.parser.node.ALogicalExpressionTail)
 234  
      */
 235  
     public void caseALogicalExpressionTail(ALogicalExpressionTail node) {
 236  0
         Object left = val;
 237  0
         val = null;
 238  
 
 239  0
         inALogicalExpressionTail(node);
 240  0
         if (node.getLogicalOperator() != null) {
 241  0
             node.getLogicalOperator().apply(this);
 242  
         }
 243  0
         if (node.getRelationalExpression() != null) {
 244  0
             node.getRelationalExpression().apply(this);
 245  
         }
 246  
 
 247  0
         Object op = node.getLogicalOperator();
 248  0
         Object right = val;
 249  0
         val = null;
 250  
 
 251  0
         if (op != null) {
 252  0
             if (op instanceof AAndLogicalOperator) {
 253  0
                 if (left != null && left instanceof Boolean
 254  
                         && !((Boolean) left)) {
 255  0
                     val = false;
 256  0
                 } else if (right != null && right instanceof Boolean
 257  
                         && !((Boolean) right)) {
 258  0
                     val = false;
 259  
                 } else {
 260  0
                     val = asBoolean(left, node) && asBoolean(right, node);
 261  
                 }
 262  0
             } else if (op instanceof AImpliesLogicalOperator) {
 263  0
                 val = !asBoolean(left, node) || asBoolean(right, node);
 264  0
             } else if (op instanceof AOrLogicalOperator) {
 265  0
                 if (left != null && left instanceof Boolean
 266  
                         && ((Boolean) left)) {
 267  0
                     val = true;
 268  0
                 } else if (right != null && right instanceof Boolean
 269  
                         && ((Boolean) right)) {
 270  0
                     val = true;
 271  
                 } else {
 272  0
                     val = asBoolean(left, node) || asBoolean(right, node);
 273  
                 }
 274  0
             } else if (op instanceof AXorLogicalOperator) {
 275  0
                 val = !asBoolean(left, node) ^ asBoolean(right, node);
 276  
             } else {
 277  0
                 error(node);
 278  
             }
 279  
         } else {
 280  0
             error(node);
 281  
         }
 282  0
         outALogicalExpressionTail(node);
 283  0
     }
 284  
 
 285  
     /*
 286  
      * @see tudresden.ocl.parser.analysis.DepthFirstAdapter#caseARelationalExpressionTail(tudresden.ocl.parser.node.ARelationalExpressionTail)
 287  
      */
 288  
     public void caseARelationalExpressionTail(ARelationalExpressionTail node) {
 289  0
         Object left = val;
 290  0
         val = null;
 291  
 
 292  0
         inARelationalExpressionTail(node);
 293  0
         if (node.getRelationalOperator() != null) {
 294  0
             node.getRelationalOperator().apply(this);
 295  
         }
 296  0
         if (node.getAdditiveExpression() != null) {
 297  0
             node.getAdditiveExpression().apply(this);
 298  
         }
 299  
 
 300  0
         Object op = node.getRelationalOperator();
 301  0
         Object right = val;
 302  0
         val = null;
 303  
 
 304  0
         if (left != null && op != null && right != null) {
 305  0
             if (op instanceof AEqualRelationalOperator) {
 306  0
                 val = left.equals(right);
 307  0
             } else if (op instanceof AGteqRelationalOperator) {
 308  0
                 val = asInteger(left, node) >= asInteger(right, node);
 309  0
             } else if (op instanceof AGtRelationalOperator) {
 310  0
                 val = asInteger(left, node) > asInteger(right, node);
 311  0
             } else if (op instanceof ALteqRelationalOperator) {
 312  0
                 val = asInteger(left, node) <= asInteger(right, node);
 313  0
             } else if (op instanceof ALtRelationalOperator) {
 314  0
                 val = asInteger(left, node) < asInteger(right, node);
 315  0
             } else if (op instanceof ANEqualRelationalOperator) {
 316  0
                 val = !left.equals(right);
 317  
             } else {
 318  0
                 error(node);
 319  
             }
 320  
         } else {
 321  
             // if one side is null, compare with the equality operator 
 322  0
             if (op instanceof AEqualRelationalOperator) {
 323  0
                 val = (left == right);
 324  0
             } else if (op instanceof ANEqualRelationalOperator) {
 325  0
                 val = (left != right);
 326  
             } else {
 327  0
                 error(node);
 328  0
                 val = null;
 329  
             }
 330  
         }
 331  0
         outARelationalExpressionTail(node);
 332  0
     }
 333  
 
 334  
     /*
 335  
      * @see tudresden.ocl.parser.analysis.DepthFirstAdapter#caseAAdditiveExpressionTail(tudresden.ocl.parser.node.AAdditiveExpressionTail)
 336  
      */
 337  
     @Override
 338  
     public void caseAAdditiveExpressionTail(AAdditiveExpressionTail node) {
 339  0
         Object left = val;
 340  0
         val = null;
 341  
 
 342  0
         inAAdditiveExpressionTail(node);
 343  0
         if (node.getAddOperator() != null) {
 344  0
             node.getAddOperator().apply(this);
 345  
         }
 346  0
         if (node.getMultiplicativeExpression() != null) {
 347  0
             node.getMultiplicativeExpression().apply(this);
 348  
         }
 349  
 
 350  0
         Object op = node.getAddOperator();
 351  0
         Object right = val;
 352  0
         val = null;
 353  
 
 354  0
         if (left != null && op != null && right != null) {
 355  0
             if (op instanceof AMinusAddOperator) {
 356  0
                 val = asInteger(left, node) - asInteger(right, node);
 357  0
             } else if (op instanceof APlusAddOperator) {
 358  0
                 val = asInteger(left, node) + asInteger(right, node);
 359  
             } else {
 360  0
                 error(node);
 361  
             }
 362  
         } else {
 363  0
             error(node);
 364  
         }
 365  
 
 366  0
         outAAdditiveExpressionTail(node);
 367  0
     }
 368  
 
 369  
     /*
 370  
      * @see tudresden.ocl.parser.analysis.DepthFirstAdapter#caseAMultiplicativeExpressionTail(tudresden.ocl.parser.node.AMultiplicativeExpressionTail)
 371  
      */
 372  
     public void caseAMultiplicativeExpressionTail(
 373  
             AMultiplicativeExpressionTail node) {
 374  0
         Object left = val;
 375  0
         val = null;
 376  
 
 377  0
         inAMultiplicativeExpressionTail(node);
 378  0
         if (node.getMultiplyOperator() != null) {
 379  0
             node.getMultiplyOperator().apply(this);
 380  
         }
 381  0
         if (node.getUnaryExpression() != null) {
 382  0
             node.getUnaryExpression().apply(this);
 383  
         }
 384  
 
 385  0
         Object op = node.getMultiplyOperator();
 386  0
         Object right = val;
 387  0
         val = null;
 388  
 
 389  0
         if (left != null && op != null && right != null) {
 390  0
             if (op instanceof ADivMultiplyOperator) {
 391  0
                 val = asInteger(left, node) / asInteger(right, node);
 392  0
             } else if (op instanceof AMultMultiplyOperator) {
 393  0
                 val = asInteger(left, node) * asInteger(right, node);
 394  
             } else {
 395  0
                 error(node);
 396  
             }
 397  
         } else {
 398  0
             error(node);
 399  
         }
 400  
 
 401  0
         outAMultiplicativeExpressionTail(node);
 402  0
     }
 403  
 
 404  
     /*
 405  
      * @see tudresden.ocl.parser.analysis.DepthFirstAdapter#caseAUnaryUnaryExpression(tudresden.ocl.parser.node.AUnaryUnaryExpression)
 406  
      */
 407  
     public void caseAUnaryUnaryExpression(AUnaryUnaryExpression node) {
 408  0
         inAUnaryUnaryExpression(node);
 409  0
         if (node.getUnaryOperator() != null) {
 410  0
             node.getUnaryOperator().apply(this);
 411  
         }
 412  0
         if (node.getPostfixExpression() != null) {
 413  0
             val = null;
 414  0
             node.getPostfixExpression().apply(this);
 415  
         }
 416  
 
 417  0
         Object op = node.getUnaryOperator();
 418  0
         if (op instanceof AMinusUnaryOperator) {
 419  0
             val = -asInteger(val, node);
 420  0
         } else if (op instanceof ANotUnaryOperator) {
 421  0
             val = !asBoolean(val, node);
 422  
         }
 423  
 
 424  0
         outAUnaryUnaryExpression(node);
 425  0
     }
 426  
 
 427  
     /*
 428  
      * @see tudresden.ocl.parser.analysis.DepthFirstAdapter#caseAPostfixExpressionTail(tudresden.ocl.parser.node.APostfixExpressionTail)
 429  
      */
 430  
     public void caseAPostfixExpressionTail(APostfixExpressionTail node) {
 431  93915
         inAPostfixExpressionTail(node);
 432  93915
         if (node.getPostfixExpressionTailBegin() != null) {
 433  93915
             node.getPostfixExpressionTailBegin().apply(this);
 434  
         }
 435  93915
         if (node.getFeatureCall() != null) {
 436  93915
             fwd = node.getPostfixExpressionTailBegin();
 437  93915
             node.getFeatureCall().apply(this);
 438  
 
 439  
             // XXX: hypotheses for AFeatureCall: fwd = op, val = head
 440  
         }
 441  93914
         outAPostfixExpressionTail(node);
 442  93914
     }
 443  
 
 444  
     /*
 445  
      * @see tudresden.ocl.parser.analysis.DepthFirstAdapter#caseAFeaturePrimaryExpression(tudresden.ocl.parser.node.AFeaturePrimaryExpression)
 446  
      */
 447  
     @Override
 448  
     public void caseAFeaturePrimaryExpression(AFeaturePrimaryExpression node) {
 449  93915
         Object subject = val;
 450  93915
         Object feature = null;
 451  93915
         List parameters = null;
 452  
 
 453  93915
         inAFeaturePrimaryExpression(node);
 454  93915
         if (node.getPathName() != null) {
 455  
             // TODO support other name kinds
 456  93915
             node.getPathName().apply(this);
 457  93915
             feature = node.getPathName().toString().trim();
 458  
         }
 459  93915
         if (node.getTimeExpression() != null) {
 460  
             // hypotheses no time expression (only invariants)
 461  0
             node.getTimeExpression().apply(this);
 462  
         }
 463  93915
         if (node.getQualifiers() != null) {
 464  
             // XXX: hypotheses no qualifiers (I don't know)
 465  0
             node.getQualifiers().apply(this);
 466  
         }
 467  93915
         if (node.getFeatureCallParameters() != null) {
 468  0
             val = null;
 469  0
             node.getFeatureCallParameters().apply(this);
 470  0
             parameters = (List) val;
 471  
         }
 472  
 
 473  93915
         if (subject == null) {
 474  93915
             val = vt.get(feature);
 475  93915
             if (val == null) {
 476  0
                 val = this.interp.getBuiltInSymbol(feature.toString().trim());
 477  
             }
 478  
         } else {
 479  0
             val = runFeatureCall(subject, feature, fwd, parameters);
 480  
         }
 481  93915
         outAFeaturePrimaryExpression(node);
 482  93915
     }
 483  
 
 484  
     /*
 485  
      * @see tudresden.ocl.parser.analysis.DepthFirstAdapter#outAEmptyFeatureCallParameters(tudresden.ocl.parser.node.AEmptyFeatureCallParameters)
 486  
      */
 487  
     @Override
 488  
     public void outAEmptyFeatureCallParameters(AEmptyFeatureCallParameters node)
 489  
     {
 490  0
         val = new ArrayList();
 491  0
         defaultOut(node);
 492  0
     }
 493  
 
 494  
     /*
 495  
      * @see tudresden.ocl.parser.analysis.DepthFirstAdapter#caseAFeatureCallParameters(tudresden.ocl.parser.node.AFeatureCallParameters)
 496  
      */
 497  
     @SuppressWarnings("unchecked")
 498  
     @Override
 499  
     public void caseAFeatureCallParameters(AFeatureCallParameters node) {
 500  0
         inAFeatureCallParameters(node);
 501  0
         if (node.getLPar() != null) {
 502  0
             node.getLPar().apply(this);
 503  
         }
 504  
 
 505  0
         boolean hasDeclarator = false;
 506  0
         if (node.getDeclarator() != null) {
 507  0
             node.getDeclarator().apply(this);
 508  0
             hasDeclarator = true;
 509  
         }
 510  0
         if (node.getActualParameterList() != null) {
 511  0
             List<String> vars = null;
 512  0
             if (hasDeclarator) {
 513  0
                 List ret = new ArrayList();
 514  0
                 vars = (List) val;
 515  0
                 final PExpression exp = ((AActualParameterList) node
 516  
                         .getActualParameterList()).getExpression();
 517  
 
 518  
                 /*
 519  
                  * For a iterator call we should provide: (a) the variables (b)
 520  
                  * the expression to be evaluated on each step (c) the
 521  
                  * lambda-evaluator to evaluate it
 522  
                  */
 523  
 
 524  0
                 ret.add(vars);
 525  0
                 ret.add(exp);
 526  0
                 ret.add(new LambdaEvaluator() {
 527  
 
 528  
                     /**
 529  
                      * @see org.argouml.profile.internal.ocl.LambdaEvaluator#evaluate(java.util.Map,
 530  
                      *      java.lang.Object)
 531  
                      */
 532  
                     public Object evaluate(Map<String, Object> vti,
 533  
                             Object expi) {
 534  
                         
 535  0
                         Object state = EvaluateExpression.this.saveState();
 536  
 
 537  0
                         EvaluateExpression.this.vt = vti;
 538  0
                         EvaluateExpression.this.val = null;
 539  0
                         EvaluateExpression.this.fwd = null;
 540  
                         
 541  0
                         ((PExpression) expi).apply(EvaluateExpression.this);
 542  
 
 543  0
                         Object reti = EvaluateExpression.this.val;
 544  0
                         EvaluateExpression.this.loadState(state);
 545  0
                         return reti;
 546  
                     }
 547  
 
 548  
                 });
 549  
 
 550  0
                 val = ret;
 551  0
             } else {
 552  0
                 node.getActualParameterList().apply(this);
 553  
             }
 554  
 
 555  
         }
 556  0
         if (node.getRPar() != null) {
 557  0
             node.getRPar().apply(this);
 558  
         }
 559  0
         outAFeatureCallParameters(node);
 560  0
     }
 561  
     
 562  
     @SuppressWarnings("unchecked")
 563  
     private void loadState(Object state) {
 564  0
         Object[] stateArr = (Object[]) state;
 565  0
         this.vt = (Map<String, Object>) stateArr[0];
 566  0
         this.val = stateArr[1];
 567  0
         this.fwd = stateArr[2];
 568  0
     }
 569  
 
 570  
     private Object saveState() {
 571  0
         return new Object[] {vt, val, fwd};
 572  
     }
 573  
 
 574  
     /*
 575  
      * @param node
 576  
      * @see tudresden.ocl.parser.analysis.DepthFirstAdapter#caseAStandardDeclarator(tudresden.ocl.parser.node.AStandardDeclarator)
 577  
      */
 578  
     @Override
 579  
     public void caseAStandardDeclarator(AStandardDeclarator node) {
 580  0
         inAStandardDeclarator(node);
 581  
 
 582  0
         List<String> vars = new ArrayList<String>();
 583  
 
 584  0
         if (node.getName() != null) {
 585  0
             node.getName().apply(this);
 586  
 
 587  0
             vars.add(node.getName().toString().trim());
 588  
         }
 589  
         {
 590  0
             Object temp[] = node.getDeclaratorTail().toArray();
 591  0
             for (int i = 0; i < temp.length; i++) {
 592  0
                 ((PDeclaratorTail) temp[i]).apply(this);
 593  
 
 594  0
                 vars.add(((ADeclaratorTail) temp[i]).getName()
 595  
                         .toString().trim());
 596  
             }
 597  
 
 598  0
             val = vars;
 599  
         }
 600  0
         if (node.getDeclaratorTypeDeclaration() != null) {
 601  
             // TODO check types!
 602  0
             node.getDeclaratorTypeDeclaration().apply(this);
 603  
         }
 604  0
         if (node.getBar() != null) {
 605  0
             node.getBar().apply(this);
 606  
         }
 607  0
         outAStandardDeclarator(node);
 608  0
     }
 609  
 
 610  
     @Override
 611  
     public void outAIterateDeclarator(AIterateDeclarator node) {
 612  
         // TODO support iterate declarator
 613  0
         val = new ArrayList<String>();
 614  0
         defaultOut(node);
 615  0
     }
 616  
 
 617  
     /*
 618  
      * @see tudresden.ocl.parser.analysis.DepthFirstAdapter#caseALetExpression(tudresden.ocl.parser.node.ALetExpression)
 619  
      */
 620  
     @Override
 621  
     public void caseALetExpression(ALetExpression node) {
 622  
         // TODO support nested let expressions !
 623  
 
 624  0
         Object name = null;
 625  0
         Object value = null;
 626  
 
 627  0
         inALetExpression(node);
 628  0
         if (node.getTLet() != null) {
 629  0
             node.getTLet().apply(this);
 630  
         }
 631  0
         if (node.getName() != null) {
 632  0
             node.getName().apply(this);
 633  0
             name = node.getName().toString().trim();
 634  
         }
 635  0
         if (node.getLetExpressionTypeDeclaration() != null) {
 636  
             // TODO: check type!
 637  0
             node.getLetExpressionTypeDeclaration().apply(this);
 638  
         }
 639  0
         if (node.getEqual() != null) {
 640  0
             node.getEqual().apply(this);
 641  
         }
 642  0
         if (node.getExpression() != null) {
 643  0
             node.getExpression().apply(this);
 644  0
             value = val;
 645  
         }
 646  0
         if (node.getTIn() != null) {
 647  0
             node.getTIn().apply(this);
 648  
         }
 649  
 
 650  0
         vt.put(("" + name).trim(), value);
 651  0
         val = null;
 652  0
         outALetExpression(node);
 653  0
     }
 654  
 
 655  
     /*
 656  
      * @see tudresden.ocl.parser.analysis.DepthFirstAdapter#outAStringLiteral(tudresden.ocl.parser.node.AStringLiteral)
 657  
      */
 658  
     public void outAStringLiteral(AStringLiteral node) {
 659  0
         String text = node.getStringLit().getText();
 660  0
         val = text.substring(1, text.length() - 1); 
 661  0
         defaultOut(node);
 662  0
     }
 663  
 
 664  
     /*
 665  
      * @see tudresden.ocl.parser.analysis.DepthFirstAdapter#outARealLiteral(tudresden.ocl.parser.node.ARealLiteral)
 666  
      */
 667  
     public void outARealLiteral(ARealLiteral node) {
 668  
         // TODO support real types
 669  0
         val = (int) Double.parseDouble(node.getReal().getText());
 670  0
         defaultOut(node);
 671  0
     }
 672  
 
 673  
     /*
 674  
      * @see tudresden.ocl.parser.analysis.DepthFirstAdapter#outAIntegerLiteral(tudresden.ocl.parser.node.AIntegerLiteral)
 675  
      */
 676  
     public void outAIntegerLiteral(AIntegerLiteral node) {
 677  0
         val = Integer.parseInt(node.getInt().getText());
 678  0
         defaultOut(node);
 679  0
     }
 680  
 
 681  
     /*
 682  
      * @see tudresden.ocl.parser.analysis.DepthFirstAdapter#outABooleanLiteral(tudresden.ocl.parser.node.ABooleanLiteral)
 683  
      */
 684  
     public void outABooleanLiteral(ABooleanLiteral node) {
 685  0
         val = Boolean.parseBoolean(node.getBool().getText());
 686  0
         defaultOut(node);
 687  0
     }
 688  
 
 689  
     /*
 690  
      * @see tudresden.ocl.parser.analysis.DepthFirstAdapter#outAEnumLiteral(tudresden.ocl.parser.node.AEnumLiteral)
 691  
      */
 692  
     public void outAEnumLiteral(AEnumLiteral node) {
 693  0
         val = new OclEnumLiteral(node.getName().toString().trim());
 694  0
         defaultOut(node);
 695  0
     }
 696  
     
 697  
     /*
 698  
      * @see tudresden.ocl.parser.analysis.DepthFirstAdapter#caseALiteralCollection(tudresden.ocl.parser.node.ALiteralCollection)
 699  
      */
 700  
     @SuppressWarnings("unchecked")
 701  
     public void caseALiteralCollection(ALiteralCollection node)
 702  
     {
 703  0
         Collection<Object> col = null;
 704  
         
 705  0
         inALiteralCollection(node);
 706  0
         if (node.getCollectionKind() != null)
 707  
         {
 708  0
             node.getCollectionKind().apply(this);
 709  
             
 710  0
             String kind = node.getCollectionKind().toString().trim();
 711  0
             if (kind.equalsIgnoreCase("Set")) {
 712  0
                 col = new HashSet<Object>();
 713  0
             } else if (kind.equalsIgnoreCase("Sequence")) {
 714  0
                 col = new ArrayList<Object>();
 715  0
             } else if (kind.equalsIgnoreCase("Bag")) {
 716  0
                 col = new HashBag<Object>();                
 717  
             }
 718  
         }        
 719  0
         if (node.getLBrace() != null) {
 720  0
             node.getLBrace().apply(this);
 721  
         }
 722  0
         if (node.getExpressionListOrRange() != null) {
 723  0
             val = null;
 724  0
             node.getExpressionListOrRange().apply(this);
 725  0
             col.addAll((Collection<Object>) val);
 726  
         }
 727  0
         if (node.getRBrace() != null) {
 728  0
             node.getRBrace().apply(this);
 729  
         }
 730  0
         val = col;
 731  0
         outALiteralCollection(node);
 732  0
     }
 733  
 
 734  
     /*
 735  
      * @see tudresden.ocl.parser.analysis.DepthFirstAdapter#caseAExpressionListOrRange(tudresden.ocl.parser.node.AExpressionListOrRange)
 736  
      */
 737  
     @Override
 738  
     public void caseAExpressionListOrRange(AExpressionListOrRange node)
 739  
     {
 740  0
         List ret = new ArrayList();
 741  0
         inAExpressionListOrRange(node);
 742  0
         if (node.getExpression() != null) {
 743  0
             val = null;
 744  0
             node.getExpression().apply(this);
 745  0
             ret.add(val);
 746  
         }
 747  0
         if (node.getExpressionListOrRangeTail() != null) {
 748  0
             val = null;
 749  0
             node.getExpressionListOrRangeTail().apply(this);
 750  0
             ret.addAll((Collection) val);
 751  
         }
 752  0
         val = ret;
 753  0
         outAExpressionListOrRange(node);
 754  0
     }
 755  
 
 756  
     /*
 757  
      * @see tudresden.ocl.parser.analysis.DepthFirstAdapter#caseAListExpressionListOrRangeTail(tudresden.ocl.parser.node.AListExpressionListOrRangeTail)
 758  
      */
 759  
     @Override
 760  
     public void caseAListExpressionListOrRangeTail(
 761  
             AListExpressionListOrRangeTail node)
 762  
     {
 763  
         // TODO support other kinds of tail
 764  0
         inAListExpressionListOrRangeTail(node);
 765  
         {
 766  0
             List ret = new ArrayList();
 767  0
             Object temp[] = node.getExpressionListTail().toArray();
 768  0
             for (int i = 0; i < temp.length; i++) {
 769  0
                 val = null;
 770  0
                 ((PExpressionListTail) temp[i]).apply(this);
 771  0
                 ret.add(val);
 772  
             }
 773  0
             val = ret;
 774  
         }
 775  0
         outAListExpressionListOrRangeTail(node);
 776  0
     }
 777  
     
 778  
     /*
 779  
      * @see tudresden.ocl.parser.analysis.DepthFirstAdapter#caseAFeatureCall(tudresden.ocl.parser.node.AFeatureCall)
 780  
      */
 781  
     @Override
 782  
     public void caseAFeatureCall(AFeatureCall node) {
 783  93915
         Object subject = val;
 784  93915
         Object feature = null;
 785  93915
         Object type = fwd;
 786  93915
         List parameters = null;
 787  
 
 788  93915
         inAFeatureCall(node);
 789  93915
         if (node.getPathName() != null) {
 790  
             // TODO support other name kinds
 791  93915
             node.getPathName().apply(this);
 792  
 
 793  93915
             feature = node.getPathName().toString().trim();
 794  
         }
 795  93915
         if (node.getTimeExpression() != null) {
 796  
             // XXX hypothesis: no time expression (inv)
 797  0
             node.getTimeExpression().apply(this);
 798  
         }
 799  93915
         if (node.getQualifiers() != null) {
 800  
             // TODO understand qualifiers
 801  0
             node.getQualifiers().apply(this);
 802  
         }
 803  93915
         if (node.getFeatureCallParameters() != null) {
 804  0
             val = null;
 805  0
             node.getFeatureCallParameters().apply(this);
 806  
 
 807  0
             parameters = (List) val;
 808  
         } else {
 809  93915
             parameters = new ArrayList();
 810  
         }
 811  
 
 812  93915
         val = runFeatureCall(subject, feature, type, parameters);
 813  93914
         outAFeatureCall(node);
 814  93914
     }
 815  
 
 816  
     @Override
 817  
     public void caseAActualParameterList(AActualParameterList node) {
 818  0
         List list = new ArrayList();
 819  0
         inAActualParameterList(node);
 820  0
         if (node.getExpression() != null) {
 821  0
             val = null;
 822  0
             node.getExpression().apply(this);
 823  0
             list.add(val);
 824  
         }
 825  
         { // TODO: why is this inside a block? Forgotten else branch?!?
 826  
             // Question by euluis @ 2009-08-16.
 827  0
             Object temp[] = node.getActualParameterListTail().toArray();
 828  0
             for (int i = 0; i < temp.length; i++) {
 829  0
                 val = null;
 830  0
                 ((PActualParameterListTail) temp[i]).apply(this);
 831  0
                 list.add(val);
 832  
             }
 833  
         }
 834  
 
 835  0
         val = list;
 836  0
         outAActualParameterList(node);
 837  0
     }
 838  
 
 839  
     /** HELPER METHODS * */
 840  
     private boolean asBoolean(Object value, Object node) {
 841  0
         if (value instanceof Boolean) {
 842  0
             return (Boolean) value;
 843  
         } else {
 844  0
             errorNotType(node, "Boolean", false);
 845  0
             return false;
 846  
         }
 847  
     }
 848  
 
 849  
     private int asInteger(Object value, Object node) {
 850  0
         if (value instanceof Integer) {
 851  0
             return (Integer) value;
 852  
         } else {
 853  0
             errorNotType(node, "integer", 0);
 854  0
             return 0;
 855  
         }
 856  
     }
 857  
 
 858  
     private Object runFeatureCall(Object subject, Object feature, Object type,
 859  
             List parameters) {
 860  
         // LOG.debug("OCL FEATURE CALL: " + subject + ""+ type +""+ feature + ""
 861  
         // + parameters);
 862  
 
 863  93915
         if (parameters == null) {
 864  0
             parameters = new ArrayList<Object>();
 865  
         }
 866  
 
 867  
         // XXX this should be done in CollectionsModelInterpreter
 868  
         // but it can't trigger another invokeFeature...
 869  
         
 870  93915
         if ((subject instanceof Collection)
 871  
                 && type.toString().trim().equals(".")) {
 872  0
             Collection col = (Collection) subject;
 873  0
             Bag res = new HashBag();
 874  0
             for (Object obj : col) {
 875  0
                 res.add(interp.invokeFeature(vt, obj,
 876  
                         feature.toString().trim(), ".", parameters.toArray()));
 877  
             }
 878  0
             return res;
 879  
         } else {
 880  93915
             return interp.invokeFeature(vt, subject, feature.toString().trim(),
 881  
                     type.toString().trim(), parameters.toArray());
 882  
         }
 883  
     }
 884  
 
 885  
     /** Error Handling * */
 886  
     private void errorNotType(Object node, String type, Object dft) {
 887  0
         LOG.error("OCL does not evaluate to a " + type + " expression!! Exp: "
 888  
                 + node + " Val: " + val);
 889  0
         val = dft;
 890  
         // TODO: We need a specific exception type here.
 891  0
         throw new RuntimeException();
 892  
     }
 893  
 
 894  
     private void error(Object node) {
 895  0
         LOG.error("Unknown error processing OCL exp!! Exp: " + node + " Val: "
 896  
                 + val);
 897  0
         val = null;
 898  
         // TODO: We need a specific exception type here.
 899  0
         throw new RuntimeException();
 900  
     }
 901  
 
 902  
 }