Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 1 | // Copyright 2014 Google Inc. All rights reserved. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | package com.google.devtools.build.lib.syntax; |
| 15 | |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 16 | import com.google.common.collect.ImmutableList; |
Francois-Rene Rideau | 89312fb | 2015-09-10 18:53:03 +0000 | [diff] [blame] | 17 | import com.google.common.collect.Iterables; |
Googler | fe98ecb | 2015-09-02 15:14:38 +0000 | [diff] [blame] | 18 | import com.google.devtools.build.lib.events.Location.LineAndColumn; |
Googler | 768cbc4 | 2015-08-28 12:52:14 +0000 | [diff] [blame] | 19 | import com.google.devtools.build.lib.profiler.Profiler; |
| 20 | import com.google.devtools.build.lib.profiler.ProfilerTask; |
Googler | fe98ecb | 2015-09-02 15:14:38 +0000 | [diff] [blame] | 21 | import com.google.devtools.build.lib.vfs.PathFragment; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 22 | |
| 23 | /** |
| 24 | * The actual function registered in the environment. This function is defined in the |
| 25 | * parsed code using {@link FunctionDefStatement}. |
| 26 | */ |
Francois-Rene Rideau | 4feb160 | 2015-03-18 19:49:13 +0000 | [diff] [blame] | 27 | public class UserDefinedFunction extends BaseFunction { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 28 | |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 29 | private final ImmutableList<Statement> statements; |
Francois-Rene Rideau | 89312fb | 2015-09-10 18:53:03 +0000 | [diff] [blame] | 30 | |
| 31 | // we close over the globals at the time of definition |
| 32 | private final Environment.Frame definitionGlobals; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 33 | |
Florian Weikert | 6f864c3 | 2015-07-23 11:26:39 +0000 | [diff] [blame] | 34 | protected UserDefinedFunction(Identifier function, |
Francois-Rene Rideau | 5dcdbf9 | 2015-02-19 18:36:17 +0000 | [diff] [blame] | 35 | FunctionSignature.WithValues<Object, SkylarkType> signature, |
Francois-Rene Rideau | 89312fb | 2015-09-10 18:53:03 +0000 | [diff] [blame] | 36 | ImmutableList<Statement> statements, Environment.Frame definitionGlobals) { |
Francois-Rene Rideau | 5dcdbf9 | 2015-02-19 18:36:17 +0000 | [diff] [blame] | 37 | super(function.getName(), signature, function.getLocation()); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 38 | this.statements = statements; |
Francois-Rene Rideau | 89312fb | 2015-09-10 18:53:03 +0000 | [diff] [blame] | 39 | this.definitionGlobals = definitionGlobals; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 40 | } |
| 41 | |
Francois-Rene Rideau | 5dcdbf9 | 2015-02-19 18:36:17 +0000 | [diff] [blame] | 42 | public FunctionSignature.WithValues<Object, SkylarkType> getFunctionSignature() { |
| 43 | return signature; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 44 | } |
| 45 | |
| 46 | ImmutableList<Statement> getStatements() { |
| 47 | return statements; |
| 48 | } |
| 49 | |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 50 | @Override |
Francois-Rene Rideau | 5dcdbf9 | 2015-02-19 18:36:17 +0000 | [diff] [blame] | 51 | public Object call(Object[] arguments, FuncallExpression ast, Environment env) |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 52 | throws EvalException, InterruptedException { |
Francois-Rene Rideau | 89312fb | 2015-09-10 18:53:03 +0000 | [diff] [blame] | 53 | if (!env.mutability().isMutable()) { |
| 54 | throw new EvalException(getLocation(), "Trying to call in frozen environment"); |
| 55 | } |
| 56 | if (env.getStackTrace().contains(this)) { |
| 57 | throw new EvalException(getLocation(), |
| 58 | String.format("Recursion was detected when calling '%s' from '%s'", |
| 59 | getName(), Iterables.getLast(env.getStackTrace()).getName())); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 60 | } |
| 61 | |
Klaas Boesche | f441c19 | 2015-09-09 16:03:55 +0000 | [diff] [blame] | 62 | Profiler.instance().startTask(ProfilerTask.SKYLARK_USER_FN, |
| 63 | getLocationPathAndLine() + "#" + getName()); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 64 | try { |
Francois-Rene Rideau | 89312fb | 2015-09-10 18:53:03 +0000 | [diff] [blame] | 65 | env.enterScope(this, ast, definitionGlobals); |
| 66 | ImmutableList<String> names = signature.getSignature().getNames(); |
| 67 | |
| 68 | // Registering the functions's arguments as variables in the local Environment |
| 69 | int i = 0; |
| 70 | for (String name : names) { |
| 71 | env.update(name, arguments[i++]); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 72 | } |
Francois-Rene Rideau | 89312fb | 2015-09-10 18:53:03 +0000 | [diff] [blame] | 73 | |
| 74 | try { |
| 75 | for (Statement stmt : statements) { |
Francois-Rene Rideau | 89312fb | 2015-09-10 18:53:03 +0000 | [diff] [blame] | 76 | stmt.exec(env); |
| 77 | } |
| 78 | } catch (ReturnStatement.ReturnException e) { |
| 79 | return e.getValue(); |
| 80 | } |
| 81 | return Runtime.NONE; |
Googler | 768cbc4 | 2015-08-28 12:52:14 +0000 | [diff] [blame] | 82 | } finally { |
Klaas Boesche | f441c19 | 2015-09-09 16:03:55 +0000 | [diff] [blame] | 83 | Profiler.instance().completeTask(ProfilerTask.SKYLARK_USER_FN); |
Francois-Rene Rideau | 89312fb | 2015-09-10 18:53:03 +0000 | [diff] [blame] | 84 | env.exitScope(); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 85 | } |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 86 | } |
Florian Weikert | 3f610e8 | 2015-08-18 14:37:46 +0000 | [diff] [blame] | 87 | |
| 88 | /** |
Googler | fe98ecb | 2015-09-02 15:14:38 +0000 | [diff] [blame] | 89 | * Returns the location (filename:line) of the BaseFunction's definition. |
| 90 | * |
| 91 | * <p>If such a location is not defined, this method returns an empty string. |
| 92 | */ |
| 93 | private String getLocationPathAndLine() { |
| 94 | if (location == null) { |
| 95 | return ""; |
| 96 | } |
| 97 | |
| 98 | StringBuilder builder = new StringBuilder(); |
| 99 | PathFragment path = location.getPath(); |
| 100 | if (path != null) { |
| 101 | builder.append(path.getPathString()); |
| 102 | } |
| 103 | |
| 104 | LineAndColumn position = location.getStartLineAndColumn(); |
| 105 | if (position != null) { |
| 106 | builder.append(":").append(position.getLine()); |
| 107 | } |
| 108 | return builder.toString(); |
| 109 | } |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 110 | } |