From 8f678923ebea788fc1e03ba8c6359b51edafe0df Mon Sep 17 00:00:00 2001 From: adonovan Date: Thu, 3 Sep 2020 10:07:03 -0700 Subject: [PATCH] bazel syntax: add examples of interpreter API RELNOTES: N/A PiperOrigin-RevId: 329940788 --- .../google/devtools/build/lib/syntax/BUILD | 1 + .../devtools/build/lib/syntax/Examples.java | 126 ++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 src/test/java/com/google/devtools/build/lib/syntax/Examples.java diff --git a/src/test/java/com/google/devtools/build/lib/syntax/BUILD b/src/test/java/com/google/devtools/build/lib/syntax/BUILD index f8f59028f8283c..402079c79002db 100644 --- a/src/test/java/com/google/devtools/build/lib/syntax/BUILD +++ b/src/test/java/com/google/devtools/build/lib/syntax/BUILD @@ -48,6 +48,7 @@ java_test( # CpuProfilerTest.java doesn't run under OSS Bazel "EvalUtilsTest.java", "EvaluationTest.java", + "Examples.java", "FunctionTest.java", "MethodLibraryTest.java", "MutabilityTest.java", diff --git a/src/test/java/com/google/devtools/build/lib/syntax/Examples.java b/src/test/java/com/google/devtools/build/lib/syntax/Examples.java new file mode 100644 index 00000000000000..e64d519c1633d0 --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/syntax/Examples.java @@ -0,0 +1,126 @@ +// Copyright 2020 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.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import java.io.IOException; +import net.starlark.java.annot.Param; +import net.starlark.java.annot.StarlarkGlobalLibrary; +import net.starlark.java.annot.StarlarkMethod; + +/** + * Examples of typical API usage of the Starlark interpreter.
+ * This is not a test, but it is checked by the compiler. + */ +final class Examples { + + /** + * This example reads, parses, compiles, and executes a Starlark file. It returns the module, + * which holds the values of global variables. + */ + Module execFile(String filename) + throws IOException, SyntaxError.Exception, EvalException, InterruptedException { + // Read input from the named file. + ParserInput input = ParserInput.readFile(filename); + + // Create the module that will be populated by executing the file. + // It holds the global variables, initially empty. + // Its predeclared environment defines only the standard builtins: + // None, True, len, and so on. + Module module = Module.create(); + + // Resolve, compile, and execute the file. + // + // The Mutability will be associated with all the values created by this thread. + // The try-with-resources statement ensures that all values become frozen + // after execution. + try (Mutability mu = Mutability.create(input.getFile())) { + StarlarkThread thread = new StarlarkThread(mu, StarlarkSemantics.DEFAULT); + Starlark.execFile(input, FileOptions.DEFAULT, module, thread); + } + + return module; + } + + /** + * This example evaluates a Starlark expression in the specified environment and returns its + * value. + */ + Object evalExpr(String expr, ImmutableMap env) + throws SyntaxError.Exception, EvalException, InterruptedException { + // The apparent file name (for error messages) will be "". + ParserInput input = ParserInput.fromString(expr, ""); + + // Create the module in which the expression is evaluated. + // It may define additional predeclared environment bindings. + Module module = Module.withPredeclared(StarlarkSemantics.DEFAULT, env); + + // Resolve, compile, and execute the expression. + try (Mutability mu = Mutability.create(input.getFile())) { + StarlarkThread thread = new StarlarkThread(mu, StarlarkSemantics.DEFAULT); + return Starlark.eval(input, FileOptions.DEFAULT, module, thread); + } + } + + /** + * This advanced example reads, parses, and compiles a Starlark file to a Program, then later + * executes it. + */ + Module compileThenExecute() + throws IOException, SyntaxError.Exception, EvalException, InterruptedException { + // Read and parse the named file. + ParserInput input = ParserInput.readFile("my/file.star"); + StarlarkFile file = StarlarkFile.parse(input); + + // Compile the program, with additional predeclared environment bindings. + Program prog = Program.compileFile(file, () -> ImmutableSet.of("zero", "square")); + + // . . . + + // TODO(adonovan): when supported, show how the compiled program can be + // saved and reloaded, to avoid repeating the cost of parsing and + // compilation. + + // Execute the compiled program to populate a module. + // The module's predeclared environment must match the + // names provided during compilation. + Module module = Module.withPredeclared(StarlarkSemantics.DEFAULT, makeEnvironment()); + try (Mutability mu = Mutability.create(prog.getFilename())) { + StarlarkThread thread = new StarlarkThread(mu, StarlarkSemantics.DEFAULT); + Starlark.execFileProgram(prog, module, thread); + } + return module; + } + + /** This function shows how to construct a callable Starlark value from a Java method. */ + ImmutableMap makeEnvironment() { + ImmutableMap.Builder env = ImmutableMap.builder(); + env.put("zero", 0); + Starlark.addMethods(env, new MyFunctions(), StarlarkSemantics.DEFAULT); // adds 'square' + return env.build(); + } + + /** The methods of this class are accessible from Starlark. */ + @StarlarkGlobalLibrary + static final class MyFunctions { + @StarlarkMethod( + name = "square", + parameters = {@Param(name = "x", type = int.class)}, + doc = "Returns the square of its integer argument.") + public int square(int x) { + return x * x; + } + } +}