Damien Martin-Guillerez | f88f4d8 | 2015-09-25 13:56:55 +0000 | [diff] [blame] | 1 | // Copyright 2014 The Bazel Authors. All rights reserved. |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 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; |
vladmos | 3feea74 | 2017-07-06 12:16:18 -0400 | [diff] [blame] | 17 | import com.google.devtools.build.lib.cmdline.Label; |
brandjon | 64c6632 | 2017-08-23 04:36:38 +0200 | [diff] [blame] | 18 | import com.google.devtools.build.lib.events.Location; |
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; |
ulfjack | 4cf2ebd | 2018-06-11 06:00:36 -0700 | [diff] [blame] | 21 | import com.google.devtools.build.lib.profiler.SilentCloseable; |
vladmos | 3feea74 | 2017-07-06 12:16:18 -0400 | [diff] [blame] | 22 | import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter; |
nharmata | 68cc06b | 2018-03-01 10:21:57 -0800 | [diff] [blame] | 23 | import com.google.devtools.build.lib.syntax.Environment.LexicalFrame; |
Klaas Boesche | 0ec13b9 | 2015-11-06 12:16:03 +0000 | [diff] [blame] | 24 | |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 25 | /** |
janakr | 9ba46f8 | 2018-03-13 13:07:52 -0700 | [diff] [blame] | 26 | * The actual function registered in the environment. This function is defined in the parsed code |
| 27 | * using {@link FunctionDefStatement}. |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 28 | */ |
Francois-Rene Rideau | 4feb160 | 2015-03-18 19:49:13 +0000 | [diff] [blame] | 29 | public class UserDefinedFunction extends BaseFunction { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 30 | |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 31 | private final ImmutableList<Statement> statements; |
Francois-Rene Rideau | 89312fb | 2015-09-10 18:53:03 +0000 | [diff] [blame] | 32 | |
| 33 | // we close over the globals at the time of definition |
nharmata | 68cc06b | 2018-03-01 10:21:57 -0800 | [diff] [blame] | 34 | private final Environment.GlobalFrame definitionGlobals; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 35 | |
brandjon | 64c6632 | 2017-08-23 04:36:38 +0200 | [diff] [blame] | 36 | public UserDefinedFunction( |
| 37 | String name, |
janakr | 9ba46f8 | 2018-03-13 13:07:52 -0700 | [diff] [blame] | 38 | Location location, |
Francois-Rene Rideau | 5dcdbf9 | 2015-02-19 18:36:17 +0000 | [diff] [blame] | 39 | FunctionSignature.WithValues<Object, SkylarkType> signature, |
Florian Weikert | 33f819b | 2015-11-09 18:15:55 +0000 | [diff] [blame] | 40 | ImmutableList<Statement> statements, |
nharmata | 68cc06b | 2018-03-01 10:21:57 -0800 | [diff] [blame] | 41 | Environment.GlobalFrame definitionGlobals) { |
janakr | 9ba46f8 | 2018-03-13 13:07:52 -0700 | [diff] [blame] | 42 | super(name, signature, location); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 43 | this.statements = statements; |
Francois-Rene Rideau | 89312fb | 2015-09-10 18:53:03 +0000 | [diff] [blame] | 44 | this.definitionGlobals = definitionGlobals; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 45 | } |
| 46 | |
brandjon | 64c6632 | 2017-08-23 04:36:38 +0200 | [diff] [blame] | 47 | public ImmutableList<Statement> getStatements() { |
| 48 | return statements; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 49 | } |
| 50 | |
nharmata | 68cc06b | 2018-03-01 10:21:57 -0800 | [diff] [blame] | 51 | public Environment.GlobalFrame getDefinitionGlobals() { |
brandjon | 64c6632 | 2017-08-23 04:36:38 +0200 | [diff] [blame] | 52 | return definitionGlobals; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 53 | } |
| 54 | |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 55 | @Override |
Francois-Rene Rideau | 5dcdbf9 | 2015-02-19 18:36:17 +0000 | [diff] [blame] | 56 | public Object call(Object[] arguments, FuncallExpression ast, Environment env) |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 57 | throws EvalException, InterruptedException { |
brandjon | 33b4943 | 2017-05-04 18:58:52 +0200 | [diff] [blame] | 58 | if (env.mutability().isFrozen()) { |
Francois-Rene Rideau | 89312fb | 2015-09-10 18:53:03 +0000 | [diff] [blame] | 59 | throw new EvalException(getLocation(), "Trying to call in frozen environment"); |
| 60 | } |
michajlo | cbb3347 | 2017-10-23 20:30:18 +0200 | [diff] [blame] | 61 | if (env.isRecursiveCall(this)) { |
Francois-Rene Rideau | 89312fb | 2015-09-10 18:53:03 +0000 | [diff] [blame] | 62 | throw new EvalException(getLocation(), |
| 63 | String.format("Recursion was detected when calling '%s' from '%s'", |
michajlo | cbb3347 | 2017-10-23 20:30:18 +0200 | [diff] [blame] | 64 | getName(), env.getCurrentFunction().getName())); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 65 | } |
| 66 | |
nharmata | 62678a4 | 2018-03-08 16:43:45 -0800 | [diff] [blame] | 67 | ImmutableList<String> names = signature.getSignature().getNames(); |
laurentlb | caafe30 | 2018-08-28 10:24:31 -0700 | [diff] [blame] | 68 | LexicalFrame lexicalFrame = LexicalFrame.create(env.mutability(), /*numArgs=*/ names.size()); |
ulfjack | 4cf2ebd | 2018-06-11 06:00:36 -0700 | [diff] [blame] | 69 | try (SilentCloseable c = Profiler.instance().profile(ProfilerTask.SKYLARK_USER_FN, getName())) { |
nharmata | 62678a4 | 2018-03-08 16:43:45 -0800 | [diff] [blame] | 70 | env.enterScope(this, lexicalFrame, ast, definitionGlobals); |
nharmata | 6e233f0 | 2018-03-07 16:02:22 -0800 | [diff] [blame] | 71 | |
| 72 | // Registering the functions's arguments as variables in the local Environment |
Taras Tsugrii | 77e4792 | 2018-08-02 06:12:15 -0700 | [diff] [blame] | 73 | // foreach loop is not used to avoid iterator overhead |
| 74 | for (int i = 0; i < names.size(); ++i) { |
| 75 | env.update(names.get(i), arguments[i]); |
nharmata | 6e233f0 | 2018-03-07 16:02:22 -0800 | [diff] [blame] | 76 | } |
| 77 | |
Googler | 29eafdf | 2018-05-23 12:32:07 -0700 | [diff] [blame] | 78 | Eval eval = Eval.fromEnvironment(env); |
Francois-Rene Rideau | 89312fb | 2015-09-10 18:53:03 +0000 | [diff] [blame] | 79 | try { |
| 80 | for (Statement stmt : statements) { |
Laurent Le Brun | b655167 | 2015-10-28 12:42:09 +0000 | [diff] [blame] | 81 | if (stmt instanceof ReturnStatement) { |
| 82 | // Performance optimization. |
| 83 | // Executing the statement would throw an exception, which is slow. |
fzaiser | 317a269 | 2017-08-23 16:40:30 +0200 | [diff] [blame] | 84 | Expression returnExpr = ((ReturnStatement) stmt).getReturnExpression(); |
| 85 | if (returnExpr == null) { |
| 86 | return Runtime.NONE; |
| 87 | } |
| 88 | return returnExpr.eval(env); |
Laurent Le Brun | b655167 | 2015-10-28 12:42:09 +0000 | [diff] [blame] | 89 | } else { |
laurentlb | 919d1b7 | 2017-09-01 20:22:11 +0200 | [diff] [blame] | 90 | eval.exec(stmt); |
Laurent Le Brun | b655167 | 2015-10-28 12:42:09 +0000 | [diff] [blame] | 91 | } |
Francois-Rene Rideau | 89312fb | 2015-09-10 18:53:03 +0000 | [diff] [blame] | 92 | } |
| 93 | } catch (ReturnStatement.ReturnException e) { |
| 94 | return e.getValue(); |
| 95 | } |
| 96 | return Runtime.NONE; |
Googler | 768cbc4 | 2015-08-28 12:52:14 +0000 | [diff] [blame] | 97 | } finally { |
Francois-Rene Rideau | 89312fb | 2015-09-10 18:53:03 +0000 | [diff] [blame] | 98 | env.exitScope(); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 99 | } |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 100 | } |
vladmos | 3feea74 | 2017-07-06 12:16:18 -0400 | [diff] [blame] | 101 | |
| 102 | @Override |
| 103 | public void repr(SkylarkPrinter printer) { |
| 104 | Label label = this.definitionGlobals.getTransitiveLabel(); |
| 105 | |
| 106 | printer.append("<function " + getName()); |
| 107 | if (label != null) { |
| 108 | printer.append(" from " + label); |
| 109 | } |
| 110 | printer.append(">"); |
| 111 | } |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 112 | } |