/* * Copyright (c) 2012, the Dart project authors. * * Licensed under the Eclipse Public License v1.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.eclipse.org/legal/epl-v10.html * * 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.dart.engine.internal.sdk; import com.google.dart.engine.ast.BooleanLiteral; import com.google.dart.engine.ast.CompilationUnit; import com.google.dart.engine.ast.Expression; import com.google.dart.engine.ast.InstanceCreationExpression; import com.google.dart.engine.ast.MapLiteralEntry; import com.google.dart.engine.ast.NamedExpression; import com.google.dart.engine.ast.SimpleIdentifier; import com.google.dart.engine.ast.SimpleStringLiteral; import com.google.dart.engine.ast.visitor.RecursiveAstVisitor; import com.google.dart.engine.error.BooleanErrorListener; import com.google.dart.engine.parser.Parser; import com.google.dart.engine.scanner.CharSequenceReader; import com.google.dart.engine.scanner.Scanner; import com.google.dart.engine.source.FileBasedSource; import com.google.dart.engine.source.Source; import java.io.File; import java.util.List; /** * Instances of the class {@code SdkLibrariesReader} read and parse the libraries file * (dart-sdk/lib/_internal/libraries.dart) for information about the libraries in an SDK. The * library information is represented as a Dart file containing a single top-level variable whose * value is a const map. The keys of the map are the names of libraries defined in the SDK and the * values in the map are info objects defining the library. For example, a subset of a typical SDK * might have a libraries file that looks like the following: * * <pre> * final Map<String, LibraryInfo> LIBRARIES = const <LibraryInfo> { * // Used by VM applications * "builtin" : const LibraryInfo( * "builtin/builtin_runtime.dart", * category: "Server", * platforms: VM_PLATFORM), * * "compiler" : const LibraryInfo( * "compiler/compiler.dart", * category: "Tools", * platforms: 0), * }; * </pre> * * @coverage dart.engine.sdk */ public class SdkLibrariesReader { public static class LibraryBuilder extends RecursiveAstVisitor<Void> { /** * The prefix added to the name of a library to form the URI used in code to reference the * library. */ private static final String LIBRARY_PREFIX = "dart:"; //$NON-NLS-1$ /** * The name of the optional parameter used to indicate whether the library is an implementation * library. */ private static final String IMPLEMENTATION = "implementation"; //$NON-NLS-1$ /** * The name of the optional parameter used to specify the path used when compiling for dart2js. */ private static final String DART2JS_PATH = "dart2jsPath"; //$NON-NLS-1$ /** * The name of the optional parameter used to indicate whether the library is documented. */ private static final String DOCUMENTED = "documented"; //$NON-NLS-1$ /** * The name of the optional parameter used to specify the category of the library. */ private static final String CATEGORY = "category"; //$NON-NLS-1$ /** * The name of the optional parameter used to specify the platforms on which the library can be * used. */ private static final String PLATFORMS = "platforms"; //$NON-NLS-1$ /** * The value of the {@link #PLATFORMS platforms} parameter used to specify that the library can * be used on the VM. */ private static final String VM_PLATFORM = "VM_PLATFORM"; //$NON-NLS-1$ /** * A flag indicating whether the dart2js path should be used when it is available. */ private boolean useDart2jsPaths; /** * The library map that is populated by visiting the AST structure parsed from the contents of * the libraries file. */ private LibraryMap librariesMap = new LibraryMap(); /** * Initialize a newly created library builder to use the dart2js path if the given value is * {@code true}. * * @param useDart2jsPaths {@code true} if the dart2js path should be used when it is available */ public LibraryBuilder(boolean useDart2jsPaths) { this.useDart2jsPaths = useDart2jsPaths; } /** * Return the library map that was populated by visiting the AST structure parsed from the * contents of the libraries file. * * @return the library map describing the contents of the SDK */ public LibraryMap getLibrariesMap() { return librariesMap; } @Override public Void visitMapLiteralEntry(MapLiteralEntry node) { String libraryName = null; Expression key = node.getKey(); if (key instanceof SimpleStringLiteral) { libraryName = LIBRARY_PREFIX + ((SimpleStringLiteral) key).getValue(); } Expression value = node.getValue(); if (value instanceof InstanceCreationExpression) { SdkLibraryImpl library = new SdkLibraryImpl(libraryName); List<Expression> arguments = ((InstanceCreationExpression) value).getArgumentList().getArguments(); for (Expression argument : arguments) { if (argument instanceof SimpleStringLiteral) { library.setPath(((SimpleStringLiteral) argument).getValue()); } else if (argument instanceof NamedExpression) { String name = ((NamedExpression) argument).getName().getLabel().getName(); Expression expression = ((NamedExpression) argument).getExpression(); if (name.equals(CATEGORY)) { library.setCategory(((SimpleStringLiteral) expression).getValue()); } else if (name.equals(IMPLEMENTATION)) { library.setImplementation(((BooleanLiteral) expression).getValue()); } else if (name.equals(DOCUMENTED)) { library.setDocumented(((BooleanLiteral) expression).getValue()); } else if (name.equals(PLATFORMS)) { if (expression instanceof SimpleIdentifier) { String identifier = ((SimpleIdentifier) expression).getName(); if (identifier.equals(VM_PLATFORM)) { library.setVmLibrary(); } else { library.setDart2JsLibrary(); } } } else if (useDart2jsPaths && name.equals(DART2JS_PATH)) { if (expression instanceof SimpleStringLiteral) { library.setPath(((SimpleStringLiteral) expression).getValue()); } } } } librariesMap.setLibrary(libraryName, library); } return null; } } /** * A flag indicating whether the dart2js path should be used when it is available. */ private boolean useDart2jsPaths; /** * Initialize a newly created library reader to use the dart2js path if the given value is * {@code true}. * * @param useDart2jsPaths {@code true} if the dart2js path should be used when it is available */ public SdkLibrariesReader(boolean useDart2jsPaths) { this.useDart2jsPaths = useDart2jsPaths; } /** * Return the library map read from the given source. * * @param file the {@link File} of the library file * @param libraryFileContents the contents from the library file * @return the library map read from the given source */ public LibraryMap readFromFile(File file, String libraryFileContents) { return readFromSource(new FileBasedSource(file), libraryFileContents); } /** * Return the library map read from the given source. * * @param source the source of the library file * @param libraryFileContents the contents from the library file * @return the library map read from the given source */ public LibraryMap readFromSource(Source source, String libraryFileContents) { BooleanErrorListener errorListener = new BooleanErrorListener(); Scanner scanner = new Scanner( source, new CharSequenceReader(libraryFileContents), errorListener); Parser parser = new Parser(source, errorListener); CompilationUnit unit = parser.parseCompilationUnit(scanner.tokenize()); LibraryBuilder libraryBuilder = new LibraryBuilder(useDart2jsPaths); // If any syntactic errors were found then don't try to visit the AST structure. if (!errorListener.getErrorReported()) { unit.accept(libraryBuilder); } return libraryBuilder.getLibrariesMap(); } }