📄 expstdop.java
字号:
/* * USE - UML based specification environment * Copyright (C) 1999-2004 Mark Richters, University of Bremen * * 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 2 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, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* $ProjectHeader: use 2-3-0-release.1 Mon, 12 Sep 2005 20:18:33 +0200 green $ */package org.tzi.use.uml.ocl.expr;import java.util.Iterator;import java.util.List;import org.tzi.use.uml.ocl.type.*;import org.tzi.use.uml.ocl.value.*;import org.tzi.use.uml.sys.MObject;import org.tzi.use.uml.sys.MObjectState;import org.tzi.use.util.HashMultiMap;import org.tzi.use.util.MultiMap;import org.tzi.use.util.StringUtil;/** * OpGeneric is the base class of a large group of individual * operations. Each operation is implemented by its own class deriving * from OpGeneric. New Operations can easily be added by writing a new * operation class and adding a single instance of the new class to * the static list of operations in Class ExpOperation (see * below). Also, this way the new operation symbol is immediately * available to the specification compiler. * * @version $ProjectVersion: 2-3-0-release.1 $ * @author Mark Richters */abstract class OpGeneric { // These constants define different groups of operations. The // groups mainly differ wrt their behavior in case of undefined // arguments. The effects of passing any undefined argument to an // operation are as follows: // // OPERATION -> UndefinedValue(T) with T being the result type // of the operation // PREDICATE -> BooleanValue(false) // SPECIAL -> operation needs special treatment of undefined arguments public static final int OPERATION = 0; public static final int PREDICATE = 1; public static final int SPECIAL = 3; abstract String name(); abstract int kind(); abstract boolean isInfixOrPrefix(); abstract Type matches(Type params[]); abstract Value eval(EvalContext ctx, Value args[], Type resultType); public String stringRep(Expression args[], String atPre) { String res; if (isInfixOrPrefix() ) { if (args.length == 1 ) { // e.g. `not true', -2, +3 // insert blank between operator and expression to // avoid `--' which would be interpreted as comment res = name() + " " + args[0]; } else // e.g. `3 + 4' res = "(" + StringUtil.fmtSeq(args, " " + name() + " ") + ")"; } else { // translate into dot notation, e.g. foo->union(bla) res = name() + atPre; if (args.length > 0 ) { if (args[0].type().isCollection() ) res = args[0] + "->" + res; else res = args[0] + "." + res; if (args.length > 1 ) res += "(" + StringUtil.fmtSeq(args, 1, ",") + ")"; } } return res; }}/** * General operation expressions. Each operation is implemented by * its own class. New Operations are easily introduced by writing a * new operation class and adding a single instance of the new class * to the list of operations (see below). Also, this way the new * operation symbol is already known to the specification compiler. * * @version $ProjectVersion: 2-3-0-release.1 $ * @author Mark Richters */public final class ExpStdOp extends Expression { private static final OpGeneric oplist[] = { // operations on Integer and Real new Op_number_add(), new Op_number_sub(), new Op_number_mult(), new Op_number_div(), new Op_number_unaryminus(), new Op_number_unaryplus(), new Op_integer_abs(), new Op_real_abs(), new Op_real_floor(), new Op_real_round(), new Op_number_max(), new Op_number_min(), new Op_integer_mod(), new Op_integer_idiv(), new Op_number_less(), new Op_number_greater(), new Op_number_lessequal(), new Op_number_greaterequal(), // operations on String new Op_string_size(), new Op_string_concat(), new Op_string_toUpper(), new Op_string_toLower(), new Op_string_substring(), new Op_string_less(), // OCL extension! new Op_string_greater(), // OCL extension! new Op_string_lessequal(), // OCL extension! new Op_string_greaterequal(), // OCL extension! // operations on Boolean new Op_boolean_or(), new Op_boolean_xor(), new Op_boolean_and(), new Op_boolean_not(), new Op_boolean_implies(), // operations on enumeration types // operations on Collection new Op_collection_size(), new Op_collection_includes(), new Op_collection_excludes(), new Op_collection_count(), new Op_collection_includesAll(), new Op_collection_excludesAll(), new Op_collection_isEmpty(), new Op_collection_notEmpty(), new Op_collection_sum(), // the following are special expressions: // exists // forall // isUnique // sortedBy // iterate new Op_collection_flatten(), // USE specific // operations on Set new Op_set_union(), new Op_set_union_bag(), new Op_set_intersection(), new Op_set_intersection_bag(), new Op_set_difference(), new Op_set_including(), new Op_set_excluding(), new Op_set_symmetricDifference(), // the following three are special expressions: // select // reject // collect // count: inherited from Collection new Op_set_asSequence(), // non-deterministic! new Op_set_asBag(), // operations on Bag new Op_bag_union(), new Op_bag_union_set(), new Op_bag_intersection(), new Op_bag_intersection_set(), new Op_bag_including(), new Op_bag_excluding(), // the following three are special expressions: // select // reject // collect // count: inherited from Collection new Op_bag_asSequence(), // non-deterministic! new Op_bag_asSet(), // operations on Sequence // count: inherited from Collection new Op_sequence_union(), new Op_sequence_append(), new Op_sequence_prepend(), new Op_sequence_subSequence(), new Op_sequence_at(), new Op_sequence_first(), new Op_sequence_last(), new Op_sequence_including(), new Op_sequence_excluding(), new Op_sequence_asBag(), new Op_sequence_asSet(), // creation operations for collections new Op_mkSet(), new Op_mkSetRange(), new Op_mkSequence(), new Op_mkSequenceRange(), new Op_mkBag(), new Op_mkBagRange(), // generic operations on all types new Op_equal(), new Op_notequal(), new Op_isDefined(), new Op_isUndefined(), // generic operations on all object types new Op_oclIsNew(), }; // (String -> OpGeneric): opname/possible (overloaded) operations) private static MultiMap opmap; // initialize operation map static { opmap = new HashMultiMap(); for (int i = 0; i < oplist.length; i++) opmap.put(oplist[i].name(), oplist[i]); } /** * Returns true if a standard operation exists matching name and * params. */ public static boolean exists(String name, Type params[]) { if (params.length == 0 ) throw new IllegalArgumentException( "ExpStdOp.exists called with empty params array"); // search by operation symbol List ops = opmap.get(name); if (ops.isEmpty() ) // unknown operation symbol return false; // search overloaded operations for a match Iterator opIter = ops.iterator(); while (opIter.hasNext() ) { OpGeneric op = (OpGeneric) opIter.next(); Type t = op.matches(params); if (t != null ) return true; } return false; } /** * Try to create a new instance of ExpOperation. * * @exception ExpInvalidException cannot find a match for operation */ public static ExpStdOp create(String name, Expression args[]) throws ExpInvalidException { if (args.length == 0 ) throw new IllegalArgumentException( "ExpOperation.create called with " + "empty args array"); // search by operation symbol List ops = opmap.get(name); if (ops.isEmpty() ) // unknown operation symbol throw new ExpInvalidException("Undefined operation named `" + name + "' in expression `" + opCallSignature(name, args) + "'."); Type[] params = new Type[args.length]; for (int i = 0; i < args.length; i++) params[i] = args[i].type(); // search overloaded operations for a match Iterator opIter = ops.iterator(); while (opIter.hasNext() ) { OpGeneric op = (OpGeneric) opIter.next(); Type t = op.matches(params); if (t != null ) return new ExpStdOp(op, args, t); } // operation name matches but arguments don't throw new ExpInvalidException("Undefined operation `" + opCallSignature(name, args) + "'."); } private static String opCallSignature(String name, Expression args[]) { // build error message with type names of arguments Type srcType = args[0].type(); StringBuffer s = new StringBuffer(srcType + ( srcType.isCollection() ? "->" : ".") + name + "("); for (int i = 1; i < args.length; i++) { if (i > 1 ) s.append(", "); s.append(args[i].type()); } s.append(")"); return s.toString(); } // instance variables private OpGeneric fOp; private Expression fArgs[]; private ExpStdOp(OpGeneric op, Expression args[], Type t) { super(t); fOp = op; fArgs = args; } public String toString() { return fOp.stringRep(fArgs, atPre()); } public String opname() { return fOp.name(); } public Expression[] args() { return fArgs; } /** * Evaluates the expression and returns a result value. */ public Value eval(EvalContext ctx) { ctx.enter(this); Value res = null; // Boolean operations need special treatment of undefined // arguments. Also, short-circuit evaluation may be used to // speed up the evaluation process. if (fOp instanceof BooleanOperation ) { res = ((BooleanOperation) fOp).evalWithArgs(ctx, fArgs); } else { Value argValues[] = new Value[fArgs.length]; int opKind = fOp.kind(); for (int i = 0; i < fArgs.length && res == null; i++) { argValues[i] = fArgs[i].eval(ctx); // if any of the arguments is undefined, the result // depends on the kind of operation we are about to // call. if (argValues[i].isUndefined() ) { switch ( opKind ) { case OpGeneric.OPERATION: // strict evaluation, result is undefined, no // need to call the operation's eval() method. res = new UndefinedValue(type()); break; case OpGeneric.PREDICATE: // predicates are by default false when passed // an undefined argument res = BooleanValue.FALSE; break; case OpGeneric.SPECIAL: // these operations handle undefined arguments // themselves break; default: throw new RuntimeException("Unexpected operation kind: " + opKind); } } } if (res == null ) { try { res = fOp.eval(ctx, argValues, type()); } catch (ArithmeticException ex) { // catch e.g. division by zero res = new UndefinedValue(type()); } } } ctx.exit(this, res);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -