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 | |
Miguel Alcon Pinto | 927f3b2 | 2016-08-22 14:21:30 +0000 | [diff] [blame^] | 16 | import com.google.common.annotations.VisibleForTesting; |
Laurent Le Brun | 8e965b8 | 2016-08-03 11:50:24 +0000 | [diff] [blame] | 17 | import com.google.common.base.Joiner; |
Miguel Alcon Pinto | 927f3b2 | 2016-08-22 14:21:30 +0000 | [diff] [blame^] | 18 | import com.google.common.base.Preconditions; |
| 19 | import com.google.common.collect.ImmutableBiMap; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 20 | import com.google.common.collect.ImmutableList; |
Miguel Alcon Pinto | 927f3b2 | 2016-08-22 14:21:30 +0000 | [diff] [blame^] | 21 | import com.google.common.collect.ImmutableMap; |
Lukacs Berki | 4833822 | 2015-06-12 11:37:46 +0000 | [diff] [blame] | 22 | import com.google.common.hash.HashCode; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 23 | import com.google.devtools.build.lib.events.Event; |
| 24 | import com.google.devtools.build.lib.events.EventHandler; |
| 25 | import com.google.devtools.build.lib.events.Location; |
Miguel Alcon Pinto | 927f3b2 | 2016-08-22 14:21:30 +0000 | [diff] [blame^] | 26 | import com.google.devtools.build.lib.syntax.Parser.ParseResult; |
| 27 | import com.google.devtools.build.lib.syntax.SkylarkImports.SkylarkImportSyntaxException; |
| 28 | import com.google.devtools.build.lib.util.Pair; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 29 | import com.google.devtools.build.lib.vfs.Path; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 30 | import java.io.IOException; |
Miguel Alcon Pinto | 927f3b2 | 2016-08-22 14:21:30 +0000 | [diff] [blame^] | 31 | import java.util.HashMap; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 32 | import java.util.List; |
Miguel Alcon Pinto | 927f3b2 | 2016-08-22 14:21:30 +0000 | [diff] [blame^] | 33 | import java.util.Map; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 34 | import javax.annotation.Nullable; |
| 35 | |
| 36 | /** |
| 37 | * Abstract syntax node for an entire BUILD file. |
| 38 | */ |
| 39 | public class BuildFileAST extends ASTNode { |
| 40 | |
| 41 | private final ImmutableList<Statement> stmts; |
| 42 | |
| 43 | private final ImmutableList<Comment> comments; |
| 44 | |
Miguel Alcon Pinto | 927f3b2 | 2016-08-22 14:21:30 +0000 | [diff] [blame^] | 45 | @Nullable private final Map<String, SkylarkImport> imports; |
Laurent Le Brun | 6190ffb | 2015-07-01 16:24:56 +0000 | [diff] [blame] | 46 | |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 47 | /** |
| 48 | * Whether any errors were encountered during scanning or parsing. |
| 49 | */ |
| 50 | private final boolean containsErrors; |
| 51 | |
Miguel Alcon Pinto | 927f3b2 | 2016-08-22 14:21:30 +0000 | [diff] [blame^] | 52 | @Nullable private final String contentHashCode; |
Lukacs Berki | f445ea1 | 2015-07-09 07:16:41 +0000 | [diff] [blame] | 53 | |
Damien Martin-Guillerez | 5e95a46 | 2016-02-05 22:32:08 +0000 | [diff] [blame] | 54 | private BuildFileAST( |
| 55 | ImmutableList<Statement> stmts, |
| 56 | boolean containsErrors, |
| 57 | String contentHashCode, |
Laurent Le Brun | 8c8857d | 2016-08-04 10:22:16 +0000 | [diff] [blame] | 58 | Location location, |
Miguel Alcon Pinto | 927f3b2 | 2016-08-22 14:21:30 +0000 | [diff] [blame^] | 59 | ImmutableList<Comment> comments, |
| 60 | @Nullable Map<String, SkylarkImport> imports) { |
Damien Martin-Guillerez | 5e95a46 | 2016-02-05 22:32:08 +0000 | [diff] [blame] | 61 | this.stmts = stmts; |
| 62 | this.containsErrors = containsErrors; |
| 63 | this.contentHashCode = contentHashCode; |
Laurent Le Brun | 8c8857d | 2016-08-04 10:22:16 +0000 | [diff] [blame] | 64 | this.comments = comments; |
Damien Martin-Guillerez | 5e95a46 | 2016-02-05 22:32:08 +0000 | [diff] [blame] | 65 | this.setLocation(location); |
Miguel Alcon Pinto | 927f3b2 | 2016-08-22 14:21:30 +0000 | [diff] [blame^] | 66 | this.imports = imports; |
| 67 | } |
| 68 | |
| 69 | private static BuildFileAST create( |
| 70 | List<Statement> preludeStatements, |
| 71 | ParseResult result, |
| 72 | String contentHashCode, |
| 73 | EventHandler eventHandler) { |
| 74 | ImmutableList<Statement> stmts = |
| 75 | ImmutableList.<Statement>builder() |
| 76 | .addAll(preludeStatements) |
| 77 | .addAll(result.statements) |
| 78 | .build(); |
| 79 | |
| 80 | boolean containsErrors = result.containsErrors; |
| 81 | Pair<Boolean, Map<String, SkylarkImport>> skylarkImports = fetchLoads(stmts, eventHandler); |
| 82 | containsErrors |= skylarkImports.first; |
| 83 | return new BuildFileAST( |
| 84 | stmts, |
| 85 | containsErrors, |
| 86 | contentHashCode, |
| 87 | result.location, |
| 88 | ImmutableList.copyOf(result.comments), |
| 89 | skylarkImports.second); |
Damien Martin-Guillerez | 5e95a46 | 2016-02-05 22:32:08 +0000 | [diff] [blame] | 90 | } |
| 91 | |
| 92 | /** |
| 93 | * Extract a subtree containing only statements from {@code firstStatement} (included) up to |
| 94 | * {@code lastStatement} excluded. |
| 95 | */ |
| 96 | public BuildFileAST subTree(int firstStatement, int lastStatement) { |
Miguel Alcon Pinto | 927f3b2 | 2016-08-22 14:21:30 +0000 | [diff] [blame^] | 97 | ImmutableList<Statement> stmts = this.stmts.subList(firstStatement, lastStatement); |
| 98 | ImmutableMap.Builder<String, SkylarkImport> imports = ImmutableBiMap.builder(); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 99 | for (Statement stmt : stmts) { |
| 100 | if (stmt instanceof LoadStatement) { |
Miguel Alcon Pinto | 927f3b2 | 2016-08-22 14:21:30 +0000 | [diff] [blame^] | 101 | String str = ((LoadStatement) stmt).getImport(); |
| 102 | imports.put( |
| 103 | str, |
| 104 | Preconditions.checkNotNull( |
| 105 | this.imports.get(str), "%s cannot be found. This is an internal error.", str)); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 106 | } |
| 107 | } |
Miguel Alcon Pinto | 927f3b2 | 2016-08-22 14:21:30 +0000 | [diff] [blame^] | 108 | return new BuildFileAST( |
| 109 | stmts, |
| 110 | containsErrors, |
| 111 | null, |
| 112 | this.stmts.get(firstStatement).getLocation(), |
| 113 | ImmutableList.<Comment>of(), |
| 114 | imports.build()); |
| 115 | } |
| 116 | |
| 117 | /** |
| 118 | * Collects all load statements. Returns a pair with a boolean saying if there were errors and the |
| 119 | * imports that could be resolved. |
| 120 | */ |
| 121 | @VisibleForTesting |
| 122 | static Pair<Boolean, Map<String, SkylarkImport>> fetchLoads( |
| 123 | List<Statement> stmts, EventHandler eventHandler) { |
| 124 | Map<String, SkylarkImport> imports = new HashMap<>(); |
| 125 | boolean error = false; |
| 126 | for (Statement stmt : stmts) { |
| 127 | if (stmt instanceof LoadStatement) { |
| 128 | String importString = ((LoadStatement) stmt).getImport(); |
| 129 | try { |
| 130 | SkylarkImport imp = SkylarkImports.create(importString); |
| 131 | imports.put(importString, imp); |
| 132 | } catch (SkylarkImportSyntaxException e) { |
| 133 | eventHandler.handle(Event.error(stmt.getLocation(), e.getMessage())); |
| 134 | error = true; |
| 135 | } |
| 136 | } |
| 137 | } |
| 138 | return Pair.of(error, imports); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 139 | } |
| 140 | |
| 141 | /** |
| 142 | * Returns true if any errors were encountered during scanning or parsing. If |
| 143 | * set, clients should not rely on the correctness of the AST for builds or |
| 144 | * BUILD-file editing. |
| 145 | */ |
| 146 | public boolean containsErrors() { |
| 147 | return containsErrors; |
| 148 | } |
| 149 | |
| 150 | /** |
| 151 | * Returns an (immutable, ordered) list of statements in this BUILD file. |
| 152 | */ |
| 153 | public ImmutableList<Statement> getStatements() { |
| 154 | return stmts; |
| 155 | } |
| 156 | |
| 157 | /** |
| 158 | * Returns an (immutable, ordered) list of comments in this BUILD file. |
| 159 | */ |
| 160 | public ImmutableList<Comment> getComments() { |
| 161 | return comments; |
| 162 | } |
| 163 | |
Miguel Alcon Pinto | 927f3b2 | 2016-08-22 14:21:30 +0000 | [diff] [blame^] | 164 | /** Returns a list of loads in this BUILD file. */ |
| 165 | public ImmutableList<SkylarkImport> getImports() { |
| 166 | Preconditions.checkNotNull(imports, "computeImports Should be called in parse* methods"); |
| 167 | return ImmutableList.copyOf(imports.values()); |
Laurent Le Brun | 6190ffb | 2015-07-01 16:24:56 +0000 | [diff] [blame] | 168 | } |
| 169 | |
Miguel Alcon Pinto | 927f3b2 | 2016-08-22 14:21:30 +0000 | [diff] [blame^] | 170 | /** Returns a list of loads as strings in this BUILD file. */ |
| 171 | public synchronized ImmutableList<String> getRawImports() { |
| 172 | ImmutableList.Builder<String> imports = ImmutableList.builder(); |
| 173 | |
| 174 | for (Statement stmt : stmts) { |
| 175 | if (stmt instanceof LoadStatement) { |
| 176 | imports.add(((LoadStatement) stmt).getImport()); |
| 177 | } |
| 178 | } |
| 179 | return imports.build(); |
| 180 | } |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 181 | /** |
| 182 | * Executes this build file in a given Environment. |
| 183 | * |
Miguel Alcon Pinto | 927f3b2 | 2016-08-22 14:21:30 +0000 | [diff] [blame^] | 184 | * <p>If, for any reason, execution of a statement cannot be completed, an {@link EvalException} |
| 185 | * is thrown by {@link Statement#exec(Environment)}. This exception is caught here and reported |
| 186 | * through reporter and execution continues on the next statement. In effect, there is a |
| 187 | * "try/except" block around every top level statement. Such exceptions are not ignored, though: |
| 188 | * they are visible via the return value. Rules declared in a package containing any error |
| 189 | * (including loading-phase semantical errors that cannot be checked here) must also be considered |
| 190 | * "in error". |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 191 | * |
Miguel Alcon Pinto | 927f3b2 | 2016-08-22 14:21:30 +0000 | [diff] [blame^] | 192 | * <p>Note that this method will not affect the value of {@link #containsErrors()}; that refers |
| 193 | * only to lexer/parser errors. |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 194 | * |
| 195 | * @return true if no error occurred during execution. |
| 196 | */ |
| 197 | public boolean exec(Environment env, EventHandler eventHandler) throws InterruptedException { |
| 198 | boolean ok = true; |
| 199 | for (Statement stmt : stmts) { |
| 200 | try { |
| 201 | stmt.exec(env); |
| 202 | } catch (EvalException e) { |
| 203 | ok = false; |
| 204 | // Do not report errors caused by a previous parsing error, as it has already been |
| 205 | // reported. |
| 206 | if (e.isDueToIncompleteAST()) { |
| 207 | continue; |
| 208 | } |
| 209 | // When the exception is raised from another file, report first the location in the |
| 210 | // BUILD file (as it is the most probable cause for the error). |
| 211 | Location exnLoc = e.getLocation(); |
| 212 | Location nodeLoc = stmt.getLocation(); |
Florian Weikert | 3f610e8 | 2015-08-18 14:37:46 +0000 | [diff] [blame] | 213 | eventHandler.handle(Event.error( |
| 214 | (exnLoc == null || !nodeLoc.getPath().equals(exnLoc.getPath())) ? nodeLoc : exnLoc, |
| 215 | e.getMessage())); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 216 | } |
| 217 | } |
| 218 | return ok; |
| 219 | } |
| 220 | |
| 221 | @Override |
| 222 | public String toString() { |
| 223 | return "BuildFileAST" + getStatements(); |
| 224 | } |
| 225 | |
| 226 | @Override |
| 227 | public void accept(SyntaxTreeVisitor visitor) { |
| 228 | visitor.visit(this); |
| 229 | } |
| 230 | |
| 231 | /** |
| 232 | * Parse the specified build file, returning its AST. All errors during |
| 233 | * scanning or parsing will be reported to the reporter. |
| 234 | * |
| 235 | * @throws IOException if the file cannot not be read. |
| 236 | */ |
Laurent Le Brun | f1112b3 | 2016-08-03 13:16:02 +0000 | [diff] [blame] | 237 | public static BuildFileAST parseBuildFile(Path buildFile, EventHandler eventHandler) |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 238 | throws IOException { |
Laurent Le Brun | f1112b3 | 2016-08-03 13:16:02 +0000 | [diff] [blame] | 239 | return parseBuildFile(buildFile, buildFile.getFileSize(), eventHandler); |
Nathan Harmata | 7f24022 | 2015-09-13 02:03:26 +0000 | [diff] [blame] | 240 | } |
| 241 | |
| 242 | public static BuildFileAST parseBuildFile(Path buildFile, long fileSize, |
Laurent Le Brun | f1112b3 | 2016-08-03 13:16:02 +0000 | [diff] [blame] | 243 | EventHandler eventHandler) |
Nathan Harmata | 7f24022 | 2015-09-13 02:03:26 +0000 | [diff] [blame] | 244 | throws IOException { |
| 245 | ParserInputSource inputSource = ParserInputSource.create(buildFile, fileSize); |
Laurent Le Brun | f1112b3 | 2016-08-03 13:16:02 +0000 | [diff] [blame] | 246 | return parseBuildFile(inputSource, eventHandler); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 247 | } |
| 248 | |
| 249 | /** |
| 250 | * Parse the specified build file, returning its AST. All errors during |
| 251 | * scanning or parsing will be reported to the reporter. |
| 252 | */ |
| 253 | public static BuildFileAST parseBuildFile(ParserInputSource input, |
| 254 | List<Statement> preludeStatements, |
Laurent Le Brun | f1112b3 | 2016-08-03 13:16:02 +0000 | [diff] [blame] | 255 | EventHandler eventHandler) { |
| 256 | Parser.ParseResult result = Parser.parseFile(input, eventHandler, false); |
Miguel Alcon Pinto | 927f3b2 | 2016-08-22 14:21:30 +0000 | [diff] [blame^] | 257 | return create(preludeStatements, result, /*contentHashCode=*/ null, eventHandler); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 258 | } |
| 259 | |
Laurent Le Brun | f1112b3 | 2016-08-03 13:16:02 +0000 | [diff] [blame] | 260 | public static BuildFileAST parseBuildFile(ParserInputSource input, EventHandler eventHandler) { |
| 261 | Parser.ParseResult result = Parser.parseFile(input, eventHandler, false); |
Miguel Alcon Pinto | 927f3b2 | 2016-08-22 14:21:30 +0000 | [diff] [blame^] | 262 | return create(ImmutableList.<Statement>of(), result, /*contentHashCode=*/ null, eventHandler); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 263 | } |
| 264 | |
| 265 | /** |
Laurent Le Brun | 8c8857d | 2016-08-04 10:22:16 +0000 | [diff] [blame] | 266 | * Parse the specified Skylark file, returning its AST. All errors during scanning or parsing will |
| 267 | * be reported to the reporter. |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 268 | * |
| 269 | * @throws IOException if the file cannot not be read. |
| 270 | */ |
Laurent Le Brun | 8c8857d | 2016-08-04 10:22:16 +0000 | [diff] [blame] | 271 | public static BuildFileAST parseSkylarkFile(Path file, EventHandler eventHandler) |
| 272 | throws IOException { |
| 273 | return parseSkylarkFile(file, file.getFileSize(), eventHandler); |
Nathan Harmata | 7f24022 | 2015-09-13 02:03:26 +0000 | [diff] [blame] | 274 | } |
| 275 | |
Laurent Le Brun | 8c8857d | 2016-08-04 10:22:16 +0000 | [diff] [blame] | 276 | public static BuildFileAST parseSkylarkFile(Path file, long fileSize, EventHandler eventHandler) |
| 277 | throws IOException { |
Nathan Harmata | 7f24022 | 2015-09-13 02:03:26 +0000 | [diff] [blame] | 278 | ParserInputSource input = ParserInputSource.create(file, fileSize); |
Laurent Le Brun | 8c8857d | 2016-08-04 10:22:16 +0000 | [diff] [blame] | 279 | Parser.ParseResult result = Parser.parseFileForSkylark(input, eventHandler); |
Miguel Alcon Pinto | 927f3b2 | 2016-08-22 14:21:30 +0000 | [diff] [blame^] | 280 | return create( |
| 281 | ImmutableList.<Statement>of(), result, |
| 282 | HashCode.fromBytes(file.getMD5Digest()).toString(), eventHandler); |
| 283 | } |
| 284 | |
| 285 | /** |
| 286 | * Parse the specified non-build Skylark file but avoid the validation of the imports, returning |
| 287 | * its AST. All errors during scanning or parsing will be reported to the reporter. |
| 288 | * |
| 289 | * <p>This method should not be used in Bazel code, since it doesn't validate that the imports are |
| 290 | * syntactically valid. |
| 291 | * |
| 292 | * @throws IOException if the file cannot not be read. |
| 293 | */ |
| 294 | public static BuildFileAST parseSkylarkFileWithoutImports( |
| 295 | ParserInputSource input, EventHandler eventHandler) throws IOException { |
| 296 | ParseResult result = Parser.parseFileForSkylark(input, eventHandler); |
| 297 | return new BuildFileAST( |
| 298 | ImmutableList.<Statement>builder() |
| 299 | .addAll(ImmutableList.<Statement>of()) |
| 300 | .addAll(result.statements) |
| 301 | .build(), |
| 302 | result.containsErrors, /*contentHashCode=*/ |
| 303 | null, |
| 304 | result.location, |
| 305 | ImmutableList.copyOf(result.comments), /*imports=*/ |
| 306 | null); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 307 | } |
| 308 | |
Laurent Le Brun | 8c8857d | 2016-08-04 10:22:16 +0000 | [diff] [blame] | 309 | /** |
| 310 | * Run static checks on the AST. |
| 311 | * |
| 312 | * @return a new AST (or the same), with the containsErrors flag updated. |
| 313 | */ |
| 314 | public BuildFileAST validate(ValidationEnvironment validationEnv, EventHandler eventHandler) { |
| 315 | boolean valid = validationEnv.validateAst(stmts, eventHandler); |
| 316 | if (valid || containsErrors) { |
| 317 | return this; |
| 318 | } |
Miguel Alcon Pinto | 927f3b2 | 2016-08-22 14:21:30 +0000 | [diff] [blame^] | 319 | return new BuildFileAST(stmts, true, contentHashCode, getLocation(), comments, imports); |
Laurent Le Brun | 8c8857d | 2016-08-04 10:22:16 +0000 | [diff] [blame] | 320 | } |
| 321 | |
Laurent Le Brun | 8e965b8 | 2016-08-03 11:50:24 +0000 | [diff] [blame] | 322 | public static BuildFileAST parseBuildString(EventHandler eventHandler, String... content) { |
| 323 | String str = Joiner.on("\n").join(content); |
| 324 | ParserInputSource input = ParserInputSource.create(str, null); |
| 325 | Parser.ParseResult result = Parser.parseFile(input, eventHandler, false); |
Miguel Alcon Pinto | 927f3b2 | 2016-08-22 14:21:30 +0000 | [diff] [blame^] | 326 | return create(ImmutableList.<Statement>of(), result, null, eventHandler); |
Laurent Le Brun | 8e965b8 | 2016-08-03 11:50:24 +0000 | [diff] [blame] | 327 | } |
| 328 | |
| 329 | // TODO(laurentlb): Merge parseSkylarkString and parseBuildString. |
| 330 | public static BuildFileAST parseSkylarkString(EventHandler eventHandler, String... content) { |
| 331 | String str = Joiner.on("\n").join(content); |
| 332 | ParserInputSource input = ParserInputSource.create(str, null); |
Laurent Le Brun | 8c8857d | 2016-08-04 10:22:16 +0000 | [diff] [blame] | 333 | Parser.ParseResult result = Parser.parseFileForSkylark(input, eventHandler); |
Miguel Alcon Pinto | 927f3b2 | 2016-08-22 14:21:30 +0000 | [diff] [blame^] | 334 | return create(ImmutableList.<Statement>of(), result, null, eventHandler); |
Laurent Le Brun | 8e965b8 | 2016-08-03 11:50:24 +0000 | [diff] [blame] | 335 | } |
| 336 | |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 337 | /** |
| 338 | * Parse the specified build file, without building the AST. |
| 339 | * |
| 340 | * @return true if the input file is syntactically valid |
| 341 | */ |
Laurent Le Brun | f1112b3 | 2016-08-03 13:16:02 +0000 | [diff] [blame] | 342 | public static boolean checkSyntax( |
| 343 | ParserInputSource input, EventHandler eventHandler, boolean parsePython) { |
| 344 | Parser.ParseResult result = Parser.parseFile(input, eventHandler, parsePython); |
| 345 | return !result.containsErrors; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 346 | } |
| 347 | |
| 348 | /** |
Laurent Le Brun | 8e965b8 | 2016-08-03 11:50:24 +0000 | [diff] [blame] | 349 | * Evaluates the code and return the value of the last statement if it's an |
| 350 | * Expression or else null. |
| 351 | */ |
| 352 | @Nullable public Object eval(Environment env) throws EvalException, InterruptedException { |
| 353 | Object last = null; |
| 354 | for (Statement statement : stmts) { |
| 355 | if (statement instanceof ExpressionStatement) { |
| 356 | last = ((ExpressionStatement) statement).getExpression().eval(env); |
| 357 | } else { |
| 358 | statement.exec(env); |
| 359 | last = null; |
| 360 | } |
| 361 | } |
| 362 | return last; |
| 363 | } |
| 364 | |
| 365 | /** |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 366 | * Returns a hash code calculated from the string content of the source file of this AST. |
| 367 | */ |
| 368 | @Nullable public String getContentHashCode() { |
| 369 | return contentHashCode; |
| 370 | } |
| 371 | } |