001/* A visitor for parse trees of the expression language. 002 003 Copyright (c) 1998-2014 The Regents of the University of California 004 All rights reserved. 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the above 008 copyright notice and the following two paragraphs appear in all copies 009 of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA OR RESEARCH IN MOTION 012 LIMITED BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, 013 INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS 014 SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA 015 OR RESEARCH IN MOTION LIMITED HAVE BEEN ADVISED OF THE POSSIBILITY OF 016 SUCH DAMAGE. 017 018 THE UNIVERSITY OF CALIFORNIA AND RESEARCH IN MOTION LIMITED 019 SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 020 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 021 PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" 022 BASIS, AND THE UNIVERSITY OF CALIFORNIA AND RESEARCH IN MOTION 023 LIMITED HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 024 ENHANCEMENTS, OR MODIFICATIONS. 025 026 027 */ 028package ptolemy.data.expr; 029 030import java.util.ArrayList; 031import java.util.HashMap; 032import java.util.List; 033import java.util.Map; 034 035import ptolemy.data.Function; 036import ptolemy.data.type.BaseType; 037import ptolemy.data.type.Type; 038import ptolemy.kernel.util.IllegalActionException; 039 040/////////////////////////////////////////////////////////////////// 041//// ExpressionFunction 042 043/** 044 An implementation of a function closure that encapsulates an 045 expression tree. Instances of this class are created during the 046 evaluation of function closure expressions in the expression language, 047 like "function(x:int, y:int) x+y". 048 049 @author Steve Neuendorffer, Xiaojun Liu 050 @version $Id$ 051 @since Ptolemy II 2.1 052 @Pt.ProposedRating Yellow (neuendor) 053 @Pt.AcceptedRating Red (neuendor) 054 @see ptolemy.data.expr.ASTPtRootNode 055 */ 056public class ExpressionFunction implements Function { 057 /** Construct a function closure that encapsulates an expression tree. 058 * @param argumentNames The names of the arguments. 059 * @param argumentTypes The types of the arguments. 060 * @param exprRoot The Expression tree that describes the function. 061 */ 062 public ExpressionFunction(List argumentNames, Type[] argumentTypes, 063 ASTPtRootNode exprRoot) { 064 _argumentNames = new ArrayList(argumentNames); 065 _argumentTypes = argumentTypes; 066 _exprRoot = exprRoot; 067 } 068 069 /////////////////////////////////////////////////////////////////// 070 //// public methods //// 071 072 /** Apply the function to the list of arguments, which are tokens. 073 * @param arguments The list of arguments. 074 * @return The result of applying the function to the given 075 * arguments. 076 * @exception IllegalActionException If thrown during evaluating 077 * the function. 078 */ 079 @Override 080 public ptolemy.data.Token apply(ptolemy.data.Token[] arguments) 081 throws IllegalActionException { 082 ParseTreeEvaluator parseTreeEvaluator = new ParseTreeEvaluator(); 083 084 // construct a NamedConstantsScope that contains mappings from 085 // argument names to the given argument values 086 Map map = new HashMap(); 087 088 for (int i = 0; i < arguments.length; ++i) { 089 String name = (String) _argumentNames.get(i); 090 ptolemy.data.Token argument = arguments[i]; 091 map.put(name, argument); 092 093 // Below is technically correct, but it prevents well typed 094 // recursive function definitions. I'm sure there's a well 095 // known solution to this, but I don't have the time to figure it 096 // out at the moment. 097 // map.put(name, _argumentTypes[i].convert(argument)); 098 } 099 100 NamedConstantsScope argumentsScope = new NamedConstantsScope(map); 101 return parseTreeEvaluator.evaluateParseTree(_exprRoot, argumentsScope); 102 } 103 104 /** Return the number of arguments of the function. 105 * @return The number of arguments of the function. 106 */ 107 @Override 108 public int getNumberOfArguments() { 109 return _argumentNames.size(); 110 } 111 112 /** Return true if this function is congruent to the given 113 * function. Classes should implement this method so that 114 * two functions are congruent under any renaming of the 115 * bound variables of the function. For simplicity, a 116 * function need only be congruent to other functions of the 117 * same class. 118 * @param function The function to check congruency against. 119 * @return True if this function is congruent. 120 */ 121 @Override 122 public boolean isCongruent(Function function) { 123 return toString().compareTo(function.toString()) == 0; 124 125 // FIXME: The above is not terribly nice... It would be nice 126 // to allow function equivalence under bound variable 127 // renaming. However, I got stuck trying to implement this, 128 // and decided I didn't want to spend any more time on it... 129 // SN - 4/18/2003 130 131 /** 132 if (!(function instanceof ExpressionFunction)) { 133 return false; 134 } 135 ExpressionFunction expressionFunction = (ExpressionFunction)function; 136 // The functions must have the same number of arguments. 137 if (getNumberOfArguments() != function.getNumberOfArguments()) { 138 return false; 139 } 140 // Construct the renaming map. 141 Map renaming = new HashMap(); 142 Iterator argNames = expressionFunction._argumentNames.iterator(); 143 for (Iterator names = _argumentNames.iterator(); 144 names.hasNext();) { 145 String name = (String)names.next(); 146 String argName = (String)argNames.next(); 147 renaming.put(name, argName); 148 } 149 return _exprRoot.isCongruent(expressionFunction._exprRoot, 150 renaming); 151 */ 152 } 153 154 /** Return a string representation of this function. 155 */ 156 @Override 157 public String toString() { 158 StringBuffer buffer = new StringBuffer("(function("); 159 int n = _argumentNames.size(); 160 161 for (int i = 0; i < n; i++) { 162 if (i > 0) { 163 buffer.append(", "); 164 } 165 166 buffer.append((String) _argumentNames.get(i)); 167 168 Type type = _argumentTypes[i]; 169 170 if (type != BaseType.GENERAL) { 171 buffer.append(":"); 172 buffer.append(type.toString()); 173 } 174 } 175 176 buffer.append(") "); 177 178 ParseTreeWriter writer = new ParseTreeWriter(); 179 String string = writer.printParseTree(_exprRoot); 180 buffer.append(string); 181 buffer.append(")"); 182 return buffer.toString(); 183 } 184 185 /////////////////////////////////////////////////////////////////// 186 //// private variables //// 187 // The root of the expression tree. 188 private ASTPtRootNode _exprRoot; 189 190 // The list of argument names that are bound in this function closure. 191 private List _argumentNames; 192 193 // The list of the (monomorphic) types of the arguments. 194 private Type[] _argumentTypes; 195}