| // Copyright 2014 The Bazel Authors. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| package com.google.devtools.build.lib.syntax; |
| |
| import com.google.common.base.Optional; |
| import com.google.common.collect.ImmutableList; |
| import com.google.devtools.build.lib.syntax.compiler.DebugInfo; |
| import com.google.devtools.build.lib.syntax.compiler.LoopLabels; |
| import com.google.devtools.build.lib.syntax.compiler.VariableScope; |
| |
| import net.bytebuddy.implementation.bytecode.ByteCodeAppender; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| /** |
| * Syntax node for a function definition. |
| */ |
| public class FunctionDefStatement extends Statement { |
| |
| private final Identifier ident; |
| private final FunctionSignature.WithValues<Expression, Expression> signature; |
| private final ImmutableList<Statement> statements; |
| private final ImmutableList<Parameter<Expression, Expression>> parameters; |
| |
| public FunctionDefStatement(Identifier ident, |
| Iterable<Parameter<Expression, Expression>> parameters, |
| FunctionSignature.WithValues<Expression, Expression> signature, |
| Iterable<Statement> statements) { |
| this.ident = ident; |
| this.signature = signature; |
| this.statements = ImmutableList.copyOf(statements); |
| this.parameters = ImmutableList.copyOf(parameters); |
| } |
| |
| @Override |
| void doExec(Environment env) throws EvalException, InterruptedException { |
| List<Expression> defaultExpressions = signature.getDefaultValues(); |
| ArrayList<Object> defaultValues = null; |
| ArrayList<SkylarkType> types = null; |
| |
| if (defaultExpressions != null) { |
| defaultValues = new ArrayList<>(defaultExpressions.size()); |
| for (Expression expr : defaultExpressions) { |
| defaultValues.add(expr.eval(env)); |
| } |
| } |
| env.update( |
| ident.getName(), |
| new UserDefinedFunction( |
| ident, |
| FunctionSignature.WithValues.<Object, SkylarkType>create( |
| signature.getSignature(), defaultValues, types), |
| statements, |
| env.getGlobals())); |
| } |
| |
| @Override |
| public String toString() { |
| return "def " + ident + "(" + signature + "):\n"; |
| } |
| |
| public Identifier getIdent() { |
| return ident; |
| } |
| |
| public ImmutableList<Statement> getStatements() { |
| return statements; |
| } |
| |
| public ImmutableList<Parameter<Expression, Expression>> getParameters() { |
| return parameters; |
| } |
| |
| public FunctionSignature.WithValues<Expression, Expression> getSignature() { |
| return signature; |
| } |
| |
| @Override |
| public void accept(SyntaxTreeVisitor visitor) { |
| visitor.visit(this); |
| } |
| |
| @Override |
| void validate(final ValidationEnvironment env) throws EvalException { |
| ValidationEnvironment localEnv = new ValidationEnvironment(env); |
| FunctionSignature sig = signature.getSignature(); |
| FunctionSignature.Shape shape = sig.getShape(); |
| ImmutableList<String> names = sig.getNames(); |
| List<Expression> defaultExpressions = signature.getDefaultValues(); |
| |
| int positionals = shape.getPositionals(); |
| int mandatoryPositionals = shape.getMandatoryPositionals(); |
| int namedOnly = shape.getNamedOnly(); |
| int mandatoryNamedOnly = shape.getMandatoryNamedOnly(); |
| boolean starArg = shape.hasStarArg(); |
| boolean kwArg = shape.hasKwArg(); |
| int named = positionals + namedOnly; |
| int args = named + (starArg ? 1 : 0) + (kwArg ? 1 : 0); |
| int startOptionals = mandatoryPositionals; |
| int endOptionals = named - mandatoryNamedOnly; |
| |
| int j = 0; // index for the defaultExpressions |
| for (int i = 0; i < args; i++) { |
| String name = names.get(i); |
| if (startOptionals <= i && i < endOptionals) { |
| defaultExpressions.get(j++).validate(env); |
| } |
| localEnv.declare(name, getLocation()); |
| } |
| for (Statement stmts : statements) { |
| stmts.validate(localEnv); |
| } |
| } |
| |
| @Override |
| ByteCodeAppender compile( |
| VariableScope scope, Optional<LoopLabels> loopLabels, DebugInfo debugInfo) { |
| throw new UnsupportedOperationException( |
| "Skylark does not support nested function definitions" |
| + " and the current entry point for the compiler is UserDefinedFunction."); |
| } |
| } |