|
| 1 | +/* |
| 2 | + * This file is part of OpenModelica. |
| 3 | + * |
| 4 | + * Copyright (c) 1998-2014, Open Source Modelica Consortium (OSMC), |
| 5 | + * c/o Linköpings universitet, Department of Computer and Information Science, |
| 6 | + * SE-58183 Linköping, Sweden. |
| 7 | + * |
| 8 | + * All rights reserved. |
| 9 | + * |
| 10 | + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 LICENSE OR |
| 11 | + * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. |
| 12 | + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES |
| 13 | + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, |
| 14 | + * ACCORDING TO RECIPIENTS CHOICE. |
| 15 | + * |
| 16 | + * The OpenModelica software and the Open Source Modelica |
| 17 | + * Consortium (OSMC) Public License (OSMC-PL) are obtained |
| 18 | + * from OSMC, either from the above address, |
| 19 | + * from the URLs: http://www.ida.liu.se/projects/OpenModelica or |
| 20 | + * http://www.openmodelica.org, and in the OpenModelica distribution. |
| 21 | + * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. |
| 22 | + * |
| 23 | + * This program is distributed WITHOUT ANY WARRANTY; without |
| 24 | + * even the implied warranty of MERCHANTABILITY or FITNESS |
| 25 | + * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH |
| 26 | + * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL. |
| 27 | + * |
| 28 | + * See the full OSMC Public License conditions for more details. |
| 29 | + * |
| 30 | + */ |
| 31 | + |
| 32 | +encapsulated package NFCall |
| 33 | + |
| 34 | +import Absyn; |
| 35 | +import NFInstNode.InstNode; |
| 36 | +import NFExpression.Expression; |
| 37 | +import Type = NFType; |
| 38 | + |
| 39 | +protected |
| 40 | +import NFInstNode.CachedData; |
| 41 | +import NFExpression.CallAttributes; |
| 42 | +import ComponentRef = NFComponentRef; |
| 43 | +import NFFunction.Function; |
| 44 | +import Inst = NFInst; |
| 45 | +import Lookup = NFLookup; |
| 46 | +import Typing = NFTyping; |
| 47 | +import Types; |
| 48 | + |
| 49 | +public |
| 50 | +function instantiate |
| 51 | + input Absyn.ComponentRef functionName; |
| 52 | + input Absyn.FunctionArgs functionArgs; |
| 53 | + input InstNode scope; |
| 54 | + input SourceInfo info; |
| 55 | + output Expression callExp; |
| 56 | +protected |
| 57 | + InstNode fn_node; |
| 58 | + Function fn; |
| 59 | + list<Function> fnl; |
| 60 | + CachedData cache; |
| 61 | + ComponentRef fn_ref; |
| 62 | + Absyn.Path fn_path; |
| 63 | +algorithm |
| 64 | + // Look up the the function. |
| 65 | + (fn_node, fn_ref, fn_path) := lookupFunction(functionName, scope, info); |
| 66 | + cache := InstNode.cachedData(fn_node); |
| 67 | + |
| 68 | + // Check if a cached instantiation of this function already exists. |
| 69 | + fnl := match cache |
| 70 | + case CachedData.FUNCTION() then cache.funcs; |
| 71 | + |
| 72 | + else // Not yet instantiated, instantiate it and cache it in the node. |
| 73 | + algorithm |
| 74 | + fn_node := Inst.instantiate(fn_node); |
| 75 | + Inst.instExpressions(fn_node); |
| 76 | + fn := Function.new(fn_path, fn_node); |
| 77 | + fn_node := InstNode.cacheAddFunc(fn, fn_node); |
| 78 | + then |
| 79 | + {fn}; |
| 80 | + end match; |
| 81 | + |
| 82 | + callExp := makeCall(fn_ref, fnl, functionArgs, scope, info); |
| 83 | +end instantiate; |
| 84 | + |
| 85 | +function typeCall |
| 86 | + input output Expression callExp; |
| 87 | + input InstNode scope; |
| 88 | + input SourceInfo info; |
| 89 | + output Type ty; |
| 90 | + output DAE.Const variability; |
| 91 | +protected |
| 92 | + InstNode fn_node; |
| 93 | + list<Function> fnl; |
| 94 | + Boolean fn_typed; |
| 95 | + Function fn; |
| 96 | + list<Expression> args; |
| 97 | + list<Type> arg_ty; |
| 98 | + list<DAE.Const> arg_var; |
| 99 | + CallAttributes ca; |
| 100 | +algorithm |
| 101 | + (callExp, ty, variability) := match callExp |
| 102 | + case Expression.CALL(ref = ComponentRef.CREF(node = fn_node)) |
| 103 | + algorithm |
| 104 | + // Fetch the cached function(s). |
| 105 | + CachedData.FUNCTION(fnl, fn_typed) := InstNode.cachedData(fn_node); |
| 106 | + |
| 107 | + // Type the function(s) if not already done. |
| 108 | + if not fn_typed then |
| 109 | + fnl := list(Function.typeFunction(f) for f in fnl); |
| 110 | + InstNode.setCachedData(CachedData.FUNCTION(fnl, true), fn_node); |
| 111 | + end if; |
| 112 | + |
| 113 | + assert(not listEmpty(fnl), getInstanceName() + " couldn't find a cached function"); |
| 114 | + |
| 115 | + fn := match fnl |
| 116 | + case {fn} then fn; // The normal case of only one matching function. |
| 117 | + else // TODO: Handle overloaded functions. |
| 118 | + algorithm |
| 119 | + assert(false, getInstanceName() + ": IMPLEMENT ME"); |
| 120 | + then |
| 121 | + fail(); |
| 122 | + end match; |
| 123 | + |
| 124 | + |
| 125 | + // Type the arguments. |
| 126 | + (args, arg_ty, arg_var) := Typing.typeExpl(callExp.arguments, scope, info); |
| 127 | + variability := Types.constAnd(v for v in arg_var); |
| 128 | + |
| 129 | + ty := fn.returnType; |
| 130 | + ca := CallAttributes.CALL_ATTR( |
| 131 | + ty, |
| 132 | + Type.isTuple(fn.returnType), |
| 133 | + Function.isBuiltin(fn), |
| 134 | + Function.isImpure(fn), |
| 135 | + Function.isFunctionPointer(fn), |
| 136 | + Function.inlineBuiltin(fn), |
| 137 | + DAE.NO_TAIL()); |
| 138 | + |
| 139 | + // TODO: Type check arguments against the inputs, and check variability. |
| 140 | + |
| 141 | + callExp := Expression.CALL(callExp.ref, args, SOME(ca)); |
| 142 | + then |
| 143 | + (callExp, ty, variability); |
| 144 | + |
| 145 | + else |
| 146 | + algorithm |
| 147 | + assert(false, getInstanceName() + " got invalid function call expression"); |
| 148 | + then |
| 149 | + fail(); |
| 150 | + end match; |
| 151 | +end typeCall; |
| 152 | + |
| 153 | +protected |
| 154 | +function lookupFunction |
| 155 | + input Absyn.ComponentRef functionName; |
| 156 | + input InstNode scope; |
| 157 | + input SourceInfo info; |
| 158 | + output InstNode node; |
| 159 | + output ComponentRef functionRef; |
| 160 | + output Absyn.Path functionPath; |
| 161 | +protected |
| 162 | + list<InstNode> nodes; |
| 163 | + InstNode found_scope; |
| 164 | +algorithm |
| 165 | + try |
| 166 | + // Make sure the name is a path. |
| 167 | + functionPath := Absyn.crefToPath(functionName); |
| 168 | + else |
| 169 | + Error.addSourceMessageAndFail(Error.SUBSCRIPTED_FUNCTION_CALL, |
| 170 | + {Dump.printComponentRefStr(functionName)}, info); |
| 171 | + end try; |
| 172 | + |
| 173 | + // Look up the function and create a cref for it. |
| 174 | + (node, nodes, found_scope) := Lookup.lookupFunctionName(functionName, scope, info); |
| 175 | + |
| 176 | + for s in InstNode.scopeList(found_scope) loop |
| 177 | + functionPath := Absyn.QUALIFIED(InstNode.name(s), functionPath); |
| 178 | + end for; |
| 179 | + |
| 180 | + functionRef := ComponentRef.fromNodeList(InstNode.scopeList(found_scope)); |
| 181 | + functionRef := Inst.makeCref(functionName, nodes, scope, info, functionRef); |
| 182 | +end lookupFunction; |
| 183 | + |
| 184 | +function makeCall |
| 185 | + input ComponentRef fnRef; |
| 186 | + input list<Function> funcs; |
| 187 | + input Absyn.FunctionArgs callArgs; |
| 188 | + input InstNode scope; |
| 189 | + input SourceInfo info; |
| 190 | + output Expression call; |
| 191 | + output list<Function> matchingFuncs; |
| 192 | +protected |
| 193 | + list<Expression> args; |
| 194 | + list<tuple<String, Expression>> named_args; |
| 195 | +algorithm |
| 196 | + (args, named_args) := instArgs(callArgs, scope, info); |
| 197 | + (args, matchingFuncs) := matchArgs(args, named_args, funcs, info); |
| 198 | + call := Expression.CALL(fnRef, args, NONE()); |
| 199 | +end makeCall; |
| 200 | + |
| 201 | +function instArgs |
| 202 | + input Absyn.FunctionArgs args; |
| 203 | + input InstNode scope; |
| 204 | + input SourceInfo info; |
| 205 | + output list<Expression> posArgs; |
| 206 | + output list<tuple<String, Expression>> namedArgs; |
| 207 | +algorithm |
| 208 | + (posArgs, namedArgs) := match args |
| 209 | + case Absyn.FUNCTIONARGS() |
| 210 | + algorithm |
| 211 | + posArgs := list(Inst.instExp(a, scope, info) for a in args.args); |
| 212 | + namedArgs := list(instNamedArg(a, scope, info) for a in args.argNames); |
| 213 | + then |
| 214 | + (posArgs, namedArgs); |
| 215 | + |
| 216 | + else |
| 217 | + algorithm |
| 218 | + assert(false, getInstanceName() + " got unknown function args"); |
| 219 | + then |
| 220 | + fail(); |
| 221 | + end match; |
| 222 | +end instArgs; |
| 223 | + |
| 224 | +function instNamedArg |
| 225 | + input Absyn.NamedArg absynArg; |
| 226 | + input InstNode scope; |
| 227 | + input SourceInfo info; |
| 228 | + output tuple<String, Expression> arg; |
| 229 | +protected |
| 230 | + String name; |
| 231 | + Absyn.Exp exp; |
| 232 | +algorithm |
| 233 | + Absyn.NAMEDARG(argName = name, argValue = exp) := absynArg; |
| 234 | + arg := (name, Inst.instExp(exp, scope, info)); |
| 235 | +end instNamedArg; |
| 236 | + |
| 237 | +function matchArgs |
| 238 | + input list<Expression> posArgs; |
| 239 | + input list<tuple<String, Expression>> namedArgs; |
| 240 | + input list<Function> funcs; |
| 241 | + input SourceInfo info; |
| 242 | + output list<Expression> args; |
| 243 | + output list<Function> matchingFuncs; |
| 244 | +protected |
| 245 | + Function fn; |
| 246 | +algorithm |
| 247 | + if listLength(funcs) == 1 then |
| 248 | + (args, true) := Function.matchArgs(posArgs, namedArgs, listHead(funcs), SOME(info)); |
| 249 | + matchingFuncs := funcs; |
| 250 | + else |
| 251 | + // TODO: Implement case for overloaded functions. |
| 252 | + assert(false, getInstanceName() + ": IMPLEMENT ME"); |
| 253 | + end if; |
| 254 | +end matchArgs; |
| 255 | + |
| 256 | +annotation(__OpenModelica_Interface="frontend"); |
| 257 | +end NFCall; |
0 commit comments