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