Introduce first class function signatures; make the parser use them.
This is the first meaty cl in a series to refactor the Skylark function call protocol.
1- We introduce a first-class notion of FunctionSignature, that supports positional and named-only arguments, mandatory and optional, default values, type-checking, *stararg and **kwarg;
2- To keep things clean, we distinguish two different kinds of Argument's: Argument.Passed that appears in function calls, and Parameter, that appears in function definitions.
3- We refactor the Parser so it uses this infrastructure, and make minimal changes to MixedModeFunction so that it works with it (but don't actually implement *starparam and **kwparam yet).
4- As we modify FuncallExpression, we ensure that the args and kwargs arguments it passes to the underlying function are immutable, as a prerequisite to upcoming implementation of *starparam and **kwparam as being provided directly from a skylark list or dict.
Further changes under review will take advantage of this FunctionSignature to redo all our function call protocol, to be used uniformly for both UserDefinedFunction's and builtin function. The result will be a simpler inheritance model, with better type-checking, builtin functions that are both simpler and better documented, and many redundant competing functionality-limited codepaths being merged and replaced by something better.
NB: The changes to MixedModeFunction, SkylarkFunction and MethodLibrary are temporary hacks to be done away with in an upcoming CL. The rest is the actual changes.
--
MOS_MIGRATED_REVID=86704072
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Parameter.java b/src/main/java/com/google/devtools/build/lib/syntax/Parameter.java
new file mode 100644
index 0000000..14267d8
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Parameter.java
@@ -0,0 +1,170 @@
+// Copyright 2014 Google Inc. 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 javax.annotation.Nullable;
+
+/**
+ * Syntax node for a Parameter in a function (or lambda) definition; it's a subclass of Argument,
+ * and contrasts with the class Argument.Passed of arguments in a function call.
+ *
+ * <p>There are four concrete subclasses of Parameter: Mandatory, Optional, Star, StarStar.
+ *
+ * <p>See FunctionSignature for how a valid list of Parameter's is organized as a signature, e.g.
+ * def foo(mandatory, optional = e1, *args, mandatorynamedonly, optionalnamedonly = e2, **kw): ...
+ *
+ * <p>V is the class of a defaultValue (Expression at compile-time, Object at runtime),
+ * T is the class of a type (Expression at compile-time, SkylarkType at runtime).
+ */
+public abstract class Parameter<V, T> extends Argument {
+
+ @Nullable protected String name;
+ @Nullable protected final T type;
+
+ private Parameter(@Nullable String name, @Nullable T type) {
+ this.name = name;
+ this.type = type;
+ }
+ private Parameter(@Nullable String name) {
+ this.name = name;
+ this.type = null;
+ }
+
+ public boolean isMandatory() {
+ return false;
+ }
+ public boolean isOptional() {
+ return false;
+ }
+ public boolean isStar() {
+ return false;
+ }
+ public boolean isStarStar() {
+ return false;
+ }
+ @Nullable public String getName() {
+ return name;
+ }
+ public boolean hasName() {
+ return true;
+ }
+ @Nullable public T getType() {
+ return type;
+ }
+ @Nullable public V getDefaultValue() {
+ return null;
+ }
+
+ /** mandatory parameter (positional or key-only depending on position): Ident */
+ public static class Mandatory<V, T> extends Parameter<V, T> {
+
+ public Mandatory(String name) {
+ super(name);
+ }
+
+ public Mandatory(String name, @Nullable T type) {
+ super(name, type);
+ }
+
+ @Override public boolean isMandatory() {
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return name.toString();
+ }
+ }
+
+ /** optional parameter (positional or key-only depending on position): Ident = Value */
+ public static class Optional<V, T> extends Parameter<V, T> {
+ public final V defaultValue;
+
+ public Optional(String name, @Nullable V defaultValue) {
+ super(name);
+ this.defaultValue = defaultValue;
+ }
+
+ public Optional(String name, @Nullable T type, @Nullable V defaultValue) {
+ super(name, type);
+ this.defaultValue = defaultValue;
+ }
+
+ @Override @Nullable public V getDefaultValue() {
+ return defaultValue;
+ }
+
+ @Override public boolean isOptional() {
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return name.toString() + "=" + String.valueOf(defaultValue);
+ }
+ }
+
+ /** extra positionals parameter (star): *identifier */
+ public static class Star<V, T> extends Parameter<V, T> {
+ public Star(@Nullable String name, @Nullable T type) {
+ super(name, type);
+ }
+
+ public Star(@Nullable String name) {
+ super(name);
+ }
+
+ @Override
+ public boolean hasName() {
+ return name != null;
+ }
+
+ @Override public boolean isStar() {
+ return true;
+ }
+
+ @Override public String toString() {
+ if (name == null) {
+ return "*";
+ } else {
+ return "*" + name.toString();
+ }
+ }
+ }
+
+ /** extra keywords parameter (star_star): **identifier */
+ public static class StarStar<V, T> extends Parameter<V, T> {
+ public StarStar(String name, @Nullable T type) {
+ super(name, type);
+ }
+
+ public StarStar(String name) {
+ super(name);
+ }
+
+ @Override public boolean isStarStar() {
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "**" + name.toString();
+ }
+ }
+
+ @Override
+ public void accept(SyntaxTreeVisitor visitor) {
+ visitor.visit(this);
+ }
+}