(StarlarkThread.Frame fr, Resolver.Function rfn)
| 160 | } |
| 161 | |
| 162 | private static StarlarkFunction newFunction(StarlarkThread.Frame fr, Resolver.Function rfn) |
| 163 | throws EvalException, InterruptedException { |
| 164 | // Evaluate default value expressions of optional parameters. |
| 165 | // We use MANDATORY to indicate a required parameter |
| 166 | // (not null, because defaults must be a legal tuple value, as |
| 167 | // it will be constructed by the code emitted by the compiler). |
| 168 | // As an optimization, we omit the prefix of MANDATORY parameters. |
| 169 | Object[] defaults = null; |
| 170 | int nparams = |
| 171 | rfn.getParameters().size() - (rfn.hasKwargs() ? 1 : 0) - (rfn.hasVarargs() ? 1 : 0); |
| 172 | CallableType functionType = rfn.getFunctionType(); |
| 173 | boolean dynamicTypeCheckingEnabled = |
| 174 | fr.thread.getSemantics().getBool(StarlarkSemantics.EXPERIMENTAL_STARLARK_TYPE_CHECKING); |
| 175 | for (int i = 0; i < nparams; i++) { |
| 176 | Expression expr = rfn.getParameters().get(i).getDefaultValue(); |
| 177 | if (expr == null && defaults == null) { |
| 178 | continue; // skip prefix of required parameters |
| 179 | } |
| 180 | if (defaults == null) { |
| 181 | defaults = new Object[nparams - i]; |
| 182 | } |
| 183 | Object defaultValue = expr == null ? StarlarkFunction.MANDATORY : eval(fr, expr); |
| 184 | defaults[i - (nparams - defaults.length)] = defaultValue; |
| 185 | |
| 186 | if (dynamicTypeCheckingEnabled && functionType != null) { |
| 187 | // Typecheck the default value |
| 188 | StarlarkType parameterType = functionType.getParameterTypeByPos(i); |
| 189 | if (!TypeChecker.isValueSubtypeOf(defaultValue, parameterType)) { |
| 190 | throw Starlark.errorf( |
| 191 | "%s(): parameter '%s' has default value of type '%s', declares '%s'", |
| 192 | rfn.getName(), |
| 193 | rfn.getParameterNames().get(i), |
| 194 | TypeChecker.type(defaultValue), |
| 195 | parameterType); |
| 196 | } |
| 197 | } |
| 198 | } |
| 199 | if (defaults == null) { |
| 200 | defaults = EMPTY; |
| 201 | } |
| 202 | |
| 203 | // Capture the cells of the function's |
| 204 | // free variables from the lexical environment. |
| 205 | Object[] freevars = new Object[rfn.getFreeVars().size()]; |
| 206 | int i = 0; |
| 207 | for (Resolver.Binding bind : rfn.getFreeVars()) { |
| 208 | // Unlike expr(Identifier), we want the cell itself, not its content. |
| 209 | switch (bind.getScope()) { |
| 210 | case FREE: |
| 211 | freevars[i++] = fn(fr).getFreeVar(bind.getIndex()); |
| 212 | break; |
| 213 | case CELL: |
| 214 | freevars[i++] = fr.locals[bind.getIndex()]; |
| 215 | break; |
| 216 | default: |
| 217 | throw new IllegalStateException("unexpected: " + bind); |
| 218 | } |
| 219 | } |
no test coverage detected