Removing copy of lib from test
diff --git a/pkgs/markdown/test/LICENSE b/pkgs/markdown/test/LICENSE deleted file mode 100644 index 81764fd..0000000 --- a/pkgs/markdown/test/LICENSE +++ /dev/null
@@ -1,24 +0,0 @@ -Copyright 2012, the Dart project authors. All rights reserved. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file
diff --git a/pkgs/markdown/test/lib/classify.dart b/pkgs/markdown/test/lib/classify.dart deleted file mode 100644 index 2838fbd..0000000 --- a/pkgs/markdown/test/lib/classify.dart +++ /dev/null
@@ -1,209 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library classify; - -import 'src/compiler/implementation/scanner/scannerlib.dart'; -// TODO(rnystrom): Use "package:" URL (#4968). -import 'markdown.dart' as md; - -/** - * Kinds of tokens that we care to highlight differently. The values of the - * fields here will be used as CSS class names for the generated spans. - */ -class Classification { - static const NONE = null; - static const ERROR = "e"; - static const COMMENT = "c"; - static const IDENTIFIER = "i"; - static const KEYWORD = "k"; - static const OPERATOR = "o"; - static const STRING = "s"; - static const NUMBER = "n"; - static const PUNCTUATION = "p"; - - // A few things that are nice to make different: - static const TYPE_IDENTIFIER = "t"; - - // Between a keyword and an identifier - static const SPECIAL_IDENTIFIER = "r"; - - static const ARROW_OPERATOR = "a"; - - static const STRING_INTERPOLATION = 'si'; -} - -/// Returns a marked up HTML string. If the code does not appear to be valid -/// Dart code, returns the original [text]. -String classifySource(String text) { - try { - var html = new StringBuffer(); - var tokenizer = new StringScanner(text, includeComments: true); - - var whitespaceOffset = 0; - var token = tokenizer.tokenize(); - var inString = false; - while (token.kind != EOF_TOKEN) { - html.add(text.substring(whitespaceOffset, token.charOffset)); - whitespaceOffset = token.charOffset + token.slowCharCount; - - // Track whether or not we're in a string. - switch (token.kind) { - case STRING_TOKEN: - case STRING_INTERPOLATION_TOKEN: - inString = true; - break; - } - - final kind = classify(token); - final escapedText = md.escapeHtml(token.slowToString()); - if (kind != null) { - // Add a secondary class to tokens appearing within a string so that - // we can highlight tokens in an interpolation specially. - var stringClass = inString ? Classification.STRING_INTERPOLATION : ''; - html.add('<span class="$kind $stringClass">$escapedText</span>'); - } else { - html.add(escapedText); - } - - // Track whether or not we're in a string. - if (token.kind == STRING_TOKEN) { - inString = false; - } - token = token.next; - } - return html.toString(); - } catch (e) { - return text; - } -} - -bool _looksLikeType(String name) { - // If the name looks like an UppercaseName, assume it's a type. - return _looksLikePublicType(name) || _looksLikePrivateType(name); -} - -bool _looksLikePublicType(String name) { - // If the name looks like an UppercaseName, assume it's a type. - return name.length >= 2 && isUpper(name[0]) && isLower(name[1]); -} - -bool _looksLikePrivateType(String name) { - // If the name looks like an _UppercaseName, assume it's a type. - return (name.length >= 3 && name[0] == '_' && isUpper(name[1]) - && isLower(name[2])); -} - -// These ensure that they don't return "true" if the string only has symbols. -bool isUpper(String s) => s.toLowerCase() != s; -bool isLower(String s) => s.toUpperCase() != s; - -String classify(Token token) { - switch (token.kind) { - case UNKNOWN_TOKEN: - return Classification.ERROR; - - case IDENTIFIER_TOKEN: - // Special case for names that look like types. - final text = token.slowToString(); - if (_looksLikeType(text) - || text == 'num' - || text == 'bool' - || text == 'int' - || text == 'double') { - return Classification.TYPE_IDENTIFIER; - } - return Classification.IDENTIFIER; - - case STRING_TOKEN: - case STRING_INTERPOLATION_TOKEN: - return Classification.STRING; - - case INT_TOKEN: - case HEXADECIMAL_TOKEN: - case DOUBLE_TOKEN: - return Classification.NUMBER; - - case COMMENT_TOKEN: - return Classification.COMMENT; - - // => is so awesome it is in a class of its own. - case FUNCTION_TOKEN: - return Classification.ARROW_OPERATOR; - - case OPEN_PAREN_TOKEN: - case CLOSE_PAREN_TOKEN: - case OPEN_SQUARE_BRACKET_TOKEN: - case CLOSE_SQUARE_BRACKET_TOKEN: - case OPEN_CURLY_BRACKET_TOKEN: - case CLOSE_CURLY_BRACKET_TOKEN: - case COLON_TOKEN: - case SEMICOLON_TOKEN: - case COMMA_TOKEN: - case PERIOD_TOKEN: - case PERIOD_PERIOD_TOKEN: - return Classification.PUNCTUATION; - - case PLUS_PLUS_TOKEN: - case MINUS_MINUS_TOKEN: - case TILDE_TOKEN: - case BANG_TOKEN: - case EQ_TOKEN: - case BAR_EQ_TOKEN: - case CARET_EQ_TOKEN: - case AMPERSAND_EQ_TOKEN: - case LT_LT_EQ_TOKEN: - case GT_GT_EQ_TOKEN: - case PLUS_EQ_TOKEN: - case MINUS_EQ_TOKEN: - case STAR_EQ_TOKEN: - case SLASH_EQ_TOKEN: - case TILDE_SLASH_EQ_TOKEN: - case PERCENT_EQ_TOKEN: - case QUESTION_TOKEN: - case BAR_BAR_TOKEN: - case AMPERSAND_AMPERSAND_TOKEN: - case BAR_TOKEN: - case CARET_TOKEN: - case AMPERSAND_TOKEN: - case LT_LT_TOKEN: - case GT_GT_TOKEN: - case PLUS_TOKEN: - case MINUS_TOKEN: - case STAR_TOKEN: - case SLASH_TOKEN: - case TILDE_SLASH_TOKEN: - case PERCENT_TOKEN: - case EQ_EQ_TOKEN: - case BANG_EQ_TOKEN: - case EQ_EQ_EQ_TOKEN: - case BANG_EQ_EQ_TOKEN: - case LT_TOKEN: - case GT_TOKEN: - case LT_EQ_TOKEN: - case GT_EQ_TOKEN: - case INDEX_TOKEN: - case INDEX_EQ_TOKEN: - return Classification.OPERATOR; - - // Color keyword token. Most are colored as keywords. - case HASH_TOKEN: - case KEYWORD_TOKEN: - if (token.stringValue == 'void') { - // Color "void" as a type. - return Classification.TYPE_IDENTIFIER; - } - if (token.stringValue == 'this' || token.stringValue == 'super') { - // Color "this" and "super" as identifiers. - return Classification.SPECIAL_IDENTIFIER; - } - return Classification.KEYWORD; - - case EOF_TOKEN: - return Classification.NONE; - - default: - return Classification.NONE; - } -}
diff --git a/pkgs/markdown/test/lib/markdown.dart b/pkgs/markdown/test/lib/markdown.dart deleted file mode 100644 index ef111fb..0000000 --- a/pkgs/markdown/test/lib/markdown.dart +++ /dev/null
@@ -1,118 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/// Parses text in a markdown-like format and renders to HTML. -library markdown; - -import 'classify.dart'; - -// TODO(rnystrom): Use "package:" URL (#4968). -part 'src/markdown/ast.dart'; -part 'src/markdown/block_parser.dart'; -part 'src/markdown/html_renderer.dart'; -part 'src/markdown/inline_parser.dart'; - -/// Converts the given string of markdown to HTML. -String markdownToHtml(String markdown) { - final document = new Document(); - - // Replace windows line endings with unix line endings, and split. - final lines = markdown.replaceAll('\r\n','\n').split('\n'); - document.parseRefLinks(lines); - final blocks = document.parseLines(lines); - return renderToHtml(blocks); -} - -/// Replaces `<`, `&`, and `>`, with their HTML entity equivalents. -String escapeHtml(String html) { - return html.replaceAll('&', '&') - .replaceAll('<', '<') - .replaceAll('>', '>'); -} - -var _implicitLinkResolver; - -Node setImplicitLinkResolver(Node resolver(String text)) { - _implicitLinkResolver = resolver; -} - -/// Maintains the context needed to parse a markdown document. -class Document { - final Map<String, Link> refLinks; - - Document() - : refLinks = <String, Link>{}; - - parseRefLinks(List<String> lines) { - // This is a hideous regex. It matches: - // [id]: http:foo.com "some title" - // Where there may whitespace in there, and where the title may be in - // single quotes, double quotes, or parentheses. - final indent = r'^[ ]{0,3}'; // Leading indentation. - final id = r'\[([^\]]+)\]'; // Reference id in [brackets]. - final quote = r'"[^"]+"'; // Title in "double quotes". - final apos = r"'[^']+'"; // Title in 'single quotes'. - final paren = r"\([^)]+\)"; // Title in (parentheses). - final pattern = new RegExp( - '$indent$id:\\s+(\\S+)\\s*($quote|$apos|$paren|)\\s*\$'); - - for (int i = 0; i < lines.length; i++) { - final match = pattern.firstMatch(lines[i]); - if (match != null) { - // Parse the link. - var id = match[1]; - var url = match[2]; - var title = match[3]; - - if (title == '') { - // No title. - title = null; - } else { - // Remove "", '', or (). - title = title.substring(1, title.length - 1); - } - - // References are case-insensitive. - id = id.toLowerCase(); - - refLinks[id] = new Link(id, url, title); - - // Remove it from the output. We replace it with a blank line which will - // get consumed by later processing. - lines[i] = ''; - } - } - } - - /// Parse the given [lines] of markdown to a series of AST nodes. - List<Node> parseLines(List<String> lines) { - final parser = new BlockParser(lines, this); - - final blocks = []; - while (!parser.isDone) { - for (final syntax in BlockSyntax.syntaxes) { - if (syntax.canParse(parser)) { - final block = syntax.parse(parser); - if (block != null) blocks.add(block); - break; - } - } - } - - return blocks; - } - - /// Takes a string of raw text and processes all inline markdown tags, - /// returning a list of AST nodes. For example, given ``"*this **is** a* - /// `markdown`"``, returns: - /// `<em>this <strong>is</strong> a</em> <code>markdown</code>`. - List<Node> parseInline(String text) => new InlineParser(text, this).parse(); -} - -class Link { - final String id; - final String url; - final String title; - Link(this.id, this.url, this.title); -}
diff --git a/pkgs/markdown/test/lib/src/compiler/compiler.dart b/pkgs/markdown/test/lib/src/compiler/compiler.dart deleted file mode 100644 index bbee705..0000000 --- a/pkgs/markdown/test/lib/src/compiler/compiler.dart +++ /dev/null
@@ -1,177 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library compiler; - -import 'dart:async'; -import 'dart:uri'; -import 'implementation/apiimpl.dart'; - -// Unless explicitly allowed, passing [:null:] for any argument to the -// methods of library will result in an Error being thrown. - -/** - * Returns a future that completes to the source corresponding to - * [uri]. If an exception occurs, the future completes with this - * exception. - */ -typedef Future<String> CompilerInputProvider(Uri uri); - -/// Deprecated, please use [CompilerInputProvider] instead. -typedef Future<String> ReadStringFromUri(Uri uri); - -/** - * Returns a [StreamSink] that will serve as compiler output for the given - * component. - * - * Components are identified by [name] and [extension]. By convention, - * the empty string [:"":] will represent the main script - * (corresponding to the script parameter of [compile]) even if the - * main script is a library. For libraries that are compiled - * separately, the library name is used. - * - * At least the following extensions can be expected: - * - * * "js" for JavaScript output. - * * "js.map" for source maps. - * * "dart" for Dart output. - * * "dart.map" for source maps. - * - * As more features are added to the compiler, new names and - * extensions may be introduced. - */ -typedef StreamSink<String> CompilerOutputProvider(String name, - String extension); - -/** - * Invoked by the compiler to report diagnostics. If [uri] is - * [:null:], so are [begin] and [end]. No other arguments may be - * [:null:]. If [uri] is not [:null:], neither are [begin] and - * [end]. [uri] indicates the compilation unit from where the - * diagnostic originates. [begin] and [end] are zero-based character - * offsets from the beginning of the compilaton unit. [message] is the - * diagnostic message, and [kind] indicates indicates what kind of - * diagnostic it is. - */ -typedef void DiagnosticHandler(Uri uri, int begin, int end, - String message, Diagnostic kind); - -/** - * Returns a future that completes to a non-null String when [script] - * has been successfully compiled. - * - * The compiler output is obtained by providing an [outputProvider]. - * - * If the compilation fails, the future's value will be [:null:] and - * [handler] will have been invoked at least once with [:kind == - * Diagnostic.ERROR:] or [:kind == Diagnostic.CRASH:]. - * - * Deprecated: if no [outputProvider] is given, the future completes - * to the compiled script. This behavior will be removed in the future - * as the compiler may create multiple files to support lazy loading - * of libraries. - */ -Future<String> compile(Uri script, - Uri libraryRoot, - Uri packageRoot, - CompilerInputProvider inputProvider, - DiagnosticHandler handler, - [List<String> options = const [], - CompilerOutputProvider outputProvider]) { - if (!libraryRoot.path.endsWith("/")) { - throw new ArgumentError("libraryRoot must end with a /"); - } - if (packageRoot != null && !packageRoot.path.endsWith("/")) { - throw new ArgumentError("packageRoot must end with a /"); - } - // TODO(ahe): Consider completing the future with an exception if - // code is null. - Compiler compiler = new Compiler(inputProvider, - outputProvider, - handler, - libraryRoot, - packageRoot, - options); - compiler.run(script); - String code = compiler.assembledCode; - if (code != null && outputProvider != null) { - String outputType = 'js'; - if (options.contains('--output-type=dart')) { - outputType = 'dart'; - } - outputProvider('', outputType) - ..add(code) - ..close(); - code = ''; // Non-null signals success. - } - return new Future.immediate(code); -} - -/** - * Kind of diagnostics that the compiler can report. - */ -class Diagnostic { - /** - * An error as identified by the "Dart Programming Language - * Specification" [http://www.dartlang.org/docs/spec/]. - * - * Note: the compiler may still produce an executable result after - * reporting a compilation error. The specification says: - * - * "A compile-time error must be reported by a Dart compiler before - * the erroneous code is executed." and "If a compile-time error - * occurs within the code of a running isolate A, A is immediately - * suspended." - * - * This means that the compiler can generate code that when executed - * terminates execution. - */ - static const Diagnostic ERROR = const Diagnostic(1, 'error'); - - /** - * A warning as identified by the "Dart Programming Language - * Specification" [http://www.dartlang.org/docs/spec/]. - */ - static const Diagnostic WARNING = const Diagnostic(2, 'warning'); - - /** - * Any other warning that is not covered by [WARNING]. - */ - static const Diagnostic LINT = const Diagnostic(4, 'lint'); - - /** - * Informational messages. - */ - static const Diagnostic INFO = const Diagnostic(8, 'info'); - - /** - * Informational messages that shouldn't be printed unless - * explicitly requested by the user of a compiler. - */ - static const Diagnostic VERBOSE_INFO = const Diagnostic(16, 'verbose info'); - - /** - * An internal error in the compiler. - */ - static const Diagnostic CRASH = const Diagnostic(32, 'crash'); - - /** - * An [int] representation of this kind. The ordinals are designed - * to be used as bitsets. - */ - final int ordinal; - - /** - * The name of this kind. - */ - final String name; - - /** - * This constructor is not private to support user-defined - * diagnostic kinds. - */ - const Diagnostic(this.ordinal, this.name); - - String toString() => name; -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/README.txt b/pkgs/markdown/test/lib/src/compiler/implementation/README.txt deleted file mode 100644 index 8fe0a29..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/README.txt +++ /dev/null
@@ -1,12 +0,0 @@ -Dart2JS is the Dart-to-JavaScript compiler for Dart. This compiler -will provide high-quality translation from Dart to JavaScript. - -Some areas that will explored in this project are: - - * high-performance extensible scanner and parser - * concrete type inferencing - * fancy language tool support - * programming environment integration - * SSA-based intermediate representation - * adaptive compilation on the client -
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/apiimpl.dart b/pkgs/markdown/test/lib/src/compiler/implementation/apiimpl.dart deleted file mode 100644 index 663e003..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/apiimpl.dart +++ /dev/null
@@ -1,266 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library leg_apiimpl; - -import 'dart:uri'; -import 'dart:async'; - -import '../compiler.dart' as api; -import 'dart2jslib.dart' as leg; -import 'tree/tree.dart' as tree; -import 'elements/elements.dart' as elements; -import 'ssa/tracer.dart' as ssa; -import '../../libraries.dart'; -import 'source_file.dart'; - -class Compiler extends leg.Compiler { - api.ReadStringFromUri provider; - api.DiagnosticHandler handler; - final Uri libraryRoot; - final Uri packageRoot; - List<String> options; - bool mockableLibraryUsed = false; - final Set<String> allowedLibraryCategories; - - Compiler(this.provider, - api.CompilerOutputProvider outputProvider, - this.handler, - this.libraryRoot, - this.packageRoot, - List<String> options) - : this.options = options, - this.allowedLibraryCategories = getAllowedLibraryCategories(options), - super( - tracer: new ssa.HTracer(), - outputProvider: outputProvider, - enableTypeAssertions: hasOption(options, '--enable-checked-mode'), - enableUserAssertions: hasOption(options, '--enable-checked-mode'), - enableMinification: hasOption(options, '--minify'), - enableNativeLiveTypeAnalysis: - !hasOption(options, '--disable-native-live-type-analysis'), - emitJavaScript: !hasOption(options, '--output-type=dart'), - disallowUnsafeEval: hasOption(options, '--disallow-unsafe-eval'), - analyzeAll: hasOption(options, '--analyze-all'), - analyzeOnly: hasOption(options, '--analyze-only'), - rejectDeprecatedFeatures: - hasOption(options, '--reject-deprecated-language-features'), - checkDeprecationInSdk: - hasOption(options, - '--report-sdk-use-of-deprecated-language-features'), - strips: getStrips(options), - enableConcreteTypeInference: - hasOption(options, '--enable-concrete-type-inference'), - preserveComments: hasOption(options, '--preserve-comments')) { - if (!libraryRoot.path.endsWith("/")) { - throw new ArgumentError("libraryRoot must end with a /"); - } - if (packageRoot != null && !packageRoot.path.endsWith("/")) { - throw new ArgumentError("packageRoot must end with a /"); - } - } - - static List<String> getStrips(List<String> options) { - for (String option in options) { - if (option.startsWith('--force-strip=')) { - return option.substring('--force-strip='.length).split(','); - } - } - return const <String>[]; - } - - static Set<String> getAllowedLibraryCategories(List<String> options) { - for (String option in options) { - if (option.startsWith('--categories=')) { - var result = option.substring('--categories='.length).split(','); - result.add('Shared'); - result.add('Internal'); - return new Set<String>.from(result); - } - } - return new Set<String>.from(['Client', 'Shared', 'Internal']); - } - - static bool hasOption(List<String> options, String option) { - return options.indexOf(option) >= 0; - } - - // TODO(johnniwinther): Merge better with [translateDartUri] when - // [scanBuiltinLibrary] is removed. - String lookupLibraryPath(String dartLibraryName) { - LibraryInfo info = LIBRARIES[dartLibraryName]; - if (info == null) return null; - if (!info.isDart2jsLibrary) return null; - if (!allowedLibraryCategories.contains(info.category)) return null; - String path = info.dart2jsPath; - if (path == null) { - path = info.path; - } - return "lib/$path"; - } - - String lookupPatchPath(String dartLibraryName) { - LibraryInfo info = LIBRARIES[dartLibraryName]; - if (info == null) return null; - if (!info.isDart2jsLibrary) return null; - String path = info.dart2jsPatchPath; - if (path == null) return null; - return "lib/$path"; - } - - elements.LibraryElement scanBuiltinLibrary(String path) { - Uri uri = libraryRoot.resolve(lookupLibraryPath(path)); - Uri canonicalUri = new Uri.fromComponents(scheme: "dart", path: path); - elements.LibraryElement library = - libraryLoader.loadLibrary(uri, null, canonicalUri); - return library; - } - - void log(message) { - handler(null, null, null, message, api.Diagnostic.VERBOSE_INFO); - } - - /// See [leg.Compiler.translateResolvedUri]. - Uri translateResolvedUri(elements.LibraryElement importingLibrary, - Uri resolvedUri, tree.Node node) { - if (resolvedUri.scheme == 'dart') { - return translateDartUri(importingLibrary, resolvedUri, node); - } - return resolvedUri; - } - - /** - * Reads the script designated by [readableUri]. - */ - leg.Script readScript(Uri readableUri, [tree.Node node]) { - if (!readableUri.isAbsolute()) { - internalError('Relative uri $readableUri provided to readScript(Uri)', - node: node); - } - return fileReadingTask.measure(() { - Uri resourceUri = translateUri(readableUri, node); - String text = ""; - try { - // TODO(ahe): We expect the future to be complete and call value - // directly. In effect, we don't support truly asynchronous API. - text = deprecatedFutureValue(provider(resourceUri)); - } catch (exception) { - if (node != null) { - cancel("$exception", node: node); - } else { - reportDiagnostic(null, "$exception", api.Diagnostic.ERROR); - throw new leg.CompilerCancelledException("$exception"); - } - } - SourceFile sourceFile = new SourceFile(resourceUri.toString(), text); - // We use [readableUri] as the URI for the script since need to preserve - // the scheme in the script because [Script.uri] is used for resolving - // relative URIs mentioned in the script. See the comment on - // [LibraryLoader] for more details. - return new leg.Script(readableUri, sourceFile); - }); - } - - /** - * Translates a readable URI into a resource URI. - * - * See [LibraryLoader] for terminology on URIs. - */ - Uri translateUri(Uri readableUri, tree.Node node) { - switch (readableUri.scheme) { - case 'package': return translatePackageUri(readableUri, node); - default: return readableUri; - } - } - - Uri translateDartUri(elements.LibraryElement importingLibrary, - Uri resolvedUri, tree.Node node) { - LibraryInfo libraryInfo = LIBRARIES[resolvedUri.path]; - String path = lookupLibraryPath(resolvedUri.path); - if (libraryInfo != null && - libraryInfo.category == "Internal") { - bool allowInternalLibraryAccess = false; - if (importingLibrary != null) { - if (importingLibrary.isPlatformLibrary || importingLibrary.isPatch) { - allowInternalLibraryAccess = true; - } else if (importingLibrary.canonicalUri.path.contains( - 'dart/tests/compiler/dart2js_native')) { - allowInternalLibraryAccess = true; - } - } - if (!allowInternalLibraryAccess) { - if (node != null && importingLibrary != null) { - reportDiagnostic(spanFromNode(node), - 'Error: Internal library $resolvedUri is not accessible from ' - '${importingLibrary.canonicalUri}.', - api.Diagnostic.ERROR); - } else { - reportDiagnostic(null, - 'Error: Internal library $resolvedUri is not accessible.', - api.Diagnostic.ERROR); - } - //path = null; - } - } - if (path == null) { - if (node != null) { - reportError(node, 'library not found ${resolvedUri}'); - } else { - reportDiagnostic(null, 'library not found ${resolvedUri}', - api.Diagnostic.ERROR); - } - return null; - } - if (resolvedUri.path == 'html' || - resolvedUri.path == 'io') { - // TODO(ahe): Get rid of mockableLibraryUsed when test.dart - // supports this use case better. - mockableLibraryUsed = true; - } - return libraryRoot.resolve(path); - } - - Uri resolvePatchUri(String dartLibraryPath) { - String patchPath = lookupPatchPath(dartLibraryPath); - if (patchPath == null) return null; - return libraryRoot.resolve(patchPath); - } - - translatePackageUri(Uri uri, tree.Node node) => packageRoot.resolve(uri.path); - - bool run(Uri uri) { - log('Allowed library categories: $allowedLibraryCategories'); - bool success = super.run(uri); - int cumulated = 0; - for (final task in tasks) { - cumulated += task.timing; - log('${task.name} took ${task.timing}msec'); - } - int total = totalCompileTime.elapsedMilliseconds; - log('Total compile-time ${total}msec;' - ' unaccounted ${total - cumulated}msec'); - return success; - } - - void reportDiagnostic(leg.SourceSpan span, String message, - api.Diagnostic kind) { - if (identical(kind, api.Diagnostic.ERROR) - || identical(kind, api.Diagnostic.CRASH)) { - compilationFailed = true; - } - // [:span.uri:] might be [:null:] in case of a [Script] with no [uri]. For - // instance in the [Types] constructor in typechecker.dart. - if (span == null || span.uri == null) { - handler(null, null, null, message, kind); - } else { - handler(translateUri(span.uri, null), span.begin, span.end, - message, kind); - } - } - - bool get isMockCompilation { - return mockableLibraryUsed - && (options.indexOf('--allow-mock-compilation') != -1); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/closure.dart b/pkgs/markdown/test/lib/src/compiler/implementation/closure.dart deleted file mode 100644 index 4ed1564..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/closure.dart +++ /dev/null
@@ -1,663 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library closureToClassMapper; - -import "elements/elements.dart"; -import "dart2jslib.dart"; -import "dart_types.dart"; -import "scanner/scannerlib.dart" show Token; -import "tree/tree.dart"; -import "util/util.dart"; -import "elements/modelx.dart" show ElementX, FunctionElementX, ClassElementX; - -abstract class ClosureNamer { - SourceString getClosureVariableName(SourceString name, int id); -} - - -class ClosureTask extends CompilerTask { - Map<Node, ClosureClassMap> closureMappingCache; - ClosureNamer namer; - ClosureTask(Compiler compiler, this.namer) - : closureMappingCache = new Map<Node, ClosureClassMap>(), - super(compiler); - - String get name => "Closure Simplifier"; - - ClosureClassMap computeClosureToClassMapping(Element element, - Expression node, - TreeElements elements) { - return measure(() { - ClosureClassMap cached = closureMappingCache[node]; - if (cached != null) return cached; - - ClosureTranslator translator = - new ClosureTranslator(compiler, elements, closureMappingCache, namer); - - // The translator will store the computed closure-mappings inside the - // cache. One for given node and one for each nested closure. - if (node is FunctionExpression) { - translator.translateFunction(element, node); - } else { - // Must be the lazy initializer of a static. - assert(node is SendSet); - translator.translateLazyInitializer(element, node); - } - assert(closureMappingCache[node] != null); - return closureMappingCache[node]; - }); - } - - ClosureClassMap getMappingForNestedFunction(FunctionExpression node) { - return measure(() { - ClosureClassMap nestedClosureData = closureMappingCache[node]; - if (nestedClosureData == null) { - compiler.internalError("No closure cache", node: node); - } - return nestedClosureData; - }); - } -} - -class ClosureFieldElement extends ElementX { - ClosureFieldElement(SourceString name, ClassElement enclosing) - : super(name, ElementKind.FIELD, enclosing); - - bool isInstanceMember() => true; - bool isAssignable() => false; - // The names of closure variables don't need renaming, since their use is very - // simple and they have 1-character names in the minified mode. - bool hasFixedBackendName() => true; - String fixedBackendName() => name.slowToString(); - - DartType computeType(Compiler compiler) => compiler.types.dynamicType; - - String toString() => "ClosureFieldElement($name)"; -} - -class ClosureClassElement extends ClassElementX { - ClosureClassElement(SourceString name, - Compiler compiler, - this.methodElement, - Element enclosingElement) - : super(name, - enclosingElement, - // By assigning a fresh class-id we make sure that the hashcode - // is unique, but also emit closure classes after all other - // classes (since the emitter sorts classes by their id). - compiler.getNextFreeClassId(), - STATE_DONE) { - compiler.closureClass.ensureResolved(compiler); - supertype = compiler.closureClass.computeType(compiler); - interfaces = const Link<DartType>(); - allSupertypes = const Link<DartType>().prepend(supertype); - } - - bool isClosure() => true; - - /** - * The most outer method this closure is declared into. - */ - Element methodElement; -} - -class BoxElement extends ElementX { - BoxElement(SourceString name, Element enclosingElement) - : super(name, ElementKind.VARIABLE, enclosingElement); -} - -class ThisElement extends ElementX { - ThisElement(Element enclosing) - : super(const SourceString('this'), ElementKind.PARAMETER, enclosing); - - bool isAssignable() => false; - - // Since there is no declaration corresponding to 'this', use the position of - // the enclosing method. - Token position() => enclosingElement.position(); -} - -class CheckVariableElement extends ElementX { - Element parameter; - CheckVariableElement(SourceString name, this.parameter, Element enclosing) - : super(name, ElementKind.VARIABLE, enclosing); - - // Since there is no declaration for the synthetic 'check' variable, use - // parameter. - Token position() => parameter.position(); -} - -// The box-element for a scope, and the captured variables that need to be -// stored in the box. -class ClosureScope { - Element boxElement; - Map<Element, Element> capturedVariableMapping; - // If the scope is attached to a [For] contains the variables that are - // declared in the initializer of the [For] and that need to be boxed. - // Otherwise contains the empty List. - List<Element> boxedLoopVariables; - - ClosureScope(this.boxElement, this.capturedVariableMapping) - : boxedLoopVariables = const <Element>[]; - - bool hasBoxedLoopVariables() => !boxedLoopVariables.isEmpty; -} - -class ClosureClassMap { - // The closure's element before any translation. Will be null for methods. - final Element closureElement; - // The closureClassElement will be null for methods that are not local - // closures. - final ClassElement closureClassElement; - // The callElement will be null for methods that are not local closures. - final FunctionElement callElement; - // The [thisElement] makes handling 'this' easier by treating it like any - // other argument. It is only set for instance-members. - final ThisElement thisElement; - - // Maps free locals, arguments and function elements to their captured - // copies. - final Map<Element, Element> freeVariableMapping; - // Maps closure-fields to their captured elements. This is somehow the inverse - // mapping of [freeVariableMapping], but whereas [freeVariableMapping] does - // not deal with boxes, here we map instance-fields (which might represent - // boxes) to their boxElement. - final Map<Element, Element> capturedFieldMapping; - - // Maps scopes ([Loop] and [FunctionExpression] nodes) to their - // [ClosureScope] which contains their box and the - // captured variables that are stored in the box. - // This map will be empty if the method/closure of this [ClosureData] does not - // contain any nested closure. - final Map<Node, ClosureScope> capturingScopes; - - final Set<Element> usedVariablesInTry; - - // A map from the parameter element to the variable element that - // holds the sentinel check. - final Map<Element, Element> parametersWithSentinel; - - ClosureClassMap(this.closureElement, - this.closureClassElement, - this.callElement, - this.thisElement) - : this.freeVariableMapping = new Map<Element, Element>(), - this.capturedFieldMapping = new Map<Element, Element>(), - this.capturingScopes = new Map<Node, ClosureScope>(), - this.usedVariablesInTry = new Set<Element>(), - this.parametersWithSentinel = new Map<Element, Element>(); - - bool isClosure() => closureElement != null; -} - -class ClosureTranslator extends Visitor { - final Compiler compiler; - final TreeElements elements; - int closureFieldCounter = 0; - int boxedFieldCounter = 0; - bool inTryStatement = false; - final Map<Node, ClosureClassMap> closureMappingCache; - - // Map of captured variables. Initially they will map to themselves. If - // a variable needs to be boxed then the scope declaring the variable - // will update this mapping. - Map<Element, Element> capturedVariableMapping; - // List of encountered closures. - List<Expression> closures; - - // The variables that have been declared in the current scope. - List<Element> scopeVariables; - - // Keep track of the mutated variables so that we don't need to box - // non-mutated variables. - Set<Element> mutatedVariables; - - Element outermostElement; - Element currentElement; - - // The closureData of the currentFunctionElement. - ClosureClassMap closureData; - - ClosureNamer namer; - - bool insideClosure = false; - - ClosureTranslator(this.compiler, this.elements, this.closureMappingCache, - this.namer) - : capturedVariableMapping = new Map<Element, Element>(), - closures = <Expression>[], - mutatedVariables = new Set<Element>(); - - void translateFunction(Element element, FunctionExpression node) { - // For constructors the [element] and the [:elements[node]:] may differ. - // The [:elements[node]:] always points to the generative-constructor - // element, whereas the [element] might be the constructor-body element. - visit(node); // [visitFunctionExpression] will call [visitInvokable]. - // When variables need to be boxed their [capturedVariableMapping] is - // updated, but we delay updating the similar freeVariableMapping in the - // closure datas that capture these variables. - // The closures don't have their fields (in the closure class) set, either. - updateClosures(); - } - - void translateLazyInitializer(Element element, SendSet node) { - assert(node.assignmentOperator.source == const SourceString("=")); - Expression initialValue = node.argumentsNode.nodes.head; - visitInvokable(element, node, () { visit(initialValue); }); - updateClosures(); - } - - // This function runs through all of the existing closures and updates their - // free variables to the boxed value. It also adds the field-elements to the - // class representing the closure. At the same time it fills the - // [capturedFieldMapping]. - void updateClosures() { - for (Expression closure in closures) { - // The captured variables that need to be stored in a field of the closure - // class. - Set<Element> fieldCaptures = new Set<Element>(); - Set<Element> boxes = new Set<Element>(); - ClosureClassMap data = closureMappingCache[closure]; - Map<Element, Element> freeVariableMapping = data.freeVariableMapping; - // We get a copy of the keys and iterate over it, to avoid modifications - // to the map while iterating over it. - freeVariableMapping.keys.toList().forEach((Element fromElement) { - assert(fromElement == freeVariableMapping[fromElement]); - Element updatedElement = capturedVariableMapping[fromElement]; - assert(updatedElement != null); - if (fromElement == updatedElement) { - assert(freeVariableMapping[fromElement] == updatedElement); - assert(Elements.isLocal(updatedElement) - || updatedElement.isTypeVariable()); - // The variable has not been boxed. - fieldCaptures.add(updatedElement); - } else { - // A boxed element. - freeVariableMapping[fromElement] = updatedElement; - Element boxElement = updatedElement.enclosingElement; - assert(boxElement.kind == ElementKind.VARIABLE); - boxes.add(boxElement); - } - }); - ClassElement closureElement = data.closureClassElement; - assert(closureElement != null || - (fieldCaptures.isEmpty && boxes.isEmpty)); - void addElement(Element element, SourceString name) { - Element fieldElement = new ClosureFieldElement(name, closureElement); - closureElement.addBackendMember(fieldElement); - data.capturedFieldMapping[fieldElement] = element; - freeVariableMapping[element] = fieldElement; - } - // Add the box elements first so we get the same ordering. - // TODO(sra): What is the canonical order of multiple boxes? - for (Element capturedElement in boxes) { - addElement(capturedElement, capturedElement.name); - } - for (Element capturedElement in - Elements.sortedByPosition(fieldCaptures)) { - int id = closureFieldCounter++; - SourceString name = - namer.getClosureVariableName(capturedElement.name, id); - addElement(capturedElement, name); - } - closureElement.reverseBackendMembers(); - } - } - - void useLocal(Element element) { - // If the element is not declared in the current function and the element - // is not the closure itself we need to mark the element as free variable. - // Note that the check on [insideClosure] is not just an - // optimization: factories have type parameters as function - // parameters, and type parameters are declared in the class, not - // the factory. - if (insideClosure && - element.enclosingElement != currentElement && - element != currentElement) { - assert(closureData.freeVariableMapping[element] == null || - closureData.freeVariableMapping[element] == element); - closureData.freeVariableMapping[element] = element; - } else if (inTryStatement) { - // Don't mark the this-element. This would complicate things in the - // builder. - if (element != closureData.thisElement) { - // TODO(ngeoffray): only do this if the variable is mutated. - closureData.usedVariablesInTry.add(element); - } - } - } - - void declareLocal(Element element) { - scopeVariables.add(element); - } - - visit(Node node) => node.accept(this); - - visitNode(Node node) => node.visitChildren(this); - - visitVariableDefinitions(VariableDefinitions node) { - for (Link<Node> link = node.definitions.nodes; - !link.isEmpty; - link = link.tail) { - Node definition = link.head; - Element element = elements[definition]; - assert(element != null); - declareLocal(element); - // We still need to visit the right-hand sides of the init-assignments. - // For SendSets don't visit the left again. Otherwise it would be marked - // as mutated. - if (definition is Send) { - Send assignment = definition; - Node arguments = assignment.argumentsNode; - if (arguments != null) { - visit(arguments); - } - } else { - visit(definition); - } - } - } - - visitIdentifier(Identifier node) { - if (node.isThis()) { - useLocal(closureData.thisElement); - } - node.visitChildren(this); - } - - visitSend(Send node) { - Element element = elements[node]; - if (Elements.isLocal(element)) { - useLocal(element); - } else if (node.receiver == null && - Elements.isInstanceSend(node, elements)) { - useLocal(closureData.thisElement); - } else if (node.isSuperCall) { - useLocal(closureData.thisElement); - } else if (node.isParameterCheck) { - Element parameter = elements[node.receiver]; - FunctionElement enclosing = parameter.enclosingElement; - FunctionExpression function = enclosing.parseNode(compiler); - ClosureClassMap cached = closureMappingCache[function]; - if (!cached.parametersWithSentinel.containsKey(parameter)) { - SourceString parameterName = parameter.name; - String name = '${parameterName.slowToString()}_check'; - Element newElement = new CheckVariableElement(new SourceString(name), - parameter, - enclosing); - useLocal(newElement); - cached.parametersWithSentinel[parameter] = newElement; - } - } - node.visitChildren(this); - } - - visitSendSet(SendSet node) { - Element element = elements[node]; - if (Elements.isLocal(element)) { - mutatedVariables.add(element); - } - super.visitSendSet(node); - } - - visitNewExpression(NewExpression node) { - DartType type = elements.getType(node); - - bool hasTypeVariable(DartType type) { - if (type is TypeVariableType) { - return true; - } else if (type is InterfaceType) { - InterfaceType ifcType = type; - for (DartType argument in ifcType.typeArguments) { - if (hasTypeVariable(argument)) { - return true; - } - } - } - return false; - } - - void analyzeTypeVariables(DartType type) { - if (type is TypeVariableType) { - useLocal(type.element); - } else if (type is InterfaceType) { - InterfaceType ifcType = type; - for (DartType argument in ifcType.typeArguments) { - analyzeTypeVariables(argument); - } - } - } - if (outermostElement.isMember() && - compiler.world.needsRti(outermostElement.getEnclosingClass())) { - if (outermostElement.isInstanceMember() - || outermostElement.isGenerativeConstructor()) { - if (hasTypeVariable(type)) useLocal(closureData.thisElement); - } else if (outermostElement.isFactoryConstructor()) { - analyzeTypeVariables(type); - } - } - - node.visitChildren(this); - } - - // If variables that are declared in the [node] scope are captured and need - // to be boxed create a box-element and update the [capturingScopes] in the - // current [closureData]. - // The boxed variables are updated in the [capturedVariableMapping]. - void attachCapturedScopeVariables(Node node) { - Element box = null; - Map<Element, Element> scopeMapping = new Map<Element, Element>(); - for (Element element in scopeVariables) { - // No need to box non-assignable elements. - if (!element.isAssignable()) continue; - if (!mutatedVariables.contains(element)) continue; - if (capturedVariableMapping.containsKey(element)) { - if (box == null) { - // TODO(floitsch): construct better box names. - SourceString boxName = - namer.getClosureVariableName(const SourceString('box'), - closureFieldCounter++); - box = new BoxElement(boxName, currentElement); - } - String elementName = element.name.slowToString(); - SourceString boxedName = - namer.getClosureVariableName(new SourceString(elementName), - boxedFieldCounter++); - // TODO(kasperl): Should this be a FieldElement instead? - Element boxed = new ElementX(boxedName, ElementKind.FIELD, box); - // No need to rename the fields of a box, so we give them a native name - // right now. - boxed.setFixedBackendName(boxedName.slowToString()); - scopeMapping[element] = boxed; - capturedVariableMapping[element] = boxed; - } - } - if (!scopeMapping.isEmpty) { - ClosureScope scope = new ClosureScope(box, scopeMapping); - closureData.capturingScopes[node] = scope; - } - } - - void inNewScope(Node node, Function action) { - List<Element> oldScopeVariables = scopeVariables; - scopeVariables = new List<Element>(); - action(); - attachCapturedScopeVariables(node); - for (Element element in scopeVariables) { - mutatedVariables.remove(element); - } - scopeVariables = oldScopeVariables; - } - - visitLoop(Loop node) { - inNewScope(node, () { - node.visitChildren(this); - }); - } - - visitFor(For node) { - visitLoop(node); - // See if we have declared loop variables that need to be boxed. - if (node.initializer == null) return; - VariableDefinitions definitions = node.initializer.asVariableDefinitions(); - if (definitions == null) return; - ClosureScope scopeData = closureData.capturingScopes[node]; - if (scopeData == null) return; - List<Element> result = <Element>[]; - for (Link<Node> link = definitions.definitions.nodes; - !link.isEmpty; - link = link.tail) { - Node definition = link.head; - Element element = elements[definition]; - if (capturedVariableMapping.containsKey(element)) { - result.add(element); - }; - } - scopeData.boxedLoopVariables = result; - } - - /** Returns a non-unique name for the given closure element. */ - String computeClosureName(Element element) { - Link<String> parts = const Link<String>(); - SourceString ownName = element.name; - if (ownName == null || ownName.stringValue == "") { - parts = parts.prepend("anon"); - } else { - parts = parts.prepend(ownName.slowToString()); - } - for (Element enclosingElement = element.enclosingElement; - enclosingElement != null && - (identical(enclosingElement.kind, - ElementKind.GENERATIVE_CONSTRUCTOR_BODY) - || identical(enclosingElement.kind, ElementKind.CLASS) - || identical(enclosingElement.kind, ElementKind.FUNCTION) - || identical(enclosingElement.kind, ElementKind.GETTER) - || identical(enclosingElement.kind, ElementKind.SETTER)); - enclosingElement = enclosingElement.enclosingElement) { - SourceString surroundingName = - Elements.operatorNameToIdentifier(enclosingElement.name); - parts = parts.prepend(surroundingName.slowToString()); - } - StringBuffer sb = new StringBuffer(); - parts.printOn(sb, '_'); - return sb.toString(); - } - - ClosureClassMap globalizeClosure(FunctionExpression node, Element element) { - SourceString closureName = new SourceString(computeClosureName(element)); - ClassElement globalizedElement = new ClosureClassElement( - closureName, compiler, element, element.getCompilationUnit()); - FunctionElement callElement = - new FunctionElementX.from(Compiler.CALL_OPERATOR_NAME, - element, - globalizedElement); - globalizedElement.addBackendMember(callElement); - // The nested function's 'this' is the same as the one for the outer - // function. It could be [null] if we are inside a static method. - Element thisElement = closureData.thisElement; - return new ClosureClassMap(element, globalizedElement, - callElement, thisElement); - } - - void visitInvokable(Element element, Expression node, void visitChildren()) { - bool oldInsideClosure = insideClosure; - Element oldFunctionElement = currentElement; - ClosureClassMap oldClosureData = closureData; - - insideClosure = outermostElement != null; - currentElement = element; - if (insideClosure) { - closures.add(node); - closureData = globalizeClosure(node, element); - } else { - outermostElement = element; - Element thisElement = null; - if (element.isInstanceMember() || element.isGenerativeConstructor()) { - thisElement = new ThisElement(element); - } - closureData = new ClosureClassMap(null, null, null, thisElement); - } - closureMappingCache[node] = closureData; - - inNewScope(node, () { - // We have to declare the implicit 'this' parameter. - if (!insideClosure && closureData.thisElement != null) { - declareLocal(closureData.thisElement); - } - // If we are inside a named closure we have to declare ourselve. For - // simplicity we declare the local even if the closure does not have a - // name. - // It will simply not be used. - if (insideClosure) { - declareLocal(element); - } - - if (currentElement.isFactoryConstructor() - && compiler.world.needsRti(currentElement.enclosingElement)) { - // Declare the type parameters in the scope. Generative - // constructors just use 'this'. - ClassElement cls = currentElement.enclosingElement; - cls.typeVariables.forEach((TypeVariableType typeVariable) { - declareLocal(typeVariable.element); - }); - } - - visitChildren(); - }); - - - ClosureClassMap savedClosureData = closureData; - bool savedInsideClosure = insideClosure; - - // Restore old values. - insideClosure = oldInsideClosure; - closureData = oldClosureData; - currentElement = oldFunctionElement; - - // Mark all free variables as captured and use them in the outer function. - Iterable<Element> freeVariables = savedClosureData.freeVariableMapping.keys; - assert(freeVariables.isEmpty || savedInsideClosure); - for (Element freeElement in freeVariables) { - if (capturedVariableMapping[freeElement] != null && - capturedVariableMapping[freeElement] != freeElement) { - compiler.internalError('In closure analyzer', node: node); - } - capturedVariableMapping[freeElement] = freeElement; - useLocal(freeElement); - } - } - - visitFunctionExpression(FunctionExpression node) { - Element element = elements[node]; - - if (element.isParameter()) { - // TODO(ahe): This is a hack. This method should *not* call - // visitChildren. - return node.name.accept(this); - } - - visitInvokable(element, node, () { - // TODO(ahe): This is problematic. The backend should not repeat - // the work of the resolver. It is the resolver's job to create - // parameters, etc. Other phases should only visit statements. - if (node.parameters != null) node.parameters.accept(this); - if (node.initializers != null) node.initializers.accept(this); - if (node.body != null) node.body.accept(this); - }); - } - - visitFunctionDeclaration(FunctionDeclaration node) { - node.visitChildren(this); - declareLocal(elements[node]); - } - - visitTryStatement(TryStatement node) { - // TODO(ngeoffray): implement finer grain state. - bool oldInTryStatement = inTryStatement; - inTryStatement = true; - node.visitChildren(this); - inTryStatement = oldInTryStatement; - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/code_buffer.dart b/pkgs/markdown/test/lib/src/compiler/implementation/code_buffer.dart deleted file mode 100644 index c3465e8..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/code_buffer.dart +++ /dev/null
@@ -1,106 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of dart2js; - -class CodeBuffer implements StringBuffer { - StringBuffer buffer; - List<CodeBufferMarker> markers; - int lastBufferOffset = 0; - int mappedRangeCounter = 0; - - CodeBuffer() - : buffer = new StringBuffer(), - markers = new List<CodeBufferMarker>(); - - int get length => buffer.length; - - bool get isEmpty { - return buffer.isEmpty; - } - - /** - * Converts [object] to a string and adds it to the buffer. If [object] is a - * [CodeBuffer], adds its markers to [markers]. - */ - CodeBuffer add(var object) { - if (object is CodeBuffer) { - return addBuffer(object); - } - if (mappedRangeCounter == 0) setSourceLocation(null); - buffer.add(object.toString()); - return this; - } - - CodeBuffer addBuffer(CodeBuffer other) { - if (other.markers.length > 0) { - CodeBufferMarker firstMarker = other.markers[0]; - int offsetDelta = - buffer.length + firstMarker.offsetDelta - lastBufferOffset; - markers.add(new CodeBufferMarker(offsetDelta, - firstMarker.sourcePosition)); - for (int i = 1; i < other.markers.length; ++i) { - markers.add(other.markers[i]); - } - lastBufferOffset = buffer.length + other.lastBufferOffset; - } - buffer.add(other.getText()); - } - - CodeBuffer addAll(Iterable<Object> iterable) { - for (Object obj in iterable) { - add(obj); - } - return this; - } - - CodeBuffer addCharCode(int charCode) { - return add(new String.fromCharCodes([charCode])); - } - - CodeBuffer clear() { - buffer.clear(); - markers.clear(); - lastBufferOffset = 0; - return this; - } - - String toString() { - throw "Don't use CodeBuffer.toString() since it drops sourcemap data."; - } - - String getText() { - return buffer.toString(); - } - - void beginMappedRange() { - ++mappedRangeCounter; - } - - void endMappedRange() { - assert(mappedRangeCounter > 0); - --mappedRangeCounter; - } - - void setSourceLocation(var sourcePosition) { - int offsetDelta = buffer.length - lastBufferOffset; - markers.add(new CodeBufferMarker(offsetDelta, sourcePosition)); - lastBufferOffset = buffer.length; - } - - void forEachSourceLocation(void f(int targetOffset, var sourcePosition)) { - int targetOffset = 0; - markers.forEach((marker) { - targetOffset += marker.offsetDelta; - f(targetOffset, marker.sourcePosition); - }); - } -} - -class CodeBufferMarker { - final int offsetDelta; - final sourcePosition; - - CodeBufferMarker(this.offsetDelta, this.sourcePosition); -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/colors.dart b/pkgs/markdown/test/lib/src/compiler/implementation/colors.dart deleted file mode 100644 index 42b3e7f..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/colors.dart +++ /dev/null
@@ -1,15 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library colors; - -const String GREEN_COLOR = '\u001b[32m'; -const String RED_COLOR = '\u001b[31m'; -const String MAGENTA_COLOR = '\u001b[35m'; -const String NO_COLOR = '\u001b[0m'; - -String wrap(String string, String color) => "${color}$string${NO_COLOR}"; -String green(String string) => wrap(string, GREEN_COLOR); -String red(String string) => wrap(string, RED_COLOR); -String magenta(String string) => wrap(string, MAGENTA_COLOR);
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/compile_time_constants.dart b/pkgs/markdown/test/lib/src/compiler/implementation/compile_time_constants.dart deleted file mode 100644 index 691cbac..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/compile_time_constants.dart +++ /dev/null
@@ -1,888 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of dart2js; - -/** - * The [ConstantHandler] keeps track of compile-time constants, - * initializations of global and static fields, and default values of - * optional parameters. - */ -class ConstantHandler extends CompilerTask { - final ConstantSystem constantSystem; - final bool isMetadata; - - /** - * Contains the initial value of fields. Must contain all static and global - * initializations of const fields. May contain eagerly compiled values for - * statics and instance fields. - */ - final Map<VariableElement, Constant> initialVariableValues; - - /** Set of all registered compiled constants. */ - final Set<Constant> compiledConstants; - - /** The set of variable elements that are in the process of being computed. */ - final Set<VariableElement> pendingVariables; - - /** Caches the statics where the initial value cannot be eagerly compiled. */ - final Set<VariableElement> lazyStatics; - - /** Caches the createRuntimeType function if registered. */ - Element createRuntimeTypeFunction = null; - - ConstantHandler(Compiler compiler, this.constantSystem, - { bool this.isMetadata: false }) - : initialVariableValues = new Map<VariableElement, dynamic>(), - compiledConstants = new Set<Constant>(), - pendingVariables = new Set<VariableElement>(), - lazyStatics = new Set<VariableElement>(), - super(compiler); - - String get name => 'ConstantHandler'; - - void registerCompileTimeConstant(Constant constant) { - registerInstantiatedClass(constant.computeType(compiler).element); - if (constant.isFunction()) { - FunctionConstant function = constant; - registerGetOfStaticFunction(function.element); - } - compiledConstants.add(constant); - } - - void registerInstantiatedClass(ClassElement element) { - if (isMetadata) return; - compiler.enqueuer.codegen.registerInstantiatedClass(element); - } - - void registerStaticUse(Element element) { - if (isMetadata) return; - compiler.enqueuer.codegen.registerStaticUse(element); - } - - void registerGetOfStaticFunction(FunctionElement element) { - if (isMetadata) return; - compiler.enqueuer.codegen.registerGetOfStaticFunction(element); - } - - void registerStringInstance() { - registerInstantiatedClass(compiler.stringClass); - } - - void registerCreateRuntimeTypeFunction() { - if (createRuntimeTypeFunction != null) return; - SourceString helperName = const SourceString('createRuntimeType'); - createRuntimeTypeFunction = compiler.findHelper(helperName); - registerStaticUse(createRuntimeTypeFunction); - } - - /** - * Compiles the initial value of the given field and stores it in an internal - * map. Returns the initial value (a constant) if it can be computed - * statically. Returns [:null:] if the variable must be initialized lazily. - * - * [work] must contain a [VariableElement] refering to a global or - * static field. - */ - Constant compileWorkItem(CodegenWorkItem work) { - return measure(() { - assert(work.element.kind == ElementKind.FIELD - || work.element.kind == ElementKind.PARAMETER - || work.element.kind == ElementKind.FIELD_PARAMETER); - VariableElement element = work.element; - // Shortcut if it has already been compiled. - Constant result = initialVariableValues[element]; - if (result != null) return result; - if (lazyStatics.contains(element)) return null; - result = compileVariableWithDefinitions(element, work.resolutionTree); - assert(pendingVariables.isEmpty); - return result; - }); - } - - /** - * Returns a compile-time constant, or reports an error if the element is not - * a compile-time constant. - */ - Constant compileConstant(VariableElement element) { - return compileVariable(element, isConst: true); - } - - /** - * Returns the a compile-time constant if the variable could be compiled - * eagerly. Otherwise returns `null`. - */ - Constant compileVariable(VariableElement element, {bool isConst: false}) { - return measure(() { - if (initialVariableValues.containsKey(element)) { - Constant result = initialVariableValues[element]; - return result; - } - return compiler.withCurrentElement(element, () { - TreeElements definitions = compiler.analyzeElement(element); - Constant constant = compileVariableWithDefinitions( - element, definitions, isConst: isConst); - return constant; - }); - }); - } - - /** - * Returns the a compile-time constant if the variable could be compiled - * eagerly. If the variable needs to be initialized lazily returns `null`. - * If the variable is `const` but cannot be compiled eagerly reports an - * error. - */ - Constant compileVariableWithDefinitions(VariableElement element, - TreeElements definitions, - {bool isConst: false}) { - return measure(() { - // Initializers for parameters must be const. - isConst = isConst || element.modifiers.isConst() - || !Elements.isStaticOrTopLevel(element); - if (!isConst && lazyStatics.contains(element)) return null; - - Node node = element.parseNode(compiler); - if (pendingVariables.contains(element)) { - if (isConst) { - MessageKind kind = MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS; - compiler.reportError(node, - new CompileTimeConstantError(kind)); - } else { - lazyStatics.add(element); - return null; - } - } - pendingVariables.add(element); - - SendSet assignment = node.asSendSet(); - Constant value; - if (assignment == null) { - // No initial value. - value = new NullConstant(); - } else { - Node right = assignment.arguments.head; - value = - compileNodeWithDefinitions(right, definitions, isConst: isConst); - if (compiler.enableTypeAssertions - && value != null - && element.isField()) { - DartType elementType = element.computeType(compiler); - DartType constantType = value.computeType(compiler); - if (elementType.isMalformed || constantType.isMalformed || - !constantSystem.isSubtype(compiler, constantType, elementType)) { - if (isConst) { - compiler.reportError(node, new CompileTimeConstantError( - MessageKind.NOT_ASSIGNABLE, - {'fromType': elementType, 'toType': constantType})); - } else { - // If the field can be lazily initialized, we will throw - // the exception at runtime. - value = null; - } - } - } - } - if (value != null) { - initialVariableValues[element] = value; - } else { - assert(!isConst); - lazyStatics.add(element); - } - pendingVariables.remove(element); - return value; - }); - } - - Constant compileNodeWithDefinitions(Node node, - TreeElements definitions, - {bool isConst: false}) { - return measure(() { - assert(node != null); - CompileTimeConstantEvaluator evaluator = new CompileTimeConstantEvaluator( - this, definitions, compiler, isConst: isConst); - return evaluator.evaluate(node); - }); - } - - /** Attempts to compile a constant expression. Returns null if not possible */ - Constant tryCompileNodeWithDefinitions(Node node, TreeElements definitions) { - return measure(() { - assert(node != null); - try { - TryCompileTimeConstantEvaluator evaluator = - new TryCompileTimeConstantEvaluator(this, definitions, compiler); - return evaluator.evaluate(node); - } on CompileTimeConstantError catch (exn) { - return null; - } - }); - } - - /** - * Returns an [Iterable] of static non final fields that need to be - * initialized. The fields list must be evaluated in order since they might - * depend on each other. - */ - Iterable<VariableElement> getStaticNonFinalFieldsForEmission() { - return initialVariableValues.keys.where((element) { - return element.kind == ElementKind.FIELD - && !element.isInstanceMember() - && !element.modifiers.isFinal() - // The const fields are all either emitted elsewhere or inlined. - && !element.modifiers.isConst(); - }); - } - - /** - * Returns an [Iterable] of static const fields that need to be initialized. - * The fields must be evaluated in order since they might depend on each - * other. - */ - Iterable<VariableElement> getStaticFinalFieldsForEmission() { - return initialVariableValues.keys.where((element) { - return element.kind == ElementKind.FIELD - && !element.isInstanceMember() - && element.modifiers.isFinal(); - }); - } - - List<VariableElement> getLazilyInitializedFieldsForEmission() { - return new List<VariableElement>.from(lazyStatics); - } - - List<Constant> getConstantsForEmission() { - // We must emit dependencies before their uses. - Set<Constant> seenConstants = new Set<Constant>(); - List<Constant> result = new List<Constant>(); - - void addConstant(Constant constant) { - if (!seenConstants.contains(constant)) { - constant.getDependencies().forEach(addConstant); - assert(!seenConstants.contains(constant)); - result.add(constant); - seenConstants.add(constant); - } - } - - compiledConstants.forEach(addConstant); - return result; - } - - Constant getInitialValueFor(VariableElement element) { - Constant initialValue = initialVariableValues[element]; - if (initialValue == null) { - compiler.internalError("No initial value for given element", - element: element); - } - return initialValue; - } -} - -class CompileTimeConstantEvaluator extends Visitor { - bool isEvaluatingConstant; - final ConstantHandler handler; - final TreeElements elements; - final Compiler compiler; - - CompileTimeConstantEvaluator(this.handler, - this.elements, - this.compiler, - {bool isConst: false}) - : this.isEvaluatingConstant = isConst; - - ConstantSystem get constantSystem => handler.constantSystem; - - Constant evaluate(Node node) { - return node.accept(this); - } - - Constant evaluateConstant(Node node) { - bool oldIsEvaluatingConstant = isEvaluatingConstant; - isEvaluatingConstant = true; - Constant result = node.accept(this); - isEvaluatingConstant = oldIsEvaluatingConstant; - assert(result != null); - return result; - } - - Constant visitNode(Node node) { - return signalNotCompileTimeConstant(node); - } - - Constant visitLiteralBool(LiteralBool node) { - handler.registerInstantiatedClass(compiler.boolClass); - return constantSystem.createBool(node.value); - } - - Constant visitLiteralDouble(LiteralDouble node) { - handler.registerInstantiatedClass(compiler.doubleClass); - return constantSystem.createDouble(node.value); - } - - Constant visitLiteralInt(LiteralInt node) { - handler.registerInstantiatedClass(compiler.intClass); - return constantSystem.createInt(node.value); - } - - Constant visitLiteralList(LiteralList node) { - if (!node.isConst()) { - return signalNotCompileTimeConstant(node); - } - List<Constant> arguments = <Constant>[]; - for (Link<Node> link = node.elements.nodes; - !link.isEmpty; - link = link.tail) { - arguments.add(evaluateConstant(link.head)); - } - // TODO(floitsch): get type parameters. - DartType type = new InterfaceType(compiler.listClass); - Constant constant = new ListConstant(type, arguments); - handler.registerCompileTimeConstant(constant); - return constant; - } - - Constant visitLiteralMap(LiteralMap node) { - if (!node.isConst()) { - return signalNotCompileTimeConstant(node); - } - List<StringConstant> keys = <StringConstant>[]; - Map<StringConstant, Constant> map = new Map<StringConstant, Constant>(); - for (Link<Node> link = node.entries.nodes; - !link.isEmpty; - link = link.tail) { - LiteralMapEntry entry = link.head; - Constant key = evaluateConstant(entry.key); - if (!key.isString() || entry.key.asStringNode() == null) { - MessageKind kind = MessageKind.KEY_NOT_A_STRING_LITERAL; - compiler.reportError(entry.key, new ResolutionError(kind)); - } - StringConstant keyConstant = key; - if (!map.containsKey(key)) keys.add(key); - map[key] = evaluateConstant(entry.value); - } - List<Constant> values = <Constant>[]; - Constant protoValue = null; - for (StringConstant key in keys) { - if (key.value == MapConstant.PROTO_PROPERTY) { - protoValue = map[key]; - } else { - values.add(map[key]); - } - } - bool hasProtoKey = (protoValue != null); - // TODO(floitsch): this should be a List<String> type. - DartType keysType = new InterfaceType(compiler.listClass); - ListConstant keysList = new ListConstant(keysType, keys); - handler.registerCompileTimeConstant(keysList); - SourceString className = hasProtoKey - ? MapConstant.DART_PROTO_CLASS - : MapConstant.DART_CLASS; - ClassElement classElement = compiler.jsHelperLibrary.find(className); - classElement.ensureResolved(compiler); - // TODO(floitsch): copy over the generic type. - DartType type = new InterfaceType(classElement); - handler.registerInstantiatedClass(classElement); - Constant constant = new MapConstant(type, keysList, values, protoValue); - handler.registerCompileTimeConstant(constant); - return constant; - } - - Constant visitLiteralNull(LiteralNull node) { - return constantSystem.createNull(); - } - - Constant visitLiteralString(LiteralString node) { - handler.registerStringInstance(); - return constantSystem.createString(node.dartString, node); - } - - Constant visitStringJuxtaposition(StringJuxtaposition node) { - StringConstant left = evaluate(node.first); - StringConstant right = evaluate(node.second); - if (left == null || right == null) return null; - handler.registerStringInstance(); - return constantSystem.createString( - new DartString.concat(left.value, right.value), node); - } - - Constant visitStringInterpolation(StringInterpolation node) { - StringConstant initialString = evaluate(node.string); - if (initialString == null) return null; - DartString accumulator = initialString.value; - for (StringInterpolationPart part in node.parts) { - Constant expression = evaluate(part.expression); - DartString expressionString; - if (expression == null) { - return signalNotCompileTimeConstant(part.expression); - } else if (expression.isNum() || expression.isBool()) { - PrimitiveConstant primitive = expression; - expressionString = new DartString.literal(primitive.value.toString()); - } else if (expression.isString()) { - PrimitiveConstant primitive = expression; - expressionString = primitive.value; - } else { - return signalNotCompileTimeConstant(part.expression); - } - accumulator = new DartString.concat(accumulator, expressionString); - StringConstant partString = evaluate(part.string); - if (partString == null) return null; - accumulator = new DartString.concat(accumulator, partString.value); - }; - handler.registerStringInstance(); - return constantSystem.createString(accumulator, node); - } - - Constant makeTypeConstant(Element element) { - DartType elementType = element.computeType(compiler).asRaw(); - DartType constantType = compiler.typeClass.computeType(compiler); - Constant constant = new TypeConstant(elementType, constantType); - // If we use a type literal in a constant, the compile time - // constant emitter will generate a call to the createRuntimeType - // helper so we register a use of that. - handler.registerCreateRuntimeTypeFunction(); - handler.registerCompileTimeConstant(constant); - return constant; - } - - // TODO(floitsch): provide better error-messages. - Constant visitSend(Send send) { - Element element = elements[send]; - if (send.isPropertyAccess) { - if (Elements.isStaticOrTopLevelFunction(element)) { - Constant constant = new FunctionConstant(element); - handler.registerCompileTimeConstant(constant); - return constant; - } else if (Elements.isStaticOrTopLevelField(element)) { - Constant result; - if (element.modifiers.isConst()) { - result = handler.compileConstant(element); - } else if (element.modifiers.isFinal() && !isEvaluatingConstant) { - result = handler.compileVariable(element); - } - if (result != null) return result; - } else if (Elements.isClass(element) || Elements.isTypedef(element)) { - return makeTypeConstant(element); - } else if (send.receiver != null) { - // Fall through to error handling. - } else if (!Elements.isUnresolved(element) - && element.isVariable() - && element.modifiers.isConst()) { - Constant result = handler.compileConstant(element); - if (result != null) return result; - } - return signalNotCompileTimeConstant(send); - } else if (send.isCall) { - if (identical(element, compiler.identicalFunction) - && send.argumentCount() == 2) { - Constant left = evaluate(send.argumentsNode.nodes.head); - Constant right = evaluate(send.argumentsNode.nodes.tail.head); - Constant result = constantSystem.identity.fold(left, right); - if (result != null) return result; - } else if (Elements.isClass(element) || Elements.isTypedef(element)) { - return makeTypeConstant(element); - } - return signalNotCompileTimeConstant(send); - } else if (send.isPrefix) { - assert(send.isOperator); - Constant receiverConstant = evaluate(send.receiver); - if (receiverConstant == null) return null; - Operator op = send.selector; - Constant folded; - switch (op.source.stringValue) { - case "!": - folded = constantSystem.not.fold(receiverConstant); - break; - case "-": - folded = constantSystem.negate.fold(receiverConstant); - break; - case "~": - folded = constantSystem.bitNot.fold(receiverConstant); - break; - default: - compiler.internalError("Unexpected operator.", node: op); - break; - } - if (folded == null) return signalNotCompileTimeConstant(send); - return folded; - } else if (send.isOperator && !send.isPostfix) { - assert(send.argumentCount() == 1); - Constant left = evaluate(send.receiver); - Constant right = evaluate(send.argumentsNode.nodes.head); - if (left == null || right == null) return null; - Operator op = send.selector.asOperator(); - Constant folded = null; - switch (op.source.stringValue) { - case "+": - folded = constantSystem.add.fold(left, right); - break; - case "-": - folded = constantSystem.subtract.fold(left, right); - break; - case "*": - folded = constantSystem.multiply.fold(left, right); - break; - case "/": - folded = constantSystem.divide.fold(left, right); - break; - case "%": - folded = constantSystem.modulo.fold(left, right); - break; - case "~/": - folded = constantSystem.truncatingDivide.fold(left, right); - break; - case "|": - folded = constantSystem.bitOr.fold(left, right); - break; - case "&": - folded = constantSystem.bitAnd.fold(left, right); - break; - case "^": - folded = constantSystem.bitXor.fold(left, right); - break; - case "||": - folded = constantSystem.booleanOr.fold(left, right); - break; - case "&&": - folded = constantSystem.booleanAnd.fold(left, right); - break; - case "<<": - folded = constantSystem.shiftLeft.fold(left, right); - break; - case ">>": - folded = constantSystem.shiftRight.fold(left, right); - break; - case "<": - folded = constantSystem.less.fold(left, right); - break; - case "<=": - folded = constantSystem.lessEqual.fold(left, right); - break; - case ">": - folded = constantSystem.greater.fold(left, right); - break; - case ">=": - folded = constantSystem.greaterEqual.fold(left, right); - break; - case "==": - if (left.isPrimitive() && right.isPrimitive()) { - folded = constantSystem.equal.fold(left, right); - } - break; - case "===": - folded = constantSystem.identity.fold(left, right); - break; - case "!=": - if (left.isPrimitive() && right.isPrimitive()) { - BoolConstant areEquals = constantSystem.equal.fold(left, right); - if (areEquals == null) { - folded = null; - } else { - folded = areEquals.negate(); - } - } - break; - case "!==": - BoolConstant areIdentical = - constantSystem.identity.fold(left, right); - if (areIdentical == null) { - folded = null; - } else { - folded = areIdentical.negate(); - } - break; - } - if (folded == null) return signalNotCompileTimeConstant(send); - return folded; - } - return signalNotCompileTimeConstant(send); - } - - Constant visitSendSet(SendSet node) { - return signalNotCompileTimeConstant(node); - } - - /** - * Returns the list of constants that are passed to the static function. - * - * Invariant: [target] must be an implementation element. - */ - List<Constant> evaluateArgumentsToConstructor(Node node, - Selector selector, - Link<Node> arguments, - FunctionElement target) { - assert(invariant(node, target.isImplementation)); - List<Constant> compiledArguments = <Constant>[]; - - Function compileArgument = evaluateConstant; - Function compileConstant = handler.compileConstant; - bool succeeded = selector.addArgumentsToList(arguments, - compiledArguments, - target, - compileArgument, - compileConstant, - compiler); - if (!succeeded) { - MessageKind kind = MessageKind.INVALID_ARGUMENTS; - compiler.reportError(node, - new CompileTimeConstantError(kind, {'methodName': target.name})); - } - return compiledArguments; - } - - Constant visitNewExpression(NewExpression node) { - if (!node.isConst()) { - return signalNotCompileTimeConstant(node); - } - - Send send = node.send; - FunctionElement constructor = elements[send]; - constructor = constructor.redirectionTarget; - ClassElement classElement = constructor.getEnclosingClass(); - if (classElement.isInterface()) { - compiler.resolver.resolveMethodElement(constructor); - constructor = constructor.defaultImplementation; - classElement = constructor.getEnclosingClass(); - } - // The constructor must be an implementation to ensure that field - // initializers are handled correctly. - constructor = constructor.implementation; - assert(invariant(node, constructor.isImplementation)); - - Selector selector = elements.getSelector(send); - List<Constant> arguments = evaluateArgumentsToConstructor( - node, selector, send.arguments, constructor); - ConstructorEvaluator evaluator = - new ConstructorEvaluator(node, constructor, handler, compiler); - evaluator.evaluateConstructorFieldValues(arguments); - List<Constant> jsNewArguments = evaluator.buildJsNewArguments(classElement); - - handler.registerInstantiatedClass(classElement); - // TODO(floitsch): take generic types into account. - DartType type = classElement.computeType(compiler); - Constant constant = new ConstructedConstant(type, jsNewArguments); - handler.registerCompileTimeConstant(constant); - return constant; - } - - Constant visitParenthesizedExpression(ParenthesizedExpression node) { - return node.expression.accept(this); - } - - error(Node node) { - // TODO(floitsch): get the list of constants that are currently compiled - // and present some kind of stack-trace. - MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; - compiler.reportError(node, new CompileTimeConstantError(kind)); - } - - Constant signalNotCompileTimeConstant(Node node) { - if (isEvaluatingConstant) { - error(node); - } - // Else we don't need to do anything. The final handler is only - // optimistically trying to compile constants. So it is normal that we - // sometimes see non-compile time constants. - // Simply return [:null:] which is used to propagate a failing - // compile-time compilation. - return null; - } -} - -class TryCompileTimeConstantEvaluator extends CompileTimeConstantEvaluator { - TryCompileTimeConstantEvaluator(ConstantHandler handler, - TreeElements elements, - Compiler compiler) - : super(handler, elements, compiler, isConst: true); - - error(Node node) { - // Just fail without reporting it anywhere. - throw new CompileTimeConstantError( - MessageKind.NOT_A_COMPILE_TIME_CONSTANT); - } -} - -class ConstructorEvaluator extends CompileTimeConstantEvaluator { - final FunctionElement constructor; - final Map<Element, Constant> definitions; - final Map<Element, Constant> fieldValues; - - /** - * Documentation wanted -- johnniwinther - * - * Invariant: [constructor] must be an implementation element. - */ - ConstructorEvaluator(Node node, - FunctionElement constructor, - ConstantHandler handler, - Compiler compiler) - : this.constructor = constructor, - this.definitions = new Map<Element, Constant>(), - this.fieldValues = new Map<Element, Constant>(), - super(handler, - compiler.resolver.resolveMethodElement(constructor.declaration), - compiler, - isConst: true) { - assert(invariant(node, constructor.isImplementation)); - } - - Constant visitSend(Send send) { - Element element = elements[send]; - if (Elements.isLocal(element)) { - Constant constant = definitions[element]; - if (constant == null) { - compiler.internalError("Local variable without value", node: send); - } - return constant; - } - return super.visitSend(send); - } - - void potentiallyCheckType(Node node, Element element, Constant constant) { - if (compiler.enableTypeAssertions) { - DartType elementType = element.computeType(compiler); - DartType constantType = constant.computeType(compiler); - // TODO(ngeoffray): Handle type parameters. - if (elementType.element.isTypeVariable()) return; - if (elementType.isMalformed || constantType.isMalformed || - !constantSystem.isSubtype(compiler, constantType, elementType)) { - compiler.reportError(node, new CompileTimeConstantError( - MessageKind.NOT_ASSIGNABLE, - {'fromType': elementType, 'toType': constantType})); - } - } - } - - void updateFieldValue(Node node, Element element, Constant constant) { - potentiallyCheckType(node, element, constant); - fieldValues[element] = constant; - } - - /** - * Given the arguments (a list of constants) assigns them to the parameters, - * updating the definitions map. If the constructor has field-initializer - * parameters (like [:this.x:]), also updates the [fieldValues] map. - */ - void assignArgumentsToParameters(List<Constant> arguments) { - // Assign arguments to parameters. - FunctionSignature parameters = constructor.computeSignature(compiler); - int index = 0; - parameters.orderedForEachParameter((Element parameter) { - Constant argument = arguments[index++]; - Node node = parameter.parseNode(compiler); - potentiallyCheckType(node, parameter, argument); - definitions[parameter] = argument; - if (parameter.kind == ElementKind.FIELD_PARAMETER) { - FieldParameterElement fieldParameterElement = parameter; - updateFieldValue(node, fieldParameterElement.fieldElement, argument); - } - }); - } - - void evaluateSuperOrRedirectSend(Node currentNode, - Selector selector, - Link<Node> arguments, - FunctionElement targetConstructor) { - List<Constant> compiledArguments = evaluateArgumentsToConstructor( - currentNode, selector, arguments, targetConstructor); - - ConstructorEvaluator evaluator = new ConstructorEvaluator( - currentNode, targetConstructor, handler, compiler); - evaluator.evaluateConstructorFieldValues(compiledArguments); - // Copy over the fieldValues from the super/redirect-constructor. - // No need to go through [updateFieldValue] because the - // assignments have already been checked in checked mode. - evaluator.fieldValues.forEach((key, value) => fieldValues[key] = value); - } - - /** - * Runs through the initializers of the given [constructor] and updates - * the [fieldValues] map. - */ - void evaluateConstructorInitializers() { - FunctionExpression functionNode = constructor.parseNode(compiler); - NodeList initializerList = functionNode.initializers; - - bool foundSuperOrRedirect = false; - - if (initializerList != null) { - for (Link<Node> link = initializerList.nodes; - !link.isEmpty; - link = link.tail) { - assert(link.head is Send); - if (link.head is !SendSet) { - // A super initializer or constructor redirection. - Send call = link.head; - FunctionElement targetConstructor = elements[call]; - Selector selector = elements.getSelector(call); - Link<Node> arguments = call.arguments; - evaluateSuperOrRedirectSend( - call, selector, arguments, targetConstructor); - foundSuperOrRedirect = true; - } else { - // A field initializer. - SendSet init = link.head; - Link<Node> initArguments = init.arguments; - assert(!initArguments.isEmpty && initArguments.tail.isEmpty); - Constant fieldValue = evaluate(initArguments.head); - updateFieldValue(init, elements[init], fieldValue); - } - } - } - - if (!foundSuperOrRedirect) { - // No super initializer found. Try to find the default constructor if - // the class is not Object. - ClassElement enclosingClass = constructor.getEnclosingClass(); - ClassElement superClass = enclosingClass.superclass; - if (enclosingClass != compiler.objectClass) { - assert(superClass != null); - assert(superClass.resolutionState == STATE_DONE); - - Selector selector = - new Selector.callDefaultConstructor(enclosingClass.getLibrary()); - - FunctionElement targetConstructor = - superClass.lookupConstructor(selector); - if (targetConstructor == null) { - compiler.internalError("no default constructor available", - node: functionNode); - } - - evaluateSuperOrRedirectSend(functionNode, - selector, - const Link<Node>(), - targetConstructor); - } - } - } - - /** - * Simulates the execution of the [constructor] with the given - * [arguments] to obtain the field values that need to be passed to the - * native JavaScript constructor. - */ - void evaluateConstructorFieldValues(List<Constant> arguments) { - compiler.withCurrentElement(constructor, () { - assignArgumentsToParameters(arguments); - evaluateConstructorInitializers(); - }); - } - - List<Constant> buildJsNewArguments(ClassElement classElement) { - List<Constant> jsNewArguments = <Constant>[]; - classElement.implementation.forEachInstanceField( - (ClassElement enclosing, Element field) { - Constant fieldValue = fieldValues[field]; - if (fieldValue == null) { - // Use the default value. - fieldValue = handler.compileConstant(field); - } - jsNewArguments.add(fieldValue); - }, - includeBackendMembers: true, - includeSuperMembers: true); - return jsNewArguments; - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/compiler.dart b/pkgs/markdown/test/lib/src/compiler/implementation/compiler.dart deleted file mode 100644 index 4fef805..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/compiler.dart +++ /dev/null
@@ -1,1130 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of dart2js; - -/** - * If true, print a warning for each method that was resolved, but not - * compiled. - */ -const bool REPORT_EXCESS_RESOLUTION = false; - -/** - * If true, dump the inferred types after compilation. - */ -const bool DUMP_INFERRED_TYPES = false; - -/** - * A string to identify the revision or build. - * - * This ID is displayed if the compiler crashes and in verbose mode, and is - * an aid in reproducing bug reports. - * - * The actual string is rewritten during the SDK build process. - */ -const String BUILD_ID = '0.3.5.1_r18300'; - -/** - * Contains backend-specific data that is used throughout the compilation of - * one work item. - */ -class ItemCompilationContext { -} - -abstract class WorkItem { - final ItemCompilationContext compilationContext; - /** - * Documentation wanted -- johnniwinther - * - * Invariant: [element] must be a declaration element. - */ - final Element element; - TreeElements get resolutionTree; - - WorkItem(this.element, this.compilationContext) { - assert(invariant(element, element.isDeclaration)); - } - - bool isAnalyzed() => resolutionTree != null; - - void run(Compiler compiler, Enqueuer world); -} - -/// [WorkItem] used exclusively by the [ResolutionEnqueuer]. -class ResolutionWorkItem extends WorkItem { - TreeElements resolutionTree; - - ResolutionWorkItem(Element element, - ItemCompilationContext compilationContext) - : super(element, compilationContext); - - void run(Compiler compiler, ResolutionEnqueuer world) { - resolutionTree = compiler.analyze(this, world); - } -} - -/// [WorkItem] used exclusively by the [CodegenEnqueuer]. -class CodegenWorkItem extends WorkItem { - final TreeElements resolutionTree; - - bool allowSpeculativeOptimization = true; - List<HTypeGuard> guards = const <HTypeGuard>[]; - - CodegenWorkItem(Element element, - TreeElements this.resolutionTree, - ItemCompilationContext compilationContext) - : super(element, compilationContext) { - assert(invariant(element, resolutionTree != null, - message: 'Resolution tree is null for $element in codegen work item')); - } - - void run(Compiler compiler, CodegenEnqueuer world) { - if (world.isProcessed(element)) return; - compiler.codegen(this, world); - } -} - -class ReadingFilesTask extends CompilerTask { - ReadingFilesTask(Compiler compiler) : super(compiler); - String get name => 'Reading input files'; -} - -abstract class Backend { - final Compiler compiler; - final ConstantSystem constantSystem; - - Backend(this.compiler, - [ConstantSystem constantSystem = DART_CONSTANT_SYSTEM]) - : this.constantSystem = constantSystem; - - void enqueueAllTopLevelFunctions(LibraryElement lib, Enqueuer world) { - lib.forEachExport((Element e) { - if (e.isFunction()) world.addToWorkList(e); - }); - } - - void enqueueHelpers(ResolutionEnqueuer world); - void codegen(CodegenWorkItem work); - - // The backend determines the native resolution enqueuer, with a no-op - // default, so tools like dart2dart can ignore the native classes. - native.NativeEnqueuer nativeResolutionEnqueuer(world) { - return new native.NativeEnqueuer(); - } - native.NativeEnqueuer nativeCodegenEnqueuer(world) { - return new native.NativeEnqueuer(); - } - - void assembleProgram(); - List<CompilerTask> get tasks; - - // TODO(ahe,karlklose): rename this? - void dumpInferredTypes() {} - - ItemCompilationContext createItemCompilationContext() { - return new ItemCompilationContext(); - } - - SourceString getCheckedModeHelper(DartType type) => null; - void registerInstantiatedClass(ClassElement cls, Enqueuer enqueuer) {} -} - -/** - * Key class used in [TokenMap] in which the hash code for a token is based - * on the [charOffset]. - */ -class TokenKey { - final Token token; - TokenKey(this.token); - int get hashCode => token.charOffset; - operator==(other) => other is TokenKey && token == other.token; -} - -/// Map of tokens and the first associated comment. -/* - * This implementation was chosen among several candidates for its space/time - * efficiency by empirical tests of running dartdoc on dartdoc itself. Time - * measurements for the use of [Compiler.commentMap]: - * - * 1) Using [TokenKey] as key (this class): ~80 msec - * 2) Using [TokenKey] as key + storing a separate map in each script: ~120 msec - * 3) Using [Token] as key in a [Map]: ~38000 msec - * 4) Storing comments is new field in [Token]: ~20 msec - * (Abandoned due to the increased memory usage) - * 5) Storing comments in an [Expando]: ~14000 msec - * 6) Storing token/comments pairs in a linked list: ~5400 msec - */ -class TokenMap { - Map<TokenKey,Token> comments = new Map<TokenKey,Token>(); - - Token operator[] (Token key) { - if (key == null) return null; - return comments[new TokenKey(key)]; - } - - void operator[]= (Token key, Token value) { - if (key == null) return; - comments[new TokenKey(key)] = value; - } -} - -abstract class Compiler implements DiagnosticListener { - final Map<String, LibraryElement> libraries; - final Stopwatch totalCompileTime = new Stopwatch(); - int nextFreeClassId = 0; - World world; - String assembledCode; - Types types; - - /** - * Map from token to the first preceeding comment token. - */ - final TokenMap commentMap = new TokenMap(); - - final bool enableMinification; - final bool enableTypeAssertions; - final bool enableUserAssertions; - final bool enableConcreteTypeInference; - /** - * The maximum size of a concrete type before it widens to dynamic during - * concrete type inference. - */ - final int maxConcreteTypeSize; - final bool analyzeAll; - final bool analyzeOnly; - final bool enableNativeLiveTypeAnalysis; - final bool rejectDeprecatedFeatures; - final bool checkDeprecationInSdk; - - /** - * If [:true:], comment tokens are collected in [commentMap] during scanning. - */ - final bool preserveComments; - - final api.CompilerOutputProvider outputProvider; - - bool disableInlining = false; - - List<Uri> librariesToAnalyzeWhenRun; - - final Tracer tracer; - - CompilerTask measuredTask; - Element _currentElement; - LibraryElement coreLibrary; - LibraryElement isolateLibrary; - LibraryElement isolateHelperLibrary; - LibraryElement jsHelperLibrary; - LibraryElement interceptorsLibrary; - LibraryElement foreignLibrary; - LibraryElement mainApp; - - ClassElement objectClass; - ClassElement closureClass; - ClassElement dynamicClass; - ClassElement boolClass; - ClassElement numClass; - ClassElement intClass; - ClassElement doubleClass; - ClassElement stringClass; - ClassElement functionClass; - ClassElement nullClass; - ClassElement listClass; - ClassElement typeClass; - ClassElement mapClass; - ClassElement jsInvocationMirrorClass; - /// Document class from dart:mirrors. - ClassElement documentClass; - Element assertMethod; - Element identicalFunction; - Element functionApplyMethod; - Element invokeOnMethod; - Element createInvocationMirrorElement; - - Element get currentElement => _currentElement; - withCurrentElement(Element element, f()) { - Element old = currentElement; - _currentElement = element; - try { - return f(); - } on SpannableAssertionFailure catch (ex) { - if (!hasCrashed) { - SourceSpan span = spanFromSpannable(ex.node); - reportDiagnostic(span, ex.message, api.Diagnostic.ERROR); - pleaseReportCrash(); - } - hasCrashed = true; - throw; - } on CompilerCancelledException catch (ex) { - throw; - } on StackOverflowError catch (ex) { - // We cannot report anything useful in this case, because we - // do not have enough stack space. - throw; - } catch (ex) { - try { - unhandledExceptionOnElement(element); - } catch (doubleFault) { - // Ignoring exceptions in exception handling. - } - throw; - } finally { - _currentElement = old; - } - } - - List<CompilerTask> tasks; - ScannerTask scanner; - DietParserTask dietParser; - ParserTask parser; - PatchParserTask patchParser; - LibraryLoader libraryLoader; - TreeValidatorTask validator; - ResolverTask resolver; - closureMapping.ClosureTask closureToClassMapper; - TypeCheckerTask checker; - ti.TypesTask typesTask; - Backend backend; - ConstantHandler constantHandler; - ConstantHandler metadataHandler; - EnqueueTask enqueuer; - CompilerTask fileReadingTask; - - static const SourceString MAIN = const SourceString('main'); - static const SourceString CALL_OPERATOR_NAME = const SourceString('call'); - static const SourceString NO_SUCH_METHOD = const SourceString('noSuchMethod'); - static const int NO_SUCH_METHOD_ARG_COUNT = 1; - static const SourceString CREATE_INVOCATION_MIRROR = - const SourceString('createInvocationMirror'); - static const SourceString INVOKE_ON = const SourceString('invokeOn'); - static const SourceString RUNTIME_TYPE = const SourceString('runtimeType'); - static const SourceString START_ROOT_ISOLATE = - const SourceString('startRootIsolate'); - bool enabledNoSuchMethod = false; - bool enabledRuntimeType = false; - bool enabledFunctionApply = false; - bool enabledInvokeOn = false; - - Stopwatch progress; - - static const int PHASE_SCANNING = 0; - static const int PHASE_RESOLVING = 1; - static const int PHASE_COMPILING = 2; - int phase; - - bool compilationFailed = false; - - bool hasCrashed = false; - - Compiler({this.tracer: const Tracer(), - this.enableTypeAssertions: false, - this.enableUserAssertions: false, - this.enableConcreteTypeInference: false, - this.maxConcreteTypeSize: 5, - this.enableMinification: false, - this.enableNativeLiveTypeAnalysis: false, - bool emitJavaScript: true, - bool generateSourceMap: true, - bool disallowUnsafeEval: false, - this.analyzeAll: false, - this.analyzeOnly: false, - this.rejectDeprecatedFeatures: false, - this.checkDeprecationInSdk: false, - this.preserveComments: false, - outputProvider, - List<String> strips: const []}) - : libraries = new Map<String, LibraryElement>(), - progress = new Stopwatch(), - this.outputProvider = - (outputProvider == null) ? NullSink.outputProvider : outputProvider - { - progress.start(); - world = new World(this); - - closureMapping.ClosureNamer closureNamer; - if (emitJavaScript) { - js_backend.JavaScriptBackend jsBackend = - new js_backend.JavaScriptBackend(this, generateSourceMap, - disallowUnsafeEval); - closureNamer = jsBackend.namer; - backend = jsBackend; - } else { - backend = new dart_backend.DartBackend(this, strips); - } - - // No-op in production mode. - validator = new TreeValidatorTask(this); - - tasks = [ - fileReadingTask = new ReadingFilesTask(this), - libraryLoader = new LibraryLoaderTask(this), - scanner = new ScannerTask(this), - dietParser = new DietParserTask(this), - parser = new ParserTask(this), - patchParser = new PatchParserTask(this), - resolver = new ResolverTask(this), - closureToClassMapper = new closureMapping.ClosureTask(this, closureNamer), - checker = new TypeCheckerTask(this), - typesTask = new ti.TypesTask(this), - constantHandler = new ConstantHandler(this, backend.constantSystem), - enqueuer = new EnqueueTask(this)]; - - tasks.addAll(backend.tasks); - metadataHandler = new ConstantHandler( - this, backend.constantSystem, isMetadata: true); - } - - Universe get resolverWorld => enqueuer.resolution.universe; - Universe get codegenWorld => enqueuer.codegen.universe; - - int getNextFreeClassId() => nextFreeClassId++; - - void ensure(bool condition) { - if (!condition) cancel('failed assertion in leg'); - } - - void unimplemented(String methodName, - {Node node, Token token, HInstruction instruction, - Element element}) { - internalError("$methodName not implemented", - node: node, token: token, - instruction: instruction, element: element); - } - - void internalError(String message, - {Node node, Token token, HInstruction instruction, - Element element}) { - cancel('Internal error: $message', - node: node, token: token, - instruction: instruction, element: element); - } - - void internalErrorOnElement(Element element, String message) { - internalError(message, element: element); - } - - void unhandledExceptionOnElement(Element element) { - if (hasCrashed) return; - hasCrashed = true; - reportDiagnostic(spanFromElement(element), - MessageKind.COMPILER_CRASHED.error().toString(), - api.Diagnostic.CRASH); - pleaseReportCrash(); - } - - void pleaseReportCrash() { - print(MessageKind.PLEASE_REPORT_THE_CRASH.message({'buildId': BUILD_ID})); - } - - void cancel(String reason, {Node node, Token token, - HInstruction instruction, Element element}) { - assembledCode = null; // Compilation failed. Make sure that we - // don't return a bogus result. - SourceSpan span = null; - if (node != null) { - span = spanFromNode(node); - } else if (token != null) { - span = spanFromTokens(token, token); - } else if (instruction != null) { - span = spanFromHInstruction(instruction); - } else if (element != null) { - span = spanFromElement(element); - } else { - throw 'No error location for error: $reason'; - } - reportDiagnostic(span, reason, api.Diagnostic.ERROR); - throw new CompilerCancelledException(reason); - } - - SourceSpan spanFromSpannable(Spannable node, [Uri uri]) { - if (node == CURRENT_ELEMENT_SPANNABLE) { - node = currentElement; - } - if (node is Node) { - return spanFromNode(node, uri); - } else if (node is Token) { - return spanFromTokens(node, node, uri); - } else if (node is HInstruction) { - return spanFromHInstruction(node); - } else if (node is Element) { - return spanFromElement(node); - } else if (node is MetadataAnnotation) { - return spanFromTokens(node.beginToken, node.endToken); - } else { - throw 'No error location.'; - } - } - - void reportFatalError(String reason, Element element, - {Node node, Token token, HInstruction instruction}) { - withCurrentElement(element, () { - cancel(reason, node: node, token: token, instruction: instruction, - element: element); - }); - } - - void log(message) { - reportDiagnostic(null, message, api.Diagnostic.VERBOSE_INFO); - } - - bool run(Uri uri) { - totalCompileTime.start(); - try { - runCompiler(uri); - } on CompilerCancelledException catch (exception) { - log('Error: $exception'); - return false; - } finally { - tracer.close(); - totalCompileTime.stop(); - } - return true; - } - - bool hasIsolateSupport() => isolateLibrary != null; - - /** - * This method is called before [library] import and export scopes have been - * set up. - */ - void onLibraryScanned(LibraryElement library, Uri uri) { - if (dynamicClass != null) { - // When loading the built-in libraries, dynamicClass is null. We - // take advantage of this as core imports js_helper and sees [dynamic] - // this way. - withCurrentElement(dynamicClass, () { - library.addToScope(dynamicClass, this); - }); - } - } - - LibraryElement scanBuiltinLibrary(String filename); - - void initializeSpecialClasses() { - final List missingCoreClasses = []; - ClassElement lookupCoreClass(String name) { - ClassElement result = coreLibrary.find(new SourceString(name)); - if (result == null) { - missingCoreClasses.add(name); - } - return result; - } - objectClass = lookupCoreClass('Object'); - boolClass = lookupCoreClass('bool'); - numClass = lookupCoreClass('num'); - intClass = lookupCoreClass('int'); - doubleClass = lookupCoreClass('double'); - stringClass = lookupCoreClass('String'); - functionClass = lookupCoreClass('Function'); - listClass = lookupCoreClass('List'); - typeClass = lookupCoreClass('Type'); - mapClass = lookupCoreClass('Map'); - if (!missingCoreClasses.isEmpty) { - internalErrorOnElement(coreLibrary, - 'dart:core library does not contain required classes: ' - '$missingCoreClasses'); - } - - final List missingHelperClasses = []; - ClassElement lookupHelperClass(String name) { - ClassElement result = jsHelperLibrary.find(new SourceString(name)); - if (result == null) { - missingHelperClasses.add(name); - } - return result; - } - jsInvocationMirrorClass = lookupHelperClass('JSInvocationMirror'); - closureClass = lookupHelperClass('Closure'); - dynamicClass = lookupHelperClass('Dynamic_'); - nullClass = lookupHelperClass('Null'); - if (!missingHelperClasses.isEmpty) { - internalErrorOnElement(jsHelperLibrary, - 'dart:_js_helper library does not contain required classes: ' - '$missingHelperClasses'); - } - - types = new Types(this, dynamicClass); - } - - void scanBuiltinLibraries() { - jsHelperLibrary = scanBuiltinLibrary('_js_helper'); - interceptorsLibrary = scanBuiltinLibrary('_interceptors'); - foreignLibrary = scanBuiltinLibrary('_foreign_helper'); - isolateHelperLibrary = scanBuiltinLibrary('_isolate_helper'); - // The helper library does not use the native language extension, - // so we manually set the native classes this library defines. - // TODO(ngeoffray): Enable annotations on these classes. - ClassElement cls = - isolateHelperLibrary.find(const SourceString('_WorkerStub')); - cls.setNative('"*Worker"'); - - assertMethod = jsHelperLibrary.find(const SourceString('assertHelper')); - identicalFunction = coreLibrary.find(const SourceString('identical')); - - initializeSpecialClasses(); - - functionClass.ensureResolved(this); - functionApplyMethod = - functionClass.lookupLocalMember(const SourceString('apply')); - jsInvocationMirrorClass.ensureResolved(this); - invokeOnMethod = jsInvocationMirrorClass.lookupLocalMember( - const SourceString('invokeOn')); - - if (preserveComments) { - var uri = new Uri.fromComponents(scheme: 'dart', path: 'mirrors'); - LibraryElement libraryElement = - libraryLoader.loadLibrary(uri, null, uri); - documentClass = libraryElement.find(const SourceString('Comment')); - } - } - - void importHelperLibrary(LibraryElement library) { - if (jsHelperLibrary != null) { - libraryLoader.importLibrary(library, jsHelperLibrary, null); - } - } - - /** - * Get an [Uri] pointing to a patch for the dart: library with - * the given path. Returns null if there is no patch. - */ - Uri resolvePatchUri(String dartLibraryPath); - - void runCompiler(Uri uri) { - assert(uri != null || analyzeOnly); - scanBuiltinLibraries(); - if (librariesToAnalyzeWhenRun != null) { - for (Uri libraryUri in librariesToAnalyzeWhenRun) { - log('analyzing $libraryUri ($BUILD_ID)'); - libraryLoader.loadLibrary(libraryUri, null, libraryUri); - } - } - if (uri != null) { - if (analyzeOnly) { - log('analyzing $uri ($BUILD_ID)'); - } else { - log('compiling $uri ($BUILD_ID)'); - } - mainApp = libraryLoader.loadLibrary(uri, null, uri); - } - Element main = null; - if (mainApp != null) { - main = mainApp.find(MAIN); - if (main == null) { - if (!analyzeOnly) { - // Allow analyze only of libraries with no main. - reportFatalError('Could not find $MAIN', mainApp); - } else if (!analyzeAll) { - reportFatalError( - "Could not find $MAIN. " - "No source will be analyzed. " - "Use '--analyze-all' to analyze all code in the library.", - mainApp); - } - } else { - if (!main.isFunction()) { - reportFatalError('main is not a function', main); - } - FunctionElement mainMethod = main; - FunctionSignature parameters = mainMethod.computeSignature(this); - parameters.forEachParameter((Element parameter) { - reportFatalError('main cannot have parameters', parameter); - }); - } - } - - log('Resolving...'); - phase = PHASE_RESOLVING; - if (analyzeAll) { - libraries.forEach((_, lib) => fullyEnqueueLibrary(lib)); - } - backend.enqueueHelpers(enqueuer.resolution); - processQueue(enqueuer.resolution, main); - enqueuer.resolution.logSummary(log); - - if (compilationFailed) return; - if (analyzeOnly) return; - assert(main != null); - - log('Inferring types...'); - typesTask.onResolutionComplete(main); - - // TODO(ahe): Remove this line. Eventually, enqueuer.resolution - // should know this. - world.populate(); - - log('Compiling...'); - phase = PHASE_COMPILING; - // TODO(johnniwinther): Move these to [CodegenEnqueuer]. - if (hasIsolateSupport()) { - enqueuer.codegen.addToWorkList( - isolateHelperLibrary.find(Compiler.START_ROOT_ISOLATE)); - } - if (enabledNoSuchMethod) { - Selector selector = new Selector.noSuchMethod(); - enqueuer.codegen.registerInvocation(NO_SUCH_METHOD, selector); - enqueuer.codegen.addToWorkList(createInvocationMirrorElement); - } - processQueue(enqueuer.codegen, main); - enqueuer.codegen.logSummary(log); - - if (compilationFailed) return; - - backend.assembleProgram(); - - checkQueues(); - } - - void fullyEnqueueLibrary(LibraryElement library) { - library.forEachLocalMember(fullyEnqueueTopLevelElement); - } - - void fullyEnqueueTopLevelElement(Element element) { - if (element.isClass()) { - ClassElement cls = element; - cls.ensureResolved(this); - cls.forEachLocalMember(enqueuer.resolution.addToWorkList); - } else { - enqueuer.resolution.addToWorkList(element); - } - } - - void processQueue(Enqueuer world, Element main) { - world.nativeEnqueuer.processNativeClasses(libraries.values); - if (main != null) { - world.addToWorkList(main); - } - progress.reset(); - world.forEach((WorkItem work) { - withCurrentElement(work.element, () => work.run(this, world)); - }); - world.queueIsClosed = true; - if (compilationFailed) return; - assert(world.checkNoEnqueuedInvokedInstanceMethods()); - if (DUMP_INFERRED_TYPES && phase == PHASE_COMPILING) { - backend.dumpInferredTypes(); - } - } - - /** - * Perform various checks of the queues. This includes checking that - * the queues are empty (nothing was added after we stopped - * processing the queues). Also compute the number of methods that - * were resolved, but not compiled (aka excess resolution). - */ - checkQueues() { - for (Enqueuer world in [enqueuer.resolution, enqueuer.codegen]) { - world.forEach((WorkItem work) { - internalErrorOnElement(work.element, "Work list is not empty."); - }); - } - if (!REPORT_EXCESS_RESOLUTION) return; - var resolved = new Set.from(enqueuer.resolution.resolvedElements.keys); - for (Element e in enqueuer.codegen.generatedCode.keys) { - resolved.remove(e); - } - for (Element e in new Set.from(resolved)) { - if (e.isClass() || - e.isField() || - e.isTypeVariable() || - e.isTypedef() || - identical(e.kind, ElementKind.ABSTRACT_FIELD)) { - resolved.remove(e); - } - if (identical(e.kind, ElementKind.GENERATIVE_CONSTRUCTOR)) { - ClassElement enclosingClass = e.getEnclosingClass(); - if (enclosingClass.isInterface()) { - resolved.remove(e); - } - resolved.remove(e); - - } - if (identical(e.getLibrary(), jsHelperLibrary)) { - resolved.remove(e); - } - if (identical(e.getLibrary(), interceptorsLibrary)) { - resolved.remove(e); - } - } - log('Excess resolution work: ${resolved.length}.'); - for (Element e in resolved) { - SourceSpan span = spanFromElement(e); - reportDiagnostic(span, 'Warning: $e resolved but not compiled.', - api.Diagnostic.WARNING); - } - } - - TreeElements analyzeElement(Element element) { - assert(invariant(element, element.isDeclaration)); - TreeElements elements = enqueuer.resolution.getCachedElements(element); - if (elements != null) return elements; - assert(parser != null); - Node tree = parser.parse(element); - validator.validate(tree); - elements = resolver.resolve(element); - if (elements != null) { - // Only analyze nodes with a corresponding [TreeElements]. - checker.check(tree, elements); - typesTask.analyze(tree, elements); - } - return elements; - } - - TreeElements analyze(ResolutionWorkItem work, ResolutionEnqueuer world) { - assert(invariant(work.element, identical(world, enqueuer.resolution))); - assert(invariant(work.element, !work.isAnalyzed(), - message: 'Element ${work.element} has already been analyzed')); - if (progress.elapsedMilliseconds > 500) { - // TODO(ahe): Add structured diagnostics to the compiler API and - // use it to separate this from the --verbose option. - if (phase == PHASE_RESOLVING) { - log('Resolved ${enqueuer.resolution.resolvedElements.length} ' - 'elements.'); - progress.reset(); - } - } - Element element = work.element; - TreeElements result = world.getCachedElements(element); - if (result != null) return result; - result = analyzeElement(element); - assert(invariant(element, element.isDeclaration)); - world.resolvedElements[element] = result; - return result; - } - - void codegen(CodegenWorkItem work, CodegenEnqueuer world) { - assert(invariant(work.element, identical(world, enqueuer.codegen))); - if (progress.elapsedMilliseconds > 500) { - // TODO(ahe): Add structured diagnostics to the compiler API and - // use it to separate this from the --verbose option. - log('Compiled ${enqueuer.codegen.generatedCode.length} methods.'); - progress.reset(); - } - backend.codegen(work); - } - - DartType resolveTypeAnnotation(Element element, - TypeAnnotation annotation) { - return resolver.resolveTypeAnnotation(element, annotation); - } - - DartType resolveReturnType(Element element, - TypeAnnotation annotation) { - return resolver.resolveReturnType(element, annotation); - } - - FunctionSignature resolveSignature(FunctionElement element) { - return withCurrentElement(element, - () => resolver.resolveSignature(element)); - } - - FunctionSignature resolveFunctionExpression(Element element, - FunctionExpression node) { - return withCurrentElement(element, - () => resolver.resolveFunctionExpression(element, node)); - } - - void resolveTypedef(TypedefElement element) { - withCurrentElement(element, - () => resolver.resolveTypedef(element)); - } - - FunctionType computeFunctionType(Element element, - FunctionSignature signature) { - return withCurrentElement(element, - () => resolver.computeFunctionType(element, signature)); - } - - reportWarning(Node node, var message) { - if (message is TypeWarning) { - // TODO(ahe): Don't supress these warning when the type checker - // is more complete. - if (identical(message.message.kind, MessageKind.NOT_ASSIGNABLE)) return; - if (identical(message.message.kind, MessageKind.MISSING_RETURN)) return; - if (identical(message.message.kind, MessageKind.MAYBE_MISSING_RETURN)) return; - if (identical(message.message.kind, MessageKind.METHOD_NOT_FOUND)) return; - } - SourceSpan span = spanFromNode(node); - - reportDiagnostic(span, 'Warning: $message', api.Diagnostic.WARNING); - } - - // TODO(ahe): Remove this method. - reportError(Node node, var message) { - SourceSpan span = spanFromNode(node); - reportDiagnostic(span, 'Error: $message', api.Diagnostic.ERROR); - throw new CompilerCancelledException(message.toString()); - } - - // TODO(ahe): Rename to reportError when that method has been removed. - void reportErrorCode(Spannable node, MessageKind errorCode, - [Map arguments = const {}]) { - reportMessage(spanFromSpannable(node), - errorCode.error(arguments), - api.Diagnostic.ERROR); - } - - void reportMessage(SourceSpan span, Diagnostic message, api.Diagnostic kind) { - // TODO(ahe): The names Diagnostic and api.Diagnostic are in - // conflict. Fix it. - reportDiagnostic(span, "$message", kind); - } - - /// Returns true if a diagnostic was emitted. - bool onDeprecatedFeature(Spannable span, String feature) { - if (currentElement == null) - throw new SpannableAssertionFailure(span, feature); - if (!checkDeprecationInSdk && - currentElement.getLibrary().isPlatformLibrary) { - return false; - } - var kind = rejectDeprecatedFeatures - ? api.Diagnostic.ERROR : api.Diagnostic.WARNING; - var message = rejectDeprecatedFeatures - ? MessageKind.DEPRECATED_FEATURE_ERROR.error({'featureName': feature}) - : MessageKind.DEPRECATED_FEATURE_WARNING.error( - {'featureName': feature}); - reportMessage(spanFromSpannable(span), message, kind); - return true; - } - - void reportDiagnostic(SourceSpan span, String message, api.Diagnostic kind); - - SourceSpan spanFromTokens(Token begin, Token end, [Uri uri]) { - if (begin == null || end == null) { - // TODO(ahe): We can almost always do better. Often it is only - // end that is null. Otherwise, we probably know the current - // URI. - throw 'Cannot find tokens to produce error message.'; - } - if (uri == null && currentElement != null) { - uri = currentElement.getCompilationUnit().script.uri; - } - return SourceSpan.withCharacterOffsets(begin, end, - (beginOffset, endOffset) => new SourceSpan(uri, beginOffset, endOffset)); - } - - SourceSpan spanFromNode(Node node, [Uri uri]) { - return spanFromTokens(node.getBeginToken(), node.getEndToken(), uri); - } - - SourceSpan spanFromElement(Element element) { - if (Elements.isErroneousElement(element)) { - element = element.enclosingElement; - } - if (element.position() == null && !element.isCompilationUnit()) { - // Sometimes, the backend fakes up elements that have no - // position. So we use the enclosing element instead. It is - // not a good error location, but cancel really is "internal - // error" or "not implemented yet", so the vicinity is good - // enough for now. - element = element.enclosingElement; - // TODO(ahe): I plan to overhaul this infrastructure anyways. - } - if (element == null) { - element = currentElement; - } - Token position = element.position(); - Uri uri = element.getCompilationUnit().script.uri; - return (position == null) - ? new SourceSpan(uri, 0, 0) - : spanFromTokens(position, position, uri); - } - - SourceSpan spanFromHInstruction(HInstruction instruction) { - Element element = instruction.sourceElement; - if (element == null) element = currentElement; - var position = instruction.sourcePosition; - if (position == null) return spanFromElement(element); - Token token = position.token; - if (token == null) return spanFromElement(element); - Uri uri = element.getCompilationUnit().script.uri; - return spanFromTokens(token, token, uri); - } - - /** - * Translates the [resolvedUri] into a readable URI. - * - * The [importingLibrary] holds the library importing [resolvedUri] or - * [:null:] if [resolvedUri] is loaded as the main library. The - * [importingLibrary] is used to grant access to internal libraries from - * platform libraries and patch libraries. - * - * If the [resolvedUri] is not accessible from [importingLibrary], this method - * is responsible for reporting errors. - * - * See [LibraryLoader] for terminology on URIs. - */ - Uri translateResolvedUri(LibraryElement importingLibrary, - Uri resolvedUri, Node node) { - unimplemented('Compiler.translateResolvedUri'); - } - - /** - * Reads the script specified by the [readableUri]. - * - * See [LibraryLoader] for terminology on URIs. - */ - Script readScript(Uri readableUri, [Node node]) { - unimplemented('Compiler.readScript'); - } - - String get legDirectory { - unimplemented('Compiler.legDirectory'); - } - - // TODO(karlklose): split into findHelperFunction and findHelperClass and - // add a check that the element has the expected kind. - Element findHelper(SourceString name) - => jsHelperLibrary.findLocal(name); - Element findInterceptor(SourceString name) - => interceptorsLibrary.findLocal(name); - - Element lookupElementIn(ScopeContainerElement container, SourceString name) { - Element element = container.localLookup(name); - if (element == null) { - throw 'Could not find ${name.slowToString()} in $container'; - } - return element; - } - - bool get isMockCompilation => false; - - Token processAndStripComments(Token currentToken) { - Token firstToken = currentToken; - Token prevToken; - while (currentToken.kind != EOF_TOKEN) { - if (identical(currentToken.kind, COMMENT_TOKEN)) { - Token firstCommentToken = currentToken; - while (identical(currentToken.kind, COMMENT_TOKEN)) { - currentToken = currentToken.next; - } - commentMap[currentToken] = firstCommentToken; - if (prevToken == null) { - firstToken = currentToken; - } else { - prevToken.next = currentToken; - } - } - prevToken = currentToken; - currentToken = currentToken.next; - } - return firstToken; - } -} - -class CompilerTask { - final Compiler compiler; - final Stopwatch watch; - - CompilerTask(this.compiler) : watch = new Stopwatch(); - - String get name => 'Unknown task'; - int get timing => watch.elapsedMilliseconds; - - measure(Function action) { - CompilerTask previous = compiler.measuredTask; - if (identical(this, previous)) return action(); - compiler.measuredTask = this; - if (previous != null) previous.watch.stop(); - watch.start(); - try { - return action(); - } finally { - watch.stop(); - if (previous != null) previous.watch.start(); - compiler.measuredTask = previous; - } - } -} - -class CompilerCancelledException implements Exception { - final String reason; - CompilerCancelledException(this.reason); - - String toString() { - String banner = 'compiler cancelled'; - return (reason != null) ? '$banner: $reason' : '$banner'; - } -} - -class Tracer { - final bool enabled = false; - - const Tracer(); - - void traceCompilation(String methodName, ItemCompilationContext context) { - } - - void traceGraph(String name, var graph) { - } - - void close() { - } -} - -class SourceSpan { - final Uri uri; - final int begin; - final int end; - - const SourceSpan(this.uri, this.begin, this.end); - - static withCharacterOffsets(Token begin, Token end, - f(int beginOffset, int endOffset)) { - final beginOffset = begin.charOffset; - final endOffset = end.charOffset + end.slowCharCount; - - // [begin] and [end] might be the same for the same empty token. This - // happens for instance when scanning '$$'. - assert(endOffset >= beginOffset); - return f(beginOffset, endOffset); - } - - String toString() => 'SourceSpan($uri, $begin, $end)'; -} - -/** - * Throws an [InvariantException] if [condition] is [:false:]. [condition] must - * be either a [:bool:] or a no-arg function returning a [:bool:]. - * - * Use this method to provide better information for assertion by calling - * [invariant] as the argument to an [:assert:] statement: - * - * assert(invariant(position, isValid)); - * - * [spannable] must be non-null and will be used to provide positional - * information in the generated error message. - */ -bool invariant(Spannable spannable, var condition, {String message: null}) { - // TODO(johnniwinther): Use [spannable] and [message] to provide better - // information on assertion errors. - if (condition is Function){ - condition = condition(); - } - if (spannable == null || !condition) { - throw new SpannableAssertionFailure(spannable, message); - } - return true; -} - -/// A sink that drains into /dev/null. -class NullSink extends StreamSink<String> { - final String name; - - NullSink(this.name); - - add(String value) {} - - void signalError(AsyncError error) {} - - void close() {} - - toString() => name; - - /// Convenience method for getting an [api.CompilerOutputProvider]. - static NullSink outputProvider(String name, String extension) { - return new NullSink('$name.$extension'); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/constant_system.dart b/pkgs/markdown/test/lib/src/compiler/implementation/constant_system.dart deleted file mode 100644 index 0fff580..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/constant_system.dart +++ /dev/null
@@ -1,80 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of dart2js; - -abstract class Operation { - SourceString get name; - bool isUserDefinable(); -} - -abstract class UnaryOperation extends Operation { - /** Returns [:null:] if it was unable to fold the operation. */ - Constant fold(Constant constant); - apply(value); -} - -abstract class BinaryOperation extends Operation { - /** Returns [:null:] if it was unable to fold the operation. */ - Constant fold(Constant left, Constant right); - apply(left, right); -} - -/** - * A [ConstantSystem] is responsible for creating constants and folding them. - */ -abstract class ConstantSystem { - BinaryOperation get add; - BinaryOperation get bitAnd; - UnaryOperation get bitNot; - BinaryOperation get bitOr; - BinaryOperation get bitXor; - BinaryOperation get booleanAnd; - BinaryOperation get booleanOr; - BinaryOperation get divide; - BinaryOperation get equal; - BinaryOperation get greaterEqual; - BinaryOperation get greater; - BinaryOperation get identity; - BinaryOperation get lessEqual; - BinaryOperation get less; - BinaryOperation get modulo; - BinaryOperation get multiply; - UnaryOperation get negate; - UnaryOperation get not; - BinaryOperation get shiftLeft; - BinaryOperation get shiftRight; - BinaryOperation get subtract; - BinaryOperation get truncatingDivide; - - const ConstantSystem(); - - Constant createInt(int i); - Constant createDouble(double d); - // We need a diagnostic node to report errors in case the string is malformed. - Constant createString(DartString string, Node diagnosticNode); - Constant createBool(bool value); - Constant createNull(); - - // We need to special case the subtype check for JavaScript constant - // system because an int is a double at runtime. - bool isSubtype(Compiler compiler, DartType s, DartType t); - - /** Returns true if the [constant] is an integer at runtime. */ - bool isInt(Constant constant); - /** Returns true if the [constant] is a double at runtime. */ - bool isDouble(Constant constant); - /** Returns true if the [constant] is a string at runtime. */ - bool isString(Constant constant); - /** Returns true if the [constant] is a boolean at runtime. */ - bool isBool(Constant constant); - /** Returns true if the [constant] is null at runtime. */ - bool isNull(Constant constant); - - Operation lookupUnary(SourceString operator) { - if (operator == const SourceString('-')) return negate; - if (operator == const SourceString('~')) return bitNot; - return null; - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/constant_system_dart.dart b/pkgs/markdown/test/lib/src/compiler/implementation/constant_system_dart.dart deleted file mode 100644 index 6732b8c..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/constant_system_dart.dart +++ /dev/null
@@ -1,380 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of dart2js; - -const DART_CONSTANT_SYSTEM = const DartConstantSystem(); - -class BitNotOperation implements UnaryOperation { - final SourceString name = const SourceString('~'); - bool isUserDefinable() => true; - const BitNotOperation(); - Constant fold(Constant constant) { - if (constant.isInt()) { - IntConstant intConstant = constant; - return DART_CONSTANT_SYSTEM.createInt(~intConstant.value); - } - return null; - } - apply(value) => ~value; -} - -class NegateOperation implements UnaryOperation { - final SourceString name = const SourceString('negate'); - bool isUserDefinable() => true; - const NegateOperation(); - Constant fold(Constant constant) { - if (constant.isInt()) { - IntConstant intConstant = constant; - return DART_CONSTANT_SYSTEM.createInt(-intConstant.value); - } - if (constant.isDouble()) { - DoubleConstant doubleConstant = constant; - return DART_CONSTANT_SYSTEM.createDouble(-doubleConstant.value); - } - return null; - } - apply(value) => -value; -} - -class NotOperation implements UnaryOperation { - final SourceString name = const SourceString('!'); - bool isUserDefinable() => true; - const NotOperation(); - Constant fold(Constant constant) { - if (constant.isBool()) { - BoolConstant boolConstant = constant; - return DART_CONSTANT_SYSTEM.createBool(!boolConstant.value); - } - return null; - } - apply(value) => !value; -} - -/** - * Operations that only work if both arguments are integers. - */ -abstract class BinaryBitOperation implements BinaryOperation { - bool isUserDefinable() => true; - const BinaryBitOperation(); - Constant fold(Constant left, Constant right) { - if (left.isInt() && right.isInt()) { - IntConstant leftInt = left; - IntConstant rightInt = right; - int resultValue = foldInts(leftInt.value, rightInt.value); - if (resultValue == null) return null; - return DART_CONSTANT_SYSTEM.createInt(resultValue); - } - return null; - } - - int foldInts(int left, int right); -} - -class BitOrOperation extends BinaryBitOperation { - final SourceString name = const SourceString('|'); - const BitOrOperation(); - int foldInts(int left, int right) => left | right; - apply(left, right) => left | right; -} - -class BitAndOperation extends BinaryBitOperation { - final SourceString name = const SourceString('&'); - const BitAndOperation(); - int foldInts(int left, int right) => left & right; - apply(left, right) => left & right; -} - -class BitXorOperation extends BinaryBitOperation { - final SourceString name = const SourceString('^'); - const BitXorOperation(); - int foldInts(int left, int right) => left ^ right; - apply(left, right) => left ^ right; -} - -class ShiftLeftOperation extends BinaryBitOperation { - final SourceString name = const SourceString('<<'); - const ShiftLeftOperation(); - int foldInts(int left, int right) { - // TODO(floitsch): find a better way to guard against excessive shifts to - // the left. - if (right > 100 || right < 0) return null; - return left << right; - } - apply(left, right) => left << right; -} - -class ShiftRightOperation extends BinaryBitOperation { - final SourceString name = const SourceString('>>'); - const ShiftRightOperation(); - int foldInts(int left, int right) { - if (right < 0) return null; - return left >> right; - } - apply(left, right) => left >> right; -} - -abstract class BinaryBoolOperation implements BinaryOperation { - bool isUserDefinable() => false; - const BinaryBoolOperation(); - Constant fold(Constant left, Constant right) { - if (left.isBool() && right.isBool()) { - BoolConstant leftBool = left; - BoolConstant rightBool = right; - bool resultValue = foldBools(leftBool.value, rightBool.value); - return DART_CONSTANT_SYSTEM.createBool(resultValue); - } - return null; - } - - bool foldBools(bool left, bool right); -} - -class BooleanAndOperation extends BinaryBoolOperation { - final SourceString name = const SourceString('&&'); - const BooleanAndOperation(); - bool foldBools(bool left, bool right) => left && right; - apply(left, right) => left && right; -} - -class BooleanOrOperation extends BinaryBoolOperation { - final SourceString name = const SourceString('||'); - const BooleanOrOperation(); - bool foldBools(bool left, bool right) => left || right; - apply(left, right) => left || right; -} - -abstract class ArithmeticNumOperation implements BinaryOperation { - bool isUserDefinable() => true; - const ArithmeticNumOperation(); - Constant fold(Constant left, Constant right) { - if (left.isNum() && right.isNum()) { - NumConstant leftNum = left; - NumConstant rightNum = right; - num foldedValue; - if (left.isInt() && right.isInt()) { - foldedValue = foldInts(leftNum.value, rightNum.value); - } else { - foldedValue = foldNums(leftNum.value, rightNum.value); - } - // A division by 0 means that we might not have a folded value. - if (foldedValue == null) return null; - if (left.isInt() && right.isInt() && !isDivide() || - isTruncatingDivide()) { - assert(foldedValue is int); - return DART_CONSTANT_SYSTEM.createInt(foldedValue); - } else { - return DART_CONSTANT_SYSTEM.createDouble(foldedValue); - } - } - return null; - } - - bool isDivide() => false; - bool isTruncatingDivide() => false; - num foldInts(int left, int right) => foldNums(left, right); - num foldNums(num left, num right); -} - -class SubtractOperation extends ArithmeticNumOperation { - final SourceString name = const SourceString('-'); - const SubtractOperation(); - num foldNums(num left, num right) => left - right; - apply(left, right) => left - right; -} - -class MultiplyOperation extends ArithmeticNumOperation { - final SourceString name = const SourceString('*'); - const MultiplyOperation(); - num foldNums(num left, num right) => left * right; - apply(left, right) => left * right; -} - -class ModuloOperation extends ArithmeticNumOperation { - final SourceString name = const SourceString('%'); - const ModuloOperation(); - int foldInts(int left, int right) { - if (right == 0) return null; - return left % right; - } - num foldNums(num left, num right) => left % right; - apply(left, right) => left % right; -} - -class TruncatingDivideOperation extends ArithmeticNumOperation { - final SourceString name = const SourceString('~/'); - const TruncatingDivideOperation(); - int foldInts(int left, int right) { - if (right == 0) return null; - return left ~/ right; - } - num foldNums(num left, num right) { - num ratio = left / right; - if (ratio.isNaN || ratio.isInfinite) return null; - return ratio.truncate().toInt(); - } - apply(left, right) => left ~/ right; - bool isTruncatingDivide() => true; -} - -class DivideOperation extends ArithmeticNumOperation { - final SourceString name = const SourceString('/'); - const DivideOperation(); - num foldNums(num left, num right) => left / right; - bool isDivide() => true; - apply(left, right) => left / right; -} - -class AddOperation implements BinaryOperation { - final SourceString name = const SourceString('+'); - bool isUserDefinable() => true; - const AddOperation(); - Constant fold(Constant left, Constant right) { - if (left.isInt() && right.isInt()) { - IntConstant leftInt = left; - IntConstant rightInt = right; - int result = leftInt.value + rightInt.value; - return DART_CONSTANT_SYSTEM.createInt(result); - } else if (left.isNum() && right.isNum()) { - NumConstant leftNum = left; - NumConstant rightNum = right; - double result = leftNum.value + rightNum.value; - return DART_CONSTANT_SYSTEM.createDouble(result); - } else { - return null; - } - } - apply(left, right) => left + right; -} - -abstract class RelationalNumOperation implements BinaryOperation { - bool isUserDefinable() => true; - const RelationalNumOperation(); - Constant fold(Constant left, Constant right) { - if (left.isNum() && right.isNum()) { - NumConstant leftNum = left; - NumConstant rightNum = right; - bool foldedValue = foldNums(leftNum.value, rightNum.value); - assert(foldedValue != null); - return DART_CONSTANT_SYSTEM.createBool(foldedValue); - } - } - - bool foldNums(num left, num right); -} - -class LessOperation extends RelationalNumOperation { - final SourceString name = const SourceString('<'); - const LessOperation(); - bool foldNums(num left, num right) => left < right; - apply(left, right) => left < right; -} - -class LessEqualOperation extends RelationalNumOperation { - final SourceString name = const SourceString('<='); - const LessEqualOperation(); - bool foldNums(num left, num right) => left <= right; - apply(left, right) => left <= right; -} - -class GreaterOperation extends RelationalNumOperation { - final SourceString name = const SourceString('>'); - const GreaterOperation(); - bool foldNums(num left, num right) => left > right; - apply(left, right) => left > right; -} - -class GreaterEqualOperation extends RelationalNumOperation { - final SourceString name = const SourceString('>='); - const GreaterEqualOperation(); - bool foldNums(num left, num right) => left >= right; - apply(left, right) => left >= right; -} - -class EqualsOperation implements BinaryOperation { - final SourceString name = const SourceString('=='); - bool isUserDefinable() => true; - const EqualsOperation(); - Constant fold(Constant left, Constant right) { - if (left.isNum() && right.isNum()) { - // Numbers need to be treated specially because: NaN != NaN, -0.0 == 0.0, - // and 1 == 1.0. - NumConstant leftNum = left; - NumConstant rightNum = right; - bool result = leftNum.value == rightNum.value; - return DART_CONSTANT_SYSTEM.createBool(result); - } - if (left.isConstructedObject()) { - // Unless we know that the user-defined object does not implement the - // equality operator we cannot fold here. - return null; - } - return DART_CONSTANT_SYSTEM.createBool(left == right); - } - apply(left, right) => left == right; -} - -class IdentityOperation implements BinaryOperation { - final SourceString name = const SourceString('==='); - bool isUserDefinable() => false; - const IdentityOperation(); - BoolConstant fold(Constant left, Constant right) { - // In order to preserve runtime semantics which says that NaN !== NaN don't - // constant fold NaN === NaN. Otherwise the output depends on inlined - // variables and other optimizations. - if (left.isNaN() && right.isNaN()) return null; - return DART_CONSTANT_SYSTEM.createBool(left == right); - } - apply(left, right) => identical(left, right); -} - -/** - * A constant system implementing the Dart semantics. This system relies on - * the underlying runtime-system. That is, if dart2js is run in an environment - * that doesn't correctly implement Dart's semantics this constant system will - * not return the correct values. - */ -class DartConstantSystem extends ConstantSystem { - const add = const AddOperation(); - const bitAnd = const BitAndOperation(); - const bitNot = const BitNotOperation(); - const bitOr = const BitOrOperation(); - const bitXor = const BitXorOperation(); - const booleanAnd = const BooleanAndOperation(); - const booleanOr = const BooleanOrOperation(); - const divide = const DivideOperation(); - const equal = const EqualsOperation(); - const greaterEqual = const GreaterEqualOperation(); - const greater = const GreaterOperation(); - const identity = const IdentityOperation(); - const lessEqual = const LessEqualOperation(); - const less = const LessOperation(); - const modulo = const ModuloOperation(); - const multiply = const MultiplyOperation(); - const negate = const NegateOperation(); - const not = const NotOperation(); - const shiftLeft = const ShiftLeftOperation(); - const shiftRight = const ShiftRightOperation(); - const subtract = const SubtractOperation(); - const truncatingDivide = const TruncatingDivideOperation(); - - const DartConstantSystem(); - - IntConstant createInt(int i) => new IntConstant(i); - DoubleConstant createDouble(double d) => new DoubleConstant(d); - StringConstant createString(DartString string, Node diagnosticNode) - => new StringConstant(string, diagnosticNode); - BoolConstant createBool(bool value) => new BoolConstant(value); - NullConstant createNull() => new NullConstant(); - - bool isInt(Constant constant) => constant.isInt(); - bool isDouble(Constant constant) => constant.isDouble(); - bool isString(Constant constant) => constant.isString(); - bool isBool(Constant constant) => constant.isBool(); - bool isNull(Constant constant) => constant.isNull(); - - bool isSubtype(Compiler compiler, DartType s, DartType t) { - return compiler.types.isSubtype(s, t); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/constants.dart b/pkgs/markdown/test/lib/src/compiler/implementation/constants.dart deleted file mode 100644 index ad5dc74..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/constants.dart +++ /dev/null
@@ -1,473 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of dart2js; - -abstract class ConstantVisitor<R> { - R visitSentinel(SentinelConstant constant); - R visitFunction(FunctionConstant constant); - R visitNull(NullConstant constant); - R visitInt(IntConstant constant); - R visitDouble(DoubleConstant constant); - R visitTrue(TrueConstant constant); - R visitFalse(FalseConstant constant); - R visitString(StringConstant constant); - R visitList(ListConstant constant); - R visitMap(MapConstant constant); - R visitConstructed(ConstructedConstant constant); - R visitType(TypeConstant constant); -} - -abstract class Constant { - const Constant(); - - bool isNull() => false; - bool isBool() => false; - bool isTrue() => false; - bool isFalse() => false; - bool isInt() => false; - bool isDouble() => false; - bool isNum() => false; - bool isString() => false; - bool isList() => false; - bool isMap() => false; - bool isConstructedObject() => false; - bool isFunction() => false; - /** Returns true if the constant is null, a bool, a number or a string. */ - bool isPrimitive() => false; - /** Returns true if the constant is a list, a map or a constructed object. */ - bool isObject() => false; - bool isType() => false; - bool isSentinel() => false; - - bool isNaN() => false; - bool isMinusZero() => false; - - DartType computeType(Compiler compiler); - - List<Constant> getDependencies(); - - accept(ConstantVisitor visitor); -} - -class SentinelConstant extends Constant { - const SentinelConstant(); - static final SENTINEL = const SentinelConstant(); - - List<Constant> getDependencies() => const <Constant>[]; - - // Just use a random value. - int get hashCode => 24297418; - - bool isSentinel() => true; - - accept(ConstantVisitor visitor) => visitor.visitSentinel(this); - - DartType computeType(Compiler compiler) => compiler.types.dynamicType; -} - -class FunctionConstant extends Constant { - Element element; - - FunctionConstant(this.element); - - bool isFunction() => true; - - bool operator ==(var other) { - if (other is !FunctionConstant) return false; - return identical(other.element, element); - } - - String toString() => element.toString(); - List<Constant> getDependencies() => const <Constant>[]; - DartString toDartString() { - return new DartString.literal(element.name.slowToString()); - } - - DartType computeType(Compiler compiler) { - return compiler.functionClass.computeType(compiler); - } - - int get hashCode => (17 * element.hashCode) & 0x7fffffff; - - accept(ConstantVisitor visitor) => visitor.visitFunction(this); -} - -abstract class PrimitiveConstant extends Constant { - get value; - const PrimitiveConstant(); - bool isPrimitive() => true; - - bool operator ==(var other) { - if (other is !PrimitiveConstant) return false; - PrimitiveConstant otherPrimitive = other; - // We use == instead of 'identical' so that DartStrings compare correctly. - return value == otherPrimitive.value; - } - - String toString() => value.toString(); - // Primitive constants don't have dependencies. - List<Constant> getDependencies() => const <Constant>[]; - DartString toDartString(); -} - -class NullConstant extends PrimitiveConstant { - /** The value a Dart null is compiled to in JavaScript. */ - static const String JsNull = "null"; - - factory NullConstant() => const NullConstant._internal(); - const NullConstant._internal(); - bool isNull() => true; - get value => null; - - DartType computeType(Compiler compiler) { - return compiler.nullClass.computeType(compiler); - } - - void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { - buffer.add(JsNull); - } - - // The magic constant has no meaning. It is just a random value. - int get hashCode => 785965825; - DartString toDartString() => const LiteralDartString("null"); - - accept(ConstantVisitor visitor) => visitor.visitNull(this); -} - -abstract class NumConstant extends PrimitiveConstant { - num get value; - const NumConstant(); - bool isNum() => true; -} - -class IntConstant extends NumConstant { - final int value; - factory IntConstant(int value) { - switch (value) { - case 0: return const IntConstant._internal(0); - case 1: return const IntConstant._internal(1); - case 2: return const IntConstant._internal(2); - case 3: return const IntConstant._internal(3); - case 4: return const IntConstant._internal(4); - case 5: return const IntConstant._internal(5); - case 6: return const IntConstant._internal(6); - case 7: return const IntConstant._internal(7); - case 8: return const IntConstant._internal(8); - case 9: return const IntConstant._internal(9); - case 10: return const IntConstant._internal(10); - case -1: return const IntConstant._internal(-1); - case -2: return const IntConstant._internal(-2); - default: return new IntConstant._internal(value); - } - } - const IntConstant._internal(this.value); - bool isInt() => true; - - DartType computeType(Compiler compiler) { - return compiler.intClass.computeType(compiler); - } - - // We have to override the equality operator so that ints and doubles are - // treated as separate constants. - // The is [:!IntConstant:] check at the beginning of the function makes sure - // that we compare only equal to integer constants. - bool operator ==(var other) { - if (other is !IntConstant) return false; - IntConstant otherInt = other; - return value == otherInt.value; - } - - int get hashCode => value.hashCode; - DartString toDartString() => new DartString.literal(value.toString()); - - accept(ConstantVisitor visitor) => visitor.visitInt(this); -} - -class DoubleConstant extends NumConstant { - final double value; - factory DoubleConstant(double value) { - if (value.isNaN) { - return const DoubleConstant._internal(double.NAN); - } else if (value == double.INFINITY) { - return const DoubleConstant._internal(double.INFINITY); - } else if (value == -double.INFINITY) { - return const DoubleConstant._internal(-double.INFINITY); - } else if (value == 0.0 && !value.isNegative) { - return const DoubleConstant._internal(0.0); - } else if (value == 1.0) { - return const DoubleConstant._internal(1.0); - } else { - return new DoubleConstant._internal(value); - } - } - const DoubleConstant._internal(this.value); - bool isDouble() => true; - bool isNaN() => value.isNaN; - // We need to check for the negative sign since -0.0 == 0.0. - bool isMinusZero() => value == 0.0 && value.isNegative; - - DartType computeType(Compiler compiler) { - return compiler.doubleClass.computeType(compiler); - } - - bool operator ==(var other) { - if (other is !DoubleConstant) return false; - DoubleConstant otherDouble = other; - double otherValue = otherDouble.value; - if (value == 0.0 && otherValue == 0.0) { - return value.isNegative == otherValue.isNegative; - } else if (value.isNaN) { - return otherValue.isNaN; - } else { - return value == otherValue; - } - } - - int get hashCode => value.hashCode; - DartString toDartString() => new DartString.literal(value.toString()); - - accept(ConstantVisitor visitor) => visitor.visitDouble(this); -} - -abstract class BoolConstant extends PrimitiveConstant { - factory BoolConstant(value) { - return value ? new TrueConstant() : new FalseConstant(); - } - const BoolConstant._internal(); - bool isBool() => true; - - DartType computeType(Compiler compiler) { - return compiler.boolClass.computeType(compiler); - } - - BoolConstant negate(); -} - -class TrueConstant extends BoolConstant { - final bool value = true; - - factory TrueConstant() => const TrueConstant._internal(); - const TrueConstant._internal() : super._internal(); - bool isTrue() => true; - - FalseConstant negate() => new FalseConstant(); - - bool operator ==(var other) => identical(this, other); - // The magic constant is just a random value. It does not have any - // significance. - int get hashCode => 499; - DartString toDartString() => const LiteralDartString("true"); - - accept(ConstantVisitor visitor) => visitor.visitTrue(this); -} - -class FalseConstant extends BoolConstant { - final bool value = false; - - factory FalseConstant() => const FalseConstant._internal(); - const FalseConstant._internal() : super._internal(); - bool isFalse() => true; - - TrueConstant negate() => new TrueConstant(); - - bool operator ==(var other) => identical(this, other); - // The magic constant is just a random value. It does not have any - // significance. - int get hashCode => 536555975; - DartString toDartString() => const LiteralDartString("false"); - - accept(ConstantVisitor visitor) => visitor.visitFalse(this); -} - -class StringConstant extends PrimitiveConstant { - final DartString value; - final int hashCode; - final Node node; - - // TODO(floitsch): cache StringConstants. - // TODO(floitsch): compute hashcode without calling toString() on the - // DartString. - StringConstant(DartString value, this.node) - : this.value = value, - this.hashCode = value.slowToString().hashCode; - bool isString() => true; - - DartType computeType(Compiler compiler) { - return compiler.stringClass.computeType(compiler); - } - - bool operator ==(var other) { - if (other is !StringConstant) return false; - StringConstant otherString = other; - return (hashCode == otherString.hashCode) && (value == otherString.value); - } - - DartString toDartString() => value; - int get length => value.length; - - accept(ConstantVisitor visitor) => visitor.visitString(this); -} - -abstract class ObjectConstant extends Constant { - final DartType type; - - ObjectConstant(this.type); - bool isObject() => true; - - DartType computeType(Compiler compiler) => type; -} - -class TypeConstant extends ObjectConstant { - /// The user type that this constant represents. - final DartType representedType; - - TypeConstant(this.representedType, type) : super(type); - - bool isType() => true; - - bool operator ==(other) { - return other is TypeConstant && representedType == other.representedType; - } - - int get hashCode => representedType.hashCode * 13; - - List<Constant> getDependencies() => const <Constant>[]; - - accept(ConstantVisitor visitor) => visitor.visitType(this); -} - -class ListConstant extends ObjectConstant { - final List<Constant> entries; - final int hashCode; - - ListConstant(DartType type, List<Constant> entries) - : this.entries = entries, - hashCode = _computeHash(entries), - super(type); - bool isList() => true; - - static int _computeHash(List<Constant> entries) { - // TODO(floitsch): create a better hash. - int hash = 0; - for (Constant input in entries) hash ^= input.hashCode; - return hash; - } - - bool operator ==(var other) { - if (other is !ListConstant) return false; - ListConstant otherList = other; - if (hashCode != otherList.hashCode) return false; - // TODO(floitsch): verify that the generic types are the same. - if (entries.length != otherList.entries.length) return false; - for (int i = 0; i < entries.length; i++) { - if (entries[i] != otherList.entries[i]) return false; - } - return true; - } - - List<Constant> getDependencies() => entries; - - int get length => entries.length; - - accept(ConstantVisitor visitor) => visitor.visitList(this); -} - -class MapConstant extends ObjectConstant { - /** - * The [PROTO_PROPERTY] must not be used as normal property in any JavaScript - * object. It would change the prototype chain. - */ - static const LiteralDartString PROTO_PROPERTY = - const LiteralDartString("__proto__"); - - /** The dart class implementing constant map literals. */ - static const SourceString DART_CLASS = const SourceString("ConstantMap"); - static const SourceString DART_PROTO_CLASS = - const SourceString("ConstantProtoMap"); - static const SourceString LENGTH_NAME = const SourceString("length"); - static const SourceString JS_OBJECT_NAME = const SourceString("_jsObject"); - static const SourceString KEYS_NAME = const SourceString("_keys"); - static const SourceString PROTO_VALUE = const SourceString("_protoValue"); - - final ListConstant keys; - final List<Constant> values; - final Constant protoValue; - final int hashCode; - - MapConstant(DartType type, this.keys, List<Constant> values, this.protoValue) - : this.values = values, - this.hashCode = computeHash(values), - super(type); - bool isMap() => true; - - static int computeHash(List<Constant> values) { - // TODO(floitsch): create a better hash. - int hash = 0; - for (Constant value in values) hash ^= value.hashCode; - return hash; - } - - bool operator ==(var other) { - if (other is !MapConstant) return false; - MapConstant otherMap = other; - if (hashCode != otherMap.hashCode) return false; - // TODO(floitsch): verify that the generic types are the same. - if (keys != otherMap.keys) return false; - for (int i = 0; i < values.length; i++) { - if (values[i] != otherMap.values[i]) return false; - } - return true; - } - - List<Constant> getDependencies() { - List<Constant> result = <Constant>[keys]; - result.addAll(values); - return result; - } - - int get length => keys.length; - - accept(ConstantVisitor visitor) => visitor.visitMap(this); -} - -class ConstructedConstant extends ObjectConstant { - final List<Constant> fields; - final int hashCode; - - ConstructedConstant(DartType type, List<Constant> fields) - : this.fields = fields, - hashCode = computeHash(type, fields), - super(type) { - assert(type != null); - } - bool isConstructedObject() => true; - - static int computeHash(DartType type, List<Constant> fields) { - // TODO(floitsch): create a better hash. - int hash = 0; - for (Constant field in fields) { - hash ^= field.hashCode; - } - hash ^= type.element.hashCode; - return hash; - } - - bool operator ==(var otherVar) { - if (otherVar is !ConstructedConstant) return false; - ConstructedConstant other = otherVar; - if (hashCode != other.hashCode) return false; - // TODO(floitsch): verify that the (generic) types are the same. - if (type.element != other.type.element) return false; - if (fields.length != other.fields.length) return false; - for (int i = 0; i < fields.length; i++) { - if (fields[i] != other.fields[i]) return false; - } - return true; - } - - List<Constant> getDependencies() => fields; - - accept(ConstantVisitor visitor) => visitor.visitConstructed(this); -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/dart2js.dart b/pkgs/markdown/test/lib/src/compiler/implementation/dart2js.dart deleted file mode 100644 index ac7d422..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/dart2js.dart +++ /dev/null
@@ -1,497 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library dart2js; - -import 'dart:async'; -import 'dart:collection' show Queue, LinkedHashMap; -import 'dart:io'; -import 'dart:uri'; -import 'dart:utf'; - -import '../compiler.dart' as api; -import 'source_file.dart'; -import 'source_file_provider.dart'; -import 'filenames.dart'; -import 'util/uri_extras.dart'; -import '../../libraries.dart'; - -const String LIBRARY_ROOT = '../../../../..'; -const String OUTPUT_LANGUAGE_DART = 'Dart'; - -typedef void HandleOption(String option); - -class OptionHandler { - String pattern; - HandleOption handle; - - OptionHandler(this.pattern, this.handle); -} - -/** - * Extract the parameter of an option. - * - * For example, in ['--out=fisk.js'] and ['-ohest.js'], the parameters - * are ['fisk.js'] and ['hest.js'], respectively. - */ -String extractParameter(String argument) { - // m[0] is the entire match (which will be equal to argument). m[1] - // is something like "-o" or "--out=", and m[2] is the parameter. - Match m = new RegExp('^(-[a-z]|--.+=)(.*)').firstMatch(argument); - if (m == null) helpAndFail('Error: Unknown option "$argument".'); - return m[2]; -} - -String extractPath(String argument) { - String path = nativeToUriPath(extractParameter(argument)); - return path.endsWith("/") ? path : "$path/"; -} - -void parseCommandLine(List<OptionHandler> handlers, List<String> argv) { - // TODO(ahe): Use ../../args/args.dart for parsing options instead. - var patterns = <String>[]; - for (OptionHandler handler in handlers) { - patterns.add(handler.pattern); - } - var pattern = new RegExp('^(${Strings.join(patterns, ")\$|(")})\$'); - OUTER: for (String argument in argv) { - Match match = pattern.firstMatch(argument); - assert(match.groupCount == handlers.length); - for (int i = 0; i < handlers.length; i++) { - if (match[i + 1] != null) { - handlers[i].handle(argument); - continue OUTER; - } - } - throw 'Internal error: "$argument" did not match'; - } -} - -void compile(List<String> argv) { - bool isWindows = (Platform.operatingSystem == 'windows'); - Uri cwd = getCurrentDirectory(); - Uri libraryRoot = cwd; - Uri out = cwd.resolve('out.js'); - Uri sourceMapOut = cwd.resolve('out.js.map'); - Uri packageRoot = null; - List<String> options = new List<String>(); - bool explicitOut = false; - bool wantHelp = false; - String outputLanguage = 'JavaScript'; - bool stripArgumentSet = false; - bool analyzeOnly = false; - SourceFileProvider inputProvider = new SourceFileProvider(); - FormattingDiagnosticHandler diagnosticHandler = - new FormattingDiagnosticHandler(inputProvider); - - passThrough(String argument) => options.add(argument); - - setLibraryRoot(String argument) { - libraryRoot = cwd.resolve(extractPath(argument)); - } - - setPackageRoot(String argument) { - packageRoot = cwd.resolve(extractPath(argument)); - } - - setOutput(String argument) { - explicitOut = true; - out = cwd.resolve(nativeToUriPath(extractParameter(argument))); - sourceMapOut = Uri.parse('$out.map'); - } - - setOutputType(String argument) { - if (argument == '--output-type=dart') { - outputLanguage = OUTPUT_LANGUAGE_DART; - if (!explicitOut) { - out = cwd.resolve('out.dart'); - sourceMapOut = cwd.resolve('out.dart.map'); - } - } - passThrough(argument); - } - - String getDepsOutput(Map<String, SourceFile> sourceFiles) { - var filenames = new List.from(sourceFiles.keys); - filenames.sort(); - return Strings.join(filenames, "\n"); - } - - setStrip(String argument) { - stripArgumentSet = true; - passThrough(argument); - } - - setAnalyzeOnly(String argument) { - analyzeOnly = true; - passThrough(argument); - } - - setCategories(String argument) { - List<String> categories = extractParameter(argument).split(','); - Set<String> allowedCategories = - LIBRARIES.values.map((x) => x.category).toSet(); - allowedCategories.remove('Shared'); - allowedCategories.remove('Internal'); - List<String> allowedCategoriesList = - new List<String>.from(allowedCategories); - allowedCategoriesList.sort(); - if (categories.contains('all')) { - categories = allowedCategoriesList; - } else { - String allowedCategoriesString = - Strings.join(allowedCategoriesList, ', '); - for (String category in categories) { - if (!allowedCategories.contains(category)) { - fail('Error: unsupported library category "$category", ' - 'supported categories are: $allowedCategoriesString'); - } - } - } - return passThrough('--categories=${Strings.join(categories, ",")}'); - } - - handleShortOptions(String argument) { - var shortOptions = argument.substring(1).splitChars(); - for (var shortOption in shortOptions) { - switch (shortOption) { - case 'v': - diagnosticHandler.verbose = true; - break; - case 'h': - case '?': - wantHelp = true; - break; - case 'c': - passThrough('--enable-checked-mode'); - break; - default: - throw 'Internal error: "$shortOption" did not match'; - } - } - } - - List<String> arguments = <String>[]; - List<OptionHandler> handlers = <OptionHandler>[ - new OptionHandler('-[chv?]+', handleShortOptions), - new OptionHandler('--throw-on-error', - (_) => diagnosticHandler.throwOnError = true), - new OptionHandler('--suppress-warnings', - (_) => diagnosticHandler.showWarnings = false), - new OptionHandler('--output-type=dart|--output-type=js', setOutputType), - new OptionHandler('--verbose', (_) => diagnosticHandler.verbose = true), - new OptionHandler('--library-root=.+', setLibraryRoot), - new OptionHandler('--out=.+|-o.+', setOutput), - new OptionHandler('--allow-mock-compilation', passThrough), - new OptionHandler('--minify', passThrough), - new OptionHandler('--force-strip=.*', setStrip), - // TODO(ahe): Remove the --no-colors option. - new OptionHandler('--disable-diagnostic-colors', - (_) => diagnosticHandler.enableColors = false), - new OptionHandler('--enable-diagnostic-colors', - (_) => diagnosticHandler.enableColors = true), - new OptionHandler('--enable[_-]checked[_-]mode|--checked', - (_) => passThrough('--enable-checked-mode')), - new OptionHandler('--enable-concrete-type-inference', - (_) => passThrough('--enable-concrete-type-inference')), - new OptionHandler(r'--help|/\?|/h', (_) => wantHelp = true), - new OptionHandler('--package-root=.+|-p.+', setPackageRoot), - new OptionHandler('--disallow-unsafe-eval', passThrough), - new OptionHandler('--analyze-all', passThrough), - new OptionHandler('--analyze-only', setAnalyzeOnly), - new OptionHandler('--disable-native-live-type-analysis', passThrough), - new OptionHandler('--reject-deprecated-language-features', passThrough), - new OptionHandler('--report-sdk-use-of-deprecated-language-features', - passThrough), - new OptionHandler('--categories=.*', setCategories), - - // The following two options must come last. - new OptionHandler('-.*', (String argument) { - helpAndFail('Error: Unknown option "$argument".'); - }), - new OptionHandler('.*', (String argument) { - arguments.add(nativeToUriPath(argument)); - }) - ]; - - parseCommandLine(handlers, argv); - if (wantHelp) helpAndExit(diagnosticHandler.verbose); - - if (outputLanguage != OUTPUT_LANGUAGE_DART && stripArgumentSet) { - helpAndFail('Error: --force-strip may only be used with ' - '--output-type=dart'); - } - if (arguments.isEmpty) { - helpAndFail('Error: No Dart file specified.'); - } - if (arguments.length > 1) { - var extra = arguments.getRange(1, arguments.length - 1); - helpAndFail('Error: Extra arguments: ${Strings.join(extra, " ")}'); - } - - void handler(Uri uri, int begin, int end, String message, - api.Diagnostic kind) { - diagnosticHandler.diagnosticHandler(uri, begin, end, message, kind); - } - - Uri uri = cwd.resolve(arguments[0]); - if (packageRoot == null) { - packageRoot = uri.resolve('./packages/'); - } - - diagnosticHandler.info('package root is $packageRoot'); - - int charactersWritten = 0; - - compilationDone(String code) { - if (analyzeOnly) return; - if (code == null) { - fail('Error: Compilation failed.'); - } - writeString(Uri.parse('$out.deps'), - getDepsOutput(inputProvider.sourceFiles)); - diagnosticHandler.info( - 'compiled ${inputProvider.dartCharactersRead} characters Dart ' - '-> $charactersWritten characters $outputLanguage ' - 'in ${relativize(cwd, out, isWindows)}'); - if (!explicitOut) { - String input = uriPathToNative(arguments[0]); - String output = relativize(cwd, out, isWindows); - print('Dart file $input compiled to $outputLanguage: $output'); - } - } - - StreamSink<String> outputProvider(String name, String extension) { - Uri uri; - String sourceMapFileName; - bool isPrimaryOutput = false; - if (name == '') { - if (extension == 'js' || extension == 'dart') { - isPrimaryOutput = true; - uri = out; - sourceMapFileName = - sourceMapOut.path.substring(sourceMapOut.path.lastIndexOf('/') + 1); - } else if (extension == 'js.map' || extension == 'dart.map') { - uri = sourceMapOut; - } else { - fail('Error: Unknown extension: $extension'); - } - } else { - uri = out.resolve('$name.$extension'); - } - - if (uri.scheme != 'file') { - fail('Error: Unhandled scheme ${uri.scheme} in $uri.'); - } - var outputStream = new File(uriPathToNative(uri.path)).openOutputStream(); - - CountingSink sink; - - onDone() { - if (sourceMapFileName != null) { - String sourceMapTag = '//@ sourceMappingURL=$sourceMapFileName\n'; - sink.count += sourceMapTag.length; - outputStream.writeString(sourceMapTag); - } - outputStream.close(); - if (isPrimaryOutput) { - charactersWritten += sink.count; - } - } - - var controller = new StreamController<String>(); - controller.stream.listen(outputStream.writeString, onDone: onDone); - sink = new CountingSink(controller); - return sink; - } - - api.compile(uri, libraryRoot, packageRoot, - inputProvider.readStringFromUri, handler, - options, outputProvider) - .then(compilationDone); -} - -// TODO(ahe): Get rid of this class if http://dartbug.com/8118 is fixed. -class CountingSink implements StreamSink<String> { - final StreamSink<String> sink; - int count = 0; - - CountingSink(this.sink); - - add(String value) { - sink.add(value); - count += value.length; - } - - signalError(AsyncError error) => sink.signalError(error); - - close() => sink.close(); -} - -class AbortLeg { - final message; - AbortLeg(this.message); - toString() => 'Aborted due to --throw-on-error: $message'; -} - -void writeString(Uri uri, String text) { - if (uri.scheme != 'file') { - fail('Error: Unhandled scheme ${uri.scheme}.'); - } - var file = new File(uriPathToNative(uri.path)).openSync(FileMode.WRITE); - file.writeStringSync(text); - file.closeSync(); -} - -void fail(String message) { - print(message); - exit(1); -} - -void compilerMain(Options options) { - var root = uriPathToNative("/$LIBRARY_ROOT"); - List<String> argv = ['--library-root=${options.script}$root']; - argv.addAll(options.arguments); - compile(argv); -} - -void help() { - // This message should be no longer than 20 lines. The default - // terminal size normally 80x24. Two lines are used for the prompts - // before and after running the compiler. Another two lines may be - // used to print an error message. - print(''' -Usage: dart2js [options] dartfile - -Compiles Dart to JavaScript. - -Common options: - -o<file> Generate the output into <file>. - -c Insert runtime type checks and enable assertions (checked mode). - -h Display this message (add -v for information about all options).'''); -} - -void verboseHelp() { - print(''' -Usage: dart2js [options] dartfile - -Compiles Dart to JavaScript. - -Supported options: - -o<file>, --out=<file> - Generate the output into <file>. - - -c, --enable-checked-mode, --checked - Insert runtime type checks and enable assertions (checked mode). - - -h, /h, /?, --help - Display this message (add -v for information about all options). - - -v, --verbose - Display verbose information. - - -p<path>, --package-root=<path> - Where to find packages, that is, "package:..." imports. - - --analyze-all - Analyze all code. Without this option, the compiler only analyzes - code that is reachable from [main]. This option is useful for - finding errors in libraries, but using it can result in bigger and - slower output. - - --analyze-only - Analyze but do not generate code. - - --minify - Generate minified output. - - --suppress-warnings - Do not display any warnings. - - --enable-diagnostic-colors - Add colors to diagnostic messages. - -The following options are only used for compiler development and may -be removed in a future version: - - --output-type=dart - Output Dart code instead of JavaScript. - - --throw-on-error - Throw an exception if a compile-time error is detected. - - --library-root=<directory> - Where to find the Dart platform libraries. - - --allow-mock-compilation - Do not generate a call to main if either of the following - libraries are used: dart:dom, dart:html dart:io. - - --enable-concrete-type-inference - Enable experimental concrete type inference. - - --disable-native-live-type-analysis - Disable the optimization that removes unused native types from dart:html - and related libraries. - - --disallow-unsafe-eval - Disable dynamic generation of code in the generated output. This is - necessary to satisfy CSP restrictions (see http://www.w3.org/TR/CSP/). - This flag is not continuously tested. Please report breakages and we - will fix them as soon as possible. - - --reject-deprecated-language-features - Reject deprecated language features. Without this option, the - compiler will accept language features that are no longer valid - according to The Dart Programming Language Specification, version - 0.12, M1. - - --report-sdk-use-of-deprecated-language-features - Report use of deprecated features in Dart platform libraries. - Without this option, the compiler will silently accept use of - deprecated language features from these libraries. The option - --reject-deprecated-language-features controls if these usages are - reported as errors or warnings. - - --categories=<categories> - - A comma separated list of allowed library categories. The default - is "Client". Possible categories can be seen by providing an - unsupported category, for example, --categories=help. To enable - all categories, use --categories=all. - -'''.trim()); -} - -void helpAndExit(bool verbose) { - if (verbose) { - verboseHelp(); - } else { - help(); - } - exit(0); -} - -void helpAndFail(String message) { - help(); - print(''); - fail(message); -} - -void main() { - try { - compilerMain(new Options()); - } catch (exception, trace) { - try { - print('Internal error: $exception'); - } catch (ignored) { - print('Internal error: error while printing exception'); - } - try { - print(trace); - } finally { - exit(253); // 253 is recognized as a crash by our test scripts. - } - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/dart2js.dart.snapshot b/pkgs/markdown/test/lib/src/compiler/implementation/dart2js.dart.snapshot deleted file mode 100644 index 758a05a..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/dart2js.dart.snapshot +++ /dev/null Binary files differ
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/dart2jslib.dart b/pkgs/markdown/test/lib/src/compiler/implementation/dart2jslib.dart deleted file mode 100644 index 9b683f2..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/dart2jslib.dart +++ /dev/null
@@ -1,61 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library dart2js; - -import 'dart:async'; -import 'dart:uri'; -import 'dart:collection' show Queue, LinkedHashMap; - -import 'closure.dart' as closureMapping; -import 'dart_backend/dart_backend.dart' as dart_backend; -import 'dart_types.dart'; -import 'elements/elements.dart'; -import 'elements/modelx.dart' - show ErroneousElementX, - CompilationUnitElementX, - LibraryElementX, - PrefixElementX, - VoidElementX; -import 'js_backend/js_backend.dart' as js_backend; -import 'native_handler.dart' as native; -import 'scanner/scanner_implementation.dart'; -import 'scanner/scannerlib.dart'; -import 'ssa/ssa.dart'; -import 'string_validator.dart'; -import 'source_file.dart'; -import 'tree/tree.dart'; -import 'universe/universe.dart'; -import 'util/characters.dart'; -import 'util/util.dart'; -import '../compiler.dart' as api; -import 'patch_parser.dart'; -import 'types/types.dart' as ti; -import 'resolution/resolution.dart'; -import 'js/js.dart' as js; - -export 'resolution/resolution.dart' show TreeElements, TreeElementMapping; -export 'scanner/scannerlib.dart' show SourceString, - isUserDefinableOperator, - isUnaryOperator, - isBinaryOperator, - isTernaryOperator, - isMinusOperator; -export 'universe/universe.dart' show Selector; - -part 'code_buffer.dart'; -part 'compile_time_constants.dart'; -part 'compiler.dart'; -part 'constants.dart'; -part 'constant_system.dart'; -part 'constant_system_dart.dart'; -part 'diagnostic_listener.dart'; -part 'enqueue.dart'; -part 'library_loader.dart'; -part 'resolved_visitor.dart'; -part 'script.dart'; -part 'tree_validator.dart'; -part 'typechecker.dart'; -part 'warnings.dart'; -part 'world.dart';
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/dart_backend/backend.dart b/pkgs/markdown/test/lib/src/compiler/implementation/dart_backend/backend.dart deleted file mode 100644 index 6a3b000..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/dart_backend/backend.dart +++ /dev/null
@@ -1,593 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of dart_backend; - -// TODO(ahe): This class is simply wrong. This backend should use -// elements when it can, not AST nodes. Perhaps a [Map<Element, -// TreeElements>] is what is needed. -class ElementAst { - final Node ast; - final TreeElements treeElements; - - ElementAst(this.ast, this.treeElements); - - factory ElementAst.rewrite(compiler, ast, treeElements, stripAsserts) { - final rewriter = - new FunctionBodyRewriter(compiler, treeElements, stripAsserts); - return new ElementAst(rewriter.visit(ast), rewriter.cloneTreeElements); - } - - ElementAst.forClassLike(this.ast) - : this.treeElements = new TreeElementMapping(null); -} - -// TODO(ahe): This class should not subclass [TreeElementMapping], if -// anything, it should implement TreeElements. -class AggregatedTreeElements extends TreeElementMapping { - final List<TreeElements> treeElements; - - AggregatedTreeElements() : treeElements = <TreeElements>[], super(null); - - Element operator[](Node node) { - final result = super[node]; - return result != null ? result : getFirstNotNullResult((e) => e[node]); - } - - Selector getSelector(Send send) { - final result = super.getSelector(send); - return result != null ? - result : getFirstNotNullResult((e) => e.getSelector(send)); - } - - DartType getType(Node node) { - final result = super.getType(node); - return result != null ? - result : getFirstNotNullResult((e) => e.getType(node)); - } - - getFirstNotNullResult(f(TreeElements element)) { - for (final element in treeElements) { - final result = f(element); - if (result != null) return result; - } - - return null; - } -} - -class VariableListAst extends ElementAst { - VariableListAst(ast) : super(ast, new AggregatedTreeElements()); - - add(VariableElement element, TreeElements treeElements) { - AggregatedTreeElements e = this.treeElements; - e[element.cachedNode] = element; - e.treeElements.add(treeElements); - } -} - -class FunctionBodyRewriter extends CloningVisitor { - final Compiler compiler; - final bool stripAsserts; - - FunctionBodyRewriter(this.compiler, originalTreeElements, this.stripAsserts) - : super(originalTreeElements); - - visitBlock(Block block) { - shouldOmit(Statement statement) { - if (statement is EmptyStatement) return true; - if (statement is ExpressionStatement) { - Send send = statement.expression.asSend(); - if (send != null) { - Element element = originalTreeElements[send]; - if (stripAsserts && identical(element, compiler.assertMethod)) { - return true; - } - } - } - return false; - } - - rewriteStatement(Statement statement) { - if (statement is Block) { - Link statements = statement.statements.nodes; - if (!statements.isEmpty && statements.tail.isEmpty) { - Statement single = statements.head; - bool isDeclaration = - single is VariableDefinitions || single is FunctionDeclaration; - if (!isDeclaration) return single; - } - } - return statement; - } - - NodeList statements = block.statements; - LinkBuilder<Statement> builder = new LinkBuilder<Statement>(); - for (Statement statement in statements.nodes) { - if (!shouldOmit(statement)) { - builder.addLast(visit(rewriteStatement(statement))); - } - } - return new Block(rewriteNodeList(statements, builder.toLink())); - } -} - -class DartBackend extends Backend { - final List<CompilerTask> tasks; - final bool forceStripTypes; - final bool stripAsserts; - // TODO(antonm): make available from command-line options. - final bool outputAst = false; - - Map<Element, TreeElements> get resolvedElements => - compiler.enqueuer.resolution.resolvedElements; - - /** - * Tells whether it is safe to remove type declarations from variables, - * functions parameters. It becomes not safe if: - * 1) TypeError is used somewhere in the code, - * 2) The code has typedefs in right hand side of IS checks, - * 3) The code has classes which extend typedefs, have type arguments typedefs - * or type variable bounds typedefs. - * These restrictions can be less strict. - */ - bool isSafeToRemoveTypeDeclarations( - Map<ClassElement, Set<Element>> classMembers) { - Set<DartType> processedTypes = new Set<DartType>(); - List<DartType> workQueue = new List<DartType>(); - workQueue.addAll( - classMembers.keys.map((classElement) => classElement.thisType)); - workQueue.addAll(compiler.resolverWorld.isChecks); - Element typeErrorElement = - compiler.coreLibrary.find(new SourceString('TypeError')); - DartType typeErrorType = typeErrorElement.computeType(compiler); - if (workQueue.indexOf(typeErrorType) != -1) { - return false; - } - - void processTypeArguments(Element classElement, NodeList typeArguments) { - if (typeArguments == null) return; - for (Node typeArgument in typeArguments.nodes) { - if (typeArgument is TypeVariable) { - typeArgument = typeArgument.bound; - } - if (typeArgument == null) continue; - assert(typeArgument is TypeAnnotation); - DartType argumentType = - compiler.resolveTypeAnnotation(classElement, typeArgument); - assert(argumentType != null); - workQueue.add(argumentType); - } - } - - void processTypeAnnotationList(Element classElement, NodeList annotations) { - for (Link link = annotations.nodes; !link.isEmpty; link = link.tail) { - TypeAnnotation typeAnnotation = link.head; - NodeList typeArguments = typeAnnotation.typeArguments; - processTypeArguments(classElement, typeArguments); - } - } - - void processSuperclassTypeArguments(Element classElement, Node superclass) { - if (superclass == null) return; - MixinApplication superMixinApplication = superclass.asMixinApplication(); - if (superMixinApplication != null) { - processTypeAnnotationList(classElement, superMixinApplication.mixins); - } else { - TypeAnnotation typeAnnotation = superclass; - NodeList typeArguments = typeAnnotation.typeArguments; - processTypeArguments(classElement, typeArguments); - } - } - - while (!workQueue.isEmpty) { - DartType type = workQueue.removeLast(); - if (processedTypes.contains(type)) continue; - processedTypes.add(type); - if (type is TypedefType) return false; - if (type is InterfaceType) { - ClassElement element = type.element; - Node node = element.parseNode(compiler); - if (node is ClassNode) { - ClassNode classNode = node; - processTypeArguments(element, classNode.typeParameters); - processSuperclassTypeArguments(element, classNode.superclass); - processTypeAnnotationList(element, classNode.interfaces); - } else { - MixinApplication mixinNode = node; - processSuperclassTypeArguments(element, mixinNode.superclass); - if (mixinNode is NamedMixinApplication) { - NamedMixinApplication namedMixinNode = mixinNode; - processTypeArguments(element, namedMixinNode.typeParameters); - } - } - // Check all supertypes. - if (element.allSupertypes != null) { - workQueue.addAll(element.allSupertypes.toList()); - } - } - } - return true; - } - - DartBackend(Compiler compiler, List<String> strips) - : tasks = <CompilerTask>[], - forceStripTypes = strips.indexOf('types') != -1, - stripAsserts = strips.indexOf('asserts') != -1, - super(compiler); - - void enqueueHelpers(ResolutionEnqueuer world) { - // Right now resolver doesn't always resolve interfaces needed - // for literals, so force them. TODO(antonm): fix in the resolver. - final LITERAL_TYPE_NAMES = const [ - 'Map', 'List', 'num', 'int', 'double', 'bool' - ]; - final coreLibrary = compiler.coreLibrary; - for (final name in LITERAL_TYPE_NAMES) { - ClassElement classElement = coreLibrary.findLocal(new SourceString(name)); - classElement.ensureResolved(compiler); - } - } - void codegen(CodegenWorkItem work) { } - void processNativeClasses(Enqueuer world, - Iterable<LibraryElement> libraries) { } - - bool isUserLibrary(LibraryElement lib) { - final INTERNAL_HELPERS = [ - compiler.jsHelperLibrary, - compiler.interceptorsLibrary, - ]; - return INTERNAL_HELPERS.indexOf(lib) == -1 && !lib.isPlatformLibrary; - } - - void assembleProgram() { - // Conservatively traverse all platform libraries and collect member names. - // TODO(antonm): ideally we should only collect names of used members, - // however as of today there are problems with names of some core library - // interfaces, most probably for interfaces of literals. - final fixedMemberNames = new Set<String>(); - for (final library in compiler.libraries.values) { - if (!library.isPlatformLibrary) continue; - library.implementation.forEachLocalMember((Element element) { - if (element.isClass()) { - ClassElement classElement = element; - // Make sure we parsed the class to initialize its local members. - // TODO(smok): Figure out if there is a better way to fill local - // members. - element.parseNode(compiler); - classElement.forEachLocalMember((member) { - final name = member.name.slowToString(); - // Skip operator names. - if (!name.startsWith(r'operator$')) { - // Fetch name of named constructors and factories if any, - // otherwise store regular name. - // TODO(antonm): better way to analyze the name. - fixedMemberNames.add(name.split(r'$').last); - } - }); - } - // Even class names are added due to a delicate problem we have: - // if one imports dart:core with a prefix, we cannot tell prefix.name - // from dynamic invocation (alas!). So we'd better err on preserving - // those names. - fixedMemberNames.add(element.name.slowToString()); - }); - } - // The VM will automatically invoke the call method of objects - // that are invoked as functions. Make sure to not rename that. - fixedMemberNames.add('call'); - // TODO(antonm): TypeError.srcType and TypeError.dstType are defined in - // runtime/lib/error.dart. Overall, all DartVM specific libs should be - // accounted for. - fixedMemberNames.add('srcType'); - fixedMemberNames.add('dstType'); - - /** - * Tells whether we should output given element. Corelib classes like - * Object should not be in the resulting code. - */ - bool shouldOutput(Element element) { - return !identical(element.kind, ElementKind.VOID) - && isUserLibrary(element.getLibrary()) - && !element.isSynthesized - && element is !AbstractFieldElement; - } - - final elementAsts = new Map<Element, ElementAst>(); - - parse(element) => element.parseNode(compiler); - - Set<Element> topLevelElements = new Set<Element>(); - Map<ClassElement, Set<Element>> classMembers = - new Map<ClassElement, Set<Element>>(); - - // Build all top level elements to emit and necessary class members. - var newTypedefElementCallback, newClassElementCallback; - - processElement(element, elementAst) { - new ReferencedElementCollector( - compiler, - element, elementAst.treeElements, - newTypedefElementCallback, newClassElementCallback).collect(); - elementAsts[element] = elementAst; - } - - addTopLevel(element, elementAst) { - if (topLevelElements.contains(element)) return; - topLevelElements.add(element); - processElement(element, elementAst); - } - - addClass(classElement) { - addTopLevel(classElement, - new ElementAst.forClassLike(parse(classElement))); - classMembers.putIfAbsent(classElement, () => new Set()); - } - - newTypedefElementCallback = (TypedefElement element) { - if (!shouldOutput(element)) return; - addTopLevel(element, - new ElementAst.forClassLike(parse(element))); - }; - newClassElementCallback = (ClassElement classElement) { - if (!shouldOutput(classElement)) return; - addClass(classElement); - }; - - compiler.resolverWorld.instantiatedClasses.forEach( - (ClassElement classElement) { - if (shouldOutput(classElement)) addClass(classElement); - }); - resolvedElements.forEach((element, treeElements) { - if (!shouldOutput(element) || treeElements == null) return; - var elementAst = new ElementAst.rewrite( - compiler, parse(element), treeElements, stripAsserts); - if (element.isField()) { - final list = (element as VariableElement).variables; - elementAst = elementAsts.putIfAbsent( - list, () => new VariableListAst(parse(list))); - (elementAst as VariableListAst).add(element, treeElements); - element = list; - } - - if (element.isMember()) { - ClassElement enclosingClass = element.getEnclosingClass(); - assert(enclosingClass.isClass()); - assert(enclosingClass.isTopLevel()); - assert(shouldOutput(enclosingClass)); - addClass(enclosingClass); - classMembers[enclosingClass].add(element); - processElement(element, elementAst); - } else { - if (!element.isTopLevel()) { - compiler.cancel('Cannot process $element', element: element); - } - addTopLevel(element, elementAst); - } - }); - - // Add synthesized constructors to classes with no resolved constructors, - // but which originally had any constructor. That should prevent - // those classes from being instantiable with default constructor. - Identifier synthesizedIdentifier = - new Identifier(new StringToken(IDENTIFIER_INFO, '', -1)); - - NextClassElement: - for (ClassElement classElement in classMembers.keys) { - for (Element member in classMembers[classElement]) { - if (member.isConstructor()) continue NextClassElement; - } - if (classElement.constructors.isEmpty) continue NextClassElement; - - // TODO(antonm): check with AAR team if there is better approach. - // As an idea: provide template as a Dart code---class C { C.name(); }--- - // and then overwrite necessary parts. - ClassNode classNode = classElement.parseNode(compiler); - SynthesizedConstructorElementX constructor = - new SynthesizedConstructorElementX(classElement); - constructor.type = new FunctionType( - constructor, - compiler.types.voidType, - const Link<DartType>(), - const Link<DartType>(), - const Link<SourceString>(), - const Link<DartType>() - ); - constructor.cachedNode = new FunctionExpression( - new Send(classNode.name, synthesizedIdentifier), - new NodeList(new StringToken(OPEN_PAREN_INFO, '(', -1), - const Link<Node>(), - new StringToken(CLOSE_PAREN_INFO, ')', -1)), - new EmptyStatement(new StringToken(SEMICOLON_INFO, ';', -1)), - null, Modifiers.EMPTY, null, null); - - classMembers[classElement].add(constructor); - elementAsts[constructor] = - new ElementAst(constructor.cachedNode, new TreeElementMapping(null)); - } - - // Create all necessary placeholders. - PlaceholderCollector collector = - new PlaceholderCollector(compiler, fixedMemberNames, elementAsts); - // Add synthesizedIdentifier to set of unresolved names to rename it to - // some unused identifier. - collector.unresolvedNodes.add(synthesizedIdentifier); - makePlaceholders(element) { - collector.collect(element); - if (element.isClass()) { - classMembers[element].forEach(makePlaceholders); - } - } - topLevelElements.forEach(makePlaceholders); - // Create renames. - Map<Node, String> renames = new Map<Node, String>(); - Map<LibraryElement, String> imports = new Map<LibraryElement, String>(); - bool shouldCutDeclarationTypes = forceStripTypes - || (compiler.enableMinification - && isSafeToRemoveTypeDeclarations(classMembers)); - renamePlaceholders( - compiler, collector, renames, imports, - fixedMemberNames, shouldCutDeclarationTypes); - - // Sort elements. - final sortedTopLevels = sortElements(topLevelElements); - final sortedClassMembers = new Map<ClassElement, List<Element>>(); - classMembers.forEach((classElement, members) { - sortedClassMembers[classElement] = sortElements(members); - }); - - if (outputAst) { - // TODO(antonm): Ideally XML should be a separate backend. - // TODO(antonm): obey renames and minification, at least as an option. - StringBuffer sb = new StringBuffer(); - outputElement(element) { sb.add(parse(element).toDebugString()); } - - // Emit XML for AST instead of the program. - for (final topLevel in sortedTopLevels) { - if (topLevel.isClass()) { - // TODO(antonm): add some class info. - sortedClassMembers[topLevel].forEach(outputElement); - } else { - outputElement(topLevel); - } - } - compiler.assembledCode = '<Program>\n$sb</Program>\n'; - return; - } - - final topLevelNodes = <Node>[]; - final memberNodes = new Map<ClassNode, List<Node>>(); - for (final element in sortedTopLevels) { - topLevelNodes.add(elementAsts[element].ast); - if (element.isClass() && !element.isMixinApplication) { - final members = <Node>[]; - for (final member in sortedClassMembers[element]) { - members.add(elementAsts[member].ast); - } - memberNodes[elementAsts[element].ast] = members; - } - } - - final unparser = new EmitterUnparser(renames); - emitCode(unparser, imports, topLevelNodes, memberNodes); - compiler.assembledCode = unparser.result; - - // Output verbose info about size ratio of resulting bundle to all - // referenced non-platform sources. - logResultBundleSizeInfo(topLevelElements); - } - - void logResultBundleSizeInfo(Set<Element> topLevelElements) { - Iterable<LibraryElement> referencedLibraries = - compiler.libraries.values.where(isUserLibrary); - // Sum total size of scripts in each referenced library. - int nonPlatformSize = 0; - for (LibraryElement lib in referencedLibraries) { - for (CompilationUnitElement compilationUnit in lib.compilationUnits) { - nonPlatformSize += compilationUnit.script.text.length; - } - } - int percentage = compiler.assembledCode.length * 100 ~/ nonPlatformSize; - log('Total used non-platform files size: ${nonPlatformSize} bytes, ' - 'bundle size: ${compiler.assembledCode.length} bytes (${percentage}%)'); - } - - log(String message) => compiler.log('[DartBackend] $message'); -} - -class EmitterUnparser extends Unparser { - final Map<Node, String> renames; - - EmitterUnparser(this.renames); - - visit(Node node) { - if (node != null && renames.containsKey(node)) { - sb.add(renames[node]); - } else { - super.visit(node); - } - } - - unparseSendReceiver(Send node, {bool spacesNeeded: false}) { - // TODO(smok): Remove ugly hack for library prefices. - if (node.receiver != null && renames[node.receiver] == '') return; - super.unparseSendReceiver(node, spacesNeeded: spacesNeeded); - } - - unparseFunctionName(Node name) { - if (name != null && renames.containsKey(name)) { - sb.add(renames[name]); - } else { - super.unparseFunctionName(name); - } - } -} - - -/** - * Some elements are not recorded by resolver now, - * for example, typedefs or classes which are only - * used in signatures, as/is operators or in super clauses - * (just to name a few). Retraverse AST to pick those up. - */ -class ReferencedElementCollector extends Visitor { - final Compiler compiler; - final Element rootElement; - final TreeElements treeElements; - final newTypedefElementCallback; - final newClassElementCallback; - - ReferencedElementCollector( - this.compiler, - Element rootElement, this.treeElements, - this.newTypedefElementCallback, this.newClassElementCallback) - : this.rootElement = (rootElement is VariableElement) - ? (rootElement as VariableElement).variables : rootElement; - - visitClassNode(ClassNode node) { - super.visitClassNode(node); - // Temporary hack which should go away once interfaces - // and default clauses are out. - if (node.defaultClause != null) { - // Resolver cannot resolve parameterized default clauses. - TypeAnnotation evilCousine = new TypeAnnotation( - node.defaultClause.typeName, null); - evilCousine.accept(this); - } - } - - visitNode(Node node) { node.visitChildren(this); } - - visitTypeAnnotation(TypeAnnotation typeAnnotation) { - // We call [resolveReturnType] to allow having 'void'. - final type = compiler.resolveReturnType(rootElement, typeAnnotation); - Element typeElement = type.element; - if (typeElement.isTypedef()) newTypedefElementCallback(typeElement); - if (typeElement.isClass()) newClassElementCallback(typeElement); - typeAnnotation.visitChildren(this); - } - - void collect() { - compiler.withCurrentElement(rootElement, () { - rootElement.parseNode(compiler).accept(this); - }); - } -} - -compareBy(f) => (x, y) => f(x).compareTo(f(y)); - -List sorted(Iterable l, comparison) { - final result = new List.from(l); - result.sort(comparison); - return result; -} - -compareElements(e0, e1) { - int result = compareBy((e) => e.getLibrary().canonicalUri.toString())(e0, e1); - if (result != 0) return result; - return compareBy((e) => e.position().charOffset)(e0, e1); -} - -List<Element> sortElements(Iterable<Element> elements) => - sorted(elements, compareElements);
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/dart_backend/dart_backend.dart b/pkgs/markdown/test/lib/src/compiler/implementation/dart_backend/dart_backend.dart deleted file mode 100644 index 8a8abe4..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/dart_backend/dart_backend.dart +++ /dev/null
@@ -1,25 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library dart_backend; - -import '../elements/elements.dart'; -import '../elements/modelx.dart' show SynthesizedConstructorElementX; -import '../dart2jslib.dart'; -import '../dart_types.dart'; -import '../tree/tree.dart'; -import '../util/util.dart'; - -import '../scanner/scannerlib.dart' show StringToken, - Keyword, - OPEN_PAREN_INFO, - CLOSE_PAREN_INFO, - SEMICOLON_INFO, - IDENTIFIER_INFO; - -part 'backend.dart'; -part 'emitter.dart'; -part 'renamer.dart'; -part 'placeholder_collector.dart'; -part 'utils.dart';
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/dart_backend/emitter.dart b/pkgs/markdown/test/lib/src/compiler/implementation/dart_backend/emitter.dart deleted file mode 100644 index c074af4..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/dart_backend/emitter.dart +++ /dev/null
@@ -1,24 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of dart_backend; - -String emitCode( - Unparser unparser, - Map<LibraryElement, String> imports, - Collection<Node> topLevelNodes, - Map<ClassNode, Collection<Node>> classMembers) { - imports.forEach((libraryElement, prefix) { - unparser.unparseImportTag('${libraryElement.canonicalUri}', prefix); - }); - - for (final node in topLevelNodes) { - if (node is ClassNode) { - // TODO(smok): Filter out default constructors here. - unparser.unparseClassWithBody(node, classMembers[node]); - } else { - unparser.unparse(node); - } - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/dart_backend/placeholder_collector.dart b/pkgs/markdown/test/lib/src/compiler/implementation/dart_backend/placeholder_collector.dart deleted file mode 100644 index d184663..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/dart_backend/placeholder_collector.dart +++ /dev/null
@@ -1,626 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of dart_backend; - -class LocalPlaceholder { - final String identifier; - final Set<Node> nodes; - LocalPlaceholder(this.identifier) : nodes = new Set<Node>(); - int get hashCode => identifier.hashCode; - String toString() => - 'local_placeholder[id($identifier), nodes($nodes)]'; -} - -class FunctionScope { - final Set<String> parameterIdentifiers; - final Set<LocalPlaceholder> localPlaceholders; - FunctionScope() - : parameterIdentifiers = new Set<String>(), - localPlaceholders = new Set<LocalPlaceholder>(); - void registerParameter(Identifier node) { - parameterIdentifiers.add(node.source.slowToString()); - } -} - -class ConstructorPlaceholder { - final Node node; - final DartType type; - final bool isRedirectingCall; - ConstructorPlaceholder(this.node, this.type) - : this.isRedirectingCall = false; - // Note: factory redirection is not redirecting call! - ConstructorPlaceholder.redirectingCall(this.node) - : this.type = null, this.isRedirectingCall = true; -} - -class DeclarationTypePlaceholder { - final TypeAnnotation typeNode; - final bool requiresVar; - DeclarationTypePlaceholder(this.typeNode, this.requiresVar); -} - -class SendVisitor extends ResolvedVisitor { - final PlaceholderCollector collector; - - get compiler => collector.compiler; - - SendVisitor(this.collector, TreeElements elements) : super(elements); - - visitOperatorSend(Send node) {} - visitForeignSend(Send node) {} - - visitSuperSend(Send node) { - Element element = elements[node]; - if (element != null && element.isConstructor()) { - collector.makeRedirectingConstructorPlaceholder(node.selector, element); - } else { - collector.tryMakeMemberPlaceholder(node.selector); - } - } - - visitDynamicSend(Send node) { - final element = elements[node]; - if (element == null || !element.isErroneous()) { - collector.tryMakeMemberPlaceholder(node.selector); - } - } - - visitClosureSend(Send node) { - final element = elements[node]; - if (element != null) { - collector.tryMakeLocalPlaceholder(element, node.selector); - } - } - - visitGetterSend(Send node) { - final element = elements[node]; - // element == null means dynamic property access. - if (element == null) { - collector.tryMakeMemberPlaceholder(node.selector); - } else if (element.isErroneous()) { - return; - } else if (element.isPrefix()) { - // Node is prefix part in case of source 'lib.somesetter = 5;' - collector.makeNullPlaceholder(node); - } else if (Elements.isStaticOrTopLevel(element)) { - // Unqualified or prefixed top level or static. - collector.makeElementPlaceholder(node.selector, element); - } else if (!element.isTopLevel()) { - if (element.isInstanceMember()) { - collector.tryMakeMemberPlaceholder(node.selector); - } else { - // May get FunctionExpression here in selector - // in case of A(int this.f()); - if (node.selector is Identifier) { - collector.tryMakeLocalPlaceholder(element, node.selector); - } else { - assert(node.selector is FunctionExpression); - } - } - } - } - - visitStaticSend(Send node) { - final element = elements[node]; - if (Elements.isUnresolved(element) - || identical(element, compiler.assertMethod)) { - return; - } - if (element.isConstructor() || element.isFactoryConstructor()) { - // Rename named constructor in redirection position: - // class C { C.named(); C.redirecting() : this.named(); } - if (node.receiver is Identifier - && node.receiver.asIdentifier().isThis()) { - assert(node.selector is Identifier); - collector.makeRedirectingConstructorPlaceholder(node.selector, element); - } - return; - } - collector.makeElementPlaceholder(node.selector, element); - // Another ugly case: <lib prefix>.<top level> is represented as - // receiver: lib prefix, selector: top level. - if (element.isTopLevel() && node.receiver != null) { - assert(elements[node.receiver].isPrefix()); - // Hack: putting null into map overrides receiver of original node. - collector.makeNullPlaceholder(node.receiver); - } - } - - internalError(String reason, {Node node}) { - collector.internalError(reason, node: node); - } - - visitTypeReferenceSend(Send node) { - collector.makeElementPlaceholder(node.selector, elements[node]); - } -} - -class PlaceholderCollector extends Visitor { - final Compiler compiler; - final Set<String> fixedMemberNames; // member names which cannot be renamed. - final Map<Element, ElementAst> elementAsts; - final Set<Node> nullNodes; // Nodes that should not be in output. - final Set<Node> unresolvedNodes; - final Map<Element, Set<Node>> elementNodes; - final Map<FunctionElement, FunctionScope> functionScopes; - final Map<LibraryElement, Set<Identifier>> privateNodes; - final List<DeclarationTypePlaceholder> declarationTypePlaceholders; - final Map<String, Set<Identifier>> memberPlaceholders; - final Map<Element, List<ConstructorPlaceholder>> constructorPlaceholders; - Map<String, LocalPlaceholder> currentLocalPlaceholders; - Element currentElement; - FunctionElement topmostEnclosingFunction; - TreeElements treeElements; - - LibraryElement get coreLibrary => compiler.coreLibrary; - FunctionElement get entryFunction => compiler.mainApp.find(Compiler.MAIN); - - get currentFunctionScope => functionScopes.putIfAbsent( - topmostEnclosingFunction, () => new FunctionScope()); - - PlaceholderCollector(this.compiler, this.fixedMemberNames, this.elementAsts) : - nullNodes = new Set<Node>(), - unresolvedNodes = new Set<Node>(), - elementNodes = new Map<Element, Set<Node>>(), - functionScopes = new Map<FunctionElement, FunctionScope>(), - privateNodes = new Map<LibraryElement, Set<Identifier>>(), - declarationTypePlaceholders = new List<DeclarationTypePlaceholder>(), - memberPlaceholders = new Map<String, Set<Identifier>>(), - constructorPlaceholders = - new Map<Element, List<ConstructorPlaceholder>>(); - - void collectFunctionDeclarationPlaceholders( - FunctionElement element, FunctionExpression node) { - if (element.isGenerativeConstructor() || element.isFactoryConstructor()) { - DartType type = element.getEnclosingClass().thisType.asRaw(); - makeConstructorPlaceholder(node.name, element, type); - Return bodyAsReturn = node.body.asReturn(); - if (bodyAsReturn != null && bodyAsReturn.isRedirectingFactoryBody) { - // Factory redirection. - FunctionElement redirectTarget = element.defaultImplementation; - assert(redirectTarget != null && redirectTarget != element); - type = redirectTarget.getEnclosingClass().thisType.asRaw(); - makeConstructorPlaceholder( - bodyAsReturn.expression, redirectTarget, type); - } - } else if (Elements.isStaticOrTopLevel(element)) { - // Note: this code should only rename private identifiers for class' - // fields/getters/setters/methods. Top-level identifiers are renamed - // just to escape conflicts and that should be enough as we shouldn't - // be able to resolve private identifiers for other libraries. - makeElementPlaceholder(node.name, element); - } else if (element.isMember()) { - if (node.name is Identifier) { - tryMakeMemberPlaceholder(node.name); - } else { - assert(node.name.asSend().isOperator); - } - } - } - - void collectFieldDeclarationPlaceholders(Element element, Node node) { - Identifier name = node is Identifier ? node : node.asSend().selector; - if (Elements.isStaticOrTopLevel(element)) { - makeElementPlaceholder(name, element); - } else if (Elements.isInstanceField(element)) { - tryMakeMemberPlaceholder(name); - } - } - - void collect(Element element) { - this.currentElement = element; - this.topmostEnclosingFunction = null; - final ElementAst elementAst = elementAsts[element]; - this.treeElements = elementAst.treeElements; - Node elementNode = elementAst.ast; - if (element is FunctionElement) { - collectFunctionDeclarationPlaceholders(element, elementNode); - } else if (element is VariableListElement) { - VariableDefinitions definitions = elementNode; - for (Node definition in definitions.definitions) { - final definitionElement = treeElements[definition]; - // definitionElement == null if variable is actually unused. - if (definitionElement == null) continue; - collectFieldDeclarationPlaceholders(definitionElement, definition); - } - makeVarDeclarationTypePlaceholder(definitions); - } else { - assert(element is ClassElement || element is TypedefElement); - } - currentLocalPlaceholders = new Map<String, LocalPlaceholder>(); - compiler.withCurrentElement(element, () { - elementNode.accept(this); - }); - } - - void tryMakeLocalPlaceholder(Element element, Identifier node) { - bool isOptionalParameter() { - FunctionElement function = element.enclosingElement; - for (Element parameter in function.functionSignature.optionalParameters) { - if (identical(parameter, element)) return true; - } - return false; - } - - // TODO(smok): Maybe we should rename privates as well, their privacy - // should not matter if they are local vars. - if (node.source.isPrivate()) return; - if (element.isParameter() && isOptionalParameter()) { - currentFunctionScope.registerParameter(node); - } else if (Elements.isLocal(element)) { - makeLocalPlaceholder(node); - } - } - - void tryMakeMemberPlaceholder(Identifier node) { - assert(node != null); - if (node.source.isPrivate()) return; - if (node is Operator) return; - final identifier = node.source.slowToString(); - if (fixedMemberNames.contains(identifier)) return; - memberPlaceholders.putIfAbsent( - identifier, () => new Set<Identifier>()).add(node); - } - - void makeTypePlaceholder(Node node, DartType type) { - if (node is Send) { - // Prefix. - assert(node.receiver is Identifier); - assert(node.selector is Identifier); - makeNullPlaceholder(node.receiver); - node = node.selector; - } - makeElementPlaceholder(node, type.element); - } - - void makeOmitDeclarationTypePlaceholder(TypeAnnotation type) { - if (type == null) return; - declarationTypePlaceholders.add( - new DeclarationTypePlaceholder(type, false)); - } - - void makeVarDeclarationTypePlaceholder(VariableDefinitions node) { - // TODO(smok): Maybe instead of calling this method and - // makeDeclaratioTypePlaceholder have type declaration placeholder - // collector logic in visitVariableDefinitions when resolver becomes better - // and/or catch syntax changes. - if (node.type == null) return; - Element definitionElement = treeElements[node.definitions.nodes.head]; - bool requiresVar = !node.modifiers.isFinalOrConst(); - declarationTypePlaceholders.add( - new DeclarationTypePlaceholder(node.type, requiresVar)); - } - - void makeNullPlaceholder(Node node) { - assert(node is Identifier || node is Send); - nullNodes.add(node); - } - - void makeElementPlaceholder(Node node, Element element) { - assert(element != null); - if (identical(element, entryFunction)) return; - if (identical(element.getLibrary(), coreLibrary)) return; - if (element.getLibrary().isPlatformLibrary && !element.isTopLevel()) { - return; - } - if (element == compiler.types.dynamicType.element) { - internalError( - 'Should never make element placeholder for dynamic type element', - node: node); - } - elementNodes.putIfAbsent(element, () => new Set<Node>()).add(node); - } - - void makePrivateIdentifier(Identifier node) { - assert(node != null); - privateNodes.putIfAbsent( - currentElement.getLibrary(), () => new Set<Identifier>()).add(node); - } - - void makeUnresolvedPlaceholder(Node node) { - unresolvedNodes.add(node); - } - - void makeLocalPlaceholder(Identifier identifier) { - LocalPlaceholder getLocalPlaceholder() { - String name = identifier.source.slowToString(); - return currentLocalPlaceholders.putIfAbsent(name, () { - LocalPlaceholder localPlaceholder = new LocalPlaceholder(name); - currentFunctionScope.localPlaceholders.add(localPlaceholder); - return localPlaceholder; - }); - } - - getLocalPlaceholder().nodes.add(identifier); - } - - void makeConstructorPlaceholder(Node node, Element element, DartType type) { - assert(type != null); - constructorPlaceholders - .putIfAbsent(element, () => <ConstructorPlaceholder>[]) - .add(new ConstructorPlaceholder(node, type)); - } - void makeRedirectingConstructorPlaceholder(Node node, Element element) { - constructorPlaceholders - .putIfAbsent(element, () => <ConstructorPlaceholder>[]) - .add(new ConstructorPlaceholder.redirectingCall(node)); - } - - void internalError(String reason, {Node node}) { - compiler.cancel(reason, node: node); - } - - void unreachable() { internalError('Unreachable case'); } - - visit(Node node) => (node == null) ? null : node.accept(this); - - visitNode(Node node) { node.visitChildren(this); } // We must go deeper. - - visitNewExpression(NewExpression node) { - Send send = node.send; - InterfaceType type = treeElements.getType(node); - assert(type != null); - Element constructor = treeElements[send]; - assert(constructor != null); - assert(send.receiver == null); - if (!Elements.isErroneousElement(constructor)) { - makeConstructorPlaceholder(node.send.selector, constructor, type); - // TODO(smok): Should this be in visitNamedArgument? - // Field names can be exposed as names of optional arguments, e.g. - // class C { - // final field; - // C([this.field]); - // } - // Do not forget to rename them as well. - FunctionElement constructorFunction = constructor; - Link<Element> optionalParameters = - constructorFunction.functionSignature.optionalParameters; - for (final argument in send.argumentsNode) { - NamedArgument named = argument.asNamedArgument(); - if (named == null) continue; - Identifier name = named.name; - String nameAsString = name.source.slowToString(); - for (final parameter in optionalParameters) { - if (identical(parameter.kind, ElementKind.FIELD_PARAMETER)) { - if (parameter.name.slowToString() == nameAsString) { - tryMakeMemberPlaceholder(name); - break; - } - } - } - } - } else { - makeUnresolvedPlaceholder(node.send.selector); - } - visit(node.send.argumentsNode); - } - - visitSend(Send send) { - new SendVisitor(this, treeElements).visitSend(send); - send.visitChildren(this); - } - - visitSendSet(SendSet send) { - Element element = treeElements[send]; - if (Elements.isErroneousElement(element)) { - // Complicated case: constructs like receiver.selector++ can resolve - // to ErroneousElement. Fortunately, receiver.selector still - // can be resoved via treeElements[send.selector], that's all - // that is needed to rename the construct properly. - element = treeElements[send.selector]; - } - if (element == null) { - if (send.receiver != null) tryMakeMemberPlaceholder(send.selector); - } else if (!element.isErroneous()) { - if (Elements.isStaticOrTopLevel(element)) { - // TODO(smok): Worth investigating why sometimes we get getter/setter - // here and sometimes abstract field. - assert(element.isClass() || element is VariableElement || - element.isAccessor() || element.isAbstractField() || - element.isFunction() || element.isTypedef() || - element is TypeVariableElement); - makeElementPlaceholder(send.selector, element); - } else { - assert(send.selector is Identifier); - if (Elements.isInstanceField(element)) { - tryMakeMemberPlaceholder(send.selector); - } else { - tryMakeLocalPlaceholder(element, send.selector); - } - } - } - send.visitChildren(this); - } - - visitIdentifier(Identifier identifier) { - if (identifier.source.isPrivate()) makePrivateIdentifier(identifier); - } - - static bool isPlainTypeName(TypeAnnotation typeAnnotation) { - if (typeAnnotation.typeName is !Identifier) return false; - if (typeAnnotation.typeArguments == null) return true; - if (typeAnnotation.typeArguments.isEmpty) return true; - return false; - } - - static bool isDynamicType(TypeAnnotation typeAnnotation) { - if (!isPlainTypeName(typeAnnotation)) return false; - String name = typeAnnotation.typeName.asIdentifier().source.slowToString(); - // TODO(aprelev@gmail.com): Removed deprecated Dynamic keyword support. - return name == 'Dynamic' || name == 'dynamic'; - } - - visitTypeAnnotation(TypeAnnotation node) { - // Poor man generic variables resolution. - // TODO(antonm): get rid of it once resolver can deal with it. - TypeDeclarationElement typeDeclarationElement; - if (currentElement is TypeDeclarationElement) { - typeDeclarationElement = currentElement; - } else { - typeDeclarationElement = currentElement.getEnclosingClass(); - } - if (typeDeclarationElement != null && isPlainTypeName(node) - && tryResolveAndCollectTypeVariable( - typeDeclarationElement, node.typeName)) { - return; - } - // We call [resolveReturnType] to allow having 'void'. - final type = compiler.resolveReturnType(currentElement, node); - if (type is InterfaceType || type is TypedefType) { - // TODO(antonm): is there a better way to detect unresolved types? - // Corner case: dart:core type with a prefix. - // Most probably there are some additional problems with - // coreLibPrefix.topLevels. - if (!identical(type.element, compiler.types.dynamicType.element)) { - makeTypePlaceholder(node.typeName, type); - } else { - if (!isDynamicType(node)) makeUnresolvedPlaceholder(node.typeName); - } - } - // Visit only type arguments, otherwise in case of lib.Class type - // annotation typeName is Send and we go to visitGetterSend, as a result - // "Class" is added to member placeholders. - visit(node.typeArguments); - } - - visitVariableDefinitions(VariableDefinitions node) { - // Collect only local placeholders. - for (Node definition in node.definitions.nodes) { - Element definitionElement = treeElements[definition]; - // definitionElement may be null if we're inside variable definitions - // of a function that is a parameter of another function. - // TODO(smok): Fix this when resolver correctly deals with - // such cases. - if (definitionElement == null) continue; - if (definition is Send) { - // May get FunctionExpression here in definition.selector - // in case of A(int this.f()); - if (definition.selector is Identifier) { - if (identical(definitionElement.kind, ElementKind.FIELD_PARAMETER)) { - tryMakeMemberPlaceholder(definition.selector); - } else { - tryMakeLocalPlaceholder(definitionElement, definition.selector); - } - } else { - assert(definition.selector is FunctionExpression); - if (identical(definitionElement.kind, ElementKind.FIELD_PARAMETER)) { - tryMakeMemberPlaceholder( - definition.selector.asFunctionExpression().name); - } - } - } else if (definition is Identifier) { - tryMakeLocalPlaceholder(definitionElement, definition); - } else if (definition is FunctionExpression) { - // Skip, it will be processed in visitFunctionExpression. - } else { - internalError('Unexpected definition structure $definition'); - } - } - node.visitChildren(this); - } - - visitFunctionExpression(FunctionExpression node) { - bool isKeyword(Identifier id) => - id != null && Keyword.keywords[id.source.slowToString()] != null; - - Element element = treeElements[node]; - // May get null here in case of A(int this.f()); - if (element != null) { - // Rename only local functions. - if (topmostEnclosingFunction == null) { - topmostEnclosingFunction = element; - } - if (!identical(element, currentElement)) { - if (node.name != null) { - assert(node.name is Identifier); - tryMakeLocalPlaceholder(element, node.name); - } - } - } - node.visitChildren(this); - // Make sure we don't omit return type of methods which names are - // identifiers, because the following works fine: - // int interface() => 1; - // But omitting 'int' makes VM unhappy. - // TODO(smok): Remove it when http://dartbug.com/5278 is fixed. - if (node.name == null || !isKeyword(node.name.asIdentifier())) { - makeOmitDeclarationTypePlaceholder(node.returnType); - } - collectFunctionParameters(node.parameters); - } - - void collectFunctionParameters(NodeList parameters) { - if (parameters == null) return; - for (Node parameter in parameters.nodes) { - if (parameter is NodeList) { - // Optional parameter list. - collectFunctionParameters(parameter); - } else { - assert(parameter is VariableDefinitions); - makeOmitDeclarationTypePlaceholder( - parameter.asVariableDefinitions().type); - } - } - } - - visitClassNode(ClassNode node) { - ClassElement classElement = currentElement; - makeElementPlaceholder(node.name, classElement); - node.visitChildren(this); - if (node.defaultClause != null) { - // Can't just visit class node's default clause because of the bug in the - // resolver, it just crashes when it meets type variable. - DartType defaultType = classElement.defaultClass; - assert(defaultType != null); - makeTypePlaceholder(node.defaultClause.typeName, defaultType); - visit(node.defaultClause.typeArguments); - } - } - - bool tryResolveAndCollectTypeVariable( - TypeDeclarationElement typeDeclaration, Identifier name) { - // Hack for case when interface and default class are in different - // libraries, try to resolve type variable to default class type arg. - // Example: - // lib1: interface I<K> default C<K> {...} - // lib2: class C<K> {...} - if (typeDeclaration is ClassElement - && (typeDeclaration as ClassElement).defaultClass != null) { - typeDeclaration = (typeDeclaration as ClassElement).defaultClass.element; - } - // Another poor man type resolution. - // Find this variable in enclosing type declaration parameters. - for (DartType type in typeDeclaration.typeVariables) { - if (type.name.slowToString() == name.source.slowToString()) { - makeTypePlaceholder(name, type); - return true; - } - } - return false; - } - - visitTypeVariable(TypeVariable node) { - assert(currentElement is TypedefElement || currentElement is ClassElement); - tryResolveAndCollectTypeVariable(currentElement, node.name); - node.visitChildren(this); - } - - visitTypedef(Typedef node) { - assert(currentElement is TypedefElement); - makeElementPlaceholder(node.name, currentElement); - node.visitChildren(this); - makeOmitDeclarationTypePlaceholder(node.returnType); - collectFunctionParameters(node.formals); - } - - visitBlock(Block node) { - for (Node statement in node.statements.nodes) { - if (statement is VariableDefinitions) { - makeVarDeclarationTypePlaceholder(statement); - } - } - node.visitChildren(this); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/dart_backend/renamer.dart b/pkgs/markdown/test/lib/src/compiler/implementation/dart_backend/renamer.dart deleted file mode 100644 index 886d39e..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/dart_backend/renamer.dart +++ /dev/null
@@ -1,359 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of dart_backend; - -Function get _compareNodes => - compareBy((n) => n.getBeginToken().charOffset); - -typedef String _Renamer(Renamable renamable); -abstract class Renamable { - const int RENAMABLE_TYPE_ELEMENT = 1; - const int RENAMABLE_TYPE_MEMBER = 2; - const int RENAMABLE_TYPE_LOCAL = 3; - - final Set<Node> nodes; - final _Renamer renamer; - - Renamable(this.nodes, this.renamer); - int compareTo(Renamable other) { - int nodesDiff = other.nodes.length.compareTo(this.nodes.length); - if (nodesDiff != 0) return nodesDiff; - int typeDiff = this.getTypeId().compareTo(other.getTypeId()); - return typeDiff != 0 ? typeDiff : compareInternals(other); - } - - int compareInternals(Renamable other); - int getTypeId(); - - String rename() => renamer(this); -} - -class ElementRenamable extends Renamable { - final Element element; - - ElementRenamable(this.element, Set<Node> nodes, _Renamer renamer) - : super(nodes, renamer); - - int compareInternals(ElementRenamable other) => - compareElements(this.element, other.element); - int getTypeId() => RENAMABLE_TYPE_ELEMENT; -} - -class MemberRenamable extends Renamable { - final String identifier; - MemberRenamable(this.identifier, Set<Node> nodes, _Renamer renamer) - : super(nodes, renamer); - int compareInternals(MemberRenamable other) => - this.identifier.compareTo(other.identifier); - int getTypeId() => RENAMABLE_TYPE_MEMBER; -} - -class LocalRenamable extends Renamable { - LocalRenamable(Set<Node> nodes, _Renamer renamer) : super(nodes, renamer); - int compareInternals(LocalRenamable other) => - _compareNodes(sorted(this.nodes, _compareNodes)[0], - sorted(other.nodes, _compareNodes)[0]); - int getTypeId() => RENAMABLE_TYPE_LOCAL; -} - -/** - * Renames only top-level elements that would let to ambiguity if not renamed. - */ -void renamePlaceholders( - Compiler compiler, - PlaceholderCollector placeholderCollector, - Map<Node, String> renames, - Map<LibraryElement, String> imports, - Set<String> fixedMemberNames, - bool cutDeclarationTypes) { - final Map<LibraryElement, Map<String, String>> renamed - = new Map<LibraryElement, Map<String, String>>(); - - renameNodes(Collection<Node> nodes, renamer) { - for (Node node in sorted(nodes, _compareNodes)) { - renames[node] = renamer(node); - } - } - - sortedForEach(Map<Element, dynamic> map, f) { - for (Element element in sortElements(map.keys)) { - f(element, map[element]); - } - } - - String renameType(DartType type, Function renameElement) { - // TODO(smok): Do not rename type if it is in platform library or - // js-helpers. - StringBuffer result = new StringBuffer(renameElement(type.element)); - if (type is InterfaceType) { - if (!type.isRaw) { - result.add('<'); - Link<DartType> argumentsLink = type.typeArguments; - result.add(renameType(argumentsLink.head, renameElement)); - for (Link<DartType> link = argumentsLink.tail; !link.isEmpty; - link = link.tail) { - result.add(','); - result.add(renameType(link.head, renameElement)); - } - result.add('>'); - } - } - return result.toString(); - } - - String renameConstructor(Element element, ConstructorPlaceholder placeholder, - Function renameString, Function renameElement) { - assert(element.isConstructor()); - StringBuffer result = new StringBuffer(); - String name = element.name.slowToString(); - if (element.name != element.getEnclosingClass().name) { - // Named constructor or factory. Is there a more reliable way to check - // this case? - if (!placeholder.isRedirectingCall) { - result.add(renameType(placeholder.type, renameElement)); - result.add('.'); - } - String prefix = '${element.getEnclosingClass().name.slowToString()}\$'; - if (!name.startsWith(prefix)) { - // Factory for another interface (that is going away soon). - compiler.internalErrorOnElement(element, - "Factory constructors for external interfaces are not supported."); - } - name = name.substring(prefix.length); - if (!element.getLibrary().isPlatformLibrary) { - name = renameString(element.getLibrary(), name); - } - result.add(name); - } else { - assert(!placeholder.isRedirectingCall); - result.add(renameType(placeholder.type, renameElement)); - } - return result.toString(); - } - - Function makeElementRenamer(rename, generateUniqueName) => (element) { - assert(Elements.isErroneousElement(element) || - Elements.isStaticOrTopLevel(element) || - element is TypeVariableElement); - // TODO(smok): We may want to reuse class static field and method names. - String originalName = element.name.slowToString(); - LibraryElement library = element.getLibrary(); - if (identical(element.getLibrary(), compiler.coreLibrary)) { - return originalName; - } - if (library.isPlatformLibrary && !library.isInternalLibrary) { - assert(element.isTopLevel()); - final prefix = - imports.putIfAbsent(library, () => generateUniqueName('p')); - return '$prefix.$originalName'; - } - - return rename(library, originalName); - }; - - Function makeRenamer(generateUniqueName) => - (library, originalName) => - renamed.putIfAbsent(library, () => {}) - .putIfAbsent(originalName, - () => generateUniqueName(originalName)); - - // Renamer function that takes library and original name and returns a new - // name for given identifier. - Function rename; - Function renameElement; - // A function that takes original identifier name and generates a new unique - // identifier. - Function generateUniqueName; - if (compiler.enableMinification) { - MinifyingGenerator generator = new MinifyingGenerator(); - Set<String> forbiddenIdentifiers = new Set<String>.from(['main']); - forbiddenIdentifiers.addAll(Keyword.keywords.keys); - forbiddenIdentifiers.addAll(fixedMemberNames); - generateUniqueName = (_) => - generator.generate(forbiddenIdentifiers.contains); - rename = makeRenamer(generateUniqueName); - renameElement = makeElementRenamer(rename, generateUniqueName); - - Set<String> allParameterIdentifiers = new Set<String>(); - for (var functionScope in placeholderCollector.functionScopes.values) { - allParameterIdentifiers.addAll(functionScope.parameterIdentifiers); - } - // Build a sorted (by usage) list of local nodes that will be renamed to - // the same identifier. So the top-used local variables in all functions - // will be renamed first and will all share the same new identifier. - List<Set<Node>> allSortedLocals = new List<Set<Node>>(); - for (var functionScope in placeholderCollector.functionScopes.values) { - // Add current sorted local identifiers to the whole sorted list - // of all local identifiers for all functions. - List<LocalPlaceholder> currentSortedPlaceholders = - sorted(functionScope.localPlaceholders, - compareBy((LocalPlaceholder ph) => -ph.nodes.length)); - List<Set<Node>> currentSortedNodes = - currentSortedPlaceholders.map((ph) => ph.nodes).toList(); - // Make room in all sorted locals list for new stuff. - while (currentSortedNodes.length > allSortedLocals.length) { - allSortedLocals.add(new Set<Node>()); - } - for (int i = 0; i < currentSortedNodes.length; i++) { - allSortedLocals[i].addAll(currentSortedNodes[i]); - } - } - - // Rename elements, members and locals together based on their usage count, - // otherwise when we rename elements first there will be no good identifiers - // left for members even if they are used often. - String elementRenamer(ElementRenamable elementRenamable) => - renameElement(elementRenamable.element); - String memberRenamer(MemberRenamable memberRenamable) => - generator.generate(forbiddenIdentifiers.contains); - String localRenamer(LocalRenamable localRenamable) => - generator.generate((name) => - allParameterIdentifiers.contains(name) - || forbiddenIdentifiers.contains(name)); - List<Renamable> renamables = []; - placeholderCollector.elementNodes.forEach( - (Element element, Set<Node> nodes) { - renamables.add(new ElementRenamable(element, nodes, elementRenamer)); - }); - placeholderCollector.memberPlaceholders.forEach( - (String memberName, Set<Identifier> identifiers) { - renamables.add( - new MemberRenamable(memberName, identifiers, memberRenamer)); - }); - for (Set<Node> localIdentifiers in allSortedLocals) { - renamables.add(new LocalRenamable(localIdentifiers, localRenamer)); - } - renamables.sort((Renamable renamable1, Renamable renamable2) => - renamable1.compareTo(renamable2)); - for (Renamable renamable in renamables) { - String newName = renamable.rename(); - renameNodes(renamable.nodes, (_) => newName); - } - } else { - // Never rename anything to 'main'. - final usedTopLevelOrMemberIdentifiers = new Set<String>(); - usedTopLevelOrMemberIdentifiers.add('main'); - usedTopLevelOrMemberIdentifiers.addAll(fixedMemberNames); - generateUniqueName = (originalName) { - String newName = conservativeGenerator( - originalName, usedTopLevelOrMemberIdentifiers.contains); - usedTopLevelOrMemberIdentifiers.add(newName); - return newName; - }; - rename = makeRenamer(generateUniqueName); - renameElement = makeElementRenamer(rename, generateUniqueName); - // Rename elements. - sortedForEach(placeholderCollector.elementNodes, - (Element element, Set<Node> nodes) { - renameNodes(nodes, (_) => renameElement(element)); - }); - - // Rename locals. - sortedForEach(placeholderCollector.functionScopes, - (functionElement, functionScope) { - Set<LocalPlaceholder> placeholders = functionScope.localPlaceholders; - Set<String> memberIdentifiers = new Set<String>(); - if (functionElement.getEnclosingClass() != null) { - functionElement.getEnclosingClass().forEachMember( - (enclosingClass, member) { - memberIdentifiers.add(member.name.slowToString()); - }); - } - Set<String> usedLocalIdentifiers = new Set<String>(); - for (LocalPlaceholder placeholder in placeholders) { - String nextId = - conservativeGenerator(placeholder.identifier, (name) => - functionScope.parameterIdentifiers.contains(name) - || usedTopLevelOrMemberIdentifiers.contains(name) - || usedLocalIdentifiers.contains(name) - || memberIdentifiers.contains(name)); - usedLocalIdentifiers.add(nextId); - renameNodes(placeholder.nodes, (_) => nextId); - } - }); - - final usedMemberIdentifiers = new Set<String>.from(fixedMemberNames); - // Do not rename members to top-levels, that allows to avoid renaming - // members to constructors. - usedMemberIdentifiers.addAll(usedTopLevelOrMemberIdentifiers); - placeholderCollector.memberPlaceholders.forEach((identifier, nodes) { - String newIdentifier = conservativeGenerator( - identifier, usedMemberIdentifiers.contains); - renameNodes(nodes, (_) => newIdentifier); - }); - } - - // Rename constructors. - sortedForEach(placeholderCollector.constructorPlaceholders, - (Element constructor, List<ConstructorPlaceholder> placeholders) { - for (ConstructorPlaceholder ph in placeholders) { - renames[ph.node] = - renameConstructor(constructor, ph, rename, renameElement); - } - }); - sortedForEach(placeholderCollector.privateNodes, (library, nodes) { - renameNodes(nodes, (node) => rename(library, node.source.slowToString())); - }); - renameNodes(placeholderCollector.unresolvedNodes, - (_) => generateUniqueName('Unresolved')); - renameNodes(placeholderCollector.nullNodes, (_) => ''); - if (cutDeclarationTypes) { - for (DeclarationTypePlaceholder placeholder in - placeholderCollector.declarationTypePlaceholders) { - renames[placeholder.typeNode] = placeholder.requiresVar ? 'var' : ''; - } - } -} - -/** Always tries to return original identifier name unless it is forbidden. */ -String conservativeGenerator( - String originalName, bool isForbidden(String name)) { - String newName = originalName; - while (isForbidden(newName)) { - newName = 'p_$newName'; - } - return newName; -} - -/** Always tries to generate the most compact identifier. */ -class MinifyingGenerator { - static const String firstCharAlphabet = - r'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; - static const String otherCharsAlphabet = - r'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_$'; - int nextIdIndex; - - MinifyingGenerator() : nextIdIndex = 0; - - String generate(bool isForbidden(String name)) { - String newName; - do { - newName = getNextId(); - } while(isForbidden(newName)); - return newName; - } - - /** - * Generates next mini ID with current index and alphabet. - * Advances current index. - * In other words, it converts index to visual representation - * as if digits are given characters. - */ - String getNextId() { - // It's like converting index in decimal to [chars] radix. - int index = nextIdIndex++; - StringBuffer resultBuilder = new StringBuffer(); - if (index < firstCharAlphabet.length) return firstCharAlphabet[index]; - resultBuilder.add(firstCharAlphabet[index % firstCharAlphabet.length]); - index ~/= firstCharAlphabet.length; - int length = otherCharsAlphabet.length; - while (index >= length) { - resultBuilder.add(otherCharsAlphabet[index % length]); - index ~/= length; - } - resultBuilder.add(otherCharsAlphabet[index]); - return resultBuilder.toString(); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/dart_backend/utils.dart b/pkgs/markdown/test/lib/src/compiler/implementation/dart_backend/utils.dart deleted file mode 100644 index c30a2cf..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/dart_backend/utils.dart +++ /dev/null
@@ -1,292 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of dart_backend; - -class CloningVisitor implements Visitor<Node> { - final TreeElements originalTreeElements; - final TreeElementMapping cloneTreeElements; - - CloningVisitor(originalTreeElements) - : cloneTreeElements = - new TreeElementMapping(originalTreeElements.currentElement), - this.originalTreeElements = originalTreeElements; - - visit(Node node) { - if (node == null) return null; - final clone = node.accept(this); - - final originalElement = originalTreeElements[node]; - if (originalElement != null) cloneTreeElements[clone] = originalElement; - - final originalType = originalTreeElements.getType(node); - if (originalType != null) cloneTreeElements.setType(clone, originalType); - return clone; - } - - visitBlock(Block node) => new Block(visit(node.statements)); - - visitBreakStatement(BreakStatement node) => new BreakStatement( - visit(node.target), node.keywordToken, node.semicolonToken); - - visitCascade(Cascade node) => new Cascade(visit(node.expression)); - - visitCascadeReceiver(CascadeReceiver node) => new CascadeReceiver( - visit(node.expression), node.cascadeOperator); - - visitCaseMatch(CaseMatch node) => new CaseMatch( - node.caseKeyword, visit(node.expression), node.colonToken); - - visitCatchBlock(CatchBlock node) => new CatchBlock( - visit(node.type), visit(node.formals), visit(node.block), - node.onKeyword, node.catchKeyword); - - visitClassNode(ClassNode node) => new ClassNode( - visit(node.modifiers), visit(node.name), visit(node.typeParameters), - visit(node.superclass), visit(node.interfaces), visit(node.defaultClause), - node.beginToken, node.extendsKeyword, visit(node.body), node.endToken); - - visitConditional(Conditional node) => new Conditional( - visit(node.condition), visit(node.thenExpression), - visit(node.elseExpression), node.questionToken, node.colonToken); - - visitContinueStatement(ContinueStatement node) => new ContinueStatement( - visit(node.target), node.keywordToken, node.semicolonToken); - - visitDoWhile(DoWhile node) => new DoWhile( - visit(node.body), visit(node.condition), - node.doKeyword, node.whileKeyword, node.endToken); - - visitEmptyStatement(EmptyStatement node) => new EmptyStatement( - node.semicolonToken); - - visitExpressionStatement(ExpressionStatement node) => new ExpressionStatement( - visit(node.expression), node.endToken); - - visitFor(For node) => new For( - visit(node.initializer), visit(node.conditionStatement), - visit(node.update), visit(node.body), node.forToken); - - visitForIn(ForIn node) => new ForIn( - visit(node.declaredIdentifier), visit(node.expression), visit(node.body), - node.forToken, node.inToken); - - visitFunctionDeclaration(FunctionDeclaration node) => new FunctionDeclaration( - visit(node.function)); - - rewriteFunctionExpression(FunctionExpression node, Statement body) => - new FunctionExpression( - visit(node.name), visit(node.parameters), body, - visit(node.returnType), visit(node.modifiers), - visit(node.initializers), node.getOrSet); - - visitFunctionExpression(FunctionExpression node) => - rewriteFunctionExpression(node, visit(node.body)); - - visitIdentifier(Identifier node) => new Identifier(node.token); - - visitIf(If node) => new If( - visit(node.condition), visit(node.thenPart), visit(node.elsePart), - node.ifToken, node.elseToken); - - visitLabel(Label node) => new Label(visit(node.identifier), node.colonToken); - - visitLabeledStatement(LabeledStatement node) => new LabeledStatement( - visit(node.labels), visit(node.statement)); - - visitLiteralBool(LiteralBool node) => new LiteralBool( - node.token, node.handler); - - visitLiteralDouble(LiteralDouble node) => new LiteralDouble( - node.token, node.handler); - - visitLiteralInt(LiteralInt node) => new LiteralInt(node.token, node.handler); - - visitLiteralList(LiteralList node) => new LiteralList( - visit(node.typeArguments), visit(node.elements), node.constKeyword); - - visitLiteralMap(LiteralMap node) => new LiteralMap( - visit(node.typeArguments), visit(node.entries), node.constKeyword); - - visitLiteralMapEntry(LiteralMapEntry node) => new LiteralMapEntry( - visit(node.key), node.colonToken, visit(node.value)); - - visitLiteralNull(LiteralNull node) => new LiteralNull(node.token); - - visitLiteralString(LiteralString node) => new LiteralString( - node.token, node.dartString); - - visitMixinApplication(MixinApplication node) => new MixinApplication( - visit(node.superclass), visit(node.mixins)); - - visitNamedMixinApplication(NamedMixinApplication node) => - new NamedMixinApplication(visit(node.name), - visit(node.typeParameters), - visit(node.modifiers), - visit(node.mixinApplication), - visit(node.interfaces), - node.typedefKeyword, - node.endToken); - - visitModifiers(Modifiers node) => new Modifiers(visit(node.nodes)); - - visitNamedArgument(NamedArgument node) => new NamedArgument( - visit(node.name), node.colonToken, visit(node.expression)); - - visitNewExpression(NewExpression node) => new NewExpression( - node.newToken, visit(node.send)); - - rewriteNodeList(NodeList node, Link link) => - new NodeList(node.beginToken, link, node.endToken, node.delimiter); - - visitNodeList(NodeList node) { - // Special case for classes which exist in hierarchy, but not - // in the visitor. - if (node is Prefix) { - return node.nodes.isEmpty ? - new Prefix() : new Prefix.singleton(visit(node.nodes.head)); - } - if (node is Postfix) { - return node.nodes.isEmpty ? - new Postfix() : new Postfix.singleton(visit(node.nodes.head)); - } - LinkBuilder<Node> builder = new LinkBuilder<Node>(); - for (Node n in node.nodes) { - builder.addLast(visit(n)); - } - return rewriteNodeList(node, builder.toLink()); - } - - visitOperator(Operator node) => new Operator(node.token); - - visitParenthesizedExpression(ParenthesizedExpression node) => - new ParenthesizedExpression(visit(node.expression), node.beginToken); - - visitReturn(Return node) => new Return( - node.beginToken, node.endToken, visit(node.expression)); - - visitScriptTag(ScriptTag node) => new ScriptTag( - visit(node.tag), visit(node.argument), - visit(node.prefixIdentifier), visit(node.prefix), - node.beginToken, node.endToken); - - visitSend(Send node) => new Send( - visit(node.receiver), visit(node.selector), visit(node.argumentsNode)); - - visitSendSet(SendSet node) => new SendSet( - visit(node.receiver), visit(node.selector), - visit(node.assignmentOperator), visit(node.argumentsNode)); - - visitStringInterpolation(StringInterpolation node) => - new StringInterpolation(visit(node.string), visit(node.parts)); - - visitStringInterpolationPart(StringInterpolationPart node) => - new StringInterpolationPart(visit(node.expression), visit(node.string)); - - visitStringJuxtaposition(StringJuxtaposition node) => - new StringJuxtaposition(visit(node.first), visit(node.second)); - - visitSwitchCase(SwitchCase node) => new SwitchCase( - visit(node.labelsAndCases), node.defaultKeyword, visit(node.statements), - node.startToken); - - visitSwitchStatement(SwitchStatement node) => new SwitchStatement( - visit(node.parenthesizedExpression), visit(node.cases), - node.switchKeyword); - - visitThrow(Throw node) => new Throw( - visit(node.expression), node.throwToken, node.endToken); - - visitTryStatement(TryStatement node) => new TryStatement( - visit(node.tryBlock), visit(node.catchBlocks), visit(node.finallyBlock), - node.tryKeyword, node.finallyKeyword); - - visitTypeAnnotation(TypeAnnotation node) => new TypeAnnotation( - visit(node.typeName), visit(node.typeArguments)); - - visitTypedef(Typedef node) => new Typedef( - visit(node.returnType), visit(node.name), visit(node.typeParameters), - visit(node.formals), node.typedefKeyword, node.endToken); - - visitTypeVariable(TypeVariable node) => new TypeVariable( - visit(node.name), visit(node.bound)); - - visitVariableDefinitions(VariableDefinitions node) => new VariableDefinitions( - visit(node.type), visit(node.modifiers), visit(node.definitions)); - - visitWhile(While node) => new While( - visit(node.condition), visit(node.body), node.whileKeyword); - - Node visitNode(Node node) { - unimplemented('visitNode', node: node); - } - - Node visitCombinator(Combinator node) { - unimplemented('visitNode', node: node); - } - - Node visitExport(Export node) { - unimplemented('visitNode', node: node); - } - - Node visitExpression(Expression node) { - unimplemented('visitNode', node: node); - } - - Node visitGotoStatement(GotoStatement node) { - unimplemented('visitNode', node: node); - } - - Node visitImport(Import node) { - unimplemented('visitNode', node: node); - } - - Node visitLibraryDependency(LibraryTag node) { - unimplemented('visitNode', node: node); - } - - Node visitLibraryName(LibraryName node) { - unimplemented('visitNode', node: node); - } - - Node visitLibraryTag(LibraryTag node) { - unimplemented('visitNode', node: node); - } - - Node visitLiteral(Literal node) { - unimplemented('visitNode', node: node); - } - - Node visitLoop(Loop node) { - unimplemented('visitNode', node: node); - } - - Node visitPart(Part node) { - unimplemented('visitNode', node: node); - } - - Node visitPartOf(PartOf node) { - unimplemented('visitNode', node: node); - } - - Node visitPostfix(Postfix node) { - unimplemented('visitNode', node: node); - } - - Node visitPrefix(Prefix node) { - unimplemented('visitNode', node: node); - } - - Node visitStatement(Statement node) { - unimplemented('visitNode', node: node); - } - - Node visitStringNode(StringNode node) { - unimplemented('visitNode', node: node); - } - - unimplemented(String message, {Node node}) { - throw message; - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/dart_types.dart b/pkgs/markdown/test/lib/src/compiler/implementation/dart_types.dart deleted file mode 100644 index 7c78bd5..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/dart_types.dart +++ /dev/null
@@ -1,806 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library dart_types; - -import 'dart2jslib.dart' show Compiler, invariant, Script, Message; -import 'elements/modelx.dart' show VoidElementX, LibraryElementX; -import 'elements/elements.dart'; -import 'scanner/scannerlib.dart' show SourceString; -import 'util/util.dart' show Link, LinkBuilder; - -class TypeKind { - final String id; - - const TypeKind(String this.id); - - static const TypeKind FUNCTION = const TypeKind('function'); - static const TypeKind INTERFACE = const TypeKind('interface'); - static const TypeKind STATEMENT = const TypeKind('statement'); - static const TypeKind TYPEDEF = const TypeKind('typedef'); - static const TypeKind TYPE_VARIABLE = const TypeKind('type variable'); - static const TypeKind MALFORMED_TYPE = const TypeKind('malformed'); - static const TypeKind VOID = const TypeKind('void'); - - String toString() => id; -} - -abstract class DartType { - SourceString get name; - - TypeKind get kind; - - const DartType(); - - /** - * Returns the [Element] which declared this type. - * - * This can be [ClassElement] for classes, [TypedefElement] for typedefs, - * [TypeVariableElement] for type variables and [FunctionElement] for - * function types. - * - * Invariant: [element] must be a declaration element. - */ - Element get element; - - /** - * Performs the substitution [: [arguments[i]/parameters[i]]this :]. - * - * The notation is known from this lambda calculus rule: - * - * (lambda x.e0)e1 -> [e1/x]e0. - * - * See [TypeVariableType] for a motivation for this method. - * - * Invariant: There must be the same number of [arguments] and [parameters]. - */ - DartType subst(Link<DartType> arguments, Link<DartType> parameters); - - /** - * Returns the unaliased type of this type. - * - * The unaliased type of a typedef'd type is the unaliased type to which its - * name is bound. The unaliased version of any other type is the type itself. - * - * For example, the unaliased type of [: typedef A Func<A,B>(B b) :] is the - * function type [: (B) -> A :] and the unaliased type of - * [: Func<int,String> :] is the function type [: (String) -> int :]. - */ - DartType unalias(Compiler compiler); - - /** - * A type is malformed if it is itself a malformed type or contains a - * malformed type. - */ - bool get isMalformed => false; - - /** - * Calls [f] with each [MalformedType] within this type. - * - * If [f] returns [: false :], the traversal stops prematurely. - * - * [forEachMalformedType] returns [: false :] if the traversal was stopped - * prematurely. - */ - bool forEachMalformedType(bool f(MalformedType type)) => true; - - bool operator ==(other); - - /** - * Is [: true :] if this type has no explict type arguments. - */ - bool get isRaw => true; - - DartType asRaw() => this; -} - -/** - * Represents a type variable, that is the type parameters of a class type. - * - * For example, in [: class Array<E> { ... } :], E is a type variable. - * - * Each class should have its own unique type variables, one for each type - * parameter. A class with type parameters is said to be parameterized or - * generic. - * - * Non-static members, constructors, and factories of generic - * class/interface can refer to type variables of the current class - * (not of supertypes). - * - * When using a generic type, also known as an application or - * instantiation of the type, the actual type arguments should be - * substituted for the type variables in the class declaration. - * - * For example, given a box, [: class Box<T> { T value; } :], the - * type of the expression [: new Box<String>().value :] is - * [: String :] because we must substitute [: String :] for the - * the type variable [: T :]. - */ -class TypeVariableType extends DartType { - final TypeVariableElement element; - - TypeVariableType(this.element); - - TypeKind get kind => TypeKind.TYPE_VARIABLE; - - SourceString get name => element.name; - - DartType subst(Link<DartType> arguments, Link<DartType> parameters) { - if (parameters.isEmpty) { - assert(arguments.isEmpty); - // Return fast on empty substitutions. - return this; - } - Link<DartType> parameterLink = parameters; - Link<DartType> argumentLink = arguments; - while (!argumentLink.isEmpty && !parameterLink.isEmpty) { - TypeVariableType parameter = parameterLink.head; - DartType argument = argumentLink.head; - if (parameter == this) { - assert(argumentLink.tail.isEmpty == parameterLink.tail.isEmpty); - return argument; - } - parameterLink = parameterLink.tail; - argumentLink = argumentLink.tail; - } - assert(argumentLink.isEmpty && parameterLink.isEmpty); - // The type variable was not substituted. - return this; - } - - DartType unalias(Compiler compiler) => this; - - int get hashCode => 17 * element.hashCode; - - bool operator ==(other) { - if (other is !TypeVariableType) return false; - return identical(other.element, element); - } - - String toString() => name.slowToString(); -} - -/** - * A statement type tracks whether a statement returns or may return. - */ -class StatementType extends DartType { - final String stringName; - - Element get element => null; - - TypeKind get kind => TypeKind.STATEMENT; - - SourceString get name => new SourceString(stringName); - - const StatementType(this.stringName); - - static const RETURNING = const StatementType('<returning>'); - static const NOT_RETURNING = const StatementType('<not returning>'); - static const MAYBE_RETURNING = const StatementType('<maybe returning>'); - - /** Combine the information about two control-flow edges that are joined. */ - StatementType join(StatementType other) { - return (identical(this, other)) ? this : MAYBE_RETURNING; - } - - DartType subst(Link<DartType> arguments, Link<DartType> parameters) { - // Statement types are not substitutable. - return this; - } - - DartType unalias(Compiler compiler) => this; - - int get hashCode => 17 * stringName.hashCode; - - bool operator ==(other) { - if (other is !StatementType) return false; - return other.stringName == stringName; - } - - String toString() => stringName; -} - -class VoidType extends DartType { - const VoidType(this.element); - - TypeKind get kind => TypeKind.VOID; - - SourceString get name => element.name; - - final Element element; - - DartType subst(Link<DartType> arguments, Link<DartType> parameters) { - // Void cannot be substituted. - return this; - } - - DartType unalias(Compiler compiler) => this; - - int get hashCode => 1729; - - bool operator ==(other) => other is VoidType; - - String toString() => name.slowToString(); -} - -class MalformedType extends DartType { - final ErroneousElement element; - - /** - * [declaredType] holds the type which the user wrote in code. - * - * For instance, for a resolved but malformed type like [: Map<String> :] the - * [declaredType] is [: Map<String> :] whereas for an unresolved type - */ - final DartType userProvidedBadType; - - /** - * Type arguments for the malformed typed, if these cannot fit in the - * [declaredType]. - * - * This field is for instance used for [: dynamic<int> :] and [: T<int> :] - * where [: T :] is a type variable, in which case [declaredType] holds - * [: dynamic :] and [: T :], respectively, or for [: X<int> :] where [: X :] - * is not resolved or does not imply a type. - */ - final Link<DartType> typeArguments; - - MalformedType(this.element, this.userProvidedBadType, - [this.typeArguments = null]); - - TypeKind get kind => TypeKind.MALFORMED_TYPE; - - SourceString get name => element.name; - - DartType subst(Link<DartType> arguments, Link<DartType> parameters) { - // Malformed types are not substitutable. - return this; - } - - bool get isMalformed => true; - - bool forEachMalformedType(bool f(MalformedType type)) => f(this); - - DartType unalias(Compiler compiler) => this; - - String toString() { - var sb = new StringBuffer(); - if (typeArguments != null) { - if (userProvidedBadType != null) { - sb.add(userProvidedBadType.name.slowToString()); - } else { - sb.add(element.name.slowToString()); - } - if (!typeArguments.isEmpty) { - sb.add('<'); - typeArguments.printOn(sb, ', '); - sb.add('>'); - } - } else { - sb.add(userProvidedBadType.toString()); - } - return sb.toString(); - } -} - -bool hasMalformed(Link<DartType> types) { - for (DartType typeArgument in types) { - if (typeArgument.isMalformed) { - return true; - } - } - return false; -} - -abstract class GenericType extends DartType { - final Link<DartType> typeArguments; - final bool isMalformed; - - GenericType(Link<DartType> this.typeArguments, bool this.isMalformed); - - TypeDeclarationElement get element; - - /// Creates a new instance of this type using the provided type arguments. - GenericType _createType(Link<DartType> newTypeArguments); - - DartType subst(Link<DartType> arguments, Link<DartType> parameters) { - if (typeArguments.isEmpty) { - // Return fast on non-generic types. - return this; - } - if (parameters.isEmpty) { - assert(arguments.isEmpty); - // Return fast on empty substitutions. - return this; - } - Link<DartType> newTypeArguments = - Types.substTypes(typeArguments, arguments, parameters); - if (!identical(typeArguments, newTypeArguments)) { - // Create a new type only if necessary. - return _createType(newTypeArguments); - } - return this; - } - - bool forEachMalformedType(bool f(MalformedType type)) { - for (DartType typeArgument in typeArguments) { - if (!typeArgument.forEachMalformedType(f)) { - return false; - } - } - return true; - } - - String toString() { - StringBuffer sb = new StringBuffer(); - sb.add(name.slowToString()); - if (!isRaw) { - sb.add('<'); - typeArguments.printOn(sb, ', '); - sb.add('>'); - } - return sb.toString(); - } - - int get hashCode { - int hash = element.hashCode; - for (Link<DartType> arguments = this.typeArguments; - !arguments.isEmpty; - arguments = arguments.tail) { - int argumentHash = arguments.head != null ? arguments.head.hashCode : 0; - hash = 17 * hash + 3 * argumentHash; - } - return hash; - } - - bool operator ==(other) { - if (!identical(element, other.element)) return false; - return typeArguments == other.typeArguments; - } - - bool get isRaw => typeArguments.isEmpty || identical(this, element.rawType); - - GenericType asRaw() => element.rawType; -} - -// TODO(johnniwinther): Add common supertype for InterfaceType and TypedefType. -class InterfaceType extends GenericType { - final ClassElement element; - - InterfaceType(this.element, - [Link<DartType> typeArguments = const Link<DartType>()]) - : super(typeArguments, hasMalformed(typeArguments)) { - assert(invariant(element, element.isDeclaration)); - } - - TypeKind get kind => TypeKind.INTERFACE; - - SourceString get name => element.name; - - InterfaceType _createType(Link<DartType> newTypeArguments) { - return new InterfaceType(element, newTypeArguments); - } - - /** - * Returns the type as an instance of class [other], if possible, null - * otherwise. - */ - DartType asInstanceOf(ClassElement other) { - if (element == other) return this; - for (InterfaceType supertype in element.allSupertypes) { - ClassElement superclass = supertype.element; - if (superclass == other) { - Link<DartType> arguments = Types.substTypes(supertype.typeArguments, - typeArguments, - element.typeVariables); - return new InterfaceType(superclass, arguments); - } - } - return null; - } - - DartType unalias(Compiler compiler) => this; - - bool operator ==(other) { - if (other is !InterfaceType) return false; - return super == other; - } - - InterfaceType asRaw() => super.asRaw(); -} - -class FunctionType extends DartType { - final Element element; - final DartType returnType; - final Link<DartType> parameterTypes; - final Link<DartType> optionalParameterTypes; - - /** - * The names of the named parameters ordered lexicographically. - */ - final Link<SourceString> namedParameters; - - /** - * The types of the named parameters in the order corresponding to the - * [namedParameters]. - */ - final Link<DartType> namedParameterTypes; - final bool isMalformed; - - factory FunctionType(Element element, - DartType returnType, - Link<DartType> parameterTypes, - Link<DartType> optionalParameterTypes, - Link<SourceString> namedParameters, - Link<DartType> namedParameterTypes) { - // Compute [isMalformed] eagerly since it is faster than a lazy computation - // and since [isMalformed] most likely will be accessed in [Types.isSubtype] - // anyway. - bool isMalformed = returnType != null && - returnType.isMalformed || - hasMalformed(parameterTypes) || - hasMalformed(optionalParameterTypes) || - hasMalformed(namedParameterTypes); - return new FunctionType.internal(element, - returnType, - parameterTypes, - optionalParameterTypes, - namedParameters, - namedParameterTypes, - isMalformed); - } - - FunctionType.internal(Element this.element, - DartType this.returnType, - Link<DartType> this.parameterTypes, - Link<DartType> this.optionalParameterTypes, - Link<SourceString> this.namedParameters, - Link<DartType> this.namedParameterTypes, - bool this.isMalformed) { - assert(element == null || invariant(element, element.isDeclaration)); - // Assert that optional and named parameters are not used at the same time. - assert(optionalParameterTypes.isEmpty || namedParameterTypes.isEmpty); - assert(namedParameters.slowLength() == namedParameterTypes.slowLength()); - } - - TypeKind get kind => TypeKind.FUNCTION; - - DartType getNamedParameterType(SourceString name) { - Link<SourceString> namedParameter = namedParameters; - Link<DartType> namedParameterType = namedParameterTypes; - while (!namedParameter.isEmpty && !namedParameterType.isEmpty) { - if (namedParameter.head == name) { - return namedParameterType.head; - } - namedParameter = namedParameter.tail; - namedParameterType = namedParameterType.tail; - } - return null; - } - - DartType subst(Link<DartType> arguments, Link<DartType> parameters) { - if (parameters.isEmpty) { - assert(arguments.isEmpty); - // Return fast on empty substitutions. - return this; - } - var newReturnType = returnType.subst(arguments, parameters); - bool changed = !identical(newReturnType, returnType); - var newParameterTypes = - Types.substTypes(parameterTypes, arguments, parameters); - var newOptionalParameterTypes = - Types.substTypes(optionalParameterTypes, arguments, parameters); - var newNamedParameterTypes = - Types.substTypes(namedParameterTypes, arguments, parameters); - if (!changed && - (!identical(parameterTypes, newParameterTypes) || - !identical(optionalParameterTypes, newOptionalParameterTypes) || - !identical(namedParameterTypes, newNamedParameterTypes))) { - changed = true; - } - if (changed) { - // Create a new type only if necessary. - return new FunctionType(element, - newReturnType, - newParameterTypes, - newOptionalParameterTypes, - namedParameters, - newNamedParameterTypes); - } - return this; - } - - bool forEachMalformedType(bool f(MalformedType type)) { - if (!returnType.forEachMalformedType(f)) { - return false; - } - for (DartType parameterType in parameterTypes) { - if (!parameterType.forEachMalformedType(f)) { - return false; - } - } - for (DartType parameterType in optionalParameterTypes) { - if (!parameterType.forEachMalformedType(f)) { - return false; - } - } - for (DartType parameterType in namedParameterTypes) { - if (!parameterType.forEachMalformedType(f)) { - return false; - } - } - return true; - } - - DartType unalias(Compiler compiler) => this; - - String toString() { - StringBuffer sb = new StringBuffer(); - sb.add('('); - parameterTypes.printOn(sb, ', '); - bool first = parameterTypes.isEmpty; - if (!optionalParameterTypes.isEmpty) { - if (!first) { - sb.add(', '); - } - sb.add('['); - optionalParameterTypes.printOn(sb, ', '); - sb.add(']'); - first = false; - } - if (!namedParameterTypes.isEmpty) { - if (!first) { - sb.add(', '); - } - sb.add('{'); - Link<SourceString> namedParameter = namedParameters; - Link<DartType> namedParameterType = namedParameterTypes; - first = true; - while (!namedParameter.isEmpty && !namedParameterType.isEmpty) { - if (!first) { - sb.add(', '); - } - sb.add(namedParameterType.head); - sb.add(' '); - sb.add(namedParameter.head.slowToString()); - namedParameter = namedParameter.tail; - namedParameterType = namedParameterType.tail; - first = false; - } - sb.add('}'); - } - sb.add(') -> ${returnType}'); - return sb.toString(); - } - - SourceString get name => const SourceString('Function'); - - int computeArity() { - int arity = 0; - parameterTypes.forEach((_) { arity++; }); - return arity; - } - - int get hashCode { - int hash = 17 * element.hashCode + 3 * returnType.hashCode; - for (DartType parameter in parameterTypes) { - hash = 17 * hash + 3 * parameter.hashCode; - } - for (DartType parameter in optionalParameterTypes) { - hash = 17 * hash + 3 * parameter.hashCode; - } - for (SourceString name in namedParameters) { - hash = 17 * hash + 3 * name.hashCode; - } - for (DartType parameter in namedParameterTypes) { - hash = 17 * hash + 3 * parameter.hashCode; - } - return hash; - } - - bool operator ==(other) { - if (other is !FunctionType) return false; - return returnType == other.returnType - && parameterTypes == other.parameterTypes - && optionalParameterTypes == other.optionalParameterTypes - && namedParameters == other.namedParameters - && namedParameterTypes == other.namedParameterTypes; - } -} - -class TypedefType extends GenericType { - final TypedefElement element; - - TypedefType(this.element, - [Link<DartType> typeArguments = const Link<DartType>()]) - : super(typeArguments, hasMalformed(typeArguments)); - - TypedefType _createType(Link<DartType> newTypeArguments) { - return new TypedefType(element, newTypeArguments); - } - - TypeKind get kind => TypeKind.TYPEDEF; - - SourceString get name => element.name; - - DartType unalias(Compiler compiler) { - // TODO(ahe): This should be [ensureResolved]. - compiler.resolveTypedef(element); - DartType definition = element.alias.unalias(compiler); - TypedefType declaration = element.computeType(compiler); - return definition.subst(typeArguments, declaration.typeArguments); - } - - bool operator ==(other) { - if (other is !TypedefType) return false; - return super == other; - } - - TypedefType asRaw() => super.asRaw(); -} - -/** - * Special type to hold the [dynamic] type. Used for correctly returning - * 'dynamic' on [toString]. - */ -class DynamicType extends InterfaceType { - DynamicType(ClassElement element) : super(element); - - SourceString get name => const SourceString('dynamic'); -} - -class Types { - final Compiler compiler; - // TODO(karlklose): should we have a class Void? - final VoidType voidType; - final DynamicType dynamicType; - - factory Types(Compiler compiler, ClassElement dynamicElement) { - LibraryElement library = new LibraryElementX(new Script(null, null)); - VoidType voidType = new VoidType(new VoidElementX(library)); - DynamicType dynamicType = new DynamicType(dynamicElement); - dynamicElement.rawType = dynamicElement.thisType = dynamicType; - return new Types.internal(compiler, voidType, dynamicType); - } - - Types.internal(this.compiler, this.voidType, this.dynamicType); - - /** Returns true if t is a subtype of s */ - bool isSubtype(DartType t, DartType s) { - if (identical(t, s) || - identical(t, dynamicType) || - identical(s, dynamicType) || - t.isMalformed || - s.isMalformed || - identical(s.element, compiler.objectClass) || - identical(t.element, compiler.nullClass)) { - return true; - } - t = t.unalias(compiler); - s = s.unalias(compiler); - - if (t is VoidType) { - return false; - } else if (t is InterfaceType) { - if (s is !InterfaceType) return false; - ClassElement tc = t.element; - if (identical(tc, s.element)) return true; - for (Link<DartType> supertypes = tc.allSupertypes; - supertypes != null && !supertypes.isEmpty; - supertypes = supertypes.tail) { - DartType supertype = supertypes.head; - if (identical(supertype.element, s.element)) return true; - } - return false; - } else if (t is FunctionType) { - if (identical(s.element, compiler.functionClass)) return true; - if (s is !FunctionType) return false; - FunctionType tf = t; - FunctionType sf = s; - Link<DartType> tps = tf.parameterTypes; - Link<DartType> sps = sf.parameterTypes; - while (!tps.isEmpty && !sps.isEmpty) { - if (!isAssignable(tps.head, sps.head)) return false; - tps = tps.tail; - sps = sps.tail; - } - if (!tps.isEmpty || !sps.isEmpty) return false; - if (!isAssignable(sf.returnType, tf.returnType)) return false; - if (!sf.namedParameters.isEmpty) { - // Since named parameters are globally ordered we can determine the - // subset relation with a linear search for [:sf.NamedParameters:] - // within [:tf.NamedParameters:]. - Link<SourceString> tNames = tf.namedParameters; - Link<DartType> tTypes = tf.namedParameterTypes; - Link<SourceString> sNames = sf.namedParameters; - Link<DartType> sTypes = sf.namedParameterTypes; - while (!tNames.isEmpty && !sNames.isEmpty) { - if (sNames.head == tNames.head) { - if (!isAssignable(tTypes.head, sTypes.head)) return false; - - sNames = sNames.tail; - sTypes = sTypes.tail; - } - tNames = tNames.tail; - tTypes = tTypes.tail; - } - if (!sNames.isEmpty) { - // We didn't find all names. - return false; - } - } - if (!sf.optionalParameterTypes.isEmpty) { - Link<DartType> tOptionalParameterType = tf.optionalParameterTypes; - Link<DartType> sOptionalParameterType = sf.optionalParameterTypes; - while (!tOptionalParameterType.isEmpty && - !sOptionalParameterType.isEmpty) { - if (!isAssignable(tOptionalParameterType.head, - sOptionalParameterType.head)) { - return false; - } - sOptionalParameterType = sOptionalParameterType.tail; - tOptionalParameterType = tOptionalParameterType.tail; - } - if (!sOptionalParameterType.isEmpty) { - // We didn't find enough optional parameters. - return false; - } - } - return true; - } else if (t is TypeVariableType) { - if (s is !TypeVariableType) return false; - return (identical(t.element, s.element)); - } else { - throw 'internal error: unknown type kind'; - } - } - - bool isAssignable(DartType r, DartType s) { - return isSubtype(r, s) || isSubtype(s, r); - } - - - /** - * Helper method for performing substitution of a linked list of types. - * - * If no types are changed by the substitution, the [types] is returned - * instead of a newly created linked list. - */ - static Link<DartType> substTypes(Link<DartType> types, - Link<DartType> arguments, - Link<DartType> parameters) { - bool changed = false; - var builder = new LinkBuilder<DartType>(); - Link<DartType> typeLink = types; - while (!typeLink.isEmpty) { - var argument = typeLink.head.subst(arguments, parameters); - if (!changed && !identical(argument, typeLink.head)) { - changed = true; - } - builder.addLast(argument); - typeLink = typeLink.tail; - } - if (changed) { - // Create a new link only if necessary. - return builder.toLink(); - } - return types; - } - - /** - * Combine error messages in a malformed type to a single message string. - */ - static String fetchReasonsFromMalformedType(DartType type) { - // TODO(johnniwinther): Figure out how to produce good error message in face - // of multiple errors, and how to ensure non-localized error messages. - var reasons = new List<String>(); - type.forEachMalformedType((MalformedType malformedType) { - ErroneousElement error = malformedType.element; - Message message = error.messageKind.message(error.messageArguments); - reasons.add(message.toString()); - return true; - }); - return Strings.join(reasons, ', '); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/diagnostic_listener.dart b/pkgs/markdown/test/lib/src/compiler/implementation/diagnostic_listener.dart deleted file mode 100644 index 1d0c2b9..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/diagnostic_listener.dart +++ /dev/null
@@ -1,28 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of dart2js; - -abstract class DiagnosticListener { - // TODO(karlklose): replace cancel with better error reporting mechanism. - void cancel(String reason, {node, token, instruction, element}); - // TODO(karlklose): rename log to something like reportInfo. - void log(message); - // TODO(karlklose): add reportWarning and reportError to this interface. - - void internalErrorOnElement(Element element, String message); - void internalError(String message, - {Node node, Token token, HInstruction instruction, - Element element}); - - SourceSpan spanFromSpannable(Spannable node, [Uri uri]); - - void reportMessage(SourceSpan span, Diagnostic message, api.Diagnostic kind); - - // TODO(ahe): Rename to reportError when that method has been removed. - void reportErrorCode(Spannable node, MessageKind errorCode, [Map arguments]); - - /// Returns true if a diagnostic was emitted. - bool onDeprecatedFeature(Spannable span, String feature); -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/elements/elements.dart b/pkgs/markdown/test/lib/src/compiler/implementation/elements/elements.dart deleted file mode 100644 index 2798f95..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/elements/elements.dart +++ /dev/null
@@ -1,792 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library elements; - -import 'dart:uri'; - -import 'modelx.dart'; -import '../tree/tree.dart'; -import '../util/util.dart'; -import '../resolution/resolution.dart'; - -import '../dart2jslib.dart' show InterfaceType, - DartType, - TypeVariableType, - TypedefType, - MessageKind, - DiagnosticListener, - Script, - FunctionType, - SourceString, - Selector, - Constant, - Compiler; - -import '../dart_types.dart'; - -import '../scanner/scannerlib.dart' show Token, - isUserDefinableOperator, - isMinusOperator; - -const int STATE_NOT_STARTED = 0; -const int STATE_STARTED = 1; -const int STATE_DONE = 2; - -class ElementCategory { - /** - * Represents things that we don't expect to find when looking in a - * scope. - */ - static const int NONE = 0; - - /** Field, parameter, or variable. */ - static const int VARIABLE = 1; - - /** Function, method, or foreign function. */ - static const int FUNCTION = 2; - - static const int CLASS = 4; - - static const int PREFIX = 8; - - /** Constructor or factory. */ - static const int FACTORY = 16; - - static const int ALIAS = 32; - - static const int SUPER = 64; - - /** Type variable */ - static const int TYPE_VARIABLE = 128; - - static const int IMPLIES_TYPE = CLASS | ALIAS | TYPE_VARIABLE; -} - -class ElementKind { - final String id; - final int category; - - const ElementKind(String this.id, this.category); - - static const ElementKind VARIABLE = - const ElementKind('variable', ElementCategory.VARIABLE); - static const ElementKind PARAMETER = - const ElementKind('parameter', ElementCategory.VARIABLE); - // Parameters in constructors that directly initialize fields. For example: - // [:A(this.field):]. - static const ElementKind FIELD_PARAMETER = - const ElementKind('field_parameter', ElementCategory.VARIABLE); - static const ElementKind FUNCTION = - const ElementKind('function', ElementCategory.FUNCTION); - static const ElementKind CLASS = - const ElementKind('class', ElementCategory.CLASS); - static const ElementKind GENERATIVE_CONSTRUCTOR = - const ElementKind('generative_constructor', ElementCategory.FACTORY); - static const ElementKind FIELD = - const ElementKind('field', ElementCategory.VARIABLE); - static const ElementKind VARIABLE_LIST = - const ElementKind('variable_list', ElementCategory.NONE); - static const ElementKind FIELD_LIST = - const ElementKind('field_list', ElementCategory.NONE); - static const ElementKind GENERATIVE_CONSTRUCTOR_BODY = - const ElementKind('generative_constructor_body', ElementCategory.NONE); - static const ElementKind COMPILATION_UNIT = - const ElementKind('compilation_unit', ElementCategory.NONE); - static const ElementKind GETTER = - const ElementKind('getter', ElementCategory.NONE); - static const ElementKind SETTER = - const ElementKind('setter', ElementCategory.NONE); - static const ElementKind TYPE_VARIABLE = - const ElementKind('type_variable', ElementCategory.TYPE_VARIABLE); - static const ElementKind ABSTRACT_FIELD = - const ElementKind('abstract_field', ElementCategory.VARIABLE); - static const ElementKind LIBRARY = - const ElementKind('library', ElementCategory.NONE); - static const ElementKind PREFIX = - const ElementKind('prefix', ElementCategory.PREFIX); - static const ElementKind TYPEDEF = - const ElementKind('typedef', ElementCategory.ALIAS); - - static const ElementKind STATEMENT = - const ElementKind('statement', ElementCategory.NONE); - static const ElementKind LABEL = - const ElementKind('label', ElementCategory.NONE); - static const ElementKind VOID = - const ElementKind('void', ElementCategory.NONE); - - static const ElementKind AMBIGUOUS = - const ElementKind('ambiguous', ElementCategory.NONE); - static const ElementKind ERROR = - const ElementKind('error', ElementCategory.NONE); - static const ElementKind MALFORMED_TYPE = - const ElementKind('malformed', ElementCategory.NONE); - - toString() => id; -} - -abstract class Element implements Spannable { - SourceString get name; - ElementKind get kind; - Modifiers get modifiers; - Element get enclosingElement; - Link<MetadataAnnotation> get metadata; - - Node parseNode(DiagnosticListener listener); - DartType computeType(Compiler compiler); - - bool isFunction(); - bool isConstructor(); - bool isClosure(); - bool isMember(); - bool isInstanceMember(); - bool isInStaticMember(); - - bool isFactoryConstructor(); - bool isGenerativeConstructor(); - bool isGenerativeConstructorBody(); - bool isCompilationUnit(); - bool isClass(); - bool isPrefix(); - bool isVariable(); - bool isParameter(); - bool isStatement(); - bool isTypedef(); - bool isTypeVariable(); - bool isField(); - bool isAbstractField(); - bool isGetter(); - bool isSetter(); - bool isAccessor(); - bool isLibrary(); - bool isErroneous(); - bool isAmbiguous(); - - bool isTopLevel(); - bool isAssignable(); - bool isNative(); - - bool impliesType(); - - Token position(); - - CompilationUnitElement getCompilationUnit(); - LibraryElement getLibrary(); - LibraryElement getImplementationLibrary(); - ClassElement getEnclosingClass(); - Element getEnclosingClassOrCompilationUnit(); - Element getEnclosingMember(); - Element getOutermostEnclosingMemberOrTopLevel(); - - FunctionElement asFunctionElement(); - - bool get isPatched; - bool get isPatch; - bool get isImplementation; - bool get isDeclaration; - bool get isSynthesized; - - Element get implementation; - Element get declaration; - Element get patch; - Element get origin; - - bool hasFixedBackendName(); - String fixedBackendName(); - - bool isAbstract(Compiler compiler); - bool isForeign(Compiler compiler); - - void addMetadata(MetadataAnnotation annotation); - void setNative(String name); - void setFixedBackendName(String name); - - Scope buildScope(); -} - -class Elements { - static bool isUnresolved(Element e) { - return e == null || e.isErroneous(); - } - static bool isErroneousElement(Element e) => e != null && e.isErroneous(); - - static bool isClass(Element e) => e != null && e.kind == ElementKind.CLASS; - static bool isTypedef(Element e) { - return e != null && e.kind == ElementKind.TYPEDEF; - } - - static bool isLocal(Element element) { - return !Elements.isUnresolved(element) - && !element.isInstanceMember() - && !isStaticOrTopLevelField(element) - && !isStaticOrTopLevelFunction(element) - && (identical(element.kind, ElementKind.VARIABLE) || - identical(element.kind, ElementKind.PARAMETER) || - identical(element.kind, ElementKind.FUNCTION)); - } - - static bool isInstanceField(Element element) { - return !Elements.isUnresolved(element) - && element.isInstanceMember() - && (identical(element.kind, ElementKind.FIELD) - || identical(element.kind, ElementKind.GETTER) - || identical(element.kind, ElementKind.SETTER)); - } - - static bool isStaticOrTopLevel(Element element) { - // TODO(ager): This should not be necessary when patch support has - // been reworked. - if (!Elements.isUnresolved(element) - && element.modifiers.isStatic()) { - return true; - } - return !Elements.isUnresolved(element) - && !element.isInstanceMember() - && !element.isPrefix() - && element.enclosingElement != null - && (element.enclosingElement.kind == ElementKind.CLASS || - element.enclosingElement.kind == ElementKind.COMPILATION_UNIT || - element.enclosingElement.kind == ElementKind.LIBRARY); - } - - static bool isStaticOrTopLevelField(Element element) { - return isStaticOrTopLevel(element) - && (identical(element.kind, ElementKind.FIELD) - || identical(element.kind, ElementKind.GETTER) - || identical(element.kind, ElementKind.SETTER)); - } - - static bool isStaticOrTopLevelFunction(Element element) { - return isStaticOrTopLevel(element) - && (identical(element.kind, ElementKind.FUNCTION)); - } - - static bool isInstanceMethod(Element element) { - return !Elements.isUnresolved(element) - && element.isInstanceMember() - && (identical(element.kind, ElementKind.FUNCTION)); - } - - static bool isInstanceSend(Send send, TreeElements elements) { - Element element = elements[send]; - if (element == null) return !isClosureSend(send, element); - return isInstanceMethod(element) || isInstanceField(element); - } - - static bool isClosureSend(Send send, Element element) { - if (send.isPropertyAccess) return false; - if (send.receiver != null) return false; - // (o)() or foo()(). - if (element == null && send.selector.asIdentifier() == null) return true; - if (element == null) return false; - // foo() with foo a local or a parameter. - return isLocal(element); - } - - static SourceString constructConstructorName(SourceString receiver, - SourceString selector) { - String r = receiver.slowToString(); - String s = selector.slowToString(); - return new SourceString('$r\$$s'); - } - - static SourceString deconstructConstructorName(SourceString name, - ClassElement holder) { - String r = '${holder.name.slowToString()}\$'; - String s = name.slowToString(); - if (s.startsWith(r)) { - return new SourceString(s.substring(r.length)); - } - return null; - } - - /** - * Map an operator-name to a valid Dart identifier. - * - * For non-operator names, this metod just returns its input. - * - * The results returned from this method are guaranteed to be valid - * JavaScript identifers, except it may include reserved words for - * non-operator names. - */ - static SourceString operatorNameToIdentifier(SourceString name) { - if (name == null) return null; - String value = name.stringValue; - if (value == null) { - return name; - } else if (identical(value, '==')) { - return const SourceString(r'operator$eq'); - } else if (identical(value, '~')) { - return const SourceString(r'operator$not'); - } else if (identical(value, '[]')) { - return const SourceString(r'operator$index'); - } else if (identical(value, '[]=')) { - return const SourceString(r'operator$indexSet'); - } else if (identical(value, '*')) { - return const SourceString(r'operator$mul'); - } else if (identical(value, '/')) { - return const SourceString(r'operator$div'); - } else if (identical(value, '%')) { - return const SourceString(r'operator$mod'); - } else if (identical(value, '~/')) { - return const SourceString(r'operator$tdiv'); - } else if (identical(value, '+')) { - return const SourceString(r'operator$add'); - } else if (identical(value, '<<')) { - return const SourceString(r'operator$shl'); - } else if (identical(value, '>>')) { - return const SourceString(r'operator$shr'); - } else if (identical(value, '>=')) { - return const SourceString(r'operator$ge'); - } else if (identical(value, '>')) { - return const SourceString(r'operator$gt'); - } else if (identical(value, '<=')) { - return const SourceString(r'operator$le'); - } else if (identical(value, '<')) { - return const SourceString(r'operator$lt'); - } else if (identical(value, '&')) { - return const SourceString(r'operator$and'); - } else if (identical(value, '^')) { - return const SourceString(r'operator$xor'); - } else if (identical(value, '|')) { - return const SourceString(r'operator$or'); - } else if (identical(value, '-')) { - return const SourceString(r'operator$sub'); - } else if (identical(value, 'unary-')) { - return const SourceString(r'operator$negate'); - } else { - return name; - } - } - - static SourceString constructOperatorNameOrNull(SourceString op, - bool isUnary) { - String value = op.stringValue; - if (isMinusOperator(value)) { - return isUnary ? const SourceString('unary-') : op; - } else if (isUserDefinableOperator(value)) { - return op; - } else { - return null; - } - } - - static SourceString constructOperatorName(SourceString op, bool isUnary) { - SourceString operatorName = constructOperatorNameOrNull(op, isUnary); - if (operatorName == null) throw 'Unhandled operator: ${op.slowToString()}'; - else return operatorName; - } - - static SourceString mapToUserOperatorOrNull(SourceString op) { - String value = op.stringValue; - - if (identical(value, '!=')) return const SourceString('=='); - if (identical(value, '*=')) return const SourceString('*'); - if (identical(value, '/=')) return const SourceString('/'); - if (identical(value, '%=')) return const SourceString('%'); - if (identical(value, '~/=')) return const SourceString('~/'); - if (identical(value, '+=')) return const SourceString('+'); - if (identical(value, '-=')) return const SourceString('-'); - if (identical(value, '<<=')) return const SourceString('<<'); - if (identical(value, '>>=')) return const SourceString('>>'); - if (identical(value, '&=')) return const SourceString('&'); - if (identical(value, '^=')) return const SourceString('^'); - if (identical(value, '|=')) return const SourceString('|'); - - return null; - } - - static SourceString mapToUserOperator(SourceString op) { - SourceString userOperator = mapToUserOperatorOrNull(op); - if (userOperator == null) throw 'Unhandled operator: ${op.slowToString()}'; - else return userOperator; - } - - static bool isNumberOrStringSupertype(Element element, Compiler compiler) { - LibraryElement coreLibrary = compiler.coreLibrary; - return (element == coreLibrary.find(const SourceString('Comparable'))); - } - - static bool isStringOnlySupertype(Element element, Compiler compiler) { - LibraryElement coreLibrary = compiler.coreLibrary; - return element == coreLibrary.find(const SourceString('Pattern')); - } - - static bool isListSupertype(Element element, Compiler compiler) { - LibraryElement coreLibrary = compiler.coreLibrary; - return (element == coreLibrary.find(const SourceString('Collection'))) - || (element == coreLibrary.find(const SourceString('Iterable'))); - } - - /// A `compareTo` function that places [Element]s in a consistent order based - /// on the source code order. - static int compareByPosition(Element a, Element b) { - CompilationUnitElement unitA = a.getCompilationUnit(); - CompilationUnitElement unitB = b.getCompilationUnit(); - if (!identical(unitA, unitB)) { - int r = unitA.script.uri.path.compareTo(unitB.script.uri.path); - if (r != 0) return r; - } - Token positionA = a.position(); - Token positionB = b.position(); - int r = positionA.charOffset.compareTo(positionB.charOffset); - if (r != 0) return r; - r = a.name.slowToString().compareTo(b.name.slowToString()); - if (r != 0) return r; - // Same file, position and name. If this happens, we should find out why - // and make the order total and independent of hashCode. - return a.hashCode.compareTo(b.hashCode); - } - - static List<Element> sortedByPosition(Iterable<Element> elements) { - return elements.toList()..sort(compareByPosition); - } -} - -abstract class ErroneousElement extends Element implements FunctionElement { - MessageKind get messageKind; - Map get messageArguments; -} - -abstract class AmbiguousElement extends Element { - MessageKind get messageKind; - Map get messageArguments; - Element get existingElement; - Element get newElement; -} - -// TODO(kasperl): This probably shouldn't be called an element. It's -// just an interface shared by classes and libraries. -abstract class ScopeContainerElement { - Element localLookup(SourceString elementName); -} - -abstract class CompilationUnitElement extends Element { - Script get script; - PartOf get partTag; - - void addMember(Element element, DiagnosticListener listener); - void setPartOf(PartOf tag, DiagnosticListener listener); - bool get hasMembers; -} - -abstract class LibraryElement extends Element implements ScopeContainerElement { - /** - * The canonical uri for this library. - * - * For user libraries the canonical uri is the script uri. For platform - * libraries the canonical uri is of the form [:dart:x:]. - */ - Uri get canonicalUri; - CompilationUnitElement get entryCompilationUnit; - Link<CompilationUnitElement> get compilationUnits; - Link<LibraryTag> get tags; - LibraryName get libraryTag; - Link<Element> get exports; - - /** - * [:true:] if this library is part of the platform, that is its canonical - * uri has the scheme 'dart'. - */ - bool get isPlatformLibrary; - - /** - * [:true:] if this library is a platform library whose path starts with - * an underscore. - */ - bool get isInternalLibrary; - bool get canUseNative; - bool get exportsHandled; - - // TODO(kasperl): We should try to get rid of these. - void set canUseNative(bool value); - void set libraryTag(LibraryName value); - - LibraryElement get implementation; - - void addCompilationUnit(CompilationUnitElement element); - void addTag(LibraryTag tag, DiagnosticListener listener); - void addImport(Element element, DiagnosticListener listener); - - void addMember(Element element, DiagnosticListener listener); - void addToScope(Element element, DiagnosticListener listener); - - // TODO(kasperl): Get rid of this method. - Iterable<Element> getNonPrivateElementsInScope(); - - void setExports(Iterable<Element> exportedElements); - - Element find(SourceString elementName); - Element findLocal(SourceString elementName); - void forEachExport(f(Element element)); - - void forEachLocalMember(f(Element element)); - - bool hasLibraryName(); - String getLibraryOrScriptName(); -} - -abstract class PrefixElement extends Element { - Map<SourceString, Element> get imported; - Element lookupLocalMember(SourceString memberName); -} - -abstract class TypedefElement extends Element - implements TypeDeclarationElement { - TypedefType get rawType; - DartType get alias; - FunctionSignature get functionSignature; - Link<DartType> get typeVariables; - - bool get isResolved; - bool get isBeingResolved; - - // TODO(kasperl): Try to get rid of these setters. - void set alias(DartType value); - void set isResolved(bool value); - void set isBeingResolved(bool value); - void set functionSignature(FunctionSignature value); -} - -abstract class VariableElement extends Element { - VariableListElement get variables; - - // TODO(kasperl): Try to get rid of this. - Expression get cachedNode; -} - -abstract class FieldParameterElement extends VariableElement { - VariableElement get fieldElement; -} - -abstract class VariableListElement extends Element { - DartType get type; - FunctionSignature get functionSignature; - - // TODO(kasperl): Try to get rid of this. - void set type(DartType value); -} - -abstract class AbstractFieldElement extends Element { - FunctionElement get getter; - FunctionElement get setter; -} - -abstract class FunctionSignature { - DartType get returnType; - Link<Element> get requiredParameters; - Link<Element> get optionalParameters; - - int get requiredParameterCount; - int get optionalParameterCount; - bool get optionalParametersAreNamed; - - int get parameterCount; - List<Element> get orderedOptionalParameters; - - void forEachParameter(void function(Element parameter)); - void forEachRequiredParameter(void function(Element parameter)); - void forEachOptionalParameter(void function(Element parameter)); - - void orderedForEachParameter(void function(Element parameter)); -} - -abstract class FunctionElement extends Element { - FunctionExpression get cachedNode; - DartType get type; - FunctionSignature get functionSignature; - FunctionElement get redirectionTarget; - FunctionElement get defaultImplementation; - - FunctionElement get patch; - FunctionElement get origin; - - // TODO(kasperl): These are bit fishy. Do we really need them? - void set patch(FunctionElement value); - void set origin(FunctionElement value); - void set defaultImplementation(FunctionElement value); - - void setPatch(FunctionElement patchElement); - FunctionSignature computeSignature(Compiler compiler); - int requiredParameterCount(Compiler compiler); - int optionalParameterCount(Compiler compiler); - int parameterCount(Compiler compiler); - - FunctionExpression parseNode(DiagnosticListener listener); -} - -abstract class ConstructorBodyElement extends FunctionElement { - FunctionElement get constructor; -} - -/** - * [TypeDeclarationElement] defines the common interface for class/interface - * declarations and typedefs. - */ -abstract class TypeDeclarationElement extends Element { - GenericType get rawType; - - /** - * The type variables declared on this declaration. The type variables are not - * available until the type of the element has been computed through - * [computeType]. - */ - Link<DartType> get typeVariables; -} - -abstract class ClassElement extends TypeDeclarationElement - implements ScopeContainerElement { - int get id; - - InterfaceType get rawType; - InterfaceType get thisType; - - ClassElement get superclass; - - DartType get supertype; - Link<DartType> get allSupertypes; - Link<DartType> get interfaces; - - bool get hasConstructor; - Link<Element> get constructors; - - ClassElement get patch; - ClassElement get origin; - ClassElement get declaration; - ClassElement get implementation; - - int get supertypeLoadState; - int get resolutionState; - SourceString get nativeTagInfo; - - bool get isMixinApplication; - bool get hasBackendMembers; - bool get hasLocalScopeMembers; - - // TODO(kasperl): These are bit fishy. Do we really need them? - void set rawType(InterfaceType value); - void set thisType(InterfaceType value); - void set supertype(DartType value); - void set allSupertypes(Link<DartType> value); - void set interfaces(Link<DartType> value); - void set patch(ClassElement value); - void set origin(ClassElement value); - void set supertypeLoadState(int value); - void set resolutionState(int value); - void set nativeTagInfo(SourceString value); - - // TODO(kasperl): These seem outdated. - bool isInterface(); - DartType get defaultClass; - void set defaultClass(DartType value); - - bool isObject(Compiler compiler); - bool isSubclassOf(ClassElement cls); - bool implementsInterface(ClassElement intrface); - bool isShadowedByField(Element fieldMember); - - ClassElement ensureResolved(Compiler compiler); - - void addMember(Element element, DiagnosticListener listener); - void addToScope(Element element, DiagnosticListener listener); - - /** - * Add a synthetic nullary constructor if there are no other - * constructors. - */ - void addDefaultConstructorIfNeeded(Compiler compiler); - - void addBackendMember(Element element); - void reverseBackendMembers(); - - Element lookupMember(SourceString memberName); - Element lookupSelector(Selector selector); - - Element lookupLocalMember(SourceString memberName); - Element lookupBackendMember(SourceString memberName); - Element lookupSuperMember(SourceString memberName); - - Element lookupSuperMemberInLibrary(SourceString memberName, - LibraryElement library); - - Element lookupSuperInterfaceMember(SourceString memberName, - LibraryElement fromLibrary); - - Element validateConstructorLookupResults(Selector selector, - Element result, - Element noMatch(Element)); - - Element lookupConstructor(Selector selector, [Element noMatch(Element)]); - Element lookupFactoryConstructor(Selector selector, - [Element noMatch(Element)]); - - void forEachMember(void f(ClassElement enclosingClass, Element member), - {includeBackendMembers: false, - includeSuperMembers: false}); - - void forEachInstanceField(void f(ClassElement enclosingClass, Element field), - {includeBackendMembers: false, - includeSuperMembers: false}); - - void forEachLocalMember(void f(Element member)); - void forEachBackendMember(void f(Element member)); -} - -abstract class MixinApplicationElement extends ClassElement { - ClassElement get mixin; - void set mixin(ClassElement value); -} - -abstract class LabelElement extends Element { - Label get label; - String get labelName; - TargetElement get target; - - bool get isTarget; - bool get isBreakTarget; - bool get isContinueTarget; - - void setBreakTarget(); - void setContinueTarget(); -} - -abstract class TargetElement extends Element { - Node get statement; - int get nestingLevel; - Link<LabelElement> get labels; - - bool get isTarget; - bool get isBreakTarget; - bool get isContinueTarget; - bool get isSwitch; - - // TODO(kasperl): Try to get rid of these. - void set isBreakTarget(bool value); - void set isContinueTarget(bool value); - - LabelElement addLabel(Label label, String labelName); -} - -abstract class TypeVariableElement extends Element { - TypeVariableType get type; - DartType get bound; - - // TODO(kasperl): Try to get rid of these. - void set type(TypeVariableType value); - void set bound(DartType value); -} - -abstract class MetadataAnnotation implements Spannable { - Constant get value; - Element get annotatedElement; - int get resolutionState; - Token get beginToken; - Token get endToken; - - // TODO(kasperl): Try to get rid of these. - void set annotatedElement(Element value); - void set resolutionState(int value); - - MetadataAnnotation ensureResolved(Compiler compiler); -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/elements/modelx.dart b/pkgs/markdown/test/lib/src/compiler/implementation/elements/modelx.dart deleted file mode 100644 index f007946..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/elements/modelx.dart +++ /dev/null
@@ -1,1981 +0,0 @@ -// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library elements.modelx; - -import 'dart:uri'; - -import 'elements.dart'; -import '../../compiler.dart' as api; -import '../tree/tree.dart'; -import '../util/util.dart'; -import '../resolution/resolution.dart'; - -import '../dart2jslib.dart' show invariant, - InterfaceType, - DartType, - TypeVariableType, - TypedefType, - MessageKind, - DiagnosticListener, - Script, - FunctionType, - SourceString, - Selector, - Constant, - Compiler; - -import '../dart_types.dart'; - -import '../scanner/scannerlib.dart' show Token, EOF_TOKEN; - - -class ElementX implements Element { - static int elementHashCode = 0; - - final SourceString name; - final ElementKind kind; - final Element enclosingElement; - final int hashCode = ++elementHashCode; - Link<MetadataAnnotation> metadata = const Link<MetadataAnnotation>(); - - ElementX(this.name, this.kind, this.enclosingElement) { - assert(isErroneous() || getImplementationLibrary() != null); - } - - Modifiers get modifiers => Modifiers.EMPTY; - - Node parseNode(DiagnosticListener listener) { - listener.internalErrorOnElement(this, 'not implemented'); - } - - DartType computeType(Compiler compiler) { - compiler.internalError("$this.computeType.", token: position()); - } - - void addMetadata(MetadataAnnotation annotation) { - assert(annotation.annotatedElement == null); - annotation.annotatedElement = this; - metadata = metadata.prepend(annotation); - } - - bool isFunction() => identical(kind, ElementKind.FUNCTION); - bool isConstructor() => isFactoryConstructor() || isGenerativeConstructor(); - bool isClosure() => false; - bool isMember() { - // Check that this element is defined in the scope of a Class. - return enclosingElement != null && enclosingElement.isClass(); - } - bool isInstanceMember() => false; - - /** - * Returns [:true:] if this element is enclosed in a static member or is - * itself a static member. - */ - bool isInStaticMember() { - Element member = getEnclosingMember(); - return member != null && member.modifiers.isStatic(); - } - - bool isFactoryConstructor() => modifiers.isFactory(); - bool isGenerativeConstructor() => - identical(kind, ElementKind.GENERATIVE_CONSTRUCTOR); - bool isGenerativeConstructorBody() => - identical(kind, ElementKind.GENERATIVE_CONSTRUCTOR_BODY); - bool isCompilationUnit() => identical(kind, ElementKind.COMPILATION_UNIT); - bool isClass() => identical(kind, ElementKind.CLASS); - bool isPrefix() => identical(kind, ElementKind.PREFIX); - bool isVariable() => identical(kind, ElementKind.VARIABLE); - bool isParameter() => identical(kind, ElementKind.PARAMETER); - bool isStatement() => identical(kind, ElementKind.STATEMENT); - bool isTypedef() => identical(kind, ElementKind.TYPEDEF); - bool isTypeVariable() => identical(kind, ElementKind.TYPE_VARIABLE); - bool isField() => identical(kind, ElementKind.FIELD); - bool isAbstractField() => identical(kind, ElementKind.ABSTRACT_FIELD); - bool isGetter() => identical(kind, ElementKind.GETTER); - bool isSetter() => identical(kind, ElementKind.SETTER); - bool isAccessor() => isGetter() || isSetter(); - bool isLibrary() => identical(kind, ElementKind.LIBRARY); - bool impliesType() => (kind.category & ElementCategory.IMPLIES_TYPE) != 0; - - /** See [ErroneousElement] for documentation. */ - bool isErroneous() => false; - - /** See [AmbiguousElement] for documentation. */ - bool isAmbiguous() => false; - - /** - * Is [:true:] if this element has a corresponding patch. - * - * If [:true:] this element has a non-null [patch] field. - * - * See [:patch_parser.dart:] for a description of the terminology. - */ - bool get isPatched => false; - - /** - * Is [:true:] if this element is a patch. - * - * If [:true:] this element has a non-null [origin] field. - * - * See [:patch_parser.dart:] for a description of the terminology. - */ - bool get isPatch => false; - - /** - * Is [:true:] if this element defines the implementation for the entity of - * this element. - * - * See [:patch_parser.dart:] for a description of the terminology. - */ - bool get isImplementation => !isPatched; - - /** - * Is [:true:] if this element introduces the entity of this element. - * - * See [:patch_parser.dart:] for a description of the terminology. - */ - bool get isDeclaration => !isPatch; - - bool get isSynthesized => false; - - /** - * Returns the element which defines the implementation for the entity of this - * element. - * - * See [:patch_parser.dart:] for a description of the terminology. - */ - Element get implementation => isPatched ? patch : this; - - /** - * Returns the element which introduces the entity of this element. - * - * See [:patch_parser.dart:] for a description of the terminology. - */ - Element get declaration => isPatch ? origin : this; - - Element get patch { - throw new UnsupportedError('patch is not supported on $this'); - } - - Element get origin { - throw new UnsupportedError('origin is not supported on $this'); - } - - // TODO(johnniwinther): This breaks for libraries (for which enclosing - // elements are null) and is invalid for top level variable declarations for - // which the enclosing element is a VariableDeclarations and not a compilation - // unit. - bool isTopLevel() { - return enclosingElement != null && enclosingElement.isCompilationUnit(); - } - - bool isAssignable() { - if (modifiers.isFinalOrConst()) return false; - if (isFunction() || isGenerativeConstructor()) return false; - return true; - } - - Token position() => null; - - Token findMyName(Token token) { - for (Token t = token; !identical(t.kind, EOF_TOKEN); t = t.next) { - if (t.value == name) return t; - } - return token; - } - - CompilationUnitElement getCompilationUnit() { - Element element = this; - while (!element.isCompilationUnit()) { - element = element.enclosingElement; - } - return element; - } - - LibraryElement getLibrary() => enclosingElement.getLibrary(); - - LibraryElement getImplementationLibrary() { - Element element = this; - while (!identical(element.kind, ElementKind.LIBRARY)) { - element = element.enclosingElement; - } - return element; - } - - ClassElement getEnclosingClass() { - for (Element e = this; e != null; e = e.enclosingElement) { - if (e.isClass()) return e; - } - return null; - } - - Element getEnclosingClassOrCompilationUnit() { - for (Element e = this; e != null; e = e.enclosingElement) { - if (e.isClass() || e.isCompilationUnit()) return e; - } - return null; - } - - /** - * Returns the member enclosing this element or the element itself if it is a - * member. If no enclosing element is found, [:null:] is returned. - */ - Element getEnclosingMember() { - for (Element e = this; e != null; e = e.enclosingElement) { - if (e.isMember()) return e; - } - return null; - } - - Element getOutermostEnclosingMemberOrTopLevel() { - // TODO(lrn): Why is this called "Outermost"? - for (Element e = this; e != null; e = e.enclosingElement) { - if (e.isMember() || e.isTopLevel()) { - return e; - } - } - return null; - } - - /** - * Creates the scope for this element. - */ - Scope buildScope() => enclosingElement.buildScope(); - - String toString() { - // TODO(johnniwinther): Test for nullness of name, or make non-nullness an - // invariant for all element types? - var nameText = name != null ? name.slowToString() : '?'; - if (enclosingElement != null && !isTopLevel()) { - String holderName = enclosingElement.name != null - ? enclosingElement.name.slowToString() - : '${enclosingElement.kind}?'; - return '$kind($holderName#${nameText})'; - } else { - return '$kind(${nameText})'; - } - } - - String _fixedBackendName = null; - bool _isNative = false; - bool isNative() => _isNative; - bool hasFixedBackendName() => _fixedBackendName != null; - String fixedBackendName() => _fixedBackendName; - // Marks this element as a native element. - void setNative(String name) { - _isNative = true; - _fixedBackendName = name; - } - void setFixedBackendName(String name) { - _fixedBackendName = name; - } - - FunctionElement asFunctionElement() => null; - - static bool isInvalid(Element e) => e == null || e.isErroneous(); - - bool isAbstract(Compiler compiler) => modifiers.isAbstract(); - bool isForeign(Compiler compiler) => getLibrary() == compiler.foreignLibrary; -} - -/** - * Represents an unresolvable or duplicated element. - * - * An [ErroneousElement] is used instead of [null] to provide additional - * information about the error that caused the element to be unresolvable - * or otherwise invalid. - * - * Accessing any field or calling any method defined on [ErroneousElement] - * except [isErroneous] will currently throw an exception. (This might - * change when we actually want more information on the erroneous element, - * e.g., the name of the element we were trying to resolve.) - * - * Code that cannot not handle an [ErroneousElement] should use - * [: Element.isInvalid(element) :] - * to check for unresolvable elements instead of - * [: element == null :]. - */ -class ErroneousElementX extends ElementX implements ErroneousElement { - final MessageKind messageKind; - final Map messageArguments; - - ErroneousElementX(this.messageKind, this.messageArguments, - SourceString name, Element enclosing) - : super(name, ElementKind.ERROR, enclosing); - - isErroneous() => true; - - unsupported() { - throw 'unsupported operation on erroneous element'; - } - - Link<MetadataAnnotation> get metadata => unsupported(); - get type => unsupported(); - get cachedNode => unsupported(); - get functionSignature => unsupported(); - get patch => unsupported(); - get origin => unsupported(); - get defaultImplementation => unsupported(); - - bool get isPatched => unsupported(); - bool get isPatch => unsupported(); - - setPatch(patch) => unsupported(); - computeSignature(compiler) => unsupported(); - requiredParameterCount(compiler) => unsupported(); - optionalParameterCount(compiler) => unsupported(); - parameterCount(compiler) => unsupported(); - - // TODO(kasperl): These seem unnecessary. - set patch(value) => unsupported(); - set origin(value) => unsupported(); - set defaultImplementation(value) => unsupported(); - - get redirectionTarget => this; - - getLibrary() => enclosingElement.getLibrary(); - - String toString() { - String n = name.slowToString(); - return '<$n: ${messageKind.message(messageArguments)}>'; - } -} - -/** - * An ambiguous element represents multiple elements accessible by the same name. - * - * Ambiguous elements are created during handling of import/export scopes. If an - * ambiguous element is encountered during resolution a warning/error should be - * reported. - */ -class AmbiguousElementX extends ElementX implements AmbiguousElement { - /** - * The message to report on resolving this element. - */ - final MessageKind messageKind; - - /** - * The message arguments to report on resolving this element. - */ - final Map messageArguments; - - /** - * The first element that this ambiguous element might refer to. - */ - final Element existingElement; - - /** - * The second element that this ambiguous element might refer to. - */ - final Element newElement; - - AmbiguousElementX(this.messageKind, this.messageArguments, - Element enclosingElement, Element existingElement, Element newElement) - : this.existingElement = existingElement, - this.newElement = newElement, - super(existingElement.name, ElementKind.AMBIGUOUS, enclosingElement); - - bool isAmbiguous() => true; -} - -class ScopeX { - final Map<SourceString, Element> contents = new Map<SourceString, Element>(); - - bool get isEmpty => contents.isEmpty; - Iterable<Element> get values => contents.values; - - Element lookup(SourceString name) { - return contents[name]; - } - - void add(Element element, DiagnosticListener listener) { - if (element.isAccessor()) { - addAccessor(element, contents[element.name], listener); - } else { - Element existing = contents.putIfAbsent(element.name, () => element); - if (!identical(existing, element)) { - // TODO(ahe): Do something similar to Resolver.reportErrorWithContext. - listener.cancel('duplicate definition', token: element.position()); - listener.cancel('existing definition', token: existing.position()); - } - } - } - - /** - * Adds a definition for an [accessor] (getter or setter) to a scope. - * The definition binds to an abstract field that can hold both a getter - * and a setter. - * - * The abstract field is added once, for the first getter or setter, and - * reused if the other one is also added. - * The abstract field should not be treated as a proper member of the - * container, it's simply a way to return two results for one lookup. - * That is, the getter or setter does not have the abstract field as enclosing - * element, they are enclosed by the class or compilation unit, as is the - * abstract field. - */ - void addAccessor(Element accessor, - Element existing, - DiagnosticListener listener) { - void reportError(Element other) { - // TODO(ahe): Do something similar to Resolver.reportErrorWithContext. - listener.cancel('duplicate definition of ${accessor.name.slowToString()}', - element: accessor); - listener.cancel('existing definition', element: other); - } - - if (existing != null) { - if (!identical(existing.kind, ElementKind.ABSTRACT_FIELD)) { - reportError(existing); - } else { - AbstractFieldElementX field = existing; - if (accessor.isGetter()) { - if (field.getter != null && field.getter != accessor) { - reportError(field.getter); - } - field.getter = accessor; - } else { - assert(accessor.isSetter()); - if (field.setter != null && field.setter != accessor) { - reportError(field.setter); - } - field.setter = accessor; - } - } - } else { - Element container = accessor.getEnclosingClassOrCompilationUnit(); - AbstractFieldElementX field = - new AbstractFieldElementX(accessor.name, container); - if (accessor.isGetter()) { - field.getter = accessor; - } else { - field.setter = accessor; - } - add(field, listener); - } - } -} - -class CompilationUnitElementX extends ElementX - implements CompilationUnitElement { - final Script script; - PartOf partTag; - Link<Element> localMembers = const Link<Element>(); - - CompilationUnitElementX(Script script, LibraryElement library) - : this.script = script, - super(new SourceString(script.name), - ElementKind.COMPILATION_UNIT, - library) { - library.addCompilationUnit(this); - } - - void addMember(Element element, DiagnosticListener listener) { - // Keep a list of top level members. - localMembers = localMembers.prepend(element); - // Provide the member to the library to build scope. - if (enclosingElement.isPatch) { - getImplementationLibrary().addMember(element, listener); - } else { - getLibrary().addMember(element, listener); - } - } - - void setPartOf(PartOf tag, DiagnosticListener listener) { - LibraryElementX library = enclosingElement; - if (library.entryCompilationUnit == this) { - listener.reportMessage( - listener.spanFromSpannable(tag), - MessageKind.ILLEGAL_DIRECTIVE.error(), - api.Diagnostic.WARNING); - return; - } - if (!localMembers.isEmpty) { - listener.reportErrorCode(tag, MessageKind.BEFORE_TOP_LEVEL); - return; - } - if (partTag != null) { - listener.reportMessage( - listener.spanFromSpannable(tag), - MessageKind.DUPLICATED_PART_OF.error(), - api.Diagnostic.WARNING); - return; - } - partTag = tag; - LibraryName libraryTag = getLibrary().libraryTag; - if (libraryTag != null) { - String actualName = tag.name.toString(); - String expectedName = libraryTag.name.toString(); - if (expectedName != actualName) { - listener.reportMessage( - listener.spanFromSpannable(tag.name), - MessageKind.LIBRARY_NAME_MISMATCH.error( - {'libraryName': expectedName}), - api.Diagnostic.WARNING); - } - } - } - - bool get hasMembers => !localMembers.isEmpty; -} - -class LibraryElementX extends ElementX implements LibraryElement { - final Uri canonicalUri; - CompilationUnitElement entryCompilationUnit; - Link<CompilationUnitElement> compilationUnits = - const Link<CompilationUnitElement>(); - Link<LibraryTag> tags = const Link<LibraryTag>(); - LibraryName libraryTag; - bool canUseNative = false; - Link<Element> localMembers = const Link<Element>(); - final ScopeX localScope = new ScopeX(); - - /** - * If this library is patched, [patch] points to the patch library. - * - * See [:patch_parser.dart:] for a description of the terminology. - */ - LibraryElementX patch = null; - - /** - * If this is a patch library, [origin] points to the origin library. - * - * See [:patch_parser.dart:] for a description of the terminology. - */ - final LibraryElementX origin; - - /** - * Map for elements imported through import declarations. - * - * Addition to the map is performed by [addImport]. Lookup is done trough - * [find]. - */ - final Map<SourceString, Element> importScope; - - /** - * Link for elements exported either through export declarations or through - * declaration. This field should not be accessed directly but instead through - * the [exports] getter. - * - * [LibraryDependencyHandler] sets this field through [setExports] when the - * library is loaded. - */ - Link<Element> slotForExports; - - LibraryElementX(Script script, [Uri canonicalUri, LibraryElement this.origin]) - : this.canonicalUri = ((canonicalUri == null) ? script.uri : canonicalUri), - importScope = new Map<SourceString, Element>(), - super(new SourceString(script.name), ElementKind.LIBRARY, null) { - entryCompilationUnit = new CompilationUnitElementX(script, this); - if (isPatch) { - origin.patch = this; - } - } - - bool get isPatched => patch != null; - bool get isPatch => origin != null; - - LibraryElement get declaration => super.declaration; - LibraryElement get implementation => super.implementation; - - CompilationUnitElement getCompilationUnit() => entryCompilationUnit; - - void addCompilationUnit(CompilationUnitElement element) { - compilationUnits = compilationUnits.prepend(element); - } - - void addTag(LibraryTag tag, DiagnosticListener listener) { - tags = tags.prepend(tag); - } - - /** - * Adds [element] to the import scope of this library. - * - * If an element by the same name is already in the imported scope, an - * [ErroneousElement] will be put in the imported scope, allowing for the - * detection of ambiguous uses of imported names. - */ - void addImport(Element element, DiagnosticListener listener) { - Element existing = importScope[element.name]; - if (existing != null) { - // TODO(johnniwinther): Provide access to the import tags from which - // the elements came. - importScope[element.name] = new AmbiguousElementX( - MessageKind.DUPLICATE_IMPORT, {'name': element.name}, - this, existing, element); - } else { - importScope[element.name] = element; - } - } - - void addMember(Element element, DiagnosticListener listener) { - localMembers = localMembers.prepend(element); - addToScope(element, listener); - } - - void addToScope(Element element, DiagnosticListener listener) { - localScope.add(element, listener); - } - - Element localLookup(SourceString elementName) { - Element result = localScope.lookup(elementName); - if (result == null && isPatch) { - result = origin.localLookup(elementName); - } - return result; - } - - /** - * Returns [:true:] if the export scope has already been computed for this - * library. - */ - bool get exportsHandled => slotForExports != null; - - Link<Element> get exports { - assert(invariant(this, exportsHandled, - message: 'Exports not handled on $this')); - return slotForExports; - } - - /** - * Sets the export scope of this library. This method can only be called once. - */ - void setExports(Iterable<Element> exportedElements) { - assert(invariant(this, !exportsHandled, - message: 'Exports already set to $slotForExports on $this')); - assert(invariant(this, exportedElements != null)); - var builder = new LinkBuilder<Element>(); - for (Element export in exportedElements) { - builder.addLast(export); - } - slotForExports = builder.toLink(); - } - - LibraryElement getLibrary() => isPatch ? origin : this; - - /** - * Look up a top-level element in this library. The element could - * potentially have been imported from another library. Returns - * null if no such element exist and an [ErroneousElement] if multiple - * elements have been imported. - */ - Element find(SourceString elementName) { - Element result = localScope.lookup(elementName); - if (result != null) return result; - if (origin != null) { - result = origin.localScope.lookup(elementName); - if (result != null) return result; - } - result = importScope[elementName]; - if (result != null) return result; - if (origin != null) { - result = origin.importScope[elementName]; - if (result != null) return result; - } - return null; - } - - /** Look up a top-level element in this library, but only look for - * non-imported elements. Returns null if no such element exist. */ - Element findLocal(SourceString elementName) { - // TODO(johnniwinther): How to handle injected elements in the patch - // library? - Element result = localScope.lookup(elementName); - if (result == null || result.getLibrary() != this) return null; - return result; - } - - void forEachExport(f(Element element)) { - exports.forEach((Element e) => f(e)); - } - - void forEachLocalMember(f(Element element)) { - if (isPatch) { - // Patch libraries traverse both origin and injected members. - origin.localMembers.forEach(f); - - void filterPatch(Element element) { - if (!element.isPatch) { - // Do not traverse the patch members. - f(element); - } - } - localMembers.forEach(filterPatch); - } else { - localMembers.forEach(f); - } - } - - Iterable<Element> getNonPrivateElementsInScope() { - return localScope.values.where((Element element) { - // At this point [localScope] only contains members so we don't need - // to check for foreign or prefix elements. - return !element.name.isPrivate(); - }); - } - - bool hasLibraryName() => libraryTag != null; - - /** - * Returns the library name (as defined by the #library tag) or for script - * (which have no #library tag) the script file name. The latter case is used - * to private 'library name' for scripts to use for instance in dartdoc. - */ - String getLibraryOrScriptName() { - if (libraryTag != null) { - return libraryTag.name.toString(); - } else { - // Use the file name as script name. - String path = canonicalUri.path; - return path.substring(path.lastIndexOf('/') + 1); - } - } - - Scope buildScope() => new LibraryScope(this); - - bool get isPlatformLibrary => canonicalUri.scheme == "dart"; - - bool get isInternalLibrary => - isPlatformLibrary && canonicalUri.path.startsWith('_'); - - String toString() { - if (origin != null) { - return 'patch library(${getLibraryOrScriptName()})'; - } else if (patch != null) { - return 'origin library(${getLibraryOrScriptName()})'; - } else { - return 'library(${getLibraryOrScriptName()})'; - } - } -} - -class PrefixElementX extends ElementX implements PrefixElement { - Map<SourceString, Element> imported; - Token firstPosition; - - PrefixElementX(SourceString prefix, Element enclosing, this.firstPosition) - : imported = new Map<SourceString, Element>(), - super(prefix, ElementKind.PREFIX, enclosing); - - Element lookupLocalMember(SourceString memberName) => imported[memberName]; - - DartType computeType(Compiler compiler) => compiler.types.dynamicType; - - Token position() => firstPosition; -} - -class TypedefElementX extends ElementX implements TypedefElement { - Typedef cachedNode; - TypedefType cachedType; - - /** - * Canonicalize raw version of [cachedType]. - * - * See [ClassElement.rawType] for motivation. - * - * The [rawType] is computed together with [cachedType] in [computeType]. - */ - TypedefType rawType; - - /** - * The type annotation which defines this typedef. - */ - DartType alias; - - bool isResolved = false; - bool isBeingResolved = false; - - TypedefElementX(SourceString name, Element enclosing) - : super(name, ElementKind.TYPEDEF, enclosing); - - /** - * Function signature for a typedef of a function type. The signature is - * kept to provide full information about parameter names through the mirror - * system. - * - * The [functionSignature] is not available until the typedef element has been - * resolved. - */ - FunctionSignature functionSignature; - - TypedefType computeType(Compiler compiler) { - if (cachedType != null) return cachedType; - Typedef node = parseNode(compiler); - Link<DartType> parameters = - TypeDeclarationElementX.createTypeVariables(this, node.typeParameters); - cachedType = new TypedefType(this, parameters); - if (parameters.isEmpty) { - rawType = cachedType; - } else { - var dynamicParameters = const Link<DartType>(); - parameters.forEach((_) { - dynamicParameters = - dynamicParameters.prepend(compiler.types.dynamicType); - }); - rawType = new TypedefType(this, dynamicParameters); - } - compiler.resolveTypedef(this); - return cachedType; - } - - Link<DartType> get typeVariables => cachedType.typeArguments; - - Scope buildScope() { - return new TypeDeclarationScope(enclosingElement.buildScope(), this); - } -} - -class VariableElementX extends ElementX implements VariableElement { - final VariableListElement variables; - Expression cachedNode; // The send or the identifier in the variables list. - - Modifiers get modifiers => variables.modifiers; - - VariableElementX(SourceString name, - VariableListElement variables, - ElementKind kind, - this.cachedNode) - : this.variables = variables, - super(name, kind, variables.enclosingElement); - - Node parseNode(DiagnosticListener listener) { - if (cachedNode != null) return cachedNode; - VariableDefinitions definitions = variables.parseNode(listener); - for (Link<Node> link = definitions.definitions.nodes; - !link.isEmpty; link = link.tail) { - Expression initializedIdentifier = link.head; - Identifier identifier = initializedIdentifier.asIdentifier(); - if (identifier == null) { - identifier = initializedIdentifier.asSendSet().selector.asIdentifier(); - } - if (identical(name, identifier.source)) { - cachedNode = initializedIdentifier; - return cachedNode; - } - } - listener.cancel('internal error: could not find $name', node: variables); - } - - DartType computeType(Compiler compiler) { - return variables.computeType(compiler); - } - - DartType get type => variables.type; - - bool isInstanceMember() => variables.isInstanceMember(); - - // Note: cachedNode.getBeginToken() will not be correct in all - // cases, for example, for function typed parameters. - Token position() => findMyName(variables.position()); -} - -/** - * Parameters in constructors that directly initialize fields. For example: - * [:A(this.field):]. - */ -class FieldParameterElementX extends VariableElementX - implements FieldParameterElement { - VariableElement fieldElement; - - FieldParameterElementX(SourceString name, - this.fieldElement, - VariableListElement variables, - Node node) - : super(name, variables, ElementKind.FIELD_PARAMETER, node); -} - -// This element represents a list of variable or field declaration. -// It contains the node, and the type. A [VariableElement] always -// references its [VariableListElement]. It forwards its -// [computeType] and [parseNode] methods to this element. -class VariableListElementX extends ElementX implements VariableListElement { - VariableDefinitions cachedNode; - DartType type; - final Modifiers modifiers; - - /** - * Function signature for a variable with a function type. The signature is - * kept to provide full information about parameter names through the mirror - * system. - */ - FunctionSignature functionSignature; - - VariableListElementX(ElementKind kind, - Modifiers this.modifiers, - Element enclosing) - : super(null, kind, enclosing); - - VariableListElementX.node(VariableDefinitions node, - ElementKind kind, - Element enclosing) - : super(null, kind, enclosing), - this.cachedNode = node, - this.modifiers = node.modifiers { - assert(modifiers != null); - } - - VariableDefinitions parseNode(DiagnosticListener listener) { - return cachedNode; - } - - DartType computeType(Compiler compiler) { - if (type != null) return type; - compiler.withCurrentElement(this, () { - VariableDefinitions node = parseNode(compiler); - if (node.type != null) { - type = compiler.resolveTypeAnnotation(this, node.type); - } else { - // Is node.definitions exactly one FunctionExpression? - Link<Node> link = node.definitions.nodes; - if (!link.isEmpty && - link.head.asFunctionExpression() != null && - link.tail.isEmpty) { - FunctionExpression functionExpression = link.head; - // We found exactly one FunctionExpression - functionSignature = - compiler.resolveFunctionExpression(this, functionExpression); - type = compiler.computeFunctionType(compiler.functionClass, - functionSignature); - } else { - type = compiler.types.dynamicType; - } - } - }); - assert(type != null); - return type; - } - - Token position() => cachedNode.getBeginToken(); - - bool isInstanceMember() { - return isMember() && !modifiers.isStatic(); - } -} - -class AbstractFieldElementX extends ElementX implements AbstractFieldElement { - FunctionElement getter; - FunctionElement setter; - - AbstractFieldElementX(SourceString name, Element enclosing) - : super(name, ElementKind.ABSTRACT_FIELD, enclosing); - - DartType computeType(Compiler compiler) { - throw "internal error: AbstractFieldElement has no type"; - } - - Node parseNode(DiagnosticListener listener) { - throw "internal error: AbstractFieldElement has no node"; - } - - position() { - // The getter and setter may be defined in two different - // compilation units. However, we know that one of them is - // non-null and defined in the same compilation unit as the - // abstract element. - // TODO(lrn): No we don't know that if the element from the same - // compilation unit is patched. - // - // We need to make sure that the position returned is relative to - // the compilation unit of the abstract element. - if (getter != null - && identical(getter.getCompilationUnit(), getCompilationUnit())) { - return getter.position(); - } else { - return setter.position(); - } - } - - Modifiers get modifiers { - // The resolver ensures that the flags match (ignoring abstract). - if (getter != null) { - return new Modifiers.withFlags( - getter.modifiers.nodes, - getter.modifiers.flags | Modifiers.FLAG_ABSTRACT); - } else { - return new Modifiers.withFlags( - setter.modifiers.nodes, - setter.modifiers.flags | Modifiers.FLAG_ABSTRACT); - } - } -} - -// TODO(johnniwinther): [FunctionSignature] should be merged with -// [FunctionType]. -class FunctionSignatureX implements FunctionSignature { - final Link<Element> requiredParameters; - final Link<Element> optionalParameters; - final DartType returnType; - final int requiredParameterCount; - final int optionalParameterCount; - final bool optionalParametersAreNamed; - - List<Element> _orderedOptionalParameters; - - FunctionSignatureX(this.requiredParameters, - this.optionalParameters, - this.requiredParameterCount, - this.optionalParameterCount, - this.optionalParametersAreNamed, - this.returnType); - - void forEachRequiredParameter(void function(Element parameter)) { - for (Link<Element> link = requiredParameters; - !link.isEmpty; - link = link.tail) { - function(link.head); - } - } - - void forEachOptionalParameter(void function(Element parameter)) { - for (Link<Element> link = optionalParameters; - !link.isEmpty; - link = link.tail) { - function(link.head); - } - } - - List<Element> get orderedOptionalParameters { - if (_orderedOptionalParameters != null) return _orderedOptionalParameters; - List<Element> list = new List<Element>.from(optionalParameters); - if (optionalParametersAreNamed) { - list.sort((Element a, Element b) { - return a.name.slowToString().compareTo(b.name.slowToString()); - }); - } - _orderedOptionalParameters = list; - return list; - } - - void forEachParameter(void function(Element parameter)) { - forEachRequiredParameter(function); - forEachOptionalParameter(function); - } - - void orderedForEachParameter(void function(Element parameter)) { - forEachRequiredParameter(function); - orderedOptionalParameters.forEach(function); - } - - int get parameterCount => requiredParameterCount + optionalParameterCount; -} - -class FunctionElementX extends ElementX implements FunctionElement { - FunctionExpression cachedNode; - DartType type; - final Modifiers modifiers; - - FunctionSignature functionSignature; - - /** - * A function declaration that should be parsed instead of the current one. - * The patch should be parsed as if it was in the current scope. Its - * signature must match this function's signature. - */ - // TODO(lrn): Consider using [defaultImplementation] to store the patch. - FunctionElement patch = null; - FunctionElement origin = null; - - /** - * If this is a redirecting factory, [defaultImplementation] will be - * changed by the resolver to point to the redirection target. If - * this is an interface constructor, [defaultImplementation] will be - * changed by the resolver to point to the default implementation. - * Otherwise, [:identical(defaultImplementation, this):]. - */ - // TODO(ahe): Rename this field to redirectionTarget and remove - // mention of interface constructors above. - FunctionElement defaultImplementation; - - FunctionElementX(SourceString name, - ElementKind kind, - Modifiers modifiers, - Element enclosing) - : this.tooMuchOverloading(name, null, kind, modifiers, enclosing, null); - - FunctionElementX.node(SourceString name, - FunctionExpression node, - ElementKind kind, - Modifiers modifiers, - Element enclosing) - : this.tooMuchOverloading(name, node, kind, modifiers, enclosing, null); - - FunctionElementX.from(SourceString name, - FunctionElement other, - Element enclosing) - : this.tooMuchOverloading(name, other.cachedNode, other.kind, - other.modifiers, enclosing, - other.functionSignature); - - FunctionElementX.tooMuchOverloading(SourceString name, - FunctionExpression this.cachedNode, - ElementKind kind, - Modifiers this.modifiers, - Element enclosing, - FunctionSignature this.functionSignature) - : super(name, kind, enclosing) { - assert(modifiers != null); - defaultImplementation = this; - } - - bool get isPatched => patch != null; - bool get isPatch => origin != null; - - FunctionElement get redirectionTarget { - if (this == defaultImplementation) return this; - var target = defaultImplementation; - Set<Element> seen = new Set<Element>(); - seen.add(target); - while (!target.isErroneous() && target != target.defaultImplementation) { - target = target.defaultImplementation; - if (seen.contains(target)) { - // TODO(ahe): This is expedient for now, but it should be - // checked by the resolver. Keeping http://dartbug.com/3970 - // open to track this. - throw new SpannableAssertionFailure( - target, 'redirecting factory leads to cycle'); - } - } - return target; - } - - /** - * Applies a patch function to this function. The patch function's body - * is used as replacement when parsing this function's body. - * This method must not be called after the function has been parsed, - * and it must be called at most once. - */ - void setPatch(FunctionElement patchElement) { - // Sanity checks. The caller must check these things before calling. - assert(patch == null); - this.patch = patchElement; - } - - bool isInstanceMember() { - return isMember() - && !isConstructor() - && !modifiers.isStatic(); - } - - FunctionSignature computeSignature(Compiler compiler) { - if (functionSignature != null) return functionSignature; - compiler.withCurrentElement(this, () { - functionSignature = compiler.resolveSignature(this); - }); - return functionSignature; - } - - int requiredParameterCount(Compiler compiler) { - return computeSignature(compiler).requiredParameterCount; - } - - int optionalParameterCount(Compiler compiler) { - return computeSignature(compiler).optionalParameterCount; - } - - int parameterCount(Compiler compiler) { - return computeSignature(compiler).parameterCount; - } - - FunctionType computeType(Compiler compiler) { - if (type != null) return type; - type = compiler.computeFunctionType(declaration, - computeSignature(compiler)); - return type; - } - - FunctionExpression parseNode(DiagnosticListener listener) { - if (patch == null) { - if (modifiers.isExternal()) { - listener.cancel("Compiling external function with no implementation.", - element: this); - } - } - return cachedNode; - } - - Token position() => cachedNode.getBeginToken(); - - FunctionElement asFunctionElement() => this; - - String toString() { - if (isPatch) { - return 'patch ${super.toString()}'; - } else if (isPatched) { - return 'origin ${super.toString()}'; - } else { - return super.toString(); - } - } - - bool isAbstract(Compiler compiler) { - if (super.isAbstract(compiler)) return true; - if (modifiers.isExternal()) return false; - if (isFunction() || isAccessor()) { - return !parseNode(compiler).hasBody(); - } - return false; - } -} - -class ConstructorBodyElementX extends FunctionElementX - implements ConstructorBodyElement { - FunctionElement constructor; - - ConstructorBodyElementX(FunctionElement constructor) - : this.constructor = constructor, - super(constructor.name, - ElementKind.GENERATIVE_CONSTRUCTOR_BODY, - Modifiers.EMPTY, - constructor.enclosingElement) { - functionSignature = constructor.functionSignature; - } - - bool isInstanceMember() => true; - - FunctionType computeType(Compiler compiler) { - compiler.reportFatalError('Internal error: $this.computeType', this); - } - - Node parseNode(DiagnosticListener listener) { - if (cachedNode != null) return cachedNode; - cachedNode = constructor.parseNode(listener); - assert(cachedNode != null); - return cachedNode; - } - - Token position() => constructor.position(); -} - -class SynthesizedConstructorElementX extends FunctionElementX { - SynthesizedConstructorElementX(Element enclosing) - : super(enclosing.name, ElementKind.GENERATIVE_CONSTRUCTOR, - Modifiers.EMPTY, enclosing); - - SynthesizedConstructorElementX.forDefault(Element enclosing, - Compiler compiler) - : super(enclosing.name, ElementKind.GENERATIVE_CONSTRUCTOR, - Modifiers.EMPTY, enclosing) { - type = new FunctionType(this, - compiler.types.voidType, - const Link<DartType>(), - const Link<DartType>(), - const Link<SourceString>(), - const Link<DartType>()); - cachedNode = new FunctionExpression( - new Identifier(enclosing.position()), - new NodeList.empty(), - new Block(new NodeList.empty()), - null, Modifiers.EMPTY, null, null); - } - - bool get isSynthesized => true; - - Token position() => enclosingElement.position(); -} - -class VoidElementX extends ElementX { - VoidElementX(Element enclosing) - : super(const SourceString('void'), ElementKind.VOID, enclosing); - DartType computeType(compiler) => compiler.types.voidType; - Node parseNode(_) { - throw 'internal error: parseNode on void'; - } - bool impliesType() => true; -} - -class TypeDeclarationElementX { - /** - * Creates the type variables, their type and corresponding element, for the - * type variables declared in [parameter] on [element]. The bounds of the type - * variables are not set until [element] has been resolved. - */ - static Link<DartType> createTypeVariables(TypeDeclarationElement element, - NodeList parameters) { - if (parameters == null) return const Link<DartType>(); - - // Create types and elements for type variable. - var arguments = new LinkBuilder<DartType>(); - for (Link link = parameters.nodes; !link.isEmpty; link = link.tail) { - TypeVariable node = link.head; - SourceString variableName = node.name.source; - TypeVariableElement variableElement = - new TypeVariableElementX(variableName, element, node); - TypeVariableType variableType = new TypeVariableType(variableElement); - variableElement.type = variableType; - arguments.addLast(variableType); - } - return arguments.toLink(); - } -} - -abstract class BaseClassElementX extends ElementX implements ClassElement { - final int id; - - /** - * The type of [:this:] for this class declaration. - * - * The type of [:this:] is the interface type based on this element in which - * the type arguments are the declared type variables. For instance, - * [:List<E>:] for [:List:] and [:Map<K,V>:] for [:Map:]. - * - * This type is computed in [computeType]. - */ - InterfaceType thisType; - - /** - * The raw type for this class declaration. - * - * The raw type is the interface type base on this element in which the type - * arguments are all [dynamic]. For instance [:List<dynamic>:] for [:List:] - * and [:Map<dynamic,dynamic>:] for [:Map:]. For non-generic classes [rawType] - * is the same as [thisType]. - * - * The [rawType] field is a canonicalization of the raw type and should be - * used to distinguish explicit and implicit uses of the [dynamic] - * type arguments. For instance should [:List:] be the [rawType] of the - * [:List:] class element whereas [:List<dynamic>:] should be its own - * instantiation of [InterfaceType] with [:dynamic:] as type argument. Using - * this distinction, we can print the raw type with type arguments only when - * the input source has used explicit type arguments. - * - * This type is computed together with [thisType] in [computeType]. - */ - InterfaceType rawType; - DartType supertype; - DartType defaultClass; - Link<DartType> interfaces; - SourceString nativeTagInfo; - int supertypeLoadState; - int resolutionState; - - // backendMembers are members that have been added by the backend to simplify - // compilation. They don't have any user-side counter-part. - Link<Element> backendMembers = const Link<Element>(); - - Link<DartType> allSupertypes; - - BaseClassElementX(SourceString name, - Element enclosing, - this.id, - int initialState) - : supertypeLoadState = initialState, - resolutionState = initialState, - super(name, ElementKind.CLASS, enclosing); - - int get hashCode => id; - ClassElement get patch => super.patch; - ClassElement get origin => super.origin; - ClassElement get declaration => super.declaration; - ClassElement get implementation => super.implementation; - - bool get hasBackendMembers => !backendMembers.isEmpty; - - InterfaceType computeType(Compiler compiler) { - if (thisType == null) { - if (origin == null) { - Link<DartType> parameters = computeTypeParameters(compiler); - thisType = new InterfaceType(this, parameters); - if (parameters.isEmpty) { - rawType = thisType; - } else { - var dynamicParameters = const Link<DartType>(); - parameters.forEach((_) { - dynamicParameters = - dynamicParameters.prepend(compiler.types.dynamicType); - }); - rawType = new InterfaceType(this, dynamicParameters); - } - } else { - thisType = origin.computeType(compiler); - rawType = origin.rawType; - } - } - return thisType; - } - - Link<DartType> computeTypeParameters(Compiler compiler); - - /** - * Return [:true:] if this element is the [:Object:] class for the [compiler]. - */ - bool isObject(Compiler compiler) => - identical(declaration, compiler.objectClass); - - Link<DartType> get typeVariables => thisType.typeArguments; - - ClassElement ensureResolved(Compiler compiler) { - if (resolutionState == STATE_NOT_STARTED) { - compiler.resolver.resolveClass(this); - } - return this; - } - - void addDefaultConstructorIfNeeded(Compiler compiler) { - if (hasConstructor) return; - FunctionElement constructor = - new SynthesizedConstructorElementX.forDefault(this, compiler); - setDefaultConstructor(constructor, compiler); - } - - void setDefaultConstructor(FunctionElement constructor, Compiler compiler); - - void addBackendMember(Element member) { - backendMembers = backendMembers.prepend(member); - } - - void reverseBackendMembers() { - backendMembers = backendMembers.reverse(); - } - - /** - * Lookup local members in the class. This will ignore constructors. - */ - Element lookupLocalMember(SourceString memberName) { - var result = localLookup(memberName); - if (result != null && result.isConstructor()) return null; - return result; - } - - /// Lookup a synthetic element created by the backend. - Element lookupBackendMember(SourceString memberName) { - for (Element element in backendMembers) { - if (element.name == memberName) { - return element; - } - } - } - /** - * Lookup super members for the class. This will ignore constructors. - */ - Element lookupSuperMember(SourceString memberName) { - return lookupSuperMemberInLibrary(memberName, getLibrary()); - } - - /** - * Lookup super members for the class that is accessible in [library]. - * This will ignore constructors. - */ - Element lookupSuperMemberInLibrary(SourceString memberName, - LibraryElement library) { - bool includeInjectedMembers = isPatch; - bool isPrivate = memberName.isPrivate(); - for (ClassElement s = superclass; s != null; s = s.superclass) { - // Private members from a different library are not visible. - if (isPrivate && !identical(library, s.getLibrary())) continue; - s = includeInjectedMembers ? s.implementation : s; - Element e = s.lookupLocalMember(memberName); - if (e == null) continue; - // Static members are not inherited. - if (e.modifiers.isStatic()) continue; - return e; - } - if (isInterface()) { - return lookupSuperInterfaceMember(memberName, getLibrary()); - } - return null; - } - - Element lookupSuperInterfaceMember(SourceString memberName, - LibraryElement fromLibrary) { - bool includeInjectedMembers = isPatch; - bool isPrivate = memberName.isPrivate(); - for (InterfaceType t in interfaces) { - ClassElement cls = t.element; - cls = includeInjectedMembers ? cls.implementation : cls; - Element e = cls.lookupLocalMember(memberName); - if (e == null) continue; - // Private members from a different library are not visible. - if (isPrivate && !identical(fromLibrary, e.getLibrary())) continue; - // Static members are not inherited. - if (e.modifiers.isStatic()) continue; - return e; - } - return null; - } - - /** - * Find the first member in the class chain with the given [selector]. - * - * This method is NOT to be used for resolving - * unqualified sends because it does not implement the scoping - * rules, where library scope comes before superclass scope. - * - * When called on the implementation element both members declared in the - * origin and the patch class are returned. - */ - Element lookupSelector(Selector selector) { - SourceString memberName = selector.name; - LibraryElement library = selector.library; - Element localMember = lookupLocalMember(memberName); - if (localMember != null && - (!memberName.isPrivate() || getLibrary() == library)) { - return localMember; - } - return lookupSuperMemberInLibrary(memberName, library); - } - - /** - * Find the first member in the class chain with the given - * [memberName]. This method is NOT to be used for resolving - * unqualified sends because it does not implement the scoping - * rules, where library scope comes before superclass scope. - */ - Element lookupMember(SourceString memberName) { - Element localMember = lookupLocalMember(memberName); - return localMember == null ? lookupSuperMember(memberName) : localMember; - } - - /** - * Returns true if the [fieldMember] is shadowed by another field. The given - * [fieldMember] must be a member of this class. - * - * This method also works if the [fieldMember] is private. - */ - bool isShadowedByField(Element fieldMember) { - assert(fieldMember.isField()); - // Note that we cannot use [lookupMember] or [lookupSuperMember] since it - // will not do the right thing for private elements. - ClassElement lookupClass = this; - LibraryElement memberLibrary = fieldMember.getLibrary(); - if (fieldMember.name.isPrivate()) { - // We find a super class in the same library as the field. This way the - // lookupMember will work. - while (lookupClass.getLibrary() != memberLibrary) { - lookupClass = lookupClass.superclass; - } - } - SourceString fieldName = fieldMember.name; - while (true) { - Element foundMember = lookupClass.lookupMember(fieldName); - if (foundMember == fieldMember) return false; - if (foundMember.isField()) return true; - lookupClass = foundMember.getEnclosingClass().superclass; - } - } - - Element validateConstructorLookupResults(Selector selector, - Element result, - Element noMatch(Element)) { - if (result == null - || !result.isConstructor() - || (selector.name.isPrivate() - && result.getLibrary() != selector.library)) { - result = noMatch != null ? noMatch(result) : null; - } - return result; - } - - // TODO(aprelev@gmail.com): Peter believes that it would be great to - // make noMatch a required argument. Peter's suspicion is that most - // callers of this method would benefit from using the noMatch method. - Element lookupConstructor(Selector selector, [Element noMatch(Element)]) { - SourceString normalizedName; - SourceString className = this.name; - SourceString constructorName = selector.name; - if (constructorName != const SourceString('')) { - normalizedName = Elements.constructConstructorName(className, - constructorName); - } else { - normalizedName = className; - } - Element result = localLookup(normalizedName); - return validateConstructorLookupResults(selector, result, noMatch); - } - - Element lookupFactoryConstructor(Selector selector, - [Element noMatch(Element)]) { - SourceString constructorName = selector.name; - Element result = localLookup(constructorName); - return validateConstructorLookupResults(selector, result, noMatch); - } - - Link<Element> get constructors { - // TODO(ajohnsen): See if we can avoid this method at some point. - Link<Element> result = const Link<Element>(); - // TODO(johnniwinther): Should we include injected constructors? - forEachMember((_, Element member) { - if (member.isConstructor()) result = result.prepend(member); - }); - return result; - } - - /** - * Returns the super class, if any. - * - * The returned element may not be resolved yet. - */ - ClassElement get superclass { - assert(supertypeLoadState == STATE_DONE); - return supertype == null ? null : supertype.element; - } - - /** - * Runs through all members of this class. - * - * The enclosing class is passed to the callback. This is useful when - * [includeSuperMembers] is [:true:]. - * - * When called on an implementation element both the members in the origin - * and patch class are included. - */ - // TODO(johnniwinther): Clean up lookup to get rid of the include predicates. - void forEachMember(void f(ClassElement enclosingClass, Element member), - {includeBackendMembers: false, - includeSuperMembers: false}) { - bool includeInjectedMembers = isPatch; - Set<ClassElement> seen = new Set<ClassElement>(); - ClassElement classElement = declaration; - do { - if (seen.contains(classElement)) return; - seen.add(classElement); - - // Iterate through the members in textual order, which requires - // to reverse the data structure [localMembers] we created. - // Textual order may be important for certain operations, for - // example when emitting the initializers of fields. - classElement.forEachLocalMember((e) => f(classElement, e)); - if (includeBackendMembers) { - classElement.forEachBackendMember((e) => f(classElement, e)); - } - if (includeInjectedMembers) { - if (classElement.patch != null) { - classElement.patch.forEachLocalMember((e) { - if (!e.isPatch) f(classElement, e); - }); - } - } - classElement = includeSuperMembers ? classElement.superclass : null; - } while(classElement != null); - } - - /** - * Runs through all instance-field members of this class. - * - * The enclosing class is passed to the callback. This is useful when - * [includeSuperMembers] is [:true:]. - * - * When [includeBackendMembers] and [includeSuperMembers] are both [:true:] - * then the fields are visited in the same order as they need to be given - * to the JavaScript constructor. - * - * When called on the implementation element both the fields declared in the - * origin and in the patch are included. - */ - void forEachInstanceField(void f(ClassElement enclosingClass, Element field), - {includeBackendMembers: false, - includeSuperMembers: false}) { - // Filters so that [f] is only invoked with instance fields. - void fieldFilter(ClassElement enclosingClass, Element member) { - if (member.isInstanceMember() && member.kind == ElementKind.FIELD) { - f(enclosingClass, member); - } - } - - forEachMember(fieldFilter, - includeBackendMembers: includeBackendMembers, - includeSuperMembers: includeSuperMembers); - } - - void forEachBackendMember(void f(Element member)) { - backendMembers.forEach(f); - } - - bool implementsInterface(ClassElement intrface) { - for (DartType implementedInterfaceType in allSupertypes) { - ClassElement implementedInterface = implementedInterfaceType.element; - if (identical(implementedInterface, intrface)) { - return true; - } - } - return false; - } - - /** - * Returns true if [this] is a subclass of [cls]. - * - * This method is not to be used for checking type hierarchy and - * assignments, because it does not take parameterized types into - * account. - */ - bool isSubclassOf(ClassElement cls) { - // Use [declaration] for both [this] and [cls], because - // declaration classes hold the superclass hierarchy. - cls = cls.declaration; - for (ClassElement s = declaration; s != null; s = s.superclass) { - if (identical(s, cls)) return true; - } - return false; - } - - bool isInterface() => false; - bool isNative() => nativeTagInfo != null; - void setNative(String name) { - nativeTagInfo = new SourceString(name); - } -} - -abstract class ClassElementX extends BaseClassElementX { - // Lazily applied patch of class members. - ClassElement patch = null; - ClassElement origin = null; - - Link<Element> localMembers = const Link<Element>(); - final ScopeX localScope = new ScopeX(); - - ClassElementX(SourceString name, Element enclosing, int id, int initialState) - : super(name, enclosing, id, initialState); - - ClassNode parseNode(Compiler compiler); - - bool get isMixinApplication => false; - bool get isPatched => patch != null; - bool get isPatch => origin != null; - bool get hasLocalScopeMembers => !localScope.isEmpty; - - void addMember(Element element, DiagnosticListener listener) { - localMembers = localMembers.prepend(element); - addToScope(element, listener); - } - - void addToScope(Element element, DiagnosticListener listener) { - localScope.add(element, listener); - } - - Element localLookup(SourceString elementName) { - Element result = localScope.lookup(elementName); - if (result == null && isPatch) { - result = origin.localLookup(elementName); - } - return result; - } - - void forEachLocalMember(void f(Element member)) { - localMembers.reverse().forEach(f); - } - - bool get hasConstructor { - // Search in scope to be sure we search patched constructors. - for (var element in localScope.values) { - if (element.isConstructor()) return true; - } - return false; - } - - void setDefaultConstructor(FunctionElement constructor, Compiler compiler) { - addToScope(constructor, compiler); - } - - Link<DartType> computeTypeParameters(Compiler compiler) { - ClassNode node = parseNode(compiler); - return TypeDeclarationElementX.createTypeVariables( - this, node.typeParameters); - } - - Scope buildScope() => new ClassScope(enclosingElement.buildScope(), this); - - String toString() { - if (origin != null) { - return 'patch ${super.toString()}'; - } else if (patch != null) { - return 'origin ${super.toString()}'; - } else { - return super.toString(); - } - } -} - -class MixinApplicationElementX extends BaseClassElementX - implements MixinApplicationElement { - final Node node; - final Modifiers modifiers; - - FunctionElement constructor; - ClassElement mixin; - - // TODO(kasperl): The analyzer complains when I don't have these two - // fields. This is pretty weird. I cannot replace them with getters. - final ClassElement patch = null; - final ClassElement origin = null; - - MixinApplicationElementX(SourceString name, Element enclosing, int id, - this.node, this.modifiers) - : super(name, enclosing, id, STATE_NOT_STARTED); - - bool get isMixinApplication => true; - bool get hasConstructor => constructor != null; - bool get hasLocalScopeMembers => false; - - Token position() => node.getBeginToken(); - - Node parseNode(DiagnosticListener listener) => node; - - Element localLookup(SourceString name) { - if (this.name == name) return constructor; - if (mixin == null) return null; - Element mixedInElement = mixin.localLookup(name); - if (mixedInElement == null) return null; - return mixedInElement.isInstanceMember() ? mixedInElement : null; - } - - void forEachLocalMember(void f(Element member)) { - if (mixin != null) mixin.forEachLocalMember((Element mixedInElement) { - if (mixedInElement.isInstanceMember()) f(mixedInElement); - }); - } - - void addMember(Element element, DiagnosticListener listener) { - throw new UnsupportedError("cannot add member to $this"); - } - - void addToScope(Element element, DiagnosticListener listener) { - throw new UnsupportedError("cannot add to scope of $this"); - } - - void setDefaultConstructor(FunctionElement constructor, Compiler compiler) { - assert(!hasConstructor); - this.constructor = constructor; - } - - Link<DartType> computeTypeParameters(Compiler compiler) { - NamedMixinApplication named = node.asNamedMixinApplication(); - if (named == null) return const Link<DartType>(); - return TypeDeclarationElementX.createTypeVariables( - this, named.typeParameters); - } -} - -class LabelElementX extends ElementX implements LabelElement { - - // We store the original label here so it can be returned by [parseNode]. - final Label label; - final String labelName; - final TargetElement target; - bool isBreakTarget = false; - bool isContinueTarget = false; - LabelElementX(Label label, String labelName, this.target, - Element enclosingElement) - : this.label = label, - this.labelName = labelName, - // In case of a synthetic label, just use [labelName] for - // identifying the element. - super(label == null - ? new SourceString(labelName) - : label.identifier.source, - ElementKind.LABEL, - enclosingElement); - - void setBreakTarget() { - isBreakTarget = true; - target.isBreakTarget = true; - } - void setContinueTarget() { - isContinueTarget = true; - target.isContinueTarget = true; - } - - bool get isTarget => isBreakTarget || isContinueTarget; - Node parseNode(DiagnosticListener l) => label; - - Token position() => label.getBeginToken(); - String toString() => "${labelName}:"; -} - -// Represents a reference to a statement or switch-case, either by label or the -// default target of a break or continue. -class TargetElementX extends ElementX implements TargetElement { - final Node statement; - final int nestingLevel; - Link<LabelElement> labels = const Link<LabelElement>(); - bool isBreakTarget = false; - bool isContinueTarget = false; - - TargetElementX(this.statement, this.nestingLevel, Element enclosingElement) - : super(const SourceString(""), ElementKind.STATEMENT, enclosingElement); - bool get isTarget => isBreakTarget || isContinueTarget; - - LabelElement addLabel(Label label, String labelName) { - LabelElement result = new LabelElementX(label, labelName, this, - enclosingElement); - labels = labels.prepend(result); - return result; - } - - Node parseNode(DiagnosticListener l) => statement; - - bool get isSwitch => statement is SwitchStatement; - - Token position() => statement.getBeginToken(); - String toString() => statement.toString(); -} - -class TypeVariableElementX extends ElementX implements TypeVariableElement { - final Node cachedNode; - TypeVariableType type; - DartType bound; - - TypeVariableElementX(name, Element enclosing, this.cachedNode, - [this.type, this.bound]) - : super(name, ElementKind.TYPE_VARIABLE, enclosing); - - TypeVariableType computeType(compiler) => type; - - Node parseNode(compiler) => cachedNode; - - String toString() => "${enclosingElement.toString()}.${name.slowToString()}"; - - Token position() => cachedNode.getBeginToken(); -} - -/** - * A single metadata annotation. - * - * For example, consider: - * - * [: - * class Data { - * const Data(); - * } - * - * const data = const Data(); - * - * @data - * class Foo {} - * - * @data @data - * class Bar {} - * :] - * - * In this example, there are three instances of [MetadataAnnotation] - * and they correspond each to a location in the source code where - * there is an at-sign, '@'. The [value] of each of these instances - * are the same compile-time constant, [: const Data() :]. - * - * The mirror system does not have a concept matching this class. - */ -abstract class MetadataAnnotationX implements MetadataAnnotation { - /** - * The compile-time constant which this annotation resolves to. - * In the mirror system, this would be an object mirror. - */ - Constant get value; - Element annotatedElement; - int resolutionState; - - /** - * The beginning token of this annotation, or [:null:] if it is synthetic. - */ - Token get beginToken; - - MetadataAnnotationX([this.resolutionState = STATE_NOT_STARTED]); - - MetadataAnnotation ensureResolved(Compiler compiler) { - if (resolutionState == STATE_NOT_STARTED) { - compiler.resolver.resolveMetadataAnnotation(this); - } - return this; - } - - String toString() => 'MetadataAnnotation($value, $resolutionState)'; -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/enqueue.dart b/pkgs/markdown/test/lib/src/compiler/implementation/enqueue.dart deleted file mode 100644 index 4a4fea8..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/enqueue.dart +++ /dev/null
@@ -1,552 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of dart2js; - -class EnqueueTask extends CompilerTask { - final ResolutionEnqueuer resolution; - final CodegenEnqueuer codegen; - - String get name => 'Enqueue'; - - EnqueueTask(Compiler compiler) - : resolution = new ResolutionEnqueuer( - compiler, compiler.backend.createItemCompilationContext), - codegen = new CodegenEnqueuer( - compiler, compiler.backend.createItemCompilationContext), - super(compiler) { - codegen.task = this; - resolution.task = this; - - codegen.nativeEnqueuer = compiler.backend.nativeCodegenEnqueuer(codegen); - resolution.nativeEnqueuer = - compiler.backend.nativeResolutionEnqueuer(resolution); - } -} - -abstract class Enqueuer { - final String name; - final Compiler compiler; // TODO(ahe): Remove this dependency. - final Function itemCompilationContextCreator; - final Map<String, Link<Element>> instanceMembersByName; - final Set<ClassElement> seenClasses; - final Universe universe; - - bool queueIsClosed = false; - EnqueueTask task; - native.NativeEnqueuer nativeEnqueuer; // Set by EnqueueTask - - Enqueuer(this.name, this.compiler, - ItemCompilationContext itemCompilationContextCreator()) - : this.itemCompilationContextCreator = itemCompilationContextCreator, - instanceMembersByName = new Map<String, Link<Element>>(), - universe = new Universe(), - seenClasses = new Set<ClassElement>(); - - /// Returns [:true:] if this enqueuer is the resolution enqueuer. - bool get isResolutionQueue => false; - - /// Returns [:true:] if [member] has been processed by this enqueuer. - bool isProcessed(Element member); - - /** - * Documentation wanted -- johnniwinther - * - * Invariant: [element] must be a declaration element. - */ - void addToWorkList(Element element, [TreeElements elements]) { - assert(invariant(element, element.isDeclaration)); - if (element.isForeign(compiler)) return; - - if (!addElementToWorkList(element, elements)) return; - - // Enable runtime type support if we discover a getter called runtimeType. - // We have to enable runtime type before hitting the codegen, so - // that constructors know whether they need to generate code for - // runtime type. - if (element.isGetter() && element.name == Compiler.RUNTIME_TYPE) { - compiler.enabledRuntimeType = true; - } else if (element == compiler.functionApplyMethod) { - compiler.enabledFunctionApply = true; - } else if (element == compiler.invokeOnMethod) { - compiler.enabledInvokeOn = true; - } - - nativeEnqueuer.registerElement(element); - } - - /** - * Adds [element] to the work list if it has not already been processed. - * - * Returns [:true:] if the [element] should be processed. - */ - // TODO(johnniwinther): Change to 'Returns true if the element was added to - // the work list'? - bool addElementToWorkList(Element element, [TreeElements elements]); - - void registerInstantiatedClass(ClassElement cls) { - if (universe.instantiatedClasses.contains(cls)) return; - if (!cls.isAbstract(compiler)) { - universe.instantiatedClasses.add(cls); - onRegisterInstantiatedClass(cls); - } - compiler.backend.registerInstantiatedClass(cls, this); - } - - bool checkNoEnqueuedInvokedInstanceMethods() { - task.measure(() { - // Run through the classes and see if we need to compile methods. - for (ClassElement classElement in universe.instantiatedClasses) { - for (ClassElement currentClass = classElement; - currentClass != null; - currentClass = currentClass.superclass) { - processInstantiatedClass(currentClass); - } - } - }); - return true; - } - - void processInstantiatedClass(ClassElement cls) { - cls.implementation.forEachMember(processInstantiatedClassMember); - } - - /** - * Documentation wanted -- johnniwinther - */ - void processInstantiatedClassMember(ClassElement cls, Element member) { - assert(invariant(member, member.isDeclaration)); - if (isProcessed(member)) return; - if (!member.isInstanceMember()) return; - if (member.isField()) { - // Native fields need to go into instanceMembersByName as they are virtual - // instantiation points and escape points. - // Test the enclosing class, since the metadata has not been parsed yet. - if (!member.enclosingElement.isNative()) return; - } - - String memberName = member.name.slowToString(); - Link<Element> members = instanceMembersByName.putIfAbsent( - memberName, () => const Link<Element>()); - instanceMembersByName[memberName] = members.prepend(member); - - if (member.kind == ElementKind.FUNCTION) { - if (member.name == Compiler.NO_SUCH_METHOD) { - enableNoSuchMethod(member); - } - if (universe.hasInvocation(member, compiler)) { - return addToWorkList(member); - } - // If there is a property access with the same name as a method we - // need to emit the method. - if (universe.hasInvokedGetter(member, compiler)) { - // We will emit a closure, so make sure the closure class is - // generated. - compiler.closureClass.ensureResolved(compiler); - registerInstantiatedClass(compiler.closureClass); - return addToWorkList(member); - } - } else if (member.kind == ElementKind.GETTER) { - if (universe.hasInvokedGetter(member, compiler)) { - return addToWorkList(member); - } - // We don't know what selectors the returned closure accepts. If - // the set contains any selector we have to assume that it matches. - if (universe.hasInvocation(member, compiler)) { - return addToWorkList(member); - } - } else if (member.kind == ElementKind.SETTER) { - if (universe.hasInvokedSetter(member, compiler)) { - return addToWorkList(member); - } - } else if (member.kind == ElementKind.FIELD && - member.enclosingElement.isNative()) { - nativeEnqueuer.handleFieldAnnotations(member); - if (universe.hasInvokedGetter(member, compiler) || - universe.hasInvocation(member, compiler)) { - nativeEnqueuer.registerFieldLoad(member); - // In handleUnseenSelector we can't tell if the field is loaded or - // stored. We need the basic algorithm to be Church-Rosser, since the - // resolution 'reduction' order is different to the codegen order. So - // register that the field is also stored. In other words: if we don't - // register the store here during resolution, the store could be - // registered during codegen on the handleUnseenSelector path, and cause - // the set of codegen elements to include unresolved elements. - nativeEnqueuer.registerFieldStore(member); - } - if (universe.hasInvokedSetter(member, compiler)) { - nativeEnqueuer.registerFieldStore(member); - // See comment after registerFieldLoad above. - nativeEnqueuer.registerFieldLoad(member); - } - } - } - - void enableNoSuchMethod(Element element) {} - - void onRegisterInstantiatedClass(ClassElement cls) { - task.measure(() { - // The class must be resolved to compute the set of all - // supertypes. - cls.ensureResolved(compiler); - - void processClass(ClassElement cls) { - if (seenClasses.contains(cls)) return; - - seenClasses.add(cls); - cls.ensureResolved(compiler); - cls.implementation.forEachMember(processInstantiatedClassMember); - if (isResolutionQueue) { - compiler.resolver.checkClass(cls); - } - - if (compiler.enableTypeAssertions) { - // We need to register is checks and helpers for checking - // assignments to fields. - // TODO(ngeoffray): This should really move to the backend. - cls.forEachLocalMember((Element member) { - if (!member.isInstanceMember() || !member.isField()) return; - DartType type = member.computeType(compiler); - registerIsCheck(type); - SourceString helper = compiler.backend.getCheckedModeHelper(type); - if (helper != null) { - Element helperElement = compiler.findHelper(helper); - registerStaticUse(helperElement); - } - }); - } - } - processClass(cls); - for (Link<DartType> supertypes = cls.allSupertypes; - !supertypes.isEmpty; supertypes = supertypes.tail) { - processClass(supertypes.head.element); - } - }); - } - - void registerNewSelector(SourceString name, - Selector selector, - Map<SourceString, Set<Selector>> selectorsMap) { - if (name != selector.name) { - String message = "$name != ${selector.name} (${selector.kind})"; - compiler.internalError("Wrong selector name: $message."); - } - Set<Selector> selectors = - selectorsMap.putIfAbsent(name, () => new Set<Selector>()); - if (!selectors.contains(selector)) { - selectors.add(selector); - handleUnseenSelector(name, selector); - } - } - - void registerInvocation(SourceString methodName, Selector selector) { - task.measure(() { - registerNewSelector(methodName, selector, universe.invokedNames); - }); - } - - void registerInvokedGetter(SourceString getterName, Selector selector) { - task.measure(() { - registerNewSelector(getterName, selector, universe.invokedGetters); - }); - } - - void registerInvokedSetter(SourceString setterName, Selector selector) { - task.measure(() { - registerNewSelector(setterName, selector, universe.invokedSetters); - }); - } - - processInstanceMembers(SourceString n, bool f(Element e)) { - String memberName = n.slowToString(); - Link<Element> members = instanceMembersByName[memberName]; - if (members != null) { - LinkBuilder<Element> remaining = new LinkBuilder<Element>(); - for (; !members.isEmpty; members = members.tail) { - if (!f(members.head)) remaining.addLast(members.head); - } - instanceMembersByName[memberName] = remaining.toLink(); - } - } - - void handleUnseenSelector(SourceString methodName, Selector selector) { - processInstanceMembers(methodName, (Element member) { - if (selector.appliesUnnamed(member, compiler)) { - if (member.isField() && member.enclosingElement.isNative()) { - if (selector.isGetter() || selector.isCall()) { - nativeEnqueuer.registerFieldLoad(member); - // We have to also handle storing to the field because we only get - // one look at each member and there might be a store we have not - // seen yet. - // TODO(sra): Process fields for storing separately. - nativeEnqueuer.registerFieldStore(member); - } else { - nativeEnqueuer.registerFieldStore(member); - // We have to also handle loading from the field because we only get - // one look at each member and there might be a load we have not - // seen yet. - // TODO(sra): Process fields for storing separately. - nativeEnqueuer.registerFieldLoad(member); - } - } else { - addToWorkList(member); - } - return true; - } - return false; - }); - } - - /** - * Documentation wanted -- johnniwinther - * - * Invariant: [element] must be a declaration element. - */ - void registerStaticUse(Element element) { - if (element == null) return; - assert(invariant(element, element.isDeclaration)); - addToWorkList(element); - } - - void registerGetOfStaticFunction(FunctionElement element) { - registerStaticUse(element); - universe.staticFunctionsNeedingGetter.add(element); - } - - void registerDynamicInvocation(SourceString methodName, Selector selector) { - assert(selector != null); - registerInvocation(methodName, selector); - } - - void registerDynamicInvocationOf(Element element, Selector selector) { - assert(selector.isCall() - || selector.isOperator() - || selector.isIndex() - || selector.isIndexSet()); - if (element.isFunction()) { - addToWorkList(element); - } else if (element.isAbstractField()) { - AbstractFieldElement field = element; - // Since the invocation is a dynamic call on a getter, we only - // need to schedule the getter on the work list. - addToWorkList(field.getter); - } else { - assert(element.isField()); - } - // We also need to add the selector to the invoked names map, - // because the emitter uses that map to generate parameter stubs. - Set<Selector> selectors = universe.invokedNames.putIfAbsent( - element.name, () => new Set<Selector>()); - selectors.add(selector); - } - - void registerDynamicGetter(SourceString methodName, Selector selector) { - registerInvokedGetter(methodName, selector); - } - - void registerDynamicSetter(SourceString methodName, Selector selector) { - registerInvokedSetter(methodName, selector); - } - - void registerFieldGetter(SourceString getterName, - LibraryElement library, - DartType type) { - task.measure(() { - Selector getter = new Selector.getter(getterName, library); - registerNewSelector(getterName, - new TypedSelector(type, getter), - universe.fieldGetters); - }); - } - - void registerFieldSetter(SourceString setterName, - LibraryElement library, - DartType type) { - task.measure(() { - Selector setter = new Selector.setter(setterName, library); - registerNewSelector(setterName, - new TypedSelector(type, setter), - universe.fieldSetters); - }); - } - - void registerIsCheck(DartType type) { - universe.isChecks.add(type); - } - - void forEach(f(WorkItem work)); - - void logSummary(log(message)) { - _logSpecificSummary(log); - nativeEnqueuer.logSummary(log); - } - - /// Log summary specific to the concrete enqueuer. - void _logSpecificSummary(log(message)); - - String toString() => 'Enqueuer($name)'; -} - -/// [Enqueuer] which is specific to resolution. -class ResolutionEnqueuer extends Enqueuer { - /** - * Map from declaration elements to the [TreeElements] object holding the - * resolution mapping for the element implementation. - * - * Invariant: Key elements are declaration elements. - */ - final Map<Element, TreeElements> resolvedElements; - - final Queue<ResolutionWorkItem> queue; - - ResolutionEnqueuer(Compiler compiler, - ItemCompilationContext itemCompilationContextCreator()) - : super('resolution enqueuer', compiler, itemCompilationContextCreator), - resolvedElements = new Map<Element, TreeElements>(), - queue = new Queue<ResolutionWorkItem>(); - - bool get isResolutionQueue => true; - - bool isProcessed(Element member) => resolvedElements.containsKey(member); - - TreeElements getCachedElements(Element element) { - // TODO(ngeoffray): Get rid of this check. - if (element.enclosingElement.isClosure()) { - closureMapping.ClosureClassElement cls = element.enclosingElement; - element = cls.methodElement; - } - Element owner = element.getOutermostEnclosingMemberOrTopLevel(); - return resolvedElements[owner.declaration]; - } - - /** - * Sets the resolved elements of [element] to [elements], or if [elements] is - * [:null:], to the elements found through [getCachedElements]. - * - * Returns the resolved elements. - */ - TreeElements ensureCachedElements(Element element, TreeElements elements) { - if (elements == null) { - elements = getCachedElements(element); - } - resolvedElements[element] = elements; - return elements; - } - - bool addElementToWorkList(Element element, [TreeElements elements]) { - if (queueIsClosed) { - if (getCachedElements(element) != null) return false; - throw new SpannableAssertionFailure(element, - "Resolution work list is closed."); - } - if (elements == null) { - elements = getCachedElements(element); - } - compiler.world.registerUsedElement(element); - - if (elements == null) { - queue.add( - new ResolutionWorkItem(element, itemCompilationContextCreator())); - } - - // Enable isolate support if we start using something from the - // isolate library, or timers for the async library. - LibraryElement library = element.getLibrary(); - if (!compiler.hasIsolateSupport()) { - String uri = library.canonicalUri.toString(); - if (uri == 'dart:isolate') { - enableIsolateSupport(library); - } else if (uri == 'dart:async') { - ClassElement cls = element.getEnclosingClass(); - if (cls != null && cls.name == const SourceString('Timer')) { - // The [:Timer:] class uses the event queue of the isolate - // library, so we make sure that event queue is generated. - enableIsolateSupport(library); - } - } - } - - return true; - } - - void enableIsolateSupport(LibraryElement element) { - compiler.isolateLibrary = element.patch; - addToWorkList( - compiler.isolateHelperLibrary.find(Compiler.START_ROOT_ISOLATE)); - addToWorkList(compiler.isolateHelperLibrary.find( - const SourceString('_currentIsolate'))); - addToWorkList(compiler.isolateHelperLibrary.find( - const SourceString('_callInIsolate'))); - } - - void enableNoSuchMethod(Element element) { - if (compiler.enabledNoSuchMethod) return; - Selector selector = new Selector.noSuchMethod(); - if (identical(element.getEnclosingClass(), compiler.objectClass)) { - registerDynamicInvocationOf(element, selector); - return; - } - compiler.enabledNoSuchMethod = true; - registerInvocation(Compiler.NO_SUCH_METHOD, selector); - - compiler.createInvocationMirrorElement = - compiler.findHelper(Compiler.CREATE_INVOCATION_MIRROR); - addToWorkList(compiler.createInvocationMirrorElement); - } - - void forEach(f(WorkItem work)) { - while (!queue.isEmpty) { - // TODO(johnniwinther): Find an optimal process order for resolution. - f(queue.removeLast()); - } - } - - void registerJsCall(Send node, ResolverVisitor resolver) { - nativeEnqueuer.registerJsCall(node, resolver); - } - - void _logSpecificSummary(log(message)) { - log('Resolved ${resolvedElements.length} elements.'); - } -} - -/// [Enqueuer] which is specific to code generation. -class CodegenEnqueuer extends Enqueuer { - final Queue<CodegenWorkItem> queue; - final Map<Element, js.Expression> generatedCode = - new Map<Element, js.Expression>(); - - CodegenEnqueuer(Compiler compiler, - ItemCompilationContext itemCompilationContextCreator()) - : super('codegen enqueuer', compiler, itemCompilationContextCreator), - queue = new Queue<CodegenWorkItem>(); - - bool isProcessed(Element member) => generatedCode.containsKey(member); - - bool addElementToWorkList(Element element, [TreeElements elements]) { - if (queueIsClosed) { - throw new SpannableAssertionFailure(element, - "Codegen work list is closed."); - } - elements = - compiler.enqueuer.resolution.ensureCachedElements(element, elements); - - CodegenWorkItem workItem = new CodegenWorkItem( - element, elements, itemCompilationContextCreator()); - queue.add(workItem); - - return true; - } - - void forEach(f(WorkItem work)) { - while(!queue.isEmpty) { - // TODO(johnniwinther): Find an optimal process order for codegen. - f(queue.removeLast()); - } - } - - void _logSpecificSummary(log(message)) { - log('Compiled ${generatedCode.length} methods.'); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/filenames.dart b/pkgs/markdown/test/lib/src/compiler/implementation/filenames.dart deleted file mode 100644 index 198a28f..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/filenames.dart +++ /dev/null
@@ -1,29 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library filenames; - -import 'dart:io'; -import 'dart:uri'; - -// TODO(ahe): This library should be replaced by a general -// path-munging library. -// -// See also: -// http://blogs.msdn.com/b/ie/archive/2006/12/06/file-uris-in-windows.aspx - -String nativeToUriPath(String filename) { - return new Path(filename).toString(); -} - -String uriPathToNative(String path) { - return new Path(path).toNativePath(); -} - -Uri getCurrentDirectory() { - final String dir = nativeToUriPath(new File('.').fullPathSync()); - return new Uri.fromComponents(scheme: 'file', path: appendSlash(dir)); -} - -String appendSlash(String path) => path.endsWith('/') ? path : '$path/';
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/js/js.dart b/pkgs/markdown/test/lib/src/compiler/implementation/js/js.dart deleted file mode 100644 index b7df642..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/js/js.dart +++ /dev/null
@@ -1,15 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library js; - -import 'precedence.dart'; -import '../util/characters.dart' as charCodes; - -// TODO(floitsch): remove this dependency (currently necessary for the -// CodeBuffer). -import '../dart2jslib.dart' as leg; - -part 'nodes.dart'; -part 'printer.dart';
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/js/nodes.dart b/pkgs/markdown/test/lib/src/compiler/implementation/js/nodes.dart deleted file mode 100644 index da8cd44..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/js/nodes.dart +++ /dev/null
@@ -1,906 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of js; - -abstract class NodeVisitor<T> { - T visitProgram(Program node); - - T visitBlock(Block node); - T visitExpressionStatement(ExpressionStatement node); - T visitEmptyStatement(EmptyStatement node); - T visitIf(If node); - T visitFor(For node); - T visitForIn(ForIn node); - T visitWhile(While node); - T visitDo(Do node); - T visitContinue(Continue node); - T visitBreak(Break node); - T visitReturn(Return node); - T visitThrow(Throw node); - T visitTry(Try node); - T visitCatch(Catch node); - T visitSwitch(Switch node); - T visitCase(Case node); - T visitDefault(Default node); - T visitFunctionDeclaration(FunctionDeclaration node); - T visitLabeledStatement(LabeledStatement node); - T visitLiteralStatement(LiteralStatement node); - - T visitLiteralExpression(LiteralExpression node); - T visitVariableDeclarationList(VariableDeclarationList node); - T visitSequence(Sequence node); - T visitAssignment(Assignment node); - T visitVariableInitialization(VariableInitialization node); - T visitConditional(Conditional cond); - T visitNew(New node); - T visitCall(Call node); - T visitBinary(Binary node); - T visitPrefix(Prefix node); - T visitPostfix(Postfix node); - - T visitVariableUse(VariableUse node); - T visitThis(This node); - T visitVariableDeclaration(VariableDeclaration node); - T visitParameter(Parameter node); - T visitAccess(PropertyAccess node); - - T visitNamedFunction(NamedFunction node); - T visitFun(Fun node); - - T visitLiteralBool(LiteralBool node); - T visitLiteralString(LiteralString node); - T visitLiteralNumber(LiteralNumber node); - T visitLiteralNull(LiteralNull node); - - T visitArrayInitializer(ArrayInitializer node); - T visitArrayElement(ArrayElement node); - T visitObjectInitializer(ObjectInitializer node); - T visitProperty(Property node); - T visitRegExpLiteral(RegExpLiteral node); -} - -class BaseVisitor<T> implements NodeVisitor<T> { - T visitNode(Node node) { - node.visitChildren(this); - return null; - } - - T visitProgram(Program node) => visitNode(node); - - T visitStatement(Statement node) => visitNode(node); - T visitLoop(Loop node) => visitStatement(node); - T visitJump(Statement node) => visitStatement(node); - - T visitBlock(Block node) => visitStatement(node); - T visitExpressionStatement(ExpressionStatement node) - => visitStatement(node); - T visitEmptyStatement(EmptyStatement node) => visitStatement(node); - T visitIf(If node) => visitStatement(node); - T visitFor(For node) => visitLoop(node); - T visitForIn(ForIn node) => visitLoop(node); - T visitWhile(While node) => visitLoop(node); - T visitDo(Do node) => visitLoop(node); - T visitContinue(Continue node) => visitJump(node); - T visitBreak(Break node) => visitJump(node); - T visitReturn(Return node) => visitJump(node); - T visitThrow(Throw node) => visitJump(node); - T visitTry(Try node) => visitStatement(node); - T visitSwitch(Switch node) => visitStatement(node); - T visitFunctionDeclaration(FunctionDeclaration node) - => visitStatement(node); - T visitLabeledStatement(LabeledStatement node) => visitStatement(node); - T visitLiteralStatement(LiteralStatement node) => visitStatement(node); - - T visitCatch(Catch node) => visitNode(node); - T visitCase(Case node) => visitNode(node); - T visitDefault(Default node) => visitNode(node); - - T visitExpression(Expression node) => visitNode(node); - T visitVariableReference(VariableReference node) => visitExpression(node); - - T visitLiteralExpression(LiteralExpression node) => visitExpression(node); - T visitVariableDeclarationList(VariableDeclarationList node) - => visitExpression(node); - T visitSequence(Sequence node) => visitExpression(node); - T visitAssignment(Assignment node) => visitExpression(node); - T visitVariableInitialization(VariableInitialization node) { - if (node.value != null) { - visitAssignment(node); - } else { - visitExpression(node); - } - } - T visitConditional(Conditional node) => visitExpression(node); - T visitNew(New node) => visitExpression(node); - T visitCall(Call node) => visitExpression(node); - T visitBinary(Binary node) => visitCall(node); - T visitPrefix(Prefix node) => visitCall(node); - T visitPostfix(Postfix node) => visitCall(node); - T visitAccess(PropertyAccess node) => visitExpression(node); - - T visitVariableUse(VariableUse node) => visitVariableReference(node); - T visitVariableDeclaration(VariableDeclaration node) - => visitVariableReference(node); - T visitParameter(Parameter node) => visitVariableDeclaration(node); - T visitThis(This node) => visitParameter(node); - - T visitNamedFunction(NamedFunction node) => visitExpression(node); - T visitFun(Fun node) => visitExpression(node); - - T visitLiteral(Literal node) => visitExpression(node); - - T visitLiteralBool(LiteralBool node) => visitLiteral(node); - T visitLiteralString(LiteralString node) => visitLiteral(node); - T visitLiteralNumber(LiteralNumber node) => visitLiteral(node); - T visitLiteralNull(LiteralNull node) => visitLiteral(node); - - T visitArrayInitializer(ArrayInitializer node) => visitExpression(node); - T visitArrayElement(ArrayElement node) => visitNode(node); - T visitObjectInitializer(ObjectInitializer node) => visitExpression(node); - T visitProperty(Property node) => visitNode(node); - T visitRegExpLiteral(RegExpLiteral node) => visitExpression(node); -} - -abstract class Node { - var sourcePosition; - var endSourcePosition; - - accept(NodeVisitor visitor); - void visitChildren(NodeVisitor visitor); - - VariableUse asVariableUse() => null; -} - -class Program extends Node { - final List<Statement> body; - Program(this.body); - - accept(NodeVisitor visitor) => visitor.visitProgram(this); - void visitChildren(NodeVisitor visitor) { - for (Statement statement in body) statement.accept(visitor); - } -} - -abstract class Statement extends Node { -} - -class Block extends Statement { - final List<Statement> statements; - Block(this.statements); - Block.empty() : this.statements = <Statement>[]; - - accept(NodeVisitor visitor) => visitor.visitBlock(this); - void visitChildren(NodeVisitor visitor) { - for (Statement statement in statements) statement.accept(visitor); - } -} - -class ExpressionStatement extends Statement { - final Expression expression; - ExpressionStatement(this.expression); - - accept(NodeVisitor visitor) => visitor.visitExpressionStatement(this); - void visitChildren(NodeVisitor visitor) { expression.accept(visitor); } -} - -class EmptyStatement extends Statement { - EmptyStatement(); - - accept(NodeVisitor visitor) => visitor.visitEmptyStatement(this); - void visitChildren(NodeVisitor visitor) {} -} - -class If extends Statement { - final Expression condition; - final Node then; - final Node otherwise; - - If(this.condition, this.then, this.otherwise); - If.noElse(this.condition, this.then) : this.otherwise = new EmptyStatement(); - - bool get hasElse => otherwise is !EmptyStatement; - - accept(NodeVisitor visitor) => visitor.visitIf(this); - - void visitChildren(NodeVisitor visitor) { - condition.accept(visitor); - then.accept(visitor); - otherwise.accept(visitor); - } -} - -abstract class Loop extends Statement { - final Statement body; - Loop(this.body); -} - -class For extends Loop { - final Expression init; - final Expression condition; - final Expression update; - - For(this.init, this.condition, this.update, Statement body) : super(body); - - accept(NodeVisitor visitor) => visitor.visitFor(this); - - void visitChildren(NodeVisitor visitor) { - if (init != null) init.accept(visitor); - if (condition != null) condition.accept(visitor); - if (update != null) update.accept(visitor); - body.accept(visitor); - } -} - -class ForIn extends Loop { - // Note that [VariableDeclarationList] is a subclass of [Expression]. - // Therefore we can type the leftHandSide as [Expression]. - final Expression leftHandSide; - final Expression object; - - ForIn(this.leftHandSide, this.object, Statement body) : super(body); - - accept(NodeVisitor visitor) => visitor.visitForIn(this); - - void visitChildren(NodeVisitor visitor) { - leftHandSide.accept(visitor); - object.accept(visitor); - body.accept(visitor); - } -} - -class While extends Loop { - final Node condition; - - While(this.condition, Statement body) : super(body); - - accept(NodeVisitor visitor) => visitor.visitWhile(this); - - void visitChildren(NodeVisitor visitor) { - condition.accept(visitor); - body.accept(visitor); - } -} - -class Do extends Loop { - final Expression condition; - - Do(Statement body, this.condition) : super(body); - - accept(NodeVisitor visitor) => visitor.visitDo(this); - - void visitChildren(NodeVisitor visitor) { - body.accept(visitor); - condition.accept(visitor); - } -} - -class Continue extends Statement { - final String targetLabel; // Can be null. - - Continue(this.targetLabel); - - accept(NodeVisitor visitor) => visitor.visitContinue(this); - void visitChildren(NodeVisitor visitor) {} -} - -class Break extends Statement { - final String targetLabel; // Can be null. - - Break(this.targetLabel); - - accept(NodeVisitor visitor) => visitor.visitBreak(this); - void visitChildren(NodeVisitor visitor) {} -} - -class Return extends Statement { - final Expression value; // Can be null. - - Return([this.value = null]); - - accept(NodeVisitor visitor) => visitor.visitReturn(this); - - void visitChildren(NodeVisitor visitor) { - if (value != null) value.accept(visitor); - } -} - -class Throw extends Statement { - final Expression expression; - - Throw(this.expression); - - accept(NodeVisitor visitor) => visitor.visitThrow(this); - - void visitChildren(NodeVisitor visitor) { - expression.accept(visitor); - } -} - -class Try extends Statement { - final Block body; - final Catch catchPart; // Can be null if [finallyPart] is non-null. - final Block finallyPart; // Can be null if [catchPart] is non-null. - - Try(this.body, this.catchPart, this.finallyPart) { - assert(catchPart != null || finallyPart != null); - } - - accept(NodeVisitor visitor) => visitor.visitTry(this); - - void visitChildren(NodeVisitor visitor) { - body.accept(visitor); - if (catchPart != null) catchPart.accept(visitor); - if (finallyPart != null) finallyPart.accept(visitor); - } -} - -class Catch extends Node { - final VariableDeclaration declaration; - final Block body; - - Catch(this.declaration, this.body); - - accept(NodeVisitor visitor) => visitor.visitCatch(this); - - void visitChildren(NodeVisitor visitor) { - declaration.accept(visitor); - body.accept(visitor); - } -} - -class Switch extends Statement { - final Expression key; - final List<SwitchClause> cases; - - Switch(this.key, this.cases); - - accept(NodeVisitor visitor) => visitor.visitSwitch(this); - - void visitChildren(NodeVisitor visitor) { - key.accept(visitor); - for (SwitchClause clause in cases) clause.accept(visitor); - } -} - -abstract class SwitchClause extends Node { - final Block body; - - SwitchClause(this.body); -} - -class Case extends SwitchClause { - final Expression expression; - - Case(this.expression, Block body) : super(body); - - accept(NodeVisitor visitor) => visitor.visitCase(this); - - void visitChildren(NodeVisitor visitor) { - expression.accept(visitor); - body.accept(visitor); - } -} - -class Default extends SwitchClause { - Default(Block body) : super(body); - - accept(NodeVisitor visitor) => visitor.visitDefault(this); - - void visitChildren(NodeVisitor visitor) { - body.accept(visitor); - } -} - -class FunctionDeclaration extends Statement { - final VariableDeclaration name; - final Fun function; - - FunctionDeclaration(this.name, this.function); - - accept(NodeVisitor visitor) => visitor.visitFunctionDeclaration(this); - - void visitChildren(NodeVisitor visitor) { - name.accept(visitor); - function.accept(visitor); - } -} - -class LabeledStatement extends Statement { - final String label; - final Statement body; - - LabeledStatement(this.label, this.body); - - accept(NodeVisitor visitor) => visitor.visitLabeledStatement(this); - - void visitChildren(NodeVisitor visitor) { - body.accept(visitor); - } -} - -class LiteralStatement extends Statement { - final String code; - - LiteralStatement(this.code); - - accept(NodeVisitor visitor) => visitor.visitLiteralStatement(this); - void visitChildren(NodeVisitor visitor) { } -} - -abstract class Expression extends Node { - int get precedenceLevel; - - PropertyAccess dot(String name) => new PropertyAccess.field(this, name); - Call callWith(List<Expression> arguments) => new Call(this, arguments); -} - -class LiteralExpression extends Expression { - final String template; - final List<Expression> inputs; - - LiteralExpression(this.template) : inputs = const []; - LiteralExpression.withData(this.template, this.inputs); - - accept(NodeVisitor visitor) => visitor.visitLiteralExpression(this); - - void visitChildren(NodeVisitor visitor) { - for (Expression expr in inputs) expr.accept(visitor); - } - - // Code that uses JS must take care of operator precedences, and - // put parenthesis if needed. - int get precedenceLevel => PRIMARY; -} - -/** - * [VariableDeclarationList] is a subclass of [Expression] to simplify the - * AST. - */ -class VariableDeclarationList extends Expression { - final List<VariableInitialization> declarations; - - VariableDeclarationList(this.declarations); - - accept(NodeVisitor visitor) => visitor.visitVariableDeclarationList(this); - - void visitChildren(NodeVisitor visitor) { - for (VariableInitialization declaration in declarations) { - declaration.accept(visitor); - } - } - - int get precedenceLevel => EXPRESSION; -} - -class Sequence extends Expression { - final List<Expression> expressions; - - Sequence(this.expressions); - - accept(NodeVisitor visitor) => visitor.visitSequence(this); - - void visitChildren(NodeVisitor visitor) { - for (Expression expr in expressions) expr.accept(visitor); - } - - int get precedenceLevel => EXPRESSION; -} - -class Assignment extends Expression { - final Expression leftHandSide; - // Null, if the assignment is not compound. - final VariableReference compoundTarget; - final Expression value; // May be null, for [VariableInitialization]s. - - Assignment(this.leftHandSide, this.value) : compoundTarget = null; - Assignment.compound(this.leftHandSide, String op, this.value) - : compoundTarget = new VariableUse(op); - - int get precedenceLevel => ASSIGNMENT; - - bool get isCompound => compoundTarget != null; - String get op => compoundTarget == null ? null : compoundTarget.name; - - accept(NodeVisitor visitor) => visitor.visitAssignment(this); - - void visitChildren(NodeVisitor visitor) { - leftHandSide.accept(visitor); - if (compoundTarget != null) compoundTarget.accept(visitor); - if (value != null) value.accept(visitor); - } -} - -class VariableInitialization extends Assignment { - /** [value] may be null. */ - VariableInitialization(VariableDeclaration declaration, Expression value) - : super(declaration, value); - - VariableDeclaration get declaration => leftHandSide; - - accept(NodeVisitor visitor) => visitor.visitVariableInitialization(this); -} - -class Conditional extends Expression { - final Expression condition; - final Expression then; - final Expression otherwise; - - Conditional(this.condition, this.then, this.otherwise); - - accept(NodeVisitor visitor) => visitor.visitConditional(this); - - void visitChildren(NodeVisitor visitor) { - condition.accept(visitor); - then.accept(visitor); - otherwise.accept(visitor); - } - - int get precedenceLevel => ASSIGNMENT; -} - -class Call extends Expression { - Expression target; - List<Expression> arguments; - - Call(this.target, this.arguments); - - accept(NodeVisitor visitor) => visitor.visitCall(this); - - void visitChildren(NodeVisitor visitor) { - target.accept(visitor); - for (Expression arg in arguments) arg.accept(visitor); - } - - int get precedenceLevel => CALL; -} - -class New extends Call { - New(Expression cls, List<Expression> arguments) : super(cls, arguments); - - accept(NodeVisitor visitor) => visitor.visitNew(this); -} - -class Binary extends Call { - Binary(String op, Expression left, Expression right) - : super(new VariableUse(op), <Expression>[left, right]); - - String get op { - VariableUse use = target; - return use.name; - } - - Expression get left => arguments[0]; - Expression get right => arguments[1]; - - accept(NodeVisitor visitor) => visitor.visitBinary(this); - - int get precedenceLevel { - // TODO(floitsch): switch to constant map. - switch (op) { - case "*": - case "/": - case "%": - return MULTIPLICATIVE; - case "+": - case "-": - return ADDITIVE; - case "<<": - case ">>": - case ">>>": - return SHIFT; - case "<": - case ">": - case "<=": - case ">=": - case "instanceof": - case "in": - return RELATIONAL; - case "==": - case "===": - case "!=": - case "!==": - return EQUALITY; - case "&": - return BIT_AND; - case "^": - return BIT_XOR; - case "|": - return BIT_OR; - case "&&": - return LOGICAL_AND; - case "||": - return LOGICAL_OR; - default: - throw new leg.CompilerCancelledException( - "Internal Error: Unhandled binary operator: $op"); - } - } -} - -class Prefix extends Call { - Prefix(String op, Expression arg) - : super(new VariableUse(op), <Expression>[arg]); - - String get op => (target as VariableUse).name; - Expression get argument => arguments[0]; - - accept(NodeVisitor visitor) => visitor.visitPrefix(this); - - int get precedenceLevel => UNARY; -} - -class Postfix extends Call { - Postfix(String op, Expression arg) - : super(new VariableUse(op), <Expression>[arg]); - - String get op => (target as VariableUse).name; - Expression get argument => arguments[0]; - - accept(NodeVisitor visitor) => visitor.visitPostfix(this); - - int get precedenceLevel => UNARY; -} - -abstract class VariableReference extends Expression { - final String name; - - // We treat operators as if they were special functions. They can thus be - // referenced like other variables. - VariableReference(this.name); - - accept(NodeVisitor visitor); - int get precedenceLevel => PRIMARY; - void visitChildren(NodeVisitor visitor) {} -} - -class VariableUse extends VariableReference { - VariableUse(String name) : super(name); - - accept(NodeVisitor visitor) => visitor.visitVariableUse(this); - - VariableUse asVariableUse() => this; -} - -class VariableDeclaration extends VariableReference { - VariableDeclaration(String name) : super(name); - - accept(NodeVisitor visitor) => visitor.visitVariableDeclaration(this); -} - -class Parameter extends VariableDeclaration { - Parameter(String id) : super(id); - - accept(NodeVisitor visitor) => visitor.visitParameter(this); -} - -class This extends Parameter { - This() : super("this"); - - accept(NodeVisitor visitor) => visitor.visitThis(this); -} - -class NamedFunction extends Expression { - final VariableDeclaration name; - final Fun function; - - NamedFunction(this.name, this.function); - - accept(NodeVisitor visitor) => visitor.visitNamedFunction(this); - - void visitChildren(NodeVisitor visitor) { - name.accept(visitor); - function.accept(visitor); - } - - int get precedenceLevel => CALL; -} - -class Fun extends Expression { - final List<Parameter> params; - final Block body; - - Fun(this.params, this.body); - - accept(NodeVisitor visitor) => visitor.visitFun(this); - - void visitChildren(NodeVisitor visitor) { - for (Parameter param in params) param.accept(visitor); - body.accept(visitor); - } - - int get precedenceLevel => CALL; -} - -class PropertyAccess extends Expression { - final Expression receiver; - final Expression selector; - - PropertyAccess(this.receiver, this.selector); - PropertyAccess.field(this.receiver, String fieldName) - : selector = new LiteralString("'$fieldName'"); - PropertyAccess.indexed(this.receiver, int index) - : selector = new LiteralNumber('$index'); - - accept(NodeVisitor visitor) => visitor.visitAccess(this); - - void visitChildren(NodeVisitor visitor) { - receiver.accept(visitor); - selector.accept(visitor); - } - - int get precedenceLevel => CALL; -} - -abstract class Literal extends Expression { - void visitChildren(NodeVisitor visitor) {} - - int get precedenceLevel => PRIMARY; -} - -class LiteralBool extends Literal { - final bool value; - - LiteralBool(this.value); - - accept(NodeVisitor visitor) => visitor.visitLiteralBool(this); - // [visitChildren] inherited from [Literal]. -} - -class LiteralNull extends Literal { - LiteralNull(); - - accept(NodeVisitor visitor) => visitor.visitLiteralNull(this); -} - -class LiteralString extends Literal { - final String value; - - LiteralString(this.value); - - accept(NodeVisitor visitor) => visitor.visitLiteralString(this); -} - -class LiteralNumber extends Literal { - final String value; - - LiteralNumber(this.value); - - accept(NodeVisitor visitor) => visitor.visitLiteralNumber(this); -} - -class ArrayInitializer extends Expression { - final int length; - // We represent the array as sparse list of elements. Each element knows its - // position in the array. - final List<ArrayElement> elements; - - ArrayInitializer(this.length, this.elements); - - factory ArrayInitializer.from(Iterable<Expression> expressions) => - new ArrayInitializer(expressions.length, _convert(expressions)); - - accept(NodeVisitor visitor) => visitor.visitArrayInitializer(this); - - void visitChildren(NodeVisitor visitor) { - for (ArrayElement element in elements) element.accept(visitor); - } - - int get precedenceLevel => PRIMARY; - - static List<ArrayElement> _convert(Iterable<Expression> expressions) { - int index = 0; - return expressions.map( - (expression) => new ArrayElement(index++, expression)) - .toList(); - } -} - -/** - * An expression inside an [ArrayInitialization]. An [ArrayElement] knows - * its position in the containing [ArrayInitialization]. - */ -class ArrayElement extends Node { - int index; - Expression value; - - ArrayElement(this.index, this.value); - - accept(NodeVisitor visitor) => visitor.visitArrayElement(this); - - void visitChildren(NodeVisitor visitor) { - value.accept(visitor); - } -} - -class ObjectInitializer extends Expression { - List<Property> properties; - - ObjectInitializer(this.properties); - - accept(NodeVisitor visitor) => visitor.visitObjectInitializer(this); - - void visitChildren(NodeVisitor visitor) { - for (Property init in properties) init.accept(visitor); - } - - int get precedenceLevel => PRIMARY; -} - -class Property extends Node { - Literal name; - Expression value; - - Property(this.name, this.value); - - accept(NodeVisitor visitor) => visitor.visitProperty(this); - - void visitChildren(NodeVisitor visitor) { - name.accept(visitor); - value.accept(visitor); - } -} - -/** - * [RegExpLiteral]s, despite being called "Literal", are not inheriting from - * [Literal]. Indeed, regular expressions in JavaScript have a side-effect and - * are thus not in the same category as numbers or strings. - */ -class RegExpLiteral extends Expression { - /** Contains the pattern and the flags.*/ - String pattern; - - RegExpLiteral(this.pattern); - - accept(NodeVisitor visitor) => visitor.visitRegExpLiteral(this); - void visitChildren(NodeVisitor visitor) {} - - int get precedenceLevel => PRIMARY; -} - -Prefix typeOf(Expression argument) => new Prefix('typeof', argument); - -Binary equals(Expression left, Expression right) { - return new Binary('==', left, right); -} - -Binary strictEquals(Expression left, Expression right) { - return new Binary('===', left, right); -} - -LiteralString string(String value) => new LiteralString('"$value"'); - -If if_(Expression condition, Node then, [Node otherwise]) { - return (otherwise == null) - ? new If.noElse(condition, then) - : new If(condition, then, otherwise); -} - -Return return_([Expression value]) => new Return(value); - -VariableUse use(String name) => new VariableUse(name); - -PropertyAccess fieldAccess(Expression receiver, String fieldName) { - return new PropertyAccess.field(receiver, fieldName); -} - -Block emptyBlock() => new Block.empty(); - -Block block1(Statement statement) => new Block(<Statement>[statement]); - -Block block2(Statement s1, Statement s2) => new Block(<Statement>[s1, s2]); - -Call call(Expression target, List<Expression> arguments) { - return new Call(target, arguments); -} - -Fun fun(List<String> parameterNames, Block body) { - return new Fun(parameterNames.map((n) => new Parameter(n)).toList(), body); -} - -Assignment assign(Expression leftHandSide, Expression value) { - return new Assignment(leftHandSide, value); -} - -Expression undefined() => new Prefix('void', new LiteralNumber('0'));
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/js/precedence.dart b/pkgs/markdown/test/lib/src/compiler/implementation/js/precedence.dart deleted file mode 100644 index 6d66f1f..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/js/precedence.dart +++ /dev/null
@@ -1,25 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library precedence; - -const EXPRESSION = 0; -const ASSIGNMENT = EXPRESSION + 1; -const LOGICAL_OR = ASSIGNMENT + 1; -const LOGICAL_AND = LOGICAL_OR + 1; -const BIT_OR = LOGICAL_AND + 1; -const BIT_XOR = BIT_OR + 1; -const BIT_AND = BIT_XOR + 1; -const EQUALITY = BIT_AND + 1; -const RELATIONAL = EQUALITY + 1; -const SHIFT = RELATIONAL + 1; -const ADDITIVE = SHIFT + 1; -const MULTIPLICATIVE = ADDITIVE + 1; -const UNARY = MULTIPLICATIVE + 1; -const LEFT_HAND_SIDE = UNARY + 1; -// We merge new, call and member expressions. -// This means that we have to emit parenthesis for 'new's. For example `new X;` -// should be printed as `new X();`. This simplifies the requirements. -const CALL = LEFT_HAND_SIDE; -const PRIMARY = CALL + 1;
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/js/printer.dart b/pkgs/markdown/test/lib/src/compiler/implementation/js/printer.dart deleted file mode 100644 index 504933d..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/js/printer.dart +++ /dev/null
@@ -1,1111 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of js; - -class Printer implements NodeVisitor { - final bool shouldCompressOutput; - leg.Compiler compiler; - leg.CodeBuffer outBuffer; - int indentLevel = 0; - bool inForInit = false; - bool atStatementBegin = false; - final DanglingElseVisitor danglingElseVisitor; - final LocalNamer localNamer; - bool pendingSemicolon = false; - bool pendingSpace = false; - static final identifierCharacterRegExp = new RegExp(r'^[a-zA-Z_0-9$]'); - static final expressionContinuationRegExp = new RegExp(r'^[-+([]'); - - Printer(leg.Compiler compiler, { allowVariableMinification: true }) - : shouldCompressOutput = compiler.enableMinification, - this.compiler = compiler, - outBuffer = new leg.CodeBuffer(), - danglingElseVisitor = new DanglingElseVisitor(compiler), - localNamer = determineRenamer(compiler.enableMinification, - allowVariableMinification); - - static LocalNamer determineRenamer(bool shouldCompressOutput, - bool allowVariableMinification) { - return (shouldCompressOutput && allowVariableMinification) - ? new MinifyRenamer() : new IdentityNamer(); - } - - /// Always emit a newline, even under `enableMinification`. - void forceLine() { - out("\n"); - } - /// Emits a newline for readability. - void lineOut() { - if (!shouldCompressOutput) forceLine(); - } - void spaceOut() { - if (!shouldCompressOutput) out(" "); - } - - String lastAddedString = null; - int get lastCharCode { - if (lastAddedString == null) return 0; - assert(lastAddedString.length != ""); - return lastAddedString.charCodeAt(lastAddedString.length - 1); - } - - void out(String str) { - if (str != "") { - if (pendingSemicolon) { - if (!shouldCompressOutput) { - outBuffer.add(";"); - } else if (str != "}") { - // We want to output newline instead of semicolon because it makes - // the raw stack traces much easier to read and it also makes line- - // based tools like diff work much better. JavaScript will - // automatically insert the semicolon at the newline if it means a - // parsing error is avoided, so we can only do this trick if the - // next line is not something that can be glued onto a valid - // expression to make a new valid expression. - if (expressionContinuationRegExp.hasMatch(str)) { - outBuffer.add(";"); - } else { - outBuffer.add("\n"); - } - } - } - if (pendingSpace && - (!shouldCompressOutput || identifierCharacterRegExp.hasMatch(str))) { - outBuffer.add(" "); - } - pendingSpace = false; - pendingSemicolon = false; - outBuffer.add(str); - lastAddedString = str; - } - } - - void outLn(String str) { - out(str); - lineOut(); - } - - void outSemicolonLn() { - if (shouldCompressOutput) { - pendingSemicolon = true; - } else { - out(";"); - forceLine(); - } - } - - void outIndent(String str) { indent(); out(str); } - void outIndentLn(String str) { indent(); outLn(str); } - void indent() { - if (!shouldCompressOutput) { - for (int i = 0; i < indentLevel; i++) out(" "); - } - } - - void recordSourcePosition(var position) { - if (position != null) { - outBuffer.setSourceLocation(position); - } - } - - visit(Node node) { - if (node.sourcePosition != null) outBuffer.beginMappedRange(); - recordSourcePosition(node.sourcePosition); - node.accept(this); - recordSourcePosition(node.endSourcePosition); - if (node.sourcePosition != null) outBuffer.endMappedRange(); - } - - visitCommaSeparated(List<Node> nodes, int hasRequiredType, - {bool newInForInit, bool newAtStatementBegin}) { - for (int i = 0; i < nodes.length; i++) { - if (i != 0) { - atStatementBegin = false; - out(","); - spaceOut(); - } - visitNestedExpression(nodes[i], hasRequiredType, - newInForInit: newInForInit, - newAtStatementBegin: newAtStatementBegin); - } - } - - visitAll(List<Node> nodes) { - nodes.forEach(visit); - } - - visitProgram(Program program) { - visitAll(program.body); - } - - bool blockBody(Node body, {bool needsSeparation, bool needsNewline}) { - if (body is Block) { - spaceOut(); - blockOut(body, false, needsNewline); - return true; - } - if (shouldCompressOutput && needsSeparation) { - // If [shouldCompressOutput] is false, then the 'lineOut' will insert - // the separation. - out(" "); - } else { - lineOut(); - } - indentLevel++; - visit(body); - indentLevel--; - return false; - } - - void blockOutWithoutBraces(Node node) { - if (node is Block) { - node.statements.forEach(blockOutWithoutBraces); - } else { - visit(node); - } - } - - void blockOut(Block node, bool shouldIndent, bool needsNewline) { - if (shouldIndent) indent(); - out("{"); - lineOut(); - indentLevel++; - node.statements.forEach(blockOutWithoutBraces); - indentLevel--; - indent(); - out("}"); - if (needsNewline) lineOut(); - } - - visitBlock(Block block) { - blockOut(block, true, true); - } - - visitExpressionStatement(ExpressionStatement expressionStatement) { - indent(); - visitNestedExpression(expressionStatement.expression, EXPRESSION, - newInForInit: false, newAtStatementBegin: true); - outSemicolonLn(); - } - - visitEmptyStatement(EmptyStatement nop) { - outIndentLn(";"); - } - - void ifOut(If node, bool shouldIndent) { - Node then = node.then; - Node elsePart = node.otherwise; - bool hasElse = node.hasElse; - - // Handle dangling elses. - if (hasElse) { - bool needsBraces = node.then.accept(danglingElseVisitor); - if (needsBraces) { - then = new Block(<Statement>[then]); - } - } - if (shouldIndent) indent(); - out("if"); - spaceOut(); - out("("); - visitNestedExpression(node.condition, EXPRESSION, - newInForInit: false, newAtStatementBegin: false); - out(")"); - bool thenWasBlock = - blockBody(then, needsSeparation: false, needsNewline: !hasElse); - if (hasElse) { - if (thenWasBlock) { - spaceOut(); - } else { - indent(); - } - out("else"); - if (elsePart is If) { - pendingSpace = true; - ifOut(elsePart, false); - } else { - blockBody(elsePart, needsSeparation: true, needsNewline: true); - } - } - } - - visitIf(If node) { - ifOut(node, true); - } - - visitFor(For loop) { - outIndent("for"); - spaceOut(); - out("("); - if (loop.init != null) { - visitNestedExpression(loop.init, EXPRESSION, - newInForInit: true, newAtStatementBegin: false); - } - out(";"); - if (loop.condition != null) { - spaceOut(); - visitNestedExpression(loop.condition, EXPRESSION, - newInForInit: false, newAtStatementBegin: false); - } - out(";"); - if (loop.update != null) { - spaceOut(); - visitNestedExpression(loop.update, EXPRESSION, - newInForInit: false, newAtStatementBegin: false); - } - out(")"); - blockBody(loop.body, needsSeparation: false, needsNewline: true); - } - - visitForIn(ForIn loop) { - outIndent("for"); - spaceOut(); - out("("); - visitNestedExpression(loop.leftHandSide, EXPRESSION, - newInForInit: true, newAtStatementBegin: false); - out(" in"); - pendingSpace = true; - visitNestedExpression(loop.object, EXPRESSION, - newInForInit: false, newAtStatementBegin: false); - out(")"); - blockBody(loop.body, needsSeparation: false, needsNewline: true); - } - - visitWhile(While loop) { - outIndent("while"); - spaceOut(); - out("("); - visitNestedExpression(loop.condition, EXPRESSION, - newInForInit: false, newAtStatementBegin: false); - out(")"); - blockBody(loop.body, needsSeparation: false, needsNewline: true); - } - - visitDo(Do loop) { - outIndent("do"); - if (blockBody(loop.body, needsSeparation: true, needsNewline: false)) { - spaceOut(); - } else { - indent(); - } - out("while"); - spaceOut(); - out("("); - visitNestedExpression(loop.condition, EXPRESSION, - newInForInit: false, newAtStatementBegin: false); - out(")"); - outSemicolonLn(); - } - - visitContinue(Continue node) { - if (node.targetLabel == null) { - outIndent("continue"); - } else { - outIndent("continue ${node.targetLabel}"); - } - outSemicolonLn(); - } - - visitBreak(Break node) { - if (node.targetLabel == null) { - outIndent("break"); - } else { - outIndent("break ${node.targetLabel}"); - } - outSemicolonLn(); - } - - visitReturn(Return node) { - if (node.value == null) { - outIndent("return"); - } else { - outIndent("return"); - pendingSpace = true; - visitNestedExpression(node.value, EXPRESSION, - newInForInit: false, newAtStatementBegin: false); - } - outSemicolonLn(); - } - - visitThrow(Throw node) { - outIndent("throw"); - pendingSpace = true; - visitNestedExpression(node.expression, EXPRESSION, - newInForInit: false, newAtStatementBegin: false); - outSemicolonLn(); - } - - visitTry(Try node) { - outIndent("try"); - blockBody(node.body, needsSeparation: true, needsNewline: false); - if (node.catchPart != null) { - visit(node.catchPart); - } - if (node.finallyPart != null) { - spaceOut(); - out("finally"); - blockBody(node.finallyPart, needsSeparation: true, needsNewline: true); - } else { - lineOut(); - } - } - - visitCatch(Catch node) { - spaceOut(); - out("catch"); - spaceOut(); - out("("); - visitNestedExpression(node.declaration, EXPRESSION, - newInForInit: false, newAtStatementBegin: false); - out(")"); - blockBody(node.body, needsSeparation: false, needsNewline: true); - } - - visitSwitch(Switch node) { - outIndent("switch"); - spaceOut(); - out("("); - visitNestedExpression(node.key, EXPRESSION, - newInForInit: false, newAtStatementBegin: false); - out(")"); - spaceOut(); - outLn("{"); - indentLevel++; - visitAll(node.cases); - indentLevel--; - outIndentLn("}"); - } - - visitCase(Case node) { - outIndent("case"); - pendingSpace = true; - visitNestedExpression(node.expression, EXPRESSION, - newInForInit: false, newAtStatementBegin: false); - outLn(":"); - if (!node.body.statements.isEmpty) { - indentLevel++; - blockOutWithoutBraces(node.body); - indentLevel--; - } - } - - visitDefault(Default node) { - outIndentLn("default:"); - if (!node.body.statements.isEmpty) { - indentLevel++; - blockOutWithoutBraces(node.body); - indentLevel--; - } - } - - visitLabeledStatement(LabeledStatement node) { - outIndent("${node.label}:"); - blockBody(node.body, needsSeparation: false, needsNewline: true); - } - - void functionOut(Fun fun, Node name, VarCollector vars) { - out("function"); - if (name != null) { - out(" "); - // Name must be a [Decl]. Therefore only test for primary expressions. - visitNestedExpression(name, PRIMARY, - newInForInit: false, newAtStatementBegin: false); - } - localNamer.enterScope(vars); - out("("); - if (fun.params != null) { - visitCommaSeparated(fun.params, PRIMARY, - newInForInit: false, newAtStatementBegin: false); - } - out(")"); - blockBody(fun.body, needsSeparation: false, needsNewline: false); - localNamer.leaveScope(); - } - - visitFunctionDeclaration(FunctionDeclaration declaration) { - VarCollector vars = new VarCollector(); - vars.visitFunctionDeclaration(declaration); - indent(); - functionOut(declaration.function, declaration.name, vars); - lineOut(); - } - - visitNestedExpression(Expression node, int requiredPrecedence, - {bool newInForInit, bool newAtStatementBegin}) { - bool needsParentheses = - // a - (b + c). - (requiredPrecedence != EXPRESSION && - node.precedenceLevel < requiredPrecedence) || - // for (a = (x in o); ... ; ... ) { ... } - (newInForInit && node is Binary && (node as Binary).op == "in") || - // (function() { ... })(). - // ({a: 2, b: 3}.toString()). - (newAtStatementBegin && (node is NamedFunction || - node is Fun || - node is ObjectInitializer)); - if (needsParentheses) { - inForInit = false; - atStatementBegin = false; - out("("); - visit(node); - out(")"); - } else { - inForInit = newInForInit; - atStatementBegin = newAtStatementBegin; - visit(node); - } - } - - visitVariableDeclarationList(VariableDeclarationList list) { - out("var "); - visitCommaSeparated(list.declarations, ASSIGNMENT, - newInForInit: inForInit, newAtStatementBegin: false); - } - - visitSequence(Sequence sequence) { - // Note that we only require that the entries are expressions and not - // assignments. This means that nested sequences are not put into - // parenthesis. - visitCommaSeparated(sequence.expressions, EXPRESSION, - newInForInit: false, - newAtStatementBegin: atStatementBegin); - } - - visitAssignment(Assignment assignment) { - visitNestedExpression(assignment.leftHandSide, LEFT_HAND_SIDE, - newInForInit: inForInit, - newAtStatementBegin: atStatementBegin); - if (assignment.value != null) { - spaceOut(); - String op = assignment.op; - if (op != null) out(op); - out("="); - spaceOut(); - visitNestedExpression(assignment.value, ASSIGNMENT, - newInForInit: inForInit, - newAtStatementBegin: false); - } - } - - visitVariableInitialization(VariableInitialization initialization) { - visitAssignment(initialization); - } - - visitConditional(Conditional cond) { - visitNestedExpression(cond.condition, LOGICAL_OR, - newInForInit: inForInit, - newAtStatementBegin: atStatementBegin); - spaceOut(); - out("?"); - spaceOut(); - // The then part is allowed to have an 'in'. - visitNestedExpression(cond.then, ASSIGNMENT, - newInForInit: false, newAtStatementBegin: false); - spaceOut(); - out(":"); - spaceOut(); - visitNestedExpression(cond.otherwise, ASSIGNMENT, - newInForInit: inForInit, newAtStatementBegin: false); - } - - visitNew(New node) { - out("new "); - visitNestedExpression(node.target, CALL, - newInForInit: inForInit, newAtStatementBegin: false); - out("("); - visitCommaSeparated(node.arguments, ASSIGNMENT, - newInForInit: false, newAtStatementBegin: false); - out(")"); - } - - visitCall(Call call) { - visitNestedExpression(call.target, LEFT_HAND_SIDE, - newInForInit: inForInit, - newAtStatementBegin: atStatementBegin); - out("("); - visitCommaSeparated(call.arguments, ASSIGNMENT, - newInForInit: false, newAtStatementBegin: false); - out(")"); - } - - visitBinary(Binary binary) { - Expression left = binary.left; - Expression right = binary.right; - String op = binary.op; - int leftPrecedenceRequirement; - int rightPrecedenceRequirement; - switch (op) { - case "||": - leftPrecedenceRequirement = LOGICAL_OR; - // x || (y || z) <=> (x || y) || z. - rightPrecedenceRequirement = LOGICAL_OR; - break; - case "&&": - leftPrecedenceRequirement = LOGICAL_AND; - // x && (y && z) <=> (x && y) && z. - rightPrecedenceRequirement = LOGICAL_AND; - break; - case "|": - leftPrecedenceRequirement = BIT_OR; - // x | (y | z) <=> (x | y) | z. - rightPrecedenceRequirement = BIT_OR; - break; - case "^": - leftPrecedenceRequirement = BIT_XOR; - // x ^ (y ^ z) <=> (x ^ y) ^ z. - rightPrecedenceRequirement = BIT_XOR; - break; - case "&": - leftPrecedenceRequirement = BIT_AND; - // x & (y & z) <=> (x & y) & z. - rightPrecedenceRequirement = BIT_AND; - break; - case "==": - case "!=": - case "===": - case "!==": - leftPrecedenceRequirement = EQUALITY; - rightPrecedenceRequirement = RELATIONAL; - break; - case "<": - case ">": - case "<=": - case ">=": - case "instanceof": - case "in": - leftPrecedenceRequirement = RELATIONAL; - rightPrecedenceRequirement = SHIFT; - break; - case ">>": - case "<<": - case ">>>": - leftPrecedenceRequirement = SHIFT; - rightPrecedenceRequirement = ADDITIVE; - break; - case "+": - case "-": - leftPrecedenceRequirement = ADDITIVE; - // We cannot remove parenthesis for "+" because - // x + (y + z) <!=> (x + y) + z: - // Example: - // "a" + (1 + 2) => "a3"; - // ("a" + 1) + 2 => "a12"; - rightPrecedenceRequirement = MULTIPLICATIVE; - break; - case "*": - case "/": - case "%": - leftPrecedenceRequirement = MULTIPLICATIVE; - // We cannot remove parenthesis for "*" because of precision issues. - rightPrecedenceRequirement = UNARY; - break; - default: - compiler.internalError("Forgot operator: $op"); - } - - visitNestedExpression(left, leftPrecedenceRequirement, - newInForInit: inForInit, - newAtStatementBegin: atStatementBegin); - - if (op == "in" || op == "instanceof") { - // There are cases where the space is not required but without further - // analysis we cannot know. - out(" "); - out(op); - out(" "); - } else { - spaceOut(); - out(op); - spaceOut(); - } - visitNestedExpression(right, rightPrecedenceRequirement, - newInForInit: inForInit, - newAtStatementBegin: false); - } - - visitPrefix(Prefix unary) { - String op = unary.op; - switch (op) { - case "delete": - case "void": - case "typeof": - // There are cases where the space is not required but without further - // analysis we cannot know. - out(op); - out(" "); - break; - case "+": - case "++": - if (lastCharCode == charCodes.$PLUS) out(" "); - out(op); - break; - case "-": - case "--": - if (lastCharCode == charCodes.$MINUS) out(" "); - out(op); - break; - default: - out(op); - } - visitNestedExpression(unary.argument, UNARY, - newInForInit: inForInit, newAtStatementBegin: false); - } - - visitPostfix(Postfix postfix) { - visitNestedExpression(postfix.argument, LEFT_HAND_SIDE, - newInForInit: inForInit, - newAtStatementBegin: atStatementBegin); - out(postfix.op); - } - - visitVariableUse(VariableUse ref) { - out(localNamer.getName(ref.name)); - } - - visitThis(This node) { - out("this"); - } - - visitVariableDeclaration(VariableDeclaration decl) { - out(localNamer.getName(decl.name)); - } - - visitParameter(Parameter param) { - out(localNamer.getName(param.name)); - } - - bool isDigit(int charCode) { - return charCodes.$0 <= charCode && charCode <= charCodes.$9; - } - - bool isValidJavaScriptId(String field) { - if (field.length < 3) return false; - // Ignore the leading and trailing string-delimiter. - for (int i = 1; i < field.length - 1; i++) { - // TODO(floitsch): allow more characters. - int charCode = field.charCodeAt(i); - if (!(charCodes.$a <= charCode && charCode <= charCodes.$z || - charCodes.$A <= charCode && charCode <= charCodes.$Z || - charCode == charCodes.$$ || - charCode == charCodes.$_ || - i != 1 && isDigit(charCode))) { - return false; - } - } - // TODO(floitsch): normally we should also check that the field is not a - // reserved word. We don't generate fields with reserved word names except - // for 'super'. - if (field == '"super"') return false; - return true; - } - - visitAccess(PropertyAccess access) { - visitNestedExpression(access.receiver, CALL, - newInForInit: inForInit, - newAtStatementBegin: atStatementBegin); - Node selector = access.selector; - if (selector is LiteralString) { - LiteralString selectorString = selector; - String fieldWithQuotes = selectorString.value; - if (isValidJavaScriptId(fieldWithQuotes)) { - if (access.receiver is LiteralNumber) out(" "); - out("."); - out(fieldWithQuotes.substring(1, fieldWithQuotes.length - 1)); - return; - } - } - out("["); - visitNestedExpression(selector, EXPRESSION, - newInForInit: false, newAtStatementBegin: false); - out("]"); - } - - visitNamedFunction(NamedFunction namedFunction) { - VarCollector vars = new VarCollector(); - vars.visitNamedFunction(namedFunction); - functionOut(namedFunction.function, namedFunction.name, vars); - } - - visitFun(Fun fun) { - VarCollector vars = new VarCollector(); - vars.visitFun(fun); - functionOut(fun, null, vars); - } - - visitLiteralBool(LiteralBool node) { - out(node.value ? "true" : "false"); - } - - visitLiteralString(LiteralString node) { - out(node.value); - } - - visitLiteralNumber(LiteralNumber node) { - int charCode = node.value.charCodeAt(0); - if (charCode == charCodes.$MINUS && lastCharCode == charCodes.$MINUS) { - out(" "); - } - out(node.value); - } - - visitLiteralNull(LiteralNull node) { - out("null"); - } - - visitArrayInitializer(ArrayInitializer node) { - out("["); - List<ArrayElement> elements = node.elements; - int elementIndex = 0; - for (int i = 0; i < node.length; i++) { - if (elementIndex < elements.length && - elements[elementIndex].index == i) { - visitNestedExpression(elements[elementIndex].value, ASSIGNMENT, - newInForInit: false, newAtStatementBegin: false); - elementIndex++; - // We can avoid a trailing "," if there was an element just before. So - // `[1]` and `[1,]` are the same, but `[,]` and `[]` are not. - if (i != node.length - 1) { - out(","); - spaceOut(); - } - } else { - out(","); - } - } - out("]"); - } - - visitArrayElement(ArrayElement node) { - throw "Unreachable"; - } - - visitObjectInitializer(ObjectInitializer node) { - // Print all the properties on one line until we see a function-valued - // property. Ideally, we would use a proper pretty-printer to make the - // decision based on layout. - bool onePerLine = false; - List<Property> properties = node.properties; - out("{"); - ++indentLevel; - for (int i = 0; i < properties.length; i++) { - Expression value = properties[i].value; - if (value is Fun || value is NamedFunction) onePerLine = true; - if (i != 0) { - out(","); - if (!onePerLine) spaceOut(); - } - if (onePerLine) { - forceLine(); - indent(); - } - visitProperty(properties[i]); - } - --indentLevel; - if (onePerLine) lineOut(); - out("}"); - } - - visitProperty(Property node) { - if (node.name is LiteralString) { - LiteralString nameString = node.name; - String name = nameString.value; - if (isValidJavaScriptId(name)) { - out(name.substring(1, name.length - 1)); - } else { - out(name); - } - } else { - assert(node.name is LiteralNumber); - LiteralNumber nameNumber = node.name; - out(nameNumber.value); - } - out(":"); - spaceOut(); - visitNestedExpression(node.value, ASSIGNMENT, - newInForInit: false, newAtStatementBegin: false); - } - - visitRegExpLiteral(RegExpLiteral node) { - out(node.pattern); - } - - visitLiteralExpression(LiteralExpression node) { - String template = node.template; - List<Expression> inputs = node.inputs; - - List<String> parts = template.split('#'); - if (parts.length != inputs.length + 1) { - compiler.internalError('Wrong number of arguments for JS: $template'); - } - // Code that uses JS must take care of operator precedences, and - // put parenthesis if needed. - out(parts[0]); - for (int i = 0; i < inputs.length; i++) { - visit(inputs[i]); - out(parts[i + 1]); - } - } - - visitLiteralStatement(LiteralStatement node) { - outLn(node.code); - } -} - - -class OrderedSet<T> { - final Set<T> set; - final List<T> list; - - OrderedSet() : set = new Set<T>(), list = <T>[]; - - void add(T x) { - if (!set.contains(x)) { - set.add(x); - list.add(x); - } - } - - void forEach(void fun(T x)) { - list.forEach(fun); - } -} - -// Collects all the var declarations in the function. We need to do this in a -// separate pass because JS vars are lifted to the top of the function. -class VarCollector extends BaseVisitor { - bool nested; - final OrderedSet<String> vars; - final OrderedSet<String> params; - - VarCollector() : nested = false, - vars = new OrderedSet<String>(), - params = new OrderedSet<String>(); - - void forEachVar(void fn(String v)) => vars.forEach(fn); - void forEachParam(void fn(String p)) => params.forEach(fn); - - void collectVarsInFunction(Fun fun) { - if (!nested) { - nested = true; - if (fun.params != null) { - for (int i = 0; i < fun.params.length; i++) { - params.add(fun.params[i].name); - } - } - visitBlock(fun.body); - nested = false; - } - } - - void visitFunctionDeclaration(FunctionDeclaration declaration) { - // Note that we don't bother collecting the name of the function. - collectVarsInFunction(declaration.function); - } - - void visitNamedFunction(NamedFunction namedFunction) { - // Note that we don't bother collecting the name of the function. - collectVarsInFunction(namedFunction.function); - } - - void visitFun(Fun fun) { - collectVarsInFunction(fun); - } - - void visitThis(This node) {} - - void visitVariableDeclaration(VariableDeclaration decl) { - vars.add(decl.name); - } -} - - -/** - * Returns true, if the given node must be wrapped into braces when used - * as then-statement in an [If] that has an else branch. - */ -class DanglingElseVisitor extends BaseVisitor<bool> { - leg.Compiler compiler; - - DanglingElseVisitor(this.compiler); - - bool visitProgram(Program node) => false; - - bool visitNode(Statement node) { - compiler.internalError("Forgot node: $node"); - } - - bool visitBlock(Block node) => false; - bool visitExpressionStatement(ExpressionStatement node) => false; - bool visitEmptyStatement(EmptyStatement node) => false; - bool visitIf(If node) { - if (!node.hasElse) return true; - return node.otherwise.accept(this); - } - bool visitFor(For node) => node.body.accept(this); - bool visitForIn(ForIn node) => node.body.accept(this); - bool visitWhile(While node) => node.body.accept(this); - bool visitDo(Do node) => false; - bool visitContinue(Continue node) => false; - bool visitBreak(Break node) => false; - bool visitReturn(Return node) => false; - bool visitThrow(Throw node) => false; - bool visitTry(Try node) { - if (node.finallyPart != null) { - return node.finallyPart.accept(this); - } else { - return node.catchPart.accept(this); - } - } - bool visitCatch(Catch node) => node.body.accept(this); - bool visitSwitch(Switch node) => false; - bool visitCase(Case node) => false; - bool visitDefault(Default node) => false; - bool visitFunctionDeclaration(FunctionDeclaration node) => false; - bool visitLabeledStatement(LabeledStatement node) - => node.body.accept(this); - bool visitLiteralStatement(LiteralStatement node) => true; - - bool visitExpression(Expression node) => false; -} - - -leg.CodeBuffer prettyPrint(Node node, leg.Compiler compiler, - { allowVariableMinification: true }) { - Printer printer = - new Printer(compiler, - allowVariableMinification: allowVariableMinification); - printer.visit(node); - return printer.outBuffer; -} - - -abstract class LocalNamer { - String getName(String oldName); - String declareVariable(String oldName); - String declareParameter(String oldName); - void enterScope(VarCollector vars); - void leaveScope(); -} - - -class IdentityNamer implements LocalNamer { - String getName(String oldName) => oldName; - String declareVariable(String oldName) => oldName; - String declareParameter(String oldName) => oldName; - void enterScope(VarCollector vars) {} - void leaveScope() {} -} - - -class MinifyRenamer implements LocalNamer { - final List<Map<String, String>> maps = []; - final List<int> parameterNumberStack = []; - final List<int> variableNumberStack = []; - int parameterNumber = 0; - int variableNumber = 0; - - MinifyRenamer(); - - void enterScope(VarCollector vars) { - maps.add(new Map<String, String>()); - variableNumberStack.add(variableNumber); - parameterNumberStack.add(parameterNumber); - vars.forEachVar(declareVariable); - vars.forEachParam(declareParameter); - } - - void leaveScope() { - maps.removeLast(); - variableNumber = variableNumberStack.removeLast(); - parameterNumber = parameterNumberStack.removeLast(); - } - - String getName(String oldName) { - // Go from inner scope to outer looking for mapping of name. - for (int i = maps.length - 1; i >= 0; i--) { - var map = maps[i]; - var replacement = map[oldName]; - if (replacement != null) return replacement; - } - return oldName; - } - - static const LOWER_CASE_LETTERS = 26; - static const LETTERS = 52; - static const DIGITS = 10; - - static int nthLetter(int n) { - return (n < LOWER_CASE_LETTERS) ? - charCodes.$a + n : - charCodes.$A + n - LOWER_CASE_LETTERS; - } - - // Parameters go from a to z and variables go from z to a. This makes each - // argument list and each top-of-function var declaration look similar and - // helps gzip compress the file. If we have more than 26 arguments and - // variables then we meet somewhere in the middle of the alphabet. After - // that we give up trying to be nice to the compression algorithm and just - // use the same namespace for arguments and variables, starting with A, and - // moving on to a0, a1, etc. - String declareVariable(String oldName) { - var newName; - if (variableNumber + parameterNumber < LOWER_CASE_LETTERS) { - // Variables start from z and go backwards, for better gzipability. - newName = getNameNumber(oldName, LOWER_CASE_LETTERS - 1 - variableNumber); - } else { - // After 26 variables and parameters we allocate them in the same order. - newName = getNameNumber(oldName, variableNumber + parameterNumber); - } - variableNumber++; - return newName; - } - - String declareParameter(String oldName) { - var newName; - if (variableNumber + parameterNumber < LOWER_CASE_LETTERS) { - newName = getNameNumber(oldName, parameterNumber); - } else { - newName = getNameNumber(oldName, variableNumber + parameterNumber); - } - parameterNumber++; - return newName; - } - - String getNameNumber(String oldName, int n) { - if (maps.isEmpty) return oldName; - - String newName; - if (n < LETTERS) { - // Start naming variables a, b, c, ..., z, A, B, C, ..., Z. - newName = new String.fromCharCodes([nthLetter(n)]); - } else { - // Then name variables a0, a1, a2, ..., a9, b0, b1, ..., Z9, aa0, aa1, ... - // For all functions with fewer than 500 locals this is just as compact - // as using aa, ab, etc. but avoids clashes with keywords. - n -= LETTERS; - int digit = n % DIGITS; - n ~/= DIGITS; - int alphaChars = 1; - int nameSpaceSize = LETTERS; - // Find out whether we should use the 1-character namespace (size 52), the - // 2-character namespace (size 52*52), etc. - while (n >= nameSpaceSize) { - n -= nameSpaceSize; - alphaChars++; - nameSpaceSize *= LETTERS; - } - var codes = <int>[]; - for (var i = 0; i < alphaChars; i++) { - nameSpaceSize ~/= LETTERS; - codes.add(nthLetter((n ~/ nameSpaceSize) % LETTERS)); - } - codes.add(charCodes.$0 + digit); - newName = new String.fromCharCodes(codes); - } - assert(new RegExp(r'[a-zA-Z][a-zA-Z0-9]*').hasMatch(newName)); - maps.last[oldName] = newName; - return newName; - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/backend.dart b/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/backend.dart deleted file mode 100644 index 2a681d8..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/backend.dart +++ /dev/null
@@ -1,1262 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of js_backend; - -typedef void Recompile(Element element); - -class ReturnInfo { - HType returnType; - List<Element> compiledFunctions; - - ReturnInfo(HType this.returnType) - : compiledFunctions = new List<Element>(); - - ReturnInfo.unknownType() : this(null); - - void update(HType type, Recompile recompile, Compiler compiler) { - HType newType = - returnType != null ? returnType.union(type, compiler) : type; - if (newType != returnType) { - if (returnType == null && identical(newType, HType.UNKNOWN)) { - // If the first actual piece of information is not providing any type - // information there is no need to recompile callers. - compiledFunctions.clear(); - } - returnType = newType; - if (recompile != null) { - compiledFunctions.forEach(recompile); - } - compiledFunctions.clear(); - } - } - - // Note that lazy initializers are treated like functions (but are not - // of type [FunctionElement]. - addCompiledFunction(Element function) => compiledFunctions.add(function); -} - -class OptionalParameterTypes { - final List<SourceString> names; - final List<HType> types; - - OptionalParameterTypes(int optionalArgumentsCount) - : names = new List<SourceString>.fixedLength(optionalArgumentsCount), - types = new List<HType>.fixedLength(optionalArgumentsCount); - - int get length => names.length; - SourceString name(int index) => names[index]; - HType type(int index) => types[index]; - int indexOf(SourceString name) => names.indexOf(name); - - HType typeFor(SourceString name) { - int index = indexOf(name); - if (index == -1) return null; - return type(index); - } - - void update(int index, SourceString name, HType type) { - names[index] = name; - types[index] = type; - } - - String toString() => "OptionalParameterTypes($names, $types)"; -} - -class HTypeList { - final List<HType> types; - final List<SourceString> namedArguments; - - HTypeList(int length) - : types = new List<HType>.fixedLength(length), - namedArguments = null; - HTypeList.withNamedArguments(int length, this.namedArguments) - : types = new List<HType>.fixedLength(length); - const HTypeList.withAllUnknown() - : types = null, - namedArguments = null; - - factory HTypeList.fromStaticInvocation(HInvokeStatic node, HTypeMap types) { - bool allUnknown = true; - for (int i = 1; i < node.inputs.length; i++) { - if (types[node.inputs[i]] != HType.UNKNOWN) { - allUnknown = false; - break; - } - } - if (allUnknown) return HTypeList.ALL_UNKNOWN; - - HTypeList result = new HTypeList(node.inputs.length - 1); - for (int i = 0; i < result.types.length; i++) { - result.types[i] = types[node.inputs[i + 1]]; - } - return result; - } - - factory HTypeList.fromDynamicInvocation(HInvokeDynamic node, - Selector selector, - HTypeMap types) { - HTypeList result; - int argumentsCount = node.inputs.length - 1; - int startInvokeIndex = HInvoke.ARGUMENTS_OFFSET; - - if (node.isInterceptorCall) { - argumentsCount--; - startInvokeIndex++; - } - - if (selector.namedArgumentCount > 0) { - result = - new HTypeList.withNamedArguments( - argumentsCount, selector.namedArguments); - } else { - result = new HTypeList(argumentsCount); - } - - for (int i = 0; i < result.types.length; i++) { - result.types[i] = types[node.inputs[i + startInvokeIndex]]; - } - return result; - } - - static const HTypeList ALL_UNKNOWN = const HTypeList.withAllUnknown(); - - bool get allUnknown => types == null; - bool get hasNamedArguments => namedArguments != null; - int get length => types.length; - HType operator[](int index) => types[index]; - void operator[]=(int index, HType type) { types[index] = type; } - - HTypeList union(HTypeList other, Compiler compiler) { - if (allUnknown) return this; - if (other.allUnknown) return other; - if (length != other.length) return HTypeList.ALL_UNKNOWN; - bool onlyUnknown = true; - HTypeList result = this; - for (int i = 0; i < length; i++) { - HType newType = this[i].union(other[i], compiler); - if (result == this && newType != this[i]) { - // Create a new argument types object with the matching types copied. - result = new HTypeList(length); - result.types.setRange(0, i, this.types); - } - if (result != this) { - result.types[i] = newType; - } - if (result[i] != HType.UNKNOWN) onlyUnknown = false; - } - return onlyUnknown ? HTypeList.ALL_UNKNOWN : result; - } - - HTypeList unionWithOptionalParameters( - Selector selector, - FunctionSignature signature, - OptionalParameterTypes defaultValueTypes) { - assert(allUnknown || selector.argumentCount == this.length); - // Create a new HTypeList for holding types for all parameters. - HTypeList result = new HTypeList(signature.parameterCount); - - // First fill in the type of the positional arguments. - int nextTypeIndex = -1; - if (allUnknown) { - for (int i = 0; i < selector.positionalArgumentCount; i++) { - result.types[i] = HType.UNKNOWN; - } - } else { - result.types.setRange(0, selector.positionalArgumentCount, this.types); - nextTypeIndex = selector.positionalArgumentCount; - } - - // Next fill the type of the optional arguments. - // As the selector can pass optional arguments positionally some of the - // optional arguments might already have a type set. We only need to look - // at the optional arguments not passed positionally. - // The variable 'index' is counting the signatures optional arguments, the - // variable 'next' is set to the next optional arguments to look at and - // is used to skip some optional arguments. - int next = selector.positionalArgumentCount; - int index = signature.requiredParameterCount; - signature.forEachOptionalParameter((Element element) { - // If some optional parameters were passed positionally these have - // already been filled. - if (index == next) { - assert(result.types[index] == null); - HType type = null; - if (hasNamedArguments && - selector.namedArguments.indexOf(element.name) >= 0) { - type = types[nextTypeIndex++]; - } else { - type = defaultValueTypes.typeFor(element.name); - } - result.types[index] = type; - next++; - } - index++; - }); - return result; - } - - String toString() => - allUnknown ? "HTypeList.ALL_UNKNOWN" : "HTypeList $types"; -} - -class FieldTypesRegistry { - final JavaScriptBackend backend; - - /** - * For each class, [constructors] holds the set of constructors. If there is - * more than one constructor for a class it is currently not possible to - * infer the field types from construction, as the information collected does - * not correlate the generative constructors and generative constructor - * body/bodies. - */ - final Map<ClassElement, Set<Element>> constructors; - - /** - * The collected type information is stored in three maps. One for types - * assigned in the initializer list(s) [fieldInitializerTypeMap], one for - * types assigned in the constructor(s) [fieldConstructorTypeMap], and one - * for types assigned in the rest of the code, where the field can be - * resolved [fieldTypeMap]. - * - * If a field has a type both from constructors and from the initializer - * list(s), then the type from the constructor(s) will owerride the one from - * the initializer list(s). - * - * Because the order in which generative constructors, generative constructor - * bodies and normal method/function bodies are compiled is undefined, and - * because they can all be recompiled, it is not possible to combine this - * information into one map at the moment. - */ - final Map<Element, HType> fieldInitializerTypeMap; - final Map<Element, HType> fieldConstructorTypeMap; - final Map<Element, HType> fieldTypeMap; - - /** - * The set of current names setter selectors used. If a named selector is - * used it is currently not possible to infer the type of the field. - */ - final Set<SourceString> setterSelectorsUsed; - - final Map<Element, Set<Element>> optimizedStaticFunctions; - final Map<Element, FunctionSet> optimizedFunctions; - - FieldTypesRegistry(JavaScriptBackend backend) - : constructors = new Map<ClassElement, Set<Element>>(), - fieldInitializerTypeMap = new Map<Element, HType>(), - fieldConstructorTypeMap = new Map<Element, HType>(), - fieldTypeMap = new Map<Element, HType>(), - setterSelectorsUsed = new Set<SourceString>(), - optimizedStaticFunctions = new Map<Element, Set<Element>>(), - optimizedFunctions = new Map<Element, FunctionSet>(), - this.backend = backend; - - Compiler get compiler => backend.compiler; - - void scheduleRecompilation(Element field) { - Set optimizedStatics = optimizedStaticFunctions[field]; - if (optimizedStatics != null) { - optimizedStatics.forEach(backend.scheduleForRecompilation); - optimizedStaticFunctions.remove(field); - } - FunctionSet optimized = optimizedFunctions[field]; - if (optimized != null) { - optimized.forEach(backend.scheduleForRecompilation); - optimizedFunctions.remove(field); - } - } - - int constructorCount(Element element) { - assert(element.isClass()); - Set<Element> ctors = constructors[element]; - return ctors == null ? 0 : ctors.length; - } - - void registerFieldType(Map<Element, HType> typeMap, - Element field, - HType type) { - assert(field.isField()); - HType before = optimisticFieldType(field); - - HType oldType = typeMap[field]; - HType newType; - - if (oldType != null) { - newType = oldType.union(type, compiler); - } else { - newType = type; - } - typeMap[field] = newType; - if (oldType != newType) { - scheduleRecompilation(field); - } - } - - void registerConstructor(Element element) { - assert(element.isGenerativeConstructor()); - Element cls = element.getEnclosingClass(); - constructors.putIfAbsent(cls, () => new Set<Element>()); - Set<Element> ctors = constructors[cls]; - if (ctors.contains(element)) return; - ctors.add(element); - // We cannot infer field types for classes with more than one constructor. - // When the second constructor is seen, recompile all functions relying on - // optimistic field types for that class. - // TODO(sgjesse): Handle field types for classes with more than one - // constructor. - if (ctors.length == 2) { - optimizedFunctions.forEach((Element field, _) { - if (identical(field.enclosingElement, cls)) { - scheduleRecompilation(field); - } - }); - } - } - - void registerFieldInitializer(Element field, HType type) { - registerFieldType(fieldInitializerTypeMap, field, type); - } - - void registerFieldConstructor(Element field, HType type) { - registerFieldType(fieldConstructorTypeMap, field, type); - } - - void registerFieldSetter(FunctionElement element, Element field, HType type) { - HType initializerType = fieldInitializerTypeMap[field]; - HType constructorType = fieldConstructorTypeMap[field]; - HType setterType = fieldTypeMap[field]; - if (type == HType.UNKNOWN - && initializerType == null - && constructorType == null - && setterType == null) { - // Don't register UNKONWN if there is currently no type information - // present for the field. Instead register the function holding the - // setter for recompilation if better type information for the field - // becomes available. - registerOptimizedFunction(element, field, type); - return; - } - registerFieldType(fieldTypeMap, field, type); - } - - void addedDynamicSetter(Selector setter, HType type) { - // Field type optimizations are disabled for all fields matching a - // setter selector. - assert(setter.isSetter()); - // TODO(sgjesse): Take the type of the setter into account. - if (setterSelectorsUsed.contains(setter.name)) return; - setterSelectorsUsed.add(setter.name); - optimizedStaticFunctions.forEach((Element field, _) { - if (field.name == setter.name) { - scheduleRecompilation(field); - } - }); - optimizedFunctions.forEach((Element field, _) { - if (field.name == setter.name) { - scheduleRecompilation(field); - } - }); - } - - HType optimisticFieldType(Element field) { - assert(field.isField()); - if (constructorCount(field.getEnclosingClass()) > 1) { - return HType.UNKNOWN; - } - if (setterSelectorsUsed.contains(field.name)) { - return HType.UNKNOWN; - } - HType initializerType = fieldInitializerTypeMap[field]; - HType constructorType = fieldConstructorTypeMap[field]; - if (initializerType == null && constructorType == null) { - // If there are no constructor type information return UNKNOWN. This - // ensures that the function will be recompiled if useful constructor - // type information becomes available. - return HType.UNKNOWN; - } - // A type set through the constructor overrides the type from the - // initializer list. - HType result = constructorType != null ? constructorType : initializerType; - HType type = fieldTypeMap[field]; - if (type != null) result = result.union(type, compiler); - return result; - } - - void registerOptimizedFunction(FunctionElement element, - Element field, - HType type) { - assert(field.isField()); - if (Elements.isStaticOrTopLevel(element)) { - optimizedStaticFunctions.putIfAbsent( - field, () => new Set<Element>()); - optimizedStaticFunctions[field].add(element); - } else { - optimizedFunctions.putIfAbsent( - field, () => new FunctionSet(backend.compiler)); - optimizedFunctions[field].add(element); - } - } - - void dump() { - Set<Element> allFields = new Set<Element>(); - fieldInitializerTypeMap.keys.forEach(allFields.add); - fieldConstructorTypeMap.keys.forEach(allFields.add); - fieldTypeMap.keys.forEach(allFields.add); - allFields.forEach((Element field) { - print("Inferred $field has type ${optimisticFieldType(field)}"); - }); - } -} - -class ArgumentTypesRegistry { - final JavaScriptBackend backend; - - /** - * Documentation wanted -- johnniwinther - * - * Invariant: Keys must be declaration elements. - */ - final Map<Element, HTypeList> staticTypeMap; - - /** - * Documentation wanted -- johnniwinther - * - * Invariant: Elements must be declaration elements. - */ - final Set<Element> optimizedStaticFunctions; - final SelectorMap<HTypeList> selectorTypeMap; - final FunctionSet optimizedFunctions; - - /** - * Documentation wanted -- johnniwinther - * - * Invariant: Keys must be declaration elements. - */ - final Map<Element, HTypeList> optimizedTypes; - final Map<Element, OptionalParameterTypes> optimizedDefaultValueTypes; - - ArgumentTypesRegistry(JavaScriptBackend backend) - : staticTypeMap = new Map<Element, HTypeList>(), - optimizedStaticFunctions = new Set<Element>(), - selectorTypeMap = new SelectorMap<HTypeList>(backend.compiler), - optimizedFunctions = new FunctionSet(backend.compiler), - optimizedTypes = new Map<Element, HTypeList>(), - optimizedDefaultValueTypes = - new Map<Element, OptionalParameterTypes>(), - this.backend = backend; - - Compiler get compiler => backend.compiler; - - bool updateTypes(HTypeList oldTypes, HTypeList newTypes, var key, var map) { - if (oldTypes.allUnknown) return false; - newTypes = oldTypes.union(newTypes, backend.compiler); - if (identical(newTypes, oldTypes)) return false; - map[key] = newTypes; - return true; - } - - void registerStaticInvocation(HInvokeStatic node, HTypeMap types) { - Element element = node.element; - assert(invariant(node, element.isDeclaration)); - HTypeList oldTypes = staticTypeMap[element]; - HTypeList newTypes = new HTypeList.fromStaticInvocation(node, types); - if (oldTypes == null) { - staticTypeMap[element] = newTypes; - } else if (updateTypes(oldTypes, newTypes, element, staticTypeMap)) { - if (optimizedStaticFunctions.contains(element)) { - backend.scheduleForRecompilation(element); - } - } - } - - void registerNonCallStaticUse(HStatic node) { - // When a static is used for anything else than a call target we cannot - // infer anything about its parameter types. - Element element = node.element; - assert(invariant(node, element.isDeclaration)); - if (optimizedStaticFunctions.contains(element)) { - backend.scheduleForRecompilation(element); - } - staticTypeMap[element] = HTypeList.ALL_UNKNOWN; - } - - void registerDynamicInvocation(HTypeList providedTypes, Selector selector) { - if (selector.isClosureCall()) { - // We cannot use the current framework to do optimizations based - // on the 'call' selector because we are also generating closure - // calls during the emitter phase, which at this point, does not - // track parameter types, nor invalidates optimized methods. - return; - } - if (!selectorTypeMap.containsKey(selector)) { - selectorTypeMap[selector] = providedTypes; - } else { - HTypeList oldTypes = selectorTypeMap[selector]; - updateTypes(oldTypes, providedTypes, selector, selectorTypeMap); - } - - // If we're not compiling, we don't have to do anything. - if (compiler.phase != Compiler.PHASE_COMPILING) return; - - // Run through all optimized functions and figure out if they need - // to be recompiled because of this new invocation. - optimizedFunctions.filterBySelector(selector).forEach((Element element) { - // TODO(kasperl): Maybe check if the element is already marked for - // recompilation? Could be pretty cheap compared to computing - // union types. - HTypeList newTypes = - parameterTypes(element, optimizedDefaultValueTypes[element]); - bool recompile = false; - if (newTypes.allUnknown) { - recompile = true; - } else { - HTypeList oldTypes = optimizedTypes[element]; - assert(newTypes.length == oldTypes.length); - for (int i = 0; i < oldTypes.length; i++) { - if (newTypes[i] != oldTypes[i]) { - recompile = true; - break; - } - } - } - if (recompile) backend.scheduleForRecompilation(element); - }); - } - - HTypeList parameterTypes(FunctionElement element, - OptionalParameterTypes defaultValueTypes) { - assert(invariant(element, element.isDeclaration)); - // Handle static functions separately. - if (Elements.isStaticOrTopLevelFunction(element) || - element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { - HTypeList types = staticTypeMap[element]; - if (types != null) { - if (!optimizedStaticFunctions.contains(element)) { - optimizedStaticFunctions.add(element); - } - return types; - } else { - return HTypeList.ALL_UNKNOWN; - } - } - - // Getters have no parameters. - if (element.isGetter()) return HTypeList.ALL_UNKNOWN; - - // TODO(kasperl): What kind of non-members do we get here? - if (!element.isMember()) return HTypeList.ALL_UNKNOWN; - - // If there are any getters for this method we cannot know anything about - // the types of the provided parameters. Use resolverWorld for now as that - // information does not change during compilation. - // TODO(ngeoffray): These checks should use the codegenWorld and keep track - // of changes to this information. - if (compiler.resolverWorld.hasInvokedGetter(element, compiler)) { - return HTypeList.ALL_UNKNOWN; - } - - FunctionSignature signature = element.computeSignature(compiler); - HTypeList found = null; - selectorTypeMap.visitMatching(element, - (Selector selector, HTypeList types) { - if (selector.argumentCount != signature.parameterCount || - selector.namedArgumentCount > 0) { - types = types.unionWithOptionalParameters(selector, - signature, - defaultValueTypes); - } - assert(types.allUnknown || types.length == signature.parameterCount); - found = (found == null) ? types : found.union(types, compiler); - return !found.allUnknown; - }); - return found != null ? found : HTypeList.ALL_UNKNOWN; - } - - void registerOptimizedFunction(Element element, - HTypeList parameterTypes, - OptionalParameterTypes defaultValueTypes) { - if (Elements.isStaticOrTopLevelFunction(element)) { - if (parameterTypes.allUnknown) { - optimizedStaticFunctions.remove(element); - } else { - optimizedStaticFunctions.add(element); - } - } - - // TODO(kasperl): What kind of non-members do we get here? - if (!element.isMember()) return; - - if (parameterTypes.allUnknown) { - optimizedFunctions.remove(element); - optimizedTypes.remove(element); - optimizedDefaultValueTypes.remove(element); - } else { - optimizedFunctions.add(element); - optimizedTypes[element] = parameterTypes; - optimizedDefaultValueTypes[element] = defaultValueTypes; - } - } - - void dump() { - optimizedFunctions.forEach((Element element) { - HTypeList types = optimizedTypes[element]; - print("Inferred $element has argument types ${types.types}"); - }); - } -} - -class JavaScriptItemCompilationContext extends ItemCompilationContext { - final HTypeMap types; - final Set<HInstruction> boundsChecked; - - JavaScriptItemCompilationContext() - : types = new HTypeMap(), - boundsChecked = new Set<HInstruction>(); -} - -class JavaScriptBackend extends Backend { - SsaBuilderTask builder; - SsaOptimizerTask optimizer; - SsaCodeGeneratorTask generator; - CodeEmitterTask emitter; - - /** - * The generated code as a js AST for compiled methods. - */ - Map<Element, js.Expression> get generatedCode { - return compiler.enqueuer.codegen.generatedCode; - } - - /** - * The generated code as a js AST for compiled bailout methods. - */ - final Map<Element, js.Expression> generatedBailoutCode = - new Map<Element, js.Expression>(); - - ClassElement jsStringClass; - ClassElement jsArrayClass; - ClassElement jsNumberClass; - ClassElement jsIntClass; - ClassElement jsDoubleClass; - ClassElement jsFunctionClass; - ClassElement jsNullClass; - ClassElement jsBoolClass; - ClassElement objectInterceptorClass; - Element jsArrayLength; - Element jsStringLength; - Element jsArrayRemoveLast; - Element jsArrayAdd; - Element jsStringSplit; - Element jsStringConcat; - Element jsStringToString; - Element getInterceptorMethod; - Element fixedLengthListConstructor; - bool seenAnyClass = false; - - final Namer namer; - - /** - * Interface used to determine if an object has the JavaScript - * indexing behavior. The interface is only visible to specific - * libraries. - */ - ClassElement jsIndexingBehaviorInterface; - - final Map<Element, ReturnInfo> returnInfo; - - /** - * Documentation wanted -- johnniwinther - * - * Invariant: Elements must be declaration elements. - */ - final List<Element> invalidateAfterCodegen; - ArgumentTypesRegistry argumentTypes; - FieldTypesRegistry fieldTypes; - - /** - * A collection of selectors of intercepted method calls. The - * emitter uses this set to generate the [:ObjectInterceptor:] class - * whose members just forward the call to the intercepted receiver. - */ - final Set<Selector> usedInterceptors; - - /** - * A collection of selectors that must have a one shot interceptor - * generated. - */ - final Set<Selector> oneShotInterceptors; - - /** - * The members of instantiated interceptor classes: maps a member - * name to the list of members that have that name. This map is used - * by the codegen to know whether a send must be intercepted or not. - */ - final Map<SourceString, Set<Element>> interceptedElements; - - /** - * A map of specialized versions of the [getInterceptorMethod]. - * Since [getInterceptorMethod] is a hot method at runtime, we're - * always specializing it based on the incoming type. The keys in - * the map are the names of these specialized versions. Note that - * the generic version that contains all possible type checks is - * also stored in this map. - */ - final Map<String, Collection<ClassElement>> specializedGetInterceptors; - - /** - * Set of classes whose instances are intercepted. Implemented as a - * [LinkedHashMap] to preserve the insertion order. - * TODO(ngeoffray): No need to preserve order anymore. - */ - final Map<ClassElement, ClassElement> interceptedClasses; - - List<CompilerTask> get tasks { - return <CompilerTask>[builder, optimizer, generator, emitter]; - } - - final RuntimeTypeInformation rti; - - JavaScriptBackend(Compiler compiler, bool generateSourceMap, bool disableEval) - : namer = determineNamer(compiler), - returnInfo = new Map<Element, ReturnInfo>(), - invalidateAfterCodegen = new List<Element>(), - usedInterceptors = new Set<Selector>(), - oneShotInterceptors = new Set<Selector>(), - interceptedElements = new Map<SourceString, Set<Element>>(), - rti = new RuntimeTypeInformation(compiler), - specializedGetInterceptors = - new Map<String, Collection<ClassElement>>(), - interceptedClasses = new LinkedHashMap<ClassElement, ClassElement>(), - super(compiler, JAVA_SCRIPT_CONSTANT_SYSTEM) { - emitter = disableEval - ? new CodeEmitterNoEvalTask(compiler, namer, generateSourceMap) - : new CodeEmitterTask(compiler, namer, generateSourceMap); - builder = new SsaBuilderTask(this); - optimizer = new SsaOptimizerTask(this); - generator = new SsaCodeGeneratorTask(this); - argumentTypes = new ArgumentTypesRegistry(this); - fieldTypes = new FieldTypesRegistry(this); - } - - static Namer determineNamer(Compiler compiler) { - return compiler.enableMinification ? - new MinifyNamer(compiler) : - new Namer(compiler); - } - - bool isInterceptorClass(Element element) { - if (element == null) return false; - return interceptedClasses.containsKey(element); - } - - void addInterceptedSelector(Selector selector) { - usedInterceptors.add(selector); - } - - void addOneShotInterceptor(Selector selector) { - oneShotInterceptors.add(selector); - } - - /** - * Returns a set of interceptor classes that contain a member whose - * signature matches the given [selector]. Returns [:null:] if there - * is no class. - */ - Set<ClassElement> getInterceptedClassesOn(Selector selector) { - Set<Element> intercepted = interceptedElements[selector.name]; - if (intercepted == null) return null; - Set<ClassElement> result = new Set<ClassElement>(); - for (Element element in intercepted) { - if (selector.applies(element, compiler)) { - result.add(element.getEnclosingClass()); - } - } - if (result.isEmpty) return null; - return result; - } - - List<ClassElement> getListOfInterceptedClasses() { - return <ClassElement>[jsStringClass, jsArrayClass, jsIntClass, - jsDoubleClass, jsNumberClass, jsNullClass, - jsFunctionClass, jsBoolClass]; - } - - void initializeInterceptorElements() { - objectInterceptorClass = - compiler.findInterceptor(const SourceString('ObjectInterceptor')); - getInterceptorMethod = - compiler.findInterceptor(const SourceString('getInterceptor')); - List<ClassElement> classes = [ - jsStringClass = compiler.findInterceptor(const SourceString('JSString')), - jsArrayClass = compiler.findInterceptor(const SourceString('JSArray')), - // The int class must be before the double class, because the - // emitter relies on this list for the order of type checks. - jsIntClass = compiler.findInterceptor(const SourceString('JSInt')), - jsDoubleClass = compiler.findInterceptor(const SourceString('JSDouble')), - jsNumberClass = compiler.findInterceptor(const SourceString('JSNumber')), - jsNullClass = compiler.findInterceptor(const SourceString('JSNull')), - jsFunctionClass = - compiler.findInterceptor(const SourceString('JSFunction')), - jsBoolClass = compiler.findInterceptor(const SourceString('JSBool'))]; - - jsArrayClass.ensureResolved(compiler); - jsArrayLength = compiler.lookupElementIn( - jsArrayClass, const SourceString('length')); - jsArrayRemoveLast = compiler.lookupElementIn( - jsArrayClass, const SourceString('removeLast')); - jsArrayAdd = compiler.lookupElementIn( - jsArrayClass, const SourceString('add')); - - jsStringClass.ensureResolved(compiler); - jsStringLength = compiler.lookupElementIn( - jsStringClass, const SourceString('length')); - jsStringSplit = compiler.lookupElementIn( - jsStringClass, const SourceString('split')); - jsStringConcat = compiler.lookupElementIn( - jsStringClass, const SourceString('concat')); - jsStringToString = compiler.lookupElementIn( - jsStringClass, const SourceString('toString')); - - for (ClassElement cls in classes) { - if (cls != null) interceptedClasses[cls] = null; - } - } - - void addInterceptors(ClassElement cls, Enqueuer enqueuer) { - if (enqueuer.isResolutionQueue) { - cls.ensureResolved(compiler); - cls.forEachMember((ClassElement classElement, Element member) { - Set<Element> set = interceptedElements.putIfAbsent( - member.name, () => new Set<Element>()); - set.add(member); - }, - includeSuperMembers: true); - } - enqueuer.registerInstantiatedClass(cls); - } - - void registerSpecializedGetInterceptor(Set<ClassElement> classes) { - compiler.enqueuer.codegen.registerInstantiatedClass(objectInterceptorClass); - String name = namer.getInterceptorName(getInterceptorMethod, classes); - if (classes.contains(compiler.objectClass)) { - // We can't use a specialized [getInterceptorMethod], so we make - // sure we emit the one with all checks. - specializedGetInterceptors.putIfAbsent(name, () { - // It is important to take the order provided by the map, - // because we want the int type check to happen before the - // double type check: the double type check covers the int - // type check. Also we don't need to do a number type check - // because that is covered by the double type check. - List<ClassElement> keys = <ClassElement>[]; - interceptedClasses.forEach((ClassElement cls, _) { - if (cls != jsNumberClass) keys.add(cls); - }); - return keys; - }); - } else { - specializedGetInterceptors[name] = classes; - } - } - - void initializeNoSuchMethod() { - // In case the emitter generates noSuchMethod calls, we need to - // make sure all [noSuchMethod] methods know they might take a - // [JsInvocationMirror] as parameter. - HTypeList types = new HTypeList(1); - types[0] = new HType.fromBoundedType( - compiler.jsInvocationMirrorClass.computeType(compiler), - compiler, - false); - argumentTypes.registerDynamicInvocation(types, new Selector.noSuchMethod()); - } - - void registerInstantiatedClass(ClassElement cls, Enqueuer enqueuer) { - if (!seenAnyClass) { - initializeInterceptorElements(); - initializeNoSuchMethod(); - seenAnyClass = true; - } - ClassElement result = null; - if (cls == compiler.stringClass) { - addInterceptors(jsStringClass, enqueuer); - } else if (cls == compiler.listClass) { - addInterceptors(jsArrayClass, enqueuer); - // The backend will try to optimize array access and use the - // `ioore` and `iae` helpers directly. - if (enqueuer.isResolutionQueue) { - enqueuer.registerStaticUse( - compiler.findHelper(const SourceString('ioore'))); - enqueuer.registerStaticUse( - compiler.findHelper(const SourceString('iae'))); - } - } else if (cls == compiler.intClass) { - addInterceptors(jsIntClass, enqueuer); - addInterceptors(jsNumberClass, enqueuer); - } else if (cls == compiler.doubleClass) { - addInterceptors(jsDoubleClass, enqueuer); - addInterceptors(jsNumberClass, enqueuer); - } else if (cls == compiler.functionClass) { - addInterceptors(jsFunctionClass, enqueuer); - } else if (cls == compiler.boolClass) { - addInterceptors(jsBoolClass, enqueuer); - } else if (cls == compiler.nullClass) { - addInterceptors(jsNullClass, enqueuer); - } else if (cls == compiler.numClass) { - addInterceptors(jsIntClass, enqueuer); - addInterceptors(jsDoubleClass, enqueuer); - addInterceptors(jsNumberClass, enqueuer); - } else if (cls == compiler.mapClass) { - // The backend will use a literal list to initialize the entries - // of the map. - if (enqueuer.isResolutionQueue) { - enqueuer.registerInstantiatedClass(compiler.listClass); - } - } - } - - Element get cyclicThrowHelper { - return compiler.findHelper(const SourceString("throwCyclicInit")); - } - - JavaScriptItemCompilationContext createItemCompilationContext() { - return new JavaScriptItemCompilationContext(); - } - - void enqueueHelpers(ResolutionEnqueuer world) { - enqueueAllTopLevelFunctions(compiler.jsHelperLibrary, world); - - jsIndexingBehaviorInterface = - compiler.findHelper(const SourceString('JavaScriptIndexingBehavior')); - if (jsIndexingBehaviorInterface != null) { - world.registerIsCheck(jsIndexingBehaviorInterface.computeType(compiler)); - } - - for (var helper in [const SourceString('Closure'), - const SourceString('ConstantMap'), - const SourceString('ConstantProtoMap')]) { - var e = compiler.findHelper(helper); - if (e != null) world.registerInstantiatedClass(e); - } - } - - void codegen(CodegenWorkItem work) { - Element element = work.element; - if (element.kind.category == ElementCategory.VARIABLE) { - Constant initialValue = compiler.constantHandler.compileWorkItem(work); - if (initialValue != null) { - return; - } else { - // If the constant-handler was not able to produce a result we have to - // go through the builder (below) to generate the lazy initializer for - // the static variable. - // We also need to register the use of the cyclic-error helper. - compiler.enqueuer.codegen.registerStaticUse(cyclicThrowHelper); - } - } - - HGraph graph = builder.build(work); - optimizer.optimize(work, graph, false); - if (work.allowSpeculativeOptimization - && optimizer.trySpeculativeOptimizations(work, graph)) { - js.Expression code = generator.generateBailoutMethod(work, graph); - generatedBailoutCode[element] = code; - optimizer.prepareForSpeculativeOptimizations(work, graph); - optimizer.optimize(work, graph, true); - } - js.Expression code = generator.generateCode(work, graph); - generatedCode[element] = code; - invalidateAfterCodegen.forEach(eagerRecompile); - invalidateAfterCodegen.clear(); - } - - native.NativeEnqueuer nativeResolutionEnqueuer(Enqueuer world) { - return new native.NativeResolutionEnqueuer(world, compiler); - } - - native.NativeEnqueuer nativeCodegenEnqueuer(Enqueuer world) { - return new native.NativeCodegenEnqueuer(world, compiler, emitter); - } - - /** - * Unit test hook that returns code of an element as a String. - * - * Invariant: [element] must be a declaration element. - */ - String assembleCode(Element element) { - assert(invariant(element, element.isDeclaration)); - return js.prettyPrint(generatedCode[element], compiler).getText(); - } - - void assembleProgram() { - emitter.assembleProgram(); - } - - /** - * Documentation wanted -- johnniwinther - * - * Invariant: [element] must be a declaration element. - */ - void scheduleForRecompilation(Element element) { - assert(invariant(element, element.isDeclaration)); - if (compiler.phase == Compiler.PHASE_COMPILING) { - invalidateAfterCodegen.add(element); - } - } - - /** - * Register a dynamic invocation and collect the provided types for the - * named selector. - */ - void registerDynamicInvocation(HInvokeDynamic node, - Selector selector, - HTypeMap types) { - HTypeList providedTypes = - new HTypeList.fromDynamicInvocation(node, selector, types); - argumentTypes.registerDynamicInvocation(providedTypes, selector); - } - - /** - * Register a static invocation and collect the provided types for the - * named selector. - */ - void registerStaticInvocation(HInvokeStatic node, HTypeMap types) { - argumentTypes.registerStaticInvocation(node, types); - } - - /** - * Register that a static is used for something else than a direct call - * target. - */ - void registerNonCallStaticUse(HStatic node) { - argumentTypes.registerNonCallStaticUse(node); - } - - /** - * Retrieve the types of the parameters used for calling the [element] - * function. The types are optimistic in the sense as they are based on the - * possible invocations of the function seen so far. - * - * Invariant: [element] must be a declaration element. - */ - HTypeList optimisticParameterTypes( - FunctionElement element, - OptionalParameterTypes defaultValueTypes) { - assert(invariant(element, element.isDeclaration)); - if (element.parameterCount(compiler) == 0) return HTypeList.ALL_UNKNOWN; - return argumentTypes.parameterTypes(element, defaultValueTypes); - } - - /** - * Register that the function [element] has been optimized under the - * assumptions that the types [parameterType] will be used for calling it. - * The passed [defaultValueTypes] holds the types of default values for - * the optional parameters. If this assumption fail the function will be - * scheduled for recompilation. - * - * Invariant: [element] must be a declaration element. - */ - registerParameterTypesOptimization( - FunctionElement element, - HTypeList parameterTypes, - OptionalParameterTypes defaultValueTypes) { - assert(invariant(element, element.isDeclaration)); - if (element.parameterCount(compiler) == 0) return; - argumentTypes.registerOptimizedFunction( - element, parameterTypes, defaultValueTypes); - } - - registerFieldTypesOptimization(FunctionElement element, - Element field, - HType type) { - fieldTypes.registerOptimizedFunction(element, field, type); - } - - /** - * Documentation wanted -- johnniwinther - * - * Invariant: [element] must be a declaration element. - */ - void registerReturnType(FunctionElement element, HType returnType) { - assert(invariant(element, element.isDeclaration)); - ReturnInfo info = returnInfo[element]; - if (info != null) { - info.update(returnType, scheduleForRecompilation, compiler); - } else { - returnInfo[element] = new ReturnInfo(returnType); - } - } - - /** - * Retrieve the return type of the function [callee]. The type is optimistic - * in the sense that is is based on the compilation of [callee]. If [callee] - * is recompiled the return type might change to someting broader. For that - * reason [caller] is registered for recompilation if this happens. If the - * function [callee] has not yet been compiled the returned type is [null]. - * - * Invariant: Both [caller] and [callee] must be declaration elements. - */ - HType optimisticReturnTypesWithRecompilationOnTypeChange( - Element caller, FunctionElement callee) { - assert(invariant(callee, callee.isDeclaration)); - returnInfo.putIfAbsent(callee, () => new ReturnInfo.unknownType()); - ReturnInfo info = returnInfo[callee]; - HType returnType = info.returnType; - if (returnType != HType.UNKNOWN && returnType != null && caller != null) { - assert(invariant(caller, caller.isDeclaration)); - info.addCompiledFunction(caller); - } - return info.returnType; - } - - void dumpReturnTypes() { - returnInfo.forEach((Element element, ReturnInfo info) { - if (info.returnType != HType.UNKNOWN) { - print("Inferred $element has return type ${info.returnType}"); - } - }); - } - - void registerConstructor(Element element) { - fieldTypes.registerConstructor(element); - } - - void registerFieldInitializer(Element field, HType type) { - fieldTypes.registerFieldInitializer(field, type); - } - - void registerFieldConstructor(Element field, HType type) { - fieldTypes.registerFieldConstructor(field, type); - } - - void registerFieldSetter(FunctionElement element, Element field, HType type) { - fieldTypes.registerFieldSetter(element, field, type); - } - - void addedDynamicSetter(Selector setter, HType type) { - fieldTypes.addedDynamicSetter(setter, type); - } - - HType optimisticFieldType(Element element) { - return fieldTypes.optimisticFieldType(element); - } - - /** - * Return the checked mode helper name that will be needed to do a - * type check on [type] at runtime. Note that this method is being - * called both by the resolver with interface types (int, String, - * ...), and by the SSA backend with implementation types (JSInt, - * JSString, ...). - */ - SourceString getCheckedModeHelper(DartType type) { - Element element = type.element; - bool nativeCheck = - emitter.nativeEmitter.requiresNativeIsCheck(element); - if (type.isMalformed) { - // Check for malformed types first, because the type may be a list type - // with a malformed argument type. - return const SourceString('malformedTypeCheck'); - } else if (type == compiler.types.voidType) { - return const SourceString('voidTypeCheck'); - } else if (element == jsStringClass || element == compiler.stringClass) { - return const SourceString('stringTypeCheck'); - } else if (element == jsDoubleClass || element == compiler.doubleClass) { - return const SourceString('doubleTypeCheck'); - } else if (element == jsNumberClass || element == compiler.numClass) { - return const SourceString('numTypeCheck'); - } else if (element == jsBoolClass || element == compiler.boolClass) { - return const SourceString('boolTypeCheck'); - } else if (element == jsFunctionClass - || element == compiler.functionClass) { - return const SourceString('functionTypeCheck'); - } else if (element == jsIntClass || element == compiler.intClass) { - return const SourceString('intTypeCheck'); - } else if (Elements.isNumberOrStringSupertype(element, compiler)) { - return nativeCheck - ? const SourceString('numberOrStringSuperNativeTypeCheck') - : const SourceString('numberOrStringSuperTypeCheck'); - } else if (Elements.isStringOnlySupertype(element, compiler)) { - return nativeCheck - ? const SourceString('stringSuperNativeTypeCheck') - : const SourceString('stringSuperTypeCheck'); - } else if (element == compiler.listClass || element == jsArrayClass) { - return const SourceString('listTypeCheck'); - } else { - if (Elements.isListSupertype(element, compiler)) { - return nativeCheck - ? const SourceString('listSuperNativeTypeCheck') - : const SourceString('listSuperTypeCheck'); - } else { - return nativeCheck - ? const SourceString('callTypeCheck') - : const SourceString('propertyTypeCheck'); - } - } - } - - void dumpInferredTypes() { - print("Inferred argument types:"); - print("------------------------"); - argumentTypes.dump(); - print(""); - print("Inferred return types:"); - print("----------------------"); - dumpReturnTypes(); - print(""); - print("Inferred field types:"); - print("------------------------"); - fieldTypes.dump(); - print(""); - } - - Element getExceptionUnwrapper() { - return compiler.findHelper(const SourceString('unwrapException')); - } - - Element getThrowRuntimeError() { - return compiler.findHelper(const SourceString('throwRuntimeError')); - } - - Element getThrowMalformedSubtypeError() { - return compiler.findHelper( - const SourceString('throwMalformedSubtypeError')); - } - - Element getThrowAbstractClassInstantiationError() { - return compiler.findHelper( - const SourceString('throwAbstractClassInstantiationError')); - } - - Element getClosureConverter() { - return compiler.findHelper(const SourceString('convertDartClosureToJS')); - } - - Element getTraceFromException() { - return compiler.findHelper(const SourceString('getTraceFromException')); - } - - Element getMapMaker() { - return compiler.findHelper(const SourceString('makeLiteralMap')); - } - - Element getSetRuntimeTypeInfo() { - return compiler.findHelper(const SourceString('setRuntimeTypeInfo')); - } - - Element getGetRuntimeTypeInfo() { - return compiler.findHelper(const SourceString('getRuntimeTypeInfo')); - } - - /** - * Remove [element] from the set of generated code, and put it back - * into the worklist. - * - * Invariant: [element] must be a declaration element. - */ - void eagerRecompile(Element element) { - assert(invariant(element, element.isDeclaration)); - generatedCode.remove(element); - generatedBailoutCode.remove(element); - compiler.enqueuer.codegen.addToWorkList(element); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/constant_emitter.dart b/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/constant_emitter.dart deleted file mode 100644 index 86717ae..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/constant_emitter.dart +++ /dev/null
@@ -1,325 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of js_backend; - -class ConstantEmitter { - ConstantReferenceEmitter _referenceEmitter; - ConstantInitializerEmitter _initializerEmitter; - - ConstantEmitter(Compiler compiler, Namer namer) { - _referenceEmitter = new ConstantReferenceEmitter(compiler, namer); - _initializerEmitter = new ConstantInitializerEmitter( - compiler, namer, _referenceEmitter); - } - - /** - * Constructs an expression that is a reference to the constant. Uses a - * canonical name unless the constant can be emitted multiple times (as for - * numbers and strings). - */ - js.Expression reference(Constant constant) { - return _referenceEmitter.generate(constant); - } - - /** - * Constructs an expression like [reference], but the expression is valid - * during isolate initialization. - */ - js.Expression referenceInInitializationContext(Constant constant) { - return _referenceEmitter.generateInInitializationContext(constant); - } - - /** - * Constructs an expression used to initialize a canonicalized constant. - */ - js.Expression initializationExpression(Constant constant) { - return _initializerEmitter.generate(constant); - } -} - -/** - * Visitor for generating JavaScript expressions to refer to [Constant]s. - * Do not use directly, use methods from [ConstantEmitter]. - */ -class ConstantReferenceEmitter implements ConstantVisitor<js.Expression> { - final Compiler compiler; - final Namer namer; - bool inIsolateInitializationContext = false; - - ConstantReferenceEmitter(this.compiler, this.namer); - - js.Expression generate(Constant constant) { - inIsolateInitializationContext = false; - return _visit(constant); - } - - js.Expression generateInInitializationContext(Constant constant) { - inIsolateInitializationContext = true; - return _visit(constant); - } - - js.Expression _visit(Constant constant) { - return constant.accept(this); - } - - js.Expression visitSentinel(SentinelConstant constant) { - return new js.VariableUse(namer.CURRENT_ISOLATE); - } - - js.Expression visitFunction(FunctionConstant constant) { - return inIsolateInitializationContext - ? new js.VariableUse(namer.isolatePropertiesAccess(constant.element)) - : new js.VariableUse(namer.isolateAccess(constant.element)); - } - - js.Expression visitNull(NullConstant constant) { - return new js.LiteralNull(); - } - - js.Expression visitInt(IntConstant constant) { - return new js.LiteralNumber('${constant.value}'); - } - - js.Expression visitDouble(DoubleConstant constant) { - double value = constant.value; - if (value.isNaN) { - return new js.LiteralNumber("(0/0)"); - } else if (value == double.INFINITY) { - return new js.LiteralNumber("(1/0)"); - } else if (value == -double.INFINITY) { - return new js.LiteralNumber("(-1/0)"); - } else { - return new js.LiteralNumber("$value"); - } - } - - js.Expression visitTrue(TrueConstant constant) { - if (compiler.enableMinification) { - // Use !0 for true. - return new js.Prefix("!", new js.LiteralNumber("0")); - } else { - return new js.LiteralBool(true); - } - - } - - js.Expression visitFalse(FalseConstant constant) { - if (compiler.enableMinification) { - // Use !1 for false. - return new js.Prefix("!", new js.LiteralNumber("1")); - } else { - return new js.LiteralBool(false); - } - } - - /** - * Write the contents of the quoted string to a [CodeBuffer] in - * a form that is valid as JavaScript string literal content. - * The string is assumed quoted by double quote characters. - */ - js.Expression visitString(StringConstant constant) { - // TODO(sra): If the string is long *and repeated* (and not on a hot path) - // then it should be assigned to a name. We don't have reference counts (or - // profile information) here, so this is the wrong place. - StringBuffer sb = new StringBuffer(); - writeJsonEscapedCharsOn(constant.value.slowToString(), sb); - return new js.LiteralString('"$sb"'); - } - - js.Expression emitCanonicalVersion(Constant constant) { - String name = namer.constantName(constant); - if (inIsolateInitializationContext) { - // $isolateName.$isolatePropertiesName.$name - return new js.PropertyAccess.field( - new js.PropertyAccess.field( - new js.VariableUse(namer.isolateName), - namer.isolatePropertiesName), - name); - } else { - return new js.PropertyAccess.field( - new js.VariableUse(namer.CURRENT_ISOLATE), - name); - } - } - - js.Expression visitList(ListConstant constant) { - return emitCanonicalVersion(constant); - } - - js.Expression visitMap(MapConstant constant) { - return emitCanonicalVersion(constant); - } - - js.Expression visitType(TypeConstant constant) { - return emitCanonicalVersion(constant); - } - - js.Expression visitConstructed(ConstructedConstant constant) { - return emitCanonicalVersion(constant); - } -} - -/** - * Visitor for generating JavaScript expressions to initialize [Constant]s. - * Do not use directly; use methods from [ConstantEmitter]. - */ -class ConstantInitializerEmitter implements ConstantVisitor<js.Expression> { - final Compiler compiler; - final Namer namer; - final ConstantReferenceEmitter referenceEmitter; - - ConstantInitializerEmitter(this.compiler, this.namer, this.referenceEmitter); - - js.Expression generate(Constant constant) { - return _visit(constant); - } - - js.Expression _visit(Constant constant) { - return constant.accept(this); - } - - js.Expression _reference(Constant constant) { - return referenceEmitter.generateInInitializationContext(constant); - } - - js.Expression visitSentinel(SentinelConstant constant) { - compiler.internalError( - "The parameter sentinel constant does not need specific JS code"); - } - - js.Expression visitFunction(FunctionConstant constant) { - compiler.internalError( - "The function constant does not need specific JS code"); - } - - js.Expression visitNull(NullConstant constant) { - return _reference(constant); - } - - js.Expression visitInt(IntConstant constant) { - return _reference(constant); - } - - js.Expression visitDouble(DoubleConstant constant) { - return _reference(constant); - } - - js.Expression visitTrue(TrueConstant constant) { - return _reference(constant); - } - - js.Expression visitFalse(FalseConstant constant) { - return _reference(constant); - } - - js.Expression visitString(StringConstant constant) { - // TODO(sra): Some larger strings are worth sharing. - return _reference(constant); - } - - js.Expression visitList(ListConstant constant) { - return new js.Call( - new js.PropertyAccess.field( - new js.VariableUse(namer.isolateName), - 'makeConstantList'), - [new js.ArrayInitializer.from(_array(constant.entries))]); - } - - String getJsConstructor(ClassElement element) { - return namer.isolatePropertiesAccess(element); - } - - js.Expression visitMap(MapConstant constant) { - js.Expression jsMap() { - List<js.Property> properties = <js.Property>[]; - int valueIndex = 0; - for (int i = 0; i < constant.keys.entries.length; i++) { - StringConstant key = constant.keys.entries[i]; - if (key.value == MapConstant.PROTO_PROPERTY) continue; - - // Keys in literal maps must be emitted in place. - js.Literal keyExpression = _visit(key); - js.Expression valueExpression = - _reference(constant.values[valueIndex++]); - properties.add(new js.Property(keyExpression, valueExpression)); - } - if (valueIndex != constant.values.length) { - compiler.internalError("Bad value count."); - } - return new js.ObjectInitializer(properties); - } - - void badFieldCountError() { - compiler.internalError( - "Compiler and ConstantMap disagree on number of fields."); - } - - ClassElement classElement = constant.type.element; - - List<js.Expression> arguments = <js.Expression>[]; - - // The arguments of the JavaScript constructor for any given Dart class - // are in the same order as the members of the class element. - int emittedArgumentCount = 0; - classElement.implementation.forEachInstanceField( - (ClassElement enclosing, Element field) { - if (field.name == MapConstant.LENGTH_NAME) { - arguments.add( - new js.LiteralNumber('${constant.keys.entries.length}')); - } else if (field.name == MapConstant.JS_OBJECT_NAME) { - arguments.add(jsMap()); - } else if (field.name == MapConstant.KEYS_NAME) { - arguments.add(_reference(constant.keys)); - } else if (field.name == MapConstant.PROTO_VALUE) { - assert(constant.protoValue != null); - arguments.add(_reference(constant.protoValue)); - } else { - badFieldCountError(); - } - emittedArgumentCount++; - }, - includeBackendMembers: true, - includeSuperMembers: true); - - if ((constant.protoValue == null && emittedArgumentCount != 3) || - (constant.protoValue != null && emittedArgumentCount != 4)) { - badFieldCountError(); - } - - return new js.New( - new js.VariableUse(getJsConstructor(classElement)), - arguments); - } - - js.Expression visitType(TypeConstant constant) { - SourceString helperSourceName = const SourceString('createRuntimeType'); - Element helper = compiler.findHelper(helperSourceName); - JavaScriptBackend backend = compiler.backend; - String helperName = backend.namer.getName(helper); - DartType type = constant.representedType; - Element element = type.element; - String name = backend.rti.getRawTypeRepresentation(type); - js.Expression typeName = new js.LiteralString("'$name'"); - return new js.Call( - new js.PropertyAccess.field( - new js.VariableUse(namer.CURRENT_ISOLATE), - helperName), - [typeName]); - } - - js.Expression visitConstructed(ConstructedConstant constant) { - return new js.New( - new js.VariableUse(getJsConstructor(constant.type.element)), - _array(constant.fields)); - } - - List<js.Expression> _array(List<Constant> values) { - List<js.Expression> valueList = <js.Expression>[]; - for (int i = 0; i < values.length; i++) { - valueList.add(_reference(values[i])); - } - return valueList; - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/constant_system_javascript.dart b/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/constant_system_javascript.dart deleted file mode 100644 index 30c8bc5..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/constant_system_javascript.dart +++ /dev/null
@@ -1,240 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of js_backend; - -const JAVA_SCRIPT_CONSTANT_SYSTEM = const JavaScriptConstantSystem(); - -class JavaScriptBitNotOperation extends BitNotOperation { - const JavaScriptBitNotOperation(); - - Constant fold(Constant constant) { - if (JAVA_SCRIPT_CONSTANT_SYSTEM.isInt(constant)) { - // In JavaScript we don't check for -0 and treat it as if it was zero. - if (constant.isMinusZero()) constant = DART_CONSTANT_SYSTEM.createInt(0); - IntConstant intConstant = constant; - // We convert the result of bit-operations to 32 bit unsigned integers. - return JAVA_SCRIPT_CONSTANT_SYSTEM.createInt32(~intConstant.value); - } - return null; - } -} - -/** - * In JavaScript we truncate the result to an unsigned 32 bit integer. Also, -0 - * is treated as if it was the integer 0. - */ -class JavaScriptBinaryBitOperation implements BinaryOperation { - final BinaryBitOperation dartBitOperation; - - const JavaScriptBinaryBitOperation(this.dartBitOperation); - - bool isUserDefinable() => dartBitOperation.isUserDefinable(); - SourceString get name => dartBitOperation.name; - - Constant fold(Constant left, Constant right) { - // In JavaScript we don't check for -0 and treat it as if it was zero. - if (left.isMinusZero()) left = DART_CONSTANT_SYSTEM.createInt(0); - if (right.isMinusZero()) right = DART_CONSTANT_SYSTEM.createInt(0); - IntConstant result = dartBitOperation.fold(left, right); - if (result != null) { - // We convert the result of bit-operations to 32 bit unsigned integers. - return JAVA_SCRIPT_CONSTANT_SYSTEM.createInt32(result.value); - } - return result; - } - - apply(left, right) => dartBitOperation.apply(left, right); -} - -class JavaScriptShiftRightOperation extends JavaScriptBinaryBitOperation { - const JavaScriptShiftRightOperation() : super(const ShiftRightOperation()); - - Constant fold(Constant left, Constant right) { - // Truncate the input value to 32 bits if necessary. - if (left.isInt()) { - IntConstant intConstant = left; - int value = intConstant.value; - int truncatedValue = value & JAVA_SCRIPT_CONSTANT_SYSTEM.BITS32; - // TODO(floitsch): we should treat the input to right shifts as unsigned. - - // Sign-extend. A 32 bit complement-two value x can be computed by: - // x_u - 2^32 (where x_u is its unsigned representation). - // Example: 0xFFFFFFFF - 0x100000000 => -1. - // We simply and with the sign-bit and multiply by two. If the sign-bit - // was set, then the result is 0. Otherwise it will become 2^32. - final int SIGN_BIT = 0x80000000; - truncatedValue -= 2 * (truncatedValue & SIGN_BIT); - if (value != truncatedValue) { - left = DART_CONSTANT_SYSTEM.createInt(truncatedValue); - } - } - return super.fold(left, right); - } -} - -class JavaScriptNegateOperation implements UnaryOperation { - final NegateOperation dartNegateOperation = const NegateOperation(); - - const JavaScriptNegateOperation(); - - bool isUserDefinable() => dartNegateOperation.isUserDefinable(); - SourceString get name => dartNegateOperation.name; - - Constant fold(Constant constant) { - if (constant.isInt()) { - IntConstant intConstant = constant; - if (intConstant.value == 0) { - return JAVA_SCRIPT_CONSTANT_SYSTEM.createDouble(-0.0); - } - } - return dartNegateOperation.fold(constant); - } - apply(value) => -value; -} - -class JavaScriptBinaryArithmeticOperation implements BinaryOperation { - final BinaryOperation dartArithmeticOperation; - - const JavaScriptBinaryArithmeticOperation(this.dartArithmeticOperation); - - bool isUserDefinable() => dartArithmeticOperation.isUserDefinable(); - SourceString get name => dartArithmeticOperation.name; - - Constant fold(Constant left, Constant right) { - Constant result = dartArithmeticOperation.fold(left, right); - if (result == null) return result; - return JAVA_SCRIPT_CONSTANT_SYSTEM.convertToJavaScriptConstant(result); - } - - apply(left, right) => dartArithmeticOperation.apply(left, right); -} - -class JavaScriptIdentityOperation implements BinaryOperation { - final IdentityOperation dartIdentityOperation = const IdentityOperation(); - - const JavaScriptIdentityOperation(); - - bool isUserDefinable() => dartIdentityOperation.isUserDefinable(); - SourceString get name => dartIdentityOperation.name; - - BoolConstant fold(Constant left, Constant right) { - BoolConstant result = dartIdentityOperation.fold(left, right); - if (result == null || result.value) return result; - // In JavaScript -0.0 === 0 and all doubles are equal to their integer - // values. Furthermore NaN !== NaN. - if (left.isNum() && right.isNum()) { - NumConstant leftNum = left; - NumConstant rightNum = right; - double leftDouble = leftNum.value.toDouble(); - double rightDouble = rightNum.value.toDouble(); - return new BoolConstant(leftDouble == rightDouble); - } - return result; - } - - apply(left, right) => identical(left, right); -} - -/** - * Constant system following the semantics for Dart code that has been - * compiled to JavaScript. - */ -class JavaScriptConstantSystem extends ConstantSystem { - const int BITS31 = 0x8FFFFFFF; - const int BITS32 = 0xFFFFFFFF; - // The maximum integer value a double can represent without losing - // precision. - const int BITS53 = 0x1FFFFFFFFFFFFF; - - final add = const JavaScriptBinaryArithmeticOperation(const AddOperation()); - final bitAnd = const JavaScriptBinaryBitOperation(const BitAndOperation()); - final bitNot = const JavaScriptBitNotOperation(); - final bitOr = const JavaScriptBinaryBitOperation(const BitOrOperation()); - final bitXor = const JavaScriptBinaryBitOperation(const BitXorOperation()); - final booleanAnd = const BooleanAndOperation(); - final booleanOr = const BooleanOrOperation(); - final divide = - const JavaScriptBinaryArithmeticOperation(const DivideOperation()); - final equal = const EqualsOperation(); - final greaterEqual = const GreaterEqualOperation(); - final greater = const GreaterOperation(); - final identity = const JavaScriptIdentityOperation(); - final lessEqual = const LessEqualOperation(); - final less = const LessOperation(); - final modulo = - const JavaScriptBinaryArithmeticOperation(const ModuloOperation()); - final multiply = - const JavaScriptBinaryArithmeticOperation(const MultiplyOperation()); - final negate = const JavaScriptNegateOperation(); - final not = const NotOperation(); - final shiftLeft = - const JavaScriptBinaryBitOperation(const ShiftLeftOperation()); - final shiftRight = const JavaScriptShiftRightOperation(); - final subtract = - const JavaScriptBinaryArithmeticOperation(const SubtractOperation()); - final truncatingDivide = const JavaScriptBinaryArithmeticOperation( - const TruncatingDivideOperation()); - - const JavaScriptConstantSystem(); - - /** - * Returns true if the given [value] fits into a double without losing - * precision. - */ - bool integerFitsIntoDouble(int value) { - int absValue = value.abs(); - return (absValue & BITS53) == absValue; - } - - NumConstant convertToJavaScriptConstant(NumConstant constant) { - if (constant.isInt()) { - IntConstant intConstant = constant; - int intValue = intConstant.value; - if (!integerFitsIntoDouble(intValue)) { - return new DoubleConstant(intValue.toDouble()); - } - } else if (constant.isDouble()) { - DoubleConstant doubleResult = constant; - double doubleValue = doubleResult.value; - if (!doubleValue.isInfinite && !doubleValue.isNaN && - !constant.isMinusZero()) { - int intValue = doubleValue.toInt(); - if (intValue == doubleValue && integerFitsIntoDouble(intValue)) { - return new IntConstant(intValue); - } - } - } - return constant; - } - - NumConstant createInt(int i) - => convertToJavaScriptConstant(new IntConstant(i)); - NumConstant createInt32(int i) => new IntConstant(i & BITS32); - NumConstant createDouble(double d) - => convertToJavaScriptConstant(new DoubleConstant(d)); - StringConstant createString(DartString string, Node diagnosticNode) - => new StringConstant(string, diagnosticNode); - BoolConstant createBool(bool value) => new BoolConstant(value); - NullConstant createNull() => new NullConstant(); - - // Integer checks don't verify that the number is not -0.0. - bool isInt(Constant constant) => constant.isInt() || constant.isMinusZero(); - bool isDouble(Constant constant) - => constant.isDouble() && !constant.isMinusZero(); - bool isString(Constant constant) => constant.isString(); - bool isBool(Constant constant) => constant.isBool(); - bool isNull(Constant constant) => constant.isNull(); - - bool isSubtype(Compiler compiler, DartType s, DartType t) { - // At runtime, an integer is both an integer and a double: the - // integer type check is Math.floor, which will return true only - // for real integers, and our double type check is 'typeof number' - // which will return true for both integers and doubles. - if (s.element == compiler.intClass && t.element == compiler.doubleClass) { - return true; - } - return compiler.types.isSubtype(s, t); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/emitter.dart b/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/emitter.dart deleted file mode 100644 index f401235..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/emitter.dart +++ /dev/null
@@ -1,2359 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of js_backend; - -/** - * A function element that represents a closure call. The signature is copied - * from the given element. - */ -class ClosureInvocationElement extends FunctionElementX { - ClosureInvocationElement(SourceString name, - FunctionElement other) - : super.from(name, other, other.enclosingElement), - methodElement = other; - - isInstanceMember() => true; - - Element getOutermostEnclosingMemberOrTopLevel() => methodElement; - - /** - * The [member] this invocation refers to. - */ - Element methodElement; -} - -/** - * A convenient type alias for some functions that emit keyed values. - */ -typedef void DefineStubFunction(String invocationName, js.Expression value); - -/** - * A data structure for collecting fragments of a class definition. - */ -class ClassBuilder { - final List<js.Property> properties = <js.Property>[]; - - // Has the same signature as [DefineStubFunction]. - void addProperty(String name, js.Expression value) { - properties.add(new js.Property(js.string(name), value)); - } - - js.Expression toObjectInitializer() => new js.ObjectInitializer(properties); -} - -/** - * Generates the code for all used classes in the program. Static fields (even - * in classes) are ignored, since they can be treated as non-class elements. - * - * The code for the containing (used) methods must exist in the [:universe:]. - */ -class CodeEmitterTask extends CompilerTask { - bool needsInheritFunction = false; - bool needsDefineClass = false; - bool needsClosureClass = false; - bool needsLazyInitializer = false; - final Namer namer; - ConstantEmitter constantEmitter; - NativeEmitter nativeEmitter; - CodeBuffer boundClosureBuffer; - CodeBuffer mainBuffer; - /** Shorter access to [isolatePropertiesName]. Both here in the code, as - well as in the generated code. */ - String isolateProperties; - String classesCollector; - Set<ClassElement> neededClasses; - // TODO(ngeoffray): remove this field. - Set<ClassElement> instantiatedClasses; - - String get _ => compiler.enableMinification ? "" : " "; - String get n => compiler.enableMinification ? "" : "\n"; - String get N => compiler.enableMinification ? "\n" : ";\n"; - - /** - * A cache of closures that are used to closurize instance methods. - * A closure is dynamically bound to the instance used when - * closurized. - */ - final Map<int, String> boundClosureCache; - - /** - * A cache of closures that are used to closurize instance methods - * of interceptors. These closures are dynamically bound to the - * interceptor instance, and the actual receiver of the method. - */ - final Map<int, String> interceptorClosureCache; - - /** - * Raw ClassElement symbols occuring in is-checks and type assertions. If the - * program contains parameterized checks `x is Set<int>` and - * `x is Set<String>` then the ClassElement `Set` will occur once in - * [checkedClasses]. - */ - Set<ClassElement> checkedClasses; - - /** - * Raw Typedef symbols occuring in is-checks and type assertions. If the - * program contains `x is F<int>` and `x is F<bool>` then the TypedefElement - * `F` will occur once in [checkedTypedefs]. - */ - Set<TypedefElement> checkedTypedefs; - - final bool generateSourceMap; - - CodeEmitterTask(Compiler compiler, Namer namer, this.generateSourceMap) - : boundClosureBuffer = new CodeBuffer(), - mainBuffer = new CodeBuffer(), - this.namer = namer, - boundClosureCache = new Map<int, String>(), - interceptorClosureCache = new Map<int, String>(), - constantEmitter = new ConstantEmitter(compiler, namer), - super(compiler) { - nativeEmitter = new NativeEmitter(this); - } - - void computeRequiredTypeChecks() { - assert(checkedClasses == null); - checkedClasses = new Set<ClassElement>(); - checkedTypedefs = new Set<TypedefElement>(); - compiler.codegenWorld.isChecks.forEach((DartType t) { - if (t is InterfaceType) { - checkedClasses.add(t.element); - } else if (t is TypedefType) { - checkedTypedefs.add(t.element); - } - }); - } - - js.Expression constantReference(Constant value) { - return constantEmitter.reference(value); - } - - js.Expression constantInitializerExpression(Constant value) { - return constantEmitter.initializationExpression(value); - } - - String get name => 'CodeEmitter'; - - String get defineClassName - => '${namer.isolateName}.\$defineClass'; - String get currentGenerateAccessorName - => '${namer.CURRENT_ISOLATE}.\$generateAccessor'; - String get generateAccessorHolder - => '$isolatePropertiesName.\$generateAccessor'; - String get finishClassesName - => '${namer.isolateName}.\$finishClasses'; - String get finishIsolateConstructorName - => '${namer.isolateName}.\$finishIsolateConstructor'; - String get pendingClassesName - => '${namer.isolateName}.\$pendingClasses'; - String get isolatePropertiesName - => '${namer.isolateName}.${namer.isolatePropertiesName}'; - String get supportsProtoName - => 'supportsProto'; - String get lazyInitializerName - => '${namer.isolateName}.\$lazy'; - - // Property name suffixes. If the accessors are renaming then the format - // is <accessorName>:<fieldName><suffix>. We use the suffix to know whether - // to look for the ':' separator in order to avoid doing the indexOf operation - // on every single property (they are quite rare). None of these characters - // are legal in an identifier and they are related by bit patterns. - // setter < 0x3c - // both = 0x3d - // getter > 0x3e - // renaming setter | 0x7c - // renaming both } 0x7d - // renaming getter ~ 0x7e - const SUFFIX_MASK = 0x3f; - const FIRST_SUFFIX_CODE = 0x3c; - const SETTER_CODE = 0x3c; - const GETTER_SETTER_CODE = 0x3d; - const GETTER_CODE = 0x3e; - const RENAMING_FLAG = 0x40; - String needsGetterCode(String variable) => '($variable & 3) > 0'; - String needsSetterCode(String variable) => '($variable & 2) == 0'; - String isRenaming(String variable) => '($variable & $RENAMING_FLAG) != 0'; - - String get generateAccessorFunction { - return """ -function generateAccessor(field, prototype) { - var len = field.length; - var lastCharCode = field.charCodeAt(len - 1); - var needsAccessor = (lastCharCode & $SUFFIX_MASK) >= $FIRST_SUFFIX_CODE; - if (needsAccessor) { - var needsGetter = ${needsGetterCode('lastCharCode')}; - var needsSetter = ${needsSetterCode('lastCharCode')}; - var renaming = ${isRenaming('lastCharCode')}; - var accessorName = field = field.substring(0, len - 1); - if (renaming) { - var divider = field.indexOf(":"); - accessorName = field.substring(0, divider); - field = field.substring(divider + 1); - } - if (needsGetter) { - var getterString = "return this." + field + ";"; - prototype["get\$" + accessorName] = new Function(getterString); - } - if (needsSetter) { - var setterString = "this." + field + " = v;"; - prototype["set\$" + accessorName] = new Function("v", setterString); - } - } - return field; -}"""; - } - - String get defineClassFunction { - // First the class name, then the field names in an array and the members - // (inside an Object literal). - // The caller can also pass in the constructor as a function if needed. - // - // Example: - // defineClass("A", ["x", "y"], { - // foo$1: function(y) { - // print(this.x + y); - // }, - // bar$2: function(t, v) { - // this.x = t - v; - // }, - // }); - return """ -function(cls, fields, prototype) { - var constructor; - if (typeof fields == 'function') { - constructor = fields; - } else { - var str = "function " + cls + "("; - var body = ""; - for (var i = 0; i < fields.length; i++) { - if (i != 0) str += ", "; - var field = fields[i]; - field = generateAccessor(field, prototype); - str += field; - body += "this." + field + " = " + field + ";\\n"; - } - str += ") {" + body + "}\\n"; - str += "return " + cls + ";"; - constructor = new Function(str)(); - } - constructor.prototype = prototype; - constructor.builtin\$cls = cls; - return constructor; -}"""; - } - - /** Needs defineClass to be defined. */ - String get protoSupportCheck { - // On Firefox and Webkit browsers we can manipulate the __proto__ - // directly. Opera claims to have __proto__ support, but it is buggy. - // So we have to do more checks. - // Opera bug was filed as DSK-370158, and fixed as CORE-47615 - // (http://my.opera.com/desktopteam/blog/2012/07/20/more-12-01-fixes). - // If the browser does not support __proto__ we need to instantiate an - // object with the correct (internal) prototype set up correctly, and then - // copy the members. - - return ''' -var $supportsProtoName = false; -var tmp = $defineClassName('c', ['f?'], {}).prototype; -if (tmp.__proto__) { - tmp.__proto__ = {}; - if (typeof tmp.get\$f !== 'undefined') $supportsProtoName = true; -} -'''; - } - - String get finishClassesFunction { - // 'defineClass' does not require the classes to be constructed in order. - // Classes are initially just stored in the 'pendingClasses' field. - // 'finishClasses' takes all pending classes and sets up the prototype. - // Once set up, the constructors prototype field satisfy: - // - it contains all (local) members. - // - its internal prototype (__proto__) points to the superclass' - // prototype field. - // - the prototype's constructor field points to the JavaScript - // constructor. - // For engines where we have access to the '__proto__' we can manipulate - // the object literal directly. For other engines we have to create a new - // object and copy over the members. - return ''' -function(collectedClasses) { - var hasOwnProperty = Object.prototype.hasOwnProperty; - for (var cls in collectedClasses) { - if (hasOwnProperty.call(collectedClasses, cls)) { - var desc = collectedClasses[cls]; -'''/* The 'fields' are either a constructor function or a string encoding - fields, constructor and superclass. Get the superclass and the fields - in the format Super;field1,field2 from the null-string property on the - descriptor. */''' - var fields = desc[''], supr; - if (typeof fields == 'string') { - var s = fields.split(';'); supr = s[0]; - fields = s[1] == '' ? [] : s[1].split(','); - } else { - supr = desc['super']; - } - $isolatePropertiesName[cls] = $defineClassName(cls, fields, desc); - if (supr) $pendingClassesName[cls] = supr; - } - } - var pendingClasses = $pendingClassesName; -'''/* FinishClasses can be called multiple times. This means that we need to - clear the pendingClasses property. */''' - $pendingClassesName = {}; - var finishedClasses = {}; - function finishClass(cls) { -'''/* Opera does not support 'getOwnPropertyNames'. Therefore we use - hasOwnProperty instead. */''' - var hasOwnProperty = Object.prototype.hasOwnProperty; - if (hasOwnProperty.call(finishedClasses, cls)) return; - finishedClasses[cls] = true; - var superclass = pendingClasses[cls]; -'''/* The superclass is only false (empty string) for Dart's Object class. */''' - if (!superclass) return; - finishClass(superclass); - var constructor = $isolatePropertiesName[cls]; - var superConstructor = $isolatePropertiesName[superclass]; - var prototype = constructor.prototype; - if ($supportsProtoName) { - prototype.__proto__ = superConstructor.prototype; - prototype.constructor = constructor; - } else { - function tmp() {}; - tmp.prototype = superConstructor.prototype; - var newPrototype = new tmp(); - constructor.prototype = newPrototype; - newPrototype.constructor = constructor; - for (var member in prototype) { - if (!member) continue; '''/* Short version of: if (member == '') */''' - if (hasOwnProperty.call(prototype, member)) { - newPrototype[member] = prototype[member]; - } - } - } - } - for (var cls in pendingClasses) finishClass(cls); -}'''; - } - - String get finishIsolateConstructorFunction { - String isolate = namer.isolateName; - // We replace the old Isolate function with a new one that initializes - // all its field with the initial (and often final) value of all globals. - // This has two advantages: - // 1. the properties are in the object itself (thus avoiding to go through - // the prototype when looking up globals. - // 2. a new isolate goes through a (usually well optimized) constructor - // function of the form: "function() { this.x = ...; this.y = ...; }". - // - // Example: If [isolateProperties] is an object containing: x = 3 and - // A = function A() { /* constructor of class A. */ }, then we generate: - // str = "{ - // var isolateProperties = Isolate.$isolateProperties; - // this.x = isolateProperties.x; - // this.A = isolateProperties.A; - // }"; - // which is then dynamically evaluated: - // var newIsolate = new Function(str); - // - // We also copy over old values like the prototype, and the - // isolateProperties themselves. - return """function(oldIsolate) { - var isolateProperties = oldIsolate.${namer.isolatePropertiesName}; - var isolatePrototype = oldIsolate.prototype; - var str = "{\\n"; - str += "var properties = $isolate.${namer.isolatePropertiesName};\\n"; - for (var staticName in isolateProperties) { - if (Object.prototype.hasOwnProperty.call(isolateProperties, staticName)) { - str += "this." + staticName + "= properties." + staticName + ";\\n"; - } - } - str += "}\\n"; - var newIsolate = new Function(str); - newIsolate.prototype = isolatePrototype; - isolatePrototype.constructor = newIsolate; - newIsolate.${namer.isolatePropertiesName} = isolateProperties; - return newIsolate; -}"""; - } - - String get lazyInitializerFunction { - String isolate = namer.CURRENT_ISOLATE; - return """ -function(prototype, staticName, fieldName, getterName, lazyValue) { - var getter = new Function("{ return $isolate." + fieldName + ";}"); -$lazyInitializerLogic -}"""; - } - - String get lazyInitializerLogic { - String isolate = namer.CURRENT_ISOLATE; - JavaScriptBackend backend = compiler.backend; - String cyclicThrow = namer.isolateAccess(backend.cyclicThrowHelper); - return """ - var sentinelUndefined = {}; - var sentinelInProgress = {}; - prototype[fieldName] = sentinelUndefined; - prototype[getterName] = function() { - var result = $isolate[fieldName]; - try { - if (result === sentinelUndefined) { - $isolate[fieldName] = sentinelInProgress; - try { - result = $isolate[fieldName] = lazyValue(); - } finally { -""" // Use try-finally, not try-catch/throw as it destroys the stack trace. -""" - if (result === sentinelUndefined) { - if ($isolate[fieldName] === sentinelInProgress) { - $isolate[fieldName] = null; - } - } - } - } else if (result === sentinelInProgress) { - $cyclicThrow(staticName); - } - return result; - } finally { - $isolate[getterName] = getter; - } - };"""; - } - - void addDefineClassAndFinishClassFunctionsIfNecessary(CodeBuffer buffer) { - if (needsDefineClass) { - // Declare function called generateAccessor. This is used in - // defineClassFunction (it's a local declaration in init()). - buffer.add("$generateAccessorFunction$N"); - buffer.add("$generateAccessorHolder = generateAccessor$N"); - buffer.add("$defineClassName = $defineClassFunction$N"); - buffer.add(protoSupportCheck); - buffer.add("$pendingClassesName = {}$N"); - buffer.add("$finishClassesName = $finishClassesFunction$N"); - } - } - - void addLazyInitializerFunctionIfNecessary(CodeBuffer buffer) { - if (needsLazyInitializer) { - buffer.add("$lazyInitializerName = $lazyInitializerFunction$N"); - } - } - - void emitFinishIsolateConstructor(CodeBuffer buffer) { - String name = finishIsolateConstructorName; - String value = finishIsolateConstructorFunction; - buffer.add("$name = $value$N"); - } - - void emitFinishIsolateConstructorInvocation(CodeBuffer buffer) { - String isolate = namer.isolateName; - buffer.add("$isolate = $finishIsolateConstructorName($isolate)$N"); - } - - /** - * Generate stubs to handle invocation of methods with optional - * arguments. - * - * A method like [: foo([x]) :] may be invoked by the following - * calls: [: foo(), foo(1), foo(x: 1) :]. See the sources of this - * function for detailed examples. - */ - void addParameterStub(FunctionElement member, - Selector selector, - DefineStubFunction defineStub, - Set<String> alreadyGenerated) { - FunctionSignature parameters = member.computeSignature(compiler); - int positionalArgumentCount = selector.positionalArgumentCount; - if (positionalArgumentCount == parameters.parameterCount) { - assert(selector.namedArgumentCount == 0); - return; - } - if (parameters.optionalParametersAreNamed - && selector.namedArgumentCount == parameters.optionalParameterCount) { - // If the selector has the same number of named arguments as - // the element, we don't need to add a stub. The call site will - // hit the method directly. - return; - } - ConstantHandler handler = compiler.constantHandler; - List<SourceString> names = selector.getOrderedNamedArguments(); - - String invocationName = namer.invocationName(selector); - if (alreadyGenerated.contains(invocationName)) return; - alreadyGenerated.add(invocationName); - - JavaScriptBackend backend = compiler.backend; - bool isInterceptorClass = - backend.isInterceptorClass(member.getEnclosingClass()); - - // If the method is in an interceptor class, we need to also pass - // the actual receiver. - int extraArgumentCount = isInterceptorClass ? 1 : 0; - // Use '$receiver' to avoid clashes with other parameter names. Using - // '$receiver' works because [:namer.safeName:] used for getting parameter - // names never returns a name beginning with a single '$'. - String receiverArgumentName = r'$receiver'; - - // The parameters that this stub takes. - List<js.Parameter> parametersBuffer = - new List<js.Parameter>.fixedLength( - selector.argumentCount + extraArgumentCount); - // The arguments that will be passed to the real method. - List<js.Expression> argumentsBuffer = - new List<js.Expression>.fixedLength( - parameters.parameterCount + extraArgumentCount); - - int count = 0; - if (isInterceptorClass) { - count++; - parametersBuffer[0] = new js.Parameter(receiverArgumentName); - argumentsBuffer[0] = new js.VariableUse(receiverArgumentName); - } - - int indexOfLastOptionalArgumentInParameters = positionalArgumentCount - 1; - TreeElements elements = - compiler.enqueuer.resolution.getCachedElements(member); - - parameters.orderedForEachParameter((Element element) { - String jsName = backend.namer.safeName(element.name.slowToString()); - assert(jsName != receiverArgumentName); - int optionalParameterStart = positionalArgumentCount + extraArgumentCount; - if (count < optionalParameterStart) { - parametersBuffer[count] = new js.Parameter(jsName); - argumentsBuffer[count] = new js.VariableUse(jsName); - } else { - int index = names.indexOf(element.name); - if (index != -1) { - indexOfLastOptionalArgumentInParameters = count; - // The order of the named arguments is not the same as the - // one in the real method (which is in Dart source order). - argumentsBuffer[count] = new js.VariableUse(jsName); - parametersBuffer[optionalParameterStart + index] = - new js.Parameter(jsName); - // Note that [elements] may be null for a synthesized [member]. - } else if (elements != null && elements.isParameterChecked(element)) { - argumentsBuffer[count] = constantReference(SentinelConstant.SENTINEL); - } else { - Constant value = handler.initialVariableValues[element]; - if (value == null) { - argumentsBuffer[count] = constantReference(new NullConstant()); - } else { - if (!value.isNull()) { - // If the value is the null constant, we should not pass it - // down to the native method. - indexOfLastOptionalArgumentInParameters = count; - } - argumentsBuffer[count] = constantReference(value); - } - } - } - count++; - }); - - List<js.Statement> body; - if (member.hasFixedBackendName()) { - body = nativeEmitter.generateParameterStubStatements( - member, invocationName, parametersBuffer, argumentsBuffer, - indexOfLastOptionalArgumentInParameters); - } else { - body = <js.Statement>[ - new js.Return( - new js.VariableUse('this') - .dot(namer.getName(member)) - .callWith(argumentsBuffer))]; - } - - js.Fun function = new js.Fun(parametersBuffer, new js.Block(body)); - - defineStub(invocationName, function); - } - - void addParameterStubs(FunctionElement member, - DefineStubFunction defineStub) { - // We fill the lists depending on the selector. For example, - // take method foo: - // foo(a, b, {c, d}); - // - // We may have multiple ways of calling foo: - // (1) foo(1, 2); - // (2) foo(1, 2, c: 3); - // (3) foo(1, 2, d: 4); - // (4) foo(1, 2, c: 3, d: 4); - // (5) foo(1, 2, d: 4, c: 3); - // - // What we generate at the call sites are: - // (1) foo$2(1, 2); - // (2) foo$3$c(1, 2, 3); - // (3) foo$3$d(1, 2, 4); - // (4) foo$4$c$d(1, 2, 3, 4); - // (5) foo$4$c$d(1, 2, 3, 4); - // - // The stubs we generate are (expressed in Dart): - // (1) foo$2(a, b) => foo$4$c$d(a, b, null, null) - // (2) foo$3$c(a, b, c) => foo$4$c$d(a, b, c, null); - // (3) foo$3$d(a, b, d) => foo$4$c$d(a, b, null, d); - // (4) No stub generated, call is direct. - // (5) No stub generated, call is direct. - - // Keep a cache of which stubs have already been generated, to - // avoid duplicates. Note that even if selectors are - // canonicalized, we would still need this cache: a typed selector - // on A and a typed selector on B could yield the same stub. - Set<String> generatedStubNames = new Set<String>(); - if (compiler.enabledFunctionApply - && member.name == namer.closureInvocationSelectorName) { - // If [Function.apply] is called, we pessimistically compile all - // possible stubs for this closure. - FunctionSignature signature = member.computeSignature(compiler); - Set<Selector> selectors = signature.optionalParametersAreNamed - ? computeNamedSelectors(signature, member) - : computeOptionalSelectors(signature, member); - for (Selector selector in selectors) { - addParameterStub(member, selector, defineStub, generatedStubNames); - } - } else { - Set<Selector> selectors = compiler.codegenWorld.invokedNames[member.name]; - if (selectors == null) return; - for (Selector selector in selectors) { - if (!selector.applies(member, compiler)) continue; - addParameterStub(member, selector, defineStub, generatedStubNames); - } - } - } - - /** - * Compute the set of possible selectors in the presence of named - * parameters. - */ - Set<Selector> computeNamedSelectors(FunctionSignature signature, - FunctionElement element) { - Set<Selector> selectors = new Set<Selector>(); - // Add the selector that does not have any optional argument. - selectors.add(new Selector(SelectorKind.CALL, - element.name, - element.getLibrary(), - signature.requiredParameterCount, - <SourceString>[])); - - // For each optional parameter, we iterator over the set of - // already computed selectors and create new selectors with that - // parameter now being passed. - signature.forEachOptionalParameter((Element element) { - Set<Selector> newSet = new Set<Selector>(); - selectors.forEach((Selector other) { - List<SourceString> namedArguments = [element.name]; - namedArguments.addAll(other.namedArguments); - newSet.add(new Selector(other.kind, - other.name, - other.library, - other.argumentCount + 1, - namedArguments)); - }); - selectors.addAll(newSet); - }); - return selectors; - } - - /** - * Compute the set of possible selectors in the presence of optional - * non-named parameters. - */ - Set<Selector> computeOptionalSelectors(FunctionSignature signature, - FunctionElement element) { - Set<Selector> selectors = new Set<Selector>(); - // Add the selector that does not have any optional argument. - selectors.add(new Selector(SelectorKind.CALL, - element.name, - element.getLibrary(), - signature.requiredParameterCount, - <SourceString>[])); - - // For each optional parameter, we increment the number of passed - // argument. - for (int i = 1; i <= signature.optionalParameterCount; i++) { - selectors.add(new Selector(SelectorKind.CALL, - element.name, - element.getLibrary(), - signature.requiredParameterCount + i, - <SourceString>[])); - } - return selectors; - } - - bool instanceFieldNeedsGetter(Element member) { - assert(member.isField()); - return compiler.codegenWorld.hasInvokedGetter(member, compiler); - } - - bool instanceFieldNeedsSetter(Element member) { - assert(member.isField()); - return (!member.modifiers.isFinalOrConst()) - && compiler.codegenWorld.hasInvokedSetter(member, compiler); - } - - String compiledFieldName(Element member) { - assert(member.isField()); - return member.hasFixedBackendName() - ? member.fixedBackendName() - : namer.getName(member); - } - - /** - * Documentation wanted -- johnniwinther - * - * Invariant: [member] must be a declaration element. - */ - void addInstanceMember(Element member, ClassBuilder builder) { - assert(invariant(member, member.isDeclaration)); - // TODO(floitsch): we don't need to deal with members of - // uninstantiated classes, that have been overwritten by subclasses. - - if (member.isFunction() - || member.isGenerativeConstructorBody() - || member.isAccessor()) { - if (member.isAbstract(compiler)) return; - JavaScriptBackend backend = compiler.backend; - js.Expression code = backend.generatedCode[member]; - if (code == null) return; - builder.addProperty(namer.getName(member), code); - code = backend.generatedBailoutCode[member]; - if (code != null) { - builder.addProperty(namer.getBailoutName(member), code); - } - FunctionElement function = member; - FunctionSignature parameters = function.computeSignature(compiler); - if (!parameters.optionalParameters.isEmpty) { - addParameterStubs(member, builder.addProperty); - } - } else if (!member.isField()) { - compiler.internalError('unexpected kind: "${member.kind}"', - element: member); - } - emitExtraAccessors(member, builder); - } - - /** - * Documentation wanted -- johnniwinther - * - * Invariant: [classElement] must be a declaration element. - */ - void emitInstanceMembers(ClassElement classElement, - ClassBuilder builder) { - assert(invariant(classElement, classElement.isDeclaration)); - JavaScriptBackend backend = compiler.backend; - if (classElement == backend.objectInterceptorClass) { - emitInterceptorMethods(builder); - // The ObjectInterceptor does not have any instance methods. - return; - } - - void visitMember(ClassElement enclosing, Element member) { - assert(invariant(classElement, member.isDeclaration)); - if (member.isInstanceMember()) { - addInstanceMember(member, builder); - } - } - - // TODO(kasperl): We should make sure to only emit one version of - // overridden methods. Right now, we rely on the ordering so the - // methods pulled in from mixins are replaced with the members - // from the class definition. - - // If the class is a native class, we have to add the instance - // members defined in the non-native mixin applications used by - // the class. - visitNativeMixins(classElement, (MixinApplicationElement mixin) { - mixin.forEachMember( - visitMember, - includeBackendMembers: true, - includeSuperMembers: false); - }); - - classElement.implementation.forEachMember( - visitMember, - includeBackendMembers: true, - includeSuperMembers: false); - - generateIsTestsOn(classElement, (Element other) { - js.Expression code; - if (compiler.objectClass == other) return; - if (nativeEmitter.requiresNativeIsCheck(other)) { - code = js.fun([], js.block1(js.return_(new js.LiteralBool(true)))); - } else { - code = new js.LiteralBool(true); - } - builder.addProperty(namer.operatorIs(other), code); - }); - - if (identical(classElement, compiler.objectClass) - && compiler.enabledNoSuchMethod) { - // Emit the noSuchMethod handlers on the Object prototype now, - // so that the code in the dynamicFunction helper can find - // them. Note that this helper is invoked before analyzing the - // full JS script. - if (!nativeEmitter.handleNoSuchMethod) { - emitNoSuchMethodHandlers(builder.addProperty); - } - } - - if (backend.isInterceptorClass(classElement)) { - // The operator== method in [:Object:] does not take the same - // number of arguments as an intercepted method, therefore we - // explicitely add one to all interceptor classes. Note that we - // would not have do do that if all intercepted methods had - // a calling convention where the receiver is the first - // parameter. - String name = backend.namer.publicInstanceMethodNameByArity( - const SourceString('=='), 1); - Function kind = (classElement == backend.jsNullClass) - ? js.equals - : js.strictEquals; - builder.addProperty(name, js.fun(['receiver', 'a'], - js.block1(js.return_(kind(js.use('receiver'), js.use('a')))))); - } - } - - void emitRuntimeClassesAndTests(CodeBuffer buffer) { - JavaScriptBackend backend = compiler.backend; - RuntimeTypeInformation rti = backend.rti; - - TypeChecks typeChecks = rti.computeRequiredChecks(); - - bool needsHolder(ClassElement cls) { - return !neededClasses.contains(cls) || cls.isNative() || - rti.isJsNative(cls); - } - - void maybeGenerateHolder(ClassElement cls) { - if (!needsHolder(cls)) return; - - String holder = namer.isolateAccess(cls); - String name = namer.getName(cls); - buffer.add("$holder$_=$_{builtin\$cls:$_'$name'"); - for (ClassElement check in typeChecks[cls]) { - buffer.add(',$_${namer.operatorIs(check)}:${_}true'); - }; - buffer.add('}$N'); - } - - // Create representation objects for classes that we do not have a class - // definition for (because they are uninstantiated or native). - for (ClassElement cls in rti.allArguments) { - maybeGenerateHolder(cls); - } - - // Add checks to the constructors of instantiated classes. - for (ClassElement cls in typeChecks) { - if (needsHolder(cls)) { - // We already emitted the is-checks in the object definition for this - // class. - continue; - } - String holder = namer.isolateAccess(cls); - for (ClassElement check in typeChecks[cls]) { - buffer.add('$holder.${namer.operatorIs(check)}$_=${_}true$N'); - }; - } - } - - void visitNativeMixins(ClassElement classElement, - void visit(MixinApplicationElement mixinApplication)) { - if (!classElement.isNative()) return; - // Use recursion to make sure to visit the superclasses before the - // subclasses. Once we start keeping track of the emitted fields - // and members, we're going to want to visit these in the other - // order so we get the most specialized definition first. - void recurse(ClassElement cls) { - if (cls == null || !cls.isMixinApplication) return; - recurse(cls.superclass); - assert(!cls.isNative()); - visit(cls); - } - recurse(classElement.superclass); - } - - /** - * Documentation wanted -- johnniwinther - * - * Invariant: [classElement] must be a declaration element. - */ - void visitClassFields(ClassElement classElement, - void addField(Element member, - String name, - String accessorName, - bool needsGetter, - bool needsSetter, - bool needsCheckedSetter)) { - assert(invariant(classElement, classElement.isDeclaration)); - // If the class is never instantiated we still need to set it up for - // inheritance purposes, but we can simplify its JavaScript constructor. - bool isInstantiated = - compiler.codegenWorld.instantiatedClasses.contains(classElement); - - void visitField(ClassElement enclosingClass, Element member) { - assert(invariant(classElement, member.isDeclaration)); - LibraryElement library = member.getLibrary(); - SourceString name = member.name; - bool isPrivate = name.isPrivate(); - - // Keep track of whether or not we're dealing with a field mixin - // into a native class. - bool isMixinNativeField = - classElement.isNative() && enclosingClass.isMixinApplication; - - // See if we can dynamically create getters and setters. - // We can only generate getters and setters for [classElement] since - // the fields of super classes could be overwritten with getters or - // setters. - bool needsGetter = false; - bool needsSetter = false; - // We need to name shadowed fields differently, so they don't clash with - // the non-shadowed field. - bool isShadowed = false; - if (isMixinNativeField || identical(enclosingClass, classElement)) { - needsGetter = instanceFieldNeedsGetter(member); - needsSetter = instanceFieldNeedsSetter(member); - } else { - isShadowed = classElement.isShadowedByField(member); - } - - if ((isInstantiated && !enclosingClass.isNative()) - || needsGetter - || needsSetter) { - String accessorName = isShadowed - ? namer.shadowedFieldName(member) - : namer.getName(member); - String fieldName = member.hasFixedBackendName() - ? member.fixedBackendName() - : (isMixinNativeField ? member.name.slowToString() : accessorName); - bool needsCheckedSetter = false; - if (needsSetter && compiler.enableTypeAssertions - && canGenerateCheckedSetter(member)) { - needsCheckedSetter = true; - needsSetter = false; - } - // Getters and setters with suffixes will be generated dynamically. - addField(member, - fieldName, - accessorName, - needsGetter, - needsSetter, - needsCheckedSetter); - } - } - - // TODO(kasperl): We should make sure to only emit one version of - // overridden fields. Right now, we rely on the ordering so the - // fields pulled in from mixins are replaced with the fields from - // the class definition. - - // If the class is a native class, we have to add the fields - // defined in the non-native mixin applications used by the class. - visitNativeMixins(classElement, (MixinApplicationElement mixin) { - mixin.forEachInstanceField( - visitField, - includeBackendMembers: true, - includeSuperMembers: false); - }); - - // If a class is not instantiated then we add the field just so we can - // generate the field getter/setter dynamically. Since this is only - // allowed on fields that are in [classElement] we don't need to visit - // superclasses for non-instantiated classes. - classElement.implementation.forEachInstanceField( - visitField, - includeBackendMembers: true, - includeSuperMembers: isInstantiated && !classElement.isNative()); - } - - void generateGetter(Element member, String fieldName, String accessorName, - ClassBuilder builder) { - String getterName = namer.getterNameFromAccessorName(accessorName); - builder.addProperty(getterName, - js.fun([], js.block1(js.return_(js.use('this').dot(fieldName))))); - } - - void generateSetter(Element member, String fieldName, String accessorName, - ClassBuilder builder) { - String setterName = namer.setterNameFromAccessorName(accessorName); - builder.addProperty(setterName, - js.fun(['v'], - js.block1( - new js.ExpressionStatement( - js.assign(js.use('this').dot(fieldName), js.use('v')))))); - } - - bool canGenerateCheckedSetter(Element member) { - DartType type = member.computeType(compiler); - if (type.element.isTypeVariable() - || type.element == compiler.dynamicClass - || type.element == compiler.objectClass) { - // TODO(ngeoffray): Support type checks on type parameters. - return false; - } - return true; - } - - void generateCheckedSetter(Element member, - String fieldName, - String accessorName, - ClassBuilder builder) { - assert(canGenerateCheckedSetter(member)); - DartType type = member.computeType(compiler); - // TODO(ahe): Generate a dynamic type error here. - if (type.element.isErroneous()) return; - SourceString helper = compiler.backend.getCheckedModeHelper(type); - FunctionElement helperElement = compiler.findHelper(helper); - String helperName = namer.isolateAccess(helperElement); - List<js.Expression> arguments = <js.Expression>[js.use('v')]; - if (helperElement.computeSignature(compiler).parameterCount != 1) { - arguments.add(js.string(namer.operatorIs(type.element))); - } - - String setterName = namer.setterNameFromAccessorName(accessorName); - builder.addProperty(setterName, - js.fun(['v'], - js.block1( - new js.ExpressionStatement( - js.assign( - js.use('this').dot(fieldName), - js.call(js.use(helperName), arguments)))))); - } - - void emitClassConstructor(ClassElement classElement, ClassBuilder builder) { - /* Do nothing. */ - } - - void emitSuper(String superName, ClassBuilder builder) { - /* Do nothing. */ - } - - void emitClassFields(ClassElement classElement, - ClassBuilder builder, - { String superClass: "", - bool classIsNative: false}) { - bool isFirstField = true; - StringBuffer buffer = new StringBuffer(); - if (!classIsNative) { - buffer.add('$superClass;'); - } - visitClassFields(classElement, (Element member, - String name, - String accessorName, - bool needsGetter, - bool needsSetter, - bool needsCheckedSetter) { - // Ignore needsCheckedSetter - that is handled below. - bool needsAccessor = (needsGetter || needsSetter); - // We need to output the fields for non-native classes so we can auto- - // generate the constructor. For native classes there are no - // constructors, so we don't need the fields unless we are generating - // accessors at runtime. - if (!classIsNative || needsAccessor) { - // Emit correct commas. - if (isFirstField) { - isFirstField = false; - } else { - buffer.add(','); - } - int flag = 0; - if (!needsAccessor) { - // Emit field for constructor generation. - assert(!classIsNative); - buffer.add(name); - } else { - // Emit (possibly renaming) field name so we can add accessors at - // runtime. - buffer.add(accessorName); - if (name != accessorName) { - buffer.add(':$name'); - // Only the native classes can have renaming accessors. - assert(classIsNative); - flag = RENAMING_FLAG; - } - } - if (needsGetter && needsSetter) { - buffer.addCharCode(GETTER_SETTER_CODE + flag); - } else if (needsGetter) { - buffer.addCharCode(GETTER_CODE + flag); - } else if (needsSetter) { - buffer.addCharCode(SETTER_CODE + flag); - } - } - }); - - String compactClassData = buffer.toString(); - if (compactClassData.length > 0) { - builder.addProperty('', js.string(compactClassData)); - } - } - - void emitClassGettersSetters(ClassElement classElement, - ClassBuilder builder) { - - visitClassFields(classElement, (Element member, - String name, - String accessorName, - bool needsGetter, - bool needsSetter, - bool needsCheckedSetter) { - compiler.withCurrentElement(member, () { - if (needsCheckedSetter) { - assert(!needsSetter); - generateCheckedSetter(member, name, accessorName, builder); - } - if (!getterAndSetterCanBeImplementedByFieldSpec) { - if (needsGetter) { - generateGetter(member, name, accessorName, builder); - } - if (needsSetter) { - generateSetter(member, name, accessorName, builder); - } - } - }); - }); - } - - /** - * Documentation wanted -- johnniwinther - * - * Invariant: [classElement] must be a declaration element. - */ - void generateClass(ClassElement classElement, CodeBuffer buffer) { - assert(invariant(classElement, classElement.isDeclaration)); - if (classElement.isNative()) { - nativeEmitter.generateNativeClass(classElement); - return; - } - - needsDefineClass = true; - String className = namer.getName(classElement); - - // Find the first non-native superclass. - ClassElement superclass = classElement.superclass; - while (superclass != null && superclass.isNative()) { - superclass = superclass.superclass; - } - - String superName = ""; - if (superclass != null) { - superName = namer.getName(superclass); - } - - ClassBuilder builder = new ClassBuilder(); - - emitClassConstructor(classElement, builder); - emitSuper(superName, builder); - emitClassFields(classElement, builder, - superClass: superName, classIsNative: false); - emitClassGettersSetters(classElement, builder); - emitInstanceMembers(classElement, builder); - - js.Expression init = - js.assign( - js.use(classesCollector).dot(className), - builder.toObjectInitializer()); - buffer.add(js.prettyPrint(init, compiler)); - buffer.add('$N$n'); - } - - bool get getterAndSetterCanBeImplementedByFieldSpec => true; - - int _selectorRank(Selector selector) { - int arity = selector.argumentCount * 3; - if (selector.isGetter()) return arity + 2; - if (selector.isSetter()) return arity + 1; - return arity; - } - - int _compareSelectorNames(Selector selector1, Selector selector2) { - String name1 = selector1.name.toString(); - String name2 = selector2.name.toString(); - if (name1 != name2) return Comparable.compare(name1, name2); - return _selectorRank(selector1) - _selectorRank(selector2); - } - - void emitInterceptorMethods(ClassBuilder builder) { - JavaScriptBackend backend = compiler.backend; - // Emit forwarders for the ObjectInterceptor class. We need to - // emit all possible sends on intercepted methods. - for (Selector selector in - backend.usedInterceptors.toList()..sort(_compareSelectorNames)) { - List<js.Parameter> parameters = <js.Parameter>[]; - List<js.Expression> arguments = <js.Expression>[]; - parameters.add(new js.Parameter('receiver')); - - String name = backend.namer.invocationName(selector); - if (selector.isSetter()) { - parameters.add(new js.Parameter('value')); - arguments.add(new js.VariableUse('value')); - } else { - for (int i = 0; i < selector.argumentCount; i++) { - String argName = 'a$i'; - parameters.add(new js.Parameter(argName)); - arguments.add(new js.VariableUse(argName)); - } - } - js.Fun function = - new js.Fun(parameters, - new js.Block( - <js.Statement>[ - new js.Return( - new js.VariableUse('receiver') - .dot(name) - .callWith(arguments))])); - builder.addProperty(name, function); - } - } - - Iterable<Element> getTypedefChecksOn(DartType type) { - bool isSubtype(TypedefElement typedef) { - FunctionType typedefType = - typedef.computeType(compiler).unalias(compiler); - return compiler.types.isSubtype(type, typedefType); - } - return checkedTypedefs.where(isSubtype).toList() - ..sort(Elements.compareByPosition); - } - - /** - * Generate "is tests" for [cls]: itself, and the "is tests" for the - * classes it implements. We don't need to add the "is tests" of the - * super class because they will be inherited at runtime. - */ - void generateIsTestsOn(ClassElement cls, - void emitIsTest(Element element)) { - if (checkedClasses.contains(cls)) { - emitIsTest(cls); - } - - Set<Element> generated = new Set<Element>(); - // A class that defines a [:call:] method implicitly implements - // [Function] and needs checks for all typedefs that are used in is-checks. - if (checkedClasses.contains(compiler.functionClass) || - !checkedTypedefs.isEmpty) { - FunctionElement call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME); - if (call == null) { - // If [cls] is a closure, it has a synthetic call operator method. - call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME); - } - if (call != null) { - generateInterfacesIsTests(compiler.functionClass, - emitIsTest, - generated); - getTypedefChecksOn(call.computeType(compiler)).forEach(emitIsTest); - } - } - - for (DartType interfaceType in cls.interfaces) { - generateInterfacesIsTests(interfaceType.element, emitIsTest, generated); - } - - // For native classes, we also have to run through their mixin - // applications and make sure we deal with 'is' tests correctly - // for those. - visitNativeMixins(cls, (MixinApplicationElement mixin) { - for (DartType interfaceType in mixin.interfaces) { - ClassElement interfaceElement = interfaceType.element; - generateInterfacesIsTests(interfaceType.element, emitIsTest, generated); - } - }); - } - - /** - * Generate "is tests" where [cls] is being implemented. - */ - void generateInterfacesIsTests(ClassElement cls, - void emitIsTest(ClassElement element), - Set<Element> alreadyGenerated) { - void tryEmitTest(ClassElement cls) { - if (!alreadyGenerated.contains(cls) && checkedClasses.contains(cls)) { - alreadyGenerated.add(cls); - emitIsTest(cls); - } - }; - - tryEmitTest(cls); - - for (DartType interfaceType in cls.interfaces) { - Element element = interfaceType.element; - tryEmitTest(element); - generateInterfacesIsTests(element, emitIsTest, alreadyGenerated); - } - - // We need to also emit "is checks" for the superclass and its supertypes. - ClassElement superclass = cls.superclass; - if (superclass != null) { - tryEmitTest(superclass); - generateInterfacesIsTests(superclass, emitIsTest, alreadyGenerated); - } - } - - /** - * Return a function that returns true if its argument is a class - * that needs to be emitted. - */ - Function computeClassFilter() { - Set<ClassElement> unneededClasses = new Set<ClassElement>(); - // The [Bool] class is not marked as abstract, but has a factory - // constructor that always throws. We never need to emit it. - unneededClasses.add(compiler.boolClass); - - JavaScriptBackend backend = compiler.backend; - - // Go over specialized interceptors and then constants to know which - // interceptors are needed. - Set<ClassElement> needed = new Set<ClassElement>(); - backend.specializedGetInterceptors.forEach( - (_, Collection<ClassElement> elements) { - needed.addAll(elements); - } - ); - - ConstantHandler handler = compiler.constantHandler; - List<Constant> constants = handler.getConstantsForEmission(); - for (Constant constant in constants) { - if (constant is ConstructedConstant) { - Element element = constant.computeType(compiler).element; - if (backend.isInterceptorClass(element)) { - needed.add(element); - } - } - } - - // Add unneeded interceptors to the [unneededClasses] set. - for (ClassElement interceptor in backend.interceptedClasses.keys) { - if (!needed.contains(interceptor)) { - unneededClasses.add(interceptor); - } - } - - return (ClassElement cls) => !unneededClasses.contains(cls); - } - - void emitClasses(CodeBuffer buffer) { - // Compute the required type checks to know which classes need a - // 'is$' method. - computeRequiredTypeChecks(); - List<ClassElement> sortedClasses = - new List<ClassElement>.from(neededClasses); - sortedClasses.sort((ClassElement class1, ClassElement class2) { - // We sort by the ids of the classes. There is no guarantee that these - // ids are meaningful (or even deterministic), but in the current - // implementation they are increasing within a source file. - return class1.id - class2.id; - }); - - // If we need noSuchMethod support, we run through all needed - // classes to figure out if we need the support on any native - // class. If so, we let the native emitter deal with it. - if (compiler.enabledNoSuchMethod) { - SourceString noSuchMethodName = Compiler.NO_SUCH_METHOD; - Selector noSuchMethodSelector = new Selector.noSuchMethod(); - for (ClassElement element in sortedClasses) { - if (!element.isNative()) continue; - Element member = element.lookupLocalMember(noSuchMethodName); - if (member == null) continue; - if (noSuchMethodSelector.applies(member, compiler)) { - nativeEmitter.handleNoSuchMethod = true; - break; - } - } - } - - for (ClassElement element in sortedClasses) { - generateClass(element, buffer); - } - - // The closure class could have become necessary because of the generation - // of stubs. - ClassElement closureClass = compiler.closureClass; - if (needsClosureClass && !instantiatedClasses.contains(closureClass)) { - generateClass(closureClass, buffer); - } - } - - void emitFinishClassesInvocationIfNecessary(CodeBuffer buffer) { - if (needsDefineClass) { - buffer.add("$finishClassesName($classesCollector)$N"); - // Reset the map. - buffer.add("$classesCollector$_=$_{}$N"); - } - } - - void emitStaticFunction(CodeBuffer buffer, - String name, - js.Expression functionExpression) { - js.Expression assignment = - js.assign(js.use(isolateProperties).dot(name), functionExpression); - buffer.add(js.prettyPrint(assignment, compiler)); - buffer.add('$N$n'); - } - - void emitStaticFunctions(CodeBuffer buffer) { - JavaScriptBackend backend = compiler.backend; - bool isStaticFunction(Element element) => - !element.isInstanceMember() && !element.isField(); - - Iterable<Element> elements = - backend.generatedCode.keys.where(isStaticFunction); - Set<Element> pendingElementsWithBailouts = - backend.generatedBailoutCode.keys - .where(isStaticFunction) - .toSet(); - - for (Element element in Elements.sortedByPosition(elements)) { - js.Expression code = backend.generatedCode[element]; - emitStaticFunction(buffer, namer.getName(element), code); - js.Expression bailoutCode = backend.generatedBailoutCode[element]; - if (bailoutCode != null) { - pendingElementsWithBailouts.remove(element); - emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode); - } - } - - // Is it possible the primary function was inlined but the bailout was not? - for (Element element in - Elements.sortedByPosition(pendingElementsWithBailouts)) { - js.Expression bailoutCode = backend.generatedBailoutCode[element]; - emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode); - } - } - - void emitStaticFunctionGetters(CodeBuffer buffer) { - Set<FunctionElement> functionsNeedingGetter = - compiler.codegenWorld.staticFunctionsNeedingGetter; - for (FunctionElement element in - Elements.sortedByPosition(functionsNeedingGetter)) { - // The static function does not have the correct name. Since - // [addParameterStubs] use the name to create its stubs we simply - // create a fake element with the correct name. - // Note: the callElement will not have any enclosingElement. - FunctionElement callElement = - new ClosureInvocationElement(namer.closureInvocationSelectorName, - element); - String staticName = namer.getName(element); - String invocationName = namer.instanceMethodName(callElement); - String fieldAccess = '$isolateProperties.$staticName'; - buffer.add("$fieldAccess.$invocationName$_=$_$fieldAccess$N"); - - addParameterStubs(callElement, (String name, js.Expression value) { - js.Expression assignment = - js.assign( - js.use(isolateProperties).dot(staticName).dot(name), - value); - buffer.add( - js.prettyPrint(new js.ExpressionStatement(assignment), compiler)); - buffer.add('$N'); - }); - - // If a static function is used as a closure we need to add its name - // in case it is used in spawnFunction. - String fieldName = namer.STATIC_CLOSURE_NAME_NAME; - buffer.add('$fieldAccess.$fieldName$_=$_"$staticName"$N'); - getTypedefChecksOn(element.computeType(compiler)).forEach( - (Element typedef) { - String operator = namer.operatorIs(typedef); - buffer.add('$fieldAccess.$operator$_=${_}true$N'); - } - ); - } - } - - void emitBoundClosureClassHeader(String mangledName, - String superName, - List<String> fieldNames, - ClassBuilder builder) { - builder.addProperty('', - js.string("$superName;${Strings.join(fieldNames,',')}")); - } - - /** - * Documentation wanted -- johnniwinther - * - * Invariant: [member] must be a declaration element. - */ - void emitDynamicFunctionGetter(FunctionElement member, - DefineStubFunction defineStub) { - assert(invariant(member, member.isDeclaration)); - // For every method that has the same name as a property-get we create a - // getter that returns a bound closure. Say we have a class 'A' with method - // 'foo' and somewhere in the code there is a dynamic property get of - // 'foo'. Then we generate the following code (in pseudo Dart/JavaScript): - // - // class A { - // foo(x, y, z) { ... } // Original function. - // get foo { return new BoundClosure499(this, "foo"); } - // } - // class BoundClosure499 extends Closure { - // var self; - // BoundClosure499(this.self, this.name); - // $call3(x, y, z) { return self[name](x, y, z); } - // } - - // TODO(floitsch): share the closure classes with other classes - // if they share methods with the same signature. Currently we do this only - // if there are no optional parameters. Closures with optional parameters - // are more difficult to canonicalize because they would need to have the - // same default values. - - bool hasOptionalParameters = member.optionalParameterCount(compiler) != 0; - int parameterCount = member.parameterCount(compiler); - - Map<int, String> cache; - String extraArg = null; - // Methods on interceptor classes take an extra parameter, which is the - // actual receiver of the call. - JavaScriptBackend backend = compiler.backend; - bool inInterceptor = backend.isInterceptorClass(member.getEnclosingClass()); - if (inInterceptor) { - cache = interceptorClosureCache; - extraArg = 'receiver'; - } else { - cache = boundClosureCache; - } - List<String> fieldNames = compiler.enableMinification - ? inInterceptor ? const ['a', 'b', 'c'] - : const ['a', 'b'] - : inInterceptor ? const ['self', 'target', 'receiver'] - : const ['self', 'target']; - - Iterable<Element> typedefChecks = - getTypedefChecksOn(member.computeType(compiler)); - bool hasTypedefChecks = !typedefChecks.isEmpty; - - bool canBeShared = !hasOptionalParameters && !hasTypedefChecks; - - String closureClass = canBeShared ? cache[parameterCount] : null; - if (closureClass == null) { - // Either the class was not cached yet, or there are optional parameters. - // Create a new closure class. - String name; - if (canBeShared) { - if (inInterceptor) { - name = 'BoundClosure\$i${parameterCount}'; - } else { - name = 'BoundClosure\$${parameterCount}'; - } - } else { - name = 'Bound_${member.name.slowToString()}' - '_${member.enclosingElement.name.slowToString()}'; - } - - ClassElement closureClassElement = new ClosureClassElement( - new SourceString(name), compiler, member, member.getCompilationUnit()); - String mangledName = namer.getName(closureClassElement); - String superName = namer.getName(closureClassElement.superclass); - needsClosureClass = true; - - // Define the constructor with a name so that Object.toString can - // find the class name of the closure class. - ClassBuilder boundClosureBuilder = new ClassBuilder(); - emitBoundClosureClassHeader( - mangledName, superName, fieldNames, boundClosureBuilder); - // Now add the methods on the closure class. The instance method does not - // have the correct name. Since [addParameterStubs] use the name to create - // its stubs we simply create a fake element with the correct name. - // Note: the callElement will not have any enclosingElement. - FunctionElement callElement = - new ClosureInvocationElement(namer.closureInvocationSelectorName, - member); - - String invocationName = namer.instanceMethodName(callElement); - - List<String> parameters = <String>[]; - List<js.Expression> arguments = <js.Expression>[]; - if (inInterceptor) { - arguments.add(js.use('this').dot(fieldNames[2])); - } - for (int i = 0; i < parameterCount; i++) { - String name = 'p$i'; - parameters.add(name); - arguments.add(js.use(name)); - } - - js.Expression fun = - js.fun(parameters, - js.block1( - js.return_( - new js.PropertyAccess( - js.use('this').dot(fieldNames[0]), - js.use('this').dot(fieldNames[1])) - .callWith(arguments)))); - boundClosureBuilder.addProperty(invocationName, fun); - - addParameterStubs(callElement, boundClosureBuilder.addProperty); - typedefChecks.forEach((Element typedef) { - String operator = namer.operatorIs(typedef); - boundClosureBuilder.addProperty(operator, new js.LiteralBool(true)); - }); - - js.Expression init = - js.assign( - js.use(classesCollector).dot(mangledName), - boundClosureBuilder.toObjectInitializer()); - boundClosureBuffer.add(js.prettyPrint(init, compiler)); - boundClosureBuffer.add("$N"); - - closureClass = namer.isolateAccess(closureClassElement); - - // Cache it. - if (canBeShared) { - cache[parameterCount] = closureClass; - } - } - - // And finally the getter. - String getterName = namer.getterName(member); - String targetName = namer.instanceMethodName(member); - - List<String> parameters = <String>[]; - List<js.Expression> arguments = <js.Expression>[]; - arguments.add(js.use('this')); - arguments.add(js.string(targetName)); - if (inInterceptor) { - parameters.add(extraArg); - arguments.add(js.use(extraArg)); - } - - js.Expression getterFunction = - js.fun(parameters, - js.block1( - js.return_( - new js.New(js.use(closureClass), arguments)))); - - defineStub(getterName, getterFunction); - } - - /** - * Documentation wanted -- johnniwinther - * - * Invariant: [member] must be a declaration element. - */ - void emitCallStubForGetter(Element member, - Set<Selector> selectors, - DefineStubFunction defineStub) { - assert(invariant(member, member.isDeclaration)); - LibraryElement memberLibrary = member.getLibrary(); - JavaScriptBackend backend = compiler.backend; - // If the class is an interceptor class, the stub gets the - // receiver explicitely and we need to pass it to the getter call. - bool isInterceptorClass = - backend.isInterceptorClass(member.getEnclosingClass()); - - const String receiverArgumentName = r'$receiver'; - - js.Expression buildGetter() { - if (member.isGetter()) { - String getterName = namer.getterName(member); - return new js.VariableUse('this').dot(getterName).callWith( - isInterceptorClass - ? <js.Expression>[new js.VariableUse(receiverArgumentName)] - : <js.Expression>[]); - } else { - String fieldName = member.hasFixedBackendName() - ? member.fixedBackendName() - : namer.instanceFieldName(member); - return new js.VariableUse('this').dot(fieldName); - } - } - - // Two selectors may match but differ only in type. To avoid generating - // identical stubs for each we track untyped selectors which already have - // stubs. - Set<Selector> generatedSelectors = new Set<Selector>(); - - for (Selector selector in selectors) { - if (selector.applies(member, compiler)) { - selector = selector.asUntyped; - if (generatedSelectors.contains(selector)) continue; - generatedSelectors.add(selector); - - String invocationName = namer.invocationName(selector); - Selector callSelector = new Selector.callClosureFrom(selector); - String closureCallName = namer.invocationName(callSelector); - - List<js.Parameter> parameters = <js.Parameter>[]; - List<js.Expression> arguments = <js.Expression>[]; - if (isInterceptorClass) { - parameters.add(new js.Parameter(receiverArgumentName)); - } - - for (int i = 0; i < selector.argumentCount; i++) { - String name = 'arg$i'; - parameters.add(new js.Parameter(name)); - arguments.add(new js.VariableUse(name)); - } - - js.Fun function = - new js.Fun(parameters, - new js.Block( - <js.Statement>[ - new js.Return( - buildGetter().dot(closureCallName) - .callWith(arguments))])); - - defineStub(invocationName, function); - } - } - } - - void emitStaticNonFinalFieldInitializations(CodeBuffer buffer) { - ConstantHandler handler = compiler.constantHandler; - Iterable<VariableElement> staticNonFinalFields = - handler.getStaticNonFinalFieldsForEmission(); - for (Element element in Elements.sortedByPosition(staticNonFinalFields)) { - compiler.withCurrentElement(element, () { - Constant initialValue = handler.getInitialValueFor(element); - js.Expression init = - new js.Assignment( - new js.PropertyAccess.field( - new js.VariableUse(isolateProperties), - namer.getName(element)), - constantEmitter.referenceInInitializationContext(initialValue)); - buffer.add(js.prettyPrint(init, compiler)); - buffer.add('$N'); - }); - } - } - - void emitLazilyInitializedStaticFields(CodeBuffer buffer) { - ConstantHandler handler = compiler.constantHandler; - List<VariableElement> lazyFields = - handler.getLazilyInitializedFieldsForEmission(); - JavaScriptBackend backend = compiler.backend; - if (!lazyFields.isEmpty) { - needsLazyInitializer = true; - for (VariableElement element in Elements.sortedByPosition(lazyFields)) { - assert(backend.generatedBailoutCode[element] == null); - js.Expression code = backend.generatedCode[element]; - assert(code != null); - // The code only computes the initial value. We build the lazy-check - // here: - // lazyInitializer(prototype, 'name', fieldName, getterName, initial); - // The name is used for error reporting. The 'initial' must be a - // closure that constructs the initial value. - List<js.Expression> arguments = <js.Expression>[]; - arguments.add(js.use(isolateProperties)); - arguments.add(js.string(element.name.slowToString())); - arguments.add(js.string(namer.getName(element))); - arguments.add(js.string(namer.getLazyInitializerName(element))); - arguments.add(code); - js.Expression getter = buildLazyInitializedGetter(element); - if (getter != null) { - arguments.add(getter); - } - js.Expression init = js.call(js.use(lazyInitializerName), arguments); - buffer.add(js.prettyPrint(init, compiler)); - buffer.add("$N"); - } - } - } - - js.Expression buildLazyInitializedGetter(VariableElement element) { - // Nothing to do, the 'lazy' function will create the getter. - return null; - } - - void emitCompileTimeConstants(CodeBuffer buffer) { - ConstantHandler handler = compiler.constantHandler; - List<Constant> constants = handler.getConstantsForEmission(); - bool addedMakeConstantList = false; - for (Constant constant in constants) { - // No need to emit functions. We already did that. - if (constant.isFunction()) continue; - // Numbers, strings and booleans are currently always inlined. - if (constant.isPrimitive()) continue; - - String name = namer.constantName(constant); - // The name is null when the constant is already a JS constant. - // TODO(floitsch): every constant should be registered, so that we can - // share the ones that take up too much space (like some strings). - if (name == null) continue; - if (!addedMakeConstantList && constant.isList()) { - addedMakeConstantList = true; - emitMakeConstantList(buffer); - } - js.Expression init = - new js.Assignment( - new js.PropertyAccess.field( - new js.VariableUse(isolateProperties), - name), - constantInitializerExpression(constant)); - buffer.add(js.prettyPrint(init, compiler)); - buffer.add('$N'); - } - } - - void emitMakeConstantList(CodeBuffer buffer) { - buffer.add(namer.isolateName); - buffer.add(r'''.makeConstantList = function(list) { - list.immutable$list = true; - list.fixed$length = true; - return list; -}; -'''); - } - - /** - * Documentation wanted -- johnniwinther - * - * Invariant: [member] must be a declaration element. - */ - void emitExtraAccessors(Element member, ClassBuilder builder) { - assert(invariant(member, member.isDeclaration)); - if (member.isGetter() || member.isField()) { - Set<Selector> selectors = compiler.codegenWorld.invokedNames[member.name]; - if (selectors != null && !selectors.isEmpty) { - emitCallStubForGetter(member, selectors, builder.addProperty); - } - } else if (member.isFunction()) { - if (compiler.codegenWorld.hasInvokedGetter(member, compiler)) { - emitDynamicFunctionGetter(member, builder.addProperty); - } - } - } - - void emitNoSuchMethodHandlers(DefineStubFunction defineStub) { - // Do not generate no such method handlers if there is no class. - if (compiler.codegenWorld.instantiatedClasses.isEmpty) return; - - String noSuchMethodName = namer.publicInstanceMethodNameByArity( - Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT); - - Element createInvocationMirrorElement = - compiler.findHelper(const SourceString("createInvocationMirror")); - String createInvocationMirrorName = - namer.getName(createInvocationMirrorElement); - - // Keep track of the JavaScript names we've already added so we - // do not introduce duplicates (bad for code size). - Set<String> addedJsNames = new Set<String>(); - - // Keep track of the noSuchMethod holders for each possible - // receiver type. - Map<ClassElement, Set<ClassElement>> noSuchMethodHolders = - new Map<ClassElement, Set<ClassElement>>(); - Set<ClassElement> noSuchMethodHoldersFor(DartType type) { - ClassElement element = type.element; - Set<ClassElement> result = noSuchMethodHolders[element]; - if (result == null) { - // For now, we check the entire world to see if an object of - // the given type may have a user-defined noSuchMethod - // implementation. We could do better by only looking at - // instantiated (or otherwise needed) classes. - result = compiler.world.findNoSuchMethodHolders(type); - noSuchMethodHolders[element] = result; - } - return result; - } - - js.Expression generateMethod(String jsName, Selector selector) { - // Values match JSInvocationMirror in js-helper library. - int type = selector.invocationMirrorKind; - String methodName = selector.invocationMirrorMemberName; - List<js.Parameter> parameters = <js.Parameter>[]; - CodeBuffer args = new CodeBuffer(); - for (int i = 0; i < selector.argumentCount; i++) { - parameters.add(new js.Parameter('\$$i')); - } - - List<js.Expression> argNames = - selector.getOrderedNamedArguments().map((SourceString name) => - js.string(name.slowToString())).toList(); - - String internalName = namer.invocationMirrorInternalName(selector); - - String createInvocationMirror = namer.getName( - compiler.createInvocationMirrorElement); - - js.Expression expression = - new js.This() - .dot(noSuchMethodName) - .callWith( - <js.Expression>[ - new js.VariableUse(namer.CURRENT_ISOLATE) - .dot(createInvocationMirror) - .callWith( - <js.Expression>[ - js.string(methodName), - js.string(internalName), - new js.LiteralNumber('$type'), - new js.ArrayInitializer.from( - parameters.map((param) => js.use(param.name)) - .toList()), - new js.ArrayInitializer.from(argNames)])]); - js.Expression function = - new js.Fun(parameters, - new js.Block(<js.Statement>[new js.Return(expression)])); - return function; - } - - void addNoSuchMethodHandlers(SourceString ignore, Set<Selector> selectors) { - // Cache the object class and type. - ClassElement objectClass = compiler.objectClass; - DartType objectType = objectClass.computeType(compiler); - - for (Selector selector in selectors) { - // Introduce a helper function that determines if the given - // class has a member that matches the current name and - // selector (grabbed from the scope). - bool hasMatchingMember(ClassElement holder) { - Element element = holder.lookupMember(selector.name); - if (element == null) return false; - - // TODO(kasperl): Consider folding this logic into the - // Selector.applies() method. - if (element is AbstractFieldElement) { - AbstractFieldElement field = element; - if (selector.isGetter()) { - return field.getter != null; - } else if (selector.isSetter()) { - return field.setter != null; - } else { - return false; - } - } else if (element is VariableElement) { - if (selector.isSetter() && element.modifiers.isFinalOrConst()) { - return false; - } - } - return selector.applies(element, compiler); - } - - // If the selector is typed, we check to see if that type may - // have a user-defined noSuchMethod implementation. If not, we - // skip the selector altogether. - DartType receiverType = objectType; - ClassElement receiverClass = objectClass; - if (selector is TypedSelector) { - TypedSelector typedSelector = selector; - receiverType = typedSelector.receiverType; - receiverClass = receiverType.element; - } - - // If the receiver class is guaranteed to have a member that - // matches what we're looking for, there's no need to - // introduce a noSuchMethod handler. It will never be called. - // - // As an example, consider this class hierarchy: - // - // A <-- noSuchMethod - // / \ - // C B <-- foo - // - // If we know we're calling foo on an object of type B we - // don't have to worry about the noSuchMethod method in A - // because objects of type B implement foo. On the other hand, - // if we end up calling foo on something of type C we have to - // add a handler for it. - if (hasMatchingMember(receiverClass)) continue; - - // If the holders of all user-defined noSuchMethod - // implementations that might be applicable to the receiver - // type have a matching member for the current name and - // selector, we avoid introducing a noSuchMethod handler. - // - // As an example, consider this class hierarchy: - // - // A <-- foo - // / \ - // noSuchMethod --> B C <-- bar - // | | - // C D <-- noSuchMethod - // - // When calling foo on an object of type A, we know that the - // implementations of noSuchMethod are in the classes B and D - // that also (indirectly) implement foo, so we do not need a - // handler for it. - // - // If we're calling bar on an object of type D, we don't need - // the handler either because all objects of type D implement - // bar through inheritance. - // - // If we're calling bar on an object of type A we do need the - // handler because we may have to call B.noSuchMethod since B - // does not implement bar. - Set<ClassElement> holders = noSuchMethodHoldersFor(receiverType); - if (holders.every(hasMatchingMember)) continue; - String jsName = namer.invocationMirrorInternalName(selector); - if (!addedJsNames.contains(jsName)) { - js.Expression method = generateMethod(jsName, selector); - defineStub(jsName, method); - addedJsNames.add(jsName); - } - } - } - - compiler.codegenWorld.invokedNames.forEach(addNoSuchMethodHandlers); - compiler.codegenWorld.invokedGetters.forEach(addNoSuchMethodHandlers); - compiler.codegenWorld.invokedSetters.forEach(addNoSuchMethodHandlers); - } - - String buildIsolateSetup(CodeBuffer buffer, - Element appMain, - Element isolateMain) { - String mainAccess = "${namer.isolateAccess(appMain)}"; - String currentIsolate = "${namer.CURRENT_ISOLATE}"; - // Since we pass the closurized version of the main method to - // the isolate method, we must make sure that it exists. - if (!compiler.codegenWorld.staticFunctionsNeedingGetter.contains(appMain)) { - Selector selector = new Selector.callClosure(0); - String invocationName = namer.invocationName(selector); - buffer.add("$mainAccess.$invocationName = $mainAccess$N"); - } - return "${namer.isolateAccess(isolateMain)}($mainAccess)"; - } - - emitMain(CodeBuffer buffer) { - if (compiler.isMockCompilation) return; - Element main = compiler.mainApp.find(Compiler.MAIN); - String mainCall = null; - if (compiler.hasIsolateSupport()) { - Element isolateMain = - compiler.isolateHelperLibrary.find(Compiler.START_ROOT_ISOLATE); - mainCall = buildIsolateSetup(buffer, main, isolateMain); - } else { - mainCall = '${namer.isolateAccess(main)}()'; - } - if (!compiler.enableMinification) { - buffer.add(""" - -// -// BEGIN invoke [main]. -// -"""); - } - buffer.add(""" -if (typeof document !== 'undefined' && document.readyState !== 'complete') { - document.addEventListener('readystatechange', function () { - if (document.readyState == 'complete') { - if (typeof dartMainRunner === 'function') { - dartMainRunner(function() { ${mainCall}; }); - } else { - ${mainCall}; - } - } - }, false); -} else { - if (typeof dartMainRunner === 'function') { - dartMainRunner(function() { ${mainCall}; }); - } else { - ${mainCall}; - } -} -"""); - if (!compiler.enableMinification) { - buffer.add(""" -// -// END invoke [main]. -// - -"""); - } - } - - void emitGetInterceptorMethod(CodeBuffer buffer, - String objectName, - String key, - Collection<ClassElement> classes) { - js.Statement buildReturnInterceptor(ClassElement cls) { - return js.return_(js.fieldAccess(js.use(namer.isolateAccess(cls)), - 'prototype')); - } - - js.VariableUse receiver = js.use('receiver'); - JavaScriptBackend backend = compiler.backend; - - /** - * Build a JavaScrit AST node for doing a type check on - * [cls]. [cls] must be an interceptor class. - */ - js.Statement buildInterceptorCheck(ClassElement cls) { - js.Expression condition; - assert(backend.isInterceptorClass(cls)); - if (cls == backend.jsBoolClass) { - condition = js.equals(js.typeOf(receiver), js.string('boolean')); - } else if (cls == backend.jsIntClass || - cls == backend.jsDoubleClass || - cls == backend.jsNumberClass) { - throw 'internal error'; - } else if (cls == backend.jsArrayClass) { - condition = js.equals(js.fieldAccess(receiver, 'constructor'), - js.use('Array')); - } else if (cls == backend.jsStringClass) { - condition = js.equals(js.typeOf(receiver), js.string('string')); - } else if (cls == backend.jsNullClass) { - condition = js.equals(receiver, new js.LiteralNull()); - } else if (cls == backend.jsFunctionClass) { - condition = js.equals(js.typeOf(receiver), js.string('function')); - } else { - throw 'internal error'; - } - return js.if_(condition, buildReturnInterceptor(cls)); - } - - bool hasArray = false; - bool hasBool = false; - bool hasDouble = false; - bool hasFunction = false; - bool hasInt = false; - bool hasNull = false; - bool hasNumber = false; - bool hasString = false; - for (ClassElement cls in classes) { - if (cls == backend.jsArrayClass) hasArray = true; - else if (cls == backend.jsBoolClass) hasBool = true; - else if (cls == backend.jsDoubleClass) hasDouble = true; - else if (cls == backend.jsFunctionClass) hasFunction = true; - else if (cls == backend.jsIntClass) hasInt = true; - else if (cls == backend.jsNullClass) hasNull = true; - else if (cls == backend.jsNumberClass) hasNumber = true; - else if (cls == backend.jsStringClass) hasString = true; - else throw 'Internal error: $cls'; - } - if (hasDouble) { - assert(!hasNumber); - hasNumber = true; - } - if (hasInt) hasNumber = true; - - js.Block block = new js.Block.empty(); - - if (hasNumber) { - js.Statement whenNumber; - - /// Note: there are two number classes in play: Dart's [num], - /// and JavaScript's Number (typeof receiver == 'number'). This - /// is the fallback used when we have determined that receiver - /// is a JavaScript Number. - js.Return returnNumberClass = buildReturnInterceptor( - hasDouble ? backend.jsDoubleClass : backend.jsNumberClass); - - if (hasInt) { - js.Expression isInt = - js.equals(js.call(js.fieldAccess(js.use('Math'), 'floor'), - [receiver]), - receiver); - (whenNumber = js.emptyBlock()).statements - ..add(js.if_(isInt, buildReturnInterceptor(backend.jsIntClass))) - ..add(returnNumberClass); - } else { - whenNumber = returnNumberClass; - } - block.statements.add( - js.if_(js.equals(js.typeOf(receiver), js.string('number')), - whenNumber)); - } - - if (hasString) { - block.statements.add(buildInterceptorCheck(backend.jsStringClass)); - } - if (hasNull) { - block.statements.add(buildInterceptorCheck(backend.jsNullClass)); - } else { - // Returning "undefined" here will provoke a JavaScript - // TypeError which is later identified as a null-error by - // [unwrapException] in js_helper.dart. - block.statements.add(js.if_(js.equals(receiver, new js.LiteralNull()), - js.return_(js.undefined()))); - } - if (hasFunction) { - block.statements.add(buildInterceptorCheck(backend.jsFunctionClass)); - } - if (hasBool) { - block.statements.add(buildInterceptorCheck(backend.jsBoolClass)); - } - // TODO(ahe): It might be faster to check for Array before - // function and bool. - if (hasArray) { - block.statements.add(buildInterceptorCheck(backend.jsArrayClass)); - } - block.statements.add(js.return_(js.fieldAccess(js.use(objectName), - 'prototype'))); - - js.PropertyAccess name = js.fieldAccess(js.use(isolateProperties), key); - buffer.add(js.prettyPrint(js.assign(name, js.fun(['receiver'], block)), - compiler)); - buffer.add(N); - } - - /** - * Emit all versions of the [:getInterceptor:] method. - */ - void emitGetInterceptorMethods(CodeBuffer buffer) { - JavaScriptBackend backend = compiler.backend; - // If no class needs to be intercepted, just return. - if (backend.objectInterceptorClass == null) return; - String objectName = namer.isolateAccess(backend.objectInterceptorClass); - var specializedGetInterceptors = backend.specializedGetInterceptors; - for (String name in specializedGetInterceptors.keys.toList()..sort()) { - Collection<ClassElement> classes = specializedGetInterceptors[name]; - emitGetInterceptorMethod(buffer, objectName, name, classes); - } - } - - void computeNeededClasses() { - instantiatedClasses = - compiler.codegenWorld.instantiatedClasses.where(computeClassFilter()) - .toSet(); - neededClasses = new Set<ClassElement>.from(instantiatedClasses); - for (ClassElement element in instantiatedClasses) { - for (ClassElement superclass = element.superclass; - superclass != null; - superclass = superclass.superclass) { - if (neededClasses.contains(superclass)) break; - neededClasses.add(superclass); - } - } - } - - int _compareSelectors(Selector selector1, Selector selector2) { - int comparison = _compareSelectorNames(selector1, selector2); - if (comparison != 0) return comparison; - - JavaScriptBackend backend = compiler.backend; - Set<ClassElement> classes1 = backend.getInterceptedClassesOn(selector1); - Set<ClassElement> classes2 = backend.getInterceptedClassesOn(selector2); - if (classes1.length != classes2.length) { - return classes1.length - classes2.length; - } - String getInterceptor1 = - namer.getInterceptorName(backend.getInterceptorMethod, classes1); - String getInterceptor2 = - namer.getInterceptorName(backend.getInterceptorMethod, classes2); - return Comparable.compare(getInterceptor1, getInterceptor2); - } - - void emitOneShotInterceptors(CodeBuffer buffer) { - JavaScriptBackend backend = compiler.backend; - for (Selector selector in - backend.oneShotInterceptors.toList()..sort(_compareSelectors)) { - Set<ClassElement> classes = backend.getInterceptedClassesOn(selector); - String oneShotInterceptorName = namer.oneShotInterceptorName(selector); - String getInterceptorName = - namer.getInterceptorName(backend.getInterceptorMethod, classes); - - List<js.Parameter> parameters = <js.Parameter>[]; - List<js.Expression> arguments = <js.Expression>[]; - parameters.add(new js.Parameter('receiver')); - arguments.add(js.use('receiver')); - - if (selector.isSetter()) { - parameters.add(new js.Parameter('value')); - arguments.add(js.use('value')); - } else { - for (int i = 0; i < selector.argumentCount; i++) { - String argName = 'a$i'; - parameters.add(new js.Parameter(argName)); - arguments.add(js.use(argName)); - } - } - - String invocationName = backend.namer.invocationName(selector); - js.Fun function = - new js.Fun(parameters, - js.block1(js.return_( - js.use(isolateProperties) - .dot(getInterceptorName) - .callWith([js.use('receiver')]) - .dot(invocationName) - .callWith(arguments)))); - - js.PropertyAccess property = - js.fieldAccess(js.use(isolateProperties), oneShotInterceptorName); - - buffer.add(js.prettyPrint(js.assign(property, function), compiler)); - buffer.add(N); - } - } - - String assembleProgram() { - measure(() { - computeNeededClasses(); - - mainBuffer.add(GENERATED_BY); - if (!compiler.enableMinification) mainBuffer.add(HOOKS_API_USAGE); - mainBuffer.add('function ${namer.isolateName}()$_{}\n'); - mainBuffer.add('init()$N$n'); - // Shorten the code by using "$$" as temporary. - classesCollector = r"$$"; - mainBuffer.add('var $classesCollector$_=$_{}$N'); - // Shorten the code by using [namer.CURRENT_ISOLATE] as temporary. - isolateProperties = namer.CURRENT_ISOLATE; - mainBuffer.add( - 'var $isolateProperties$_=$_$isolatePropertiesName$N'); - emitClasses(mainBuffer); - mainBuffer.add(boundClosureBuffer); - // Clear the buffer, so that we can reuse it for the native classes. - boundClosureBuffer.clear(); - emitStaticFunctions(mainBuffer); - emitStaticFunctionGetters(mainBuffer); - // We need to finish the classes before we construct compile time - // constants. - emitFinishClassesInvocationIfNecessary(mainBuffer); - emitRuntimeClassesAndTests(mainBuffer); - emitCompileTimeConstants(mainBuffer); - // Static field initializations require the classes and compile-time - // constants to be set up. - emitStaticNonFinalFieldInitializations(mainBuffer); - emitOneShotInterceptors(mainBuffer); - emitGetInterceptorMethods(mainBuffer); - emitLazilyInitializedStaticFields(mainBuffer); - - isolateProperties = isolatePropertiesName; - // The following code should not use the short-hand for the - // initialStatics. - mainBuffer.add('var ${namer.CURRENT_ISOLATE}$_=${_}null$N'); - mainBuffer.add(boundClosureBuffer); - emitFinishClassesInvocationIfNecessary(mainBuffer); - // After this assignment we will produce invalid JavaScript code if we use - // the classesCollector variable. - classesCollector = 'classesCollector should not be used from now on'; - - emitFinishIsolateConstructorInvocation(mainBuffer); - mainBuffer.add('var ${namer.CURRENT_ISOLATE}$_=' - '${_}new ${namer.isolateName}()$N'); - - nativeEmitter.assembleCode(mainBuffer); - emitMain(mainBuffer); - mainBuffer.add('function init()$_{\n'); - mainBuffer.add('$isolateProperties$_=$_{}$N'); - addDefineClassAndFinishClassFunctionsIfNecessary(mainBuffer); - addLazyInitializerFunctionIfNecessary(mainBuffer); - emitFinishIsolateConstructor(mainBuffer); - mainBuffer.add('}\n'); - compiler.assembledCode = mainBuffer.getText(); - - if (generateSourceMap) { - SourceFile compiledFile = new SourceFile(null, compiler.assembledCode); - String sourceMap = buildSourceMap(mainBuffer, compiledFile); - compiler.outputProvider('', 'js.map') - ..add(sourceMap) - ..close(); - } - }); - return compiler.assembledCode; - } - - String buildSourceMap(CodeBuffer buffer, SourceFile compiledFile) { - SourceMapBuilder sourceMapBuilder = new SourceMapBuilder(); - buffer.forEachSourceLocation(sourceMapBuilder.addMapping); - return sourceMapBuilder.build(compiledFile); - } -} - -const String GENERATED_BY = """ -// Generated by dart2js, the Dart to JavaScript compiler. -"""; -const String HOOKS_API_USAGE = """ -// The code supports the following hooks: -// dartPrint(message) - if this function is defined it is called -// instead of the Dart [print] method. -// dartMainRunner(main) - if this function is defined, the Dart [main] -// method will not be invoked directly. -// Instead, a closure that will invoke [main] is -// passed to [dartMainRunner]. -""";
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/emitter_no_eval.dart b/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/emitter_no_eval.dart deleted file mode 100644 index 06d5d01..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/emitter_no_eval.dart +++ /dev/null
@@ -1,138 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of js_backend; - -class CodeEmitterNoEvalTask extends CodeEmitterTask { - CodeEmitterNoEvalTask(Compiler compiler, - Namer namer, - bool generateSourceMap) - : super(compiler, namer, generateSourceMap); - - String get generateGetterSetterFunction { - return """ -function() { - throw 'Internal Error: no dynamic generation of getters and setters allowed'; -}"""; - } - - String get defineClassFunction { - return """ -function(cls, constructor, prototype) { - constructor.prototype = prototype; - constructor.builtin\$cls = cls; - return constructor; -}"""; - } - - String get protoSupportCheck { - // We don't modify the prototypes in CSP mode. Therefore we can have an - // easier prototype-check. - return 'var $supportsProtoName = !!{}.__proto__;\n'; - } - - String get finishIsolateConstructorFunction { - // We replace the old Isolate function with a new one that initializes - // all its field with the initial (and often final) value of all globals. - // - // We also copy over old values like the prototype, and the - // isolateProperties themselves. - return """ -function(oldIsolate) { - var isolateProperties = oldIsolate.${namer.isolatePropertiesName}; - function Isolate() { - for (var staticName in isolateProperties) { - if (Object.prototype.hasOwnProperty.call(isolateProperties, staticName)) { - this[staticName] = isolateProperties[staticName]; - } - } - // Use the newly created object as prototype. In Chrome this creates a - // hidden class for the object and makes sure it is fast to access. - function ForceEfficientMap() {} - ForceEfficientMap.prototype = this; - new ForceEfficientMap; - } - Isolate.prototype = oldIsolate.prototype; - Isolate.prototype.constructor = Isolate; - Isolate.${namer.isolatePropertiesName} = isolateProperties; - return Isolate; -}"""; - } - - String get lazyInitializerFunction { - return """ -function(prototype, staticName, fieldName, getterName, lazyValue, getter) { -$lazyInitializerLogic -}"""; - } - - js.Expression buildLazyInitializedGetter(VariableElement element) { - String isolate = namer.CURRENT_ISOLATE; - return js.fun([], - js.block1( - js.return_( - js.fieldAccess(js.use(isolate), namer.getName(element))))); - } - - js.Expression buildConstructor(String mangledName, List<String> fieldNames) { - return new js.NamedFunction( - new js.VariableDeclaration(mangledName), - new js.Fun( - fieldNames - .map((fieldName) => new js.Parameter(fieldName)) - .toList(), - new js.Block( - fieldNames.map((fieldName) => - new js.ExpressionStatement( - new js.Assignment( - new js.This().dot(fieldName), - new js.VariableUse(fieldName)))) - .toList()))); - } - - void emitBoundClosureClassHeader(String mangledName, - String superName, - List<String> fieldNames, - ClassBuilder builder) { - builder.addProperty('', buildConstructor(mangledName, fieldNames)); - builder.addProperty('super', js.string(superName)); - } - - void emitClassConstructor(ClassElement classElement, ClassBuilder builder) { - // Say we have a class A with fields b, c and d, where c needs a getter and - // d needs both a getter and a setter. Then we produce: - // - a constructor (directly into the given [buffer]): - // function A(b, c, d) { this.b = b, this.c = c, this.d = d; } - // - getters and setters (stored in the [explicitGettersSetters] list): - // get$c : function() { return this.c; } - // get$d : function() { return this.d; } - // set$d : function(x) { this.d = x; } - List<String> fields = <String>[]; - visitClassFields(classElement, (Element member, - String name, - String accessorName, - bool needsGetter, - bool needsSetter, - bool needsCheckedSetter) { - fields.add(name); - }); - String constructorName = namer.safeName(classElement.name.slowToString()); - - builder.addProperty('', buildConstructor(constructorName, fields)); - } - - void emitSuper(String superName, ClassBuilder builder) { - if (superName != '') { - builder.addProperty('super', js.string(superName)); - } - } - - void emitClassFields(ClassElement classElement, - ClassBuilder builder, - { String superClass: "", - bool classIsNative: false}) { - } - - bool get getterAndSetterCanBeImplementedByFieldSpec => false; -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/js_backend.dart b/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/js_backend.dart deleted file mode 100644 index 52e6ee0..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/js_backend.dart +++ /dev/null
@@ -1,33 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library js_backend; - -import 'dart:collection' show LinkedHashMap; - -import '../closure.dart'; -import '../../compiler.dart' as api; -import '../elements/elements.dart'; -import '../elements/modelx.dart' show FunctionElementX; -import '../dart2jslib.dart' hide Selector; -import '../dart_types.dart'; -import '../js/js.dart' as js; -import '../native_handler.dart' as native; -import '../source_file.dart'; -import '../source_map_builder.dart'; -import '../ssa/ssa.dart'; -import '../tree/tree.dart'; -import '../universe/universe.dart'; -import '../util/characters.dart'; -import '../util/util.dart'; - -part 'backend.dart'; -part 'constant_emitter.dart'; -part 'constant_system_javascript.dart'; -part 'emitter.dart'; -part 'emitter_no_eval.dart'; -part 'minify_namer.dart'; -part 'namer.dart'; -part 'native_emitter.dart'; -part 'runtime_types.dart';
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/minify_namer.dart b/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/minify_namer.dart deleted file mode 100644 index 98344a1..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/minify_namer.dart +++ /dev/null
@@ -1,200 +0,0 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of js_backend; - -/** - * Assigns JavaScript identifiers to Dart variables, class-names and members. - */ -class MinifyNamer extends Namer { - MinifyNamer(Compiler compiler) : super(compiler) { - reserveBackendNames(); - } - - String get isolateName => 'I'; - String get isolatePropertiesName => 'p'; - bool get shouldMinify => true; - - const ALPHABET_CHARACTERS = 52; // a-zA-Z. - const ALPHANUMERIC_CHARACTERS = 62; // a-zA-Z0-9. - - // You can pass an invalid identifier to this and unlike its non-minifying - // counterpart it will never return the proposedName as the new fresh name. - String getFreshName(String proposedName, - Set<String> usedNames, - Map<String, String> suggestedNames, - {bool ensureSafe: true}) { - var freshName; - var suggestion = suggestedNames[proposedName]; - if (suggestion != null && !usedNames.contains(suggestion)) { - freshName = suggestion; - } else { - freshName = _getUnusedName(proposedName, usedNames); - } - usedNames.add(freshName); - return freshName; - } - - SourceString getClosureVariableName(SourceString name, int id) { - if (id < ALPHABET_CHARACTERS) { - return new SourceString(new String.fromCharCodes([_letterNumber(id)])); - } - return new SourceString("${getMappedInstanceName('closure')}_$id"); - } - - void reserveBackendNames() { - // From issue 7554. These should not be used on objects (as instance - // variables) because they clash with names from the DOM. - const reservedNativeProperties = const <String>[ - 'Q', 'a', 'b', 'c', 'd', 'e', 'f', 'r', 'x', 'y', 'z', - // 2-letter: - 'ch', 'cx', 'cy', 'db', 'dx', 'dy', 'fr', 'fx', 'fy', 'go', 'id', 'k1', - 'k2', 'k3', 'k4', 'r1', 'r2', 'rx', 'ry', 'x1', 'x2', 'y1', 'y2', - // 3-letter: - 'add', 'all', 'alt', 'arc', 'CCW', 'cmp', 'dir', 'end', 'get', 'in1', - 'in2', 'INT', 'key', 'log', 'low', 'm11', 'm12', 'm13', 'm14', 'm21', - 'm22', 'm23', 'm24', 'm31', 'm32', 'm33', 'm34', 'm41', 'm42', 'm43', - 'm44', 'max', 'min', 'now', 'ONE', 'put', 'red', 'rel', 'rev', 'RGB', - 'sdp', 'set', 'src', 'tag', 'top', 'uid', 'uri', 'url', 'URL', - // 4-letter: - 'abbr', 'atob', 'Attr', 'axes', 'axis', 'back', 'BACK', 'beta', 'bias', - 'Blob', 'blue', 'blur', 'BLUR', 'body', 'BOOL', 'BOTH', 'btoa', 'BYTE', - 'cite', 'clip', 'code', 'cols', 'cues', 'data', 'DECR', 'DONE', 'face', - 'file', 'File', 'fill', 'find', 'font', 'form', 'gain', 'hash', 'head', - 'high', 'hint', 'host', 'href', 'HRTF', 'IDLE', 'INCR', 'info', 'INIT', - 'isId', 'item', 'KEEP', 'kind', 'knee', 'lang', 'left', 'LESS', 'line', - 'link', 'list', 'load', 'loop', 'mode', 'name', 'Node', 'None', 'NONE', - 'only', 'open', 'OPEN', 'ping', 'play', 'port', 'rect', 'Rect', 'refX', - 'refY', 'RGBA', 'root', 'rows', 'save', 'seed', 'seek', 'self', 'send', - 'show', 'SINE', 'size', 'span', 'stat', 'step', 'stop', 'tags', 'text', - 'Text', 'time', 'type', 'view', 'warn', 'wrap', 'ZERO']; - for (var name in reservedNativeProperties) { - if (name.length < 2) { - instanceNameMap[name] = name; - } - usedInstanceNames.add(name); - } - - // This list of popular instance variable names generated with: - // cat out.js | - // perl -ne '$_=~s/(?<![^a-z0-9_\$]\$)\.([a-z0-9_\$]+)/print("$1\n")/gei' | - // sort | uniq -c | sort -nr | head -40 - // Removed: html, call*, hasOwnProperty. - _populateSuggestedNames( - suggestedInstanceNames, - usedInstanceNames, - const <String>[ - r'$add', r'add$1', r'box_0', r'charCodeAt$1', r'constructor', - r'current', r'$defineNativeClass', r'$eq', r'$ne', - r'getPrototypeOf', r'hasOwnProperty', r'$index', r'$indexSet', - r'$isJavaScriptIndexingBehavior', r'$isolateProperties', - r'iterator', r'length', r'$lt', r'$gt', r'$le', r'$ge', - r'moveNext$0', r'node', r'on', r'prototype', r'push', r'self', - r'start', r'target', r'this_0', r'value', r'width', r'style']); - - _populateSuggestedNames( - suggestedGlobalNames, - usedGlobalNames, - const <String>[ - r'Object', r'$throw', r'$eq', r'S', r'ioore', r'UnsupportedError$', - r'length', r'$sub', r'getInterceptor$JSStringJSArray', r'$add', - r'$gt', r'$ge', r'$lt', r'$le', r'add', r'getInterceptor$JSNumber', - r'iterator', r'$index', r'iae', r'getInterceptor$JSArray', - r'ArgumentError$', r'BoundClosure', r'StateError$', - r'getInterceptor', r'max', r'$mul', r'List_List', r'Map_Map', - r'getInterceptor$JSString', r'$div', r'$indexSet', - r'List_List$from', r'Set_Set$from', r'toString', r'toInt', r'min', - r'StringBuffer_StringBuffer', r'contains1', r'WhereIterable$', - r'RangeError$value', r'JSString', r'JSNumber', - r'JSArray' - ]); - } - - void _populateSuggestedNames(Map<String, String> suggestionMap, - Set<String> used, - List<String> suggestions) { - int c = $a - 1; - String letter; - for (String name in suggestions) { - do { - assert(c != $Z); - c = (c == $z) ? $A : c + 1; - letter = new String.fromCharCodes([c]); - } while (used.contains(letter)); - assert(suggestionMap[name] == null); - suggestionMap[name] = letter; - } - } - - - // This gets a minified name based on a hash of the proposed name. This - // is slightly less efficient than just getting the next name in a series, - // but it means that small changes in the input program will give smallish - // changes in the output, which can be useful for diffing etc. - String _getUnusedName(String proposedName, Set<String> usedNames) { - int hash = _calculateHash(proposedName); - // Avoid very small hashes that won't try many names. - hash = hash < 1000 ? hash * 314159 : hash; // Yes, it's prime. - - // Try other n-character names based on the hash. We try one to three - // character identifiers. For each length we try around 10 different names - // in a predictable order determined by the proposed name. This is in order - // to make the renamer stable: small changes in the input should nornally - // result in relatively small changes in the output. - for (var n = 2; n <= 3; n++) { - int h = hash; - while (h > 10) { - var codes = <int>[_letterNumber(h)]; - int h2 = h ~/ ALPHABET_CHARACTERS; - for (var i = 1; i < n; i++) { - codes.add(_alphaNumericNumber(h2)); - h2 ~/= ALPHANUMERIC_CHARACTERS; - } - final candidate = new String.fromCharCodes(codes); - if (!usedNames.contains(candidate) && !jsReserved.contains(candidate)) { - return candidate; - } - // Try again with a slightly different hash. After around 10 turns - // around this loop h is zero and we try a longer name. - h ~/= 7; - } - } - - // If we can't find a hash based name in the three-letter space, then base - // the name on a letter and a counter. - var startLetter = new String.fromCharCodes([_letterNumber(hash)]); - var i = 0; - while (usedNames.contains("$startLetter$i")) { - i++; - } - return "$startLetter$i"; - } - - int _calculateHash(String name) { - int h = 0; - for (int i = 0; i < name.length; i++) { - h += name.charCodeAt(i); - h &= 0xffffffff; - h += h << 10; - h &= 0xffffffff; - h ^= h >> 6; - h &= 0xffffffff; - } - return h; - } - - int _letterNumber(int x) { - if (x >= ALPHABET_CHARACTERS) x %= ALPHABET_CHARACTERS; - if (x < 26) return $a + x; - return $A + x - 26; - } - - int _alphaNumericNumber(int x) { - if (x >= ALPHANUMERIC_CHARACTERS) x %= ALPHANUMERIC_CHARACTERS; - if (x < 26) return $a + x; - if (x < 52) return $A + x - 26; - return $0 + x - 52; - } - -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/namer.dart b/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/namer.dart deleted file mode 100644 index e5bb967..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/namer.dart +++ /dev/null
@@ -1,754 +0,0 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of js_backend; - -/** - * Assigns JavaScript identifiers to Dart variables, class-names and members. - */ -class Namer implements ClosureNamer { - - static const javaScriptKeywords = const <String>[ - // These are current keywords. - "break", "delete", "function", "return", "typeof", "case", "do", "if", - "switch", "var", "catch", "else", "in", "this", "void", "continue", - "false", "instanceof", "throw", "while", "debugger", "finally", "new", - "true", "with", "default", "for", "null", "try", - - // These are future keywords. - "abstract", "double", "goto", "native", "static", "boolean", "enum", - "implements", "package", "super", "byte", "export", "import", "private", - "synchronized", "char", "extends", "int", "protected", "throws", - "class", "final", "interface", "public", "transient", "const", "float", - "long", "short", "volatile" - ]; - - static const reservedPropertySymbols = - const <String>["__proto__", "prototype", "constructor", "call"]; - - // Symbols that we might be using in our JS snippets. - static const reservedGlobalSymbols = const <String>[ - // Section references are from Ecma-262 - // (http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf) - - // 15.1.1 Value Properties of the Global Object - "NaN", "Infinity", "undefined", - - // 15.1.2 Function Properties of the Global Object - "eval", "parseInt", "parseFloat", "isNaN", "isFinite", - - // 15.1.3 URI Handling Function Properties - "decodeURI", "decodeURIComponent", - "encodeURI", - "encodeURIComponent", - - // 15.1.4 Constructor Properties of the Global Object - "Object", "Function", "Array", "String", "Boolean", "Number", "Date", - "RegExp", "Error", "EvalError", "RangeError", "ReferenceError", - "SyntaxError", "TypeError", "URIError", - - // 15.1.5 Other Properties of the Global Object - "Math", - - // 10.1.6 Activation Object - "arguments", - - // B.2 Additional Properties (non-normative) - "escape", "unescape", - - // Window props (https://developer.mozilla.org/en/DOM/window) - "applicationCache", "closed", "Components", "content", "controllers", - "crypto", "defaultStatus", "dialogArguments", "directories", - "document", "frameElement", "frames", "fullScreen", "globalStorage", - "history", "innerHeight", "innerWidth", "length", - "location", "locationbar", "localStorage", "menubar", - "mozInnerScreenX", "mozInnerScreenY", "mozScreenPixelsPerCssPixel", - "name", "navigator", "opener", "outerHeight", "outerWidth", - "pageXOffset", "pageYOffset", "parent", "personalbar", "pkcs11", - "returnValue", "screen", "scrollbars", "scrollMaxX", "scrollMaxY", - "self", "sessionStorage", "sidebar", "status", "statusbar", "toolbar", - "top", "window", - - // Window methods (https://developer.mozilla.org/en/DOM/window) - "alert", "addEventListener", "atob", "back", "blur", "btoa", - "captureEvents", "clearInterval", "clearTimeout", "close", "confirm", - "disableExternalCapture", "dispatchEvent", "dump", - "enableExternalCapture", "escape", "find", "focus", "forward", - "GeckoActiveXObject", "getAttention", "getAttentionWithCycleCount", - "getComputedStyle", "getSelection", "home", "maximize", "minimize", - "moveBy", "moveTo", "open", "openDialog", "postMessage", "print", - "prompt", "QueryInterface", "releaseEvents", "removeEventListener", - "resizeBy", "resizeTo", "restore", "routeEvent", "scroll", "scrollBy", - "scrollByLines", "scrollByPages", "scrollTo", "setInterval", - "setResizeable", "setTimeout", "showModalDialog", "sizeToContent", - "stop", "uuescape", "updateCommands", "XPCNativeWrapper", - "XPCSafeJSOjbectWrapper", - - // Mozilla Window event handlers, same cite - "onabort", "onbeforeunload", "onchange", "onclick", "onclose", - "oncontextmenu", "ondragdrop", "onerror", "onfocus", "onhashchange", - "onkeydown", "onkeypress", "onkeyup", "onload", "onmousedown", - "onmousemove", "onmouseout", "onmouseover", "onmouseup", - "onmozorientation", "onpaint", "onreset", "onresize", "onscroll", - "onselect", "onsubmit", "onunload", - - // Safari Web Content Guide - // http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/SafariWebContent.pdf - // WebKit Window member data, from WebKit DOM Reference - // (http://developer.apple.com/safari/library/documentation/AppleApplications/Reference/WebKitDOMRef/DOMWindow_idl/Classes/DOMWindow/index.html) - "ontouchcancel", "ontouchend", "ontouchmove", "ontouchstart", - "ongesturestart", "ongesturechange", "ongestureend", - - // extra window methods - "uneval", - - // keywords https://developer.mozilla.org/en/New_in_JavaScript_1.7, - // https://developer.mozilla.org/en/New_in_JavaScript_1.8.1 - "getPrototypeOf", "let", "yield", - - // "future reserved words" - "abstract", "int", "short", "boolean", "interface", "static", "byte", - "long", "char", "final", "native", "synchronized", "float", "package", - "throws", "goto", "private", "transient", "implements", "protected", - "volatile", "double", "public", - - // IE methods - // (http://msdn.microsoft.com/en-us/library/ms535873(VS.85).aspx#) - "attachEvent", "clientInformation", "clipboardData", "createPopup", - "dialogHeight", "dialogLeft", "dialogTop", "dialogWidth", - "onafterprint", "onbeforedeactivate", "onbeforeprint", - "oncontrolselect", "ondeactivate", "onhelp", "onresizeend", - - // Common browser-defined identifiers not defined in ECMAScript - "event", "external", "Debug", "Enumerator", "Global", "Image", - "ActiveXObject", "VBArray", "Components", - - // Functions commonly defined on Object - "toString", "getClass", "constructor", "prototype", "valueOf", - - // Client-side JavaScript identifiers - "Anchor", "Applet", "Attr", "Canvas", "CanvasGradient", - "CanvasPattern", "CanvasRenderingContext2D", "CDATASection", - "CharacterData", "Comment", "CSS2Properties", "CSSRule", - "CSSStyleSheet", "Document", "DocumentFragment", "DocumentType", - "DOMException", "DOMImplementation", "DOMParser", "Element", "Event", - "ExternalInterface", "FlashPlayer", "Form", "Frame", "History", - "HTMLCollection", "HTMLDocument", "HTMLElement", "IFrame", "Image", - "Input", "JSObject", "KeyEvent", "Link", "Location", "MimeType", - "MouseEvent", "Navigator", "Node", "NodeList", "Option", "Plugin", - "ProcessingInstruction", "Range", "RangeException", "Screen", "Select", - "Table", "TableCell", "TableRow", "TableSelection", "Text", "TextArea", - "UIEvent", "Window", "XMLHttpRequest", "XMLSerializer", - "XPathException", "XPathResult", "XSLTProcessor", - - // These keywords trigger the loading of the java-plugin. For the - // next-generation plugin, this results in starting a new Java process. - "java", "Packages", "netscape", "sun", "JavaObject", "JavaClass", - "JavaArray", "JavaMember" - ]; - - Set<String> _jsReserved = null; - /// Names that cannot be used by members, top level and static - /// methods. - Set<String> get jsReserved { - if (_jsReserved == null) { - _jsReserved = new Set<String>(); - _jsReserved.addAll(javaScriptKeywords); - _jsReserved.addAll(reservedPropertySymbols); - } - return _jsReserved; - } - - Set<String> _jsVariableReserved = null; - /// Names that cannot be used by local variables and parameters. - Set<String> get jsVariableReserved { - if (_jsVariableReserved == null) { - _jsVariableReserved = new Set<String>(); - _jsVariableReserved.addAll(javaScriptKeywords); - _jsVariableReserved.addAll(reservedPropertySymbols); - _jsVariableReserved.addAll(reservedGlobalSymbols); - } - return _jsVariableReserved; - } - - final String CURRENT_ISOLATE = r'$'; - - /** - * Map from top-level or static elements to their unique identifiers provided - * by [getName]. - * - * Invariant: Keys must be declaration elements. - */ - final Compiler compiler; - final Map<Element, String> globals; - final Map<Selector, String> oneShotInterceptorNames; - final Map<String, LibraryElement> shortPrivateNameOwners; - - final Set<String> usedGlobalNames; - final Set<String> usedInstanceNames; - final Map<String, String> globalNameMap; - final Map<String, String> suggestedGlobalNames; - final Map<String, String> instanceNameMap; - final Map<String, String> suggestedInstanceNames; - - final Map<String, String> operatorNameMap; - final Map<String, int> popularNameCounters; - - final Map<Element, String> bailoutNames; - - final Map<Constant, String> constantNames; - - Namer(this.compiler) - : globals = new Map<Element, String>(), - oneShotInterceptorNames = new Map<Selector, String>(), - shortPrivateNameOwners = new Map<String, LibraryElement>(), - bailoutNames = new Map<Element, String>(), - usedGlobalNames = new Set<String>(), - usedInstanceNames = new Set<String>(), - instanceNameMap = new Map<String, String>(), - operatorNameMap = new Map<String, String>(), - globalNameMap = new Map<String, String>(), - suggestedGlobalNames = new Map<String, String>(), - suggestedInstanceNames = new Map<String, String>(), - constantNames = new Map<Constant, String>(), - popularNameCounters = new Map<String, int>(); - - String get isolateName => 'Isolate'; - String get isolatePropertiesName => r'$isolateProperties'; - /** - * Some closures must contain their name. The name is stored in - * [STATIC_CLOSURE_NAME_NAME]. - */ - String get STATIC_CLOSURE_NAME_NAME => r'$name'; - SourceString get closureInvocationSelectorName => Compiler.CALL_OPERATOR_NAME; - bool get shouldMinify => false; - - bool isReserved(String name) => name == isolateName; - - String constantName(Constant constant) { - // In the current implementation it doesn't make sense to give names to - // function constants since the function-implementation itself serves as - // constant and can be accessed directly. - assert(!constant.isFunction()); - String result = constantNames[constant]; - if (result == null) { - String longName; - if (shouldMinify) { - if (constant.isString()) { - StringConstant stringConstant = constant; - // The minifier always constructs a new name, using the argument as - // input to its hashing algorithm. The given name does not need to be - // valid. - longName = stringConstant.value.slowToString(); - } else { - longName = "C"; - } - } else { - longName = "CONSTANT"; - } - result = getFreshName(longName, usedGlobalNames, suggestedGlobalNames, - ensureSafe: true); - constantNames[constant] = result; - } - return result; - } - - String breakLabelName(LabelElement label) { - return '\$${label.labelName}\$${label.target.nestingLevel}'; - } - - String implicitBreakLabelName(TargetElement target) { - return '\$${target.nestingLevel}'; - } - - // We sometimes handle continue targets differently from break targets, - // so we have special continue-only labels. - String continueLabelName(LabelElement label) { - return 'c\$${label.labelName}\$${label.target.nestingLevel}'; - } - - String implicitContinueLabelName(TargetElement target) { - return 'c\$${target.nestingLevel}'; - } - - /** - * If the [name] is not private returns [:name.slowToString():]. Otherwise - * mangles the [name] so that each library has a unique name. - */ - String privateName(LibraryElement library, SourceString name) { - // Public names are easy. - String nameString = name.slowToString(); - if (!name.isPrivate()) return nameString; - - // The first library asking for a short private name wins. - LibraryElement owner = shouldMinify - ? library - : shortPrivateNameOwners.putIfAbsent(nameString, () => library); - - // If a private name could clash with a mangled private name we don't - // use the short name. For example a private name "_lib3_foo" would - // clash with "_foo" from "lib3". - if (owner == library && - !nameString.startsWith('_$LIBRARY_PREFIX') && - !shouldMinify) { - return nameString; - } - - // If a library name does not start with the [LIBRARY_PREFIX] then our - // assumptions about clashing with mangled private members do not hold. - String libraryName = getName(library); - assert(shouldMinify || libraryName.startsWith(LIBRARY_PREFIX)); - // TODO(erikcorry): Fix this with other manglings to avoid clashes. - return '_lib$libraryName\$$nameString'; - } - - String instanceMethodName(FunctionElement element) { - SourceString elementName = element.name; - SourceString name = operatorNameToIdentifier(elementName); - if (name != elementName) return getMappedOperatorName(name.slowToString()); - - LibraryElement library = element.getLibrary(); - if (element.kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY) { - ConstructorBodyElement bodyElement = element; - name = bodyElement.constructor.name; - } - FunctionSignature signature = element.computeSignature(compiler); - String methodName = - '${privateName(library, name)}\$${signature.parameterCount}'; - if (signature.optionalParametersAreNamed && - !signature.optionalParameters.isEmpty) { - StringBuffer buffer = new StringBuffer(); - signature.orderedOptionalParameters.forEach((Element element) { - buffer.add('\$${safeName(element.name.slowToString())}'); - }); - methodName = '$methodName$buffer'; - } - if (name == closureInvocationSelectorName) return methodName; - return getMappedInstanceName(methodName); - } - - String publicInstanceMethodNameByArity(SourceString name, int arity) { - SourceString newName = operatorNameToIdentifier(name); - if (newName != name) return getMappedOperatorName(newName.slowToString()); - assert(!name.isPrivate()); - var base = name.slowToString(); - // We don't mangle the closure invoking function name because it - // is generated by string concatenation in applyFunction from - // js_helper.dart. - var proposedName = '$base\$$arity'; - if (name == closureInvocationSelectorName) return proposedName; - return getMappedInstanceName(proposedName); - } - - String invocationName(Selector selector) { - if (selector.isGetter()) { - String proposedName = privateName(selector.library, selector.name); - return 'get\$${getMappedInstanceName(proposedName)}'; - } else if (selector.isSetter()) { - String proposedName = privateName(selector.library, selector.name); - return 'set\$${getMappedInstanceName(proposedName)}'; - } else { - SourceString name = selector.name; - if (selector.kind == SelectorKind.OPERATOR - || selector.kind == SelectorKind.INDEX) { - name = operatorNameToIdentifier(name); - assert(name != selector.name); - return getMappedOperatorName(name.slowToString()); - } - assert(name == operatorNameToIdentifier(name)); - StringBuffer buffer = new StringBuffer(); - for (SourceString argumentName in selector.getOrderedNamedArguments()) { - buffer.add(r'$'); - argumentName.printOn(buffer); - } - String suffix = '\$${selector.argumentCount}$buffer'; - // We don't mangle the closure invoking function name because it - // is generated by string concatenation in applyFunction from - // js_helper.dart. - if (selector.isClosureCall()) { - return "${name.slowToString()}$suffix"; - } else { - String proposedName = privateName(selector.library, name); - return getMappedInstanceName('$proposedName$suffix'); - } - } - } - - /** - * Returns the internal name used for an invocation mirror of this selector. - */ - String invocationMirrorInternalName(Selector selector) - => invocationName(selector); - - String instanceFieldName(Element element) { - String proposedName = privateName(element.getLibrary(), element.name); - return getMappedInstanceName(proposedName); - } - - // Construct a new name for the element based on the library and class it is - // in. The name here is not important, we just need to make sure it is - // unique. If we are minifying, we actually construct the name from the - // minified versions of the class and instance names, but the result is - // minified once again, so that is not visible in the end result. - String shadowedFieldName(Element fieldElement) { - // Check for following situation: Native field ${fieldElement.name} has - // fixed JSName ${fieldElement.nativeName()}, but a subclass shadows this - // name. We normally handle that by renaming the superclass field, but we - // can't do that because native fields have fixed JavaScript names. - // In practice this can't happen because we can't inherit from native - // classes. - assert (!fieldElement.hasFixedBackendName()); - - String libraryName = getName(fieldElement.getLibrary()); - String className = getName(fieldElement.getEnclosingClass()); - String instanceName = instanceFieldName(fieldElement); - return getMappedInstanceName('$libraryName\$$className\$$instanceName'); - } - - String setterName(Element element) { - // We dynamically create setters from the field-name. The setter name must - // therefore be derived from the instance field-name. - LibraryElement library = element.getLibrary(); - String name = getMappedInstanceName(privateName(library, element.name)); - return 'set\$$name'; - } - - String setterNameFromAccessorName(String name) { - // We dynamically create setters from the field-name. The setter name must - // therefore be derived from the instance field-name. - return 'set\$$name'; - } - - String publicGetterName(SourceString name) { - // We dynamically create getters from the field-name. The getter name must - // therefore be derived from the instance field-name. - String fieldName = getMappedInstanceName(name.slowToString()); - return 'get\$$fieldName'; - } - - String getterNameFromAccessorName(String name) { - // We dynamically create getters from the field-name. The getter name must - // therefore be derived from the instance field-name. - return 'get\$$name'; - } - - String getterName(Element element) { - // We dynamically create getters from the field-name. The getter name must - // therefore be derived from the instance field-name. - LibraryElement library = element.getLibrary(); - String name = getMappedInstanceName(privateName(library, element.name)); - return 'get\$$name'; - } - - String getMappedGlobalName(String proposedName) { - var newName = globalNameMap[proposedName]; - if (newName == null) { - newName = getFreshName(proposedName, usedGlobalNames, - suggestedGlobalNames, ensureSafe: true); - globalNameMap[proposedName] = newName; - } - return newName; - } - - String getMappedInstanceName(String proposedName) { - var newName = instanceNameMap[proposedName]; - if (newName == null) { - newName = getFreshName(proposedName, usedInstanceNames, - suggestedInstanceNames, ensureSafe: true); - instanceNameMap[proposedName] = newName; - } - return newName; - } - - String getMappedOperatorName(String proposedName) { - var newName = operatorNameMap[proposedName]; - if (newName == null) { - newName = getFreshName(proposedName, usedInstanceNames, - suggestedInstanceNames, ensureSafe: false); - operatorNameMap[proposedName] = newName; - } - return newName; - } - - String getFreshName(String proposedName, - Set<String> usedNames, - Map<String, String> suggestedNames, - {bool ensureSafe: true}) { - var candidate; - if (ensureSafe) { - proposedName = safeName(proposedName); - } - assert(!jsReserved.contains(proposedName)); - if (!usedNames.contains(proposedName)) { - candidate = proposedName; - } else { - var counter = popularNameCounters[proposedName]; - var i = counter == null ? 0 : counter; - while (usedNames.contains("$proposedName$i")) { - i++; - } - popularNameCounters[proposedName] = i + 1; - candidate = "$proposedName$i"; - } - usedNames.add(candidate); - return candidate; - } - - SourceString getClosureVariableName(SourceString name, int id) { - return new SourceString("${name.slowToString()}_$id"); - } - - static const String LIBRARY_PREFIX = "lib"; - - /** - * Returns a preferred JS-id for the given top-level or static element. - * The returned id is guaranteed to be a valid JS-id. - */ - String _computeGuess(Element element) { - assert(!element.isInstanceMember()); - String name; - if (element.isGenerativeConstructor()) { - if (element.name == element.getEnclosingClass().name) { - // Keep the class name for the class and not the factory. - name = "${element.name.slowToString()}\$"; - } else { - name = element.name.slowToString(); - } - } else if (Elements.isStaticOrTopLevel(element)) { - if (element.isMember()) { - ClassElement enclosingClass = element.getEnclosingClass(); - name = "${enclosingClass.name.slowToString()}_" - "${element.name.slowToString()}"; - } else { - name = element.name.slowToString(); - } - } else if (element.isLibrary()) { - name = LIBRARY_PREFIX; - } else { - name = element.name.slowToString(); - } - return name; - } - - String getInterceptorName(Element element, Collection<ClassElement> classes) { - if (classes.contains(compiler.objectClass)) { - // If the object class is in the set of intercepted classes, we - // need to go through the generic getInterceptorMethod. - return getName(element); - } - // Use the unminified names here to construct the interceptor names. This - // helps ensure that they don't all suddenly change names due to a name - // clash in the minifier, which would affect the diff size. - StringBuffer buffer = new StringBuffer('${element.name.slowToString()}\$'); - for (ClassElement cls in classes) { - buffer.add(cls.name.slowToString()); - } - return getMappedGlobalName(buffer.toString()); - } - - String getBailoutName(Element element) { - String name = bailoutNames[element]; - if (name != null) return name; - bool global = !element.isInstanceMember(); - // Despite the name of the variable, this gets the minified name when we - // are minifying, but it doesn't really make much difference. The - // important thing is that it is a unique name. We add $bailout and, if we - // are minifying, we minify the minified name and '$bailout'. - String unminifiedName = '${getName(element)}\$bailout'; - if (global) { - name = getMappedGlobalName(unminifiedName); - } else { - // Make sure two bailout methods on the same inheritance chain do not have - // the same name to prevent a subclass bailout method being accidentally - // called from the superclass main method. Use the count of the number of - // elements with the same name on the superclass chain to disambiguate - // based on 'level'. - int level = 0; - ClassElement classElement = element.getEnclosingClass().superclass; - while (classElement != null) { - if (classElement.localLookup(element.name) != null) level++; - classElement = classElement.superclass; - } - name = unminifiedName; - if (level != 0) { - name = '$unminifiedName$level'; - } - name = getMappedInstanceName(name); - } - bailoutNames[element] = name; - return name; - } - - /** - * Returns a preferred JS-id for the given element. The returned id is - * guaranteed to be a valid JS-id. Globals and static fields are furthermore - * guaranteed to be unique. - * - * For accessing statics consider calling - * [isolateAccess]/[isolateBailoutAccess] or [isolatePropertyAccess] instead. - */ - String getName(Element element) { - if (element.isInstanceMember()) { - if (element.kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY - || element.kind == ElementKind.FUNCTION) { - return instanceMethodName(element); - } else if (element.kind == ElementKind.GETTER) { - return getterName(element); - } else if (element.kind == ElementKind.SETTER) { - return setterName(element); - } else if (element.kind == ElementKind.FIELD) { - return instanceFieldName(element); - } else { - compiler.internalError('getName for bad kind: ${element.kind}', - node: element.parseNode(compiler)); - } - } else { - // Use declaration element to ensure invariant on [globals]. - element = element.declaration; - // Dealing with a top-level or static element. - String cached = globals[element]; - if (cached != null) return cached; - - String guess = _computeGuess(element); - ElementKind kind = element.kind; - if (kind == ElementKind.VARIABLE || - kind == ElementKind.PARAMETER) { - // The name is not guaranteed to be unique. - return safeName(guess); - } - if (kind == ElementKind.GENERATIVE_CONSTRUCTOR || - kind == ElementKind.FUNCTION || - kind == ElementKind.CLASS || - kind == ElementKind.FIELD || - kind == ElementKind.GETTER || - kind == ElementKind.SETTER || - kind == ElementKind.TYPEDEF || - kind == ElementKind.LIBRARY || - kind == ElementKind.MALFORMED_TYPE) { - bool fixedName = false; - if (kind == ElementKind.CLASS) { - ClassElement classElement = element; - } - if (Elements.isInstanceField(element)) { - fixedName = element.hasFixedBackendName(); - } - String result = fixedName - ? guess - : getFreshName(guess, usedGlobalNames, suggestedGlobalNames, - ensureSafe: true); - globals[element] = result; - return result; - } - compiler.internalError('getName for unknown kind: ${element.kind}', - node: element.parseNode(compiler)); - } - } - - String getLazyInitializerName(Element element) { - assert(Elements.isStaticOrTopLevelField(element)); - return getMappedGlobalName("get\$${getName(element)}"); - } - - String isolatePropertiesAccess(Element element) { - return "$isolateName.$isolatePropertiesName.${getName(element)}"; - } - - String isolateAccess(Element element) { - return "$CURRENT_ISOLATE.${getName(element)}"; - } - - String isolateBailoutAccess(Element element) { - String newName = getMappedGlobalName('${getName(element)}\$bailout'); - return '$CURRENT_ISOLATE.$newName'; - } - - String isolateLazyInitializerAccess(Element element) { - return "$CURRENT_ISOLATE.${getLazyInitializerName(element)}"; - } - - String operatorIsPrefix() => r'$is'; - - String operatorIs(Element element) { - // TODO(erikcorry): Reduce from $isx to ix when we are minifying. - return '${operatorIsPrefix()}${getName(element)}'; - } - - /* - * Returns a name that does not clash with reserved JS keywords, - * and also ensures it won't clash with other identifiers. - */ - String _safeName(String name, Set<String> reserved) { - if (reserved.contains(name) || name.startsWith(r'$')) { - name = '\$$name'; - } - assert(!reserved.contains(name)); - return name; - } - - String safeName(String name) => _safeName(name, jsReserved); - String safeVariableName(String name) => _safeName(name, jsVariableReserved); - - String oneShotInterceptorName(Selector selector) { - // TODO(ngeoffray): What to do about typed selectors? We could - // filter them out, or keep them and hope the generated one shot - // interceptor takes advantage of the type. - String cached = oneShotInterceptorNames[selector]; - if (cached != null) return cached; - SourceString name = operatorNameToIdentifier(selector.name); - String result = getFreshName(name.slowToString(), usedGlobalNames, - suggestedGlobalNames); - oneShotInterceptorNames[selector] = result; - return result; - } - - SourceString operatorNameToIdentifier(SourceString name) { - if (name == null) return null; - String value = name.stringValue; - if (value == null) { - return name; - } else if (value == '==') { - return const SourceString(r'$eq'); - } else if (value == '~') { - return const SourceString(r'$not'); - } else if (value == '[]') { - return const SourceString(r'$index'); - } else if (value == '[]=') { - return const SourceString(r'$indexSet'); - } else if (value == '*') { - return const SourceString(r'$mul'); - } else if (value == '/') { - return const SourceString(r'$div'); - } else if (value == '%') { - return const SourceString(r'$mod'); - } else if (value == '~/') { - return const SourceString(r'$tdiv'); - } else if (value == '+') { - return const SourceString(r'$add'); - } else if (value == '<<') { - return const SourceString(r'$shl'); - } else if (value == '>>') { - return const SourceString(r'$shr'); - } else if (value == '>=') { - return const SourceString(r'$ge'); - } else if (value == '>') { - return const SourceString(r'$gt'); - } else if (value == '<=') { - return const SourceString(r'$le'); - } else if (value == '<') { - return const SourceString(r'$lt'); - } else if (value == '&') { - return const SourceString(r'$and'); - } else if (value == '^') { - return const SourceString(r'$xor'); - } else if (value == '|') { - return const SourceString(r'$or'); - } else if (value == '-') { - return const SourceString(r'$sub'); - } else if (value == 'unary-') { - return const SourceString(r'$negate'); - } else { - return name; - } - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/native_emitter.dart b/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/native_emitter.dart deleted file mode 100644 index 9400f5f..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/native_emitter.dart +++ /dev/null
@@ -1,546 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of js_backend; - -class NativeEmitter { - - CodeEmitterTask emitter; - CodeBuffer nativeBuffer; - - // Classes that participate in dynamic dispatch. These are the - // classes that contain used members. - Set<ClassElement> classesWithDynamicDispatch; - - // Native classes found in the application. - Set<ClassElement> nativeClasses; - - // Caches the native subtypes of a native class. - Map<ClassElement, List<ClassElement>> subtypes; - - // Caches the direct native subtypes of a native class. - Map<ClassElement, List<ClassElement>> directSubtypes; - - // Caches the native methods that are overridden by a native class. - // Note that the method that overrides does not have to be native: - // it's the overridden method that must make sure it will dispatch - // to its subclass if it sees an instance whose class is a subclass. - Set<FunctionElement> overriddenMethods; - - // Caches the methods that have a native body. - Set<FunctionElement> nativeMethods; - - // Do we need the native emitter to take care of handling - // noSuchMethod for us? This flag is set to true in the emitter if - // it finds any native class that needs noSuchMethod handling. - bool handleNoSuchMethod = false; - - NativeEmitter(this.emitter) - : classesWithDynamicDispatch = new Set<ClassElement>(), - nativeClasses = new Set<ClassElement>(), - subtypes = new Map<ClassElement, List<ClassElement>>(), - directSubtypes = new Map<ClassElement, List<ClassElement>>(), - overriddenMethods = new Set<FunctionElement>(), - nativeMethods = new Set<FunctionElement>(), - nativeBuffer = new CodeBuffer(); - - Compiler get compiler => emitter.compiler; - JavaScriptBackend get backend => compiler.backend; - - String get _ => emitter._; - String get n => emitter.n; - String get N => emitter.N; - - String get dynamicName { - Element element = compiler.findHelper( - const SourceString('dynamicFunction')); - return backend.namer.isolateAccess(element); - } - - String get dynamicSetMetadataName { - Element element = compiler.findHelper( - const SourceString('dynamicSetMetadata')); - return backend.namer.isolateAccess(element); - } - - String get typeNameOfName { - Element element = compiler.findHelper( - const SourceString('getTypeNameOf')); - return backend.namer.isolateAccess(element); - } - - String get defPropName { - Element element = compiler.findHelper( - const SourceString('defineProperty')); - return backend.namer.isolateAccess(element); - } - - String get toStringHelperName { - Element element = compiler.findHelper( - const SourceString('toStringForNativeObject')); - return backend.namer.isolateAccess(element); - } - - String get hashCodeHelperName { - Element element = compiler.findHelper( - const SourceString('hashCodeForNativeObject')); - return backend.namer.isolateAccess(element); - } - - String get defineNativeClassName - => '${backend.namer.CURRENT_ISOLATE}.\$defineNativeClass'; - - String get defineNativeClassFunction { - return """ -function(cls, desc) { - var fields = desc['']; - var fields_array = fields ? fields.split(',') : []; - for (var i = 0; i < fields_array.length; i++) { - ${emitter.currentGenerateAccessorName}(fields_array[i], desc); - } - var hasOwnProperty = Object.prototype.hasOwnProperty; - for (var method in desc) { - if (method) { - if (hasOwnProperty.call(desc, method)) { - $dynamicName(method)[cls] = desc[method]; - } - } - } -}"""; - } - - bool isNativeGlobal(String quotedName) { - return identical(quotedName[1], '@'); - } - - String toNativeTag(ClassElement cls) { - String quotedName = cls.nativeTagInfo.slowToString(); - if (isNativeGlobal(quotedName)) { - // Global object, just be like the other types for now. - return quotedName.substring(3, quotedName.length - 1); - } else { - return quotedName.substring(2, quotedName.length - 1); - } - } - - void generateNativeClass(ClassElement classElement) { - assert(!classElement.hasBackendMembers); - nativeClasses.add(classElement); - - ClassBuilder builder = new ClassBuilder(); - emitter.emitClassFields(classElement, builder, classIsNative: true); - emitter.emitClassGettersSetters(classElement, builder); - emitter.emitInstanceMembers(classElement, builder); - - // An empty native class may be omitted since the superclass methods can be - // located via the dispatch metadata. - if (builder.properties.isEmpty) return; - - String nativeTag = toNativeTag(classElement); - js.Expression definition = - js.call(js.use(defineNativeClassName), - [js.string(nativeTag), builder.toObjectInitializer()]); - - nativeBuffer.add(js.prettyPrint(definition, compiler)); - nativeBuffer.add('$N$n'); - - classesWithDynamicDispatch.add(classElement); - } - - List<ClassElement> getDirectSubclasses(ClassElement cls) { - List<ClassElement> result = directSubtypes[cls]; - return result == null ? const<ClassElement>[] : result; - } - - void potentiallyConvertDartClosuresToJs(List<js.Statement> statements, - FunctionElement member, - List<js.Parameter> stubParameters) { - FunctionSignature parameters = member.computeSignature(compiler); - Element converter = - compiler.findHelper(const SourceString('convertDartClosureToJS')); - String closureConverter = backend.namer.isolateAccess(converter); - Set<String> stubParameterNames = new Set<String>.from( - stubParameters.map((param) => param.name)); - parameters.forEachParameter((Element parameter) { - String name = parameter.name.slowToString(); - // If [name] is not in [stubParameters], then the parameter is an optional - // parameter that was not provided for this stub. - for (js.Parameter stubParameter in stubParameters) { - if (stubParameter.name == name) { - DartType type = parameter.computeType(compiler).unalias(compiler); - if (type is FunctionType) { - // The parameter type is a function type either directly or through - // typedef(s). - int arity = type.computeArity(); - - statements.add( - new js.ExpressionStatement( - js.assign( - js.use(name), - js.use(closureConverter).callWith( - [js.use(name), new js.LiteralNumber('$arity')])))); - break; - } - } - } - }); - } - - List<js.Statement> generateParameterStubStatements( - Element member, - String invocationName, - List<js.Parameter> stubParameters, - List<js.Expression> argumentsBuffer, - int indexOfLastOptionalArgumentInParameters) { - // The target JS function may check arguments.length so we need to - // make sure not to pass any unspecified optional arguments to it. - // For example, for the following Dart method: - // foo([x, y, z]); - // The call: - // foo(y: 1) - // must be turned into a JS call to: - // foo(null, y). - - ClassElement classElement = member.enclosingElement; - String nativeTagInfo = classElement.nativeTagInfo.slowToString(); - - List<js.Statement> statements = <js.Statement>[]; - potentiallyConvertDartClosuresToJs(statements, member, stubParameters); - - String target; - List<js.Expression> arguments; - - if (!nativeMethods.contains(member)) { - // When calling a method that has a native body, we call it with our - // calling conventions. - target = backend.namer.getName(member); - arguments = argumentsBuffer; - } else { - // When calling a JS method, we call it with the native name, and only the - // arguments up until the last one provided. - target = member.fixedBackendName(); - arguments = argumentsBuffer.getRange( - 0, indexOfLastOptionalArgumentInParameters + 1); - } - statements.add( - new js.Return( - new js.VariableUse('this').dot(target).callWith(arguments))); - - if (!overriddenMethods.contains(member)) { - // Call the method directly. - return statements; - } else { - return <js.Statement>[ - generateMethodBodyWithPrototypeCheck( - invocationName, new js.Block(statements), stubParameters)]; - } - } - - // If a method is overridden, we must check if the prototype of 'this' has the - // method available. Otherwise, we may end up calling the method from the - // super class. If the method is not available, we make a direct call to - // Object.prototype.$methodName. This method will patch the prototype of - // 'this' to the real method. - js.Statement generateMethodBodyWithPrototypeCheck( - String methodName, - js.Statement body, - List<js.Parameter> parameters) { - return js.if_( - js.use('Object').dot('getPrototypeOf') - .callWith([js.use('this')]) - .dot('hasOwnProperty').callWith([js.string(methodName)]), - body, - js.return_( - js.use('Object').dot('prototype').dot(methodName).dot('call') - .callWith( - <js.Expression>[js.use('this')]..addAll( - parameters.map((param) => js.use(param.name)))))); - } - - js.Block generateMethodBodyWithPrototypeCheckForElement( - FunctionElement element, - js.Block body, - List<js.Parameter> parameters) { - ElementKind kind = element.kind; - if (kind != ElementKind.FUNCTION && - kind != ElementKind.GETTER && - kind != ElementKind.SETTER) { - compiler.internalError("unexpected kind: '$kind'", element: element); - } - - String methodName = backend.namer.getName(element); - return new js.Block( - [generateMethodBodyWithPrototypeCheck(methodName, body, parameters)]); - } - - - void emitDynamicDispatchMetadata() { - if (classesWithDynamicDispatch.isEmpty) return; - int length = classesWithDynamicDispatch.length; - if (!compiler.enableMinification) { - nativeBuffer.add('// $length dynamic classes.\n'); - } - - // Build a pre-order traversal over all the classes and their subclasses. - Set<ClassElement> seen = new Set<ClassElement>(); - List<ClassElement> classes = <ClassElement>[]; - void visit(ClassElement cls) { - if (seen.contains(cls)) return; - seen.add(cls); - getDirectSubclasses(cls).forEach(visit); - classes.add(cls); - } - classesWithDynamicDispatch.forEach(visit); - - List<ClassElement> preorderDispatchClasses = classes.where( - (cls) => !getDirectSubclasses(cls).isEmpty && - classesWithDynamicDispatch.contains(cls)).toList(); - - if (!compiler.enableMinification) { - nativeBuffer.add('// ${classes.length} classes\n'); - } - Iterable<ClassElement> classesThatHaveSubclasses = classes.where( - (ClassElement t) => !getDirectSubclasses(t).isEmpty); - if (!compiler.enableMinification) { - nativeBuffer.add('// ${classesThatHaveSubclasses.length} !leaf\n'); - } - - // Generate code that builds the map from cls tags used in dynamic dispatch - // to the set of cls tags of classes that extend (TODO: or implement) those - // classes. The set is represented as a string of tags joined with '|'. - // This is easily split into an array of tags, or converted into a regexp. - // - // To reduce the size of the sets, subsets are CSE-ed out into variables. - // The sets could be much smaller if we could make assumptions about the - // cls tags of other classes (which are constructor names or part of the - // result of Object.protocls.toString). For example, if objects that are - // Dart objects could be easily excluded, then we might be able to simplify - // the test, replacing dozens of HTMLxxxElement classes with the regexp - // /HTML.*Element/. - - // Temporary variables for common substrings. - List<String> varNames = <String>[]; - // Values of temporary variables. - Map<String, js.Expression> varDefns = new Map<String, js.Expression>(); - - // Expression to compute tags string for a class. The expression will - // initially be a string or expression building a string, but may be - // replaced with a variable reference to the common substring. - Map<ClassElement, js.Expression> tagDefns = - new Map<ClassElement, js.Expression>(); - - js.Expression makeExpression(ClassElement classElement) { - // Expression fragments for this set of cls keys. - List<js.Expression> expressions = <js.Expression>[]; - // TODO: Remove if cls is abstract. - List<String> subtags = [toNativeTag(classElement)]; - void walk(ClassElement cls) { - for (final ClassElement subclass in getDirectSubclasses(cls)) { - ClassElement tag = subclass; - js.Expression existing = tagDefns[tag]; - if (existing == null) { - // [subclass] is still within the subtree between dispatch classes. - subtags.add(toNativeTag(tag)); - walk(subclass); - } else { - // [subclass] is one of the preorderDispatchClasses, so CSE this - // reference with the previous reference. - js.VariableUse use = existing.asVariableUse(); - if (use != null && varDefns.containsKey(use.name)) { - // We end up here if the subclasses have a DAG structure. We - // don't have DAGs yet, but if the dispatch is used for mixins - // that will be a possibility. - // Re-use the previously created temporary variable. - expressions.add(new js.VariableUse(use.name)); - } else { - String varName = 'v${varNames.length}_${tag.name.slowToString()}'; - varNames.add(varName); - varDefns[varName] = existing; - tagDefns[tag] = new js.VariableUse(varName); - expressions.add(new js.VariableUse(varName)); - } - } - } - } - walk(classElement); - - if (!subtags.isEmpty) { - expressions.add(js.string(Strings.join(subtags, '|'))); - } - js.Expression expression; - if (expressions.length == 1) { - expression = expressions[0]; - } else { - js.Expression array = new js.ArrayInitializer.from(expressions); - expression = js.call(array.dot('join'), [js.string('|')]); - } - return expression; - } - - for (final ClassElement classElement in preorderDispatchClasses) { - tagDefns[classElement] = makeExpression(classElement); - } - - // Write out a thunk that builds the metadata. - if (!tagDefns.isEmpty) { - List<js.Statement> statements = <js.Statement>[]; - - List<js.VariableInitialization> initializations = - <js.VariableInitialization>[]; - for (final String varName in varNames) { - initializations.add( - new js.VariableInitialization( - new js.VariableDeclaration(varName), - varDefns[varName])); - } - if (!initializations.isEmpty) { - statements.add( - new js.ExpressionStatement( - new js.VariableDeclarationList(initializations))); - } - - // [table] is a list of lists, each inner list of the form: - // [dynamic-dispatch-tag, tags-of-classes-implementing-dispatch-tag] - // E.g. - // [['Node', 'Text|HTMLElement|HTMLDivElement|...'], ...] - js.Expression table = - new js.ArrayInitializer.from( - preorderDispatchClasses.map((cls) => - new js.ArrayInitializer.from([ - js.string(toNativeTag(cls)), - tagDefns[cls]]))); - - // $.dynamicSetMetadata(table); - statements.add( - new js.ExpressionStatement( - new js.Call( - new js.VariableUse(dynamicSetMetadataName), - [table]))); - - // (function(){statements})(); - if (emitter.compiler.enableMinification) nativeBuffer.add(';'); - nativeBuffer.add( - js.prettyPrint( - new js.ExpressionStatement( - new js.Call(new js.Fun([], new js.Block(statements)), [])), - compiler)); - } - } - - bool isSupertypeOfNativeClass(Element element) { - if (element.isTypeVariable()) { - compiler.cancel("Is check for type variable", element: element); - return false; - } - if (element.computeType(compiler).unalias(compiler) is FunctionType) { - // The element type is a function type either directly or through - // typedef(s). - return false; - } - - if (!element.isClass()) { - compiler.cancel("Is check does not handle element", element: element); - return false; - } - - return subtypes[element] != null; - } - - bool requiresNativeIsCheck(Element element) { - if (!element.isClass()) return false; - ClassElement cls = element; - if (cls.isNative()) return true; - return isSupertypeOfNativeClass(element); - } - - void assembleCode(CodeBuffer targetBuffer) { - if (nativeClasses.isEmpty) return; - emitDynamicDispatchMetadata(); - targetBuffer.add('$defineNativeClassName = ' - '$defineNativeClassFunction$N$n'); - - List<js.Property> objectProperties = <js.Property>[]; - - void addProperty(String name, js.Expression value) { - objectProperties.add(new js.Property(js.string(name), value)); - } - - // Because of native classes, we have to generate some is checks - // by calling a method, instead of accessing a property. So we - // attach to the JS Object prototype these methods that return - // false, and will be overridden by subclasses when they have to - // return true. - void emitIsChecks() { - for (ClassElement element in - Elements.sortedByPosition(emitter.checkedClasses)) { - if (!requiresNativeIsCheck(element)) continue; - if (element.isObject(compiler)) continue; - String name = backend.namer.operatorIs(element); - addProperty(name, - js.fun([], js.block1(js.return_(new js.LiteralBool(false))))); - } - } - emitIsChecks(); - - js.Expression makeCallOnThis(String functionName) => - js.fun([], - js.block1( - js.return_( - js.call(js.use(functionName), [js.use('this')])))); - - // In order to have the toString method on every native class, - // we must patch the JS Object prototype with a helper method. - String toStringName = backend.namer.publicInstanceMethodNameByArity( - const SourceString('toString'), 0); - addProperty(toStringName, makeCallOnThis(toStringHelperName)); - - // Same as above, but for hashCode. - String hashCodeName = - backend.namer.publicGetterName(const SourceString('hashCode')); - addProperty(hashCodeName, makeCallOnThis(hashCodeHelperName)); - - // Same as above, but for operator==. - String equalsName = backend.namer.publicInstanceMethodNameByArity( - const SourceString('=='), 1); - addProperty(equalsName, js.fun(['a'], js.block1( - js.return_(js.strictEquals(new js.This(), js.use('a')))))); - - // If the native emitter has been asked to take care of the - // noSuchMethod handlers, we do that now. - if (handleNoSuchMethod) { - emitter.emitNoSuchMethodHandlers(addProperty); - } - - // If we have any properties to add to Object.prototype, we run - // through them and add them using defineProperty. - if (!objectProperties.isEmpty) { - js.Expression init = - js.call( - js.fun(['table'], - js.block1( - new js.ForIn( - new js.VariableDeclarationList( - [new js.VariableInitialization( - new js.VariableDeclaration('key'), - null)]), - js.use('table'), - new js.ExpressionStatement( - js.call( - js.use(defPropName), - [js.use('Object').dot('prototype'), - js.use('key'), - new js.PropertyAccess(js.use('table'), - js.use('key'))]))))), - [new js.ObjectInitializer(objectProperties)]); - - if (emitter.compiler.enableMinification) targetBuffer.add(';'); - targetBuffer.add(js.prettyPrint( - new js.ExpressionStatement(init), compiler)); - targetBuffer.add('\n'); - } - - targetBuffer.add(nativeBuffer); - targetBuffer.add('\n'); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/runtime_types.dart b/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/runtime_types.dart deleted file mode 100644 index a3a0339..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/js_backend/runtime_types.dart +++ /dev/null
@@ -1,173 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of js_backend; - -/// For each class, stores the possible class subtype tests that could succeed. -abstract class TypeChecks { - /// Get the set of checks required for class [element]. - Iterable<ClassElement> operator[](ClassElement element); - // Get the iterator for all classes that need type checks. - Iterator<ClassElement> get iterator; -} - -class RuntimeTypeInformation { - final Compiler compiler; - - RuntimeTypeInformation(this.compiler); - - /// Contains the classes of all arguments that have been used in - /// instantiations and checks. - Set<ClassElement> allArguments; - - bool isJsNative(Element element) { - return (element == compiler.intClass || - element == compiler.boolClass || - element == compiler.numClass || - element == compiler.doubleClass || - element == compiler.stringClass || - element == compiler.listClass || - element == compiler.objectClass || - element == compiler.dynamicClass); - } - - TypeChecks computeRequiredChecks() { - Set<ClassElement> instantiatedArguments = new Set<ClassElement>(); - for (DartType type in compiler.codegenWorld.instantiatedTypes) { - addAllInterfaceTypeArguments(type, instantiatedArguments); - } - - Set<ClassElement> checkedArguments = new Set<ClassElement>(); - for (DartType type in compiler.enqueuer.codegen.universe.isChecks) { - addAllInterfaceTypeArguments(type, checkedArguments); - } - - allArguments = new Set<ClassElement>.from(instantiatedArguments) - ..addAll(checkedArguments); - - TypeCheckMapping requiredChecks = new TypeCheckMapping(); - for (ClassElement element in instantiatedArguments) { - if (element == compiler.dynamicClass) continue; - if (checkedArguments.contains(element)) { - requiredChecks.add(element, element); - } - // Find all supertypes of [element] in [checkedArguments] and add checks. - for (DartType supertype in element.allSupertypes) { - ClassElement superelement = supertype.element; - if (checkedArguments.contains(superelement)) { - requiredChecks.add(element, superelement); - } - } - } - - return requiredChecks; - } - - void addAllInterfaceTypeArguments(DartType type, Set<ClassElement> classes) { - if (type is !InterfaceType) return; - for (DartType argument in type.typeArguments) { - forEachInterfaceType(argument, (InterfaceType t) { - ClassElement cls = t.element; - if (cls != compiler.dynamicClass && cls != compiler.objectClass) { - classes.add(cls); - } - }); - } - } - - void forEachInterfaceType(DartType type, f(InterfaceType type)) { - if (type.kind == TypeKind.INTERFACE) { - f(type); - InterfaceType interface = type; - for (DartType argument in interface.typeArguments) { - forEachInterfaceType(argument, f); - } - } - } - - /// Return the unique name for the element as an unquoted string. - String getNameAsString(Element element) { - JavaScriptBackend backend = compiler.backend; - return backend.namer.getName(element); - } - - /// Return the unique JS name for the element, which is a quoted string for - /// native classes and the isolate acccess to the constructor for classes. - String getJsName(Element element) { - JavaScriptBackend backend = compiler.backend; - Namer namer = backend.namer; - return namer.isolateAccess(element); - } - - String getRawTypeRepresentation(DartType type) { - String name = getNameAsString(type.element); - if (!type.element.isClass()) return name; - InterfaceType interface = type; - Link<DartType> variables = interface.element.typeVariables; - if (variables.isEmpty) return name; - List<String> arguments = []; - variables.forEach((_) => arguments.add('dynamic')); - return '$name<${Strings.join(arguments, ', ')}>'; - } - - String getTypeRepresentation(DartType type, void onVariable(variable)) { - StringBuffer builder = new StringBuffer(); - void build(DartType part) { - if (part is TypeVariableType) { - builder.add('#'); - onVariable(part); - } else { - bool hasArguments = part is InterfaceType && !part.isRaw; - Element element = part.element; - if (hasArguments) { - builder.add('['); - } - builder.add(getJsName(element)); - if (!hasArguments) return; - InterfaceType interface = part; - for (DartType argument in interface.typeArguments) { - builder.add(', '); - build(argument); - } - builder.add(']'); - } - } - build(type); - return builder.toString(); - } - - static bool hasTypeArguments(DartType type) { - if (type is InterfaceType) { - InterfaceType interfaceType = type; - return !interfaceType.isRaw; - } - return false; - } - - static int getTypeVariableIndex(TypeVariableType variable) { - ClassElement classElement = variable.element.getEnclosingClass(); - Link<DartType> variables = classElement.typeVariables; - for (int index = 0; !variables.isEmpty; - index++, variables = variables.tail) { - if (variables.head == variable) return index; - } - } -} - -class TypeCheckMapping implements TypeChecks { - final Map<ClassElement, Set<ClassElement>> map = - new Map<ClassElement, Set<ClassElement>>(); - - Iterable<ClassElement> operator[](ClassElement element) { - Set<ClassElement> result = map[element]; - return result != null ? result : const <ClassElement>[]; - } - - void add(ClassElement cls, ClassElement check) { - map.putIfAbsent(cls, () => new Set<ClassElement>()); - map[cls].add(check); - } - - Iterator<ClassElement> get iterator => map.keys.iterator; -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/lib/async_patch.dart b/pkgs/markdown/test/lib/src/compiler/implementation/lib/async_patch.dart deleted file mode 100644 index 0fccce2..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/lib/async_patch.dart +++ /dev/null
@@ -1,21 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// Patch file for the dart:async library. - -import 'dart:_isolate_helper' show TimerImpl; - -patch class Timer { - patch factory Timer(int milliseconds, void callback(Timer timer)) { - return new TimerImpl(milliseconds, callback); - } - - /** - * Creates a new repeating timer. The [callback] is invoked every - * [milliseconds] millisecond until cancelled. - */ - patch factory Timer.repeating(int milliseconds, void callback(Timer timer)) { - return new TimerImpl.repeating(milliseconds, callback); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/lib/constant_map.dart b/pkgs/markdown/test/lib/src/compiler/implementation/lib/constant_map.dart deleted file mode 100644 index 75446c7..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/lib/constant_map.dart +++ /dev/null
@@ -1,75 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of _js_helper; - -// This class has no constructor. This is on purpose since the instantiation -// is shortcut by the compiler. -class ConstantMap<V> implements Map<String, V> { - final int length; - // A constant map is backed by a JavaScript object. - final _jsObject; - final List<String> _keys; - - bool containsValue(V needle) { - return values.any((V value) => value == needle); - } - - bool containsKey(String key) { - if (key == '__proto__') return false; - return jsHasOwnProperty(_jsObject, key); - } - - V operator [](String key) { - if (!containsKey(key)) return null; - return jsPropertyAccess(_jsObject, key); - } - - void forEach(void f(String key, V value)) { - _keys.forEach((String key) => f(key, this[key])); - } - - Iterable<String> get keys { - return new _ConstantMapKeyIterable(this); - } - - Iterable<V> get values { - return _keys.map((String key) => this[key]); - } - - bool get isEmpty => length == 0; - - String toString() => Maps.mapToString(this); - - _throwUnmodifiable() { - throw new UnsupportedError("Cannot modify unmodifiable Map"); - } - void operator []=(String key, V val) => _throwUnmodifiable(); - V putIfAbsent(String key, V ifAbsent()) => _throwUnmodifiable(); - V remove(String key) => _throwUnmodifiable(); - void clear() => _throwUnmodifiable(); -} - -// This class has no constructor. This is on purpose since the instantiation -// is shortcut by the compiler. -class ConstantProtoMap<V> extends ConstantMap<V> { - final V _protoValue; - - bool containsKey(String key) { - if (key == '__proto__') return true; - return super.containsKey(key); - } - - V operator [](String key) { - if (key == '__proto__') return _protoValue; - return super[key]; - } -} - -class _ConstantMapKeyIterable extends Iterable<String> { - ConstantMap _map; - _ConstantMapKeyIterable(this._map); - - Iterator<String> get iterator => _map._keys.iterator; -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/lib/core_patch.dart b/pkgs/markdown/test/lib/src/compiler/implementation/lib/core_patch.dart deleted file mode 100644 index 09e31da..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/lib/core_patch.dart +++ /dev/null
@@ -1,250 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// Patch file for dart:core classes. - -import 'dart:_interceptors'; -import 'dart:_js_helper' show checkNull, - getRuntimeTypeString, - isJsArray, - JSSyntaxRegExp, - Primitives, - TypeImpl, - stringJoinUnchecked, - JsStringBuffer; - -patch void print(var object) { - Primitives.printString(object.toString()); -} - -// Patch for Object implementation. -patch class Object { - patch int get hashCode => Primitives.objectHashCode(this); - - patch String toString() => Primitives.objectToString(this); - - patch dynamic noSuchMethod(InvocationMirror invocation) { - throw new NoSuchMethodError(this, - invocation.memberName, - invocation.positionalArguments, - invocation.namedArguments); - } - - patch Type get runtimeType { - String type = getRuntimeTypeString(this); - return new TypeImpl(type); - } -} - -// Patch for Function implementation. -patch class Function { - patch static apply(Function function, - List positionalArguments, - [Map<String,dynamic> namedArguments]) { - return Primitives.applyFunction( - function, positionalArguments, namedArguments); - } -} - -// Patch for Expando implementation. -patch class Expando<T> { - patch Expando([String name]) : this.name = name; - - patch T operator[](Object object) { - var values = Primitives.getProperty(object, _EXPANDO_PROPERTY_NAME); - return (values == null) ? null : Primitives.getProperty(values, _getKey()); - } - - patch void operator[]=(Object object, T value) { - var values = Primitives.getProperty(object, _EXPANDO_PROPERTY_NAME); - if (values == null) { - values = new Object(); - Primitives.setProperty(object, _EXPANDO_PROPERTY_NAME, values); - } - Primitives.setProperty(values, _getKey(), value); - } - - String _getKey() { - String key = Primitives.getProperty(this, _KEY_PROPERTY_NAME); - if (key == null) { - key = "expando\$key\$${_keyCount++}"; - Primitives.setProperty(this, _KEY_PROPERTY_NAME, key); - } - return key; - } - - static const String _KEY_PROPERTY_NAME = 'expando\$key'; - static const String _EXPANDO_PROPERTY_NAME = 'expando\$values'; - static int _keyCount = 0; -} - -patch class int { - patch static int parse(String source, - { int radix, - int onError(String source) }) { - return Primitives.parseInt(source, radix, onError); - } -} - -patch class double { - patch static double parse(String source, [int handleError(String source)]) { - return Primitives.parseDouble(source, handleError); - } -} - -patch class Error { - patch static String _objectToString(Object object) { - return Primitives.objectToString(object); - } -} - - -// Patch for DateTime implementation. -patch class DateTime { - patch DateTime._internal(int year, - int month, - int day, - int hour, - int minute, - int second, - int millisecond, - bool isUtc) - : this.isUtc = checkNull(isUtc), - millisecondsSinceEpoch = Primitives.valueFromDecomposedDate( - year, month, day, hour, minute, second, millisecond, isUtc) { - Primitives.lazyAsJsDate(this); - } - - patch DateTime._now() - : isUtc = false, - millisecondsSinceEpoch = Primitives.dateNow() { - Primitives.lazyAsJsDate(this); - } - - patch static int _brokenDownDateToMillisecondsSinceEpoch( - int year, int month, int day, int hour, int minute, int second, - int millisecond, bool isUtc) { - return Primitives.valueFromDecomposedDate( - year, month, day, hour, minute, second, millisecond, isUtc); - } - - patch String get timeZoneName { - if (isUtc) return "UTC"; - return Primitives.getTimeZoneName(this); - } - - patch Duration get timeZoneOffset { - if (isUtc) return new Duration(); - return new Duration(minutes: Primitives.getTimeZoneOffsetInMinutes(this)); - } - - patch int get year => Primitives.getYear(this); - - patch int get month => Primitives.getMonth(this); - - patch int get day => Primitives.getDay(this); - - patch int get hour => Primitives.getHours(this); - - patch int get minute => Primitives.getMinutes(this); - - patch int get second => Primitives.getSeconds(this); - - patch int get millisecond => Primitives.getMilliseconds(this); - - patch int get weekday => Primitives.getWeekday(this); -} - - -// Patch for Stopwatch implementation. -patch class Stopwatch { - patch static int _frequency() => 1000000; - patch static int _now() => Primitives.numMicroseconds(); -} - - -// Patch for List implementation. -patch class List<E> { - patch factory List([int length = 0]) { - // Explicit type test is necessary to protect Primitives.newGrowableList in - // unchecked mode. - if ((length is !int) || (length < 0)) { - throw new ArgumentError("Length must be a positive integer: $length."); - } - return Primitives.newGrowableList(length); - } - - patch factory List.fixedLength(int length, {E fill: null}) { - // Explicit type test is necessary to protect Primitives.newFixedList in - // unchecked mode. - if ((length is !int) || (length < 0)) { - throw new ArgumentError("Length must be a positive integer: $length."); - } - List result = Primitives.newFixedList(length); - if (length != 0 && fill != null) { - for (int i = 0; i < result.length; i++) { - result[i] = fill; - } - } - return result; - } -} - - -patch class String { - patch factory String.fromCharCodes(List<int> charCodes) { - if (!isJsArray(charCodes)) { - if (charCodes is !List) throw new ArgumentError(charCodes); - charCodes = new List.from(charCodes); - } - return Primitives.stringFromCharCodes(charCodes); - } -} - -// Patch for String implementation. -patch class Strings { - patch static String join(Iterable<String> strings, String separator) { - checkNull(strings); - if (separator is !String) throw new ArgumentError(separator); - return stringJoinUnchecked(_toJsStringArray(strings), separator); - } - - patch static String concatAll(Iterable<String> strings) { - return stringJoinUnchecked(_toJsStringArray(strings), ""); - } - - static List _toJsStringArray(Iterable<String> strings) { - checkNull(strings); - var array; - if (!isJsArray(strings)) { - strings = new List.from(strings); - } - final length = strings.length; - for (int i = 0; i < length; i++) { - final string = strings[i]; - if (string is !String) throw new ArgumentError(string); - } - return strings; - } -} - -patch class RegExp { - patch factory RegExp(String pattern, - {bool multiLine: false, - bool caseSensitive: true}) - => new JSSyntaxRegExp(pattern, - multiLine: multiLine, - caseSensitive: caseSensitive); -} - -// Patch for 'identical' function. -patch bool identical(Object a, Object b) { - return Primitives.identicalImplementation(a, b); -} - -patch class StringBuffer { - patch factory StringBuffer([Object content = ""]) { - return new JsStringBuffer(content); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/lib/foreign_helper.dart b/pkgs/markdown/test/lib/src/compiler/implementation/lib/foreign_helper.dart deleted file mode 100644 index 2ad4a1e..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/lib/foreign_helper.dart +++ /dev/null
@@ -1,138 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library _foreign_helper; - -/** - * Emits a JavaScript code fragment parameterized by arguments. - * - * Hash characters `#` in the [codeTemplate] are replaced in left-to-right order - * with expressions that contain the values of, or evaluate to, the arguments. - * The number of hash marks must match the number or arguments. Although - * declared with arguments [arg0] through [arg2], the form actually has no limit - * on the number of arguments. - * - * The [typeDescription] argument is interpreted as a description of the - * behavior of the JavaScript code. Currently it describes the types that may - * be returned by the expression, with the additional behavior that the returned - * values may be fresh instances of the types. The type information must be - * correct as it is trusted by the compiler in optimizations, and it must be - * precise as possible since it is used for native live type analysis to - * tree-shake large parts of the DOM libraries. If poorly written, the - * [typeDescription] will cause unnecessarily bloated programs. (You can check - * for this by compiling with `--verbose`; there is an info message describing - * the number of native (DOM) types that can be removed, which usually should be - * greater than zero.) - * - * The [typeDescription] is a [String] which contains a union of types separated - * by vertical bar `|` symbols, e.g. `"num|String"` describes the union of - * numbers and Strings. There is no type in Dart that is this precise. The - * Dart alternative would be `Object` or `dynamic`, but these types imply that - * the JS-code might also be creating instances of all the DOM types. The - * [typeDescription] has several extensions to help describe the behavior more - * accurately. In addition to the union type already described: - * - * + `=List` is the JavaScript array type. This is more precise than `List`, - * which includes about fifty DOM types that also implement the List - * interface. - * - * + `=Object` is a plain JavaScript object. Some DOM methods return instances - * that have no corresponing Dart type (e.g. cross-frame documents), - * `=Object` can be used to describe these untyped' values. - * - * + `var`. If the entire [typeDescription] is `var` then the type is - * `dynamic` but the code is known to not create any instances. - * - * Examples: - * - * // Create a JavaScript Array. - * List a = JS('=List', 'new Array(#)', length); - * - * // Parent window might be an opaque cross-frame window. - * var thing = JS('=Object|Window', '#.parent', myWindow); - * - * Guidelines: - * - * + Do not use any parameter, local, method or field names in the - * [codeTemplate]. These names are all subject to arbitrary renaming by the - * compiler. Pass the values in via `#` substition, and test with the - * `--minify` dart2js command-line option. - * - * + The substituted expressions are values, not locations. - * - * JS('void', '# += "x"', this.field); - * - * `this.field` might not be a substituted as a reference to the field. The - * generated code might accidentally work as intended, but it also might be - * - * var t1 = this.field; - * t1 += "x"; - * - * or - * - * this.get$field() += "x"; - * - * The remedy in this case is to expand the `+=` operator, leaving all - * references to the Dart field as Dart code: - * - * this.field = JS('String', '# + "x"', this.field); - * - * - * Additional notes. - * - * In the future we may extend [typeDescription] to include other aspects of the - * behavior, for example, separating the returned types from the instantiated - * types, or including effects to allow the compiler to perform more - * optimizations around the code. This might be an extension of [JS] or a new - * function similar to [JS] with additional arguments for the new information. - */ -// Add additional optional arguments if needed. The method is treated internally -// as a variable argument method. -dynamic JS(String typeDescription, String codeTemplate, - [var arg0, var arg1, var arg2, var arg3, var arg4, var arg5, var arg6, - var arg7, var arg8, var arg9, var arg10, var arg11]) {} - -/** - * Returns the isolate in which this code is running. - */ -dynamic JS_CURRENT_ISOLATE() {} - -/** - * Invokes [function] in the context of [isolate]. - */ -dynamic JS_CALL_IN_ISOLATE(var isolate, Function function) {} - -/** - * Converts the Dart closure [function] into a JavaScript closure. - */ -dynamic DART_CLOSURE_TO_JS(Function function) {} - -/** - * Returns a raw reference to the JavaScript function which implements - * [function]. - * - * Warning: this is dangerous, you should probably use - * [DART_CLOSURE_TO_JS] instead. The returned object is not a valid - * Dart closure, does not store the isolate context or arity. - * - * A valid example of where this can be used is as the second argument - * to V8's Error.captureStackTrace. See - * https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi. - */ -dynamic RAW_DART_FUNCTION_REF(Function function) {} - -/** - * Sets the current isolate to [isolate]. - */ -void JS_SET_CURRENT_ISOLATE(var isolate) {} - -/** - * Creates an isolate and returns it. - */ -dynamic JS_CREATE_ISOLATE() {} - -/** - * Returns the prefix used for generated is checks on classes. - */ -String JS_OPERATOR_IS_PREFIX() {}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/lib/interceptors.dart b/pkgs/markdown/test/lib/src/compiler/implementation/lib/interceptors.dart deleted file mode 100644 index 6a32f17..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/lib/interceptors.dart +++ /dev/null
@@ -1,90 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library _interceptors; - -import 'dart:collection'; -import 'dart:_collection-dev'; -import 'dart:_js_helper' show allMatchesInStringUnchecked, - Null, - JSSyntaxRegExp, - Primitives, - checkGrowable, - checkMutable, - checkNull, - checkNum, - checkString, - getRuntimeTypeString, - listInsertRange, - regExpGetNative, - stringContainsUnchecked, - stringLastIndexOfUnchecked, - stringReplaceAllFuncUnchecked, - stringReplaceAllUnchecked, - stringReplaceFirstUnchecked, - TypeImpl; -import 'dart:_foreign_helper' show JS; - -part 'js_array.dart'; -part 'js_number.dart'; -part 'js_string.dart'; - -/** - * The interceptor class for all non-primitive objects. All its - * members are synthethized by the compiler's emitter. - */ -class ObjectInterceptor { - const ObjectInterceptor(); -} - -/** - * Get the interceptor for [object]. Called by the compiler when it needs - * to emit a call to an intercepted method, that is a method that is - * defined in an interceptor class. - */ -getInterceptor(object) { - // This is a magic method: the compiler does specialization of it - // depending on the uses of intercepted methods and instantiated - // primitive types. -} - -/** - * The interceptor class for tear-off static methods. Unlike - * tear-off instance methods, tear-off static methods are just the JS - * function, and methods inherited from Object must therefore be - * intercepted. - */ -class JSFunction implements Function { - const JSFunction(); - String toString() => 'Closure'; -} - -/** - * The interceptor class for [bool]. - */ -class JSBool implements bool { - const JSBool(); - - // Note: if you change this, also change the function [S]. - String toString() => JS('String', r'String(#)', this); - - // The values here are SMIs, co-prime and differ about half of the bit - // positions, including the low bit, so they are different mod 2^k. - int get hashCode => this ? (2 * 3 * 23 * 3761) : (269 * 811); - - Type get runtimeType => bool; -} - -/** - * The interceptor class for [Null]. - */ -class JSNull implements Null { - const JSNull(); - - // Note: if you change this, also change the function [S]. - String toString() => 'null'; - - int get hashCode => 0; - Type get runtimeType => Null; -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/lib/io_patch.dart b/pkgs/markdown/test/lib/src/compiler/implementation/lib/io_patch.dart deleted file mode 100644 index 0374de5..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/lib/io_patch.dart +++ /dev/null
@@ -1,217 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -patch class _BufferUtils { - patch static bool _isBuiltinList(List buffer) { - throw new UnsupportedError("_isBuiltinList"); - } -} - -patch class _Directory { - patch static String _current() { - throw new UnsupportedError("Directory._current"); - } - patch static _createTemp(String template) { - throw new UnsupportedError("Directory._createTemp"); - } - patch static int _exists(String path) { - throw new UnsupportedError("Directory._exists"); - } - patch static _create(String path) { - throw new UnsupportedError("Directory._create"); - } - patch static _delete(String path, bool recursive) { - throw new UnsupportedError("Directory._delete"); - } - patch static _rename(String path, String newPath) { - throw new UnsupportedError("Directory._rename"); - } - patch static List _list(String path, bool recursive) { - throw new UnsupportedError("Directory._list"); - } - patch static SendPort _newServicePort() { - throw new UnsupportedError("Directory._newServicePort"); - } -} - -patch class _EventHandler { - patch static void _start() { - throw new UnsupportedError("EventHandler._start"); - } - - patch static _sendData(Object sender, - ReceivePort receivePort, - int data) { - throw new UnsupportedError("EventHandler._sendData"); - } -} - -patch class _FileUtils { - patch static SendPort _newServicePort() { - throw new UnsupportedError("FileUtils._newServicePort"); - } -} - -patch class _File { - patch static _exists(String name) { - throw new UnsupportedError("File._exists"); - } - patch static _create(String name) { - throw new UnsupportedError("File._create"); - } - patch static _delete(String name) { - throw new UnsupportedError("File._delete"); - } - patch static _directory(String name) { - throw new UnsupportedError("File._directory"); - } - patch static _lengthFromName(String name) { - throw new UnsupportedError("File._lengthFromName"); - } - patch static _lastModified(String name) { - throw new UnsupportedError("File._lastModified"); - } - patch static _open(String name, int mode) { - throw new UnsupportedError("File._open"); - } - patch static int _openStdio(int fd) { - throw new UnsupportedError("File._openStdio"); - } - patch static _fullPath(String name) { - throw new UnsupportedError("File._fullPath"); - } -} - -patch class _RandomAccessFile { - patch static int _close(int id) { - throw new UnsupportedError("RandomAccessFile._close"); - } - patch static _readByte(int id) { - throw new UnsupportedError("RandomAccessFile._readByte"); - } - patch static _read(int id, int bytes) { - throw new UnsupportedError("RandomAccessFile._read"); - } - patch static _readList(int id, List<int> buffer, int offset, int bytes) { - throw new UnsupportedError("RandomAccessFile._readList"); - } - patch static _writeByte(int id, int value) { - throw new UnsupportedError("RandomAccessFile._writeByte"); - } - patch static _writeList(int id, List<int> buffer, int offset, int bytes) { - throw new UnsupportedError("RandomAccessFile._writeList"); - } - patch static _position(int id) { - throw new UnsupportedError("RandomAccessFile._position"); - } - patch static _setPosition(int id, int position) { - throw new UnsupportedError("RandomAccessFile._setPosition"); - } - patch static _truncate(int id, int length) { - throw new UnsupportedError("RandomAccessFile._truncate"); - } - patch static _length(int id) { - throw new UnsupportedError("RandomAccessFile._length"); - } - patch static _flush(int id) { - throw new UnsupportedError("RandomAccessFile._flush"); - } -} - -patch class _HttpSessionManager { - patch static Uint8List _getRandomBytes(int count) { - throw new UnsupportedError("HttpSessionManager._getRandomBytes"); - } -} - -patch class _Platform { - patch static int _numberOfProcessors() { - throw new UnsupportedError("Platform._numberOfProcessors"); - } - patch static String _pathSeparator() { - throw new UnsupportedError("Platform._pathSeparator"); - } - patch static String _operatingSystem() { - throw new UnsupportedError("Platform._operatingSystem"); - } - patch static _localHostname() { - throw new UnsupportedError("Platform._localHostname"); - } - patch static _environment() { - throw new UnsupportedError("Platform._environment"); - } -} - -patch class _ProcessUtils { - patch static _exit(int status) { - throw new UnsupportedError("ProcessUtils._exit"); - } - patch static _setExitCode(int status) { - throw new UnsupportedError("ProcessUtils._setExitCode"); - } -} - -patch class Process { - patch static Future<Process> start(String executable, - List<String> arguments, - [ProcessOptions options]) { - throw new UnsupportedError("Process.start"); - } - - patch static Future<ProcessResult> run(String executable, - List<String> arguments, - [ProcessOptions options]) { - throw new UnsupportedError("Process.run"); - } -} - -patch class ServerSocket { - patch factory ServerSocket(String bindAddress, int port, int backlog) { - throw new UnsupportedError("ServerSocket constructor"); - } -} - -patch class Socket { - patch factory Socket(String host, int port) { - throw new UnsupportedError("Socket constructor"); - } -} - -patch class SecureSocket { - patch static void initialize({String database, - String password, - bool useBuiltinRoots: true}) { - throw new UnsupportedError("SecureSocket.setCertificateDatabase"); - } -} - -patch class _SecureFilter { - patch factory _SecureFilter() { - throw new UnsupportedError("_SecureFilter._SecureFilter"); - } -} - -patch class _StdIOUtils { - patch static InputStream _getStdioInputStream() { - throw new UnsupportedError("StdIOUtils._getStdioInputStream"); - } - patch static OutputStream _getStdioOutputStream(int fd) { - throw new UnsupportedError("StdIOUtils._getStdioOutputStream"); - } - patch static int _socketType(Socket socket) { - throw new UnsupportedError("StdIOUtils._socketType"); - } -} - -patch class _WindowsCodePageDecoder { - patch static String _decodeBytes(List<int> bytes) { - throw new UnsupportedError("_WindowsCodePageDecoder._decodeBytes"); - } -} - -patch class _WindowsCodePageEncoder { - patch static List<int> _encodeString(String string) { - throw new UnsupportedError("_WindowsCodePageEncoder._encodeString"); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/lib/isolate_helper.dart b/pkgs/markdown/test/lib/src/compiler/implementation/lib/isolate_helper.dart deleted file mode 100644 index 82a80fe..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/lib/isolate_helper.dart +++ /dev/null
@@ -1,1329 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library _isolate_helper; - -import 'dart:async'; -import 'dart:collection' show Queue, HashMap; -import 'dart:isolate'; -import 'dart:_js_helper' show convertDartClosureToJS, - Null; -import 'dart:_foreign_helper' show DART_CLOSURE_TO_JS, - JS, - JS_CREATE_ISOLATE, - JS_SET_CURRENT_ISOLATE; - -ReceivePort lazyPort; - -/** - * Called by the compiler to support switching - * between isolates when we get a callback from the DOM. - */ -void _callInIsolate(_IsolateContext isolate, Function function) { - isolate.eval(function); - _globalState.topEventLoop.run(); -} - -/** - * Called by the compiler to fetch the current isolate context. - */ -_IsolateContext _currentIsolate() => _globalState.currentContext; - -/** - * Wrapper that takes the dart entry point and runs it within an isolate. The - * dart2js compiler will inject a call of the form - * [: startRootIsolate(main); :] when it determines that this wrapping - * is needed. For single-isolate applications (e.g. hello world), this - * call is not emitted. - */ -void startRootIsolate(entry) { - _globalState = new _Manager(); - - // Don't start the main loop again, if we are in a worker. - if (_globalState.isWorker) return; - final rootContext = new _IsolateContext(); - _globalState.rootContext = rootContext; - - // BUG(5151491): Setting currentContext should not be necessary, but - // because closures passed to the DOM as event handlers do not bind their - // isolate automatically we try to give them a reasonable context to live in - // by having a "default" isolate (the first one created). - _globalState.currentContext = rootContext; - - rootContext.eval(entry); - _globalState.topEventLoop.run(); -} - -/******************************************************** - Inserted from lib/isolate/dart2js/isolateimpl.dart - ********************************************************/ - -/** - * Concepts used here: - * - * "manager" - A manager contains one or more isolates, schedules their - * execution, and performs other plumbing on their behalf. The isolate - * present at the creation of the manager is designated as its "root isolate". - * A manager may, for example, be implemented on a web Worker. - * - * [_Manager] - State present within a manager (exactly once, as a global). - * - * [_ManagerStub] - A handle held within one manager that allows interaction - * with another manager. A target manager may be addressed by zero or more - * [_ManagerStub]s. - * - */ - -/** - * A native object that is shared across isolates. This object is visible to all - * isolates running under the same manager (either UI or background web worker). - * - * This is code that is intended to 'escape' the isolate boundaries in order to - * implement the semantics of isolates in JavaScript. Without this we would have - * been forced to implement more code (including the top-level event loop) in - * JavaScript itself. - */ -// TODO(eub, sigmund): move the "manager" to be entirely in JS. -// Running any Dart code outside the context of an isolate gives it -// the chance to break the isolate abstraction. -_Manager get _globalState => JS("_Manager", r"$globalState"); - -set _globalState(_Manager val) { - JS("void", r"$globalState = #", val); -} - -/** State associated with the current manager. See [globalState]. */ -// TODO(sigmund): split in multiple classes: global, thread, main-worker states? -class _Manager { - - /** Next available isolate id within this [_Manager]. */ - int nextIsolateId = 0; - - /** id assigned to this [_Manager]. */ - int currentManagerId = 0; - - /** - * Next available manager id. Only used by the main manager to assign a unique - * id to each manager created by it. - */ - int nextManagerId = 1; - - /** Context for the currently running [Isolate]. */ - _IsolateContext currentContext = null; - - /** Context for the root [Isolate] that first run in this [_Manager]. */ - _IsolateContext rootContext = null; - - /** The top-level event loop. */ - _EventLoop topEventLoop; - - /** Whether this program is running from the command line. */ - bool fromCommandLine; - - /** Whether this [_Manager] is running as a web worker. */ - bool isWorker; - - /** Whether we support spawning web workers. */ - bool supportsWorkers; - - /** - * Whether to use web workers when implementing isolates. Set to false for - * debugging/testing. - */ - bool get useWorkers => supportsWorkers; - - /** - * Whether to use the web-worker JSON-based message serialization protocol. By - * default this is only used with web workers. For debugging, you can force - * using this protocol by changing this field value to [true]. - */ - bool get needSerialization => useWorkers; - - /** - * Registry of isolates. Isolates must be registered if, and only if, receive - * ports are alive. Normally no open receive-ports means that the isolate is - * dead, but DOM callbacks could resurrect it. - */ - Map<int, _IsolateContext> isolates; - - /** Reference to the main [_Manager]. Null in the main [_Manager] itself. */ - _ManagerStub mainManager; - - /** Registry of active [_ManagerStub]s. Only used in the main [_Manager]. */ - Map<int, _ManagerStub> managers; - - _Manager() { - _nativeDetectEnvironment(); - topEventLoop = new _EventLoop(); - isolates = new Map<int, _IsolateContext>(); - managers = new Map<int, _ManagerStub>(); - if (isWorker) { // "if we are not the main manager ourself" is the intent. - mainManager = new _MainManagerStub(); - _nativeInitWorkerMessageHandler(); - } - } - - void _nativeDetectEnvironment() { - bool isWindowDefined = globalWindow != null; - bool isWorkerDefined = globalWorker != null; - - isWorker = !isWindowDefined && globalPostMessageDefined; - supportsWorkers = isWorker - || (isWorkerDefined && IsolateNatives.thisScript != null); - fromCommandLine = !isWindowDefined && !isWorker; - } - - void _nativeInitWorkerMessageHandler() { - var function = JS('', - "function (e) { #(#, e); }", - DART_CLOSURE_TO_JS(IsolateNatives._processWorkerMessage), - mainManager); - JS("void", r"#.onmessage = #", globalThis, function); - // We define dartPrint so that the implementation of the Dart - // print method knows what to call. - // TODO(ngeoffray): Should we forward to the main isolate? What if - // it exited? - JS('void', r'#.dartPrint = function (object) {}', globalThis); - } - - - /** - * Close the worker running this code if all isolates are done and - * there is no active timer. - */ - void maybeCloseWorker() { - if (isWorker - && isolates.isEmpty - && topEventLoop.activeTimerCount == 0) { - mainManager.postMessage(_serializeMessage({'command': 'close'})); - } - } -} - -/** Context information tracked for each isolate. */ -class _IsolateContext { - /** Current isolate id. */ - int id; - - /** Registry of receive ports currently active on this isolate. */ - Map<int, ReceivePort> ports; - - /** Holds isolate globals (statics and top-level properties). */ - var isolateStatics; // native object containing all globals of an isolate. - - _IsolateContext() { - id = _globalState.nextIsolateId++; - ports = new Map<int, ReceivePort>(); - isolateStatics = JS_CREATE_ISOLATE(); - } - - /** - * Run [code] in the context of the isolate represented by [this]. - */ - dynamic eval(Function code) { - var old = _globalState.currentContext; - _globalState.currentContext = this; - this._setGlobals(); - var result = null; - try { - result = code(); - } finally { - _globalState.currentContext = old; - if (old != null) old._setGlobals(); - } - return result; - } - - void _setGlobals() { - JS_SET_CURRENT_ISOLATE(isolateStatics); - } - - /** Lookup a port registered for this isolate. */ - ReceivePort lookup(int portId) => ports[portId]; - - /** Register a port on this isolate. */ - void register(int portId, ReceivePort port) { - if (ports.containsKey(portId)) { - throw new Exception("Registry: ports must be registered only once."); - } - ports[portId] = port; - _globalState.isolates[id] = this; // indicate this isolate is active - } - - /** Unregister a port on this isolate. */ - void unregister(int portId) { - ports.remove(portId); - if (ports.isEmpty) { - _globalState.isolates.remove(id); // indicate this isolate is not active - } - } -} - -/** Represent the event loop on a javascript thread (DOM or worker). */ -class _EventLoop { - final Queue<_IsolateEvent> events = new Queue<_IsolateEvent>(); - int activeTimerCount = 0; - - _EventLoop(); - - void enqueue(isolate, fn, msg) { - events.addLast(new _IsolateEvent(isolate, fn, msg)); - } - - _IsolateEvent dequeue() { - if (events.isEmpty) return null; - return events.removeFirst(); - } - - void checkOpenReceivePortsFromCommandLine() { - if (_globalState.rootContext != null - && _globalState.isolates.containsKey(_globalState.rootContext.id) - && _globalState.fromCommandLine - && _globalState.rootContext.ports.isEmpty) { - // We want to reach here only on the main [_Manager] and only - // on the command-line. In the browser the isolate might - // still be alive due to DOM callbacks, but the presumption is - // that on the command-line, no future events can be injected - // into the event queue once it's empty. Node has setTimeout - // so this presumption is incorrect there. We think(?) that - // in d8 this assumption is valid. - throw new Exception("Program exited with open ReceivePorts."); - } - } - - /** Process a single event, if any. */ - bool runIteration() { - final event = dequeue(); - if (event == null) { - checkOpenReceivePortsFromCommandLine(); - _globalState.maybeCloseWorker(); - return false; - } - event.process(); - return true; - } - - /** - * Runs multiple iterations of the run-loop. If possible, each iteration is - * run asynchronously. - */ - void _runHelper() { - if (globalWindow != null) { - // Run each iteration from the browser's top event loop. - void next() { - if (!runIteration()) return; - new Timer(0, (_) => next()); - } - next(); - } else { - // Run synchronously until no more iterations are available. - while (runIteration()) {} - } - } - - /** - * Call [_runHelper] but ensure that worker exceptions are propragated. - */ - void run() { - if (!_globalState.isWorker) { - _runHelper(); - } else { - try { - _runHelper(); - } catch (e, trace) { - _globalState.mainManager.postMessage(_serializeMessage( - {'command': 'error', 'msg': '$e\n$trace' })); - } - } - } -} - -/** An event in the top-level event queue. */ -class _IsolateEvent { - _IsolateContext isolate; - Function fn; - String message; - - _IsolateEvent(this.isolate, this.fn, this.message); - - void process() { - isolate.eval(fn); - } -} - -/** An interface for a stub used to interact with a manager. */ -abstract class _ManagerStub { - get id; - void set id(int i); - void set onmessage(Function f); - void postMessage(msg); - void terminate(); -} - -/** A stub for interacting with the main manager. */ -class _MainManagerStub implements _ManagerStub { - get id => 0; - void set id(int i) { throw new UnimplementedError(); } - void set onmessage(f) { - throw new Exception("onmessage should not be set on MainManagerStub"); - } - void postMessage(msg) { - JS("void", r"#.postMessage(#)", globalThis, msg); - } - void terminate() {} // Nothing useful to do here. -} - -/** - * A stub for interacting with a manager built on a web worker. This - * definition uses a 'hidden' type (* prefix on the native name) to - * enforce that the type is defined dynamically only when web workers - * are actually available. - */ -// @Native("*Worker"); -class _WorkerStub implements _ManagerStub { - get id => JS("", "#.id", this); - void set id(i) { JS("void", "#.id = #", this, i); } - void set onmessage(f) { JS("void", "#.onmessage = #", this, f); } - void postMessage(msg) { JS("void", "#.postMessage(#)", this, msg); } - void terminate() { JS("void", "#.terminate()", this); } -} - -const String _SPAWNED_SIGNAL = "spawned"; - -var globalThis = IsolateNatives.computeGlobalThis(); -var globalWindow = JS('', "#.window", globalThis); -var globalWorker = JS('', "#.Worker", globalThis); -bool globalPostMessageDefined = - JS('', "#.postMessage !== (void 0)", globalThis); - -class IsolateNatives { - - static String thisScript = computeThisScript(); - - /** - * The src url for the script tag that loaded this code. Used to create - * JavaScript workers. - */ - static String computeThisScript() { - // TODO(7369): Find a cross-platform non-brittle way of getting the - // currently running script. - var scripts = JS('', r"document.getElementsByTagName('script')"); - // The scripts variable only contains the scripts that have already been - // executed. The last one is the currently running script. - for (int i = 0, len = JS('int', '#.length', scripts); i < len; i++) { - var script = JS('', '#[#]', scripts, i); - var src = JS('String|Null', '# && #.src', script, script); - // Filter out the test controller script, and the Dart - // bootstrap script. - if (src != null - && !src.endsWith('test_controller.js') - && !src.endsWith('dart.js')) { - return src; - } - } - return null; - } - - static computeGlobalThis() => JS('', 'function() { return this; }()'); - - /** Starts a new worker with the given URL. */ - static _WorkerStub _newWorker(url) => JS("_WorkerStub", r"new Worker(#)", url); - - /** - * Assume that [e] is a browser message event and extract its message data. - * We don't import the dom explicitly so, when workers are disabled, this - * library can also run on top of nodejs. - */ - static _getEventData(e) => JS("", "#.data", e); - - /** - * Process messages on a worker, either to control the worker instance or to - * pass messages along to the isolate running in the worker. - */ - static void _processWorkerMessage(sender, e) { - var msg = _deserializeMessage(_getEventData(e)); - switch (msg['command']) { - case 'start': - _globalState.currentManagerId = msg['id']; - Function entryPoint = _getJSFunctionFromName(msg['functionName']); - var replyTo = _deserializeMessage(msg['replyTo']); - var context = new _IsolateContext(); - _globalState.topEventLoop.enqueue(context, function() { - _startIsolate(entryPoint, replyTo); - }, 'worker-start'); - // Make sure we always have a current context in this worker. - // TODO(7907): This is currently needed because we're using - // Timers to implement Futures, and this isolate library - // implementation uses Futures. We should either stop using - // Futures in this library, or re-adapt if Futures get a - // different implementation. - _globalState.currentContext = context; - _globalState.topEventLoop.run(); - break; - case 'spawn-worker': - _spawnWorker(msg['functionName'], msg['uri'], msg['replyPort']); - break; - case 'message': - SendPort port = msg['port']; - // If the port has been closed, we ignore the message. - if (port != null) { - msg['port'].send(msg['msg'], msg['replyTo']); - } - _globalState.topEventLoop.run(); - break; - case 'close': - _log("Closing Worker"); - _globalState.managers.remove(sender.id); - sender.terminate(); - _globalState.topEventLoop.run(); - break; - case 'log': - _log(msg['msg']); - break; - case 'print': - if (_globalState.isWorker) { - _globalState.mainManager.postMessage( - _serializeMessage({'command': 'print', 'msg': msg})); - } else { - print(msg['msg']); - } - break; - case 'error': - throw msg['msg']; - } - } - - /** Log a message, forwarding to the main [_Manager] if appropriate. */ - static _log(msg) { - if (_globalState.isWorker) { - _globalState.mainManager.postMessage( - _serializeMessage({'command': 'log', 'msg': msg })); - } else { - try { - _consoleLog(msg); - } catch (e, trace) { - throw new Exception(trace); - } - } - } - - static void _consoleLog(msg) { - JS("void", r"#.console.log(#)", globalThis, msg); - } - - /** Find a constructor given its name. */ - static dynamic _getJSConstructorFromName(String factoryName) { - return JS("", r"$[#]", factoryName); - } - - static dynamic _getJSFunctionFromName(String functionName) { - return JS("", r"$[#]", functionName); - } - - /** - * Get a string name for the function, if possible. The result for - * anonymous functions is browser-dependent -- it may be "" or "anonymous" - * but you should probably not count on this. - */ - static String _getJSFunctionName(Function f) { - return JS("String|Null", r"(#.$name || #)", f, null); - } - - /** Create a new JavaScript object instance given its constructor. */ - static dynamic _allocate(var ctor) { - return JS("", "new #()", ctor); - } - - static SendPort spawnFunction(void topLevelFunction()) { - final name = _getJSFunctionName(topLevelFunction); - if (name == null) { - throw new UnsupportedError( - "only top-level functions can be spawned."); - } - return spawn(name, null, false); - } - - static SendPort spawnDomFunction(void topLevelFunction()) { - final name = _getJSFunctionName(topLevelFunction); - if (name == null) { - throw new UnsupportedError( - "only top-level functions can be spawned."); - } - return spawn(name, null, true); - } - - // TODO(sigmund): clean up above, after we make the new API the default: - - static spawn(String functionName, String uri, bool isLight) { - Completer<SendPort> completer = new Completer<SendPort>(); - ReceivePort port = new ReceivePort(); - port.receive((msg, SendPort replyPort) { - port.close(); - assert(msg == _SPAWNED_SIGNAL); - completer.complete(replyPort); - }); - - SendPort signalReply = port.toSendPort(); - - if (_globalState.useWorkers && !isLight) { - _startWorker(functionName, uri, signalReply); - } else { - _startNonWorker(functionName, uri, signalReply); - } - return new _BufferingSendPort( - _globalState.currentContext.id, completer.future); - } - - static SendPort _startWorker( - String functionName, String uri, SendPort replyPort) { - if (_globalState.isWorker) { - _globalState.mainManager.postMessage(_serializeMessage({ - 'command': 'spawn-worker', - 'functionName': functionName, - 'uri': uri, - 'replyPort': replyPort})); - } else { - _spawnWorker(functionName, uri, replyPort); - } - } - - static SendPort _startNonWorker( - String functionName, String uri, SendPort replyPort) { - // TODO(eub): support IE9 using an iframe -- Dart issue 1702. - if (uri != null) throw new UnsupportedError( - "Currently spawnUri is not supported without web workers."); - _globalState.topEventLoop.enqueue(new _IsolateContext(), function() { - final func = _getJSFunctionFromName(functionName); - _startIsolate(func, replyPort); - }, 'nonworker start'); - } - - static void _startIsolate(Function topLevel, SendPort replyTo) { - lazyPort = new ReceivePort(); - replyTo.send(_SPAWNED_SIGNAL, port.toSendPort()); - topLevel(); - } - - /** - * Spawns an isolate in a worker. [factoryName] is the Javascript constructor - * name for the isolate entry point class. - */ - static void _spawnWorker(functionName, uri, replyPort) { - if (functionName == null) functionName = 'main'; - if (uri == null) uri = thisScript; - final worker = _newWorker(uri); - worker.onmessage = JS('', - 'function(e) { #(#, e); }', - DART_CLOSURE_TO_JS(_processWorkerMessage), - worker); - var workerId = _globalState.nextManagerId++; - // We also store the id on the worker itself so that we can unregister it. - worker.id = workerId; - _globalState.managers[workerId] = worker; - worker.postMessage(_serializeMessage({ - 'command': 'start', - 'id': workerId, - // Note: we serialize replyPort twice because the child worker needs to - // first deserialize the worker id, before it can correctly deserialize - // the port (port deserialization is sensitive to what is the current - // workerId). - 'replyTo': _serializeMessage(replyPort), - 'functionName': functionName })); - } -} - -/******************************************************** - Inserted from lib/isolate/dart2js/ports.dart - ********************************************************/ - -/** Common functionality to all send ports. */ -class _BaseSendPort implements SendPort { - /** Id for the destination isolate. */ - final int _isolateId; - - const _BaseSendPort(this._isolateId); - - void _checkReplyTo(SendPort replyTo) { - if (replyTo != null - && replyTo is! _NativeJsSendPort - && replyTo is! _WorkerSendPort - && replyTo is! _BufferingSendPort) { - throw new Exception("SendPort.send: Illegal replyTo port type"); - } - } - - Future call(var message) { - final completer = new Completer(); - final port = new ReceivePortImpl(); - send(message, port.toSendPort()); - port.receive((value, ignoreReplyTo) { - port.close(); - if (value is Exception) { - completer.completeError(value); - } else { - completer.complete(value); - } - }); - return completer.future; - } - - void send(var message, [SendPort replyTo]); - bool operator ==(var other); - int get hashCode; -} - -/** A send port that delivers messages in-memory via native JavaScript calls. */ -class _NativeJsSendPort extends _BaseSendPort implements SendPort { - final ReceivePortImpl _receivePort; - - const _NativeJsSendPort(this._receivePort, int isolateId) : super(isolateId); - - void send(var message, [SendPort replyTo = null]) { - _waitForPendingPorts([message, replyTo], () { - _checkReplyTo(replyTo); - // Check that the isolate still runs and the port is still open - final isolate = _globalState.isolates[_isolateId]; - if (isolate == null) return; - if (_receivePort._callback == null) return; - - // We force serialization/deserialization as a simple way to ensure - // isolate communication restrictions are respected between isolates that - // live in the same worker. [_NativeJsSendPort] delivers both messages - // from the same worker and messages from other workers. In particular, - // messages sent from a worker via a [_WorkerSendPort] are received at - // [_processWorkerMessage] and forwarded to a native port. In such cases, - // here we'll see [_globalState.currentContext == null]. - final shouldSerialize = _globalState.currentContext != null - && _globalState.currentContext.id != _isolateId; - var msg = message; - var reply = replyTo; - if (shouldSerialize) { - msg = _serializeMessage(msg); - reply = _serializeMessage(reply); - } - _globalState.topEventLoop.enqueue(isolate, () { - if (_receivePort._callback != null) { - if (shouldSerialize) { - msg = _deserializeMessage(msg); - reply = _deserializeMessage(reply); - } - _receivePort._callback(msg, reply); - } - }, 'receive $message'); - }); - } - - bool operator ==(var other) => (other is _NativeJsSendPort) && - (_receivePort == other._receivePort); - - int get hashCode => _receivePort._id; -} - -/** A send port that delivers messages via worker.postMessage. */ -// TODO(eub): abstract this for iframes. -class _WorkerSendPort extends _BaseSendPort implements SendPort { - final int _workerId; - final int _receivePortId; - - const _WorkerSendPort(this._workerId, int isolateId, this._receivePortId) - : super(isolateId); - - void send(var message, [SendPort replyTo = null]) { - _waitForPendingPorts([message, replyTo], () { - _checkReplyTo(replyTo); - final workerMessage = _serializeMessage({ - 'command': 'message', - 'port': this, - 'msg': message, - 'replyTo': replyTo}); - - if (_globalState.isWorker) { - // Communication from one worker to another go through the - // main worker. - _globalState.mainManager.postMessage(workerMessage); - } else { - // Deliver the message only if the worker is still alive. - _ManagerStub manager = _globalState.managers[_workerId]; - if (manager != null) { - manager.postMessage(workerMessage); - } - } - }); - } - - bool operator ==(var other) { - return (other is _WorkerSendPort) && - (_workerId == other._workerId) && - (_isolateId == other._isolateId) && - (_receivePortId == other._receivePortId); - } - - int get hashCode { - // TODO(sigmund): use a standard hash when we get one available in corelib. - return (_workerId << 16) ^ (_isolateId << 8) ^ _receivePortId; - } -} - -/** A port that buffers messages until an underlying port gets resolved. */ -class _BufferingSendPort extends _BaseSendPort implements SendPort { - /** Internal counter to assign unique ids to each port. */ - static int _idCount = 0; - - /** For implementing equals and hashcode. */ - final int _id; - - /** Underlying port, when resolved. */ - SendPort _port; - - /** - * Future of the underlying port, so that we can detect when this port can be - * sent on messages. - */ - Future<SendPort> _futurePort; - - /** Pending messages (and reply ports). */ - List pending; - - _BufferingSendPort(isolateId, this._futurePort) - : super(isolateId), _id = _idCount, pending = [] { - _idCount++; - _futurePort.then((p) { - _port = p; - for (final item in pending) { - p.send(item['message'], item['replyTo']); - } - pending = null; - }); - } - - _BufferingSendPort.fromPort(isolateId, this._port) - : super(isolateId), _id = _idCount { - _idCount++; - } - - void send(var message, [SendPort replyTo]) { - if (_port != null) { - _port.send(message, replyTo); - } else { - pending.add({'message': message, 'replyTo': replyTo}); - } - } - - bool operator ==(var other) => - other is _BufferingSendPort && _id == other._id; - int get hashCode => _id; -} - -/** Implementation of a multi-use [ReceivePort] on top of JavaScript. */ -class ReceivePortImpl implements ReceivePort { - int _id; - Function _callback; - static int _nextFreeId = 1; - - ReceivePortImpl() - : _id = _nextFreeId++ { - _globalState.currentContext.register(_id, this); - } - - void receive(void onMessage(var message, SendPort replyTo)) { - _callback = onMessage; - } - - void close() { - _callback = null; - _globalState.currentContext.unregister(_id); - } - - SendPort toSendPort() { - return new _NativeJsSendPort(this, _globalState.currentContext.id); - } -} - -/** Wait until all ports in a message are resolved. */ -_waitForPendingPorts(var message, void callback()) { - final finder = new _PendingSendPortFinder(); - finder.traverse(message); - Future.wait(finder.ports).then((_) => callback()); -} - - -/** Visitor that finds all unresolved [SendPort]s in a message. */ -class _PendingSendPortFinder extends _MessageTraverser { - List<Future<SendPort>> ports; - _PendingSendPortFinder() : super(), ports = [] { - _visited = new _JsVisitedMap(); - } - - visitPrimitive(x) {} - - visitList(List list) { - final seen = _visited[list]; - if (seen != null) return; - _visited[list] = true; - // TODO(sigmund): replace with the following: (bug #1660) - // list.forEach(_dispatch); - list.forEach((e) => _dispatch(e)); - } - - visitMap(Map map) { - final seen = _visited[map]; - if (seen != null) return; - - _visited[map] = true; - // TODO(sigmund): replace with the following: (bug #1660) - // map.values.forEach(_dispatch); - map.values.forEach((e) => _dispatch(e)); - } - - visitSendPort(SendPort port) { - if (port is _BufferingSendPort && port._port == null) { - ports.add(port._futurePort); - } - } -} - -/******************************************************** - Inserted from lib/isolate/dart2js/messages.dart - ********************************************************/ - -// Defines message visitors, serialization, and deserialization. - -/** Serialize [message] (or simulate serialization). */ -_serializeMessage(message) { - if (_globalState.needSerialization) { - return new _JsSerializer().traverse(message); - } else { - return new _JsCopier().traverse(message); - } -} - -/** Deserialize [message] (or simulate deserialization). */ -_deserializeMessage(message) { - if (_globalState.needSerialization) { - return new _JsDeserializer().deserialize(message); - } else { - // Nothing more to do. - return message; - } -} - -class _JsSerializer extends _Serializer { - - _JsSerializer() : super() { _visited = new _JsVisitedMap(); } - - visitSendPort(SendPort x) { - if (x is _NativeJsSendPort) return visitNativeJsSendPort(x); - if (x is _WorkerSendPort) return visitWorkerSendPort(x); - if (x is _BufferingSendPort) return visitBufferingSendPort(x); - throw "Illegal underlying port $x"; - } - - visitNativeJsSendPort(_NativeJsSendPort port) { - return ['sendport', _globalState.currentManagerId, - port._isolateId, port._receivePort._id]; - } - - visitWorkerSendPort(_WorkerSendPort port) { - return ['sendport', port._workerId, port._isolateId, port._receivePortId]; - } - - visitBufferingSendPort(_BufferingSendPort port) { - if (port._port != null) { - return visitSendPort(port._port); - } else { - // TODO(floitsch): Use real exception (which one?). - throw - "internal error: must call _waitForPendingPorts to ensure all" - " ports are resolved at this point."; - } - } - -} - - -class _JsCopier extends _Copier { - - _JsCopier() : super() { _visited = new _JsVisitedMap(); } - - visitSendPort(SendPort x) { - if (x is _NativeJsSendPort) return visitNativeJsSendPort(x); - if (x is _WorkerSendPort) return visitWorkerSendPort(x); - if (x is _BufferingSendPort) return visitBufferingSendPort(x); - throw "Illegal underlying port $p"; - } - - SendPort visitNativeJsSendPort(_NativeJsSendPort port) { - return new _NativeJsSendPort(port._receivePort, port._isolateId); - } - - SendPort visitWorkerSendPort(_WorkerSendPort port) { - return new _WorkerSendPort( - port._workerId, port._isolateId, port._receivePortId); - } - - SendPort visitBufferingSendPort(_BufferingSendPort port) { - if (port._port != null) { - return visitSendPort(port._port); - } else { - // TODO(floitsch): Use real exception (which one?). - throw - "internal error: must call _waitForPendingPorts to ensure all" - " ports are resolved at this point."; - } - } - -} - -class _JsDeserializer extends _Deserializer { - - SendPort deserializeSendPort(List x) { - int managerId = x[1]; - int isolateId = x[2]; - int receivePortId = x[3]; - // If two isolates are in the same manager, we use NativeJsSendPorts to - // deliver messages directly without using postMessage. - if (managerId == _globalState.currentManagerId) { - var isolate = _globalState.isolates[isolateId]; - if (isolate == null) return null; // Isolate has been closed. - var receivePort = isolate.lookup(receivePortId); - if (receivePort == null) return null; // Port has been closed. - return new _NativeJsSendPort(receivePort, isolateId); - } else { - return new _WorkerSendPort(managerId, isolateId, receivePortId); - } - } - -} - -class _JsVisitedMap implements _MessageTraverserVisitedMap { - List tagged; - - /** Retrieves any information stored in the native object [object]. */ - operator[](var object) { - return _getAttachedInfo(object); - } - - /** Injects some information into the native [object]. */ - void operator[]=(var object, var info) { - tagged.add(object); - _setAttachedInfo(object, info); - } - - /** Get ready to rumble. */ - void reset() { - assert(tagged == null); - tagged = new List(); - } - - /** Remove all information injected in the native objects. */ - void cleanup() { - for (int i = 0, length = tagged.length; i < length; i++) { - _clearAttachedInfo(tagged[i]); - } - tagged = null; - } - - void _clearAttachedInfo(var o) { - JS("void", "#['__MessageTraverser__attached_info__'] = #", o, null); - } - - void _setAttachedInfo(var o, var info) { - JS("void", "#['__MessageTraverser__attached_info__'] = #", o, info); - } - - _getAttachedInfo(var o) { - return JS("", "#['__MessageTraverser__attached_info__']", o); - } -} - -// only visible for testing purposes -// TODO(sigmund): remove once we can disable privacy for testing (bug #1882) -class TestingOnly { - static copy(x) { - return new _JsCopier().traverse(x); - } - - // only visible for testing purposes - static serialize(x) { - _Serializer serializer = new _JsSerializer(); - _Deserializer deserializer = new _JsDeserializer(); - return deserializer.deserialize(serializer.traverse(x)); - } -} - -/******************************************************** - Inserted from lib/isolate/serialization.dart - ********************************************************/ - -class _MessageTraverserVisitedMap { - - operator[](var object) => null; - void operator[]=(var object, var info) { } - - void reset() { } - void cleanup() { } - -} - -/** Abstract visitor for dart objects that can be sent as isolate messages. */ -class _MessageTraverser { - - _MessageTraverserVisitedMap _visited; - _MessageTraverser() : _visited = new _MessageTraverserVisitedMap(); - - /** Visitor's entry point. */ - traverse(var x) { - if (isPrimitive(x)) return visitPrimitive(x); - _visited.reset(); - var result; - try { - result = _dispatch(x); - } finally { - _visited.cleanup(); - } - return result; - } - - _dispatch(var x) { - if (isPrimitive(x)) return visitPrimitive(x); - if (x is List) return visitList(x); - if (x is Map) return visitMap(x); - if (x is SendPort) return visitSendPort(x); - if (x is SendPortSync) return visitSendPortSync(x); - - // Overridable fallback. - return visitObject(x); - } - - visitPrimitive(x); - visitList(List x); - visitMap(Map x); - visitSendPort(SendPort x); - visitSendPortSync(SendPortSync x); - - visitObject(Object x) { - // TODO(floitsch): make this a real exception. (which one)? - throw "Message serialization: Illegal value $x passed"; - } - - static bool isPrimitive(x) { - return (x == null) || (x is String) || (x is num) || (x is bool); - } -} - - -/** A visitor that recursively copies a message. */ -class _Copier extends _MessageTraverser { - - visitPrimitive(x) => x; - - List visitList(List list) { - List copy = _visited[list]; - if (copy != null) return copy; - - int len = list.length; - - // TODO(floitsch): we loose the generic type of the List. - copy = new List(len); - _visited[list] = copy; - for (int i = 0; i < len; i++) { - copy[i] = _dispatch(list[i]); - } - return copy; - } - - Map visitMap(Map map) { - Map copy = _visited[map]; - if (copy != null) return copy; - - // TODO(floitsch): we loose the generic type of the map. - copy = new Map(); - _visited[map] = copy; - map.forEach((key, val) { - copy[_dispatch(key)] = _dispatch(val); - }); - return copy; - } - -} - -/** Visitor that serializes a message as a JSON array. */ -class _Serializer extends _MessageTraverser { - int _nextFreeRefId = 0; - - visitPrimitive(x) => x; - - visitList(List list) { - int copyId = _visited[list]; - if (copyId != null) return ['ref', copyId]; - - int id = _nextFreeRefId++; - _visited[list] = id; - var jsArray = _serializeList(list); - // TODO(floitsch): we are losing the generic type. - return ['list', id, jsArray]; - } - - visitMap(Map map) { - int copyId = _visited[map]; - if (copyId != null) return ['ref', copyId]; - - int id = _nextFreeRefId++; - _visited[map] = id; - var keys = _serializeList(map.keys.toList()); - var values = _serializeList(map.values.toList()); - // TODO(floitsch): we are losing the generic type. - return ['map', id, keys, values]; - } - - _serializeList(List list) { - int len = list.length; - var result = new List(len); - for (int i = 0; i < len; i++) { - result[i] = _dispatch(list[i]); - } - return result; - } -} - -/** Deserializes arrays created with [_Serializer]. */ -class _Deserializer { - Map<int, dynamic> _deserialized; - - _Deserializer(); - - static bool isPrimitive(x) { - return (x == null) || (x is String) || (x is num) || (x is bool); - } - - deserialize(x) { - if (isPrimitive(x)) return x; - // TODO(floitsch): this should be new HashMap<int, var|Dynamic>() - _deserialized = new HashMap(); - return _deserializeHelper(x); - } - - _deserializeHelper(x) { - if (isPrimitive(x)) return x; - assert(x is List); - switch (x[0]) { - case 'ref': return _deserializeRef(x); - case 'list': return _deserializeList(x); - case 'map': return _deserializeMap(x); - case 'sendport': return deserializeSendPort(x); - default: return deserializeObject(x); - } - } - - _deserializeRef(List x) { - int id = x[1]; - var result = _deserialized[id]; - assert(result != null); - return result; - } - - List _deserializeList(List x) { - int id = x[1]; - // We rely on the fact that Dart-lists are directly mapped to Js-arrays. - List dartList = x[2]; - _deserialized[id] = dartList; - int len = dartList.length; - for (int i = 0; i < len; i++) { - dartList[i] = _deserializeHelper(dartList[i]); - } - return dartList; - } - - Map _deserializeMap(List x) { - Map result = new Map(); - int id = x[1]; - _deserialized[id] = result; - List keys = x[2]; - List values = x[3]; - int len = keys.length; - assert(len == values.length); - for (int i = 0; i < len; i++) { - var key = _deserializeHelper(keys[i]); - var value = _deserializeHelper(values[i]); - result[key] = value; - } - return result; - } - - deserializeSendPort(List x); - - deserializeObject(List x) { - // TODO(floitsch): Use real exception (which one?). - throw "Unexpected serialized object"; - } -} - -class TimerImpl implements Timer { - final bool _once; - bool _inEventLoop = false; - int _handle; - - TimerImpl(int milliseconds, void callback(Timer timer)) - : _once = true { - if (milliseconds == 0 && (!hasTimer() || _globalState.isWorker)) { - // This makes a dependency between the async library and the - // event loop of the isolate library. The compiler makes sure - // that the event loop is compiled if [Timer] is used. - // TODO(7907): In case of web workers, we need to use the event - // loop instead of setTimeout, to make sure the futures get executed in - // order. - _globalState.topEventLoop.enqueue(_globalState.currentContext, () { - callback(this); - }, 'timer'); - _inEventLoop = true; - } else if (hasTimer()) { - _globalState.topEventLoop.activeTimerCount++; - void internalCallback() { - callback(this); - _handle = null; - _globalState.topEventLoop.activeTimerCount--; - } - _handle = JS('int', '#.setTimeout(#, #)', - globalThis, - convertDartClosureToJS(internalCallback, 0), - milliseconds); - } else { - assert(milliseconds > 0); - throw new UnsupportedError("Timer greater than 0."); - } - } - - TimerImpl.repeating(int milliseconds, void callback(Timer timer)) - : _once = false { - if (hasTimer()) { - _globalState.topEventLoop.activeTimerCount++; - _handle = JS('int', '#.setInterval(#, #)', - globalThis, - convertDartClosureToJS(() { callback(this); }, 0), - milliseconds); - } else { - throw new UnsupportedError("Repeating timer."); - } - } - - void cancel() { - if (hasTimer()) { - if (_inEventLoop) { - throw new UnsupportedError("Timer in event loop cannot be canceled."); - } - if (_handle == null) return; - _globalState.topEventLoop.activeTimerCount--; - if (_once) { - JS('void', '#.clearTimeout(#)', globalThis, _handle); - } else { - JS('void', '#.clearInterval(#)', globalThis, _handle); - } - _handle = null; - } else { - throw new UnsupportedError("Canceling a timer."); - } - } -} - -bool hasTimer() => JS('', '#.setTimeout', globalThis) != null;
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/lib/isolate_patch.dart b/pkgs/markdown/test/lib/src/compiler/implementation/lib/isolate_patch.dart deleted file mode 100644 index aab847a..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/lib/isolate_patch.dart +++ /dev/null
@@ -1,34 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// Patch file for the dart:isolate library. - -import 'dart:_isolate_helper' show IsolateNatives, - lazyPort, - ReceivePortImpl; - -patch class _Isolate { - patch static ReceivePort get port { - if (lazyPort == null) { - lazyPort = new ReceivePort(); - } - return lazyPort; - } - - patch static SendPort spawnFunction(void topLevelFunction(), - [bool UnhandledExceptionCallback(IsolateUnhandledException e)]) { - return IsolateNatives.spawnFunction(topLevelFunction); - } - - patch static SendPort spawnUri(String uri) { - return IsolateNatives.spawn(null, uri, false); - } -} - -/** Default factory for receive ports. */ -patch class ReceivePort { - patch factory ReceivePort() { - return new ReceivePortImpl(); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/lib/js_array.dart b/pkgs/markdown/test/lib/src/compiler/implementation/lib/js_array.dart deleted file mode 100644 index e33ae3f..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/lib/js_array.dart +++ /dev/null
@@ -1,295 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of _interceptors; - -/** - * The interceptor class for [List]. The compiler recognizes this - * class as an interceptor, and changes references to [:this:] to - * actually use the receiver of the method, which is generated as an extra - * argument added to each member. - */ -class JSArray<E> implements List<E> { - const JSArray(); - - void add(E value) { - checkGrowable(this, 'add'); - JS('void', r'#.push(#)', this, value); - } - - E removeAt(int index) { - if (index is !int) throw new ArgumentError(index); - if (index < 0 || index >= length) { - throw new RangeError.value(index); - } - checkGrowable(this, 'removeAt'); - return JS('var', r'#.splice(#, 1)[0]', this, index); - } - - E removeLast() { - checkGrowable(this, 'removeLast'); - if (length == 0) throw new RangeError.value(-1); - return JS('var', r'#.pop()', this); - } - - void remove(Object element) { - checkGrowable(this, 'remove'); - for (int i = 0; i < this.length; i++) { - if (this[i] == element) { - JS('var', r'#.splice(#, 1)', this, i); - return; - } - } - } - - void removeAll(Iterable elements) { - IterableMixinWorkaround.removeAllList(this, elements); - } - - void retainAll(Iterable elements) { - IterableMixinWorkaround.retainAll(this, elements); - } - - void removeMatching(bool test(E element)) { - // This could, and should, be optimized. - IterableMixinWorkaround.removeMatchingList(this, test); - } - - void retainMatching(bool test(E element)) { - IterableMixinWorkaround.removeMatchingList(this, - (E element) => !test(element)); - } - - Iterable<E> where(bool f(E element)) { - return IterableMixinWorkaround.where(this, f); - } - - Iterable expand(Iterable f(E element)) { - return IterableMixinWorkaround.expand(this, f); - } - - void addAll(Collection<E> collection) { - for (E e in collection) { - this.add(e); - } - } - - void addLast(E value) { - checkGrowable(this, 'addLast'); - JS('void', r'#.push(#)', this, value); - } - - void clear() { - length = 0; - } - - void forEach(void f(E element)) { - return IterableMixinWorkaround.forEach(this, f); - } - - Iterable map(f(E element)) { - return IterableMixinWorkaround.mapList(this, f); - } - - List mappedBy(f(E element)) { - return IterableMixinWorkaround.mappedByList(this, f); - } - - String join([String separator]) { - if (separator == null) separator = ""; - var list = new List(this.length); - for (int i = 0; i < this.length; i++) { - list[i] = "${this[i]}"; - } - return JS('String', "#.join(#)", list, separator); - } - - Iterable<E> take(int n) { - return IterableMixinWorkaround.takeList(this, n); - } - - Iterable<E> takeWhile(bool test(E value)) { - return IterableMixinWorkaround.takeWhile(this, test); - } - - Iterable<E> skip(int n) { - return IterableMixinWorkaround.skipList(this, n); - } - - Iterable<E> skipWhile(bool test(E value)) { - return IterableMixinWorkaround.skipWhile(this, test); - } - - reduce(initialValue, combine(previousValue, E element)) { - return IterableMixinWorkaround.reduce(this, initialValue, combine); - } - - E firstMatching(bool test(E value), {E orElse()}) { - return IterableMixinWorkaround.firstMatching(this, test, orElse); - } - - E lastMatching(bool test(E value), {E orElse()}) { - return IterableMixinWorkaround.lastMatchingInList(this, test, orElse); - } - - E singleMatching(bool test(E value)) { - return IterableMixinWorkaround.singleMatching(this, test); - } - - E elementAt(int index) { - return this[index]; - } - - List<E> getRange(int start, int length) { - // TODO(ngeoffray): Parameterize the return value. - if (0 == length) return []; - checkNull(start); // TODO(ahe): This is not specified but co19 tests it. - checkNull(length); // TODO(ahe): This is not specified but co19 tests it. - if (start is !int) throw new ArgumentError(start); - if (length is !int) throw new ArgumentError(length); - if (length < 0) throw new ArgumentError(length); - if (start < 0) throw new RangeError.value(start); - int end = start + length; - if (end > this.length) { - throw new RangeError.value(length); - } - if (length < 0) throw new ArgumentError(length); - return JS('=List', r'#.slice(#, #)', this, start, end); - } - - void insertRange(int start, int length, [E initialValue]) { - return listInsertRange(this, start, length, initialValue); - } - - E get first { - if (length > 0) return this[0]; - throw new StateError("No elements"); - } - - E get last { - if (length > 0) return this[length - 1]; - throw new StateError("No elements"); - } - - E get single { - if (length == 1) return this[0]; - if (length == 0) throw new StateError("No elements"); - throw new StateError("More than one element"); - } - - E min([int compare(E a, E b)]) => IterableMixinWorkaround.min(this, compare); - - E max([int compare(E a, E b)]) => IterableMixinWorkaround.max(this, compare); - - void removeRange(int start, int length) { - checkGrowable(this, 'removeRange'); - if (length == 0) { - return; - } - checkNull(start); // TODO(ahe): This is not specified but co19 tests it. - checkNull(length); // TODO(ahe): This is not specified but co19 tests it. - if (start is !int) throw new ArgumentError(start); - if (length is !int) throw new ArgumentError(length); - if (length < 0) throw new ArgumentError(length); - var receiverLength = this.length; - if (start < 0 || start >= receiverLength) { - throw new RangeError.value(start); - } - if (start + length > receiverLength) { - throw new RangeError.value(start + length); - } - Arrays.copy(this, - start + length, - this, - start, - receiverLength - length - start); - this.length = receiverLength - length; - } - - void setRange(int start, int length, List<E> from, [int startFrom = 0]) { - checkMutable(this, 'set range'); - if (length == 0) return; - checkNull(start); // TODO(ahe): This is not specified but co19 tests it. - checkNull(length); // TODO(ahe): This is not specified but co19 tests it. - checkNull(from); // TODO(ahe): This is not specified but co19 tests it. - checkNull(startFrom); // TODO(ahe): This is not specified but co19 tests it. - if (start is !int) throw new ArgumentError(start); - if (length is !int) throw new ArgumentError(length); - if (startFrom is !int) throw new ArgumentError(startFrom); - if (length < 0) throw new ArgumentError(length); - if (start < 0) throw new RangeError.value(start); - if (start + length > this.length) { - throw new RangeError.value(start + length); - } - - Arrays.copy(from, startFrom, this, start, length); - } - - bool any(bool f(E element)) => IterableMixinWorkaround.any(this, f); - - bool every(bool f(E element)) => IterableMixinWorkaround.every(this, f); - - List<E> get reversed => IterableMixinWorkaround.reversedList(this); - - void sort([int compare(E a, E b)]) { - checkMutable(this, 'sort'); - IterableMixinWorkaround.sortList(this, compare); - } - - int indexOf(E element, [int start = 0]) { - if (start is !int) throw new ArgumentError(start); - return Arrays.indexOf(this, element, start, length); - } - - int lastIndexOf(E element, [int start]) { - if (start == null) start = this.length - 1; - return Arrays.lastIndexOf(this, element, start); - } - - bool contains(E other) { - for (int i = 0; i < length; i++) { - if (other == this[i]) return true; - } - return false; - } - - bool get isEmpty => length == 0; - - String toString() => Collections.collectionToString(this); - - List<E> toList() => new List<E>.from(this); - - Set<E> toSet() => new Set<E>.from(this); - - Iterator<E> get iterator => new ListIterator<E>(this); - - int get hashCode => Primitives.objectHashCode(this); - - Type get runtimeType { - // Call getRuntimeTypeString to get the name including type arguments. - return new TypeImpl(getRuntimeTypeString(this)); - } - - int get length => JS('int', r'#.length', this); - - void set length(int newLength) { - if (newLength is !int) throw new ArgumentError(newLength); - if (newLength < 0) throw new RangeError.value(newLength); - checkGrowable(this, 'set length'); - JS('void', r'#.length = #', this, newLength); - } - - E operator [](int index) { - if (index is !int) throw new ArgumentError(index); - if (index >= length || index < 0) throw new RangeError.value(index); - return JS('var', '#[#]', this, index); - } - - void operator []=(int index, E value) { - checkMutable(this, 'indexed set'); - if (index is !int) throw new ArgumentError(index); - if (index >= length || index < 0) throw new RangeError.value(index); - JS('void', r'#[#] = #', this, index, value); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/lib/js_helper.dart b/pkgs/markdown/test/lib/src/compiler/implementation/lib/js_helper.dart deleted file mode 100644 index 0fbff9c..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/lib/js_helper.dart +++ /dev/null
@@ -1,1513 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library _js_helper; - -import 'dart:collection'; -import 'dart:_foreign_helper' show DART_CLOSURE_TO_JS, - JS, - JS_CALL_IN_ISOLATE, - JS_CURRENT_ISOLATE, - JS_OPERATOR_IS_PREFIX, - JS_HAS_EQUALS, - RAW_DART_FUNCTION_REF, - UNINTERCEPTED; -import 'dart:_interceptors' show getInterceptor; - -part 'constant_map.dart'; -part 'native_helper.dart'; -part 'regexp_helper.dart'; -part 'string_helper.dart'; - -bool isJsArray(var value) { - return value != null && JS('bool', r'#.constructor === Array', value); -} - -checkMutable(list, reason) { - if (JS('bool', r'!!(#.immutable$list)', list)) { - throw new UnsupportedError(reason); - } -} - -checkGrowable(list, reason) { - if (JS('bool', r'!!(#.fixed$length)', list)) { - throw new UnsupportedError(reason); - } -} - -String S(value) { - if (value is String) return value; - if ((value is num && value != 0) || value is bool) { - return JS('String', r'String(#)', value); - } - if (value == null) return 'null'; - var res = value.toString(); - if (res is !String) throw new ArgumentError(value); - return res; -} - -createInvocationMirror(name, internalName, type, arguments, argumentNames) => - new JSInvocationMirror(name, internalName, type, arguments, argumentNames); - -class JSInvocationMirror implements InvocationMirror { - static const METHOD = 0; - static const GETTER = 1; - static const SETTER = 2; - - final String memberName; - final String _internalName; - final int _kind; - final List _arguments; - final List _namedArgumentNames; - /** Map from argument name to index in _arguments. */ - Map<String,dynamic> _namedIndices = null; - - JSInvocationMirror(this.memberName, - this._internalName, - this._kind, - this._arguments, - this._namedArgumentNames); - - bool get isMethod => _kind == METHOD; - bool get isGetter => _kind == GETTER; - bool get isSetter => _kind == SETTER; - bool get isAccessor => _kind != METHOD; - - List get positionalArguments { - if (isGetter) return null; - var list = []; - var argumentCount = - _arguments.length - _namedArgumentNames.length; - for (var index = 0 ; index < argumentCount ; index++) { - list.add(_arguments[index]); - } - return list; - } - - Map<String,dynamic> get namedArguments { - if (isAccessor) return null; - var map = <String,dynamic>{}; - int namedArgumentCount = _namedArgumentNames.length; - int namedArgumentsStartIndex = _arguments.length - namedArgumentCount; - for (int i = 0; i < namedArgumentCount; i++) { - map[_namedArgumentNames[i]] = _arguments[namedArgumentsStartIndex + i]; - } - return map; - } - - static final _objectInterceptor = getInterceptor(new Object()); - invokeOn(Object object) { - var interceptor = getInterceptor(object); - var receiver = object; - var name = _internalName; - var arguments = _arguments; - if (identical(interceptor, _objectInterceptor)) { - if (!isJsArray(arguments)) arguments = new List.from(arguments); - } else { - arguments = [object]..addAll(arguments); - receiver = interceptor; - } - return JS("var", "#[#].apply(#, #)", receiver, name, receiver, arguments); - } -} - -class Primitives { - static int hashCodeSeed = 0; - - static int objectHashCode(object) { - int hash = JS('var', r'#.$identityHash', object); - if (hash == null) { - // TOOD(ahe): We should probably randomize this somehow. - hash = ++hashCodeSeed; - JS('void', r'#.$identityHash = #', object, hash); - } - return hash; - } - - /** - * This is the low-level method that is used to implement - * [print]. It is possible to override this function from JavaScript - * by defining a function in JavaScript called "dartPrint". - */ - static void printString(String string) { - if (JS('bool', r'typeof dartPrint == "function"')) { - // Support overriding print from JavaScript. - JS('void', r'dartPrint(#)', string); - return; - } - - // Inside browser. - if (JS('bool', r'typeof window == "object"')) { - // On IE, the console is only defined if dev tools is open. - if (JS('bool', r'typeof console == "object"')) { - JS('void', r'console.log(#)', string); - } - return; - } - - // Running in d8, the V8 developer shell, or in Firefox' js-shell. - if (JS('bool', r'typeof print == "function"')) { - JS('void', r'print(#)', string); - return; - } - - // This is somewhat nasty, but we don't want to drag in a bunch of - // dependencies to handle a situation that cannot happen. So we - // avoid using Dart [:throw:] and Dart [toString]. - JS('void', "throw 'Unable to print message: ' + String(#)", string); - } - - static void _throwFormatException(String string) { - throw new FormatException(string); - } - - static int parseInt(String source, - int radix, - int handleError(String source)) { - if (handleError == null) handleError = _throwFormatException; - - checkString(source); - var match = JS('=List|Null', - r'/^\s*[+-]?((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$/i.exec(#)', - source); - int digitsIndex = 1; - int hexIndex = 2; - int decimalIndex = 3; - int nonDecimalHexIndex = 4; - if (radix == null) { - radix = 10; - if (match != null) { - if (match[hexIndex] != null) { - // Cannot fail because we know that the digits are all hex. - return JS('num', r'parseInt(#, 16)', source); - } - if (match[decimalIndex] != null) { - // Cannot fail because we know that the digits are all decimal. - return JS('num', r'parseInt(#, 10)', source); - } - return handleError(source); - } - } else { - if (radix is! int) throw new ArgumentError("Radix is not an integer"); - if (radix < 2 || radix > 36) { - throw new RangeError("Radix $radix not in range 2..36"); - } - if (match != null) { - if (radix == 10 && match[decimalIndex] != null) { - // Cannot fail because we know that the digits are all decimal. - return JS('num', r'parseInt(#, 10)', source); - } - if (radix < 10 || match[decimalIndex] == null) { - // We know that the characters must be ASCII as otherwise the - // regexp wouldn't have matched. Calling toLowerCase is thus - // guaranteed to be a safe operation. If it wasn't ASCII, then - // "İ" would become "i", and we would accept it for radices greater - // than 18. - int maxCharCode; - if (radix <= 10) { - // Allow all digits less than the radix. For example 0, 1, 2 for - // radix 3. - // "0".charCodeAt(0) + radix - 1; - maxCharCode = 0x30 + radix - 1; - } else { - // Characters are located after the digits in ASCII. Therefore we - // only check for the character code. The regexp above made already - // sure that the string does not contain anything but digits or - // characters. - // "0".charCodeAt(0) + radix - 1; - maxCharCode = 0x61 + radix - 10 - 1; - } - String digitsPart = match[digitsIndex].toLowerCase(); - for (int i = 0; i < digitsPart.length; i++) { - if (digitsPart.charCodeAt(i) > maxCharCode) { - return handleError(source); - } - } - } - } - } - if (match == null) return handleError(source); - return JS('num', r'parseInt(#, #)', source, radix); - } - - static double parseDouble(String source, int handleError(String source)) { - checkString(source); - if (handleError == null) handleError = _throwFormatException; - // Notice that JS parseFloat accepts garbage at the end of the string. - // Accept only: - // - NaN - // - [+/-]Infinity - // - a Dart double literal - // We do not allow leading or trailing whitespace. - if (!JS('bool', - r'/^\s*(?:NaN|[+-]?(?:Infinity|' - r'(?:\.\d+|\d+(?:\.\d+)?)(?:[eE][+-]?\d+)?))\s*$/.test(#)', - source)) { - return handleError(source); - } - var result = JS('num', r'parseFloat(#)', source); - if (result.isNaN && source != 'NaN') { - return handleError(source); - } - return result; - } - - /** [: r"$".charCodeAt(0) :] */ - static const int DOLLAR_CHAR_VALUE = 36; - - static String objectTypeName(Object object) { - String name = constructorNameFallback(object); - if (name == 'Object') { - // Try to decompile the constructor by turning it into a string - // and get the name out of that. If the decompiled name is a - // string, we use that instead of the very generic 'Object'. - var decompiled = JS('var', r'#.match(/^\s*function\s*(\S*)\s*\(/)[1]', - JS('var', r'String(#.constructor)', object)); - if (decompiled is String) name = decompiled; - } - // TODO(kasperl): If the namer gave us a fresh global name, we may - // want to remove the numeric suffix that makes it unique too. - if (identical(name.charCodeAt(0), DOLLAR_CHAR_VALUE)) name = name.substring(1); - return name; - } - - static String objectToString(Object object) { - String name = objectTypeName(object); - return "Instance of '$name'"; - } - - static List newGrowableList(length) { - return JS('=List', r'new Array(#)', length); - } - - static List newFixedList(length) { - var result = JS('=List', r'new Array(#)', length); - JS('void', r'#.fixed$length = #', result, true); - return result; - } - - static num dateNow() => JS('num', r'Date.now()'); - - static num numMicroseconds() { - if (JS('bool', 'typeof window != "undefined" && window !== null')) { - var performance = JS('var', 'window.performance'); - if (performance != null && - JS('bool', 'typeof #.webkitNow == "function"', performance)) { - return (1000 * JS('num', '#.webkitNow()', performance)).floor(); - } - } - return 1000 * dateNow(); - } - - // This is to avoid stack overflows due to very large argument arrays in - // apply(). It fixes http://dartbug.com/6919 - static String _fromCharCodeApply(List<int> array) { - String result = ""; - const kMaxApply = 500; - int end = array.length; - for (var i = 0; i < end; i += kMaxApply) { - var subarray; - if (end <= kMaxApply) { - subarray = array; - } else { - subarray = JS('=List', r'#.slice(#, #)', array, - i, i + kMaxApply < end ? i + kMaxApply : end); - } - result = JS('String', '# + String.fromCharCode.apply(#, #)', - result, null, subarray); - } - return result; - } - - static String stringFromCodePoints(codePoints) { - List<int> a = <int>[]; - for (var i in codePoints) { - if (i is !int) throw new ArgumentError(i); - if (i <= 0xffff) { - a.add(i); - } else if (i <= 0x10ffff) { - a.add(0xd800 + ((((i - 0x10000) >> 10) & 0x3ff))); - a.add(0xdc00 + (i & 0x3ff)); - } else { - throw new ArgumentError(i); - } - } - return _fromCharCodeApply(a); - } - - static String stringFromCharCodes(charCodes) { - for (var i in charCodes) { - if (i is !int) throw new ArgumentError(i); - if (i < 0) throw new ArgumentError(i); - if (i > 0xffff) return stringFromCodePoints(charCodes); - } - return _fromCharCodeApply(charCodes); - } - - static String getTimeZoneName(receiver) { - // When calling toString on a Date it will emit the timezone in parenthesis. - // Example: "Wed May 16 2012 21:13:00 GMT+0200 (CEST)". - // We extract this name using a regexp. - var d = lazyAsJsDate(receiver); - return JS('String', r'/\((.*)\)/.exec(#.toString())[1]', d); - } - - static int getTimeZoneOffsetInMinutes(receiver) { - // Note that JS and Dart disagree on the sign of the offset. - return -JS('int', r'#.getTimezoneOffset()', lazyAsJsDate(receiver)); - } - - static valueFromDecomposedDate(years, month, day, hours, minutes, seconds, - milliseconds, isUtc) { - final int MAX_MILLISECONDS_SINCE_EPOCH = 8640000000000000; - checkInt(years); - checkInt(month); - checkInt(day); - checkInt(hours); - checkInt(minutes); - checkInt(seconds); - checkInt(milliseconds); - checkBool(isUtc); - var jsMonth = month - 1; - var value; - if (isUtc) { - value = JS('num', r'Date.UTC(#, #, #, #, #, #, #)', - years, jsMonth, day, hours, minutes, seconds, milliseconds); - } else { - value = JS('num', r'new Date(#, #, #, #, #, #, #).valueOf()', - years, jsMonth, day, hours, minutes, seconds, milliseconds); - } - if (value.isNaN || - value < -MAX_MILLISECONDS_SINCE_EPOCH || - value > MAX_MILLISECONDS_SINCE_EPOCH) { - throw new ArgumentError(); - } - if (years <= 0 || years < 100) return patchUpY2K(value, years, isUtc); - return value; - } - - static patchUpY2K(value, years, isUtc) { - var date = JS('', r'new Date(#)', value); - if (isUtc) { - JS('num', r'#.setUTCFullYear(#)', date, years); - } else { - JS('num', r'#.setFullYear(#)', date, years); - } - return JS('num', r'#.valueOf()', date); - } - - // Lazily keep a JS Date stored in the JS object. - static lazyAsJsDate(receiver) { - if (JS('bool', r'#.date === (void 0)', receiver)) { - JS('void', r'#.date = new Date(#)', receiver, - receiver.millisecondsSinceEpoch); - } - return JS('var', r'#.date', receiver); - } - - // The getters for date and time parts below add a positive integer to ensure - // that the result is really an integer, because the JavaScript implementation - // may return -0.0 instead of 0. - - static getYear(receiver) { - return (receiver.isUtc) - ? JS('int', r'(#.getUTCFullYear() + 0)', lazyAsJsDate(receiver)) - : JS('int', r'(#.getFullYear() + 0)', lazyAsJsDate(receiver)); - } - - static getMonth(receiver) { - return (receiver.isUtc) - ? JS('int', r'#.getUTCMonth() + 1', lazyAsJsDate(receiver)) - : JS('int', r'#.getMonth() + 1', lazyAsJsDate(receiver)); - } - - static getDay(receiver) { - return (receiver.isUtc) - ? JS('int', r'(#.getUTCDate() + 0)', lazyAsJsDate(receiver)) - : JS('int', r'(#.getDate() + 0)', lazyAsJsDate(receiver)); - } - - static getHours(receiver) { - return (receiver.isUtc) - ? JS('int', r'(#.getUTCHours() + 0)', lazyAsJsDate(receiver)) - : JS('int', r'(#.getHours() + 0)', lazyAsJsDate(receiver)); - } - - static getMinutes(receiver) { - return (receiver.isUtc) - ? JS('int', r'(#.getUTCMinutes() + 0)', lazyAsJsDate(receiver)) - : JS('int', r'(#.getMinutes() + 0)', lazyAsJsDate(receiver)); - } - - static getSeconds(receiver) { - return (receiver.isUtc) - ? JS('int', r'(#.getUTCSeconds() + 0)', lazyAsJsDate(receiver)) - : JS('int', r'(#.getSeconds() + 0)', lazyAsJsDate(receiver)); - } - - static getMilliseconds(receiver) { - return (receiver.isUtc) - ? JS('int', r'(#.getUTCMilliseconds() + 0)', lazyAsJsDate(receiver)) - : JS('int', r'(#.getMilliseconds() + 0)', lazyAsJsDate(receiver)); - } - - static getWeekday(receiver) { - int weekday = (receiver.isUtc) - ? JS('int', r'#.getUTCDay() + 0', lazyAsJsDate(receiver)) - : JS('int', r'#.getDay() + 0', lazyAsJsDate(receiver)); - // Adjust by one because JS weeks start on Sunday. - return (weekday + 6) % 7 + 1; - } - - static valueFromDateString(str) { - if (str is !String) throw new ArgumentError(str); - var value = JS('num', r'Date.parse(#)', str); - if (value.isNaN) throw new ArgumentError(str); - return value; - } - - static getProperty(object, key) { - if (object == null || object is bool || object is num || object is String) { - throw new ArgumentError(object); - } - return JS('var', '#[#]', object, key); - } - - static void setProperty(object, key, value) { - if (object == null || object is bool || object is num || object is String) { - throw new ArgumentError(object); - } - JS('void', '#[#] = #', object, key, value); - } - - static applyFunction(Function function, - List positionalArguments, - Map<String, dynamic> namedArguments) { - int argumentCount = 0; - StringBuffer buffer = new StringBuffer(); - List arguments = []; - - if (positionalArguments != null) { - argumentCount += positionalArguments.length; - arguments.addAll(positionalArguments); - } - - // Sort the named arguments to get the right selector name and - // arguments order. - if (namedArguments != null && !namedArguments.isEmpty) { - // Call new List.from to make sure we get a JavaScript array. - List<String> listOfNamedArguments = - new List<String>.from(namedArguments.keys); - argumentCount += namedArguments.length; - // We're sorting on strings, and the behavior is the same between - // Dart string sort and JS string sort. To avoid needing the Dart - // sort implementation, we use the JavaScript one instead. - JS('void', '#.sort()', listOfNamedArguments); - listOfNamedArguments.forEach((String name) { - buffer.add('\$$name'); - arguments.add(namedArguments[name]); - }); - } - - String selectorName = 'call\$$argumentCount$buffer'; - var jsFunction = JS('var', '#[#]', function, selectorName); - if (jsFunction == null) { - throw new NoSuchMethodError(function, selectorName, arguments, {}); - } - // We bound 'this' to [function] because of how we compile - // closures: escaped local variables are stored and accessed through - // [function]. - return JS('var', '#.apply(#, #)', jsFunction, function, arguments); - } - - static getConstructor(String className) { - // TODO(ahe): How to safely access $? - return JS('var', r'$[#]', className); - } - - static bool identicalImplementation(a, b) { - return JS('bool', '# == null', a) - ? JS('bool', '# == null', b) - : JS('bool', '# === #', a, b); - } -} - -/** - * Called by generated code to throw an illegal-argument exception, - * for example, if a non-integer index is given to an optimized - * indexed access. - */ -iae(argument) { - throw new ArgumentError(argument); -} - -/** - * Called by generated code to throw an index-out-of-range exception, - * for example, if a bounds check fails in an optimized indexed - * access. - */ -ioore(index) { - throw new RangeError.value(index); -} - -listInsertRange(receiver, start, length, initialValue) { - if (length == 0) { - return; - } - if (length is !int) throw new ArgumentError(length); - if (length < 0) throw new ArgumentError(length); - if (start is !int) throw new ArgumentError(start); - - var receiverLength = JS('num', r'#.length', receiver); - if (start < 0 || start > receiverLength) { - throw new RangeError.value(start); - } - receiver.length = receiverLength + length; - Arrays.copy(receiver, - start, - receiver, - start + length, - receiverLength - start); - if (initialValue != null) { - for (int i = start; i < start + length; i++) { - receiver[i] = initialValue; - } - } - receiver.length = receiverLength + length; -} - -stringLastIndexOfUnchecked(receiver, element, start) - => JS('int', r'#.lastIndexOf(#, #)', receiver, element, start); - - -checkNull(object) { - if (object == null) throw new ArgumentError(null); - return object; -} - -checkNum(value) { - if (value is !num) { - throw new ArgumentError(value); - } - return value; -} - -checkInt(value) { - if (value is !int) { - throw new ArgumentError(value); - } - return value; -} - -checkBool(value) { - if (value is !bool) { - throw new ArgumentError(value); - } - return value; -} - -checkString(value) { - if (value is !String) { - throw new ArgumentError(value); - } - return value; -} - -class MathNatives { - static double sqrt(num value) - => JS('double', r'Math.sqrt(#)', checkNum(value)); - - static double sin(num value) - => JS('double', r'Math.sin(#)', checkNum(value)); - - static double cos(num value) - => JS('double', r'Math.cos(#)', checkNum(value)); - - static double tan(num value) - => JS('double', r'Math.tan(#)', checkNum(value)); - - static double acos(num value) - => JS('double', r'Math.acos(#)', checkNum(value)); - - static double asin(num value) - => JS('double', r'Math.asin(#)', checkNum(value)); - - static double atan(num value) - => JS('double', r'Math.atan(#)', checkNum(value)); - - static double atan2(num a, num b) - => JS('double', r'Math.atan2(#, #)', checkNum(a), checkNum(b)); - - static double exp(num value) - => JS('double', r'Math.exp(#)', checkNum(value)); - - static double log(num value) - => JS('double', r'Math.log(#)', checkNum(value)); - - static num pow(num value, num exponent) { - checkNum(value); - checkNum(exponent); - return JS('num', r'Math.pow(#, #)', value, exponent); - } - - static double random() => JS('double', r'Math.random()'); -} - -/** - * Wrap the given Dart object and record a stack trace. - * - * The code in [unwrapException] deals with getting the original Dart - * object out of the wrapper again. - */ -$throw(ex) { - if (ex == null) ex = const NullThrownError(); - var wrapper = new DartError(ex); - - if (JS('bool', '!!Error.captureStackTrace')) { - // Use V8 API for recording a "fast" stack trace (this installs a - // "stack" property getter on [wrapper]). - JS('void', r'Error.captureStackTrace(#, #)', - wrapper, RAW_DART_FUNCTION_REF($throw)); - } else { - // Otherwise, produce a stack trace and record it in the wrapper. - // This is a slower way to create a stack trace which works on - // some browsers, but may simply evaluate to null. - String stackTrace = JS('', 'new Error().stack'); - JS('void', '#.stack = #', wrapper, stackTrace); - } - return wrapper; -} - -/** - * Wrapper class for throwing exceptions. - */ -class DartError { - /// The Dart object (or primitive JavaScript value) which was thrown is - /// attached to this object as a field named 'dartException'. We do this - /// only in raw JS so that we can use the 'in' operator and so that the - /// minifier does not rename the field. Therefore it is not declared as a - /// real field. - - DartError(var dartException) { - JS('void', '#.dartException = #', this, dartException); - // Install a toString method that the JavaScript system will call - // to format uncaught exceptions. - JS('void', '#.toString = #', this, DART_CLOSURE_TO_JS(toStringWrapper)); - } - - /** - * V8/Chrome installs a property getter, "stack", when calling - * Error.captureStackTrace (see [$throw]). In [$throw], we make sure - * that this property is always set. - */ - String get stack => JS('', '#.stack', this); - - /** - * This method can be invoked by calling toString from - * JavaScript. See the constructor of this class. - * - * We only expect this method to be called (indirectly) by the - * browser when an uncaught exception occurs. Instance of this class - * should never escape into Dart code (except for [$throw] above). - */ - String toString() { - // If Error.captureStackTrace is available, accessing stack from - // this method would cause recursion because the stack property - // (on this object) is actually a getter which calls toString on - // this object (via the wrapper installed in this class' - // constructor). Fortunately, both Chrome and d8 prints the stack - // trace and Chrome even applies source maps to the stack - // trace. Remeber, this method is only ever invoked by the browser - // when an uncaught exception occurs. - var dartException = JS('var', r'#.dartException', this); - if (JS('bool', '!!Error.captureStackTrace') || (stack == null)) { - return dartException.toString(); - } else { - return '$dartException\n$stack'; - } - } - - /** - * This method is installed as JavaScript toString method on - * [DartError]. So JavaScript 'this' binds to an instance of - * DartError. - */ - static toStringWrapper() => JS('', r'this').toString(); -} - -makeLiteralListConst(list) { - JS('bool', r'#.immutable$list = #', list, true); - JS('bool', r'#.fixed$length = #', list, true); - return list; -} - -throwRuntimeError(message) { - throw new RuntimeError(message); -} - -/** - * The SSA builder generates a call to this method when a malformed type is used - * in a subtype test. - */ -throwMalformedSubtypeError(value, type, reasons) { - throw new TypeErrorImplementation.malformedSubtype(value, type, reasons); -} - -throwAbstractClassInstantiationError(className) { - throw new AbstractClassInstantiationError(className); -} - -/** - * Called from catch blocks in generated code to extract the Dart - * exception from the thrown value. The thrown value may have been - * created by [$throw] or it may be a 'native' JS exception. - * - * Some native exceptions are mapped to new Dart instances, others are - * returned unmodified. - */ -unwrapException(ex) { - // Note that we are checking if the object has the property. If it - // has, it could be set to null if the thrown value is null. - if (JS('bool', r'"dartException" in #', ex)) { - return JS('', r'#.dartException', ex); - } - - // Grab hold of the exception message. This field is available on - // all supported browsers. - var message = JS('var', r'#.message', ex); - - if (JS('bool', r'# instanceof TypeError', ex)) { - // The type and arguments fields are Chrome specific but they - // allow us to get very detailed information about what kind of - // exception occurred. - var type = JS('var', r'#.type', ex); - var name = JS('var', r'#.arguments ? #.arguments[0] : ""', ex, ex); - if (contains(message, 'JSNull') || - type == 'property_not_function' || - type == 'called_non_callable' || - type == 'non_object_property_call' || - type == 'non_object_property_load') { - return new NoSuchMethodError(null, name, [], {}); - } else if (type == 'undefined_method') { - return new NoSuchMethodError('', name, [], {}); - } - - var ieErrorCode = JS('int', '#.number & 0xffff', ex); - var ieFacilityNumber = JS('int', '#.number>>16 & 0x1FFF', ex); - // If we cannot use [type] to determine what kind of exception - // we're dealing with we fall back on looking at the exception - // message if it is available and a string. - if (message is String) { - if (message.endsWith('is null') || - message.endsWith('is undefined') || - message.endsWith('is null or undefined') || - message.endsWith('of undefined') || - message.endsWith('of null')) { - return new NoSuchMethodError(null, '<unknown>', [], {}); - } else if (contains(message, ' has no method ') || - contains(message, ' is not a function') || - (ieErrorCode == 438 && ieFacilityNumber == 10)) { - // Examples: - // x.foo is not a function - // 'undefined' is not a function (evaluating 'x.foo(1,2,3)') - // Object doesn't support property or method 'foo' which sets the error - // code 438 in IE. - // TODO(kasperl): Compute the right name if possible. - return new NoSuchMethodError('', '<unknown>', [], {}); - } - } - - // If we cannot determine what kind of error this is, we fall back - // to reporting this as a generic exception. It's probably better - // than nothing. - return new Exception(message is String ? message : ''); - } - - if (JS('bool', r'# instanceof RangeError', ex)) { - if (message is String && contains(message, 'call stack')) { - return new StackOverflowError(); - } - - // In general, a RangeError is thrown when trying to pass a number - // as an argument to a function that does not allow a range that - // includes that number. - return new ArgumentError(); - } - - // Check for the Firefox specific stack overflow signal. - if (JS('bool', - r"typeof InternalError == 'function' && # instanceof InternalError", - ex)) { - if (message is String && message == 'too much recursion') { - return new StackOverflowError(); - } - } - - // Just return the exception. We should not wrap it because in case - // the exception comes from the DOM, it is a JavaScript - // object backed by a native Dart class. - return ex; -} - -/** - * Called by generated code to fetch the stack trace from an - * exception. - */ -StackTrace getTraceFromException(exception) { - return new StackTrace(JS("var", r"#.stack", exception)); -} - -class StackTrace { - var stack; - StackTrace(this.stack); - String toString() => stack != null ? stack : ''; -} - - -/** - * Called by generated code to build a map literal. [keyValuePairs] is - * a list of key, value, key, value, ..., etc. - */ -makeLiteralMap(List keyValuePairs) { - Iterator iterator = keyValuePairs.iterator; - Map result = new LinkedHashMap(); - while (iterator.moveNext()) { - String key = iterator.current; - iterator.moveNext(); - var value = iterator.current; - result[key] = value; - } - return result; -} - -invokeClosure(Function closure, - var isolate, - int numberOfArguments, - var arg1, - var arg2) { - if (numberOfArguments == 0) { - return JS_CALL_IN_ISOLATE(isolate, () => closure()); - } else if (numberOfArguments == 1) { - return JS_CALL_IN_ISOLATE(isolate, () => closure(arg1)); - } else if (numberOfArguments == 2) { - return JS_CALL_IN_ISOLATE(isolate, () => closure(arg1, arg2)); - } else { - throw new Exception( - 'Unsupported number of arguments for wrapped closure'); - } -} - -/** - * Called by generated code to convert a Dart closure to a JS - * closure when the Dart closure is passed to the DOM. - */ -convertDartClosureToJS(closure, int arity) { - if (closure == null) return null; - var function = JS('var', r'#.$identity', closure); - if (JS('bool', r'!!#', function)) return function; - // By fetching the current isolate before creating the JavaScript - // function, we prevent the compiler from inlining its use in - // the JavaScript function below (the compiler generates code for - // fetching the isolate before creating the JavaScript function). - // If it was inlined, the JavaScript function would not get the - // current isolate, but the one that is active when the callback - // executes. - var currentIsolate = JS_CURRENT_ISOLATE(); - - // We use $0 and $1 to not clash with variable names used by the - // compiler and/or minifier. - function = JS("var", - r"""function($0, $1) { return #(#, #, #, $0, $1); }""", - DART_CLOSURE_TO_JS(invokeClosure), - closure, - JS_CURRENT_ISOLATE(), - arity); - - JS('void', r'#.$identity = #', closure, function); - return function; -} - -/** - * Super class for Dart closures. - */ -class Closure implements Function { - String toString() => "Closure"; -} - -bool jsHasOwnProperty(var jsObject, String property) { - return JS('bool', r'#.hasOwnProperty(#)', jsObject, property); -} - -jsPropertyAccess(var jsObject, String property) { - return JS('var', r'#[#]', jsObject, property); -} - -/** - * Called at the end of unaborted switch cases to get the singleton - * FallThroughError exception that will be thrown. - */ -getFallThroughError() => const FallThroughErrorImplementation(); - -/** - * Represents the type Dynamic. The compiler treats this specially. - */ -abstract class Dynamic_ { -} - -/** - * A metadata annotation describing the types instantiated by a native element. - * - * The annotation is valid on a native method and a field of a native class. - * - * By default, a field of a native class is seen as an instantiation point for - * all native classes that are a subtype of the field's type, and a native - * method is seen as an instantiation point fo all native classes that are a - * subtype of the method's return type, or the argument types of the declared - * type of the method's callback parameter. - * - * An @[Creates] annotation overrides the default set of instantiated types. If - * one or more @[Creates] annotations are present, the type of the native - * element is ignored, and the union of @[Creates] annotations is used instead. - * The names in the strings are resolved and the program will fail to compile - * with dart2js if they do not name types. - * - * The argument to [Creates] is a string. The string is parsed as the names of - * one or more types, separated by vertical bars `|`. There are some special - * names: - * - * * `=List`. This means 'exactly List', which is the JavaScript Array - * implementation of [List] and no other implementation. - * - * * `=Object`. This means 'exactly Object', which is a plain JavaScript object - * with properties and none of the subtypes of Object. - * - * Example: we may know that a method always returns a specific implementation: - * - * @Creates('_NodeList') - * List<Node> getElementsByTagName(String tag) native; - * - * Useful trick: A method can be marked as not instantiating any native classes - * with the annotation `@Creates('Null')`. This is useful for fields on native - * classes that are used only in Dart code. - * - * @Creates('Null') - * var _cachedFoo; - */ -class Creates { - final String types; - const Creates(this.types); -} - -/** - * A metadata annotation describing the types returned or yielded by a native - * element. - * - * The annotation is valid on a native method and a field of a native class. - * - * By default, a native method or field is seen as returning or yielding all - * subtypes if the method return type or field type. This annotation allows a - * more precise set of types to be specified. - * - * See [Creates] for the syntax of the argument. - * - * Example: IndexedDB keys are numbers, strings and JavaScript Arrays of keys. - * - * @Returns('String|num|=List') - * dynamic key; - * - * // Equivalent: - * @Returns('String') @Returns('num') @Returns('=List') - * dynamic key; - */ -class Returns { - final String types; - const Returns(this.types); -} - -/** - * A metadata annotation placed on native methods and fields of native classes - * to specify the JavaScript name. - * - * This example declares a Dart field + getter + setter called `$dom_title` that - * corresponds to the JavaScript property `title`. - * - * class Docmument native "*Foo" { - * @JSName('title') - * String $dom_title; - * } - */ -class JSName { - final String name; - const JSName(this.name); -} - -/** - * Represents the type of Null. The compiler treats this specially. - * TODO(lrn): Null should be defined in core. It's a class, like int. - * It just happens to act differently in assignability tests and, - * like int, can't be extended or implemented. - */ -class Null { - factory Null() { - throw new UnsupportedError('new Null()'); - } -} - -setRuntimeTypeInfo(target, typeInfo) { - assert(typeInfo == null || isJsArray(typeInfo)); - // We have to check for null because factories may return null. - if (target != null) JS('var', r'#.$builtinTypeInfo = #', target, typeInfo); -} - -getRuntimeTypeInfo(target) { - if (target == null) return null; - var res = JS('var', r'#.$builtinTypeInfo', target); - // If the object does not have runtime type information, return an - // empty literal, to avoid null checks. - // TODO(ngeoffray): Make the object a top-level field to avoid - // allocating a new object every single time. - return (res == null) ? JS('var', '{}') : res; -} - -/** - * The following methods are called by the runtime to implement - * checked mode and casts. We specialize each primitive type (eg int, bool), and - * use the compiler's convention to do is-checks on regular objects. - */ -boolConversionCheck(value) { - boolTypeCheck(value); - assert(value != null); - return value; -} - -stringTypeCheck(value) { - if (value == null) return value; - if (value is String) return value; - throw new TypeErrorImplementation(value, 'String'); -} - -stringTypeCast(value) { - if (value is String || value == null) return value; - // TODO(lrn): When reified types are available, pass value.class and String. - throw new CastErrorImplementation( - Primitives.objectTypeName(value), 'String'); -} - -doubleTypeCheck(value) { - if (value == null) return value; - if (value is double) return value; - throw new TypeErrorImplementation(value, 'double'); -} - -doubleTypeCast(value) { - if (value is double || value == null) return value; - throw new CastErrorImplementation( - Primitives.objectTypeName(value), 'double'); -} - -numTypeCheck(value) { - if (value == null) return value; - if (value is num) return value; - throw new TypeErrorImplementation(value, 'num'); -} - -numTypeCast(value) { - if (value is num || value == null) return value; - throw new CastErrorImplementation( - Primitives.objectTypeName(value), 'num'); -} - -boolTypeCheck(value) { - if (value == null) return value; - if (value is bool) return value; - throw new TypeErrorImplementation(value, 'bool'); -} - -boolTypeCast(value) { - if (value is bool || value == null) return value; - throw new CastErrorImplementation( - Primitives.objectTypeName(value), 'bool'); -} - -functionTypeCheck(value) { - if (value == null) return value; - if (value is Function) return value; - throw new TypeErrorImplementation(value, 'Function'); -} - -functionTypeCast(value) { - if (value is Function || value == null) return value; - throw new CastErrorImplementation( - Primitives.objectTypeName(value), 'Function'); -} - -intTypeCheck(value) { - if (value == null) return value; - if (value is int) return value; - throw new TypeErrorImplementation(value, 'int'); -} - -intTypeCast(value) { - if (value is int || value == null) return value; - throw new CastErrorImplementation( - Primitives.objectTypeName(value), 'int'); -} - -void propertyTypeError(value, property) { - // Cuts the property name to the class name. - String name = property.substring(3, property.length); - throw new TypeErrorImplementation(value, name); -} - -void propertyTypeCastError(value, property) { - // Cuts the property name to the class name. - String actualType = Primitives.objectTypeName(value); - String expectedType = property.substring(3, property.length); - throw new CastErrorImplementation(actualType, expectedType); -} - -/** - * For types that are not supertypes of native (eg DOM) types, - * we emit a simple property check to check that an object implements - * that type. - */ -propertyTypeCheck(value, property) { - if (value == null) return value; - if (JS('bool', '!!#[#]', value, property)) return value; - propertyTypeError(value, property); -} - -/** - * For types that are not supertypes of native (eg DOM) types, - * we emit a simple property check to check that an object implements - * that type. - */ -propertyTypeCast(value, property) { - if (value == null || JS('bool', '!!#[#]', value, property)) return value; - propertyTypeCastError(value, property); -} - -/** - * For types that are supertypes of native (eg DOM) types, we emit a - * call because we cannot add a JS property to their prototype at load - * time. - */ -callTypeCheck(value, property) { - if (value == null) return value; - if ((identical(JS('String', 'typeof #', value), 'object')) - && JS('bool', '#[#]()', value, property)) { - return value; - } - propertyTypeError(value, property); -} - -/** - * For types that are supertypes of native (eg DOM) types, we emit a - * call because we cannot add a JS property to their prototype at load - * time. - */ -callTypeCast(value, property) { - if (value == null - || ((JS('bool', 'typeof # === "object"', value)) - && JS('bool', '#[#]()', value, property))) { - return value; - } - propertyTypeCastError(value, property); -} - -/** - * Specialization of the type check for num and String and their - * supertype since [value] can be a JS primitive. - */ -numberOrStringSuperTypeCheck(value, property) { - if (value == null) return value; - if (value is String) return value; - if (value is num) return value; - if (JS('bool', '!!#[#]', value, property)) return value; - propertyTypeError(value, property); -} - -numberOrStringSuperTypeCast(value, property) { - if (value is String) return value; - if (value is num) return value; - return propertyTypeCast(value, property); -} - -numberOrStringSuperNativeTypeCheck(value, property) { - if (value == null) return value; - if (value is String) return value; - if (value is num) return value; - if (JS('bool', '#[#]()', value, property)) return value; - propertyTypeError(value, property); -} - -numberOrStringSuperNativeTypeCast(value, property) { - if (value == null) return value; - if (value is String) return value; - if (value is num) return value; - if (JS('bool', '#[#]()', value, property)) return value; - propertyTypeCastError(value, property); -} - -/** - * Specialization of the type check for String and its supertype - * since [value] can be a JS primitive. - */ -stringSuperTypeCheck(value, property) { - if (value == null) return value; - if (value is String) return value; - if (JS('bool', '!!#[#]', value, property)) return value; - propertyTypeError(value, property); -} - -stringSuperTypeCast(value, property) { - if (value is String) return value; - return propertyTypeCast(value, property); -} - -stringSuperNativeTypeCheck(value, property) { - if (value == null) return value; - if (value is String) return value; - if (JS('bool', '#[#]()', value, property)) return value; - propertyTypeError(value, property); -} - -stringSuperNativeTypeCast(value, property) { - if (value is String || value == null) return value; - if (JS('bool', '#[#]()', value, property)) return value; - propertyTypeCastError(value, property); -} - -/** - * Specialization of the type check for List and its supertypes, - * since [value] can be a JS array. - */ -listTypeCheck(value) { - if (value == null) return value; - if (value is List) return value; - throw new TypeErrorImplementation(value, 'List'); -} - -listTypeCast(value) { - if (value is List || value == null) return value; - throw new CastErrorImplementation( - Primitives.objectTypeName(value), 'List'); -} - -listSuperTypeCheck(value, property) { - if (value == null) return value; - if (value is List) return value; - if (JS('bool', '!!#[#]', value, property)) return value; - propertyTypeError(value, property); -} - -listSuperTypeCast(value, property) { - if (value is List) return value; - return propertyTypeCast(value, property); -} - -listSuperNativeTypeCheck(value, property) { - if (value == null) return value; - if (value is List) return value; - if (JS('bool', '#[#]()', value, property)) return value; - propertyTypeError(value, property); -} - -listSuperNativeTypeCast(value, property) { - if (value is List || value == null) return value; - if (JS('bool', '#[#]()', value, property)) return value; - propertyTypeCastError(value, property); -} - -voidTypeCheck(value) { - if (value == null) return value; - throw new TypeErrorImplementation(value, 'void'); -} - -malformedTypeCheck(value, type, reasons) { - if (value == null) return value; - throwMalformedSubtypeError(value, type, reasons); -} - -/** - * Special interface recognized by the compiler and implemented by DOM - * objects that support integer indexing. This interface is not - * visible to anyone, and is only injected into special libraries. - */ -abstract class JavaScriptIndexingBehavior { -} - -// TODO(lrn): These exceptions should be implemented in core. -// When they are, remove the 'Implementation' here. - -/** Thrown by type assertions that fail. */ -class TypeErrorImplementation implements TypeError { - final String message; - - /** - * Normal type error caused by a failed subtype test. - */ - TypeErrorImplementation(Object value, String type) - : message = "type '${Primitives.objectTypeName(value)}' is not a subtype " - "of type '$type'"; - - /** - * Type error caused by a subtype test on a malformed type. - */ - TypeErrorImplementation.malformedSubtype(Object value, - String type, String reasons) - : message = "type '${Primitives.objectTypeName(value)}' is not a subtype " - "of type '$type' because '$type' is malformed: $reasons."; - - String toString() => message; -} - -/** Thrown by the 'as' operator if the cast isn't valid. */ -class CastErrorImplementation implements CastError { - // TODO(lrn): Rename to CastError (and move implementation into core). - // TODO(lrn): Change actualType and expectedType to "Type" when reified - // types are available. - final Object actualType; - final Object expectedType; - - CastErrorImplementation(this.actualType, this.expectedType); - - String toString() { - return "CastError: Casting value of type $actualType to" - " incompatible type $expectedType"; - } -} - -class FallThroughErrorImplementation implements FallThroughError { - const FallThroughErrorImplementation(); - String toString() => "Switch case fall-through."; -} - -/** - * Helper function for implementing asserts. The compiler treats this specially. - */ -void assertHelper(condition) { - if (condition is Function) condition = condition(); - if (condition is !bool) { - throw new TypeErrorImplementation(condition, 'bool'); - } - // Compare to true to avoid boolean conversion check in checked - // mode. - if (!identical(condition, true)) throw new AssertionError(); -} - -/** - * Called by generated code when a method that must be statically - * resolved cannot be found. - */ -void throwNoSuchMethod(obj, name, arguments, expectedArgumentNames) { - throw new NoSuchMethodError(obj, name, arguments, const {}, - expectedArgumentNames); -} - -/** - * Called by generated code when a static field's initializer references the - * field that is currently being initialized. - */ -void throwCyclicInit(String staticName) { - throw new RuntimeError("Cyclic initialization for static $staticName"); -} - -class TypeImpl implements Type { - final String typeName; - TypeImpl(this.typeName); - toString() => typeName; - int get hashCode => typeName.hashCode; - bool operator ==(other) { - if (other is !TypeImpl) return false; - return typeName == other.typeName; - } -} - -String getClassName(var object) { - return JS('String', r'#.constructor.builtin$cls', object); -} - -String getTypeArgumentAsString(List runtimeType) { - String className = getConstructorName(runtimeType[0]); - if (runtimeType.length == 1) return className; - return '$className<${joinArguments(runtimeType, 1)}>'; -} - -String getConstructorName(type) => JS('String', r'#.builtin$cls', type); - -String runtimeTypeToString(type) { - if (type == null) { - return 'dynamic'; - } else if (isJsArray(type)) { - // A list representing a type with arguments. - return getTypeArgumentAsString(type); - } else { - // A reference to the constructor. - return getConstructorName(type); - } -} - -String joinArguments(var types, int startIndex) { - bool firstArgument = true; - StringBuffer buffer = new StringBuffer(); - for (int index = startIndex; index < types.length; index++) { - if (firstArgument) { - firstArgument = false; - } else { - buffer. add(', '); - } - var argument = types[index]; - buffer.add(runtimeTypeToString(argument)); - } - return buffer.toString(); -} - -String getRuntimeTypeString(var object) { - String className = isJsArray(object) ? 'List' : getClassName(object); - var typeInfo = JS('var', r'#.$builtinTypeInfo', object); - if (typeInfo == null) return className; - return "$className<${joinArguments(typeInfo, 0)}>"; -} - -/** - * Check whether the type represented by [s] is a subtype of the type - * represented by [t]. - * - * Type representations can be: - * 1) a JavaScript constructor for a class C: the represented type is the raw - * type C. - * 2) a JavaScript object: this represents a class for which there is no - * JavaScript constructor, because it is only used in type arguments or it - * is native. The represented type is the raw type of this class. - * 3) a JavaScript array: the first entry is of type 1 or 2 and identifies the - * class of the type and the rest of the array are the type arguments. - * 4) [:null:]: the dynamic type. - */ -bool isSubtype(var s, var t) { - // If either type is dynamic, [s] is a subtype of [t]. - if (JS('bool', '# == null', s) || JS('bool', '# == null', t)) return true; - // Subtyping is reflexive. - if (JS('bool', '# === #', s, t)) return true; - // Get the object describing the class and check for the subtyping flag - // constructed from the type of [t]. - var typeOfS = isJsArray(s) ? s[0] : s; - var typeOfT = isJsArray(t) ? t[0] : t; - var test = '${JS_OPERATOR_IS_PREFIX()}${runtimeTypeToString(typeOfT)}'; - if (JS('var', r'#[#]', typeOfS, test) == null) return false; - // The class of [s] is a subclass of the class of [t]. If either of the types - // is raw, [s] is a subtype of [t]. - if (!isJsArray(s) || !isJsArray(t)) return true; - // Recursively check the type arguments. - int len = s.length; - if (len != t.length) return false; - for (int i = 1; i < len; i++) { - if (!isSubtype(s[i], t[i])) { - return false; - } - } - return true; -} - -createRuntimeType(String name) => new TypeImpl(name);
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/lib/js_number.dart b/pkgs/markdown/test/lib/src/compiler/implementation/lib/js_number.dart deleted file mode 100644 index fa5677f..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/lib/js_number.dart +++ /dev/null
@@ -1,272 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of _interceptors; - -/** - * The super interceptor class for [JSInt] and [JSDouble]. The compiler - * recognizes this class as an interceptor, and changes references to - * [:this:] to actually use the receiver of the method, which is - * generated as an extra argument added to each member. - */ -class JSNumber implements num { - const JSNumber(); - - int compareTo(num b) { - if (b is! num) throw new ArgumentError(b); - if (this < b) { - return -1; - } else if (this > b) { - return 1; - } else if (this == b) { - if (this == 0) { - bool bIsNegative = b.isNegative; - if (isNegative == bIsNegative) return 0; - if (isNegative) return -1; - return 1; - } - return 0; - } else if (isNaN) { - if (b.isNaN) { - return 0; - } - return 1; - } else { - return -1; - } - } - - bool get isNegative => (this == 0) ? (1 / this) < 0 : this < 0; - - bool get isNaN => JS('bool', r'isNaN(#)', this); - - num remainder(num b) { - checkNull(b); // TODO(ngeoffray): This is not specified but co19 tests it. - if (b is! num) throw new ArgumentError(b); - return JS('num', r'# % #', this, b); - } - - num abs() => JS('num', r'Math.abs(#)', this); - - int toInt() { - if (isNaN) throw new UnsupportedError('NaN'); - if (isInfinite) throw new UnsupportedError('Infinity'); - num truncated = truncate(); - return JS('bool', r'# == -0.0', truncated) ? 0 : truncated; - } - - num ceil() => JS('num', r'Math.ceil(#)', this); - - num floor() => JS('num', r'Math.floor(#)', this); - - bool get isInfinite { - return JS('bool', r'# == Infinity', this) - || JS('bool', r'# == -Infinity', this); - } - - num round() { - if (this < 0) { - return JS('num', r'-Math.round(-#)', this); - } else { - return JS('num', r'Math.round(#)', this); - } - } - - num clamp(lowerLimit, upperLimit) { - if (lowerLimit is! num) throw new ArgumentError(lowerLimit); - if (upperLimit is! num) throw new ArgumentError(upperLimit); - if (lowerLimit.compareTo(upperLimit) > 0) { - throw new ArgumentError(lowerLimit); - } - if (this.compareTo(lowerLimit) < 0) return lowerLimit; - if (this.compareTo(upperLimit) > 0) return upperLimit; - return this; - } - - double toDouble() => this; - - num truncate() => this < 0 ? ceil() : floor(); - - String toStringAsFixed(int fractionDigits) { - checkNum(fractionDigits); - // TODO(floitsch): fractionDigits must be an integer. - if (fractionDigits < 0 || fractionDigits > 20) { - throw new RangeError(fractionDigits); - } - String result = JS('String', r'#.toFixed(#)', this, fractionDigits); - if (this == 0 && isNegative) return "-$result"; - return result; - } - - String toStringAsExponential([int fractionDigits]) { - String result; - if (fractionDigits != null) { - // TODO(floitsch): fractionDigits must be an integer. - checkNum(fractionDigits); - if (fractionDigits < 0 || fractionDigits > 20) { - throw new RangeError(fractionDigits); - } - result = JS('String', r'#.toExponential(#)', this, fractionDigits); - } else { - result = JS('String', r'#.toExponential()', this); - } - if (this == 0 && isNegative) return "-$result"; - return result; - } - - String toStringAsPrecision(int precision) { - // TODO(floitsch): precision must be an integer. - checkNum(precision); - if (precision < 1 || precision > 21) { - throw new RangeError(precision); - } - String result = JS('String', r'#.toPrecision(#)', - this, precision); - if (this == 0 && isNegative) return "-$result"; - return result; - } - - String toRadixString(int radix) { - checkNum(radix); - if (radix < 2 || radix > 36) throw new RangeError(radix); - return JS('String', r'#.toString(#)', this, radix); - } - - // Note: if you change this, also change the function [S]. - String toString() { - if (this == 0 && JS('bool', '(1 / #) < 0', this)) { - return '-0.0'; - } else { - return JS('String', r'String(#)', this); - } - } - - int get hashCode => JS('int', '# & 0x1FFFFFFF', this); - - num operator -() => JS('num', r'-#', this); - - num operator +(num other) { - if (other is !num) throw new ArgumentError(other); - return JS('num', '# + #', this, other); - } - - num operator -(num other) { - if (other is !num) throw new ArgumentError(other); - return JS('num', '# - #', this, other); - } - - num operator /(num other) { - if (other is !num) throw new ArgumentError(other); - return JS('num', '# / #', this, other); - } - - num operator *(num other) { - if (other is !num) throw new ArgumentError(other); - return JS('num', '# * #', this, other); - } - - num operator %(num other) { - if (other is !num) throw new ArgumentError(other); - // Euclidean Modulo. - num result = JS('num', r'# % #', this, other); - if (result == 0) return 0; // Make sure we don't return -0.0. - if (result > 0) return result; - if (JS('num', '#', other) < 0) { - return result - JS('num', '#', other); - } else { - return result + JS('num', '#', other); - } - } - - num operator ~/(num other) { - if (other is !num) throw new ArgumentError(other); - return (JS('num', r'# / #', this, other)).truncate(); - } - - // TODO(ngeoffray): Move the bit operations below to [JSInt] and - // make them take an int. Because this will make operations slower, - // we define these methods on number for now but we need to decide - // the grain at which we do the type checks. - - num operator <<(num other) { - if (other is !num) throw new ArgumentError(other); - if (JS('num', '#', other) < 0) throw new ArgumentError(other); - // JavaScript only looks at the last 5 bits of the shift-amount. Shifting - // by 33 is hence equivalent to a shift by 1. - if (JS('bool', r'# > 31', other)) return 0; - return JS('num', r'(# << #) >>> 0', this, other); - } - - num operator >>(num other) { - if (other is !num) throw new ArgumentError(other); - if (JS('num', '#', other) < 0) throw new ArgumentError(other); - if (JS('num', '#', this) > 0) { - // JavaScript only looks at the last 5 bits of the shift-amount. In JS - // shifting by 33 is hence equivalent to a shift by 1. Shortcut the - // computation when that happens. - if (JS('bool', r'# > 31', other)) return 0; - // Given that 'a' is positive we must not use '>>'. Otherwise a number - // that has the 31st bit set would be treated as negative and shift in - // ones. - return JS('num', r'# >>> #', this, other); - } - // For negative numbers we just clamp the shift-by amount. 'a' could be - // negative but not have its 31st bit set. The ">>" would then shift in - // 0s instead of 1s. Therefore we cannot simply return 0xFFFFFFFF. - if (JS('num', '#', other) > 31) other = 31; - return JS('num', r'(# >> #) >>> 0', this, other); - } - - num operator &(num other) { - if (other is !num) throw new ArgumentError(other); - return JS('num', r'(# & #) >>> 0', this, other); - } - - num operator |(num other) { - if (other is !num) throw new ArgumentError(other); - return JS('num', r'(# | #) >>> 0', this, other); - } - - num operator ^(num other) { - if (other is !num) throw new ArgumentError(other); - return JS('num', r'(# ^ #) >>> 0', this, other); - } - - bool operator <(num other) { - if (other is !num) throw new ArgumentError(other); - return JS('num', '# < #', this, other); - } - - bool operator >(num other) { - if (other is !num) throw new ArgumentError(other); - return JS('num', '# > #', this, other); - } - - bool operator <=(num other) { - if (other is !num) throw new ArgumentError(other); - return JS('num', '# <= #', this, other); - } - - bool operator >=(num other) { - if (other is !num) throw new ArgumentError(other); - return JS('num', '# >= #', this, other); - } -} - -class JSInt extends JSNumber implements int { - const JSInt(); - - bool get isEven => (this & 1) == 0; - - bool get isOdd => (this & 1) == 1; - - Type get runtimeType => int; - - int operator ~() => JS('int', r'(~#) >>> 0', this); -} - -class JSDouble extends JSNumber implements double { - const JSDouble(); - Type get runtimeType => double; -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/lib/js_string.dart b/pkgs/markdown/test/lib/src/compiler/implementation/lib/js_string.dart deleted file mode 100644 index 381a690..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/lib/js_string.dart +++ /dev/null
@@ -1,229 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of _interceptors; - -/** - * The interceptor class for [String]. The compiler recognizes this - * class as an interceptor, and changes references to [:this:] to - * actually use the receiver of the method, which is generated as an extra - * argument added to each member. - */ -class JSString implements String { - const JSString(); - - int charCodeAt(index) => codeUnitAt(index); - - int codeUnitAt(int index) { - if (index is !num) throw new ArgumentError(index); - if (index < 0) throw new RangeError.value(index); - if (index >= length) throw new RangeError.value(index); - return JS('int', r'#.charCodeAt(#)', this, index); - } - - Iterable<Match> allMatches(String str) { - checkString(str); - return allMatchesInStringUnchecked(this, str); - } - - String concat(String other) { - if (other is !String) throw new ArgumentError(other); - return JS('String', r'# + #', this, other); - } - - bool endsWith(String other) { - checkString(other); - int otherLength = other.length; - if (otherLength > length) return false; - return other == substring(length - otherLength); - } - - String replaceAll(Pattern from, String to) { - checkString(to); - return stringReplaceAllUnchecked(this, from, to); - } - - String replaceAllMapped(Pattern from, String convert(Match match)) { - return this.splitMapJoin(from, onMatch: convert); - } - - String splitMapJoin(Pattern from, - {String onMatch(Match match), - String onNonMatch(String nonMatch)}) { - return stringReplaceAllFuncUnchecked(this, from, onMatch, onNonMatch); - } - - String replaceFirst(Pattern from, String to) { - checkString(to); - return stringReplaceFirstUnchecked(this, from, to); - } - - List<String> split(Pattern pattern) { - checkNull(pattern); - if (pattern is String) { - return JS('=List', r'#.split(#)', this, pattern); - } else if (pattern is JSSyntaxRegExp) { - var re = regExpGetNative(pattern); - return JS('=List', r'#.split(#)', this, re); - } else { - throw "String.split(Pattern) UNIMPLEMENTED"; - } - } - - List<String> splitChars() { - return JS('=List', r'#.split("")', this); - } - - bool startsWith(String other) { - checkString(other); - int otherLength = other.length; - if (otherLength > length) return false; - return JS('bool', r'# == #', other, - JS('String', r'#.substring(0, #)', this, otherLength)); - } - - String substring(int startIndex, [int endIndex]) { - checkNum(startIndex); - if (endIndex == null) endIndex = length; - checkNum(endIndex); - if (startIndex < 0 ) throw new RangeError.value(startIndex); - if (startIndex > endIndex) throw new RangeError.value(startIndex); - if (endIndex > length) throw new RangeError.value(endIndex); - return JS('String', r'#.substring(#, #)', this, startIndex, endIndex); - } - - String slice([int startIndex, int endIndex]) { - int start, end; - if (startIndex == null) { - start = 0; - } else if (startIndex is! int) { - throw new ArgumentError("startIndex is not int"); - } else if (startIndex >= 0) { - start = startIndex; - } else { - start = this.length + startIndex; - } - if (start < 0 || start > this.length) { - throw new RangeError( - "startIndex out of range: $startIndex (length: $length)"); - } - if (endIndex == null) { - end = this.length; - } else if (endIndex is! int) { - throw new ArgumentError("endIndex is not int"); - } else if (endIndex >= 0) { - end = endIndex; - } else { - end = this.length + endIndex; - } - if (end < 0 || end > this.length) { - throw new RangeError( - "endIndex out of range: $endIndex (length: $length)"); - } - if (end < start) { - throw new ArgumentError( - "End before start: $endIndex < $startIndex (length: $length)"); - } - return JS('String', '#.substring(#, #)', this, start, end); - } - - - String toLowerCase() { - return JS('String', r'#.toLowerCase()', this); - } - - String toUpperCase() { - return JS('String', r'#.toUpperCase()', this); - } - - String trim() { - return JS('String', r'#.trim()', this); - } - - List<int> get charCodes { - List<int> result = new List<int>.fixedLength(length); - for (int i = 0; i < length; i++) { - result[i] = JS('int', '#.charCodeAt(#)', this, i); - } - return result; - } - - Iterable<int> get codeUnits { - throw new UnimplementedError("String.codeUnits"); - } - - Iterable<int> get runes { - throw new UnimplementedError("String.runes"); - } - - int indexOf(String other, [int start = 0]) { - checkNull(other); - if (start is !int) throw new ArgumentError(start); - if (other is !String) throw new ArgumentError(other); - if (start < 0) return -1; - return JS('int', r'#.indexOf(#, #)', this, other, start); - } - - int lastIndexOf(String other, [int start]) { - checkNull(other); - if (other is !String) throw new ArgumentError(other); - if (start != null) { - if (start is !num) throw new ArgumentError(start); - if (start < 0) return -1; - if (start >= length) { - if (other == "") return length; - start = length - 1; - } - } else { - start = length - 1; - } - return stringLastIndexOfUnchecked(this, other, start); - } - - bool contains(String other, [int startIndex = 0]) { - checkNull(other); - return stringContainsUnchecked(this, other, startIndex); - } - - bool get isEmpty => length == 0; - - int compareTo(String other) { - if (other is !String) throw new ArgumentError(other); - return this == other ? 0 - : JS('bool', r'# < #', this, other) ? -1 : 1; - } - - // Note: if you change this, also change the function [S]. - String toString() => this; - - /** - * This is the [Jenkins hash function][1] but using masking to keep - * values in SMI range. - * - * [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function - */ - int get hashCode { - // TODO(ahe): This method shouldn't have to use JS. Update when our - // optimizations are smarter. - int hash = 0; - for (int i = 0; i < length; i++) { - hash = 0x1fffffff & (hash + JS('int', r'#.charCodeAt(#)', this, i)); - hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); - hash = JS('int', '# ^ (# >> 6)', hash, hash); - } - hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); - hash = JS('int', '# ^ (# >> 11)', hash, hash); - return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); - } - - Type get runtimeType => String; - - int get length => JS('int', r'#.length', this); - - String operator [](int index) { - if (index is !int) throw new ArgumentError(index); - if (index >= length || index < 0) throw new RangeError.value(index); - return JS('String', '#[#]', this, index); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/lib/math_patch.dart b/pkgs/markdown/test/lib/src/compiler/implementation/lib/math_patch.dart deleted file mode 100644 index 3bccb2c..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/lib/math_patch.dart +++ /dev/null
@@ -1,68 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// Patch file for dart:math library. -import 'dart:_foreign_helper' show JS; - -patch double sqrt(num x) - => JS('double', r'Math.sqrt(#)', checkNum(x)); - -patch double sin(num x) - => JS('double', r'Math.sin(#)', checkNum(x)); - -patch double cos(num x) - => JS('double', r'Math.cos(#)', checkNum(x)); - -patch double tan(num x) - => JS('double', r'Math.tan(#)', checkNum(x)); - -patch double acos(num x) - => JS('double', r'Math.acos(#)', checkNum(x)); - -patch double asin(num x) - => JS('double', r'Math.asin(#)', checkNum(x)); - -patch double atan(num x) - => JS('double', r'Math.atan(#)', checkNum(x)); - -patch double atan2(num a, num b) - => JS('double', r'Math.atan2(#, #)', checkNum(a), checkNum(b)); - -patch double exp(num x) - => JS('double', r'Math.exp(#)', checkNum(x)); - -patch double log(num x) - => JS('double', r'Math.log(#)', checkNum(x)); - -patch num pow(num x, num exponent) { - checkNum(x); - checkNum(exponent); - return JS('num', r'Math.pow(#, #)', x, exponent); -} - -patch class Random { - patch factory Random([int seed]) => const _Random(); -} - -class _Random implements Random { - // The Dart2JS implementation of Random doesn't use a seed. - const _Random(); - - int nextInt(int max) { - if (max < 0) throw new ArgumentError("negative max: $max"); - if (max > 0xFFFFFFFF) max = 0xFFFFFFFF; - return JS("int", "(Math.random() * #) >>> 0", max); - } - - /** - * Generates a positive random floating point value uniformly distributed on - * the range from 0.0, inclusive, to 1.0, exclusive. - */ - double nextDouble() => JS("double", "Math.random()"); - - /** - * Generates a random boolean value. - */ - bool nextBool() => JS("bool", "Math.random() < 0.5"); -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/lib/mirrors_patch.dart b/pkgs/markdown/test/lib/src/compiler/implementation/lib/mirrors_patch.dart deleted file mode 100644 index 1236507..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/lib/mirrors_patch.dart +++ /dev/null
@@ -1,114 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// Patch library for dart:mirrors. - -import 'dart:_foreign_helper' show JS; - -// Yeah, seriously: mirrors in dart2js are experimental... -const String _MIRROR_OPT_IN_MESSAGE = """ - -This program is using an experimental feature called \"mirrors\". As -currently implemented, mirrors do not work with minification, and will -cause spurious errors depending on how code was optimized. - -The authors of this program are aware of these problems and have -decided the thrill of using an experimental feature is outweighing the -risks. Furthermore, the authors of this program understand that -long-term, to fix the problems mentioned above, mirrors may have -negative impact on size and performance of Dart programs compiled to -JavaScript. -"""; - -bool _mirrorsEnabled = false; - -/** - * Stub class for the mirror system. - */ -patch MirrorSystem currentMirrorSystem() { - _ensureEnabled(); - throw new UnsupportedError("MirrorSystem not implemented"); -} - -patch Future<MirrorSystem> mirrorSystemOf(SendPort port) { - _ensureEnabled(); - throw new UnsupportedError("MirrorSystem not implemented"); -} - -patch InstanceMirror reflect(Object reflectee) { - if (!_mirrorsEnabled && (_MIRROR_OPT_IN_MESSAGE == reflectee)) { - // Turn on mirrors and warn that it is an experimental feature. - _mirrorsEnabled = true; - print(reflectee); - } - _ensureEnabled(); - return new _InstanceMirror(reflectee); -} - -class _InstanceMirror extends InstanceMirror { - static final Expando<ClassMirror> classMirrors = new Expando<ClassMirror>(); - - final reflectee; - - _InstanceMirror(this.reflectee) { - _ensureEnabled(); - } - - bool get hasReflectee => true; - - ClassMirror get type { - String className = Primitives.objectTypeName(reflectee); - var constructor = Primitives.getConstructor(className); - var mirror = classMirrors[constructor]; - if (mirror == null) { - mirror = new _ClassMirror(className, constructor); - classMirrors[constructor] = mirror; - } - return mirror; - } - - Future<InstanceMirror> invoke(String memberName, - List<Object> positionalArguments, - [Map<String,Object> namedArguments]) { - if (namedArguments != null && !namedArguments.isEmpty) { - throw new UnsupportedError('Named arguments are not implemented'); - } - // Copy the list to ensure that it can safely be passed to - // JavaScript. - var jsList = new List.from(positionalArguments); - var mangledName = '${memberName}\$${positionalArguments.length}'; - var method = JS('var', '#[#]', reflectee, mangledName); - var completer = new Completer<InstanceMirror>(); - // TODO(ahe): [Completer] or [Future] should have API to create a - // delayed action. Simulating with a [Timer]. - new Timer(0, (timer) { - if (JS('String', 'typeof #', method) == 'function') { - var result = - JS('var', '#.apply(#, #)', method, reflectee, jsList); - completer.complete(new _InstanceMirror(result)); - } else { - completer.completeError('not a method $memberName'); - } - }); - return completer.future; - } - - String toString() => 'InstanceMirror($reflectee)'; -} - -class _ClassMirror extends ClassMirror { - final String _name; - final _jsConstructor; - - _ClassMirror(this._name, this._jsConstructor) { - _ensureEnabled(); - } - - String toString() => 'ClassMirror($_name)'; -} - -_ensureEnabled() { - if (_mirrorsEnabled) return; - throw new UnsupportedError('dart:mirrors is an experimental feature'); -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/lib/native_helper.dart b/pkgs/markdown/test/lib/src/compiler/implementation/lib/native_helper.dart deleted file mode 100644 index c75e554..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/lib/native_helper.dart +++ /dev/null
@@ -1,431 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of _js_helper; - -String typeNameInChrome(obj) { - String name = JS('String', "#.constructor.name", obj); - return typeNameInWebKitCommon(name); -} - -String typeNameInSafari(obj) { - String name = JS('String', '#', constructorNameFallback(obj)); - // Safari is very similar to Chrome. - return typeNameInWebKitCommon(name); -} - -String typeNameInWebKitCommon(tag) { - String name = JS('String', '#', tag); - if (name == 'Window') return 'DOMWindow'; - if (name == 'CanvasPixelArray') return 'Uint8ClampedArray'; - if (name == 'WebKitMutationObserver') return 'MutationObserver'; - if (name == 'AudioChannelMerger') return 'ChannelMergerNode'; - if (name == 'AudioChannelSplitter') return 'ChannelSplitterNode'; - if (name == 'AudioGainNode') return 'GainNode'; - if (name == 'AudioPannerNode') return 'PannerNode'; - if (name == 'JavaScriptAudioNode') return 'ScriptProcessorNode'; - if (name == 'Oscillator') return 'OscillatorNode'; - if (name == 'RealtimeAnalyserNode') return 'AnalyserNode'; - if (name == 'IDBVersionChangeRequest') return 'IDBOpenDBRequest'; - return name; -} - -String typeNameInOpera(obj) { - String name = JS('String', '#', constructorNameFallback(obj)); - if (name == 'Window') return 'DOMWindow'; - if (name == 'ApplicationCache') return 'DOMApplicationCache'; - return name; -} - -String typeNameInFirefox(obj) { - String name = JS('String', '#', constructorNameFallback(obj)); - if (name == 'Window') return 'DOMWindow'; - if (name == 'CSS2Properties') return 'CSSStyleDeclaration'; - if (name == 'DataTransfer') return 'Clipboard'; - if (name == 'DragEvent') return 'MouseEvent'; - if (name == 'GeoGeolocation') return 'Geolocation'; - if (name == 'MouseScrollEvent') return 'WheelEvent'; - if (name == 'OfflineResourceList') return 'DOMApplicationCache'; - if (name == 'WorkerMessageEvent') return 'MessageEvent'; - if (name == 'XMLDocument') return 'Document'; - return name; -} - -String typeNameInIE(obj) { - String name = JS('String', '#', constructorNameFallback(obj)); - if (name == 'Window') return 'DOMWindow'; - if (name == 'Document') { - // IE calls both HTML and XML documents 'Document', so we check for the - // xmlVersion property, which is the empty string on HTML documents. - if (JS('bool', '!!#.xmlVersion', obj)) return 'Document'; - return 'HTMLDocument'; - } - if (name == 'ApplicationCache') return 'DOMApplicationCache'; - if (name == 'CanvasPixelArray') return 'Uint8ClampedArray'; - if (name == 'DataTransfer') return 'Clipboard'; - if (name == 'DragEvent') return 'MouseEvent'; - if (name == 'HTMLDDElement') return 'HTMLElement'; - if (name == 'HTMLDTElement') return 'HTMLElement'; - if (name == 'HTMLTableDataCellElement') return 'HTMLTableCellElement'; - if (name == 'HTMLTableHeaderCellElement') return 'HTMLTableCellElement'; - if (name == 'HTMLPhraseElement') return 'HTMLElement'; - if (name == 'MSStyleCSSProperties') return 'CSSStyleDeclaration'; - if (name == 'MouseWheelEvent') return 'WheelEvent'; - if (name == 'Position') return 'Geoposition'; - - // Patches for types which report themselves as Objects. - if (name == 'Object') { - if (JS('bool', 'window.DataView && (# instanceof window.DataView)', obj)) { - return 'DataView'; - } - } - return name; -} - -String constructorNameFallback(object) { - if (object == null) return 'Null'; - var constructor = JS('var', "#.constructor", object); - if (identical(JS('String', "typeof(#)", constructor), 'function')) { - // The constructor isn't null or undefined at this point. Try - // to grab hold of its name. - var name = JS('var', '#.name', constructor); - // If the name is a non-empty string, we use that as the type - // name of this object. On Firefox, we often get 'Object' as - // the constructor name even for more specialized objects so - // we have to fall through to the toString() based implementation - // below in that case. - if (name is String - && !identical(name, '') - && !identical(name, 'Object') - && !identical(name, 'Function.prototype')) { // Can happen in Opera. - return name; - } - } - String string = JS('String', 'Object.prototype.toString.call(#)', object); - return JS('String', '#.substring(8, # - 1)', string, string.length); -} - -/** - * If a lookup on an object [object] that has [tag] fails, this function is - * called to provide an alternate tag. This allows us to fail gracefully if we - * can make a good guess, for example, when browsers add novel kinds of - * HTMLElement that we have never heard of. - */ -String alternateTag(object, String tag) { - // Does it smell like some kind of HTML element? - if (JS('bool', r'!!/^HTML[A-Z].*Element$/.test(#)', tag)) { - // Check that it is not a simple JavaScript object. - String string = JS('String', 'Object.prototype.toString.call(#)', object); - if (string == '[object Object]') return null; - return 'HTMLElement'; - } - return null; -} - -// TODO(ngeoffray): stop using this method once our optimizers can -// change str1.contains(str2) into str1.indexOf(str2) != -1. -bool contains(String userAgent, String name) { - return JS('int', '#.indexOf(#)', userAgent, name) != -1; -} - -int arrayLength(List array) { - return JS('int', '#.length', array); -} - -arrayGet(List array, int index) { - return JS('var', '#[#]', array, index); -} - -void arraySet(List array, int index, var value) { - JS('var', '#[#] = #', array, index, value); -} - -propertyGet(var object, String property) { - return JS('var', '#[#]', object, property); -} - -bool callHasOwnProperty(var function, var object, String property) { - return JS('bool', '#.call(#, #)', function, object, property); -} - -void propertySet(var object, String property, var value) { - JS('var', '#[#] = #', object, property, value); -} - -getPropertyFromPrototype(var object, String name) { - return JS('var', 'Object.getPrototypeOf(#)[#]', object, name); -} - -newJsObject() { - return JS('var', '{}'); -} - -/** - * Returns the function to use to get the type name of an object. - */ -Function getFunctionForTypeNameOf() { - // If we're not in the browser, we're almost certainly running on v8. - if (!identical(JS('String', 'typeof(navigator)'), 'object')) return typeNameInChrome; - - String userAgent = JS('String', "navigator.userAgent"); - if (contains(userAgent, 'Chrome') || contains(userAgent, 'DumpRenderTree')) { - return typeNameInChrome; - } else if (contains(userAgent, 'Firefox')) { - return typeNameInFirefox; - } else if (contains(userAgent, 'MSIE')) { - return typeNameInIE; - } else if (contains(userAgent, 'Opera')) { - return typeNameInOpera; - } else if (contains(userAgent, 'AppleWebKit')) { - // Chrome matches 'AppleWebKit' too, but we test for Chrome first, so this - // is not a problem. - // Note: Just testing for "Safari" doesn't work when the page is embedded - // in a UIWebView on iOS 6. - return typeNameInSafari; - } else { - return constructorNameFallback; - } -} - - -/** - * Cached value for the function to use to get the type name of an - * object. - */ -Function _getTypeNameOf; - -/** - * Returns the type name of [obj]. - */ -String getTypeNameOf(var obj) { - if (_getTypeNameOf == null) _getTypeNameOf = getFunctionForTypeNameOf(); - return _getTypeNameOf(obj); -} - -String toStringForNativeObject(var obj) { - String name = JS('String', '#', getTypeNameOf(obj)); - return 'Instance of $name'; -} - -int hashCodeForNativeObject(object) => Primitives.objectHashCode(object); - -/** - * Sets a JavaScript property on an object. - */ -void defineProperty(var obj, String property, var value) { - JS('void', - 'Object.defineProperty(#, #, ' - '{value: #, enumerable: false, writable: true, configurable: true})', - obj, - property, - value); -} - -/** - * This method looks up the type name of [obj] in [methods]. [methods] - * is a Javascript object. If it cannot find it, it looks into the - * [_dynamicMetadata] array. If the method can still not be found, it - * creates a method that will throw a [NoSuchMethodError]. - * - * Once it has a method, the prototype of [obj] is patched with that - * method, on the property [name]. The method is then invoked. - * - * This method returns the result of invoking the found method. - */ -dynamicBind(var obj, - String name, - var methods, - List arguments) { - // The tag is related to the class name. E.g. the dart:html class - // '_ButtonElement' has the tag 'HTMLButtonElement'. TODO(erikcorry): rename - // getTypeNameOf to getTypeTag. - String tag = getTypeNameOf(obj); - var hasOwnPropertyFunction = JS('var', 'Object.prototype.hasOwnProperty'); - - var method = dynamicBindLookup(hasOwnPropertyFunction, tag, methods); - if (method == null) { - String secondTag = alternateTag(obj, tag); - if (secondTag != null) { - method = dynamicBindLookup(hasOwnPropertyFunction, secondTag, methods); - } - } - - // If we didn't find the method then look up in the Dart Object class, using - // getTypeNameOf in case the minifier has renamed Object. - if (method == null) { - String nameOfObjectClass = getTypeNameOf(const Object()); - method = - lookupDynamicClass(hasOwnPropertyFunction, methods, nameOfObjectClass); - } - - var proto = JS('var', 'Object.getPrototypeOf(#)', obj); - if (method == null) { - // If the method cannot be found, we use a trampoline method that - // will throw a [NoSuchMethodError] if the object is of the - // exact prototype, or will call [dynamicBind] again if the object - // is a subclass. - method = JS('var', - 'function () {' - 'if (Object.getPrototypeOf(this) === #) {' - 'throw new TypeError(# + " is not a function");' - '} else {' - 'return Object.prototype[#].apply(this, arguments);' - '}' - '}', - proto, name, name); - } - - if (!callHasOwnProperty(hasOwnPropertyFunction, proto, name)) { - defineProperty(proto, name, method); - } - - return JS('var', '#.apply(#, #)', method, obj, arguments); -} - -dynamicBindLookup(var hasOwnPropertyFunction, String tag, var methods) { - var method = lookupDynamicClass(hasOwnPropertyFunction, methods, tag); - // Look at the inheritance data, getting the class tags and using them - // to check the methods table for this method name. - if (method == null && _dynamicMetadata != null) { - for (int i = 0; i < arrayLength(_dynamicMetadata); i++) { - MetaInfo entry = arrayGet(_dynamicMetadata, i); - if (callHasOwnProperty(hasOwnPropertyFunction, entry._set, tag)) { - method = - lookupDynamicClass(hasOwnPropertyFunction, methods, entry._tag); - // Stop if we found it in the methods array. - if (method != null) break; - } - } - } - return method; -} - -// For each method name and class inheritance subtree, we use an ordinary JS -// object as a hash map to store the method for each class. Entries are added -// in native_emitter.dart (see dynamicName). In order to avoid the class names -// clashing with the method names on Object.prototype (needed for native -// objects) we must always use hasOwnProperty. -var lookupDynamicClass(var hasOwnPropertyFunction, - var methods, - String className) { - return callHasOwnProperty(hasOwnPropertyFunction, methods, className) ? - propertyGet(methods, className) : - null; -} - -/** - * Code for doing the dynamic dispatch on JavaScript prototypes that are not - * available at compile-time. Each property of a native Dart class - * is registered through this function, which is called with the - * following pattern: - * - * dynamicFunction('propertyName').prototypeName = // JS code - * - * What this function does is: - * - Creates a map of { prototypeName: JS code }. - * - Attaches 'propertyName' to the JS Object prototype that will - * intercept at runtime all calls to propertyName. - * - Sets the value of 'propertyName' to the returned method from - * [dynamicBind]. - * - */ -dynamicFunction(name) { - var f = JS('var', 'Object.prototype[#]', name); - if (f != null && JS('bool', '!!#.methods', f)) { - return JS('var', '#.methods', f); - } - - // TODO(ngeoffray): We could make this a map if the code we - // generate plays well with a Dart map. - var methods = JS('var', '{}'); - // If there is a method attached to the Dart Object class, use it as - // the method to call in case no method is registered for that type. - var dartMethod = getPropertyFromPrototype(const Object(), name); - // Take the method from the Dart Object class if we didn't find it yet and it - // is there. - if (dartMethod != null) propertySet(methods, 'Object', dartMethod); - - var bind = JS('var', - 'function() {' - 'return #(this, #, #, Array.prototype.slice.call(arguments));' - '}', - DART_CLOSURE_TO_JS(dynamicBind), name, methods); - - JS('void', '#.methods = #', bind, methods); - defineProperty(JS('var', 'Object.prototype'), name, bind); - return methods; -} - -/** - * This class encodes the class hierarchy when we need it for dynamic - * dispatch. - */ -class MetaInfo { - /** - * The type name this [MetaInfo] relates to. - */ - String _tag; - - /** - * A string containing the names of subtypes of [tag], separated by - * '|'. - */ - String _tags; - - /** - * A list of names of subtypes of [tag]. - */ - Object _set; - - MetaInfo(this._tag, this._tags, this._set); -} - -List<MetaInfo> get _dynamicMetadata { - // Because [dynamicMetadata] has to be shared with multiple isolates - // that access native classes (eg multiple DOM isolates), - // [_dynamicMetadata] cannot be a field, otherwise all non-main - // isolates would not have any value for it. - if (identical(JS('var', 'typeof(\$dynamicMetadata)'), 'undefined')) { - _dynamicMetadata = <MetaInfo>[]; - } - return JS('var', '\$dynamicMetadata'); -} - -void set _dynamicMetadata(List<MetaInfo> table) { - JS('void', '\$dynamicMetadata = #', table); -} - -/** - * Builds the metadata used for encoding the class hierarchy of native - * classes. The following example: - * - * class A native "*A" {} - * class B extends A native "*B" {} - * - * Will generate: - * ['A', 'A|B'] - * - * This method returns a list of [MetaInfo] objects. - */ -List <MetaInfo> buildDynamicMetadata(List<List<String>> inputTable) { - List<MetaInfo> result = <MetaInfo>[]; - for (int i = 0; i < arrayLength(inputTable); i++) { - String tag = JS('String', '#', arrayGet(arrayGet(inputTable, i), 0)); - String tags = JS('String', '#', arrayGet(arrayGet(inputTable, i), 1)); - var set = newJsObject(); - List<String> tagNames = tags.split('|'); - for (int j = 0; j < arrayLength(tagNames); j++) { - propertySet(set, arrayGet(tagNames, j), true); - } - result.add(new MetaInfo(tag, tags, set)); - } - return result; -} - -/** - * Called by the compiler to setup [_dynamicMetadata]. - */ -void dynamicSetMetadata(List<List<String>> inputTable) { - _dynamicMetadata = buildDynamicMetadata(inputTable); -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/lib/regexp_helper.dart b/pkgs/markdown/test/lib/src/compiler/implementation/lib/regexp_helper.dart deleted file mode 100644 index b62b0b5..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/lib/regexp_helper.dart +++ /dev/null
@@ -1,151 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of _js_helper; - -List regExpExec(JSSyntaxRegExp regExp, String str) { - var nativeRegExp = regExpGetNative(regExp); - var result = JS('=List', r'#.exec(#)', nativeRegExp, str); - if (JS('bool', r'# == null', result)) return null; - return result; -} - -bool regExpTest(JSSyntaxRegExp regExp, String str) { - var nativeRegExp = regExpGetNative(regExp); - return JS('bool', r'#.test(#)', nativeRegExp, str); -} - -regExpGetNative(JSSyntaxRegExp regExp) { - var r = JS('var', r'#._re', regExp); - if (r == null) { - r = JS('var', r'#._re = #', regExp, regExpMakeNative(regExp)); - } - return r; -} - -regExpAttachGlobalNative(JSSyntaxRegExp regExp) { - JS('void', r'#._re = #', regExp, regExpMakeNative(regExp, global: true)); -} - -regExpMakeNative(JSSyntaxRegExp regExp, {bool global: false}) { - String pattern = regExp.pattern; - bool isMultiLine = regExp.isMultiLine; - bool isCaseSensitive = regExp.isCaseSensitive; - checkString(pattern); - StringBuffer sb = new StringBuffer(); - if (isMultiLine) sb.add('m'); - if (!isCaseSensitive) sb.add('i'); - if (global) sb.add('g'); - try { - return JS('var', r'new RegExp(#, #)', pattern, sb.toString()); - } catch (e) { - throw new IllegalJSRegExpException(pattern, - JS('String', r'String(#)', e)); - } -} - -int regExpMatchStart(m) => JS('int', r'#.index', m); - -class JSSyntaxRegExp implements RegExp { - final String _pattern; - final bool _isMultiLine; - final bool _isCaseSensitive; - - const JSSyntaxRegExp(String pattern, - {bool multiLine: false, - bool caseSensitive: true}) - : _pattern = pattern, - _isMultiLine = multiLine, - _isCaseSensitive = caseSensitive; - - Match firstMatch(String str) { - List<String> m = regExpExec(this, checkString(str)); - if (m == null) return null; - var matchStart = regExpMatchStart(m); - // m.lastIndex only works with flag 'g'. - var matchEnd = matchStart + m[0].length; - return new _MatchImplementation(pattern, str, matchStart, matchEnd, m); - } - - bool hasMatch(String str) => regExpTest(this, checkString(str)); - - String stringMatch(String str) { - var match = firstMatch(str); - return match == null ? null : match.group(0); - } - - Iterable<Match> allMatches(String str) { - checkString(str); - return new _AllMatchesIterable(this, str); - } - - String get pattern => _pattern; - bool get isMultiLine => _isMultiLine; - bool get isCaseSensitive => _isCaseSensitive; - - static JSSyntaxRegExp _globalVersionOf(JSSyntaxRegExp other) { - JSSyntaxRegExp re = - new JSSyntaxRegExp(other.pattern, - multiLine: other.isMultiLine, - caseSensitive: other.isCaseSensitive); - regExpAttachGlobalNative(re); - return re; - } - - _getNative() => regExpGetNative(this); -} - -class _MatchImplementation implements Match { - final String pattern; - final String str; - final int start; - final int end; - final List<String> _groups; - - const _MatchImplementation( - String this.pattern, - String this.str, - int this.start, - int this.end, - List<String> this._groups); - - String group(int index) => _groups[index]; - String operator [](int index) => group(index); - int get groupCount => _groups.length - 1; - - List<String> groups(List<int> groups) { - List<String> out = []; - for (int i in groups) { - out.add(group(i)); - } - return out; - } -} - -class _AllMatchesIterable extends Iterable<Match> { - final JSSyntaxRegExp _re; - final String _str; - - const _AllMatchesIterable(this._re, this._str); - - Iterator<Match> get iterator => new _AllMatchesIterator(_re, _str); -} - -class _AllMatchesIterator implements Iterator<Match> { - final RegExp _re; - final String _str; - Match _current; - - _AllMatchesIterator(JSSyntaxRegExp re, String this._str) - : _re = JSSyntaxRegExp._globalVersionOf(re); - - Match get current => _current; - - bool moveNext() { - // firstMatch actually acts as nextMatch because of - // hidden global flag. - _current = _re.firstMatch(_str); - return _current != null; - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/lib/scalarlist_patch.dart b/pkgs/markdown/test/lib/src/compiler/implementation/lib/scalarlist_patch.dart deleted file mode 100644 index 326b892..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/lib/scalarlist_patch.dart +++ /dev/null
@@ -1,130 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// This is an empty dummy patch file for the VM dart:scalarlist library. -// This is needed in order to be able to generate documentation for the -// scalarlist library. - -patch class Int8List { - patch factory Int8List(int length) { - throw new UnsupportedError('Int8List'); - } - - patch factory Int8List.view(ByteArray array, [int start = 0, int length]) { - throw new UnsupportedError('Int8List.view'); - } -} - - -patch class Uint8List { - patch factory Uint8List(int length) { - throw new UnsupportedError('Uint8List'); - } - - patch factory Uint8List.view(ByteArray array, - [int start = 0, int length]) { - throw new UnsupportedError('Uint8List.view'); - } -} - - -patch class Uint8ClampedList { - patch factory Uint8ClampedList(int length) { - throw new UnsupportedError('Uint8ClampedList'); - } - - patch factory Uint8ClampedList.view(ByteArray array, - [int start = 0, int length]) { - throw new UnsupportedError('Uint8ClampedList.view'); - } -} - - -patch class Int16List { - patch factory Int16List(int length) { - throw new UnsupportedError('Int16List'); - - } - - patch factory Int16List.view(ByteArray array, [int start = 0, int length]) { - throw new UnsupportedError('Int16List.view'); - } -} - - -patch class Uint16List { - patch factory Uint16List(int length) { - throw new UnsupportedError('Uint16List'); - } - - patch factory Uint16List.view(ByteArray array, [int start = 0, int length]) { - throw new UnsupportedError('Uint16List.view'); - } -} - - -patch class Int32List { - patch factory Int32List(int length) { - throw new UnsupportedError('Int32List'); - } - - patch factory Int32List.view(ByteArray array, [int start = 0, int length]) { - throw new UnsupportedError('Int32List.view'); - } -} - - -patch class Uint32List { - patch factory Uint32List(int length) { - throw new UnsupportedError('Uint32List'); - } - - patch factory Uint32List.view(ByteArray array, [int start = 0, int length]) { - throw new UnsupportedError('Uint32List.view'); - } -} - - -patch class Int64List { - patch factory Int64List(int length) { - throw new UnsupportedError('Int64List'); - } - - patch factory Int64List.view(ByteArray array, [int start = 0, int length]) { - throw new UnsupportedError('Int64List.view'); - } -} - - -patch class Uint64List { - patch factory Uint64List(int length) { - throw new UnsupportedError('Uint64List'); - } - - patch factory Uint64List.view(ByteArray array, [int start = 0, int length]) { - throw new UnsupportedError('Uint64List.view'); - } -} - - -patch class Float32List { - patch factory Float32List(int length) { - throw new UnsupportedError('Float32List'); - } - - patch factory Float32List.view(ByteArray array, [int start = 0, int length]) { - throw new UnsupportedError('Float32List.view'); - } -} - - -patch class Float64List { - patch factory Float64List(int length) { - throw new UnsupportedError('Float64List'); - } - - patch factory Float64List.view(ByteArray array, [int start = 0, int length]) { - throw new UnsupportedError('Float64List.view'); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/lib/string_helper.dart b/pkgs/markdown/test/lib/src/compiler/implementation/lib/string_helper.dart deleted file mode 100644 index 8ac1fa4..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/lib/string_helper.dart +++ /dev/null
@@ -1,234 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of _js_helper; - -class StringMatch implements Match { - const StringMatch(int this.start, - String this.str, - String this.pattern); - - int get end => start + pattern.length; - String operator[](int g) => group(g); - int get groupCount => 0; - - String group(int group_) { - if (group_ != 0) { - throw new RangeError.value(group_); - } - return pattern; - } - - List<String> groups(List<int> groups_) { - List<String> result = new List<String>(); - for (int g in groups_) { - result.add(group(g)); - } - return result; - } - - final int start; - final String str; - final String pattern; -} - -List<Match> allMatchesInStringUnchecked(String needle, String haystack) { - // Copied from StringBase.allMatches in - // /runtime/lib/string_base.dart - List<Match> result = new List<Match>(); - int length = haystack.length; - int patternLength = needle.length; - int startIndex = 0; - while (true) { - int position = haystack.indexOf(needle, startIndex); - if (position == -1) { - break; - } - result.add(new StringMatch(position, haystack, needle)); - int endIndex = position + patternLength; - if (endIndex == length) { - break; - } else if (position == endIndex) { - ++startIndex; // empty match, advance and restart - } else { - startIndex = endIndex; - } - } - return result; -} - -stringContainsUnchecked(receiver, other, startIndex) { - if (other is String) { - return receiver.indexOf(other, startIndex) != -1; - } else if (other is JSSyntaxRegExp) { - return other.hasMatch(receiver.substring(startIndex)); - } else { - var substr = receiver.substring(startIndex); - return other.allMatches(substr).iterator.moveNext(); - } -} - -stringReplaceJS(receiver, replacer, to) { - // The JavaScript String.replace method recognizes replacement - // patterns in the replacement string. Dart does not have that - // behavior. - to = JS('String', r"#.replace('$', '$$$$')", to); - return JS('String', r'#.replace(#, #)', receiver, replacer, to); -} - -final RegExp quoteRegExp = new JSSyntaxRegExp(r'[-[\]{}()*+?.,\\^$|#\s]'); - -stringReplaceAllUnchecked(receiver, from, to) { - checkString(to); - if (from is String) { - if (from == "") { - if (receiver == "") { - return to; - } else { - StringBuffer result = new StringBuffer(); - int length = receiver.length; - result.add(to); - for (int i = 0; i < length; i++) { - result.add(receiver[i]); - result.add(to); - } - return result.toString(); - } - } else { - var quoter = regExpMakeNative(quoteRegExp, global: true); - var quoted = JS('String', r'#.replace(#, "\\$&")', from, quoter); - RegExp replaceRegExp = new JSSyntaxRegExp(quoted); - var replacer = regExpMakeNative(replaceRegExp, global: true); - return stringReplaceJS(receiver, replacer, to); - } - } else if (from is JSSyntaxRegExp) { - var re = regExpMakeNative(from, global: true); - return stringReplaceJS(receiver, re, to); - } else { - checkNull(from); - // TODO(floitsch): implement generic String.replace (with patterns). - throw "String.replaceAll(Pattern) UNIMPLEMENTED"; - } -} - -String _matchString(Match match) => match[0]; -String _stringIdentity(String string) => string; - -stringReplaceAllFuncUnchecked(receiver, pattern, onMatch, onNonMatch) { - if (pattern is! Pattern) { - throw new ArgumentError("${pattern} is not a Pattern"); - } - if (onMatch == null) onMatch = _matchString; - if (onNonMatch == null) onNonMatch = _stringIdentity; - if (pattern is String) { - return stringReplaceAllStringFuncUnchecked(receiver, pattern, - onMatch, onNonMatch); - } - StringBuffer buffer = new StringBuffer(); - int startIndex = 0; - for (Match match in pattern.allMatches(receiver)) { - buffer.add(onNonMatch(receiver.substring(startIndex, match.start))); - buffer.add(onMatch(match)); - startIndex = match.end; - } - buffer.add(onNonMatch(receiver.substring(startIndex))); - return buffer.toString(); -} - -stringReplaceAllEmptyFuncUnchecked(receiver, onMatch, onNonMatch) { - // Pattern is the empty string. - StringBuffer buffer = new StringBuffer(); - int length = receiver.length; - int i = 0; - buffer.add(onNonMatch("")); - while (i < length) { - buffer.add(onMatch(new StringMatch(i, receiver, ""))); - // Special case to avoid splitting a surrogate pair. - int code = receiver.charCodeAt(i); - if ((code & ~0x3FF) == 0xD800 && length > i + 1) { - // Leading surrogate; - code = receiver.charCodeAt(i + 1); - if ((code & ~0x3FF) == 0xDC00) { - // Matching trailing surrogate. - buffer.add(onNonMatch(receiver.substring(i, i + 2))); - i += 2; - continue; - } - } - buffer.add(onNonMatch(receiver[i])); - i++; - } - buffer.add(onMatch(new StringMatch(i, receiver, ""))); - buffer.add(onNonMatch("")); - return buffer.toString(); -} - -stringReplaceAllStringFuncUnchecked(receiver, pattern, onMatch, onNonMatch) { - int patternLength = pattern.length; - if (patternLength == 0) { - return stringReplaceAllEmptyFuncUnchecked(receiver, onMatch, onNonMatch); - } - int length = receiver.length; - StringBuffer buffer = new StringBuffer(); - int startIndex = 0; - while (startIndex < length) { - int position = receiver.indexOf(pattern, startIndex); - if (position == -1) { - break; - } - buffer.add(onNonMatch(receiver.substring(startIndex, position))); - buffer.add(onMatch(new StringMatch(position, receiver, pattern))); - startIndex = position + patternLength; - } - buffer.add(onNonMatch(receiver.substring(startIndex))); - return buffer.toString(); -} - - -stringReplaceFirstUnchecked(receiver, from, to) { - if (from is String) { - return stringReplaceJS(receiver, from, to); - } else if (from is JSSyntaxRegExp) { - var re = regExpGetNative(from); - return stringReplaceJS(receiver, re, to); - } else { - checkNull(from); - // TODO(floitsch): implement generic String.replace (with patterns). - throw "String.replace(Pattern) UNIMPLEMENTED"; - } -} - -stringJoinUnchecked(array, separator) { - return JS('String', r'#.join(#)', array, separator); -} - -class JsStringBuffer implements StringBuffer { - String _contents; - - JsStringBuffer(content) - : _contents = (content is String) ? content : '$content'; - - int get length => _contents.length; - - bool get isEmpty => length == 0; - - void add(Object obj) { - _contents = JS('String', '# + #', _contents, - (obj is String) ? obj : '$obj'); - } - - void addAll(Iterable objects) { - for (Object obj in objects) add(obj); - } - - void addCharCode(int charCode) { - add(new String.fromCharCodes([charCode])); - } - - void clear() { - _contents = ""; - } - - String toString() => _contents; -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/library_loader.dart b/pkgs/markdown/test/lib/src/compiler/implementation/library_loader.dart deleted file mode 100644 index 074cece..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/library_loader.dart +++ /dev/null
@@ -1,837 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of dart2js; - -/** - * [CompilerTask] for loading libraries and setting up the import/export scopes. - * - * The library loader uses four different kinds of URIs in different parts of - * the loading process. - * - * ## User URI ## - * - * A 'user URI' is a URI provided by the user in code and as the main entry URI - * at the command line. These generally come in 3 versions: - * - * * A relative URI such as 'foo.dart', '../bar.dart', and 'baz/boz.dart'. - * - * * A dart URI such as 'dart:core' and 'dart:_js_helper'. - * - * * A package URI such as 'package:foo.dart' and 'package:bar/baz.dart'. - * - * A user URI can also be absolute, like 'file:///foo.dart' or - * 'http://example.com/bar.dart', but such URIs cannot necessarily be used for - * locating source files, since the scheme must be supported by the input - * provider. The standard input provider for dart2js only supports the 'file' - * scheme. - * - * ## Resolved URI ## - * - * A 'resolved URI' is a (user) URI that has been resolved to an absolute URI - * based on the readable URI (see below) from which it was loaded. A URI with an - * explicit scheme (such as 'dart:', 'package:' or 'file:') is already resolved. - * A relative URI like for instance '../foo/bar.dart' is translated into an - * resolved URI in one of three ways: - * - * * If provided as the main entry URI at the command line, the URI is resolved - * relative to the current working directory, say - * 'file:///current/working/dir/', and the resolved URI is therefore - * 'file:///current/working/foo/bar.dart'. - * - * * If the relative URI is provided in an import, export or part tag, and the - * readable URI of the enclosing compilation unit is a file URI, - * 'file://some/path/baz.dart', then the resolved URI is - * 'file://some/foo/bar.dart'. - * - * * If the relative URI is provided in an import, export or part tag, and the - * readable URI of the enclosing compilation unit is a package URI, - * 'package:some/path/baz.dart', then the resolved URI is - * 'package:some/foo/bar.dart'. - * - * The resolved URI thus preserves the scheme through resolution: A readable - * file URI results in an resolved file URI and a readable package URI results - * in an resolved package URI. Note that since a dart URI is not a readable URI, - * import, export or part tags within platform libraries are not interpreted as - * dart URIs but instead relative to the library source file location. - * - * The resolved URI of a library is also used as the canonical URI - * ([LibraryElement.canonicalUri]) by which we identify which libraries are - * identical. This means that libraries loaded through the 'package' scheme will - * resolve to the same library when loaded from within using relative URIs (see - * for instance the test 'standalone/package/package1_test.dart'). But loading a - * platform library using a relative URI will _not_ result in the same library - * as when loaded through the dart URI. - * - * ## Readable URI ## - * - * A 'readable URI' is an absolute URI whose scheme is either 'package' or - * something supported by the input provider, normally 'file'. Dart URIs such as - * 'dart:core' and 'dart:_js_helper' are not readable themselves but are instead - * resolved into a readable URI using the library root URI provided from the - * command line and the list of platform libraries found in - * 'sdk/lib/_internal/libraries.dart'. This is done through the - * [Compiler.translateResolvedUri] method which checks whether a library by that - * name exists and in case of internal libraries whether access is granted. - * - * ## Resource URI ## - * - * A 'resource URI' is an absolute URI with a scheme supported by the input - * provider. For the standard implementation this means a URI with the 'file' - * scheme. Readable URIs are converted into resource URIs as part of the - * [Compiler.readScript] method. In the standard implementation the package URIs - * are converted to file URIs using the package root URI provided on the - * command line as base. If the package root URI is - * 'file:///current/working/dir/' then the package URI 'package:foo/bar.dart' - * will be resolved to the resource URI - * 'file:///current/working/dir/foo/bar.dart'. - * - * The distinction between readable URI and resource URI is necessary to ensure - * that these imports - * - * import 'package:foo.dart' as a; - * import 'packages/foo.dart' as b; - * - * do _not_ resolve to the same library when the package root URI happens to - * point to the 'packages' folder. - * - */ -abstract class LibraryLoader extends CompilerTask { - LibraryLoader(Compiler compiler) : super(compiler); - - /** - * Loads the library specified by the [resolvedUri] and returns its - * [LibraryElement]. - * - * If the library is not already loaded, the method creates the - * [LibraryElement] for the library and computes the import/export scope, - * loading and computing the import/export scopes of all required libraries in - * the process. The method handles cyclic dependency between libraries. - * - * This is the main entry point for [LibraryLoader]. - */ - // TODO(johnniwinther): Remove [canonicalUri] together with - // [Compiler.scanBuiltinLibrary]. - LibraryElement loadLibrary(Uri resolvedUri, Node node, Uri canonicalUri); - - // TODO(johnniwinther): Remove this when patches don't need special parsing. - void registerLibraryFromTag(LibraryDependencyHandler handler, - LibraryElement library, - LibraryDependency tag); - - /** - * Adds the elements in the export scope of [importedLibrary] to the import - * scope of [importingLibrary]. - */ - // TODO(johnniwinther): Move handling of 'js_helper' to the library loader - // to remove this method from the [LibraryLoader] interface. - void importLibrary(LibraryElement importingLibrary, - LibraryElement importedLibrary, - Import tag); -} - -/** - * [CombinatorFilter] is a succinct representation of a list of combinators from - * a library dependency tag. - */ -class CombinatorFilter { - const CombinatorFilter(); - - /** - * Returns [:true:] if [element] is excluded by this filter. - */ - bool exclude(Element element) => false; - - /** - * Creates a filter based on the combinators of [tag]. - */ - factory CombinatorFilter.fromTag(LibraryDependency tag) { - if (tag == null || tag.combinators == null) { - return const CombinatorFilter(); - } - - // If the list of combinators contain at least one [:show:] we can create - // a positive list of elements to include, otherwise we create a negative - // list of elements to exclude. - bool show = false; - Set<SourceString> nameSet; - for (Combinator combinator in tag.combinators) { - if (combinator.isShow) { - show = true; - var set = new Set<SourceString>(); - for (Identifier identifier in combinator.identifiers) { - set.add(identifier.source); - } - if (nameSet == null) { - nameSet = set; - } else { - nameSet = nameSet.intersection(set); - } - } - } - if (nameSet == null) { - nameSet = new Set<SourceString>(); - } - for (Combinator combinator in tag.combinators) { - if (combinator.isHide) { - for (Identifier identifier in combinator.identifiers) { - if (show) { - // We have a positive list => Remove hidden elements. - nameSet.remove(identifier.source); - } else { - // We have no positive list => Accumulate hidden elements. - nameSet.add(identifier.source); - } - } - } - } - return show ? new ShowFilter(nameSet) : new HideFilter(nameSet); - } -} - -/** - * A list of combinators represented as a list of element names to include. - */ -class ShowFilter extends CombinatorFilter { - final Set<SourceString> includedNames; - - ShowFilter(this.includedNames); - - bool exclude(Element element) => !includedNames.contains(element.name); -} - -/** - * A list of combinators represented as a list of element names to exclude. - */ -class HideFilter extends CombinatorFilter { - final Set<SourceString> excludedNames; - - HideFilter(this.excludedNames); - - bool exclude(Element element) => excludedNames.contains(element.name); -} - -/** - * Implementation class for [LibraryLoader]. The distinction between - * [LibraryLoader] and [LibraryLoaderTask] is made to hide internal members from - * the [LibraryLoader] interface. - */ -class LibraryLoaderTask extends LibraryLoader { - LibraryLoaderTask(Compiler compiler) : super(compiler); - String get name => 'LibraryLoader'; - - final Map<String, LibraryElement> libraryNames = - new LinkedHashMap<String, LibraryElement>(); - - LibraryDependencyHandler currentHandler; - - LibraryElement loadLibrary(Uri resolvedUri, Node node, Uri canonicalUri) { - return measure(() { - assert(currentHandler == null); - currentHandler = new LibraryDependencyHandler(compiler); - LibraryElement library = - createLibrary(currentHandler, null, resolvedUri, node, canonicalUri); - currentHandler.computeExports(); - currentHandler = null; - return library; - }); - } - - /** - * Processes the library tags in [library]. - * - * The imported/exported libraries are loaded and processed recursively but - * the import/export scopes are not set up. - */ - void processLibraryTags(LibraryDependencyHandler handler, - LibraryElement library) { - int tagState = TagState.NO_TAG_SEEN; - - /** - * If [value] is less than [tagState] complain and return - * [tagState]. Otherwise return the new value for [tagState] - * (transition function for state machine). - */ - int checkTag(int value, LibraryTag tag) { - if (tagState > value) { - compiler.reportError(tag, 'out of order'); - return tagState; - } - return TagState.NEXT[value]; - } - - bool importsDartCore = false; - var libraryDependencies = new LinkBuilder<LibraryDependency>(); - Uri base = library.entryCompilationUnit.script.uri; - for (LibraryTag tag in library.tags.reverse()) { - if (tag.isImport) { - Import import = tag; - tagState = checkTag(TagState.IMPORT_OR_EXPORT, import); - if (import.uri.dartString.slowToString() == 'dart:core') { - importsDartCore = true; - } - libraryDependencies.addLast(import); - } else if (tag.isExport) { - tagState = checkTag(TagState.IMPORT_OR_EXPORT, tag); - libraryDependencies.addLast(tag); - } else if (tag.isLibraryName) { - tagState = checkTag(TagState.LIBRARY, tag); - if (library.libraryTag != null) { - compiler.cancel("duplicated library declaration", node: tag); - } else { - library.libraryTag = tag; - } - checkDuplicatedLibraryName(library); - } else if (tag.isPart) { - Part part = tag; - StringNode uri = part.uri; - Uri resolvedUri = base.resolve(uri.dartString.slowToString()); - tagState = checkTag(TagState.SOURCE, part); - scanPart(part, resolvedUri, library); - } else { - compiler.internalError("Unhandled library tag.", node: tag); - } - } - - // Apply patch, if any. - if (library.isPlatformLibrary) { - patchDartLibrary(handler, library, library.canonicalUri.path); - } - - // Import dart:core if not already imported. - if (!importsDartCore && !isDartCore(library.canonicalUri)) { - handler.registerDependency(library, null, loadCoreLibrary(handler)); - } - - for (LibraryDependency tag in libraryDependencies.toLink()) { - registerLibraryFromTag(handler, library, tag); - } - } - - void checkDuplicatedLibraryName(LibraryElement library) { - LibraryName tag = library.libraryTag; - if (tag != null) { - String name = library.getLibraryOrScriptName(); - LibraryElement existing = - libraryNames.putIfAbsent(name, () => library); - if (!identical(existing, library)) { - Uri uri = library.entryCompilationUnit.script.uri; - compiler.reportMessage( - compiler.spanFromSpannable(tag.name, uri), - MessageKind.DUPLICATED_LIBRARY_NAME.error({'libraryName': name}), - api.Diagnostic.WARNING); - Uri existingUri = existing.entryCompilationUnit.script.uri; - compiler.reportMessage( - compiler.spanFromSpannable(existing.libraryTag.name, existingUri), - MessageKind.DUPLICATED_LIBRARY_NAME.error({'libraryName': name}), - api.Diagnostic.WARNING); - } - } - } - - bool isDartCore(Uri uri) => uri.scheme == "dart" && uri.path == "core"; - - /** - * Lazily loads and returns the [LibraryElement] for the dart:core library. - */ - LibraryElement loadCoreLibrary(LibraryDependencyHandler handler) { - if (compiler.coreLibrary == null) { - Uri coreUri = new Uri.fromComponents(scheme: 'dart', path: 'core'); - compiler.coreLibrary - = createLibrary(handler, null, coreUri, null, coreUri); - } - return compiler.coreLibrary; - } - - void patchDartLibrary(LibraryDependencyHandler handler, - LibraryElement library, String dartLibraryPath) { - if (library.isPatched) return; - Uri patchUri = compiler.resolvePatchUri(dartLibraryPath); - if (patchUri != null) { - compiler.patchParser.patchLibrary(handler, patchUri, library); - } - } - - /** - * Handle a part tag in the scope of [library]. The [resolvedUri] given is - * used as is, any URI resolution should be done beforehand. - */ - void scanPart(Part part, Uri resolvedUri, LibraryElement library) { - if (!resolvedUri.isAbsolute()) throw new ArgumentError(resolvedUri); - Uri readableUri = compiler.translateResolvedUri(library, resolvedUri, part); - Script sourceScript = compiler.readScript(readableUri, part); - CompilationUnitElement unit = - new CompilationUnitElementX(sourceScript, library); - compiler.withCurrentElement(unit, () { - compiler.scanner.scan(unit); - if (unit.partTag == null) { - bool wasDiagnosticEmitted = false; - compiler.withCurrentElement(library, () { - wasDiagnosticEmitted = - compiler.onDeprecatedFeature(part, 'missing part-of tag'); - }); - if (wasDiagnosticEmitted) { - compiler.reportMessage( - compiler.spanFromElement(unit), - MessageKind.MISSING_PART_OF_TAG.error(), - api.Diagnostic.INFO); - } - } - }); - } - - /** - * Handle an import/export tag by loading the referenced library and - * registering its dependency in [handler] for the computation of the import/ - * export scope. - */ - void registerLibraryFromTag(LibraryDependencyHandler handler, - LibraryElement library, - LibraryDependency tag) { - Uri base = library.entryCompilationUnit.script.uri; - Uri resolvedUri = base.resolve(tag.uri.dartString.slowToString()); - LibraryElement loadedLibrary = - createLibrary(handler, library, resolvedUri, tag.uri, resolvedUri); - handler.registerDependency(library, tag, loadedLibrary); - - if (!loadedLibrary.hasLibraryName()) { - compiler.withCurrentElement(library, () { - compiler.reportError(tag == null ? null : tag.uri, - 'no library name found in ${loadedLibrary.canonicalUri}'); - }); - } - } - - /** - * Create (or reuse) a library element for the library specified by the - * [resolvedUri]. - * - * If a new library is created, the [handler] is notified. - */ - // TODO(johnniwinther): Remove [canonicalUri] and make [resolvedUri] the - // canonical uri when [Compiler.scanBuiltinLibrary] is removed. - LibraryElement createLibrary(LibraryDependencyHandler handler, - LibraryElement importingLibrary, - Uri resolvedUri, Node node, Uri canonicalUri) { - bool newLibrary = false; - Uri readableUri = - compiler.translateResolvedUri(importingLibrary, resolvedUri, node); - if (readableUri == null) return null; - LibraryElement createLibrary() { - newLibrary = true; - Script script = compiler.readScript(readableUri, node); - LibraryElement element = new LibraryElementX(script, canonicalUri); - handler.registerNewLibrary(element); - native.maybeEnableNative(compiler, element); - return element; - } - LibraryElement library; - if (canonicalUri == null) { - library = createLibrary(); - } else { - library = compiler.libraries.putIfAbsent(canonicalUri.toString(), - createLibrary); - } - if (newLibrary) { - compiler.withCurrentElement(library, () { - compiler.scanner.scanLibrary(library); - processLibraryTags(handler, library); - handler.registerLibraryExports(library); - compiler.onLibraryScanned(library, resolvedUri); - }); - } - return library; - } - - // TODO(johnniwinther): Remove this method when 'js_helper' is handled by - // [LibraryLoaderTask]. - void importLibrary(LibraryElement importingLibrary, - LibraryElement importedLibrary, - Import tag) { - new ImportLink(tag, importedLibrary).importLibrary(compiler, - importingLibrary); - } -} - - -/** - * The fields of this class models a state machine for checking script - * tags come in the correct order. - */ -class TagState { - static const int NO_TAG_SEEN = 0; - static const int LIBRARY = 1; - static const int IMPORT_OR_EXPORT = 2; - static const int SOURCE = 3; - static const int RESOURCE = 4; - - /** Next state. */ - static const List<int> NEXT = - const <int>[NO_TAG_SEEN, - IMPORT_OR_EXPORT, // Only one library tag is allowed. - IMPORT_OR_EXPORT, - SOURCE, - RESOURCE]; -} - -/** - * An [import] tag and the [importedLibrary] imported through [import]. - */ -class ImportLink { - final Import import; - final LibraryElement importedLibrary; - - ImportLink(this.import, this.importedLibrary); - - /** - * Imports the library into the [importingLibrary]. - */ - void importLibrary(Compiler compiler, LibraryElement importingLibrary) { - assert(invariant(importingLibrary, - importedLibrary.exportsHandled, - message: 'Exports not handled on $importedLibrary')); - var combinatorFilter = new CombinatorFilter.fromTag(import); - if (import != null && import.prefix != null) { - SourceString prefix = import.prefix.source; - Element e = importingLibrary.find(prefix); - if (e == null) { - e = new PrefixElementX(prefix, importingLibrary.entryCompilationUnit, - import.getBeginToken()); - importingLibrary.addToScope(e, compiler); - } - if (!identical(e.kind, ElementKind.PREFIX)) { - compiler.withCurrentElement(e, () { - compiler.reportWarning(new Identifier(e.position()), - 'duplicated definition'); - }); - compiler.reportError(import.prefix, 'duplicate definition'); - } - PrefixElement prefixElement = e; - importedLibrary.forEachExport((Element element) { - if (combinatorFilter.exclude(element)) return; - // TODO(johnniwinther): Clean-up like [checkDuplicateLibraryName]. - Element existing = - prefixElement.imported.putIfAbsent(element.name, () => element); - if (!identical(existing, element)) { - compiler.withCurrentElement(existing, () { - compiler.reportWarning(new Identifier(existing.position()), - 'duplicated import'); - }); - compiler.withCurrentElement(element, () { - compiler.reportError(new Identifier(element.position()), - 'duplicated import'); - }); - } - }); - } else { - importedLibrary.forEachExport((Element element) { - compiler.withCurrentElement(element, () { - if (combinatorFilter.exclude(element)) return; - importingLibrary.addImport(element, compiler); - }); - }); - } - } -} - -/** - * The combinator filter computed from an export tag and the library dependency - * node for the library that declared the export tag. This represents an edge in - * the library dependency graph. - */ -class ExportLink { - final CombinatorFilter combinatorFilter; - final LibraryDependencyNode exportNode; - - ExportLink(Export export, LibraryDependencyNode this.exportNode) - : this.combinatorFilter = new CombinatorFilter.fromTag(export); - - /** - * Exports [element] to the dependent library unless [element] is filtered by - * the export combinators. Returns [:true:] if the set pending exports of the - * dependent library was modified. - */ - bool exportElement(Element element) { - if (combinatorFilter.exclude(element)) return false; - return exportNode.addElementToPendingExports(element); - } -} - -/** - * A node in the library dependency graph. - * - * This class is used to collect the library dependencies expressed through - * import and export tags, and as the work-list entry in computations of library - * exports performed in [LibraryDependencyHandler.computeExports]. - */ -class LibraryDependencyNode { - final LibraryElement library; - - // TODO(ahe): Remove [hashCodeCounter] and [hashCode] when - // VM implementation of Object.hashCode is not slow. - final int hashCode = ++hashCodeCounter; - static int hashCodeCounter = 0; - - - /** - * A linked list of the import tags that import [library] mapped to the - * corresponding libraries. This is used to propagate exports into imports - * after the export scopes have been computed. - */ - Link<ImportLink> imports = const Link<ImportLink>(); - - /** - * A linked list of the export tags the dependent upon this node library. - * This is used to propagate exports during the computation of export scopes. - */ - Link<ExportLink> dependencies = const Link<ExportLink>(); - - /** - * The export scope for [library] which is gradually computed by the work-list - * computation in [LibraryDependencyHandler.computeExports]. - */ - Map<SourceString, Element> exportScope = - new LinkedHashMap<SourceString, Element>(); - - /** - * The set of exported elements that need to be propageted to dependent - * libraries as part of the work-list computation performed in - * [LibraryDependencyHandler.computeExports]. - */ - Set<Element> pendingExportSet = new Set<Element>(); - - LibraryDependencyNode(LibraryElement this.library); - - /** - * Registers that the library of this node imports [importLibrary] through the - * [import] tag. - */ - void registerImportDependency(Import import, - LibraryElement importedLibrary) { - imports = imports.prepend(new ImportLink(import, importedLibrary)); - } - - /** - * Registers that the library of this node is exported by - * [exportingLibraryNode] through the [export] tag. - */ - void registerExportDependency(Export export, - LibraryDependencyNode exportingLibraryNode) { - dependencies = - dependencies.prepend(new ExportLink(export, exportingLibraryNode)); - } - - /** - * Registers all non-private locally declared members of the library of this - * node to be exported. This forms the basis for the work-list computation of - * the export scopes performed in [LibraryDependencyHandler.computeExports]. - */ - void registerInitialExports() { - pendingExportSet.addAll(library.getNonPrivateElementsInScope()); - } - - void registerHandledExports(LibraryElement exportedLibraryElement, - CombinatorFilter filter) { - assert(invariant(library, exportedLibraryElement.exportsHandled)); - for (Element exportedElement in exportedLibraryElement.exports) { - if (!filter.exclude(exportedElement)) { - pendingExportSet.add(exportedElement); - } - } - } - - /** - * Registers the compute export scope with the node library. - */ - void registerExports() { - library.setExports(exportScope.values.toList()); - } - - /** - * Registers the imports of the node library. - */ - void registerImports(Compiler compiler) { - for (ImportLink link in imports) { - link.importLibrary(compiler, library); - } - } - - /** - * Copies and clears pending export set for this node. - */ - List<Element> pullPendingExports() { - List<Element> pendingExports = new List.from(pendingExportSet); - pendingExportSet.clear(); - return pendingExports; - } - - /** - * Adds [element] to the export scope for this node. If the [element] name - * is a duplicate, an error element is inserted into the export scope. - */ - Element addElementToExportScope(Compiler compiler, Element element) { - SourceString name = element.name; - Element existingElement = exportScope[name]; - if (existingElement != null) { - if (existingElement.isErroneous()) { - compiler.reportErrorCode(element, MessageKind.DUPLICATE_EXPORT, - {'name': name}); - element = existingElement; - } else if (existingElement.getLibrary() != library) { - // Declared elements hide exported elements. - compiler.reportErrorCode(existingElement, MessageKind.DUPLICATE_EXPORT, - {'name': name}); - compiler.reportErrorCode(element, MessageKind.DUPLICATE_EXPORT, - {'name': name}); - element = exportScope[name] = new ErroneousElementX( - MessageKind.DUPLICATE_EXPORT, {'name': name}, name, library); - } - } else { - exportScope[name] = element; - } - return element; - } - - /** - * Propagates the exported [element] to all library nodes that depend upon - * this node. If the propagation updated any pending exports, [:true:] is - * returned. - */ - bool propagateElement(Element element) { - bool change = false; - for (ExportLink link in dependencies) { - if (link.exportElement(element)) { - change = true; - } - } - return change; - } - - /** - * Adds [element] to the pending exports of this node and returns [:true:] if - * the pending export set was modified. The combinators of [export] are used - * to filter the element. - */ - bool addElementToPendingExports(Element element) { - if (!identical(exportScope[element.name], element)) { - if (!pendingExportSet.contains(element)) { - pendingExportSet.add(element); - return true; - } - } - return false; - } -} - -/** - * Helper class used for computing the possibly cyclic import/export scopes of - * a set of libraries. - * - * This class is used by [ScannerTask.loadLibrary] to collect all newly loaded - * libraries and to compute their import/export scopes through a fixed-point - * algorithm. - */ -class LibraryDependencyHandler { - final Compiler compiler; - - /** - * Newly loaded libraries and their corresponding node in the library - * dependency graph. Libraries that have already been fully loaded are not - * part of the dependency graph of this handler since their export scopes have - * already been computed. - */ - Map<LibraryElement,LibraryDependencyNode> nodeMap = - new LinkedHashMap<LibraryElement,LibraryDependencyNode>(); - - LibraryDependencyHandler(Compiler this.compiler); - - /** - * Performs a fixed-point computation on the export scopes of all registered - * libraries and creates the import/export of the libraries based on the - * fixed-point. - */ - void computeExports() { - bool changed = true; - while (changed) { - changed = false; - Map<LibraryDependencyNode, List<Element>> tasks = - new LinkedHashMap<LibraryDependencyNode, List<Element>>(); - - // Locally defined elements take precedence over exported - // elements. So we must propagate local elements first. We - // ensure this by pulling the pending exports before - // propagating. This enforces that we handle exports - // breadth-first, with locally defined elements being level 0. - nodeMap.forEach((_, LibraryDependencyNode node) { - List<Element> pendingExports = node.pullPendingExports(); - tasks[node] = pendingExports; - }); - tasks.forEach((LibraryDependencyNode node, List<Element> pendingExports) { - pendingExports.forEach((Element element) { - element = node.addElementToExportScope(compiler, element); - if (node.propagateElement(element)) { - changed = true; - } - }); - }); - } - - // Setup export scopes. These have to be set before computing the import - // scopes to avoid accessing uncomputed export scopes during handling of - // imports. - nodeMap.forEach((LibraryElement library, LibraryDependencyNode node) { - node.registerExports(); - }); - - // Setup import scopes. - nodeMap.forEach((LibraryElement library, LibraryDependencyNode node) { - node.registerImports(compiler); - }); - } - - /** - * Registers that [library] depends on [loadedLibrary] through [tag]. - */ - void registerDependency(LibraryElement library, - LibraryDependency tag, - LibraryElement loadedLibrary) { - if (tag is Export) { - // [loadedLibrary] is exported by [library]. - LibraryDependencyNode exportingNode = nodeMap[library]; - if (loadedLibrary.exportsHandled) { - // Export scope already computed on [loadedLibrary]. - var combinatorFilter = new CombinatorFilter.fromTag(tag); - exportingNode.registerHandledExports(loadedLibrary, combinatorFilter); - return; - } - LibraryDependencyNode exportedNode = nodeMap[loadedLibrary]; - assert(invariant(loadedLibrary, exportedNode != null, - message: "$loadedLibrary has not been registered")); - assert(invariant(library, exportingNode != null, - message: "$library has not been registered")); - exportedNode.registerExportDependency(tag, exportingNode); - } else if (tag == null || tag is Import) { - // [loadedLibrary] is imported by [library]. - LibraryDependencyNode importingNode = nodeMap[library]; - assert(invariant(library, importingNode != null, - message: "$library has not been registered")); - importingNode.registerImportDependency(tag, loadedLibrary); - } - } - - /** - * Registers [library] for the processing of its import/export scope. - */ - void registerNewLibrary(LibraryElement library) { - nodeMap[library] = new LibraryDependencyNode(library); - } - - /** - * Registers all top-level entities of [library] as starting point for the - * fixed-point computation of the import/export scopes. - */ - void registerLibraryExports(LibraryElement library) { - nodeMap[library].registerInitialExports(); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/mirrors/dart2js_mirror.dart b/pkgs/markdown/test/lib/src/compiler/implementation/mirrors/dart2js_mirror.dart deleted file mode 100644 index 13a15f8..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/mirrors/dart2js_mirror.dart +++ /dev/null
@@ -1,1742 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library mirrors_dart2js; - -import 'dart:async'; -import 'dart:collection' show LinkedHashMap; -import 'dart:io'; -import 'dart:uri'; - -import '../../compiler.dart' as diagnostics; -import '../elements/elements.dart'; -import '../resolution/resolution.dart' show ResolverTask, ResolverVisitor; -import '../apiimpl.dart' show Compiler; -import '../scanner/scannerlib.dart' hide SourceString; -import '../ssa/ssa.dart'; -import '../dart2jslib.dart' hide Compiler; -import '../dart_types.dart'; -import '../filenames.dart'; -import '../source_file.dart'; -import '../tree/tree.dart'; -import '../util/util.dart'; -import '../util/uri_extras.dart'; -import '../dart2js.dart'; -import '../util/characters.dart'; -import '../source_file_provider.dart'; - -import 'mirrors.dart'; -import 'mirrors_util.dart'; -import 'util.dart'; - -//------------------------------------------------------------------------------ -// Utility types and functions for the dart2js mirror system -//------------------------------------------------------------------------------ - -bool _isPrivate(String name) { - return name.startsWith('_'); -} - -List<ParameterMirror> _parametersFromFunctionSignature( - Dart2JsMirrorSystem system, - Dart2JsMethodMirror method, - FunctionSignature signature) { - var parameters = <ParameterMirror>[]; - Link<Element> link = signature.requiredParameters; - while (!link.isEmpty) { - parameters.add(new Dart2JsParameterMirror( - system, method, link.head, false, false)); - link = link.tail; - } - link = signature.optionalParameters; - bool isNamed = signature.optionalParametersAreNamed; - while (!link.isEmpty) { - parameters.add(new Dart2JsParameterMirror( - system, method, link.head, true, isNamed)); - link = link.tail; - } - return parameters; -} - -Dart2JsTypeMirror _convertTypeToTypeMirror( - Dart2JsMirrorSystem system, - DartType type, - InterfaceType defaultType, - [FunctionSignature functionSignature]) { - if (type == null) { - return new Dart2JsInterfaceTypeMirror(system, defaultType); - } else if (type is InterfaceType) { - if (type == system.compiler.types.dynamicType) { - return new Dart2JsDynamicMirror(system, type); - } else { - return new Dart2JsInterfaceTypeMirror(system, type); - } - } else if (type is TypeVariableType) { - return new Dart2JsTypeVariableMirror(system, type); - } else if (type is FunctionType) { - return new Dart2JsFunctionTypeMirror(system, type, functionSignature); - } else if (type is VoidType) { - return new Dart2JsVoidMirror(system, type); - } else if (type is TypedefType) { - return new Dart2JsTypedefMirror(system, type); - } else if (type is MalformedType) { - // TODO(johnniwinther): We need a mirror on malformed types. - return system.dynamicType; - } - _diagnosticListener.internalError( - "Unexpected type $type of kind ${type.kind}"); - system.compiler.internalError("Unexpected type $type of kind ${type.kind}"); -} - -Collection<Dart2JsMemberMirror> _convertElementMemberToMemberMirrors( - Dart2JsContainerMirror library, Element element) { - if (element.isSynthesized) { - return const <Dart2JsMemberMirror>[]; - } else if (element is VariableElement) { - return <Dart2JsMemberMirror>[new Dart2JsFieldMirror(library, element)]; - } else if (element is FunctionElement) { - return <Dart2JsMemberMirror>[new Dart2JsMethodMirror(library, element)]; - } else if (element is AbstractFieldElement) { - var members = <Dart2JsMemberMirror>[]; - if (element.getter != null) { - members.add(new Dart2JsMethodMirror(library, element.getter)); - } - if (element.setter != null) { - members.add(new Dart2JsMethodMirror(library, element.setter)); - } - return members; - } - library.mirrors.compiler.internalError( - "Unexpected member type $element ${element.kind}"); -} - -MethodMirror _convertElementMethodToMethodMirror(Dart2JsContainerMirror library, - Element element) { - if (element is FunctionElement) { - return new Dart2JsMethodMirror(library, element); - } else { - return null; - } -} - -InstanceMirror _convertConstantToInstanceMirror(Dart2JsMirrorSystem mirrors, - Constant constant) { - if (constant is BoolConstant) { - return new Dart2JsBoolConstantMirror(mirrors, constant); - } else if (constant is NumConstant) { - return new Dart2JsNumConstantMirror(mirrors, constant); - } else if (constant is StringConstant) { - return new Dart2JsStringConstantMirror(mirrors, constant); - } else if (constant is ListConstant) { - return new Dart2JsListConstantMirror(mirrors, constant); - } else if (constant is MapConstant) { - return new Dart2JsMapConstantMirror(mirrors, constant); - } else if (constant is TypeConstant) { - return new Dart2JsTypeConstantMirror(mirrors, constant); - } else if (constant is FunctionConstant) { - return new Dart2JsConstantMirror(mirrors, constant); - } else if (constant is NullConstant) { - return new Dart2JsNullConstantMirror(mirrors, constant); - } else if (constant is ConstructedConstant) { - return new Dart2JsConstructedConstantMirror(mirrors, constant); - } - mirrors.compiler.internalError("Unexpected constant $constant"); -} - -class Dart2JsMethodKind { - static const Dart2JsMethodKind REGULAR = const Dart2JsMethodKind("regular"); - static const Dart2JsMethodKind GENERATIVE = - const Dart2JsMethodKind("generative"); - static const Dart2JsMethodKind REDIRECTING = - const Dart2JsMethodKind("redirecting"); - static const Dart2JsMethodKind CONST = const Dart2JsMethodKind("const"); - static const Dart2JsMethodKind FACTORY = const Dart2JsMethodKind("factory"); - static const Dart2JsMethodKind GETTER = const Dart2JsMethodKind("getter"); - static const Dart2JsMethodKind SETTER = const Dart2JsMethodKind("setter"); - static const Dart2JsMethodKind OPERATOR = const Dart2JsMethodKind("operator"); - - final String text; - - const Dart2JsMethodKind(this.text); - - String toString() => text; -} - - -String _getOperatorFromOperatorName(String name) { - Map<String, String> mapping = const { - 'eq': '==', - 'not': '~', - 'index': '[]', - 'indexSet': '[]=', - 'mul': '*', - 'div': '/', - 'mod': '%', - 'tdiv': '~/', - 'add': '+', - 'sub': '-', - 'shl': '<<', - 'shr': '>>', - 'ge': '>=', - 'gt': '>', - 'le': '<=', - 'lt': '<', - 'and': '&', - 'xor': '^', - 'or': '|', - }; - String newName = mapping[name]; - if (newName == null) { - throw new Exception('Unhandled operator name: $name'); - } - return newName; -} - -DiagnosticListener get _diagnosticListener { - return const Dart2JsDiagnosticListener(); -} - -class Dart2JsDiagnosticListener implements DiagnosticListener { - const Dart2JsDiagnosticListener(); - - void cancel(String reason, {node, token, instruction, element}) { - print(reason); - } - - void log(message) { - print(message); - } - - void internalError(String message, - {Node node, Token token, HInstruction instruction, - Element element}) { - cancel('Internal error: $message', node: node, token: token, - instruction: instruction, element: element); - } - - void internalErrorOnElement(Element element, String message) { - internalError(message, element: element); - } - - SourceSpan spanFromSpannable(Node node, [Uri uri]) { - // TODO(johnniwinther): implement this. - throw 'unimplemented'; - } - - void reportMessage(SourceSpan span, Diagnostic message, - diagnostics.Diagnostic kind) { - // TODO(johnniwinther): implement this. - throw 'unimplemented'; - } - - bool onDeprecatedFeature(Spannable span, String feature) { - // TODO(johnniwinther): implement this? - throw 'unimplemented'; - } -} - -//------------------------------------------------------------------------------ -// Compilation implementation -//------------------------------------------------------------------------------ - -// TODO(johnniwinther): Support client configurable handlers/providers. -class Dart2JsCompilation implements Compilation { - Compiler _compiler; - final Uri cwd; - final SourceFileProvider provider; - - Dart2JsCompilation(Path script, Path libraryRoot, - [Path packageRoot, List<String> opts = const <String>[]]) - : cwd = getCurrentDirectory(), - provider = new SourceFileProvider() { - var handler = new FormattingDiagnosticHandler(provider); - var libraryUri = cwd.resolve(libraryRoot.toString()); - var packageUri; - if (packageRoot != null) { - packageUri = cwd.resolve(packageRoot.toString()); - } else { - packageUri = libraryUri; - } - _compiler = new Compiler(provider.readStringFromUri, - null, - handler.diagnosticHandler, - libraryUri, packageUri, opts); - var scriptUri = cwd.resolve(script.toString()); - // TODO(johnniwinther): Detect file not found - _compiler.run(scriptUri); - } - - Dart2JsCompilation.library(List<Path> libraries, Path libraryRoot, - [Path packageRoot, List<String> opts = const <String>[]]) - : cwd = getCurrentDirectory(), - provider = new SourceFileProvider() { - var libraryUri = cwd.resolve(libraryRoot.toString()); - var packageUri; - if (packageRoot != null) { - packageUri = cwd.resolve(packageRoot.toString()); - } else { - packageUri = libraryUri; - } - opts = new List<String>.from(opts); - opts.add('--analyze-only'); - opts.add('--analyze-all'); - _compiler = new Compiler(provider.readStringFromUri, - null, - silentDiagnosticHandler, - libraryUri, packageUri, opts); - var librariesUri = <Uri>[]; - for (Path library in libraries) { - librariesUri.add(cwd.resolve(library.toString())); - // TODO(johnniwinther): Detect file not found - } - _compiler.librariesToAnalyzeWhenRun = librariesUri; - _compiler.run(null); - } - - MirrorSystem get mirrors => new Dart2JsMirrorSystem(_compiler); - - Future<String> compileToJavaScript() => - new Future<String>.immediate(_compiler.assembledCode); -} - - -//------------------------------------------------------------------------------ -// Dart2Js specific extensions of mirror interfaces -//------------------------------------------------------------------------------ - -abstract class Dart2JsMirror implements Mirror { - Dart2JsMirrorSystem get mirrors; -} - -abstract class Dart2JsDeclarationMirror extends Dart2JsMirror - implements DeclarationMirror { - - bool get isTopLevel => owner != null && owner is LibraryMirror; - - bool get isPrivate => _isPrivate(simpleName); - - /** - * Returns the first token for the source of this declaration, not including - * metadata annotations. - */ - Token getBeginToken(); - - /** - * Returns the last token for the source of this declaration. - */ - Token getEndToken(); - - /** - * Returns the script for the source of this declaration. - */ - Script getScript(); -} - -abstract class Dart2JsTypeMirror extends Dart2JsDeclarationMirror - implements TypeMirror { -} - -abstract class Dart2JsElementMirror extends Dart2JsDeclarationMirror { - final Dart2JsMirrorSystem mirrors; - final Element _element; - List<InstanceMirror> _metadata; - - Dart2JsElementMirror(this.mirrors, this._element) { - assert (mirrors != null); - assert (_element != null); - } - - String get simpleName => _element.name.slowToString(); - - String get displayName => simpleName; - - /** - * Computes the first token for this declaration using the begin token of the - * element node or element position as indicator. - */ - Token getBeginToken() { - // TODO(johnniwinther): Avoid calling [parseNode]. - Node node = _element.parseNode(mirrors.compiler); - if (node == null) { - return _element.position(); - } - return node.getBeginToken(); - } - - /** - * Computes the last token for this declaration using the end token of the - * element node or element position as indicator. - */ - Token getEndToken() { - // TODO(johnniwinther): Avoid calling [parseNode]. - Node node = _element.parseNode(mirrors.compiler); - if (node == null) { - return _element.position(); - } - return node.getEndToken(); - } - - /** - * Returns the first token for the source of this declaration, including - * metadata annotations. - */ - Token getFirstToken() { - if (!_element.metadata.isEmpty) { - for (MetadataAnnotation metadata in _element.metadata) { - if (metadata.beginToken != null) { - return metadata.beginToken; - } - } - } - return getBeginToken(); - } - - Script getScript() => _element.getCompilationUnit().script; - - SourceLocation get location { - Token beginToken = getFirstToken(); - Script script = getScript(); - SourceSpan span; - if (beginToken == null) { - span = new SourceSpan(script.uri, 0, 0); - } else { - Token endToken = getEndToken(); - span = mirrors.compiler.spanFromTokens(beginToken, endToken, script.uri); - } - return new Dart2JsSourceLocation(script, span); - } - - String toString() => _element.toString(); - - int get hashCode => qualifiedName.hashCode; - - void _appendCommentTokens(Token commentToken) { - while (commentToken != null && commentToken.kind == COMMENT_TOKEN) { - _metadata.add(new Dart2JsCommentInstanceMirror( - mirrors, commentToken.slowToString())); - commentToken = commentToken.next; - } - } - - List<InstanceMirror> get metadata { - if (_metadata == null) { - _metadata = <InstanceMirror>[]; - for (MetadataAnnotation metadata in _element.metadata) { - _appendCommentTokens(mirrors.compiler.commentMap[metadata.beginToken]); - metadata.ensureResolved(mirrors.compiler); - _metadata.add( - _convertConstantToInstanceMirror(mirrors, metadata.value)); - } - _appendCommentTokens(mirrors.compiler.commentMap[getBeginToken()]); - } - // TODO(johnniwinther): Return an unmodifiable list instead. - return new List<InstanceMirror>.from(_metadata); - } -} - -abstract class Dart2JsMemberMirror extends Dart2JsElementMirror - implements MemberMirror { - - Dart2JsMemberMirror(Dart2JsMirrorSystem system, Element element) - : super(system, element); - - bool get isConstructor => false; - - bool get isVariable => false; - - bool get isMethod => false; - - bool get isStatic => false; - - bool get isParameter => false; -} - -//------------------------------------------------------------------------------ -// Mirror system implementation. -//------------------------------------------------------------------------------ - -class Dart2JsMirrorSystem implements MirrorSystem { - final Compiler compiler; - Map<String, Dart2JsLibraryMirror> _libraries; - Map<LibraryElement, Dart2JsLibraryMirror> _libraryMap; - - Dart2JsMirrorSystem(this.compiler) - : _libraryMap = new Map<LibraryElement, Dart2JsLibraryMirror>(); - - void _ensureLibraries() { - if (_libraries == null) { - _libraries = <String, Dart2JsLibraryMirror>{}; - compiler.libraries.forEach((_, LibraryElement v) { - var mirror = new Dart2JsLibraryMirror(mirrors, v); - _libraries[mirror.simpleName] = mirror; - _libraryMap[v] = mirror; - }); - } - } - - Map<String, LibraryMirror> get libraries { - _ensureLibraries(); - return new ImmutableMapWrapper<String, LibraryMirror>(_libraries); - } - - Dart2JsLibraryMirror _getLibrary(LibraryElement element) => - _libraryMap[element]; - - Dart2JsMirrorSystem get mirrors => this; - - TypeMirror get dynamicType => - _convertTypeToTypeMirror(this, compiler.types.dynamicType, null); - - TypeMirror get voidType => - _convertTypeToTypeMirror(this, compiler.types.voidType, null); -} - -abstract class Dart2JsContainerMirror extends Dart2JsElementMirror - implements ContainerMirror { - Map<String, MemberMirror> _members; - - Dart2JsContainerMirror(Dart2JsMirrorSystem system, Element element) - : super(system, element); - - void _ensureMembers(); - - Map<String, MemberMirror> get members { - _ensureMembers(); - return new ImmutableMapWrapper<String, MemberMirror>(_members); - } - - Map<String, MethodMirror> get functions { - _ensureMembers(); - return new AsFilteredImmutableMap<String, MemberMirror, MethodMirror>( - _members, - (MemberMirror member) => member is MethodMirror ? member : null); - } - - Map<String, MethodMirror> get getters { - _ensureMembers(); - return new AsFilteredImmutableMap<String, MemberMirror, MethodMirror>( - _members, - (MemberMirror member) => - member is MethodMirror && (member as MethodMirror).isGetter ? - member : null); - } - - Map<String, MethodMirror> get setters { - _ensureMembers(); - return new AsFilteredImmutableMap<String, MemberMirror, MethodMirror>( - _members, - (MemberMirror member) => - member is MethodMirror && (member as MethodMirror).isSetter ? - member : null); - } - - Map<String, VariableMirror> get variables { - _ensureMembers(); - return new AsFilteredImmutableMap<String, MemberMirror, VariableMirror>( - _members, - (MemberMirror member) => member is VariableMirror ? member : null); - } -} - -class Dart2JsLibraryMirror extends Dart2JsContainerMirror - implements LibraryMirror { - Map<String, ClassMirror> _classes; - - Dart2JsLibraryMirror(Dart2JsMirrorSystem system, LibraryElement library) - : super(system, library); - - LibraryElement get _library => _element; - - Uri get uri => _library.canonicalUri; - - DeclarationMirror get owner => null; - - bool get isPrivate => false; - - LibraryMirror library() => this; - - /** - * Returns the library name (for libraries with a #library tag) or the script - * file name (for scripts without a #library tag). The latter case is used to - * provide a 'library name' for scripts, to use for instance in dartdoc. - */ - String get simpleName { - if (_library.libraryTag != null) { - // TODO(ahe): Remove StringNode check when old syntax is removed. - StringNode name = _library.libraryTag.name.asStringNode(); - if (name != null) { - return name.dartString.slowToString(); - } else { - return _library.libraryTag.name.toString(); - } - } else { - // Use the file name as script name. - String path = _library.canonicalUri.path; - return path.substring(path.lastIndexOf('/') + 1); - } - } - - String get qualifiedName => simpleName; - - void _ensureClasses() { - if (_classes == null) { - _classes = <String, ClassMirror>{}; - _library.forEachLocalMember((Element e) { - if (e.isClass()) { - ClassElement classElement = e; - classElement.ensureResolved(mirrors.compiler); - var type = new Dart2JsClassMirror.fromLibrary(this, classElement); - assert(invariant(_library, !_classes.containsKey(type.simpleName), - message: "Type name '${type.simpleName}' " - "is not unique in $_library.")); - _classes[type.simpleName] = type; - } else if (e.isTypedef()) { - var type = new Dart2JsTypedefMirror.fromLibrary(this, - e.computeType(mirrors.compiler)); - assert(invariant(_library, !_classes.containsKey(type.simpleName), - message: "Type name '${type.simpleName}' " - "is not unique in $_library.")); - _classes[type.simpleName] = type; - } - }); - } - } - - void _ensureMembers() { - if (_members == null) { - _members = <String, MemberMirror>{}; - _library.forEachLocalMember((Element e) { - if (!e.isClass() && !e.isTypedef()) { - for (var member in _convertElementMemberToMemberMirrors(this, e)) { - assert(!_members.containsKey(member.simpleName)); - _members[member.simpleName] = member; - } - } - }); - } - } - - Map<String, ClassMirror> get classes { - _ensureClasses(); - return new ImmutableMapWrapper<String, ClassMirror>(_classes); - } - - /** - * Computes the first token of this library using the first library tag as - * indicator. - */ - Token getBeginToken() { - if (_library.libraryTag != null) { - return _library.libraryTag.getBeginToken(); - } else if (!_library.tags.isEmpty) { - return _library.tags.reverse().head.getBeginToken(); - } - return null; - } - - /** - * Computes the first token of this library using the last library tag as - * indicator. - */ - Token getEndToken() { - if (!_library.tags.isEmpty) { - return _library.tags.head.getEndToken(); - } - return null; - } -} - -class Dart2JsSourceLocation implements SourceLocation { - final Script _script; - final SourceSpan _span; - int _line; - int _column; - - Dart2JsSourceLocation(this._script, this._span); - - int _computeLine() { - var sourceFile = _script.file as SourceFile; - if (sourceFile != null) { - return sourceFile.getLine(offset) + 1; - } - var index = 0; - var lineNumber = 0; - while (index <= offset && index < sourceText.length) { - index = sourceText.indexOf('\n', index) + 1; - if (index <= 0) break; - lineNumber++; - } - return lineNumber; - } - - int get line { - if (_line == null) { - _line = _computeLine(); - } - return _line; - } - - int _computeColumn() { - if (length == 0) return 0; - - var sourceFile = _script.file as SourceFile; - if (sourceFile != null) { - return sourceFile.getColumn(sourceFile.getLine(offset), offset) + 1; - } - int index = offset - 1; - var columnNumber = 0; - while (0 <= index && index < sourceText.length) { - columnNumber++; - var charCode = sourceText.charCodeAt(index); - if (charCode == $CR || charCode == $LF) { - break; - } - index--; - } - return columnNumber; - } - - int get column { - if (_column == null) { - _column = _computeColumn(); - } - return _column; - } - - int get offset => _span.begin; - - int get length => _span.end - _span.begin; - - String get text => _script.text.substring(_span.begin, _span.end); - - Uri get sourceUri => _script.uri; - - String get sourceText => _script.text; -} - -class Dart2JsParameterMirror extends Dart2JsMemberMirror - implements ParameterMirror { - final MethodMirror _method; - final bool isOptional; - final bool isNamed; - - factory Dart2JsParameterMirror(Dart2JsMirrorSystem system, - MethodMirror method, - VariableElement element, - bool isOptional, - bool isNamed) { - if (element is FieldParameterElement) { - return new Dart2JsFieldParameterMirror(system, - method, element, isOptional, isNamed); - } - return new Dart2JsParameterMirror._normal(system, - method, element, isOptional, isNamed); - } - - Dart2JsParameterMirror._normal(Dart2JsMirrorSystem system, - this._method, - VariableElement element, - this.isOptional, - this.isNamed) - : super(system, element); - - DeclarationMirror get owner => _method; - - VariableElement get _variableElement => _element; - - String get qualifiedName => '${_method.qualifiedName}#${simpleName}'; - - TypeMirror get type => _convertTypeToTypeMirror(mirrors, - _variableElement.computeType(mirrors.compiler), - mirrors.compiler.types.dynamicType, - _variableElement.variables.functionSignature); - - - bool get isFinal => false; - - bool get isConst => false; - - String get defaultValue { - if (hasDefaultValue) { - SendSet expression = _variableElement.cachedNode.asSendSet(); - return unparse(expression.arguments.head); - } - return null; - } - - bool get hasDefaultValue { - return _variableElement.cachedNode != null && - _variableElement.cachedNode is SendSet; - } - - bool get isInitializingFormal => false; - - VariableMirror get initializedField => null; -} - -class Dart2JsFieldParameterMirror extends Dart2JsParameterMirror { - - Dart2JsFieldParameterMirror(Dart2JsMirrorSystem system, - MethodMirror method, - FieldParameterElement element, - bool isOptional, - bool isNamed) - : super._normal(system, method, element, isOptional, isNamed); - - FieldParameterElement get _fieldParameterElement => _element; - - TypeMirror get type { - if (_fieldParameterElement.variables.cachedNode.type != null) { - return super.type; - } - return _convertTypeToTypeMirror(mirrors, - _fieldParameterElement.fieldElement.computeType(mirrors.compiler), - mirrors.compiler.types.dynamicType, - _variableElement.variables.functionSignature); - } - - bool get isInitializingFormal => true; - - VariableMirror get initializedField => new Dart2JsFieldMirror( - _method.owner, _fieldParameterElement.fieldElement); -} - -//------------------------------------------------------------------------------ -// Declarations -//------------------------------------------------------------------------------ -class Dart2JsClassMirror extends Dart2JsContainerMirror - implements Dart2JsTypeMirror, ClassMirror { - final Dart2JsLibraryMirror library; - List<TypeVariableMirror> _typeVariables; - - Dart2JsClassMirror(Dart2JsMirrorSystem system, ClassElement _class) - : this.library = system._getLibrary(_class.getLibrary()), - super(system, _class); - - ClassElement get _class => _element; - - Dart2JsClassMirror.fromLibrary(Dart2JsLibraryMirror library, - ClassElement _class) - : this.library = library, - super(library.mirrors, _class); - - DeclarationMirror get owner => library; - - String get qualifiedName => '${library.qualifiedName}.${simpleName}'; - - void _ensureMembers() { - if (_members == null) { - _members = <String, Dart2JsMemberMirror>{}; - _class.forEachMember((_, e) { - for (var member in _convertElementMemberToMemberMirrors(this, e)) { - assert(!_members.containsKey(member.simpleName)); - _members[member.simpleName] = member; - } - }); - } - } - - Map<String, MethodMirror> get methods => functions; - - Map<String, MethodMirror> get constructors { - _ensureMembers(); - return new AsFilteredImmutableMap<String, MemberMirror, MethodMirror>( - _members, (m) => m.isConstructor ? m : null); - } - - bool get isObject => _class == mirrors.compiler.objectClass; - - bool get isDynamic => false; - - bool get isVoid => false; - - bool get isTypeVariable => false; - - bool get isTypedef => false; - - bool get isFunction => false; - - ClassMirror get originalDeclaration => this; - - ClassMirror get superclass { - if (_class.supertype != null) { - return new Dart2JsInterfaceTypeMirror(mirrors, _class.supertype); - } - return null; - } - - List<ClassMirror> get superinterfaces { - var list = <ClassMirror>[]; - Link<DartType> link = _class.interfaces; - while (!link.isEmpty) { - var type = _convertTypeToTypeMirror(mirrors, link.head, - mirrors.compiler.types.dynamicType); - list.add(type); - link = link.tail; - } - return list; - } - - bool get isClass => !_class.isInterface(); - - bool get isInterface => _class.isInterface(); - - bool get isAbstract => _class.modifiers.isAbstract(); - - bool get isOriginalDeclaration => true; - - List<TypeMirror> get typeArguments { - throw new UnsupportedError( - 'Declarations do not have type arguments'); - } - - List<TypeVariableMirror> get typeVariables { - if (_typeVariables == null) { - _typeVariables = <TypeVariableMirror>[]; - _class.ensureResolved(mirrors.compiler); - for (TypeVariableType typeVariable in _class.typeVariables) { - _typeVariables.add( - new Dart2JsTypeVariableMirror(mirrors, typeVariable)); - } - } - return _typeVariables; - } - - /** - * Returns the default type for this interface. - */ - ClassMirror get defaultFactory { - if (_class.defaultClass != null) { - return new Dart2JsInterfaceTypeMirror(mirrors, _class.defaultClass); - } - return null; - } - - bool operator ==(Object other) { - if (identical(this, other)) { - return true; - } - if (other is! ClassMirror) { - return false; - } - if (library != other.library) { - return false; - } - if (!identical(isOriginalDeclaration, other.isOriginalDeclaration)) { - return false; - } - return qualifiedName == other.qualifiedName; - } -} - -class Dart2JsTypedefMirror extends Dart2JsTypeElementMirror - implements Dart2JsTypeMirror, TypedefMirror { - final Dart2JsLibraryMirror _library; - List<TypeVariableMirror> _typeVariables; - TypeMirror _definition; - - Dart2JsTypedefMirror(Dart2JsMirrorSystem system, TypedefType _typedef) - : this._library = system._getLibrary(_typedef.element.getLibrary()), - super(system, _typedef); - - Dart2JsTypedefMirror.fromLibrary(Dart2JsLibraryMirror library, - TypedefType _typedef) - : this._library = library, - super(library.mirrors, _typedef); - - TypedefType get _typedef => _type; - - String get qualifiedName => '${library.qualifiedName}.${simpleName}'; - - LibraryMirror get library => _library; - - bool get isTypedef => true; - - List<TypeMirror> get typeArguments { - throw new UnsupportedError( - 'Declarations do not have type arguments'); - } - - List<TypeVariableMirror> get typeVariables { - if (_typeVariables == null) { - _typeVariables = <TypeVariableMirror>[]; - for (TypeVariableType typeVariable in _typedef.typeArguments) { - _typeVariables.add( - new Dart2JsTypeVariableMirror(mirrors, typeVariable)); - } - } - return _typeVariables; - } - - TypeMirror get value { - if (_definition == null) { - // TODO(johnniwinther): Should be [ensureResolved]. - mirrors.compiler.resolveTypedef(_typedef.element); - _definition = _convertTypeToTypeMirror( - mirrors, - _typedef.element.alias, - mirrors.compiler.types.dynamicType, - _typedef.element.functionSignature); - } - return _definition; - } - - ClassMirror get originalDeclaration => this; - - // TODO(johnniwinther): How should a typedef respond to these? - ClassMirror get superclass => null; - - List<ClassMirror> get superinterfaces => const <ClassMirror>[]; - - bool get isClass => false; - - bool get isInterface => false; - - bool get isOriginalDeclaration => true; - - bool get isAbstract => false; -} - -class Dart2JsTypeVariableMirror extends Dart2JsTypeElementMirror - implements TypeVariableMirror { - final TypeVariableType _typeVariableType; - ClassMirror _declarer; - - Dart2JsTypeVariableMirror(Dart2JsMirrorSystem system, - TypeVariableType typeVariableType) - : this._typeVariableType = typeVariableType, - super(system, typeVariableType) { - assert(_typeVariableType != null); - } - - - String get qualifiedName => '${declarer.qualifiedName}.${simpleName}'; - - ClassMirror get declarer { - if (_declarer == null) { - if (_typeVariableType.element.enclosingElement.isClass()) { - _declarer = new Dart2JsClassMirror(mirrors, - _typeVariableType.element.enclosingElement); - } else if (_typeVariableType.element.enclosingElement.isTypedef()) { - _declarer = new Dart2JsTypedefMirror(mirrors, - _typeVariableType.element.enclosingElement.computeType( - mirrors.compiler)); - } - } - return _declarer; - } - - LibraryMirror get library => declarer.library; - - DeclarationMirror get owner => declarer; - - bool get isTypeVariable => true; - - TypeMirror get upperBound => _convertTypeToTypeMirror( - mirrors, - _typeVariableType.element.bound, - mirrors.compiler.objectClass.computeType(mirrors.compiler)); - - bool operator ==(Object other) { - if (identical(this, other)) { - return true; - } - if (other is! TypeVariableMirror) { - return false; - } - if (declarer != other.declarer) { - return false; - } - return qualifiedName == other.qualifiedName; - } -} - - -//------------------------------------------------------------------------------ -// Types -//------------------------------------------------------------------------------ - -abstract class Dart2JsTypeElementMirror extends Dart2JsElementMirror - implements Dart2JsTypeMirror { - final DartType _type; - - Dart2JsTypeElementMirror(Dart2JsMirrorSystem system, DartType type) - : super(system, type.element), - this._type = type; - - String get simpleName => _type.name.slowToString(); - - DeclarationMirror get owner => library; - - LibraryMirror get library { - return mirrors._getLibrary(_type.element.getLibrary()); - } - - bool get isObject => false; - - bool get isVoid => false; - - bool get isDynamic => false; - - bool get isTypeVariable => false; - - bool get isTypedef => false; - - bool get isFunction => false; - - String toString() => _type.toString(); - - Map<String, MemberMirror> get members => const <String, MemberMirror>{}; - - Map<String, MethodMirror> get constructors => const <String, MethodMirror>{}; - - Map<String, MethodMirror> get methods => const <String, MethodMirror>{}; - - Map<String, MethodMirror> get getters => const <String, MethodMirror>{}; - - Map<String, MethodMirror> get setters => const <String, MethodMirror>{}; - - Map<String, VariableMirror> get variables => const <String, VariableMirror>{}; - - ClassMirror get defaultFactory => null; -} - -class Dart2JsInterfaceTypeMirror extends Dart2JsTypeElementMirror - implements ClassMirror { - List<TypeMirror> _typeArguments; - - Dart2JsInterfaceTypeMirror(Dart2JsMirrorSystem system, - InterfaceType interfaceType) - : super(system, interfaceType); - - InterfaceType get _interfaceType => _type; - - String get qualifiedName => originalDeclaration.qualifiedName; - - // TODO(johnniwinther): Substitute type arguments for type variables. - Map<String, MemberMirror> get members => originalDeclaration.members; - - bool get isObject => mirrors.compiler.objectClass == _type.element; - - bool get isDynamic => mirrors.compiler.dynamicClass == _type.element; - - ClassMirror get originalDeclaration - => new Dart2JsClassMirror(mirrors, _type.element); - - // TODO(johnniwinther): Substitute type arguments for type variables. - ClassMirror get superclass => originalDeclaration.superclass; - - // TODO(johnniwinther): Substitute type arguments for type variables. - List<ClassMirror> get superinterfaces => originalDeclaration.superinterfaces; - - bool get isClass => originalDeclaration.isClass; - - bool get isInterface => originalDeclaration.isInterface; - - bool get isAbstract => originalDeclaration.isAbstract; - - bool get isPrivate => originalDeclaration.isPrivate; - - bool get isOriginalDeclaration => false; - - List<TypeMirror> get typeArguments { - if (_typeArguments == null) { - _typeArguments = <TypeMirror>[]; - if (!_interfaceType.isRaw) { - Link<DartType> type = _interfaceType.typeArguments; - while (type != null && type.head != null) { - _typeArguments.add(_convertTypeToTypeMirror(mirrors, type.head, - mirrors.compiler.types.dynamicType)); - type = type.tail; - } - } - } - return _typeArguments; - } - - List<TypeVariableMirror> get typeVariables => - originalDeclaration.typeVariables; - - // TODO(johnniwinther): Substitute type arguments for type variables. - Map<String, MethodMirror> get constructors => - originalDeclaration.constructors; - - // TODO(johnniwinther): Substitute type arguments for type variables. - Map<String, MethodMirror> get methods => originalDeclaration.methods; - - // TODO(johnniwinther): Substitute type arguments for type variables. - Map<String, MethodMirror> get setters => originalDeclaration.setters; - - // TODO(johnniwinther): Substitute type arguments for type variables. - Map<String, MethodMirror> get getters => originalDeclaration.getters; - - // TODO(johnniwinther): Substitute type arguments for type variables. - Map<String, VariableMirror> get variables => originalDeclaration.variables; - - // TODO(johnniwinther): Substitute type arguments for type variables? - ClassMirror get defaultFactory => originalDeclaration.defaultFactory; - - bool operator ==(Object other) { - if (identical(this, other)) { - return true; - } - if (other is! ClassMirror) { - return false; - } - if (other.isOriginalDeclaration) { - return false; - } - if (originalDeclaration != other.originalDeclaration) { - return false; - } - var thisTypeArguments = typeArguments.iterator; - var otherTypeArguments = other.typeArguments.iterator; - while (thisTypeArguments.moveNext()) { - if (!otherTypeArguments.moveNext()) return false; - if (thisTypeArguments.current != otherTypeArguments.current) { - return false; - } - } - return !otherTypeArguments.moveNext(); - } -} - - -class Dart2JsFunctionTypeMirror extends Dart2JsTypeElementMirror - implements FunctionTypeMirror { - final FunctionSignature _functionSignature; - List<ParameterMirror> _parameters; - - Dart2JsFunctionTypeMirror(Dart2JsMirrorSystem system, - FunctionType functionType, this._functionSignature) - : super(system, functionType) { - assert (_functionSignature != null); - } - - FunctionType get _functionType => _type; - - // TODO(johnniwinther): Is this the qualified name of a function type? - String get qualifiedName => originalDeclaration.qualifiedName; - - // TODO(johnniwinther): Substitute type arguments for type variables. - Map<String, MemberMirror> get members { - var method = callMethod; - if (method != null) { - var map = new Map<String, MemberMirror>.from( - originalDeclaration.members); - var name = method.qualifiedName; - assert(!map.containsKey(name)); - map[name] = method; - return new ImmutableMapWrapper<String, MemberMirror>(map); - } - return originalDeclaration.members; - } - - bool get isFunction => true; - - MethodMirror get callMethod => _convertElementMethodToMethodMirror( - mirrors._getLibrary(_functionType.element.getLibrary()), - _functionType.element); - - ClassMirror get originalDeclaration - => new Dart2JsClassMirror(mirrors, mirrors.compiler.functionClass); - - // TODO(johnniwinther): Substitute type arguments for type variables. - ClassMirror get superclass => originalDeclaration.superclass; - - // TODO(johnniwinther): Substitute type arguments for type variables. - List<ClassMirror> get superinterfaces => originalDeclaration.superinterfaces; - - bool get isClass => originalDeclaration.isClass; - - bool get isInterface => originalDeclaration.isInterface; - - bool get isPrivate => originalDeclaration.isPrivate; - - bool get isOriginalDeclaration => false; - - bool get isAbstract => false; - - List<TypeMirror> get typeArguments => const <TypeMirror>[]; - - List<TypeVariableMirror> get typeVariables => - originalDeclaration.typeVariables; - - TypeMirror get returnType { - return _convertTypeToTypeMirror(mirrors, _functionType.returnType, - mirrors.compiler.types.dynamicType); - } - - List<ParameterMirror> get parameters { - if (_parameters == null) { - _parameters = _parametersFromFunctionSignature(mirrors, callMethod, - _functionSignature); - } - return _parameters; - } -} - -class Dart2JsVoidMirror extends Dart2JsTypeElementMirror { - - Dart2JsVoidMirror(Dart2JsMirrorSystem system, VoidType voidType) - : super(system, voidType); - - VoidType get _voidType => _type; - - String get qualifiedName => simpleName; - - /** - * The void type has no location. - */ - SourceLocation get location => null; - - /** - * The void type has no library. - */ - LibraryMirror get library => null; - - bool get isVoid => true; - - bool operator ==(Object other) { - if (identical(this, other)) { - return true; - } - if (other is! TypeMirror) { - return false; - } - return other.isVoid; - } -} - - -class Dart2JsDynamicMirror extends Dart2JsTypeElementMirror { - Dart2JsDynamicMirror(Dart2JsMirrorSystem system, InterfaceType voidType) - : super(system, voidType); - - InterfaceType get _dynamicType => _type; - - String get qualifiedName => simpleName; - - /** - * The dynamic type has no location. - */ - SourceLocation get location => null; - - /** - * The dynamic type has no library. - */ - LibraryMirror get library => null; - - bool get isDynamic => true; - - bool operator ==(Object other) { - if (identical(this, other)) { - return true; - } - if (other is! TypeMirror) { - return false; - } - return other.isDynamic; - } -} - -//------------------------------------------------------------------------------ -// Member mirrors implementation. -//------------------------------------------------------------------------------ - -class Dart2JsMethodMirror extends Dart2JsMemberMirror - implements MethodMirror { - final Dart2JsContainerMirror _objectMirror; - final String simpleName; - final String displayName; - final String constructorName; - final String operatorName; - final Dart2JsMethodKind _kind; - - Dart2JsMethodMirror._internal(Dart2JsContainerMirror objectMirror, - FunctionElement function, - String this.simpleName, - String this.displayName, - String this.constructorName, - String this.operatorName, - Dart2JsMethodKind this._kind) - : this._objectMirror = objectMirror, - super(objectMirror.mirrors, function); - - factory Dart2JsMethodMirror(Dart2JsContainerMirror objectMirror, - FunctionElement function) { - String realName = function.name.slowToString(); - // TODO(ahe): This method should not be calling - // Elements.operatorNameToIdentifier. - String simpleName = - Elements.operatorNameToIdentifier(function.name).slowToString(); - String displayName; - String constructorName = null; - String operatorName = null; - Dart2JsMethodKind kind; - if (function.kind == ElementKind.GETTER) { - kind = Dart2JsMethodKind.GETTER; - displayName = simpleName; - } else if (function.kind == ElementKind.SETTER) { - kind = Dart2JsMethodKind.SETTER; - displayName = simpleName; - simpleName = '$simpleName='; - } else if (function.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { - // TODO(johnniwinther): Support detection of redirecting constructors. - constructorName = ''; - int dollarPos = simpleName.indexOf('\$'); - if (dollarPos != -1) { - constructorName = simpleName.substring(dollarPos + 1); - simpleName = simpleName.substring(0, dollarPos); - // Simple name is TypeName.constructorName. - simpleName = '$simpleName.$constructorName'; - } else { - // Simple name is TypeName. - } - if (function.modifiers.isConst()) { - kind = Dart2JsMethodKind.CONST; - } else { - kind = Dart2JsMethodKind.GENERATIVE; - } - displayName = simpleName; - } else if (function.modifiers.isFactory()) { - kind = Dart2JsMethodKind.FACTORY; - constructorName = ''; - int dollarPos = simpleName.indexOf('\$'); - if (dollarPos != -1) { - constructorName = simpleName.substring(dollarPos+1); - simpleName = simpleName.substring(0, dollarPos); - simpleName = '$simpleName.$constructorName'; - } - // Simple name is TypeName.constructorName. - displayName = simpleName; - } else if (realName == 'unary-') { - kind = Dart2JsMethodKind.OPERATOR; - operatorName = '-'; - // Simple name is 'unary-'. - simpleName = Mirror.UNARY_MINUS; - // Display name is 'operator operatorName'. - displayName = 'operator -'; - } else if (simpleName.startsWith('operator\$')) { - String str = simpleName.substring(9); - simpleName = 'operator'; - kind = Dart2JsMethodKind.OPERATOR; - operatorName = _getOperatorFromOperatorName(str); - // Simple name is 'operator operatorName'. - simpleName = operatorName; - // Display name is 'operator operatorName'. - displayName = 'operator $operatorName'; - } else { - kind = Dart2JsMethodKind.REGULAR; - displayName = simpleName; - } - return new Dart2JsMethodMirror._internal(objectMirror, function, - simpleName, displayName, constructorName, operatorName, kind); - } - - FunctionElement get _function => _element; - - String get qualifiedName - => '${owner.qualifiedName}.$simpleName'; - - DeclarationMirror get owner => _objectMirror; - - bool get isTopLevel => _objectMirror is LibraryMirror; - - bool get isConstructor - => isGenerativeConstructor || isConstConstructor || - isFactoryConstructor || isRedirectingConstructor; - - bool get isMethod => !isConstructor; - - bool get isPrivate => - isConstructor ? _isPrivate(constructorName) : _isPrivate(simpleName); - - bool get isStatic => _function.modifiers.isStatic(); - - List<ParameterMirror> get parameters { - return _parametersFromFunctionSignature(mirrors, this, - _function.computeSignature(mirrors.compiler)); - } - - TypeMirror get returnType => _convertTypeToTypeMirror( - mirrors, _function.computeSignature(mirrors.compiler).returnType, - mirrors.compiler.types.dynamicType); - - bool get isAbstract => _function.isAbstract(mirrors.compiler); - - bool get isRegularMethod => !(isGetter || isSetter || isConstructor); - - bool get isConstConstructor => _kind == Dart2JsMethodKind.CONST; - - bool get isGenerativeConstructor => _kind == Dart2JsMethodKind.GENERATIVE; - - bool get isRedirectingConstructor => _kind == Dart2JsMethodKind.REDIRECTING; - - bool get isFactoryConstructor => _kind == Dart2JsMethodKind.FACTORY; - - bool get isGetter => _kind == Dart2JsMethodKind.GETTER; - - bool get isSetter => _kind == Dart2JsMethodKind.SETTER; - - bool get isOperator => _kind == Dart2JsMethodKind.OPERATOR; -} - -class Dart2JsFieldMirror extends Dart2JsMemberMirror implements VariableMirror { - Dart2JsContainerMirror _objectMirror; - VariableElement _variable; - - Dart2JsFieldMirror(Dart2JsContainerMirror objectMirror, - VariableElement variable) - : this._objectMirror = objectMirror, - this._variable = variable, - super(objectMirror.mirrors, variable); - - String get qualifiedName - => '${owner.qualifiedName}.$simpleName'; - - DeclarationMirror get owner => _objectMirror; - - bool get isTopLevel => _objectMirror is LibraryMirror; - - bool get isVariable => true; - - bool get isStatic => _variable.modifiers.isStatic(); - - bool get isFinal => _variable.modifiers.isFinal(); - - bool get isConst => _variable.modifiers.isConst(); - - TypeMirror get type => _convertTypeToTypeMirror(mirrors, - _variable.computeType(mirrors.compiler), - mirrors.compiler.types.dynamicType); -} - -//////////////////////////////////////////////////////////////////////////////// -// Mirrors on constant values used for metadata. -//////////////////////////////////////////////////////////////////////////////// - -class Dart2JsConstantMirror extends InstanceMirror { - final Dart2JsMirrorSystem mirrors; - final Constant _constant; - - Dart2JsConstantMirror(this.mirrors, this._constant); - - ClassMirror get type { - return new Dart2JsClassMirror(mirrors, - _constant.computeType(mirrors.compiler).element); - } - - bool get hasReflectee => false; - - get reflectee { - // TODO(johnniwinther): Which exception/error should be thrown here? - throw new UnsupportedError('InstanceMirror does not have a reflectee'); - } - - Future<InstanceMirror> getField(String fieldName) { - // TODO(johnniwinther): Which exception/error should be thrown here? - throw new UnsupportedError('InstanceMirror does not have a reflectee'); - } -} - -class Dart2JsNullConstantMirror extends Dart2JsConstantMirror { - Dart2JsNullConstantMirror(Dart2JsMirrorSystem mirrors, NullConstant constant) - : super(mirrors, constant); - - NullConstant get _constant => super._constant; - - bool get hasReflectee => true; - - get reflectee => null; -} - -class Dart2JsBoolConstantMirror extends Dart2JsConstantMirror { - Dart2JsBoolConstantMirror(Dart2JsMirrorSystem mirrors, BoolConstant constant) - : super(mirrors, constant); - - Dart2JsBoolConstantMirror.fromBool(Dart2JsMirrorSystem mirrors, bool value) - : super(mirrors, value ? new TrueConstant() : new FalseConstant()); - - BoolConstant get _constant => super._constant; - - bool get hasReflectee => true; - - get reflectee => _constant is TrueConstant; -} - -class Dart2JsStringConstantMirror extends Dart2JsConstantMirror { - Dart2JsStringConstantMirror(Dart2JsMirrorSystem mirrors, - StringConstant constant) - : super(mirrors, constant); - - Dart2JsStringConstantMirror.fromString(Dart2JsMirrorSystem mirrors, - String text) - : super(mirrors, - new StringConstant(new DartString.literal(text), null)); - - StringConstant get _constant => super._constant; - - bool get hasReflectee => true; - - get reflectee => _constant.value.slowToString(); -} - -class Dart2JsNumConstantMirror extends Dart2JsConstantMirror { - Dart2JsNumConstantMirror(Dart2JsMirrorSystem mirrors, - NumConstant constant) - : super(mirrors, constant); - - NumConstant get _constant => super._constant; - - bool get hasReflectee => true; - - get reflectee => _constant.value; -} - -class Dart2JsListConstantMirror extends Dart2JsConstantMirror - implements ListInstanceMirror { - Dart2JsListConstantMirror(Dart2JsMirrorSystem mirrors, - ListConstant constant) - : super(mirrors, constant); - - ListConstant get _constant => super._constant; - - int get length => _constant.length; - - Future<InstanceMirror> operator[](int index) { - if (index < 0) throw new RangeError('Negative index'); - if (index >= _constant.length) throw new RangeError('Index out of bounds'); - return new Future<InstanceMirror>.immediate( - _convertConstantToInstanceMirror(mirrors, _constant.entries[index])); - } -} - -class Dart2JsMapConstantMirror extends Dart2JsConstantMirror - implements MapInstanceMirror { - List<String> _listCache; - - Dart2JsMapConstantMirror(Dart2JsMirrorSystem mirrors, - MapConstant constant) - : super(mirrors, constant); - - MapConstant get _constant => super._constant; - - List<String> get _list { - if (_listCache == null) { - _listCache = new List<String>(_constant.keys.entries.length); - int index = 0; - for (StringConstant keyConstant in _constant.keys.entries) { - _listCache[index] = keyConstant.value.slowToString(); - index++; - } - } - return _listCache; - } - - int get length => _constant.length; - - Collection<String> get keys { - // TODO(johnniwinther): Return an unmodifiable list instead. - return new List<String>.from(_list); - } - - Future<InstanceMirror> operator[](String key) { - int index = _list.indexOf(key); - if (index == -1) return null; - return new Future<InstanceMirror>.immediate( - _convertConstantToInstanceMirror(mirrors, _constant.values[index])); - } -} - -class Dart2JsTypeConstantMirror extends Dart2JsConstantMirror - implements TypeInstanceMirror { - - Dart2JsTypeConstantMirror(Dart2JsMirrorSystem mirrors, - TypeConstant constant) - : super(mirrors, constant); - - TypeConstant get _constant => super._constant; - - TypeMirror get representedType => _convertTypeToTypeMirror( - mirrors, _constant.representedType, mirrors.compiler.types.dynamicType); -} - -class Dart2JsConstructedConstantMirror extends Dart2JsConstantMirror { - Map<String,Constant> _fieldMapCache; - - Dart2JsConstructedConstantMirror(Dart2JsMirrorSystem mirrors, - ConstructedConstant constant) - : super(mirrors, constant); - - ConstructedConstant get _constant => super._constant; - - Map<String,Constant> get _fieldMap { - if (_fieldMapCache == null) { - _fieldMapCache = new LinkedHashMap<String,Constant>(); - if (identical(_constant.type.element.kind, ElementKind.CLASS)) { - var index = 0; - ClassElement element = _constant.type.element; - element.forEachInstanceField((_, Element field) { - String fieldName = field.name.slowToString(); - _fieldMapCache.putIfAbsent(fieldName, () => _constant.fields[index]); - index++; - }, includeBackendMembers: true, includeSuperMembers: true); - } - } - return _fieldMapCache; - } - - Future<InstanceMirror> getField(String fieldName) { - Constant fieldConstant = _fieldMap[fieldName]; - if (fieldConstant != null) { - return new Future<InstanceMirror>.immediate( - _convertConstantToInstanceMirror(mirrors, fieldConstant)); - } - return super.getField(fieldName); - } -} - -class Dart2JsCommentInstanceMirror implements CommentInstanceMirror { - final Dart2JsMirrorSystem mirrors; - final String text; - String _trimmedText; - - Dart2JsCommentInstanceMirror(this.mirrors, this.text); - - ClassMirror get type { - return new Dart2JsClassMirror(mirrors, mirrors.compiler.documentClass); - } - - bool get isDocComment => text.startsWith('/**') || text.startsWith('///'); - - String get trimmedText { - if (_trimmedText == null) { - _trimmedText = stripComment(text); - } - return _trimmedText; - } - - bool get hasReflectee => false; - - get reflectee { - // TODO(johnniwinther): Which exception/error should be thrown here? - throw new UnsupportedError('InstanceMirror does not have a reflectee'); - } - - Future<InstanceMirror> getField(String fieldName) { - if (fieldName == 'isDocComment') { - return new Future.immediate( - new Dart2JsBoolConstantMirror.fromBool(mirrors, isDocComment)); - } else if (fieldName == 'text') { - return new Future.immediate( - new Dart2JsStringConstantMirror.fromString(mirrors, text)); - } else if (fieldName == 'trimmedText') { - return new Future.immediate( - new Dart2JsStringConstantMirror.fromString(mirrors, trimmedText)); - } - // TODO(johnniwinther): Which exception/error should be thrown here? - throw new UnsupportedError('InstanceMirror does not have a reflectee'); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/mirrors/mirrors.dart b/pkgs/markdown/test/lib/src/compiler/implementation/mirrors/mirrors.dart deleted file mode 100644 index 6f5189e..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/mirrors/mirrors.dart +++ /dev/null
@@ -1,738 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library mirrors; - -import 'dart:async'; -import 'dart:io'; -import 'dart:uri'; - -// TODO(rnystrom): Use "package:" URL (#4968). -import 'dart2js_mirror.dart'; - -/** - * [Compilation] encapsulates the compilation of a program. - */ -abstract class Compilation { - /** - * Creates a new compilation which has [script] as its entry point. - */ - factory Compilation(Path script, - Path libraryRoot, - [Path packageRoot, - List<String> opts = const <String>[]]) { - return new Dart2JsCompilation(script, libraryRoot, packageRoot, opts); - } - - /** - * Creates a new compilation which consists of a set of libraries, but which - * has no entry point. This compilation cannot generate output but can only - * be used for static inspection of the source code. - */ - factory Compilation.library(List<Path> libraries, - Path libraryRoot, - [Path packageRoot, - List<String> opts = const []]) { - return new Dart2JsCompilation.library(libraries, libraryRoot, - packageRoot, opts); - } - - /** - * Returns the mirror system for this compilation. - */ - final MirrorSystem mirrors; - - /** - * Returns a future for the compiled JavaScript code. - */ - Future<String> compileToJavaScript(); -} - -/** - * The main interface for the whole mirror system. - */ -abstract class MirrorSystem { - /** - * Returns an unmodifiable map of all libraries in this mirror system. - */ - Map<String, LibraryMirror> get libraries; - - /** - * A mirror on the [:dynamic:] type. - */ - TypeMirror get dynamicType; - - /** - * A mirror on the [:void:] type. - */ - TypeMirror get voidType; -} - - -/** - * An entity in the mirror system. - */ -abstract class Mirror { - static const String UNARY_MINUS = 'unary-'; - - // TODO(johnniwinther): Do we need this on all mirrors? - /** - * Returns the mirror system which contains this mirror. - */ - MirrorSystem get mirrors; -} - -abstract class DeclarationMirror implements Mirror { - /** - * The simple name of the entity. The simple name is unique within the - * scope of the entity declaration. - * - * The simple name is in most cases the declared single identifier name of - * the entity, such as 'method' for a method [:void method() {...}:]. For an - * unnamed constructor for [:class Foo:] the simple name is 'Foo'. For a - * constructor for [:class Foo:] named 'named' the simple name is 'Foo.named'. - * For a property [:foo:] the simple name of the getter method is 'foo' and - * the simple name of the setter is 'foo='. For operators the simple name is - * the operator itself, for example '+' for [:operator +:]. - * - * The simple name for the unary minus operator is [UNARY_MINUS]. - */ - String get simpleName; - - /** - * The display name is the normal representation of the entity name. In most - * cases the display name is the simple name, but for a setter 'foo=' the - * display name is simply 'foo' and for the unary minus operator the display - * name is 'operator -'. The display name is not unique. - */ - String get displayName; - - /** - * Returns the name of this entity qualified by is enclosing context. For - * instance, the qualified name of a method 'method' in class 'Class' in - * library 'library' is 'library.Class.method'. - */ - String get qualifiedName; - - /** - * The source location of this Dart language entity. - */ - SourceLocation get location; - - /** - * A mirror on the owner of this function. This is the declaration immediately - * surrounding the reflectee. - * - * Note that for libraries, the owner will be [:null:]. - */ - DeclarationMirror get owner; - - /** - * Is this declaration private? - * - * Note that for libraries, this will be [:false:]. - */ - bool get isPrivate; - - /** - * Is this declaration top-level? - * - * This is defined to be equivalent to: - * [:mirror.owner != null && mirror.owner is LibraryMirror:] - */ - bool get isTopLevel; - - /** - * A list of the metadata associated with this declaration. - */ - List<InstanceMirror> get metadata; -} - -abstract class ObjectMirror implements Mirror { - /** - * Invokes a getter and returns a mirror on the result. The getter - * can be the implicit getter for a field or a user-defined getter - * method. - */ - Future<InstanceMirror> getField(String fieldName); -} - -/** - * An [InstanceMirror] reflects an instance of a Dart language object. - */ -abstract class InstanceMirror implements ObjectMirror { - /** - * A mirror on the type of the reflectee. - */ - ClassMirror get type; - - /** - * Does [reflectee] contain the instance reflected by this mirror? - * This will always be true in the local case (reflecting instances - * in the same isolate), but only true in the remote case if this - * mirror reflects a simple value. - * - * A value is simple if one of the following holds: - * - the value is null - * - the value is of type [num] - * - the value is of type [bool] - * - the value is of type [String] - */ - bool get hasReflectee; - - /** - * If the [InstanceMirror] reflects an instance it is meaningful to - * have a local reference to, we provide access to the actual - * instance here. - * - * If you access [reflectee] when [hasReflectee] is false, an - * exception is thrown. - */ - get reflectee; -} - -/** - * Specialized [InstanceMirror] used for reflection on constant lists. - */ -abstract class ListInstanceMirror implements InstanceMirror { - Future<InstanceMirror> operator[](int index); - int get length; -} - -/** - * Specialized [InstanceMirror] used for reflection on constant maps. - */ -abstract class MapInstanceMirror implements InstanceMirror { - /** - * Returns a collection containing all the keys in the map. - */ - Collection<String> get keys; - - /** - * Returns a future on the instance mirror of the value for the given key or - * null if key is not in the map. - */ - Future<InstanceMirror> operator[](String key); - - /** - * The number of {key, value} pairs in the map. - */ - int get length; -} - -/** - * Specialized [InstanceMirror] used for reflection on type constants. - */ -abstract class TypeInstanceMirror implements InstanceMirror { - /** - * Returns the type mirror for the type represented by the reflected type - * constant. - */ - TypeMirror get representedType; -} - -/** - * Specialized [InstanceMirror] used for reflection on comments as metadata. - */ -abstract class CommentInstanceMirror implements InstanceMirror { - /** - * The comment text as written in the source text. - */ - String get text; - - /** - * The comment text without the start, end, and padding text. - * - * For example, if [text] is [: /** Comment text. */ :] then the [trimmedText] - * is [: Comment text. :]. - */ - String get trimmedText; - - /** - * Is [:true:] if this comment is a documentation comment. - * - * That is, that the comment is either enclosed in [: /** ... */ :] or starts - * with [: /// :]. - */ - bool get isDocComment; -} - -/** - * Common interface for classes and libraries. - */ -abstract class ContainerMirror implements Mirror { - - /** - * An immutable map from from names to mirrors for all members in this - * container. - */ - Map<String, MemberMirror> get members; -} - -/** - * A library. - */ -abstract class LibraryMirror implements ContainerMirror, DeclarationMirror { - /** - * An immutable map from from names to mirrors for all members in this - * library. - * - * The members of a library are its top-level classes, functions, variables, - * getters, and setters. - */ - Map<String, MemberMirror> get members; - - /** - * An immutable map from names to mirrors for all class - * declarations in this library. - */ - Map<String, ClassMirror> get classes; - - /** - * An immutable map from names to mirrors for all function, getter, - * and setter declarations in this library. - */ - Map<String, MethodMirror> get functions; - - /** - * An immutable map from names to mirrors for all getter - * declarations in this library. - */ - Map<String, MethodMirror> get getters; - - /** - * An immutable map from names to mirrors for all setter - * declarations in this library. - */ - Map<String, MethodMirror> get setters; - - /** - * An immutable map from names to mirrors for all variable - * declarations in this library. - */ - Map<String, VariableMirror> get variables; - - /** - * Returns the canonical URI for this library. - */ - Uri get uri; -} - -/** - * Common interface for classes, interfaces, typedefs and type variables. - */ -abstract class TypeMirror implements DeclarationMirror { - /** - * Returns the library in which this member resides. - */ - LibraryMirror get library; - - /** - * Is [:true:] iff this type is the [:Object:] type. - */ - bool get isObject; - - /** - * Is [:true:] iff this type is the [:dynamic:] type. - */ - bool get isDynamic; - - /** - * Is [:true:] iff this type is the void type. - */ - bool get isVoid; - - /** - * Is [:true:] iff this type is a type variable. - */ - bool get isTypeVariable; - - /** - * Is [:true:] iff this type is a typedef. - */ - bool get isTypedef; - - /** - * Is [:true:] iff this type is a function type. - */ - bool get isFunction; -} - -/** - * A class or interface type. - */ -abstract class ClassMirror implements TypeMirror, ContainerMirror { - /** - * A mirror on the original declaration of this type. - * - * For most classes, they are their own original declaration. For - * generic classes, however, there is a distinction between the - * original class declaration, which has unbound type variables, and - * the instantiations of generic classes, which have bound type - * variables. - */ - ClassMirror get originalDeclaration; - - /** - * Returns the super class of this type, or null if this type is [Object] or a - * typedef. - */ - ClassMirror get superclass; - - /** - * Returns a list of the interfaces directly implemented by this type. - */ - List<ClassMirror> get superinterfaces; - - /** - * Is [:true:] iff this type is a class. - */ - bool get isClass; - - /** - * Is [:true:] iff this type is an interface. - */ - bool get isInterface; - - /** - * Is this the original declaration of this type? - * - * For most classes, they are their own original declaration. For - * generic classes, however, there is a distinction between the - * original class declaration, which has unbound type variables, and - * the instantiations of generic classes, which have bound type - * variables. - */ - bool get isOriginalDeclaration; - - /** - * Is [:true:] if this class is declared abstract. - */ - bool get isAbstract; - - /** - * Returns a list of the type arguments for this type. - */ - List<TypeMirror> get typeArguments; - - /** - * Returns the list of type variables for this type. - */ - List<TypeVariableMirror> get typeVariables; - - /** - * An immutable map from from names to mirrors for all members of - * this type. - * - * The members of a type are its methods, fields, getters, and - * setters. Note that constructors and type variables are not - * considered to be members of a type. - * - * This does not include inherited members. - */ - Map<String, MemberMirror> get members; - - /** - * An immutable map from names to mirrors for all method, - * declarations for this type. This does not include getters and - * setters. - */ - Map<String, MethodMirror> get methods; - - /** - * An immutable map from names to mirrors for all getter - * declarations for this type. - */ - Map<String, MethodMirror> get getters; - - /** - * An immutable map from names to mirrors for all setter - * declarations for this type. - */ - Map<String, MethodMirror> get setters; - - /** - * An immutable map from names to mirrors for all variable - * declarations for this type. - */ - Map<String, VariableMirror> get variables; - - /** - * An immutable map from names to mirrors for all constructor - * declarations for this type. - */ - Map<String, MethodMirror> get constructors; - - /** - * Returns the default type for this interface. - */ - ClassMirror get defaultFactory; -} - -/** - * A type parameter as declared on a generic type. - */ -abstract class TypeVariableMirror implements TypeMirror { - /** - * Returns the bound of the type parameter. - */ - TypeMirror get upperBound; -} - -/** - * A function type. - */ -abstract class FunctionTypeMirror implements ClassMirror { - /** - * Returns the return type of this function type. - */ - TypeMirror get returnType; - - /** - * Returns the parameters for this function type. - */ - List<ParameterMirror> get parameters; - - /** - * Returns the call method for this function type. - */ - MethodMirror get callMethod; -} - -/** - * A typedef. - */ -abstract class TypedefMirror implements ClassMirror { - /** - * The defining type for this typedef. - * - * For instance [:void f(int):] for a [:typedef void f(int):]. - */ - TypeMirror get value; -} - -/** - * A member of a type, i.e. a field, method or constructor. - */ -abstract class MemberMirror implements DeclarationMirror { - /** - * Is this member a constructor? - */ - bool get isConstructor; - - /** - * Is this member a variable? - * - * This is [:false:] for locals. - */ - bool get isVariable; - - /** - * Is this member a method?. - * - * This is [:false:] for constructors. - */ - bool get isMethod; - - /** - * Is this member declared static? - */ - bool get isStatic; - - /** - * Is this member a parameter? - */ - bool get isParameter; -} - -/** - * A field. - */ -abstract class VariableMirror implements MemberMirror { - - /** - * Returns true if this field is final. - */ - bool get isFinal; - - /** - * Returns true if this field is const. - */ - bool get isConst; - - /** - * Returns the type of this field. - */ - TypeMirror get type; -} - -/** - * Common interface constructors and methods, including factories, getters and - * setters. - */ -abstract class MethodMirror implements MemberMirror { - /** - * Returns the list of parameters for this method. - */ - List<ParameterMirror> get parameters; - - /** - * Returns the return type of this method. - */ - TypeMirror get returnType; - - /** - * Is the reflectee abstract? - */ - bool get isAbstract; - - /** - * Is the reflectee a regular function or method? - * - * A function or method is regular if it is not a getter, setter, or - * constructor. Note that operators, by this definition, are - * regular methods. - */ - bool get isRegularMethod; - - /** - * Is the reflectee a const constructor? - */ - bool get isConstConstructor; - - /** - * Is the reflectee a generative constructor? - */ - bool get isGenerativeConstructor; - - /** - * Is the reflectee a redirecting constructor? - */ - bool get isRedirectingConstructor; - - /** - * Is the reflectee a factory constructor? - */ - bool get isFactoryConstructor; - - /** - * Returns the constructor name for named constructors and factory methods, - * e.g. [:'bar':] for constructor [:Foo.bar:] of type [:Foo:]. - */ - String get constructorName; - - /** - * Is [:true:] if this method is a getter method. - */ - bool get isGetter; - - /** - * Is [:true:] if this method is a setter method. - */ - bool get isSetter; - - /** - * Is [:true:] if this method is an operator method. - */ - bool get isOperator; - - /** - * Returns the operator name for operator methods, e.g. [:'<':] for - * [:operator <:] - */ - String get operatorName; -} - -/** - * A formal parameter. - */ -abstract class ParameterMirror implements VariableMirror { - /** - * Returns the type of this parameter. - */ - TypeMirror get type; - - /** - * Returns the default value for this parameter. - */ - String get defaultValue; - - /** - * Does this parameter have a default value? - */ - bool get hasDefaultValue; - - /** - * Is this parameter optional? - */ - bool get isOptional; - - /** - * Is this parameter named? - */ - bool get isNamed; - - /** - * Returns [:true:] iff this parameter is an initializing formal of a - * constructor. That is, if it is of the form [:this.x:] where [:x:] is a - * field. - */ - bool get isInitializingFormal; - - /** - * Returns the initialized field, if this parameter is an initializing formal. - */ - VariableMirror get initializedField; -} - -/** - * A [SourceLocation] describes the span of an entity in Dart source code. - * A [SourceLocation] with a non-zero [length] should be the minimum span that - * encloses the declaration of the mirrored entity. - */ -abstract class SourceLocation { - /** - * The 1-based line number for this source location. - * - * A value of 0 means that the line number is unknown. - */ - int get line; - - /** - * The 1-based column number for this source location. - * - * A value of 0 means that the column number is unknown. - */ - int get column; - - /** - * The 0-based character offset into the [sourceText] where this source - * location begins. - * - * A value of -1 means that the offset is unknown. - */ - int get offset; - - /** - * The number of characters in this source location. - * - * A value of 0 means that the [offset] is approximate. - */ - int get length; - - /** - * The text of the location span. - */ - String get text; - - /** - * Returns the URI where the source originated. - */ - Uri get sourceUri; - - /** - * Returns the text of this source. - */ - String get sourceText; -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/mirrors/mirrors_util.dart b/pkgs/markdown/test/lib/src/compiler/implementation/mirrors/mirrors_util.dart deleted file mode 100644 index d904089..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/mirrors/mirrors_util.dart +++ /dev/null
@@ -1,161 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library mirrors_util; - -import 'dart:collection' show Queue; - -// TODO(rnystrom): Use "package:" URL (#4968). -import 'mirrors.dart'; - -//------------------------------------------------------------------------------ -// Utility functions for using the Mirror API -//------------------------------------------------------------------------------ - -/** - * Returns an iterable over the type declarations directly inheriting from - * the declaration of this type. - */ -Iterable<ClassMirror> computeSubdeclarations(ClassMirror type) { - type = type.originalDeclaration; - var subtypes = <ClassMirror>[]; - type.mirrors.libraries.forEach((_, library) { - for (ClassMirror otherType in library.classes.values) { - var superClass = otherType.superclass; - if (superClass != null) { - superClass = superClass.originalDeclaration; - if (type.library == superClass.library) { - if (superClass == type) { - subtypes.add(otherType); - } - } - } - final superInterfaces = otherType.superinterfaces; - for (ClassMirror superInterface in superInterfaces) { - superInterface = superInterface.originalDeclaration; - if (type.library == superInterface.library) { - if (superInterface == type) { - subtypes.add(otherType); - } - } - } - } - }); - return subtypes; -} - -LibraryMirror findLibrary(MemberMirror member) { - DeclarationMirror owner = member.owner; - if (owner is LibraryMirror) { - return owner; - } else if (owner is TypeMirror) { - return owner.library; - } - throw new Exception('Unexpected owner: ${owner}'); -} - -class HierarchyIterable extends Iterable<ClassMirror> { - final bool includeType; - final ClassMirror type; - - HierarchyIterable(this.type, {bool includeType}) - : this.includeType = includeType; - - Iterator<ClassMirror> get iterator => - new HierarchyIterator(type, includeType: includeType); -} - -/** - * [HierarchyIterator] iterates through the class hierarchy of the provided - * type. - * - * First the superclass relation is traversed, skipping [Object], next the - * superinterface relation and finally is [Object] visited. The supertypes are - * visited in breadth first order and a superinterface is visited more than once - * if implemented through multiple supertypes. - */ -class HierarchyIterator implements Iterator<ClassMirror> { - final Queue<ClassMirror> queue = new Queue<ClassMirror>(); - ClassMirror object; - ClassMirror _current; - - HierarchyIterator(ClassMirror type, {bool includeType}) { - if (includeType) { - queue.add(type); - } else { - push(type); - } - } - - ClassMirror push(ClassMirror type) { - if (type.superclass != null) { - if (type.superclass.isObject) { - object = type.superclass; - } else { - queue.addFirst(type.superclass); - } - } - queue.addAll(type.superinterfaces); - return type; - } - - ClassMirror get current => _current; - - bool moveNext() { - _current = null; - if (queue.isEmpty) { - if (object == null) return false; - _current = object; - object = null; - return true; - } else { - _current = push(queue.removeFirst()); - return true; - } - } -} - -final RegExp _singleLineCommentStart = new RegExp(r'^///? ?(.*)'); -final RegExp _multiLineCommentStartEnd = - new RegExp(r'^/\*\*? ?([\s\S]*)\*/$', multiLine: true); -final RegExp _multiLineCommentLineStart = new RegExp(r'^[ \t]*\* ?(.*)'); - -/** - * Pulls the raw text out of a comment (i.e. removes the comment - * characters). - */ -String stripComment(String comment) { - Match match = _singleLineCommentStart.firstMatch(comment); - if (match != null) { - return match[1]; - } - match = _multiLineCommentStartEnd.firstMatch(comment); - if (match != null) { - comment = match[1]; - var sb = new StringBuffer(); - List<String> lines = comment.split('\n'); - for (int index = 0 ; index < lines.length ; index++) { - String line = lines[index]; - if (index == 0) { - sb.add(line); // Add the first line unprocessed. - continue; - } - sb.add('\n'); - match = _multiLineCommentLineStart.firstMatch(line); - if (match != null) { - sb.add(match[1]); - } else if (index < lines.length-1 || !line.trim().isEmpty) { - // Do not add the last line if it only contains white space. - // This interprets cases like - // /* - // * Foo - // */ - // as "\nFoo\n" and not as "\nFoo\n ". - sb.add(line); - } - } - return sb.toString(); - } - throw new ArgumentError('Invalid comment $comment'); -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/mirrors/util.dart b/pkgs/markdown/test/lib/src/compiler/implementation/mirrors/util.dart deleted file mode 100644 index 3470211..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/mirrors/util.dart +++ /dev/null
@@ -1,173 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library util; - -/** - * An abstract map implementation. This class can be used as a superclass for - * implementing maps, requiring only the further implementation of the - * [:operator []:], [:forEach:] and [:length:] methods to provide a fully - * implemented immutable map. - */ -abstract class AbstractMap<K,V> implements Map<K,V> { - AbstractMap(); - - AbstractMap.from(Map<K,V> other) { - other.forEach((k,v) => this[k] = v); - } - - void operator []=(K key, value) { - throw new UnsupportedError('[]= is not supported'); - } - - void clear() { - throw new UnsupportedError('clear() is not supported'); - } - - bool containsKey(K key) { - var found = false; - forEach((k,_) { - if (k == key) { - found = true; - } - }); - return found; - } - - bool containsValue(V value) { - var found = false; - forEach((_,v) { - if (v == value) { - found = true; - } - }); - return found; - } - - Collection<K> get keys { - var keys = <K>[]; - forEach((k,_) => keys.add(k)); - return keys; - } - - Collection<V> get values { - var values = <V>[]; - forEach((_,v) => values.add(v)); - return values; - } - - bool get isEmpty => length == 0; - V putIfAbsent(K key, V ifAbsent()) { - if (!containsKey(key)) { - V value = this[key]; - this[key] = ifAbsent(); - return value; - } - return null; - } - - V remove(K key) { - throw new UnsupportedError('V remove(K key) is not supported'); - } -} - -/** - * [ImmutableMapWrapper] wraps a (mutable) map as an immutable map where all - * mutating operations throw [UnsupportedError] upon invocation. - */ -class ImmutableMapWrapper<K,V> extends AbstractMap<K,V> { - final Map<K,V> _map; - - ImmutableMapWrapper(this._map); - - int get length => _map.length; - - V operator [](K key) { - if (key is K) { - return _map[key]; - } - return null; - } - - void forEach(void f(K key, V value)) { - _map.forEach(f); - } -} - -/** - * A [Filter] function returns [:true:] iff [value] should be included. - */ -typedef bool Filter<V>(V value); - -/** - * An immutable map wrapper capable of filtering the input map. - */ -class FilteredImmutableMap<K,V> extends ImmutableMapWrapper<K,V> { - final Filter<V> _filter; - - FilteredImmutableMap(Map<K,V> map, this._filter) : super(map); - - int get length { - var count = 0; - forEach((k,v) { - count++; - }); - return count; - } - - void forEach(void f(K key, V value)) { - _map.forEach((K k, V v) { - if (_filter(v)) { - f(k, v); - } - }); - } -} - -/** - * An [AsFilter] takes a [value] of type [V1] and returns [value] iff it is of - * type [V2] or [:null:] otherwise. An [AsFilter] therefore behaves like the - * [:as:] expression. - */ -typedef V2 AsFilter<V1, V2>(V1 value); - -/** - * An immutable map wrapper capable of filtering the input map based on types. - * It takes an [AsFilter] function which converts the original values of type - * [Vin] into values of type [Vout], or returns [:null:] if the value should - * not be included in the filtered map. - */ -class AsFilteredImmutableMap<K, Vin, Vout> extends AbstractMap<K, Vout> { - final Map<K, Vin> _map; - final AsFilter<Vin, Vout> _filter; - - AsFilteredImmutableMap(this._map, this._filter); - - int get length { - var count = 0; - forEach((k,v) { - count++; - }); - return count; - } - - Vout operator [](K key) { - if (key is K) { - Vin value = _map[key]; - if (value != null) { - return _filter(value); - } - } - return null; - } - - void forEach(void f(K key, Vout value)) { - _map.forEach((K k, Vin v) { - var value = _filter(v); - if (value != null) { - f(k, value); - } - }); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/native_handler.dart b/pkgs/markdown/test/lib/src/compiler/implementation/native_handler.dart deleted file mode 100644 index 373f16e..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/native_handler.dart +++ /dev/null
@@ -1,902 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library native; - -import 'dart:collection' show Queue; -import 'dart:uri'; -import 'dart2jslib.dart' hide SourceString; -import 'dart_types.dart'; -import 'elements/elements.dart'; -import 'js_backend/js_backend.dart'; -import 'resolution/resolution.dart' show ResolverVisitor; -import 'scanner/scannerlib.dart'; -import 'ssa/ssa.dart'; -import 'tree/tree.dart'; -import 'util/util.dart'; - - -/// This class is a temporary work-around until we get a more powerful DartType. -class SpecialType { - final String name; - const SpecialType._(this.name); - - /// The type Object, but no subtypes: - static const JsObject = const SpecialType._('=Object'); - - /// The specific implementation of List that is JavaScript Array: - static const JsArray = const SpecialType._('=List'); -} - - -/** - * This could be an abstract class but we use it as a stub for the dart_backend. - */ -class NativeEnqueuer { - /// Initial entry point to native enqueuer. - void processNativeClasses(Iterable<LibraryElement> libraries) {} - - /// Notification of a main Enqueuer worklist element. For methods, adds - /// information from metadata attributes, and computes types instantiated due - /// to calling the method. - void registerElement(Element element) {} - - /// Notification of native field. Adds information from metadata attributes. - void handleFieldAnnotations(Element field) {} - - /// Computes types instantiated due to getting a native field. - void registerFieldLoad(Element field) {} - - /// Computes types instantiated due to setting a native field. - void registerFieldStore(Element field) {} - - NativeBehavior getNativeBehaviorOf(Send node) => null; - - /** - * Handles JS-calls, which can be an instantiation point for types. - * - * For example, the following code instantiates and returns native classes - * that are `_DOMWindowImpl` or a subtype. - * - * JS('_DOMWindowImpl', 'window') - * - */ - // TODO(sra): The entry from codegen will not have a resolver. - void registerJsCall(Send node, ResolverVisitor resolver) {} - - /// Emits a summary information using the [log] function. - void logSummary(log(message)) {} -} - - -abstract class NativeEnqueuerBase implements NativeEnqueuer { - - /** - * The set of all native classes. Each native class is in [nativeClasses] and - * exactly one of [unusedClasses], [pendingClasses] and [registeredClasses]. - */ - final Set<ClassElement> nativeClasses = new Set<ClassElement>(); - - final Set<ClassElement> registeredClasses = new Set<ClassElement>(); - final Set<ClassElement> pendingClasses = new Set<ClassElement>(); - final Set<ClassElement> unusedClasses = new Set<ClassElement>(); - - /** - * Records matched constraints ([SpecialType] or [DartType]). Once a type - * constraint has been matched, there is no need to match it again. - */ - final Set matchedTypeConstraints = new Set(); - - /// Pending actions. Classes in [pendingClasses] have action thunks in - /// [queue] to register the class. - final queue = new Queue(); - bool flushing = false; - - /// Maps JS foreign calls to their computed native behavior. - final Map<Node, NativeBehavior> nativeBehaviors = - new Map<Node, NativeBehavior>(); - - final Enqueuer world; - final Compiler compiler; - final bool enableLiveTypeAnalysis; - - ClassElement _annotationCreatesClass; - ClassElement _annotationReturnsClass; - ClassElement _annotationJsNameClass; - - /// Subclasses of [NativeEnqueuerBase] are constructed by the backend. - NativeEnqueuerBase(this.world, this.compiler, this.enableLiveTypeAnalysis); - - void processNativeClasses(Iterable<LibraryElement> libraries) { - libraries.forEach(processNativeClassesInLibrary); - processNativeClassesInLibrary(compiler.isolateHelperLibrary); - if (!enableLiveTypeAnalysis) { - nativeClasses.forEach((c) => enqueueClass(c, 'forced')); - flushQueue(); - } - } - - void processNativeClassesInLibrary(LibraryElement library) { - // Use implementation to ensure the inclusion of injected members. - library.implementation.forEachLocalMember((Element element) { - if (element.isClass() && element.isNative()) { - processNativeClass(element); - } - }); - } - - void processNativeClass(ClassElement classElement) { - nativeClasses.add(classElement); - unusedClasses.add(classElement); - // Resolve class to ensure the class has valid inheritance info. - classElement.ensureResolved(compiler); - } - - ClassElement get annotationCreatesClass { - findAnnotationClasses(); - return _annotationCreatesClass; - } - - ClassElement get annotationReturnsClass { - findAnnotationClasses(); - return _annotationReturnsClass; - } - - ClassElement get annotationJsNameClass { - findAnnotationClasses(); - return _annotationJsNameClass; - } - - void findAnnotationClasses() { - if (_annotationCreatesClass != null) return; - ClassElement find(name) { - Element e = compiler.findHelper(name); - if (e == null || e is! ClassElement) { - compiler.cancel("Could not find implementation class '${name}'"); - } - return e; - } - _annotationCreatesClass = find(const SourceString('Creates')); - _annotationReturnsClass = find(const SourceString('Returns')); - _annotationJsNameClass = find(const SourceString('JSName')); - } - - /// Returns the JSName annotation string or `null` if no JSName annotation is - /// present. - String findJsNameFromAnnotation(Element element) { - String name = null; - ClassElement annotationClass = annotationJsNameClass; - for (Link<MetadataAnnotation> link = element.metadata; - !link.isEmpty; - link = link.tail) { - MetadataAnnotation annotation = link.head.ensureResolved(compiler); - var value = annotation.value; - if (value is! ConstructedConstant) continue; - if (value.type is! InterfaceType) continue; - if (!identical(value.type.element, annotationClass)) continue; - - var fields = value.fields; - // TODO(sra): Better validation of the constant. - if (fields.length != 1 || fields[0] is! StringConstant) { - PartialMetadataAnnotation partial = annotation; - compiler.cancel( - 'Annotations needs one string: ${partial.parseNode(compiler)}'); - } - String specString = fields[0].toDartString().slowToString(); - if (name == null) { - name = specString; - } else { - PartialMetadataAnnotation partial = annotation; - compiler.cancel( - 'Too many JSName annotations: ${partial.parseNode(compiler)}'); - } - } - return name; - } - - enqueueClass(ClassElement classElement, cause) { - assert(unusedClasses.contains(classElement)); - unusedClasses.remove(classElement); - pendingClasses.add(classElement); - queue.add(() { processClass(classElement, cause); }); - } - - void flushQueue() { - if (flushing) return; - flushing = true; - while (!queue.isEmpty) { - (queue.removeFirst())(); - } - flushing = false; - } - - processClass(ClassElement classElement, cause) { - assert(!registeredClasses.contains(classElement)); - - bool firstTime = registeredClasses.isEmpty; - pendingClasses.remove(classElement); - registeredClasses.add(classElement); - - world.registerInstantiatedClass(classElement); - - // Also parse the node to know all its methods because otherwise it will - // only be parsed if there is a call to one of its constructors. - classElement.parseNode(compiler); - - if (firstTime) { - queue.add(onFirstNativeClass); - } - } - - registerElement(Element element) { - compiler.withCurrentElement(element, () { - if (element.isFunction() || element.isGetter() || element.isSetter()) { - handleMethodAnnotations(element); - if (element.isNative()) { - registerMethodUsed(element); - } - } else if (element.isField()) { - handleFieldAnnotations(element); - if (element.isNative()) { - registerFieldLoad(element); - registerFieldStore(element); - } - } - }); - } - - handleFieldAnnotations(Element element) { - if (element.enclosingElement.isNative()) { - // Exclude non-instance (static) fields - they not really native and are - // compiled as isolate globals. Access of a property of a constructor - // function or a non-method property in the prototype chain, must be coded - // using a JS-call. - if (element.isInstanceMember()) { - setNativeName(element); - } - } - } - - handleMethodAnnotations(Element method) { - if (isNativeMethod(method)) { - setNativeName(method); - } - } - - /// Sets the native name of [element], either from an annotation, or - /// defaulting to the Dart name. - void setNativeName(Element element) { - String name = findJsNameFromAnnotation(element); - if (name == null) name = element.name.slowToString(); - element.setNative(name); - } - - bool isNativeMethod(Element element) { - if (!element.getLibrary().canUseNative) return false; - // Native method? - return compiler.withCurrentElement(element, () { - Node node = element.parseNode(compiler); - if (node is! FunctionExpression) return false; - node = node.body; - Token token = node.getBeginToken(); - if (identical(token.stringValue, 'native')) return true; - return false; - }); - } - - void registerMethodUsed(Element method) { - processNativeBehavior( - NativeBehavior.ofMethod(method, compiler), - method); - flushQueue(); - } - - void registerFieldLoad(Element field) { - processNativeBehavior( - NativeBehavior.ofFieldLoad(field, compiler), - field); - flushQueue(); - } - - void registerFieldStore(Element field) { - processNativeBehavior( - NativeBehavior.ofFieldStore(field, compiler), - field); - flushQueue(); - } - - void registerJsCall(Send node, ResolverVisitor resolver) { - NativeBehavior behavior = NativeBehavior.ofJsCall(node, compiler, resolver); - processNativeBehavior(behavior, node); - nativeBehaviors[node] = behavior; - flushQueue(); - } - - NativeBehavior getNativeBehaviorOf(Send node) => nativeBehaviors[node]; - - processNativeBehavior(NativeBehavior behavior, cause) { - bool allUsedBefore = unusedClasses.isEmpty; - for (var type in behavior.typesInstantiated) { - if (matchedTypeConstraints.contains(type)) continue; - matchedTypeConstraints.add(type); - if (type is SpecialType) { - if (type == SpecialType.JsArray) { - world.registerInstantiatedClass(compiler.listClass); - } else if (type == SpecialType.JsObject) { - world.registerInstantiatedClass(compiler.objectClass); - } - continue; - } - if (type is InterfaceType) { - if (type.element == compiler.intClass) { - world.registerInstantiatedClass(compiler.intClass); - } else if (type.element == compiler.doubleClass) { - world.registerInstantiatedClass(compiler.doubleClass); - } else if (type.element == compiler.numClass) { - world.registerInstantiatedClass(compiler.doubleClass); - world.registerInstantiatedClass(compiler.intClass); - } else if (type.element == compiler.stringClass) { - world.registerInstantiatedClass(compiler.stringClass); - } else if (type.element == compiler.nullClass) { - world.registerInstantiatedClass(compiler.nullClass); - } else if (type.element == compiler.boolClass) { - world.registerInstantiatedClass(compiler.boolClass); - } - } - assert(type is DartType); - enqueueUnusedClassesMatching( - (nativeClass) => compiler.types.isSubtype(nativeClass.thisType, type), - cause, - 'subtypeof($type)'); - } - - // Give an info so that library developers can compile with -v to find why - // all the native classes are included. - if (unusedClasses.isEmpty && !allUsedBefore) { - compiler.log('All native types marked as used due to $cause.'); - } - } - - enqueueUnusedClassesMatching(bool predicate(classElement), - cause, - [String reason]) { - Iterable matches = unusedClasses.where(predicate); - matches.forEach((c) => enqueueClass(c, cause)); - } - - onFirstNativeClass() { - staticUse(name) => world.registerStaticUse(compiler.findHelper(name)); - - staticUse(const SourceString('dynamicFunction')); - staticUse(const SourceString('dynamicSetMetadata')); - staticUse(const SourceString('defineProperty')); - staticUse(const SourceString('toStringForNativeObject')); - staticUse(const SourceString('hashCodeForNativeObject')); - - addNativeExceptions(); - } - - addNativeExceptions() { - enqueueUnusedClassesMatching((classElement) { - // TODO(sra): Annotate exception classes in dart:html. - String name = classElement.name.slowToString(); - if (name.contains('Exception')) return true; - if (name.contains('Error')) return true; - return false; - }, - 'native exception'); - } -} - - -class NativeResolutionEnqueuer extends NativeEnqueuerBase { - - NativeResolutionEnqueuer(Enqueuer world, Compiler compiler) - : super(world, compiler, compiler.enableNativeLiveTypeAnalysis); - - void logSummary(log(message)) { - log('Resolved ${registeredClasses.length} native elements used, ' - '${unusedClasses.length} native elements dead.'); - } -} - - -class NativeCodegenEnqueuer extends NativeEnqueuerBase { - - final CodeEmitterTask emitter; - - final Set<ClassElement> doneAddSubtypes = new Set<ClassElement>(); - - NativeCodegenEnqueuer(Enqueuer world, Compiler compiler, this.emitter) - : super(world, compiler, compiler.enableNativeLiveTypeAnalysis); - - void processNativeClasses(Iterable<LibraryElement> libraries) { - super.processNativeClasses(libraries); - - // HACK HACK - add all the resolved classes. - NativeEnqueuerBase enqueuer = compiler.enqueuer.resolution.nativeEnqueuer; - for (final classElement in enqueuer.registeredClasses) { - if (unusedClasses.contains(classElement)) { - enqueueClass(classElement, 'was resolved'); - } - } - flushQueue(); - } - - processClass(ClassElement classElement, cause) { - super.processClass(classElement, cause); - // Add the information that this class is a subtype of its supertypes. The - // code emitter and the ssa builder use that information. - addSubtypes(classElement, emitter.nativeEmitter); - } - - void addSubtypes(ClassElement cls, NativeEmitter emitter) { - if (!cls.isNative()) return; - if (doneAddSubtypes.contains(cls)) return; - doneAddSubtypes.add(cls); - - // Walk the superclass chain since classes on the superclass chain might not - // be instantiated (abstract or simply unused). - addSubtypes(cls.superclass, emitter); - - for (DartType type in cls.allSupertypes) { - List<Element> subtypes = emitter.subtypes.putIfAbsent( - type.element, - () => <ClassElement>[]); - subtypes.add(cls); - } - - // Skip through all the mixin applications in the super class - // chain. That way, the direct subtypes set only contain the - // natives classes. - ClassElement superclass = cls.superclass; - while (superclass != null && superclass.isMixinApplication) { - assert(!superclass.isNative()); - superclass = superclass.superclass; - } - - List<Element> directSubtypes = emitter.directSubtypes.putIfAbsent( - superclass, - () => <ClassElement>[]); - directSubtypes.add(cls); - } - - void logSummary(log(message)) { - log('Compiled ${registeredClasses.length} native classes, ' - '${unusedClasses.length} native classes omitted.'); - } -} - -void maybeEnableNative(Compiler compiler, - LibraryElement library) { - String libraryName = library.canonicalUri.toString(); - if (library.entryCompilationUnit.script.name.contains( - 'dart/tests/compiler/dart2js_native') - || libraryName == 'dart:async' - || libraryName == 'dart:html' - || libraryName == 'dart:html_common' - || libraryName == 'dart:indexed_db' - || libraryName == 'dart:svg' - || libraryName == 'dart:web_audio') { - library.canUseNative = true; - } -} - -/** - * A summary of the behavior of a native element. - * - * Native code can return values of one type and cause native subtypes of - * another type to be instantiated. By default, we compute both from the - * declared type. - * - * A field might yield any native type that 'is' the field type. - * - * A method might create and return instances of native subclasses of its - * declared return type, and a callback argument may be called with instances of - * the callback parameter type (e.g. Event). - * - * If there is one or more @Creates annotations, the union of the named types - * replaces the inferred instantiated type, and the return type is ignored for - * the purpose of inferring instantiated types. - * - * @Creates(IDBCursor) // Created asynchronously. - * @Creates(IDBRequest) // Created synchronously (for return value). - * IDBRequest request = objectStore.openCursor(); - * - * If there is one or more @Returns annotations, the union of the named types - * replaces the declared return type. - * - * @Returns(IDBRequest) - * IDBRequest request = objectStore.openCursor(); - */ -class NativeBehavior { - - /// [DartType]s or [SpecialType]s returned or yielded by the native element. - final List typesReturned = []; - - /// [DartType]s or [SpecialType]s instantiated by the native element. - final List typesInstantiated = []; - - static final NativeBehavior NONE = new NativeBehavior(); - - //NativeBehavior(); - - static NativeBehavior ofJsCall(Send jsCall, Compiler compiler, resolver) { - // The first argument of a JS-call is a string encoding various attributes - // of the code. - // - // 'Type1|Type2'. A union type. - // '=Object'. A JavaScript Object, no subtype. - // '=List'. A JavaScript Array, no subtype. - - var argNodes = jsCall.arguments; - if (argNodes.isEmpty) { - compiler.cancel("JS expression has no type", node: jsCall); - } - - var firstArg = argNodes.head; - LiteralString specLiteral = firstArg.asLiteralString(); - if (specLiteral != null) { - String specString = specLiteral.dartString.slowToString(); - // Various things that are not in fact types. - if (specString == 'void') return NativeBehavior.NONE; - if (specString == '' || specString == 'var') { - var behavior = new NativeBehavior(); - behavior.typesReturned.add(compiler.objectClass.computeType(compiler)); - return behavior; - } - var behavior = new NativeBehavior(); - for (final typeString in specString.split('|')) { - var type = _parseType(typeString, compiler, - (name) => resolver.resolveTypeFromString(name), - jsCall); - behavior.typesInstantiated.add(type); - behavior.typesReturned.add(type); - } - return behavior; - } - - // TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2'). It - // is not very satisfactory because it does not work for void, dynamic. - - compiler.cancel("Unexpected JS first argument", node: firstArg); - } - - static NativeBehavior ofMethod(FunctionElement method, Compiler compiler) { - FunctionType type = method.computeType(compiler); - var behavior = new NativeBehavior(); - behavior.typesReturned.add(type.returnType); - behavior._capture(type, compiler); - - // TODO(sra): Optional arguments are currently missing from the - // DartType. This should be fixed so the following work-around can be - // removed. - method.computeSignature(compiler).forEachOptionalParameter( - (Element parameter) { - behavior._escape(parameter.computeType(compiler), compiler); - }); - - behavior._overrideWithAnnotations(method, compiler); - return behavior; - } - - static NativeBehavior ofFieldLoad(Element field, Compiler compiler) { - DartType type = field.computeType(compiler); - var behavior = new NativeBehavior(); - behavior.typesReturned.add(type); - behavior._capture(type, compiler); - behavior._overrideWithAnnotations(field, compiler); - return behavior; - } - - static NativeBehavior ofFieldStore(Element field, Compiler compiler) { - DartType type = field.computeType(compiler); - var behavior = new NativeBehavior(); - behavior._escape(type, compiler); - // We don't override the default behaviour - the annotations apply to - // loading the field. - return behavior; - } - - void _overrideWithAnnotations(Element element, Compiler compiler) { - if (element.metadata.isEmpty) return; - - DartType lookup(String name) { - Element e = element.buildScope().lookup(new SourceString(name)); - if (e == null) return null; - if (e is! ClassElement) return null; - e.ensureResolved(compiler); - return e.computeType(compiler); - } - - NativeEnqueuerBase enqueuer = compiler.enqueuer.resolution.nativeEnqueuer; - var creates = _collect(element, compiler, enqueuer.annotationCreatesClass, - lookup); - var returns = _collect(element, compiler, enqueuer.annotationReturnsClass, - lookup); - - if (creates != null) { - typesInstantiated..clear()..addAll(creates); - } - if (returns != null) { - typesReturned..clear()..addAll(returns); - } - } - - /** - * Returns a list of type constraints from the annotations of - * [annotationClass]. - * Returns `null` if no constraints. - */ - static _collect(Element element, Compiler compiler, Element annotationClass, - lookup(str)) { - var types = null; - for (Link<MetadataAnnotation> link = element.metadata; - !link.isEmpty; - link = link.tail) { - MetadataAnnotation annotation = link.head.ensureResolved(compiler); - var value = annotation.value; - if (value is! ConstructedConstant) continue; - if (value.type is! InterfaceType) continue; - if (!identical(value.type.element, annotationClass)) continue; - - var fields = value.fields; - // TODO(sra): Better validation of the constant. - if (fields.length != 1 || fields[0] is! StringConstant) { - PartialMetadataAnnotation partial = annotation; - compiler.cancel( - 'Annotations needs one string: ${partial.parseNode(compiler)}'); - } - String specString = fields[0].toDartString().slowToString(); - for (final typeString in specString.split('|')) { - var type = _parseType(typeString, compiler, lookup, annotation); - if (types == null) types = []; - types.add(type); - } - } - return types; - } - - /// Models the behavior of having intances of [type] escape from Dart code - /// into native code. - void _escape(DartType type, Compiler compiler) { - type = type.unalias(compiler); - if (type is FunctionType) { - // A function might be called from native code, passing us novel - // parameters. - _escape(type.returnType, compiler); - for (Link<DartType> parameters = type.parameterTypes; - !parameters.isEmpty; - parameters = parameters.tail) { - _capture(parameters.head, compiler); - } - } - } - - /// Models the behavior of Dart code receiving instances and methods of [type] - /// from native code. We usually start the analysis by capturing a native - /// method that has been used. - void _capture(DartType type, Compiler compiler) { - type = type.unalias(compiler); - if (type is FunctionType) { - _capture(type.returnType, compiler); - for (Link<DartType> parameters = type.parameterTypes; - !parameters.isEmpty; - parameters = parameters.tail) { - _escape(parameters.head, compiler); - } - } else { - typesInstantiated.add(type); - } - } - - static _parseType(String typeString, Compiler compiler, - lookup(name), locationNodeOrElement) { - if (typeString == '=Object') return SpecialType.JsObject; - if (typeString == '=List') return SpecialType.JsArray; - if (typeString == 'dynamic') { - return compiler.dynamicClass.computeType(compiler); - } - DartType type = lookup(typeString); - if (type != null) return type; - - int index = typeString.indexOf('<'); - if (index < 1) { - compiler.cancel("Type '$typeString' not found", - node: _errorNode(locationNodeOrElement, compiler)); - } - type = lookup(typeString.substring(0, index)); - if (type != null) { - // TODO(sra): Parse type parameters. - return type; - } - compiler.cancel("Type '$typeString' not found", - node: _errorNode(locationNodeOrElement, compiler)); - } - - static _errorNode(locationNodeOrElement, compiler) { - if (locationNodeOrElement is Node) return locationNodeOrElement; - return locationNodeOrElement.parseNode(compiler); - } -} - -void checkAllowedLibrary(ElementListener listener, Token token) { - LibraryElement currentLibrary = listener.compilationUnitElement.getLibrary(); - if (!currentLibrary.canUseNative) { - listener.recoverableError("Unexpected token", token: token); - } -} - -Token handleNativeBlockToSkip(Listener listener, Token token) { - checkAllowedLibrary(listener, token); - token = token.next; - if (identical(token.kind, STRING_TOKEN)) { - token = token.next; - } - if (identical(token.stringValue, '{')) { - BeginGroupToken beginGroupToken = token; - token = beginGroupToken.endGroup; - } - return token; -} - -Token handleNativeClassBodyToSkip(Listener listener, Token token) { - checkAllowedLibrary(listener, token); - listener.handleIdentifier(token); - token = token.next; - if (!identical(token.kind, STRING_TOKEN)) { - return listener.unexpected(token); - } - token = token.next; - if (!identical(token.stringValue, '{')) { - return listener.unexpected(token); - } - BeginGroupToken beginGroupToken = token; - token = beginGroupToken.endGroup; - return token; -} - -Token handleNativeClassBody(Listener listener, Token token) { - checkAllowedLibrary(listener, token); - token = token.next; - if (!identical(token.kind, STRING_TOKEN)) { - listener.unexpected(token); - } else { - token = token.next; - } - return token; -} - -Token handleNativeFunctionBody(ElementListener listener, Token token) { - checkAllowedLibrary(listener, token); - Token begin = token; - listener.beginReturnStatement(token); - token = token.next; - bool hasExpression = false; - if (identical(token.kind, STRING_TOKEN)) { - hasExpression = true; - listener.beginLiteralString(token); - listener.endLiteralString(0); - token = token.next; - } - listener.endReturnStatement(hasExpression, begin, token); - // TODO(ngeoffray): expect a ';'. - // Currently there are method with both native marker and Dart body. - return token.next; -} - -SourceString checkForNativeClass(ElementListener listener) { - SourceString nativeTagInfo; - Node node = listener.nodes.head; - if (node != null - && node.asIdentifier() != null - && node.asIdentifier().source.stringValue == 'native') { - nativeTagInfo = node.asIdentifier().token.next.value; - listener.popNode(); - } - return nativeTagInfo; -} - -bool isOverriddenMethod(FunctionElement element, - ClassElement cls, - NativeEmitter nativeEmitter) { - List<ClassElement> subtypes = nativeEmitter.subtypes[cls]; - if (subtypes == null) return false; - for (ClassElement subtype in subtypes) { - if (subtype.lookupLocalMember(element.name) != null) return true; - } - return false; -} - -final RegExp nativeRedirectionRegExp = new RegExp(r'^[a-zA-Z][a-zA-Z_$0-9]*$'); - -void handleSsaNative(SsaBuilder builder, Expression nativeBody) { - Compiler compiler = builder.compiler; - FunctionElement element = builder.work.element; - NativeEmitter nativeEmitter = builder.emitter.nativeEmitter; - - HInstruction convertDartClosure(Element parameter, FunctionType type) { - HInstruction local = builder.localsHandler.readLocal(parameter); - Constant arityConstant = - builder.constantSystem.createInt(type.computeArity()); - HInstruction arity = builder.graph.addConstant(arityConstant); - // TODO(ngeoffray): For static methods, we could pass a method with a - // defined arity. - Element helper = builder.backend.getClosureConverter(); - builder.pushInvokeHelper2(helper, local, arity, HType.UNKNOWN); - HInstruction closure = builder.pop(); - return closure; - } - - // Check which pattern this native method follows: - // 1) foo() native; - // hasBody = false - // 2) foo() native "bar"; - // No longer supported, this is now done with @JSName('foo') and case 1. - // 3) foo() native "return 42"; - // hasBody = true - bool hasBody = false; - assert(element.isNative()); - String nativeMethodName = element.fixedBackendName(); - if (nativeBody != null) { - LiteralString jsCode = nativeBody.asLiteralString(); - String str = jsCode.dartString.slowToString(); - if (nativeRedirectionRegExp.hasMatch(str)) { - compiler.cancel("Deprecated syntax, use @JSName('name') instead.", - node: nativeBody); - } - hasBody = true; - } - - if (!hasBody) { - nativeEmitter.nativeMethods.add(element); - } - - FunctionSignature parameters = element.computeSignature(builder.compiler); - if (!hasBody) { - List<String> arguments = <String>[]; - List<HInstruction> inputs = <HInstruction>[]; - String receiver = ''; - if (element.isInstanceMember()) { - receiver = '#.'; - inputs.add(builder.localsHandler.readThis()); - } - parameters.forEachParameter((Element parameter) { - DartType type = parameter.computeType(compiler).unalias(compiler); - HInstruction input = builder.localsHandler.readLocal(parameter); - if (type is FunctionType) { - // The parameter type is a function type either directly or through - // typedef(s). - input = convertDartClosure(parameter, type); - } - inputs.add(input); - arguments.add('#'); - }); - - String foreignParameters = Strings.join(arguments, ','); - String nativeMethodCall; - if (element.kind == ElementKind.FUNCTION) { - nativeMethodCall = '$receiver$nativeMethodName($foreignParameters)'; - } else if (element.kind == ElementKind.GETTER) { - nativeMethodCall = '$receiver$nativeMethodName'; - } else if (element.kind == ElementKind.SETTER) { - nativeMethodCall = '$receiver$nativeMethodName = $foreignParameters'; - } else { - builder.compiler.internalError('unexpected kind: "${element.kind}"', - element: element); - } - - DartString jsCode = new DartString.literal(nativeMethodCall); - builder.push(new HForeign(jsCode, HType.UNKNOWN, inputs)); - builder.close(new HReturn(builder.pop())).addSuccessor(builder.graph.exit); - } else { - if (parameters.parameterCount != 0) { - compiler.cancel( - 'native "..." syntax is restricted to functions with zero parameters', - node: nativeBody); - } - LiteralString jsCode = nativeBody.asLiteralString(); - builder.push(new HForeign.statement(jsCode.dartString, <HInstruction>[])); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/patch_parser.dart b/pkgs/markdown/test/lib/src/compiler/implementation/patch_parser.dart deleted file mode 100644 index 5a0da01..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/patch_parser.dart +++ /dev/null
@@ -1,596 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/** - * This library contains the infrastructure to parse and integrate patch files. - * - * Three types of elements can be patched: [LibraryElement], [ClassElement], - * [FunctionElement]. Patches are introduced in patch libraries which are loaded - * together with the corresponding origin library. Which libraries that are - * patched is determined by the [dart2jsPatchPath] field of [LibraryInfo] found - * in [:lib/_internal/libraries.dart:]. - * - * Patch libraries are parsed like regular library and thus provided with their - * own elements. These elements which are distinct from the elements from the - * patched library and the relation between patched and patch elements is - * established through the [:patch:] and [:origin:] fields found on - * [LibraryElement], [ClassElement] and [FunctionElement]. The [:patch:] fields - * are set on the patched elements to point to their corresponding patch - * element, and the [:origin:] elements are set on the patch elements to point - * their corresponding patched elements. - * - * The fields [Element.isPatched] and [Element.isPatch] can be used to determine - * whether the [:patch:] or [:origin:] field, respectively, has been set on an - * element, regardless of whether the element is one of the three patchable - * element types or not. - * - * ## Variants of Classes and Functions ## - * - * With patches there are four variants of classes and function: - * - * Regular: A class or function which is not declared in a patch library and - * which has no corresponding patch. - * Origin: A class or function which is not declared in a patch library and - * which has a corresponding patch. Origin functions must use the [:external:] - * modifier and can have no body. Origin classes and functions are also - * called 'patched'. - * Patch: A class or function which is declared in a patch library and which - * has a corresponding origin. Both patch classes and patch functions must use - * the [:patch:] modifier. - * Injected: A class or function (or even field) which is declared in a - * patch library and which has no corresponding origin. An injected element - * cannot use the [:patch:] modifier. Injected elements are never visible from - * outside the patch library in which they have been declared. For this - * reason, injected elements are often declared private and therefore called - * also called 'patch private'. - * - * Examples of the variants is shown in the code below: - * - * // In the origin library: - * class RegularClass { // A regular class. - * void regularMethod() {} // A regular method. - * } - * class PatchedClass { // An origin class. - * int regularField; // A regular field. - * void regularMethod() {} // A regular method. - * external void patchedMethod(); // An origin method. - * } - * - * // In the patch library: - * class _InjectedClass { // An injected class. - * void _injectedMethod() {} // An injected method. - * } - * patch class PatchedClass { // A patch class. - * int _injectedField; { // An injected field. - * patch void patchedMethod() {} // A patch method. - * } - * - * - * ## Declaration and Implementation ## - * - * With patches we have two views on elements: as the 'declaration' which - * introduces the entity and defines its interface, and as the 'implementation' - * which defines the actual implementation of the entity. - * - * Every element has a 'declaration' and an 'implementation' element. For - * regular and injected elements these are the same. For origin elements the - * declaration is the element itself and the implementation is the patch element - * found through its [:patch:] field. For patch elements the implementation is - * the element itself and the declaration is the origin element found through - * its [:origin:] field. The declaration and implementation of any element is - * conveniently available through the [Element.declaration] and - * [Element.implementation] getters. - * - * Most patch-related invariants enforced through-out the compiler are defined - * in terms of 'declaration' and 'implementation', and tested through the - * predicate getters [Element.isDeclaration] and [Element.isImplementation]. - * Patch invariants are stated both in comments and as assertions. - * - * - * ## General invariant guidelines ## - * - * For [LibraryElement] we always use declarations. This means the - * [Element.getLibrary] method will only return library declarations. Patch - * library implementations are only accessed through calls to - * [Element.getImplementationLibrary] which is used to setup the correct - * [Element.enclosingElement] relation between patch/injected elements and the - * patch library. - * - * For [ClassElement] and [FunctionElement] we use declarations for determining - * identity and implementations for work based on the AST nodes, such as - * resolution, type-checking, type inference, building SSA graphs, etc. - * - Worklist only contain declaration elements. - * - Most maps and sets use declarations exclusively, and their individual - * invariants are stated in the field comments. - * - [TreeElements] only map to patch elements from inside a patch library. - * TODO(johnniwinther): Simplify this invariant to use only declarations in - * [TreeElements]. - * - Builders shift between declaration and implementation depending on usages. - * - Compile-time constants use constructor implementation exclusively. - * - Work on function parameters is performed on the declaration of the function - * element. - */ - -library patchparser; - -import "dart:uri"; -import "tree/tree.dart" as tree; -import "dart2jslib.dart" as leg; // CompilerTask, Compiler. -import "apiimpl.dart"; -import "../compiler.dart" as api; -import "scanner/scannerlib.dart"; // Scanner, Parsers, Listeners -import "elements/elements.dart"; -import "elements/modelx.dart" show LibraryElementX, MetadataAnnotationX; -import 'util/util.dart'; - -class PatchParserTask extends leg.CompilerTask { - PatchParserTask(leg.Compiler compiler): super(compiler); - final String name = "Patching Parser"; - - /** - * Scans a library patch file, applies the method patches and - * injections to the library, and returns a list of class - * patches. - */ - void patchLibrary(leg.LibraryDependencyHandler handler, - Uri patchUri, LibraryElement originLibrary) { - - leg.Script script = compiler.readScript(patchUri, null); - var patchLibrary = new LibraryElementX(script, null, originLibrary); - compiler.withCurrentElement(patchLibrary, () { - handler.registerNewLibrary(patchLibrary); - LinkBuilder<tree.LibraryTag> imports = new LinkBuilder<tree.LibraryTag>(); - compiler.withCurrentElement(patchLibrary.entryCompilationUnit, () { - // This patches the elements of the patch library into [library]. - // Injected elements are added directly under the compilation unit. - // Patch elements are stored on the patched functions or classes. - scanLibraryElements(patchLibrary.entryCompilationUnit, imports); - }); - // After scanning declarations, we handle the import tags in the patch. - // TODO(lrn): These imports end up in the original library and are in - // scope for the original methods too. This should be fixed. - compiler.importHelperLibrary(originLibrary); - for (tree.LibraryTag tag in imports.toLink()) { - compiler.libraryLoader.registerLibraryFromTag( - handler, patchLibrary, tag); - } - }); - } - - void scanLibraryElements( - CompilationUnitElement compilationUnit, - LinkBuilder<tree.LibraryTag> imports) { - measure(() { - // TODO(lrn): Possibly recursively handle #source directives in patch. - leg.Script script = compilationUnit.script; - Token tokens = new StringScanner(script.text).tokenize(); - Function idGenerator = compiler.getNextFreeClassId; - PatchListener patchListener = - new PatchElementListener(compiler, - compilationUnit, - idGenerator, - imports); - new PatchParser(patchListener).parseUnit(tokens); - }); - } - - void parsePatchClassNode(PartialClassElement element) { - // Parse [PartialClassElement] using a "patch"-aware parser instead - // of calling its [parseNode] method. - if (element.cachedNode != null) return; - - return measure(() => compiler.withCurrentElement(element, () { - PatchMemberListener listener = new PatchMemberListener(compiler, element); - Parser parser = new PatchClassElementParser(listener); - Token token = parser.parseTopLevelDeclaration(element.beginToken); - assert(identical(token, element.endToken.next)); - element.cachedNode = listener.popNode(); - assert(listener.nodes.isEmpty); - - Link<Element> patches = element.localMembers; - applyContainerPatch(element.origin, patches); - })); - } - - void applyContainerPatch(ClassElement originClass, - Link<Element> patches) { - for (Element patch in patches) { - if (!isPatchElement(patch)) continue; - - Element origin = originClass.localLookup(patch.name); - patchElement(compiler, origin, patch); - } - } -} - -/** - * Extension of the [Listener] interface to handle the extra "patch" pseudo- - * keyword in patch files. - * Patch files shouldn't have a type named "patch". - */ -abstract class PatchListener extends Listener { - void beginPatch(Token patch); - void endPatch(Token patch); -} - -/** - * Partial parser that extends the top-level and class grammars to allow the - * word "patch" in front of some declarations. - */ -class PatchParser extends PartialParser { - PatchParser(PatchListener listener) : super(listener); - - PatchListener get patchListener => listener; - - bool isPatch(Token token) { - return token.stringValue == null && - token.slowToString() == "patch"; - } - - /** - * Parse top-level declarations, and allow "patch" in front of functions - * and classes. - */ - Token parseTopLevelDeclaration(Token token) { - if (!isPatch(token)) { - return super.parseTopLevelDeclaration(token); - } - Token patch = token; - token = token.next; - String value = token.stringValue; - if (identical(value, 'interface') - || identical(value, 'typedef') - || identical(value, '#') - || identical(value, 'abstract')) { - // At the top level, you can only patch functions and classes. - // Patch classes and functions can't be marked abstract. - return listener.unexpected(patch); - } - patchListener.beginPatch(patch); - token = super.parseTopLevelDeclaration(token); - patchListener.endPatch(patch); - return token; - } - - /** - * Parse a class member. - * If the member starts with "patch", it's a member override. - * Only methods can be overridden, including constructors, getters and - * setters, but not fields. If "patch" occurs in front of a field, the error - * is caught elsewhere. - */ - Token parseMember(Token token) { - if (!isPatch(token)) { - return super.parseMember(token); - } - Token patch = token; - patchListener.beginPatch(patch); - token = super.parseMember(token.next); - patchListener.endPatch(patch); - return token; - } -} - -/** - * Partial parser for patch files that also handles the members of class - * declarations. - */ -class PatchClassElementParser extends PatchParser { - PatchClassElementParser(PatchListener listener) : super(listener); - - Token parseClassBody(Token token) => fullParseClassBody(token); -} - -/** - * Extension of [ElementListener] for parsing patch files. - */ -class PatchElementListener extends ElementListener implements PatchListener { - final LinkBuilder<tree.LibraryTag> imports; - bool isMemberPatch = false; - bool isClassPatch = false; - - PatchElementListener(leg.DiagnosticListener listener, - CompilationUnitElement patchElement, - int idGenerator(), - this.imports) - : super(listener, patchElement, idGenerator); - - MetadataAnnotation popMetadataHack() { - // TODO(ahe): Remove this method. - popNode(); // Discard null. - return new PatchMetadataAnnotation(); - } - - void beginPatch(Token token) { - if (identical(token.next.stringValue, "class")) { - isClassPatch = true; - } else { - isMemberPatch = true; - } - handleIdentifier(token); - } - - void endPatch(Token token) { - if (identical(token.next.stringValue, "class")) { - isClassPatch = false; - } else { - isMemberPatch = false; - } - } - - /** - * Allow script tags (import only, the parser rejects the rest for now) in - * patch files. The import tags will be added to the library. - */ - bool allowLibraryTags() => true; - - void addLibraryTag(tree.LibraryTag tag) { - super.addLibraryTag(tag); - imports.addLast(tag); - } - - void pushElement(Element patch) { - if (isMemberPatch || (isClassPatch && patch is ClassElement)) { - // Apply patch. - patch.addMetadata(popMetadataHack()); - LibraryElement originLibrary = compilationUnitElement.getLibrary(); - assert(originLibrary.isPatched); - Element origin = originLibrary.localLookup(patch.name); - patchElement(listener, origin, patch); - } - super.pushElement(patch); - } -} - -/** - * Extension of [MemberListener] for parsing patch class bodies. - */ -class PatchMemberListener extends MemberListener implements PatchListener { - bool isMemberPatch = false; - bool isClassPatch = false; - PatchMemberListener(leg.DiagnosticListener listener, - Element enclosingElement) - : super(listener, enclosingElement); - - MetadataAnnotation popMetadataHack() { - // TODO(ahe): Remove this method. - popNode(); // Discard null. - return new PatchMetadataAnnotation(); - } - - void beginPatch(Token token) { - if (identical(token.next.stringValue, "class")) { - isClassPatch = true; - } else { - isMemberPatch = true; - } - handleIdentifier(token); - } - - void endPatch(Token token) { - if (identical(token.next.stringValue, "class")) { - isClassPatch = false; - } else { - isMemberPatch = false; - } - } - - void addMember(Element element) { - if (isMemberPatch || (isClassPatch && element is ClassElement)) { - element.addMetadata(popMetadataHack()); - } - super.addMember(element); - } -} - -// TODO(ahe): Get rid of this class. -class PatchMetadataAnnotation extends MetadataAnnotationX { - final leg.Constant value = null; - - PatchMetadataAnnotation() : super(STATE_DONE); - - Token get beginToken => null; - Token get endToken => null; -} - -void patchElement(leg.DiagnosticListener listener, - Element origin, - Element patch) { - if (origin == null) { - listener.reportMessage( - listener.spanFromSpannable(patch), - leg.MessageKind.PATCH_NON_EXISTING.error({'name': patch.name}), - api.Diagnostic.ERROR); - return; - } - if (!(origin.isClass() || - origin.isConstructor() || - origin.isFunction() || - origin.isAbstractField())) { - listener.reportMessage( - listener.spanFromSpannable(origin), - leg.MessageKind.PATCH_NONPATCHABLE.error(), - api.Diagnostic.ERROR); - return; - } - if (patch.isClass()) { - tryPatchClass(listener, origin, patch); - } else if (patch.isGetter()) { - tryPatchGetter(listener, origin, patch); - } else if (patch.isSetter()) { - tryPatchSetter(listener, origin, patch); - } else if (patch.isConstructor()) { - tryPatchConstructor(listener, origin, patch); - } else if(patch.isFunction()) { - tryPatchFunction(listener, origin, patch); - } else { - listener.reportMessage( - listener.spanFromSpannable(patch), - leg.MessageKind.PATCH_NONPATCHABLE.error(), - api.Diagnostic.ERROR); - } -} - -void tryPatchClass(leg.DiagnosticListener listener, - Element origin, - ClassElement patch) { - if (!origin.isClass()) { - listener.reportMessage( - listener.spanFromSpannable(origin), - leg.MessageKind.PATCH_NON_CLASS.error({'className': patch.name}), - api.Diagnostic.ERROR); - listener.reportMessage( - listener.spanFromSpannable(patch), - leg.MessageKind.PATCH_POINT_TO_CLASS.error({'className': patch.name}), - api.Diagnostic.INFO); - return; - } - patchClass(listener, origin, patch); -} - -void patchClass(leg.DiagnosticListener listener, - ClassElement origin, - ClassElement patch) { - if (origin.isPatched) { - listener.internalErrorOnElement( - origin, "Patching the same class more than once."); - } - // TODO(johnniwinther): Change to functions on the ElementX class. - origin.patch = patch; - patch.origin = origin; -} - -void tryPatchGetter(leg.DiagnosticListener listener, - Element origin, - FunctionElement patch) { - if (!origin.isAbstractField()) { - listener.reportMessage( - listener.spanFromSpannable(origin), - leg.MessageKind.PATCH_NON_GETTER.error({'name': origin.name}), - api.Diagnostic.ERROR); - listener.reportMessage( - listener.spanFromSpannable(patch), - leg.MessageKind.PATCH_POINT_TO_GETTER.error({'getterName': patch.name}), - api.Diagnostic.INFO); - return; - } - AbstractFieldElement originField = origin; - if (originField.getter == null) { - listener.reportMessage( - listener.spanFromSpannable(origin), - leg.MessageKind.PATCH_NO_GETTER.error({'getterName': patch.name}), - api.Diagnostic.ERROR); - listener.reportMessage( - listener.spanFromSpannable(patch), - leg.MessageKind.PATCH_POINT_TO_GETTER.error({'getterName': patch.name}), - api.Diagnostic.INFO); - return; - } - patchFunction(listener, originField.getter, patch); -} - -void tryPatchSetter(leg.DiagnosticListener listener, - Element origin, - FunctionElement patch) { - if (!origin.isAbstractField()) { - listener.reportMessage( - listener.spanFromSpannable(origin), - leg.MessageKind.PATCH_NON_SETTER.error({'name': origin.name}), - api.Diagnostic.ERROR); - listener.reportMessage( - listener.spanFromSpannable(patch), - leg.MessageKind.PATCH_POINT_TO_SETTER.error({'setterName': patch.name}), - api.Diagnostic.INFO); - return; - } - AbstractFieldElement originField = origin; - if (originField.setter == null) { - listener.reportMessage( - listener.spanFromSpannable(origin), - leg.MessageKind.PATCH_NO_SETTER.error({'setterName': patch.name}), - api.Diagnostic.ERROR); - listener.reportMessage( - listener.spanFromSpannable(patch), - leg.MessageKind.PATCH_POINT_TO_SETTER.error({'setterName': patch.name}), - api.Diagnostic.INFO); - return; - } - patchFunction(listener, originField.setter, patch); -} - -void tryPatchConstructor(leg.DiagnosticListener listener, - Element origin, - FunctionElement patch) { - if (!origin.isConstructor()) { - listener.reportMessage( - listener.spanFromSpannable(origin), - leg.MessageKind.PATCH_NON_CONSTRUCTOR.error( - {'constructorName': patch.name}), - api.Diagnostic.ERROR); - listener.reportMessage( - listener.spanFromSpannable(patch), - leg.MessageKind.PATCH_POINT_TO_CONSTRUCTOR.error( - {'constructorName': patch.name}), - api.Diagnostic.INFO); - return; - } - patchFunction(listener, origin, patch); -} - -void tryPatchFunction(leg.DiagnosticListener listener, - Element origin, - FunctionElement patch) { - if (!origin.isFunction()) { - listener.reportMessage( - listener.spanFromSpannable(origin), - leg.MessageKind.PATCH_NON_FUNCTION.error({'functionName': patch.name}), - api.Diagnostic.ERROR); - listener.reportMessage( - listener.spanFromSpannable(patch), - leg.MessageKind.PATCH_POINT_TO_FUNCTION.error( - {'functionName': patch.name}), - api.Diagnostic.INFO); - return; - } - patchFunction(listener, origin, patch); -} - -void patchFunction(leg.DiagnosticListener listener, - FunctionElement origin, - FunctionElement patch) { - if (!origin.modifiers.isExternal()) { - listener.reportMessage( - listener.spanFromSpannable(origin), - leg.MessageKind.PATCH_NON_EXTERNAL.error(), - api.Diagnostic.ERROR); - listener.reportMessage( - listener.spanFromSpannable(patch), - leg.MessageKind.PATCH_POINT_TO_FUNCTION.error( - {'functionName': patch.name}), - api.Diagnostic.INFO); - return; - } - if (origin.isPatched) { - listener.internalErrorOnElement(origin, - "Trying to patch a function more than once."); - } - if (origin.cachedNode != null) { - listener.internalErrorOnElement(origin, - "Trying to patch an already compiled function."); - } - // Don't just assign the patch field. This also updates the cachedNode. - // TODO(johnniwinther): Change to functions on the ElementX class. - origin.setPatch(patch); - patch.origin = origin; -} - -// TODO(johnniwinther): Add unittest when patch is (real) metadata. -bool isPatchElement(Element element) { - // TODO(lrn): More checks needed if we introduce metadata for real. - // In that case, it must have the identifier "native" as metadata. - for (Link link = element.metadata; !link.isEmpty; link = link.tail) { - if (link.head is PatchMetadataAnnotation) return true; - } - return false; -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/resolution/members.dart b/pkgs/markdown/test/lib/src/compiler/implementation/resolution/members.dart deleted file mode 100644 index e62aa70..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/resolution/members.dart +++ /dev/null
@@ -1,3663 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of resolution; - -abstract class TreeElements { - Element operator[](Node node); - Selector getSelector(Send send); - DartType getType(Node node); - bool isParameterChecked(Element element); - Set<Node> get superUses; -} - -class TreeElementMapping implements TreeElements { - final Element currentElement; - final Map<Node, Selector> selectors = new LinkedHashMap<Node, Selector>(); - final Map<Node, DartType> types = new LinkedHashMap<Node, DartType>(); - final Set<Element> checkedParameters = new Set<Element>(); - final Set<Node> superUses = new Set<Node>(); - - TreeElementMapping(this.currentElement); - - operator []=(Node node, Element element) { - assert(invariant(node, () { - if (node is FunctionExpression) { - return !node.modifiers.isExternal(); - } - return true; - })); - // TODO(johnniwinther): Simplify this invariant to use only declarations in - // [TreeElements]. - assert(invariant(node, () { - if (!element.isErroneous() && currentElement != null && element.isPatch) { - return currentElement.getImplementationLibrary().isPatch; - } - return true; - })); - // TODO(ahe): Investigate why the invariant below doesn't hold. - // assert(invariant(node, - // getTreeElement(node) == element || - // getTreeElement(node) == null, - // message: '${getTreeElement(node)}; $element')); - - setTreeElement(node, element); - } - - operator [](Node node) => getTreeElement(node); - - void remove(Node node) { - setTreeElement(node, null); - } - - void setType(Node node, DartType type) { - types[node] = type; - } - - DartType getType(Node node) => types[node]; - - void setSelector(Node node, Selector selector) { - selectors[node] = selector; - } - - Selector getSelector(Node node) => selectors[node]; - - bool isParameterChecked(Element element) { - return checkedParameters.contains(element); - } -} - -class ResolverTask extends CompilerTask { - ResolverTask(Compiler compiler) : super(compiler); - - String get name => 'Resolver'; - - TreeElements resolve(Element element) { - return measure(() { - if (Elements.isErroneousElement(element)) return null; - - for (MetadataAnnotation metadata in element.metadata) { - metadata.ensureResolved(compiler); - } - - ElementKind kind = element.kind; - if (identical(kind, ElementKind.GENERATIVE_CONSTRUCTOR) || - identical(kind, ElementKind.FUNCTION) || - identical(kind, ElementKind.GETTER) || - identical(kind, ElementKind.SETTER)) { - return resolveMethodElement(element); - } - - if (identical(kind, ElementKind.FIELD)) return resolveField(element); - - if (identical(kind, ElementKind.PARAMETER) || - identical(kind, ElementKind.FIELD_PARAMETER)) { - return resolveParameter(element); - } - if (element.isClass()) { - ClassElement cls = element; - cls.ensureResolved(compiler); - return null; - } else if (element.isTypedef()) { - TypedefElement typdef = element; - resolveTypedef(typdef); - return null; - } else if (element.isTypeVariable()) { - element.computeType(compiler); - return null; - } - - compiler.unimplemented("resolve($element)", - node: element.parseNode(compiler)); - }); - } - - String constructorNameForDiagnostics(SourceString className, - SourceString constructorName) { - String classNameString = className.slowToString(); - String constructorNameString = constructorName.slowToString(); - return (constructorName == const SourceString('')) - ? classNameString - : "$classNameString.$constructorNameString"; - } - - void resolveRedirectingConstructor(InitializerResolver resolver, - Node node, - FunctionElement constructor, - FunctionElement redirection) { - Set<FunctionElement> seen = new Set<FunctionElement>(); - seen.add(constructor); - while (redirection != null) { - if (seen.contains(redirection)) { - resolver.visitor.error(node, MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE); - return; - } - seen.add(redirection); - - if (redirection.isPatched) { - checkMatchingPatchSignatures(constructor, redirection.patch); - redirection = redirection.patch; - } - redirection = resolver.visitor.resolveConstructorRedirection(redirection); - } - } - - void checkMatchingPatchParameters(FunctionElement origin, - Link<Element> originParameters, - Link<Element> patchParameters) { - while (!originParameters.isEmpty) { - Element originParameter = originParameters.head; - Element patchParameter = patchParameters.head; - // Hack: Use unparser to test parameter equality. This only works because - // we are restricting patch uses and the approach cannot be used - // elsewhere. - String originParameterText = - originParameter.parseNode(compiler).toString(); - String patchParameterText = - patchParameter.parseNode(compiler).toString(); - if (originParameterText != patchParameterText) { - error(originParameter.parseNode(compiler), - MessageKind.PATCH_PARAMETER_MISMATCH, - {'methodName': origin.name, - 'originParameter': originParameterText, - 'patchParameter': patchParameterText}); - } - - originParameters = originParameters.tail; - patchParameters = patchParameters.tail; - } - } - - void checkMatchingPatchSignatures(FunctionElement origin, - FunctionElement patch) { - // TODO(johnniwinther): Show both origin and patch locations on errors. - FunctionExpression originTree = compiler.withCurrentElement(origin, () { - return origin.parseNode(compiler); - }); - FunctionSignature originSignature = compiler.withCurrentElement(origin, () { - return origin.computeSignature(compiler); - }); - FunctionExpression patchTree = compiler.withCurrentElement(patch, () { - return patch.parseNode(compiler); - }); - FunctionSignature patchSignature = compiler.withCurrentElement(patch, () { - return patch.computeSignature(compiler); - }); - - if (originSignature.returnType != patchSignature.returnType) { - compiler.withCurrentElement(patch, () { - Node errorNode = - patchTree.returnType != null ? patchTree.returnType : patchTree; - error(errorNode, MessageKind.PATCH_RETURN_TYPE_MISMATCH, - {'methodName': origin.name, - 'originReturnType': originSignature.returnType, - 'patchReturnType': patchSignature.returnType}); - }); - } - if (originSignature.requiredParameterCount != - patchSignature.requiredParameterCount) { - compiler.withCurrentElement(patch, () { - error(patchTree, - MessageKind.PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH, - {'methodName': origin.name, - 'originParameterCount': originSignature.requiredParameterCount, - 'patchParameterCount': patchSignature.requiredParameterCount}); - }); - } else { - checkMatchingPatchParameters(origin, - originSignature.requiredParameters, - patchSignature.requiredParameters); - } - if (originSignature.optionalParameterCount != 0 && - patchSignature.optionalParameterCount != 0) { - if (originSignature.optionalParametersAreNamed != - patchSignature.optionalParametersAreNamed) { - compiler.withCurrentElement(patch, () { - error(patchTree, - MessageKind.PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH, - {'methodName': origin.name}); - }); - } - } - if (originSignature.optionalParameterCount != - patchSignature.optionalParameterCount) { - compiler.withCurrentElement(patch, () { - error(patchTree, - MessageKind.PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH, - {'methodName': origin.name, - 'originParameterCount': originSignature.optionalParameterCount, - 'patchParameterCount': patchSignature.optionalParameterCount}); - }); - } else { - checkMatchingPatchParameters(origin, - originSignature.optionalParameters, - patchSignature.optionalParameters); - } - } - - TreeElements resolveMethodElement(FunctionElement element) { - assert(invariant(element, element.isDeclaration)); - return compiler.withCurrentElement(element, () { - bool isConstructor = - identical(element.kind, ElementKind.GENERATIVE_CONSTRUCTOR); - TreeElements elements = - compiler.enqueuer.resolution.getCachedElements(element); - if (elements != null) { - assert(isConstructor); - return elements; - } - if (element.isPatched) { - checkMatchingPatchSignatures(element, element.patch); - element = element.patch; - } - return compiler.withCurrentElement(element, () { - FunctionExpression tree = element.parseNode(compiler); - if (tree.modifiers.isExternal()) { - error(tree, MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION); - return; - } - if (isConstructor) { - if (tree.returnType != null) { - error(tree, MessageKind.CONSTRUCTOR_WITH_RETURN_TYPE); - } - resolveConstructorImplementation(element, tree); - } - ResolverVisitor visitor = visitorFor(element); - visitor.useElement(tree, element); - visitor.setupFunction(tree, element); - - if (isConstructor) { - // Even if there is no initializer list we still have to do the - // resolution in case there is an implicit super constructor call. - InitializerResolver resolver = new InitializerResolver(visitor); - FunctionElement redirection = - resolver.resolveInitializers(element, tree); - if (redirection != null) { - resolveRedirectingConstructor(resolver, tree, element, redirection); - } - } else if (tree.initializers != null) { - error(tree, MessageKind.FUNCTION_WITH_INITIALIZER); - } - visitBody(visitor, tree.body); - - // Get the resolution tree and check that the resolved - // function doesn't use 'super' if it is mixed into another - // class. This is the part of the 'super' mixin check that - // happens when a function is resolved after the mixin - // application has been performed. - TreeElements resolutionTree = visitor.mapping; - ClassElement enclosingClass = element.getEnclosingClass(); - if (enclosingClass != null) { - Set<MixinApplicationElement> mixinUses = - compiler.world.mixinUses[enclosingClass]; - if (mixinUses != null) { - ClassElement mixin = enclosingClass; - for (MixinApplicationElement mixinApplication in mixinUses) { - checkMixinSuperUses(resolutionTree, mixinApplication, mixin); - } - } - } - return resolutionTree; - }); - }); - } - - /// This method should only be used by this library (or tests of - /// this library). - ResolverVisitor visitorFor(Element element) { - var mapping = new TreeElementMapping(element); - return new ResolverVisitor(compiler, element, mapping); - } - - void visitBody(ResolverVisitor visitor, Statement body) { - visitor.visit(body); - } - - void resolveConstructorImplementation(FunctionElement constructor, - FunctionExpression node) { - if (!identical(constructor.defaultImplementation, constructor)) return; - ClassElement intrface = constructor.getEnclosingClass(); - if (!intrface.isInterface()) return; - DartType defaultType = intrface.defaultClass; - if (defaultType == null) { - error(node, MessageKind.NO_DEFAULT_CLASS, - {'interfaceName': intrface.name}); - } - ClassElement defaultClass = defaultType.element; - defaultClass.ensureResolved(compiler); - assert(defaultClass.resolutionState == STATE_DONE); - assert(defaultClass.supertypeLoadState == STATE_DONE); - if (defaultClass.isInterface()) { - error(node, MessageKind.CANNOT_INSTANTIATE_INTERFACE, - {'interfaceName': defaultClass.name}); - } - // We have now established the following: - // [intrface] is an interface, let's say "MyInterface". - // [defaultClass] is a class, let's say "MyClass". - - Selector selector; - // If the default class implements the interface then we must use the - // default class' name. Otherwise we look for a factory with the name - // of the interface. - if (defaultClass.implementsInterface(intrface)) { - var constructorNameString = constructor.name.slowToString(); - // Create selector based on constructor.name but where interface - // is replaced with default class name. - // TODO(ahe): Don't use string manipulations here. - int classNameSeparatorIndex = constructorNameString.indexOf('\$'); - if (classNameSeparatorIndex < 0) { - selector = new Selector.callDefaultConstructor( - defaultClass.getLibrary()); - } else { - selector = new Selector.callConstructor( - new SourceString( - constructorNameString.substring(classNameSeparatorIndex + 1)), - defaultClass.getLibrary()); - } - constructor.defaultImplementation = - defaultClass.lookupConstructor(selector); - } else { - selector = - new Selector.callConstructor(constructor.name, - defaultClass.getLibrary()); - constructor.defaultImplementation = - defaultClass.lookupFactoryConstructor(selector); - } - if (constructor.defaultImplementation == null) { - // We failed to find a constructor named either - // "MyInterface.name" or "MyClass.name". - // TODO(aprelev@gmail.com): Use constructorNameForDiagnostics in - // the error message below. - error(node, - MessageKind.CANNOT_FIND_CONSTRUCTOR2, - {'constructorName': selector.name, 'className': defaultClass.name}); - } - } - - TreeElements resolveField(VariableElement element) { - Node tree = element.parseNode(compiler); - if(element.modifiers.isStatic() && element.variables.isTopLevel()) { - error(element.modifiers.getStatic(), - MessageKind.TOP_LEVEL_VARIABLE_DECLARED_STATIC); - } - ResolverVisitor visitor = visitorFor(element); - initializerDo(tree, visitor.visit); - - // Perform various checks as side effect of "computing" the type. - element.computeType(compiler); - - return visitor.mapping; - } - - TreeElements resolveParameter(Element element) { - Node tree = element.parseNode(compiler); - ResolverVisitor visitor = visitorFor(element.enclosingElement); - initializerDo(tree, visitor.visit); - return visitor.mapping; - } - - DartType resolveTypeAnnotation(Element element, TypeAnnotation annotation) { - DartType type = resolveReturnType(element, annotation); - if (type == compiler.types.voidType) { - error(annotation, MessageKind.VOID_NOT_ALLOWED); - } - return type; - } - - DartType resolveReturnType(Element element, TypeAnnotation annotation) { - if (annotation == null) return compiler.types.dynamicType; - DartType result = visitorFor(element).resolveTypeAnnotation(annotation); - if (result == null) { - // TODO(karklose): warning. - return compiler.types.dynamicType; - } - return result; - } - - /** - * Load and resolve the supertypes of [cls]. - * - * Warning: do not call this method directly. It should only be - * called by [resolveClass] and [ClassSupertypeResolver]. - */ - void loadSupertypes(ClassElement cls, Spannable from) { - compiler.withCurrentElement(cls, () => measure(() { - if (cls.supertypeLoadState == STATE_DONE) return; - if (cls.supertypeLoadState == STATE_STARTED) { - compiler.reportErrorCode(from, MessageKind.CYCLIC_CLASS_HIERARCHY, - {'className': cls.name}); - cls.supertypeLoadState = STATE_DONE; - cls.allSupertypes = const Link<DartType>().prepend( - compiler.objectClass.computeType(compiler)); - // TODO(ahe): We should also set cls.supertype here to avoid - // creating a malformed class hierarchy. - return; - } - cls.supertypeLoadState = STATE_STARTED; - compiler.withCurrentElement(cls, () { - // TODO(ahe): Cache the node in cls. - cls.parseNode(compiler).accept( - new ClassSupertypeResolver(compiler, cls)); - if (cls.supertypeLoadState != STATE_DONE) { - cls.supertypeLoadState = STATE_DONE; - } - }); - })); - } - - // TODO(johnniwinther): Remove this queue when resolution has been split into - // syntax and semantic resolution. - ClassElement currentlyResolvedClass; - Queue<ClassElement> pendingClassesToBeResolved = new Queue<ClassElement>(); - - /** - * Resolve the class [element]. - * - * Before calling this method, [element] was constructed by the - * scanner and most fields are null or empty. This method fills in - * these fields and also ensure that the supertypes of [element] are - * resolved. - * - * Warning: Do not call this method directly. Instead use - * [:element.ensureResolved(compiler):]. - */ - void resolveClass(ClassElement element) { - ClassElement previousResolvedClass = currentlyResolvedClass; - currentlyResolvedClass = element; - resolveClassInternal(element); - if (previousResolvedClass == null) { - while (!pendingClassesToBeResolved.isEmpty) { - pendingClassesToBeResolved.removeFirst().ensureResolved(compiler); - } - } - currentlyResolvedClass = previousResolvedClass; - } - - void _ensureClassWillBeResolved(ClassElement element) { - if (currentlyResolvedClass == null) { - element.ensureResolved(compiler); - } else { - pendingClassesToBeResolved.add(element); - } - } - - void resolveClassInternal(ClassElement element) { - if (!element.isPatch) { - compiler.withCurrentElement(element, () => measure(() { - assert(element.resolutionState == STATE_NOT_STARTED); - element.resolutionState = STATE_STARTED; - Node tree = element.parseNode(compiler); - loadSupertypes(element, tree); - - ClassResolverVisitor visitor = - new ClassResolverVisitor(compiler, element); - visitor.visit(tree); - element.resolutionState = STATE_DONE; - })); - if (element.isPatched) { - // Ensure handling patch after origin. - element.patch.ensureResolved(compiler); - } - } else { // Handle patch classes: - element.resolutionState = STATE_STARTED; - // Ensure handling origin before patch. - element.origin.ensureResolved(compiler); - // Ensure that the type is computed. - element.computeType(compiler); - // Copy class hiearchy from origin. - element.supertype = element.origin.supertype; - element.defaultClass = element.origin.defaultClass; - element.interfaces = element.origin.interfaces; - element.allSupertypes = element.origin.allSupertypes; - // Stepwise assignment to ensure invariant. - element.supertypeLoadState = STATE_STARTED; - element.supertypeLoadState = STATE_DONE; - element.resolutionState = STATE_DONE; - // TODO(johnniwinther): Check matching type variables and - // empty extends/implements clauses. - } - for (MetadataAnnotation metadata in element.metadata) { - metadata.ensureResolved(compiler); - } - } - - void checkClass(ClassElement element) { - if (element.isMixinApplication) { - checkMixinApplication(element); - } else { - checkClassMembers(element); - } - } - - void checkMixinApplication(MixinApplicationElement mixinApplication) { - Modifiers modifiers = mixinApplication.modifiers; - int illegalFlags = modifiers.flags & ~Modifiers.FLAG_ABSTRACT; - if (illegalFlags != 0) { - Modifiers illegalModifiers = new Modifiers.withFlags(null, illegalFlags); - compiler.reportErrorCode( - modifiers, - MessageKind.ILLEGAL_MIXIN_APPLICATION_MODIFIERS, - {'modifiers': illegalModifiers}); - } - - // In case of cyclic mixin applications, the mixin chain will have - // been cut. If so, we have already reported the error to the - // user so we just return from here. - ClassElement mixin = mixinApplication.mixin; - if (mixin == null) return; - - // Check that the mixed in class has Object as its superclass. - if (!mixin.superclass.isObject(compiler)) { - compiler.reportErrorCode(mixin, MessageKind.ILLEGAL_MIXIN_SUPERCLASS); - } - - // Check that the mixed in class doesn't have any constructors and - // make sure we aren't mixing in methods that use 'super'. - mixin.forEachLocalMember((Element member) { - if (member.isGenerativeConstructor() && !member.isSynthesized) { - compiler.reportErrorCode(member, MessageKind.ILLEGAL_MIXIN_CONSTRUCTOR); - } else { - // Get the resolution tree and check that the resolved member - // doesn't use 'super'. This is the part of the 'super' mixin - // check that happens when a function is resolved before the - // mixin application has been performed. - checkMixinSuperUses( - compiler.enqueuer.resolution.resolvedElements[member], - mixinApplication, - mixin); - } - }); - } - - void checkMixinSuperUses(TreeElements resolutionTree, - MixinApplicationElement mixinApplication, - ClassElement mixin) { - if (resolutionTree == null) return; - Set<Node> superUses = resolutionTree.superUses; - if (superUses.isEmpty) return; - compiler.reportErrorCode(mixinApplication, - MessageKind.ILLEGAL_MIXIN_WITH_SUPER, - {'className': mixin.name}); - // Show the user the problematic uses of 'super' in the mixin. - for (Node use in superUses) { - CompilationError error = MessageKind.ILLEGAL_MIXIN_SUPER_USE.error(); - compiler.reportMessage(compiler.spanFromNode(use), - error, Diagnostic.INFO); - } - } - - void checkClassMembers(ClassElement cls) { - assert(invariant(cls, cls.isDeclaration)); - if (cls.isObject(compiler)) return; - // TODO(johnniwinther): Should this be done on the implementation element as - // well? - cls.forEachMember((holder, member) { - compiler.withCurrentElement(member, () { - // Perform various checks as side effect of "computing" the type. - member.computeType(compiler); - - // Check modifiers. - if (member.isFunction() && member.modifiers.isFinal()) { - compiler.reportErrorCode( - member, MessageKind.ILLEGAL_FINAL_METHOD_MODIFIER); - } - if (member.isConstructor()) { - final mismatchedFlagsBits = - member.modifiers.flags & - (Modifiers.FLAG_STATIC | Modifiers.FLAG_ABSTRACT); - if (mismatchedFlagsBits != 0) { - final mismatchedFlags = - new Modifiers.withFlags(null, mismatchedFlagsBits); - compiler.reportErrorCode( - member, - MessageKind.ILLEGAL_CONSTRUCTOR_MODIFIERS, - {'modifiers': mismatchedFlags}); - } - checkConstructorNameHack(holder, member); - } - checkAbstractField(member); - checkValidOverride(member, cls.lookupSuperMember(member.name)); - checkUserDefinableOperator(member); - }); - }); - } - - // TODO(ahe): Remove this method. It is only needed while we store - // constructor names as ClassName$id. Once we start storing - // constructors as just id, this will be caught by the general - // mechanism for duplicate members. - /// Check that a constructor name does not conflict with a member. - void checkConstructorNameHack(ClassElement holder, FunctionElement member) { - // If the name of the constructor is the same as the name of the - // class, there cannot be a problem. - if (member.name == holder.name) return; - - SourceString name = - Elements.deconstructConstructorName(member.name, holder); - - // If the name could not be deconstructed, this is is from a - // factory method from a deprecated interface implementation. - if (name == null) return; - - Element otherMember = holder.lookupLocalMember(name); - if (otherMember != null) { - if (compiler.onDeprecatedFeature(member, 'conflicting constructor')) { - compiler.reportMessage( - compiler.spanFromElement(otherMember), - MessageKind.GENERIC.error({'text': 'This member conflicts with a' - ' constructor.'}), - Diagnostic.INFO); - } - } - } - - void checkAbstractField(Element member) { - // Only check for getters. The test can only fail if there is both a setter - // and a getter with the same name, and we only need to check each abstract - // field once, so we just ignore setters. - if (!member.isGetter()) return; - - // Find the associated abstract field. - ClassElement classElement = member.getEnclosingClass(); - Element lookupElement = classElement.lookupLocalMember(member.name); - if (lookupElement == null) { - compiler.internalErrorOnElement(member, - "No abstract field for accessor"); - } else if (!identical(lookupElement.kind, ElementKind.ABSTRACT_FIELD)) { - compiler.internalErrorOnElement( - member, "Inaccessible abstract field for accessor"); - } - AbstractFieldElement field = lookupElement; - - if (field.getter == null) return; - if (field.setter == null) return; - int getterFlags = field.getter.modifiers.flags | Modifiers.FLAG_ABSTRACT; - int setterFlags = field.setter.modifiers.flags | Modifiers.FLAG_ABSTRACT; - if (!identical(getterFlags, setterFlags)) { - final mismatchedFlags = - new Modifiers.withFlags(null, getterFlags ^ setterFlags); - compiler.reportErrorCode( - field.getter, - MessageKind.GETTER_MISMATCH, - {'modifiers': mismatchedFlags}); - compiler.reportErrorCode( - field.setter, - MessageKind.SETTER_MISMATCH, - {'modifiers': mismatchedFlags}); - } - } - - void checkUserDefinableOperator(Element member) { - FunctionElement function = member.asFunctionElement(); - if (function == null) return; - String value = member.name.stringValue; - if (value == null) return; - if (!(isUserDefinableOperator(value) || identical(value, 'unary-'))) return; - - bool isMinus = false; - int requiredParameterCount; - MessageKind messageKind; - FunctionSignature signature = function.computeSignature(compiler); - if (identical(value, 'unary-')) { - isMinus = true; - messageKind = MessageKind.MINUS_OPERATOR_BAD_ARITY; - requiredParameterCount = 0; - } else if (isMinusOperator(value)) { - isMinus = true; - messageKind = MessageKind.MINUS_OPERATOR_BAD_ARITY; - requiredParameterCount = 1; - } else if (isUnaryOperator(value)) { - messageKind = MessageKind.UNARY_OPERATOR_BAD_ARITY; - requiredParameterCount = 0; - } else if (isBinaryOperator(value)) { - messageKind = MessageKind.BINARY_OPERATOR_BAD_ARITY; - requiredParameterCount = 1; - } else if (isTernaryOperator(value)) { - messageKind = MessageKind.TERNARY_OPERATOR_BAD_ARITY; - requiredParameterCount = 2; - } else { - compiler.internalErrorOnElement(function, - 'Unexpected user defined operator $value'); - } - checkArity(function, requiredParameterCount, messageKind, isMinus); - } - - void checkArity(FunctionElement function, - int requiredParameterCount, MessageKind messageKind, - bool isMinus) { - FunctionExpression node = function.parseNode(compiler); - FunctionSignature signature = function.computeSignature(compiler); - if (signature.requiredParameterCount != requiredParameterCount) { - Node errorNode = node; - if (node.parameters != null) { - if (isMinus || - signature.requiredParameterCount < requiredParameterCount) { - // If there are too few parameters, point to the whole parameter list. - // For instance - // - // int operator +() {} - // ^^ - // - // int operator []=(value) {} - // ^^^^^^^ - // - // For operator -, always point the whole parameter list, like - // - // int operator -(a, b) {} - // ^^^^^^ - // - // instead of - // - // int operator -(a, b) {} - // ^ - // - // since the correction might not be to remove 'b' but instead to - // remove 'a, b'. - errorNode = node.parameters; - } else { - errorNode = node.parameters.nodes.skip(requiredParameterCount).head; - } - } - compiler.reportErrorCode( - errorNode, messageKind, {'operatorName': function.name}); - } - if (signature.optionalParameterCount != 0) { - Node errorNode = - node.parameters.nodes.skip(signature.requiredParameterCount).head; - if (signature.optionalParametersAreNamed) { - compiler.reportErrorCode( - errorNode, - MessageKind.OPERATOR_NAMED_PARAMETERS, - {'operatorName': function.name}); - } else { - compiler.reportErrorCode( - errorNode, - MessageKind.OPERATOR_OPTIONAL_PARAMETERS, - {'operatorName': function.name}); - } - } - } - - reportErrorWithContext(Element errorneousElement, - MessageKind errorMessage, - Element contextElement, - MessageKind contextMessage) { - compiler.reportErrorCode( - errorneousElement, - errorMessage, - {'memberName': contextElement.name, - 'className': contextElement.getEnclosingClass().name}); - compiler.reportMessage( - compiler.spanFromElement(contextElement), - contextMessage.error(), - Diagnostic.INFO); - } - - void checkValidOverride(Element member, Element superMember) { - if (superMember == null) return; - if (member.modifiers.isStatic()) { - reportErrorWithContext( - member, MessageKind.NO_STATIC_OVERRIDE, - superMember, MessageKind.NO_STATIC_OVERRIDE_CONT); - } else { - FunctionElement superFunction = superMember.asFunctionElement(); - FunctionElement function = member.asFunctionElement(); - if (superFunction == null || superFunction.isAccessor()) { - // Field or accessor in super. - if (function != null && !function.isAccessor()) { - // But a plain method in this class. - reportErrorWithContext( - member, MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD, - superMember, MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD_CONT); - } - } else { - // Instance method in super. - if (function == null || function.isAccessor()) { - // But a field (or accessor) in this class. - reportErrorWithContext( - member, MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD, - superMember, MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD_CONT); - } else { - // Both are plain instance methods. - if (superFunction.requiredParameterCount(compiler) != - function.requiredParameterCount(compiler)) { - reportErrorWithContext( - member, - MessageKind.BAD_ARITY_OVERRIDE, - superMember, - MessageKind.BAD_ARITY_OVERRIDE_CONT); - } - // TODO(ahe): Check optional parameters. - } - } - } - } - - FunctionSignature resolveSignature(FunctionElement element) { - return compiler.withCurrentElement(element, () { - FunctionExpression node = - compiler.parser.measure(() => element.parseNode(compiler)); - return measure(() => SignatureResolver.analyze( - compiler, node.parameters, node.returnType, element)); - }); - } - - FunctionSignature resolveFunctionExpression(Element element, - FunctionExpression node) { - return measure(() => SignatureResolver.analyze( - compiler, node.parameters, node.returnType, element)); - } - - void resolveTypedef(TypedefElement element) { - if (element.isResolved || element.isBeingResolved) return; - element.isBeingResolved = true; - return compiler.withCurrentElement(element, () { - measure(() { - Typedef node = - compiler.parser.measure(() => element.parseNode(compiler)); - TypedefResolverVisitor visitor = - new TypedefResolverVisitor(compiler, element); - visitor.visit(node); - - element.isBeingResolved = false; - element.isResolved = true; - }); - }); - } - - FunctionType computeFunctionType(Element element, - FunctionSignature signature) { - var parameterTypes = new LinkBuilder<DartType>(); - for (Element parameter in signature.requiredParameters) { - parameterTypes.addLast(parameter.computeType(compiler)); - } - var optionalParameterTypes = const Link<DartType>(); - var namedParameters = const Link<SourceString>(); - var namedParameterTypes = const Link<DartType>(); - if (signature.optionalParametersAreNamed) { - var namedParametersBuilder = new LinkBuilder<SourceString>(); - var namedParameterTypesBuilder = new LinkBuilder<DartType>(); - for (Element parameter in signature.orderedOptionalParameters) { - namedParametersBuilder.addLast(parameter.name); - namedParameterTypesBuilder.addLast(parameter.computeType(compiler)); - } - namedParameters = namedParametersBuilder.toLink(); - namedParameterTypes = namedParameterTypesBuilder.toLink(); - } else { - var optionalParameterTypesBuilder = new LinkBuilder<DartType>(); - for (Element parameter in signature.optionalParameters) { - optionalParameterTypesBuilder.addLast(parameter.computeType(compiler)); - } - optionalParameterTypes = optionalParameterTypesBuilder.toLink(); - } - return new FunctionType(element, - signature.returnType, - parameterTypes.toLink(), - optionalParameterTypes, - namedParameters, - namedParameterTypes); - } - - void resolveMetadataAnnotation(PartialMetadataAnnotation annotation) { - compiler.withCurrentElement(annotation.annotatedElement, () => measure(() { - assert(annotation.resolutionState == STATE_NOT_STARTED); - annotation.resolutionState = STATE_STARTED; - - Node node = annotation.parseNode(compiler); - ResolverVisitor visitor = - visitorFor(annotation.annotatedElement.enclosingElement); - node.accept(visitor); - annotation.value = compiler.metadataHandler.compileNodeWithDefinitions( - node, visitor.mapping, isConst: true); - - annotation.resolutionState = STATE_DONE; - })); - } - - error(Node node, MessageKind kind, [arguments = const {}]) { - ResolutionError message = new ResolutionError(kind, arguments); - compiler.reportError(node, message); - } -} - -class InitializerResolver { - final ResolverVisitor visitor; - final Map<SourceString, Node> initialized; - Link<Node> initializers; - bool hasSuper; - - InitializerResolver(this.visitor) - : initialized = new Map<SourceString, Node>(), hasSuper = false; - - error(Node node, MessageKind kind, [arguments = const {}]) { - visitor.error(node, kind, arguments); - } - - warning(Node node, MessageKind kind, [arguments = const {}]) { - visitor.warning(node, kind, arguments); - } - - bool isFieldInitializer(SendSet node) { - if (node.selector.asIdentifier() == null) return false; - if (node.receiver == null) return true; - if (node.receiver.asIdentifier() == null) return false; - return node.receiver.asIdentifier().isThis(); - } - - void checkForDuplicateInitializers(SourceString name, Node init) { - if (initialized.containsKey(name)) { - error(init, MessageKind.DUPLICATE_INITIALIZER, {'fieldName': name}); - warning(initialized[name], MessageKind.ALREADY_INITIALIZED, - {'fieldName': name}); - } - initialized[name] = init; - } - - void resolveFieldInitializer(FunctionElement constructor, SendSet init) { - // init is of the form [this.]field = value. - final Node selector = init.selector; - final SourceString name = selector.asIdentifier().source; - // Lookup target field. - Element target; - if (isFieldInitializer(init)) { - target = constructor.getEnclosingClass().lookupLocalMember(name); - if (target == null) { - error(selector, MessageKind.CANNOT_RESOLVE, {'name': name}); - } else if (target.kind != ElementKind.FIELD) { - error(selector, MessageKind.NOT_A_FIELD, {'fieldName': name}); - } else if (!target.isInstanceMember()) { - error(selector, MessageKind.INIT_STATIC_FIELD, {'fieldName': name}); - } - } else { - error(init, MessageKind.INVALID_RECEIVER_IN_INITIALIZER); - } - visitor.useElement(init, target); - visitor.world.registerStaticUse(target); - checkForDuplicateInitializers(name, init); - // Resolve initializing value. - visitor.visitInStaticContext(init.arguments.head); - } - - ClassElement getSuperOrThisLookupTarget(FunctionElement constructor, - bool isSuperCall, - Node diagnosticNode) { - ClassElement lookupTarget = constructor.getEnclosingClass(); - if (isSuperCall) { - // Calculate correct lookup target and constructor name. - if (identical(lookupTarget, visitor.compiler.objectClass)) { - error(diagnosticNode, MessageKind.SUPER_INITIALIZER_IN_OBJECT); - } else { - return lookupTarget.supertype.element; - } - } - return lookupTarget; - } - - Element resolveSuperOrThisForSend(FunctionElement constructor, - FunctionExpression functionNode, - Send call) { - // Resolve the selector and the arguments. - ResolverTask resolver = visitor.compiler.resolver; - visitor.inStaticContext(() { - visitor.resolveSelector(call); - visitor.resolveArguments(call.argumentsNode); - }); - Selector selector = visitor.mapping.getSelector(call); - bool isSuperCall = Initializers.isSuperConstructorCall(call); - - ClassElement lookupTarget = getSuperOrThisLookupTarget(constructor, - isSuperCall, - call); - Selector constructorSelector = - visitor.getRedirectingThisOrSuperConstructorSelector(call); - FunctionElement calledConstructor = - lookupTarget.lookupConstructor(constructorSelector); - - final bool isImplicitSuperCall = false; - final SourceString className = lookupTarget.name; - verifyThatConstructorMatchesCall(calledConstructor, - selector, - isImplicitSuperCall, - call, - className, - constructorSelector); - - visitor.useElement(call, calledConstructor); - visitor.world.registerStaticUse(calledConstructor); - return calledConstructor; - } - - void resolveImplicitSuperConstructorSend(FunctionElement constructor, - FunctionExpression functionNode) { - // If the class has a super resolve the implicit super call. - ClassElement classElement = constructor.getEnclosingClass(); - ClassElement superClass = classElement.superclass; - if (classElement != visitor.compiler.objectClass) { - assert(superClass != null); - assert(superClass.resolutionState == STATE_DONE); - SourceString constructorName = const SourceString(''); - Selector callToMatch = new Selector.call( - constructorName, - classElement.getLibrary(), - 0); - - final bool isSuperCall = true; - ClassElement lookupTarget = getSuperOrThisLookupTarget(constructor, - isSuperCall, - functionNode); - Selector constructorSelector = new Selector.callDefaultConstructor( - visitor.enclosingElement.getLibrary()); - Element calledConstructor = lookupTarget.lookupConstructor( - constructorSelector); - - final SourceString className = lookupTarget.name; - final bool isImplicitSuperCall = true; - verifyThatConstructorMatchesCall(calledConstructor, - callToMatch, - isImplicitSuperCall, - functionNode, - className, - constructorSelector); - - visitor.world.registerStaticUse(calledConstructor); - } - } - - void verifyThatConstructorMatchesCall( - FunctionElement lookedupConstructor, - Selector call, - bool isImplicitSuperCall, - Node diagnosticNode, - SourceString className, - Selector constructorSelector) { - if (lookedupConstructor == null - || !lookedupConstructor.isGenerativeConstructor()) { - var fullConstructorName = - visitor.compiler.resolver.constructorNameForDiagnostics( - className, - constructorSelector.name); - MessageKind kind = isImplicitSuperCall - ? MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT - : MessageKind.CANNOT_RESOLVE_CONSTRUCTOR; - error(diagnosticNode, kind, {'constructorName': fullConstructorName}); - } else { - if (!call.applies(lookedupConstructor, visitor.compiler)) { - MessageKind kind = isImplicitSuperCall - ? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT - : MessageKind.NO_MATCHING_CONSTRUCTOR; - error(diagnosticNode, kind); - } - } - } - - FunctionElement resolveRedirection(FunctionElement constructor, - FunctionExpression functionNode) { - if (functionNode.initializers == null) return null; - Link<Node> link = functionNode.initializers.nodes; - if (!link.isEmpty && Initializers.isConstructorRedirect(link.head)) { - return resolveSuperOrThisForSend(constructor, functionNode, link.head); - } - return null; - } - - /** - * Resolve all initializers of this constructor. In the case of a redirecting - * constructor, the resolved constructor's function element is returned. - */ - FunctionElement resolveInitializers(FunctionElement constructor, - FunctionExpression functionNode) { - // Keep track of all "this.param" parameters specified for constructor so - // that we can ensure that fields are initialized only once. - FunctionSignature functionParameters = - constructor.computeSignature(visitor.compiler); - functionParameters.forEachParameter((Element element) { - if (identical(element.kind, ElementKind.FIELD_PARAMETER)) { - checkForDuplicateInitializers(element.name, - element.parseNode(visitor.compiler)); - } - }); - - if (functionNode.initializers == null) { - initializers = const Link<Node>(); - } else { - initializers = functionNode.initializers.nodes; - } - FunctionElement result; - bool resolvedSuper = false; - for (Link<Node> link = initializers; - !link.isEmpty; - link = link.tail) { - if (link.head.asSendSet() != null) { - final SendSet init = link.head.asSendSet(); - resolveFieldInitializer(constructor, init); - } else if (link.head.asSend() != null) { - final Send call = link.head.asSend(); - if (Initializers.isSuperConstructorCall(call)) { - if (resolvedSuper) { - error(call, MessageKind.DUPLICATE_SUPER_INITIALIZER); - } - resolveSuperOrThisForSend(constructor, functionNode, call); - resolvedSuper = true; - } else if (Initializers.isConstructorRedirect(call)) { - // Check that there is no body (Language specification 7.5.1). - if (functionNode.hasBody()) { - error(functionNode, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY); - } - // Check that there are no other initializers. - if (!initializers.tail.isEmpty) { - error(call, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER); - } - return resolveSuperOrThisForSend(constructor, functionNode, call); - } else { - visitor.error(call, MessageKind.CONSTRUCTOR_CALL_EXPECTED); - return null; - } - } else { - error(link.head, MessageKind.INVALID_INITIALIZER); - } - } - if (!resolvedSuper) { - resolveImplicitSuperConstructorSend(constructor, functionNode); - } - return null; // If there was no redirection always return null. - } -} - -class CommonResolverVisitor<R> extends Visitor<R> { - final Compiler compiler; - - CommonResolverVisitor(Compiler this.compiler); - - R visitNode(Node node) { - cancel(node, - 'internal error: Unhandled node: ${node.getObjectDescription()}'); - } - - R visitEmptyStatement(Node node) => null; - - /** Convenience method for visiting nodes that may be null. */ - R visit(Node node) => (node == null) ? null : node.accept(this); - - void error(Node node, MessageKind kind, [Map arguments = const {}]) { - ResolutionError message = new ResolutionError(kind, arguments); - compiler.reportError(node, message); - } - - void warning(Node node, MessageKind kind, [Map arguments = const {}]) { - ResolutionWarning message = new ResolutionWarning(kind, arguments); - compiler.reportWarning(node, message); - } - - void cancel(Node node, String message) { - compiler.cancel(message, node: node); - } - - void internalError(Node node, String message) { - compiler.internalError(message, node: node); - } - - void unimplemented(Node node, String message) { - compiler.unimplemented(message, node: node); - } -} - -abstract class LabelScope { - LabelScope get outer; - LabelElement lookup(String label); -} - -class LabeledStatementLabelScope implements LabelScope { - final LabelScope outer; - final Map<String, LabelElement> labels; - LabeledStatementLabelScope(this.outer, this.labels); - LabelElement lookup(String labelName) { - LabelElement label = labels[labelName]; - if (label != null) return label; - return outer.lookup(labelName); - } -} - -class SwitchLabelScope implements LabelScope { - final LabelScope outer; - final Map<String, LabelElement> caseLabels; - - SwitchLabelScope(this.outer, this.caseLabels); - - LabelElement lookup(String labelName) { - LabelElement result = caseLabels[labelName]; - if (result != null) return result; - return outer.lookup(labelName); - } -} - -class EmptyLabelScope implements LabelScope { - const EmptyLabelScope(); - LabelElement lookup(String label) => null; - LabelScope get outer { - throw 'internal error: empty label scope has no outer'; - } -} - -class StatementScope { - LabelScope labels; - Link<TargetElement> breakTargetStack; - Link<TargetElement> continueTargetStack; - // Used to provide different numbers to statements if one is inside the other. - // Can be used to make otherwise duplicate labels unique. - int nestingLevel = 0; - - StatementScope() - : labels = const EmptyLabelScope(), - breakTargetStack = const Link<TargetElement>(), - continueTargetStack = const Link<TargetElement>(); - - LabelElement lookupLabel(String label) { - return labels.lookup(label); - } - - TargetElement currentBreakTarget() => - breakTargetStack.isEmpty ? null : breakTargetStack.head; - - TargetElement currentContinueTarget() => - continueTargetStack.isEmpty ? null : continueTargetStack.head; - - void enterLabelScope(Map<String, LabelElement> elements) { - labels = new LabeledStatementLabelScope(labels, elements); - nestingLevel++; - } - - void exitLabelScope() { - nestingLevel--; - labels = labels.outer; - } - - void enterLoop(TargetElement element) { - breakTargetStack = breakTargetStack.prepend(element); - continueTargetStack = continueTargetStack.prepend(element); - nestingLevel++; - } - - void exitLoop() { - nestingLevel--; - breakTargetStack = breakTargetStack.tail; - continueTargetStack = continueTargetStack.tail; - } - - void enterSwitch(TargetElement breakElement, - Map<String, LabelElement> continueElements) { - breakTargetStack = breakTargetStack.prepend(breakElement); - labels = new SwitchLabelScope(labels, continueElements); - nestingLevel++; - } - - void exitSwitch() { - nestingLevel--; - breakTargetStack = breakTargetStack.tail; - labels = labels.outer; - } -} - -class TypeResolver { - final Compiler compiler; - - TypeResolver(this.compiler); - - Element resolveTypeName(Scope scope, - SourceString prefixName, - Identifier typeName) { - if (prefixName != null) { - Element e = scope.lookup(prefixName); - if (e != null) { - if (identical(e.kind, ElementKind.PREFIX)) { - // The receiver is a prefix. Lookup in the imported members. - PrefixElement prefix = e; - return prefix.lookupLocalMember(typeName.source); - } else if (identical(e.kind, ElementKind.CLASS)) { - // TODO(johnniwinther): Remove this case. - // The receiver is the class part of a named constructor. - return e; - } - } else { - // The caller creates the ErroneousElement for the MalformedType. - return null; - } - } else { - String stringValue = typeName.source.stringValue; - if (identical(stringValue, 'void')) { - return compiler.types.voidType.element; - } else if (identical(stringValue, 'Dynamic')) { - // TODO(aprelev@gmail.com): Remove deprecated Dynamic keyword support. - compiler.onDeprecatedFeature(typeName, 'Dynamic'); - return compiler.dynamicClass; - } else if (identical(stringValue, 'dynamic')) { - return compiler.dynamicClass; - } else { - return scope.lookup(typeName.source); - } - } - } - - // TODO(johnniwinther): Change [onFailure] and [whenResolved] to use boolean - // flags instead of closures. - DartType resolveTypeAnnotation( - TypeAnnotation node, - Scope scope, - Element enclosingElement, - {onFailure(Node node, MessageKind kind, [Map arguments]), - whenResolved(Node node, DartType type)}) { - if (onFailure == null) { - onFailure = (n, k, [arguments]) {}; - } - if (whenResolved == null) { - whenResolved = (n, t) {}; - } - if (scope == null) { - compiler.internalError('resolveTypeAnnotation: no scope specified'); - } - return resolveTypeAnnotationInContext(scope, node, enclosingElement, - onFailure, whenResolved); - } - - DartType resolveTypeAnnotationInContext(Scope scope, TypeAnnotation node, - Element enclosingElement, - onFailure, whenResolved) { - Identifier typeName; - SourceString prefixName; - Send send = node.typeName.asSend(); - if (send != null) { - // The type name is of the form [: prefix . identifier :]. - prefixName = send.receiver.asIdentifier().source; - typeName = send.selector.asIdentifier(); - } else { - typeName = node.typeName.asIdentifier(); - } - - Element element = resolveTypeName(scope, prefixName, typeName); - DartType type; - - DartType reportFailureAndCreateType(MessageKind messageKind, - Map messageArguments) { - onFailure(node, messageKind, messageArguments); - var erroneousElement = new ErroneousElementX( - messageKind, messageArguments, typeName.source, enclosingElement); - var arguments = new LinkBuilder<DartType>(); - resolveTypeArguments( - node, null, enclosingElement, - scope, onFailure, whenResolved, arguments); - return new MalformedType(erroneousElement, null, arguments.toLink()); - } - - DartType checkNoTypeArguments(DartType type) { - var arguments = new LinkBuilder<DartType>(); - bool hashTypeArgumentMismatch = resolveTypeArguments( - node, const Link<DartType>(), enclosingElement, - scope, onFailure, whenResolved, arguments); - if (hashTypeArgumentMismatch) { - type = new MalformedType( - new ErroneousElementX(MessageKind.TYPE_ARGUMENT_COUNT_MISMATCH, - {'type': node}, typeName.source, enclosingElement), - type, arguments.toLink()); - } - return type; - } - - if (element == null) { - type = reportFailureAndCreateType( - MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': node.typeName}); - } else if (element.isAmbiguous()) { - AmbiguousElement ambiguous = element; - type = reportFailureAndCreateType( - ambiguous.messageKind, ambiguous.messageArguments); - } else if (!element.impliesType()) { - type = reportFailureAndCreateType( - MessageKind.NOT_A_TYPE, {'node': node.typeName}); - } else { - if (identical(element, compiler.types.voidType.element) || - identical(element, compiler.types.dynamicType.element)) { - type = checkNoTypeArguments(element.computeType(compiler)); - } else if (element.isClass()) { - ClassElement cls = element; - compiler.resolver._ensureClassWillBeResolved(cls); - element.computeType(compiler); - var arguments = new LinkBuilder<DartType>(); - bool hashTypeArgumentMismatch = resolveTypeArguments( - node, cls.typeVariables, enclosingElement, - scope, onFailure, whenResolved, arguments); - if (hashTypeArgumentMismatch) { - type = new MalformedType( - new ErroneousElementX(MessageKind.TYPE_ARGUMENT_COUNT_MISMATCH, - {'type': node}, typeName.source, enclosingElement), - new InterfaceType(cls.declaration, arguments.toLink())); - } else { - if (arguments.isEmpty) { - type = cls.rawType; - } else { - type = new InterfaceType(cls.declaration, arguments.toLink()); - } - } - } else if (element.isTypedef()) { - TypedefElement typdef = element; - // TODO(ahe): Should be [ensureResolved]. - compiler.resolveTypedef(typdef); - var arguments = new LinkBuilder<DartType>(); - bool hashTypeArgumentMismatch = resolveTypeArguments( - node, typdef.typeVariables, enclosingElement, - scope, onFailure, whenResolved, arguments); - if (hashTypeArgumentMismatch) { - type = new MalformedType( - new ErroneousElementX(MessageKind.TYPE_ARGUMENT_COUNT_MISMATCH, - {'type': node}, typeName.source, enclosingElement), - new TypedefType(typdef, arguments.toLink())); - } else { - if (arguments.isEmpty) { - type = typdef.rawType; - } else { - type = new TypedefType(typdef, arguments.toLink()); - } - } - } else if (element.isTypeVariable()) { - if (enclosingElement.isInStaticMember()) { - compiler.reportWarning(node, - MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER.message( - {'typeVariableName': node})); - type = new MalformedType( - new ErroneousElementX( - MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER, - {'typeVariableName': node}, - typeName.source, enclosingElement), - element.computeType(compiler)); - } else { - type = element.computeType(compiler); - } - type = checkNoTypeArguments(type); - } else { - compiler.cancel("unexpected element kind ${element.kind}", - node: node); - } - } - whenResolved(node, type); - return type; - } - - /** - * Resolves the type arguments of [node] and adds these to [arguments]. - * - * Returns [: true :] if the number of type arguments did not match the - * number of type variables. - */ - bool resolveTypeArguments( - TypeAnnotation node, - Link<DartType> typeVariables, - Element enclosingElement, - Scope scope, - onFailure, whenResolved, - LinkBuilder<DartType> arguments) { - if (node.typeArguments == null) { - return false; - } - bool typeArgumentCountMismatch = false; - for (Link<Node> typeArguments = node.typeArguments.nodes; - !typeArguments.isEmpty; - typeArguments = typeArguments.tail) { - if (typeVariables != null && typeVariables.isEmpty) { - onFailure(typeArguments.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT); - typeArgumentCountMismatch = true; - } - DartType argType = resolveTypeAnnotationInContext(scope, - typeArguments.head, - enclosingElement, - onFailure, - whenResolved); - arguments.addLast(argType); - if (typeVariables != null && !typeVariables.isEmpty) { - typeVariables = typeVariables.tail; - } - } - if (typeVariables != null && !typeVariables.isEmpty) { - onFailure(node.typeArguments, MessageKind.MISSING_TYPE_ARGUMENT); - typeArgumentCountMismatch = true; - } - return typeArgumentCountMismatch; - } -} - -/** - * Core implementation of resolution. - * - * Do not subclass or instantiate this class outside this library - * except for testing. - */ -class ResolverVisitor extends CommonResolverVisitor<Element> { - final TreeElementMapping mapping; - Element enclosingElement; - final TypeResolver typeResolver; - bool inInstanceContext; - bool inCheckContext; - bool inCatchBlock; - Scope scope; - ClassElement currentClass; - ExpressionStatement currentExpressionStatement; - bool typeRequired = false; - StatementScope statementScope; - int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION - | ElementCategory.IMPLIES_TYPE; - - ResolverVisitor(Compiler compiler, Element element, this.mapping) - : this.enclosingElement = element, - // When the element is a field, we are actually resolving its - // initial value, which should not have access to instance - // fields. - inInstanceContext = (element.isInstanceMember() && !element.isField()) - || element.isGenerativeConstructor(), - this.currentClass = element.isMember() ? element.getEnclosingClass() - : null, - this.statementScope = new StatementScope(), - typeResolver = new TypeResolver(compiler), - scope = element.buildScope(), - inCheckContext = compiler.enableTypeAssertions, - inCatchBlock = false, - super(compiler); - - ResolutionEnqueuer get world => compiler.enqueuer.resolution; - - Element lookup(Node node, SourceString name) { - Element result = scope.lookup(name); - if (!Elements.isUnresolved(result)) { - if (!inInstanceContext && result.isInstanceMember()) { - compiler.reportErrorCode( - node, MessageKind.NO_INSTANCE_AVAILABLE, {'name': name}); - return new ErroneousElementX(MessageKind.NO_INSTANCE_AVAILABLE, - {'name': name}, - name, enclosingElement); - } else if (result.isAmbiguous()) { - AmbiguousElement ambiguous = result; - compiler.reportErrorCode( - node, ambiguous.messageKind, ambiguous.messageArguments); - return new ErroneousElementX(ambiguous.messageKind, - ambiguous.messageArguments, - name, enclosingElement); - } - } - return result; - } - - // Create, or reuse an already created, statement element for a statement. - TargetElement getOrCreateTargetElement(Node statement) { - TargetElement element = mapping[statement]; - if (element == null) { - element = new TargetElementX(statement, - statementScope.nestingLevel, - enclosingElement); - mapping[statement] = element; - } - return element; - } - - doInCheckContext(action()) { - bool wasInCheckContext = inCheckContext; - inCheckContext = true; - var result = action(); - inCheckContext = wasInCheckContext; - return result; - } - - inStaticContext(action()) { - bool wasInstanceContext = inInstanceContext; - inInstanceContext = false; - var result = action(); - inInstanceContext = wasInstanceContext; - return result; - } - - visitInStaticContext(Node node) { - inStaticContext(() => visit(node)); - } - - ErroneousElement warnAndCreateErroneousElement(Node node, - SourceString name, - MessageKind kind, - [Map arguments = const {}]) { - ResolutionWarning warning = new ResolutionWarning(kind, arguments); - compiler.reportWarning(node, warning); - return new ErroneousElementX(kind, arguments, name, enclosingElement); - } - - Element visitIdentifier(Identifier node) { - if (node.isThis()) { - if (!inInstanceContext) { - error(node, MessageKind.NO_INSTANCE_AVAILABLE, {'name': node}); - } - return null; - } else if (node.isSuper()) { - if (!inInstanceContext) error(node, MessageKind.NO_SUPER_IN_STATIC); - if ((ElementCategory.SUPER & allowedCategory) == 0) { - error(node, MessageKind.INVALID_USE_OF_SUPER); - } - return null; - } else { - Element element = lookup(node, node.source); - if (element == null) { - if (!inInstanceContext) { - element = warnAndCreateErroneousElement(node, node.source, - MessageKind.CANNOT_RESOLVE, - {'name': node}); - } - } else if (element.isErroneous()) { - // Use the erroneous element. - } else { - if ((element.kind.category & allowedCategory) == 0) { - // TODO(ahe): Improve error message. Need UX input. - error(node, MessageKind.GENERIC, - {'text': "is not an expression $element"}); - } - } - if (!Elements.isUnresolved(element) - && element.kind == ElementKind.CLASS) { - ClassElement classElement = element; - classElement.ensureResolved(compiler); - } - return useElement(node, element); - } - } - - Element visitTypeAnnotation(TypeAnnotation node) { - DartType type = resolveTypeAnnotation(node); - if (type != null) { - if (inCheckContext) { - compiler.enqueuer.resolution.registerIsCheck(type); - } - return type.element; - } - return null; - } - - Element defineElement(Node node, Element element, - {bool doAddToScope: true}) { - compiler.ensure(element != null); - mapping[node] = element; - if (doAddToScope) { - Element existing = scope.add(element); - if (existing != element) { - error(node, MessageKind.DUPLICATE_DEFINITION, {'name': node}); - } - } - return element; - } - - Element useElement(Node node, Element element) { - if (element == null) return null; - return mapping[node] = element; - } - - DartType useType(TypeAnnotation annotation, DartType type) { - if (type != null) { - mapping.setType(annotation, type); - useElement(annotation, type.element); - } - return type; - } - - bool isNamedConstructor(Send node) => node.receiver != null; - - Selector getRedirectingThisOrSuperConstructorSelector(Send node) { - if (isNamedConstructor(node)) { - SourceString constructorName = node.selector.asIdentifier().source; - return new Selector.callConstructor( - constructorName, - enclosingElement.getLibrary()); - } else { - return new Selector.callDefaultConstructor( - enclosingElement.getLibrary()); - } - } - - FunctionElement resolveConstructorRedirection(FunctionElement constructor) { - FunctionExpression node = constructor.parseNode(compiler); - - // A synthetic constructor does not have a node. - if (node == null) return null; - if (node.initializers == null) return null; - Link<Node> initializers = node.initializers.nodes; - if (!initializers.isEmpty && - Initializers.isConstructorRedirect(initializers.head)) { - Selector selector = - getRedirectingThisOrSuperConstructorSelector(initializers.head); - final ClassElement classElement = constructor.getEnclosingClass(); - return classElement.lookupConstructor(selector); - } - return null; - } - - void setupFunction(FunctionExpression node, FunctionElement function) { - scope = new MethodScope(scope, function); - - // Put the parameters in scope. - FunctionSignature functionParameters = - function.computeSignature(compiler); - Link<Node> parameterNodes = (node.parameters == null) - ? const Link<Node>() : node.parameters.nodes; - functionParameters.forEachParameter((Element element) { - if (element == functionParameters.optionalParameters.head) { - NodeList nodes = parameterNodes.head; - parameterNodes = nodes.nodes; - } - VariableDefinitions variableDefinitions = parameterNodes.head; - Node parameterNode = variableDefinitions.definitions.nodes.head; - initializerDo(parameterNode, (n) => n.accept(this)); - // Field parameters (this.x) are not visible inside the constructor. The - // fields they reference are visible, but must be resolved independently. - if (element.kind == ElementKind.FIELD_PARAMETER) { - useElement(parameterNode, element); - } else { - defineElement(variableDefinitions.definitions.nodes.head, element); - } - parameterNodes = parameterNodes.tail; - }); - } - - visitCascade(Cascade node) { - visit(node.expression); - } - - visitCascadeReceiver(CascadeReceiver node) { - visit(node.expression); - } - - Element visitClassNode(ClassNode node) { - cancel(node, "shouldn't be called"); - } - - visitIn(Node node, Scope nestedScope) { - Scope oldScope = scope; - scope = nestedScope; - Element element = visit(node); - scope = oldScope; - return element; - } - - /** - * Introduces new default targets for break and continue - * before visiting the body of the loop - */ - visitLoopBodyIn(Node loop, Node body, Scope bodyScope) { - TargetElement element = getOrCreateTargetElement(loop); - statementScope.enterLoop(element); - visitIn(body, bodyScope); - statementScope.exitLoop(); - if (!element.isTarget) { - mapping.remove(loop); - } - } - - visitBlock(Block node) { - visitIn(node.statements, new BlockScope(scope)); - } - - visitDoWhile(DoWhile node) { - visitLoopBodyIn(node, node.body, new BlockScope(scope)); - visit(node.condition); - } - - visitEmptyStatement(EmptyStatement node) { } - - visitExpressionStatement(ExpressionStatement node) { - ExpressionStatement oldExpressionStatement = currentExpressionStatement; - currentExpressionStatement = node; - visit(node.expression); - currentExpressionStatement = oldExpressionStatement; - } - - visitFor(For node) { - Scope blockScope = new BlockScope(scope); - visitIn(node.initializer, blockScope); - visitIn(node.condition, blockScope); - visitIn(node.update, blockScope); - visitLoopBodyIn(node, node.body, blockScope); - } - - visitFunctionDeclaration(FunctionDeclaration node) { - assert(node.function.name != null); - visit(node.function); - FunctionElement functionElement = mapping[node.function]; - // TODO(floitsch): this might lead to two errors complaining about - // shadowing. - defineElement(node, functionElement); - } - - visitFunctionExpression(FunctionExpression node) { - visit(node.returnType); - SourceString name; - if (node.name == null) { - name = const SourceString(""); - } else { - name = node.name.asIdentifier().source; - } - - FunctionElement function = new FunctionElementX.node( - name, node, ElementKind.FUNCTION, Modifiers.EMPTY, - enclosingElement); - Scope oldScope = scope; // The scope is modified by [setupFunction]. - setupFunction(node, function); - defineElement(node, function, doAddToScope: node.name != null); - - Element previousEnclosingElement = enclosingElement; - enclosingElement = function; - // Run the body in a fresh statement scope. - StatementScope oldStatementScope = statementScope; - statementScope = new StatementScope(); - visit(node.body); - statementScope = oldStatementScope; - - scope = oldScope; - enclosingElement = previousEnclosingElement; - - world.registerInstantiatedClass(compiler.functionClass); - } - - visitIf(If node) { - visit(node.condition); - visit(node.thenPart); - visit(node.elsePart); - } - - static bool isLogicalOperator(Identifier op) { - String str = op.source.stringValue; - return (identical(str, '&&') || str == '||' || str == '!'); - } - - Element resolveSend(Send node) { - Selector selector = resolveSelector(node); - if (node.isSuperCall) mapping.superUses.add(node); - - if (node.receiver == null) { - // If this send is of the form "assert(expr);", then - // this is an assertion. - if (selector.isAssert()) { - if (selector.argumentCount != 1) { - error(node.selector, - MessageKind.WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT, - {'argumentCount': selector.argumentCount}); - } else if (selector.namedArgumentCount != 0) { - error(node.selector, - MessageKind.ASSERT_IS_GIVEN_NAMED_ARGUMENTS, - {'argumentCount': selector.namedArgumentCount}); - } - return compiler.assertMethod; - } - - return node.selector.accept(this); - } - - var oldCategory = allowedCategory; - allowedCategory |= ElementCategory.PREFIX | ElementCategory.SUPER; - Element resolvedReceiver = visit(node.receiver); - allowedCategory = oldCategory; - - Element target; - SourceString name = node.selector.asIdentifier().source; - if (identical(name.stringValue, 'this')) { - error(node.selector, MessageKind.GENERIC, - {'text': "expected an identifier"}); - } else if (node.isSuperCall) { - if (node.isOperator) { - if (isUserDefinableOperator(name.stringValue)) { - name = selector.name; - } else { - error(node.selector, MessageKind.ILLEGAL_SUPER_SEND, {'name': name}); - } - } - if (!inInstanceContext) { - error(node.receiver, MessageKind.NO_INSTANCE_AVAILABLE, {'name': name}); - return null; - } - if (currentClass.supertype == null) { - // This is just to guard against internal errors, so no need - // for a real error message. - error(node.receiver, MessageKind.GENERIC, - {'text': "Object has no superclass"}); - } - // TODO(johnniwinther): Ensure correct behavior if currentClass is a - // patch. - target = currentClass.lookupSuperMember(name); - // [target] may be null which means invoking noSuchMethod on - // super. - } else if (Elements.isUnresolved(resolvedReceiver)) { - return null; - } else if (identical(resolvedReceiver.kind, ElementKind.CLASS)) { - ClassElement receiverClass = resolvedReceiver; - receiverClass.ensureResolved(compiler); - if (node.isOperator) { - // When the resolved receiver is a class, we can have two cases: - // 1) a static send: C.foo, or - // 2) an operator send, where the receiver is a class literal: 'C + 1'. - // The following code that looks up the selector on the resolved - // receiver will treat the second as the invocation of a static operator - // if the resolved receiver is not null. - return null; - } - target = receiverClass.lookupLocalMember(name); - if (target == null) { - // TODO(johnniwinther): With the simplified [TreeElements] invariant, - // try to resolve injected elements if [currentClass] is in the patch - // library of [receiverClass]. - - // TODO(karlklose): this should be reported by the caller of - // [resolveSend] to select better warning messages for getters and - // setters. - return warnAndCreateErroneousElement(node, name, - MessageKind.METHOD_NOT_FOUND, - {'className': receiverClass.name, - 'methodName': name}); - } else if (target.isInstanceMember()) { - error(node, MessageKind.MEMBER_NOT_STATIC, - {'className': receiverClass.name, - 'memberName': name}); - } - } else if (identical(resolvedReceiver.kind, ElementKind.PREFIX)) { - PrefixElement prefix = resolvedReceiver; - target = prefix.lookupLocalMember(name); - if (Elements.isUnresolved(target)) { - return warnAndCreateErroneousElement( - node, name, MessageKind.NO_SUCH_LIBRARY_MEMBER, - {'libraryName': prefix.name, 'memberName': name}); - } else if (target.kind == ElementKind.CLASS) { - ClassElement classElement = target; - classElement.ensureResolved(compiler); - } - } - return target; - } - - DartType resolveTypeTest(Node argument) { - TypeAnnotation node = argument.asTypeAnnotation(); - if (node == null) { - // node is of the form !Type. - node = argument.asSend().receiver.asTypeAnnotation(); - if (node == null) compiler.cancel("malformed send"); - } - return resolveTypeRequired(node); - } - - static Selector computeSendSelector(Send node, LibraryElement library) { - // First determine if this is part of an assignment. - bool isSet = node.asSendSet() != null; - - if (node.isIndex) { - return isSet ? new Selector.indexSet() : new Selector.index(); - } - - if (node.isOperator) { - SourceString source = node.selector.asOperator().source; - String string = source.stringValue; - if (identical(string, '!') || - identical(string, '&&') || identical(string, '||') || - identical(string, 'is') || identical(string, 'as') || - identical(string, '===') || identical(string, '!==') || - identical(string, '?') || - identical(string, '>>>')) { - return null; - } - if (!isUserDefinableOperator(source.stringValue)) { - source = Elements.mapToUserOperator(source); - } - return node.arguments.isEmpty - ? new Selector.unaryOperator(source) - : new Selector.binaryOperator(source); - } - - Identifier identifier = node.selector.asIdentifier(); - if (node.isPropertyAccess) { - assert(!isSet); - return new Selector.getter(identifier.source, library); - } else if (isSet) { - return new Selector.setter(identifier.source, library); - } - - // Compute the arity and the list of named arguments. - int arity = 0; - List<SourceString> named = <SourceString>[]; - for (Link<Node> link = node.argumentsNode.nodes; - !link.isEmpty; - link = link.tail) { - Expression argument = link.head; - NamedArgument namedArgument = argument.asNamedArgument(); - if (namedArgument != null) { - named.add(namedArgument.name.source); - } - arity++; - } - - // If we're invoking a closure, we do not have an identifier. - return (identifier == null) - ? new Selector.callClosure(arity, named) - : new Selector.call(identifier.source, library, arity, named); - } - - Selector resolveSelector(Send node) { - LibraryElement library = enclosingElement.getLibrary(); - Selector selector = computeSendSelector(node, library); - if (selector != null) mapping.setSelector(node, selector); - return selector; - } - - void resolveArguments(NodeList list) { - if (list == null) return; - List<SourceString> seenNamedArguments = <SourceString>[]; - for (Link<Node> link = list.nodes; !link.isEmpty; link = link.tail) { - Expression argument = link.head; - visit(argument); - NamedArgument namedArgument = argument.asNamedArgument(); - if (namedArgument != null) { - SourceString source = namedArgument.name.source; - if (seenNamedArguments.contains(source)) { - error(argument, MessageKind.DUPLICATE_DEFINITION, - {'name': source}); - } - seenNamedArguments.add(source); - } else if (!seenNamedArguments.isEmpty) { - error(argument, MessageKind.INVALID_ARGUMENT_AFTER_NAMED); - } - } - } - - visitSend(Send node) { - Element target = resolveSend(node); - if (!Elements.isUnresolved(target) - && target.kind == ElementKind.ABSTRACT_FIELD) { - AbstractFieldElement field = target; - target = field.getter; - if (target == null && !inInstanceContext) { - target = - warnAndCreateErroneousElement(node.selector, field.name, - MessageKind.CANNOT_RESOLVE_GETTER); - } - } - - bool resolvedArguments = false; - if (node.isOperator) { - String operatorString = node.selector.asOperator().source.stringValue; - if (identical(operatorString, 'is') || identical(operatorString, 'as')) { - assert(node.arguments.tail.isEmpty); - DartType type = resolveTypeTest(node.arguments.head); - if (type != null) { - compiler.enqueuer.resolution.registerIsCheck(type); - } - resolvedArguments = true; - } else if (identical(operatorString, '?')) { - Element parameter = mapping[node.receiver]; - if (parameter == null - || !identical(parameter.kind, ElementKind.PARAMETER)) { - error(node.receiver, MessageKind.PARAMETER_NAME_EXPECTED); - } else { - mapping.checkedParameters.add(parameter); - } - } - } - - if (!resolvedArguments) { - resolveArguments(node.argumentsNode); - } - - // If the selector is null, it means that we will not be generating - // code for this as a send. - Selector selector = mapping.getSelector(node); - if (selector == null) return; - - if (node.isCall) { - if (Elements.isUnresolved(target) || - target.isGetter() || - Elements.isClosureSend(node, target)) { - // If we don't know what we're calling or if we are calling a getter, - // we need to register that fact that we may be calling a closure - // with the same arguments. - Selector call = new Selector.callClosureFrom(selector); - world.registerDynamicInvocation(call.name, call); - } else if (target.impliesType()) { - // We call 'call()' on a Type instance returned from the reference to a - // class or typedef literal. We do not need to register this call as a - // dynamic invocation, because we statically know what the target is. - } else if (!selector.applies(target, compiler)) { - warnArgumentMismatch(node, target); - } - - if (target != null && - target.isForeign(compiler) && - selector.name == const SourceString('JS')) { - world.registerJsCall(node, this); - } - } - - // TODO(ngeoffray): Warn if target is null and the send is - // unqualified. - useElement(node, target); - registerSend(selector, target); - if (node.isPropertyAccess) { - // It might be the closurization of a method. - world.registerInstantiatedClass(compiler.functionClass); - } - return node.isPropertyAccess ? target : null; - } - - void warnArgumentMismatch(Send node, Element target) { - // TODO(karlklose): we can be more precise about the reason of the - // mismatch. - warning(node.argumentsNode, MessageKind.INVALID_ARGUMENTS, - {'methodName': target.name}); - } - - /// Callback for native enqueuer to parse a type. Returns [:null:] on error. - DartType resolveTypeFromString(String typeName) { - Element element = scope.lookup(new SourceString(typeName)); - if (element == null) return null; - if (element is! ClassElement) return null; - element.ensureResolved(compiler); - return element.computeType(compiler); - } - - visitSendSet(SendSet node) { - Element target = resolveSend(node); - Element setter = target; - Element getter = target; - SourceString operatorName = node.assignmentOperator.source; - String source = operatorName.stringValue; - bool isComplex = !identical(source, '='); - if (!Elements.isUnresolved(target) - && target.kind == ElementKind.ABSTRACT_FIELD) { - AbstractFieldElement field = target; - setter = field.setter; - getter = field.getter; - if (setter == null && !inInstanceContext) { - setter = - warnAndCreateErroneousElement(node.selector, field.name, - MessageKind.CANNOT_RESOLVE_SETTER); - } - if (isComplex && getter == null && !inInstanceContext) { - getter = - warnAndCreateErroneousElement(node.selector, field.name, - MessageKind.CANNOT_RESOLVE_GETTER); - } - } - - visit(node.argumentsNode); - - // TODO(ngeoffray): Check if the target can be assigned. - // TODO(ngeoffray): Warn if target is null and the send is - // unqualified. - - Selector selector = mapping.getSelector(node); - if (isComplex) { - if (selector.isSetter()) { - // TODO(kasperl): We're registering the getter selector for - // compound assignments on the AST selector node. In the code - // generator, we then fetch it from there when generating the - // getter for a SendSet node. - Selector getterSelector = new Selector.getterFrom(selector); - registerSend(getterSelector, getter); - mapping.setSelector(node.selector, getterSelector); - useElement(node.selector, getter); - } else { - // TODO(kasperl): If [getter] is resolved, it will actually - // refer to the []= operator which isn't the one we want to - // register here. We should consider using some notion of - // abstract indexable element that we can resolve to so we can - // distinguish the two. - assert(selector.isIndexSet()); - registerSend(new Selector.index(), null); - } - - // Make sure we include the + and - operators if we are using - // the ++ and -- ones. Also, if op= form is used, include op itself. - void registerBinaryOperator(SourceString name) { - Selector binop = new Selector.binaryOperator(name); - world.registerDynamicInvocation(binop.name, binop); - } - if (identical(source, '++')) registerBinaryOperator(const SourceString('+')); - if (identical(source, '--')) registerBinaryOperator(const SourceString('-')); - if (source.endsWith('=')) { - registerBinaryOperator(Elements.mapToUserOperator(operatorName)); - } - } - - registerSend(selector, setter); - return useElement(node, setter); - } - - void registerSend(Selector selector, Element target) { - if (target == null || target.isInstanceMember()) { - if (selector.isGetter()) { - world.registerDynamicGetter(selector.name, selector); - } else if (selector.isSetter()) { - world.registerDynamicSetter(selector.name, selector); - } else { - world.registerDynamicInvocation(selector.name, selector); - } - } else if (Elements.isStaticOrTopLevel(target)) { - // TODO(kasperl): It seems like we're not supposed to register - // the use of classes. Wouldn't it be simpler if we just did? - if (!target.isClass()) { - // [target] might be the implementation element and only declaration - // elements may be registered. - world.registerStaticUse(target.declaration); - } - } - } - - visitLiteralInt(LiteralInt node) { - world.registerInstantiatedClass(compiler.intClass); - } - - visitLiteralDouble(LiteralDouble node) { - world.registerInstantiatedClass(compiler.doubleClass); - } - - visitLiteralBool(LiteralBool node) { - world.registerInstantiatedClass(compiler.boolClass); - } - - visitLiteralString(LiteralString node) { - world.registerInstantiatedClass(compiler.stringClass); - } - - visitLiteralNull(LiteralNull node) { - world.registerInstantiatedClass(compiler.nullClass); - } - - visitStringJuxtaposition(StringJuxtaposition node) { - world.registerInstantiatedClass(compiler.stringClass); - node.visitChildren(this); - } - - visitNodeList(NodeList node) { - for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) { - visit(link.head); - } - } - - visitOperator(Operator node) { - unimplemented(node, 'operator'); - } - - visitReturn(Return node) { - if (node.isRedirectingFactoryBody) { - handleRedirectingFactoryBody(node); - } else { - visit(node.expression); - } - } - - void handleRedirectingFactoryBody(Return node) { - if (!enclosingElement.isFactoryConstructor()) { - compiler.reportErrorCode( - node, MessageKind.FACTORY_REDIRECTION_IN_NON_FACTORY); - compiler.reportErrorCode( - enclosingElement, MessageKind.MISSING_FACTORY_KEYWORD); - } - Element redirectionTarget = resolveRedirectingFactory(node); - var type = mapping.getType(node.expression); - if (type is InterfaceType && !type.isRaw) { - unimplemented(node.expression, 'type arguments on redirecting factory'); - } - useElement(node.expression, redirectionTarget); - FunctionElement constructor = enclosingElement; - if (constructor.modifiers.isConst() && - !redirectionTarget.modifiers.isConst()) { - error(node, MessageKind.CONSTRUCTOR_IS_NOT_CONST); - } - constructor.defaultImplementation = redirectionTarget; - if (Elements.isUnresolved(redirectionTarget)) return; - - // TODO(ahe): Check that this doesn't lead to a cycle. For now, - // just make sure that the redirection target isn't itself a - // redirecting factory. - { // This entire block is temporary code per the above TODO. - FunctionElement targetImplementation = redirectionTarget.implementation; - FunctionExpression function = targetImplementation.parseNode(compiler); - if (function.body != null && function.body.asReturn() != null - && function.body.asReturn().isRedirectingFactoryBody) { - unimplemented(node.expression, 'redirecing to redirecting factory'); - } - } - world.registerStaticUse(redirectionTarget); - world.registerInstantiatedClass( - redirectionTarget.enclosingElement.declaration); - } - - visitThrow(Throw node) { - if (!inCatchBlock && node.expression == null) { - error(node, MessageKind.THROW_WITHOUT_EXPRESSION); - } - visit(node.expression); - } - - visitVariableDefinitions(VariableDefinitions node) { - VariableDefinitionsVisitor visitor = - new VariableDefinitionsVisitor(compiler, node, this, - ElementKind.VARIABLE); - // Ensure that we set the type of the [VariableListElement] since it depends - // on the current scope. If the current scope is a [MethodScope] or - // [BlockScope] it will not be available for the - // [VariableListElement.computeType] method. - if (node.type != null) { - visitor.variables.type = resolveTypeAnnotation(node.type); - } else { - visitor.variables.type = compiler.types.dynamicType; - } - visitor.visit(node.definitions); - } - - visitWhile(While node) { - visit(node.condition); - visitLoopBodyIn(node, node.body, new BlockScope(scope)); - } - - visitParenthesizedExpression(ParenthesizedExpression node) { - visit(node.expression); - } - - visitNewExpression(NewExpression node) { - Node selector = node.send.selector; - FunctionElement constructor = resolveConstructor(node); - resolveSelector(node.send); - resolveArguments(node.send.argumentsNode); - useElement(node.send, constructor); - if (Elements.isUnresolved(constructor)) return constructor; - // TODO(karlklose): handle optional arguments. - if (node.send.argumentCount() != constructor.parameterCount(compiler)) { - // TODO(ngeoffray): resolution error with wrong number of - // parameters. We cannot do this rigth now because of the - // List constructor. - } - // [constructor] might be the implementation element and only declaration - // elements may be registered. - world.registerStaticUse(constructor.declaration); - compiler.withCurrentElement(constructor, () { - FunctionExpression tree = constructor.parseNode(compiler); - compiler.resolver.resolveConstructorImplementation(constructor, tree); - }); - // [constructor.defaultImplementation] might be the implementation element - // and only declaration elements may be registered. - world.registerStaticUse(constructor.defaultImplementation.declaration); - ClassElement cls = constructor.defaultImplementation.getEnclosingClass(); - // [cls] might be the implementation element and only declaration elements - // may be registered. - world.registerInstantiatedClass(cls.declaration); - // [cls] might be the declaration element and we want to include injected - // members. - cls.implementation.forEachInstanceField( - (ClassElement enclosingClass, Element member) { - world.addToWorkList(member); - }, - includeBackendMembers: false, - includeSuperMembers: true); - return null; - } - - /** - * Try to resolve the constructor that is referred to by [node]. - * Note: this function may return an ErroneousFunctionElement instead of - * [null], if there is no corresponding constructor, class or library. - */ - FunctionElement resolveConstructor(NewExpression node) { - return node.accept(new ConstructorResolver(compiler, this)); - } - - FunctionElement resolveRedirectingFactory(Return node) { - return node.accept(new ConstructorResolver(compiler, this)); - } - - DartType resolveTypeRequired(TypeAnnotation node) { - bool old = typeRequired; - typeRequired = true; - DartType result = resolveTypeAnnotation(node); - typeRequired = old; - return result; - } - - void analyzeTypeArgument(DartType annotation, DartType argument) { - if (argument == null) return; - if (argument.element.isTypeVariable()) { - // Register a dependency between the class where the type - // variable is, and the annotation. If the annotation requires - // runtime type information, then the class of the type variable - // does too. - compiler.world.registerRtiDependency( - annotation.element, - argument.element.enclosingElement); - } else if (argument is InterfaceType) { - InterfaceType type = argument; - type.typeArguments.forEach((DartType argument) { - analyzeTypeArgument(type, argument); - }); - } - } - - DartType resolveTypeAnnotation(TypeAnnotation node) { - Function report = typeRequired ? error : warning; - DartType type = typeResolver.resolveTypeAnnotation( - node, scope, enclosingElement, - onFailure: report, whenResolved: useType); - if (type == null) return null; - if (inCheckContext) { - compiler.enqueuer.resolution.registerIsCheck(type); - } - if (typeRequired || inCheckContext) { - if (type is InterfaceType) { - InterfaceType itf = type; - itf.typeArguments.forEach((DartType argument) { - analyzeTypeArgument(type, argument); - }); - } - // TODO(ngeoffray): Also handle cases like: - // 1) a is T - // 2) T a (in checked mode). - } - return type; - } - - visitModifiers(Modifiers node) { - // TODO(ngeoffray): Implement this. - unimplemented(node, 'modifiers'); - } - - visitLiteralList(LiteralList node) { - world.registerInstantiatedClass(compiler.listClass); - NodeList arguments = node.typeArguments; - if (arguments != null) { - Link<Node> nodes = arguments.nodes; - if (nodes.isEmpty) { - error(arguments, MessageKind.MISSING_TYPE_ARGUMENT); - } else { - resolveTypeRequired(nodes.head); - for (nodes = nodes.tail; !nodes.isEmpty; nodes = nodes.tail) { - error(nodes.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT); - resolveTypeRequired(nodes.head); - } - } - } - visit(node.elements); - } - - visitConditional(Conditional node) { - node.visitChildren(this); - } - - visitStringInterpolation(StringInterpolation node) { - world.registerInstantiatedClass(compiler.stringClass); - node.visitChildren(this); - } - - visitStringInterpolationPart(StringInterpolationPart node) { - registerImplicitInvocation(const SourceString('toString'), 0); - node.visitChildren(this); - } - - visitBreakStatement(BreakStatement node) { - TargetElement target; - if (node.target == null) { - target = statementScope.currentBreakTarget(); - if (target == null) { - error(node, MessageKind.NO_BREAK_TARGET); - return; - } - target.isBreakTarget = true; - } else { - String labelName = node.target.source.slowToString(); - LabelElement label = statementScope.lookupLabel(labelName); - if (label == null) { - error(node.target, MessageKind.UNBOUND_LABEL, {'labelName': labelName}); - return; - } - target = label.target; - if (!target.statement.isValidBreakTarget()) { - error(node.target, MessageKind.INVALID_BREAK); - return; - } - label.setBreakTarget(); - mapping[node.target] = label; - } - if (mapping[node] != null) { - // TODO(ahe): I'm not sure why this node already has an element - // that is different from target. I will talk to Lasse and - // figure out what is going on. - mapping.remove(node); - } - mapping[node] = target; - } - - visitContinueStatement(ContinueStatement node) { - TargetElement target; - if (node.target == null) { - target = statementScope.currentContinueTarget(); - if (target == null) { - error(node, MessageKind.NO_CONTINUE_TARGET); - return; - } - target.isContinueTarget = true; - } else { - String labelName = node.target.source.slowToString(); - LabelElement label = statementScope.lookupLabel(labelName); - if (label == null) { - error(node.target, MessageKind.UNBOUND_LABEL, {'labelName': labelName}); - return; - } - target = label.target; - if (!target.statement.isValidContinueTarget()) { - error(node.target, MessageKind.INVALID_CONTINUE); - } - // TODO(lrn): Handle continues to switch cases. - if (target.statement is SwitchCase) { - unimplemented(node, "continue to switch case"); - } - label.setContinueTarget(); - mapping[node.target] = label; - } - mapping[node] = target; - } - - registerImplicitInvocation(SourceString name, int arity) { - Selector selector = new Selector.call(name, null, arity); - world.registerDynamicInvocation(name, selector); - } - - registerImplicitFieldGet(SourceString name) { - Selector selector = new Selector.getter(name, null); - world.registerDynamicGetter(name, selector); - } - - visitForIn(ForIn node) { - for (final name in const [ - const SourceString('iterator'), - const SourceString('current')]) { - registerImplicitFieldGet(name); - } - registerImplicitInvocation(const SourceString('moveNext'), 0); - visit(node.expression); - Scope blockScope = new BlockScope(scope); - Node declaration = node.declaredIdentifier; - visitIn(declaration, blockScope); - visitLoopBodyIn(node, node.body, blockScope); - - // TODO(lrn): Also allow a single identifier. - if ((declaration is !Send || declaration.asSend().selector is !Identifier - || declaration.asSend().receiver != null) - && (declaration is !VariableDefinitions || - !declaration.asVariableDefinitions().definitions.nodes.tail.isEmpty)) - { - // The variable declaration is either not an identifier, not a - // declaration, or it's declaring more than one variable. - error(node.declaredIdentifier, MessageKind.INVALID_FOR_IN); - } - } - - visitLabel(Label node) { - // Labels are handled by their containing statements/cases. - } - - visitLabeledStatement(LabeledStatement node) { - Statement body = node.statement; - TargetElement targetElement = getOrCreateTargetElement(body); - Map<String, LabelElement> labelElements = <String, LabelElement>{}; - for (Label label in node.labels) { - String labelName = label.slowToString(); - if (labelElements.containsKey(labelName)) continue; - LabelElement element = targetElement.addLabel(label, labelName); - labelElements[labelName] = element; - } - statementScope.enterLabelScope(labelElements); - visit(node.statement); - statementScope.exitLabelScope(); - labelElements.forEach((String labelName, LabelElement element) { - if (element.isTarget) { - mapping[element.label] = element; - } else { - warning(element.label, MessageKind.UNUSED_LABEL, - {'labelName': labelName}); - } - }); - if (!targetElement.isTarget && identical(mapping[body], targetElement)) { - // If the body is itself a break or continue for another target, it - // might have updated its mapping to the target it actually does target. - mapping.remove(body); - } - } - - visitLiteralMap(LiteralMap node) { - world.registerInstantiatedClass(compiler.mapClass); - node.visitChildren(this); - } - - visitLiteralMapEntry(LiteralMapEntry node) { - node.visitChildren(this); - } - - visitNamedArgument(NamedArgument node) { - visit(node.expression); - } - - visitSwitchStatement(SwitchStatement node) { - node.expression.accept(this); - - TargetElement breakElement = getOrCreateTargetElement(node); - Map<String, LabelElement> continueLabels = <String, LabelElement>{}; - Link<Node> cases = node.cases.nodes; - while (!cases.isEmpty) { - SwitchCase switchCase = cases.head; - for (Node labelOrCase in switchCase.labelsAndCases) { - if (labelOrCase is! Label) continue; - Label label = labelOrCase; - String labelName = label.slowToString(); - - LabelElement existingElement = continueLabels[labelName]; - if (existingElement != null) { - // It's an error if the same label occurs twice in the same switch. - warning(label, MessageKind.DUPLICATE_LABEL, {'labelName': labelName}); - error(existingElement.label, MessageKind.EXISTING_LABEL, - {'labelName': labelName}); - } else { - // It's only a warning if it shadows another label. - existingElement = statementScope.lookupLabel(labelName); - if (existingElement != null) { - warning(label, MessageKind.DUPLICATE_LABEL, - {'labelName': labelName}); - warning(existingElement.label, - MessageKind.EXISTING_LABEL, {'labelName': labelName}); - } - } - - TargetElement targetElement = - new TargetElementX(switchCase, - statementScope.nestingLevel, - enclosingElement); - if (mapping[switchCase] != null) { - // TODO(ahe): Talk to Lasse about this. - mapping.remove(switchCase); - } - mapping[switchCase] = targetElement; - - LabelElement labelElement = - new LabelElementX(label, labelName, - targetElement, enclosingElement); - mapping[label] = labelElement; - continueLabels[labelName] = labelElement; - } - cases = cases.tail; - // Test that only the last case, if any, is a default case. - if (switchCase.defaultKeyword != null && !cases.isEmpty) { - error(switchCase, MessageKind.INVALID_CASE_DEFAULT); - } - } - - statementScope.enterSwitch(breakElement, continueLabels); - node.cases.accept(this); - statementScope.exitSwitch(); - - // Clean-up unused labels. - continueLabels.forEach((String key, LabelElement label) { - if (!label.isContinueTarget) { - TargetElement targetElement = label.target; - SwitchCase switchCase = targetElement.statement; - mapping.remove(switchCase); - mapping.remove(label.label); - } - }); - } - - visitSwitchCase(SwitchCase node) { - node.labelsAndCases.accept(this); - visitIn(node.statements, new BlockScope(scope)); - } - - visitCaseMatch(CaseMatch node) { - visit(node.expression); - } - - visitTryStatement(TryStatement node) { - visit(node.tryBlock); - if (node.catchBlocks.isEmpty && node.finallyBlock == null) { - // TODO(ngeoffray): The precise location is - // node.getEndtoken.next. Adjust when issue #1581 is fixed. - error(node, MessageKind.NO_CATCH_NOR_FINALLY); - } - visit(node.catchBlocks); - visit(node.finallyBlock); - } - - visitCatchBlock(CatchBlock node) { - // Check that if catch part is present, then - // it has one or two formal parameters. - if (node.formals != null) { - if (node.formals.isEmpty) { - error(node, MessageKind.EMPTY_CATCH_DECLARATION); - } - if (!node.formals.nodes.tail.isEmpty && - !node.formals.nodes.tail.tail.isEmpty) { - for (Node extra in node.formals.nodes.tail.tail) { - error(extra, MessageKind.EXTRA_CATCH_DECLARATION); - } - } - - // Check that the formals aren't optional and that they have no - // modifiers or type. - for (Link<Node> link = node.formals.nodes; - !link.isEmpty; - link = link.tail) { - // If the formal parameter is a node list, it means that it is a - // sequence of optional parameters. - NodeList nodeList = link.head.asNodeList(); - if (nodeList != null) { - error(nodeList, MessageKind.OPTIONAL_PARAMETER_IN_CATCH); - } else { - VariableDefinitions declaration = link.head; - for (Node modifier in declaration.modifiers.nodes) { - error(modifier, MessageKind.PARAMETER_WITH_MODIFIER_IN_CATCH); - } - TypeAnnotation type = declaration.type; - if (type != null) { - error(type, MessageKind.PARAMETER_WITH_TYPE_IN_CATCH); - } - } - } - } - - Scope blockScope = new BlockScope(scope); - var wasTypeRequired = typeRequired; - typeRequired = true; - doInCheckContext(() => visitIn(node.type, blockScope)); - typeRequired = wasTypeRequired; - visitIn(node.formals, blockScope); - var oldInCatchBlock = inCatchBlock; - inCatchBlock = true; - visitIn(node.block, blockScope); - inCatchBlock = oldInCatchBlock; - } - - visitTypedef(Typedef node) { - unimplemented(node, 'typedef'); - } -} - -class TypeDefinitionVisitor extends CommonResolverVisitor<DartType> { - Scope scope; - TypeDeclarationElement element; - TypeResolver typeResolver; - - TypeDefinitionVisitor(Compiler compiler, TypeDeclarationElement element) - : this.element = element, - scope = Scope.buildEnclosingScope(element), - typeResolver = new TypeResolver(compiler), - super(compiler); - - void resolveTypeVariableBounds(NodeList node) { - if (node == null) return; - - var nameSet = new Set<SourceString>(); - // Resolve the bounds of type variables. - Link<DartType> typeLink = element.typeVariables; - Link<Node> nodeLink = node.nodes; - while (!nodeLink.isEmpty) { - TypeVariableType typeVariable = typeLink.head; - SourceString typeName = typeVariable.name; - TypeVariable typeNode = nodeLink.head; - if (nameSet.contains(typeName)) { - error(typeNode, MessageKind.DUPLICATE_TYPE_VARIABLE_NAME, - {'typeVariableName': typeName}); - } - nameSet.add(typeName); - - TypeVariableElement variableElement = typeVariable.element; - if (typeNode.bound != null) { - DartType boundType = typeResolver.resolveTypeAnnotation( - typeNode.bound, scope, element, onFailure: warning); - if (boundType != null && boundType.element == variableElement) { - // TODO(johnniwinther): Check for more general cycles, like - // [: <A extends B, B extends C, C extends B> :]. - warning(node, MessageKind.CYCLIC_TYPE_VARIABLE, - {'typeVariableName': variableElement.name}); - } else if (boundType != null) { - variableElement.bound = boundType; - } else { - // TODO(johnniwinther): Should be an erroneous type. - variableElement.bound = compiler.objectClass.computeType(compiler); - } - } else { - variableElement.bound = compiler.objectClass.computeType(compiler); - } - nodeLink = nodeLink.tail; - typeLink = typeLink.tail; - } - assert(typeLink.isEmpty); - } -} - -class TypedefResolverVisitor extends TypeDefinitionVisitor { - TypedefElement get element => super.element; - - TypedefResolverVisitor(Compiler compiler, TypedefElement typedefElement) - : super(compiler, typedefElement); - - visitTypedef(Typedef node) { - TypedefType type = element.computeType(compiler); - scope = new TypeDeclarationScope(scope, element); - resolveTypeVariableBounds(node.typeParameters); - - element.functionSignature = SignatureResolver.analyze( - compiler, node.formals, node.returnType, element); - - element.alias = compiler.computeFunctionType( - element, element.functionSignature); - - // TODO(johnniwinther): Check for cyclic references in the typedef alias. - } -} - -/** - * The implementation of [ResolverTask.resolveClass]. - * - * This visitor has to be extra careful as it is building the basic - * element information, and cannot safely look at other elements as - * this may lead to cycles. - * - * This visitor can assume that the supertypes have already been - * resolved, but it cannot call [ResolverTask.resolveClass] directly - * or indirectly (through [ClassElement.ensureResolved]) for any other - * types. - */ -class ClassResolverVisitor extends TypeDefinitionVisitor { - ClassElement get element => super.element; - - ClassResolverVisitor(Compiler compiler, ClassElement classElement) - : super(compiler, classElement); - - DartType visitClassNode(ClassNode node) { - compiler.ensure(element != null); - compiler.ensure(element.resolutionState == STATE_STARTED); - - InterfaceType type = element.computeType(compiler); - scope = new TypeDeclarationScope(scope, element); - // TODO(ahe): It is not safe to call resolveTypeVariableBounds yet. - // As a side-effect, this may get us back here trying to - // resolve this class again. - resolveTypeVariableBounds(node.typeParameters); - - // Setup the supertype for the element. - assert(element.supertype == null); - if (node.superclass != null) { - MixinApplication superMixin = node.superclass.asMixinApplication(); - if (superMixin != null) { - DartType supertype = resolveSupertype(element, superMixin.superclass); - Link<Node> link = superMixin.mixins.nodes; - while (!link.isEmpty) { - supertype = applyMixin(supertype, visit(link.head)); - link = link.tail; - } - element.supertype = supertype; - } else { - element.supertype = resolveSupertype(element, node.superclass); - } - } - - // If the super type isn't specified, we make it Object. - final objectElement = compiler.objectClass; - if (!identical(element, objectElement) && element.supertype == null) { - if (objectElement == null) { - compiler.internalError("Internal error: cannot resolve Object", - node: node); - } else { - objectElement.ensureResolved(compiler); - } - element.supertype = objectElement.computeType(compiler); - } - - assert(element.interfaces == null); - element.interfaces = resolveInterfaces(node.interfaces, node.superclass); - calculateAllSupertypes(element); - - if (node.defaultClause != null) { - element.defaultClass = visit(node.defaultClause); - } - element.addDefaultConstructorIfNeeded(compiler); - return element.computeType(compiler); - } - - DartType visitNamedMixinApplication(NamedMixinApplication node) { - compiler.ensure(element != null); - compiler.ensure(element.resolutionState == STATE_STARTED); - - InterfaceType type = element.computeType(compiler); - scope = new TypeDeclarationScope(scope, element); - resolveTypeVariableBounds(node.typeParameters); - - // Generate anonymous mixin application elements for the - // intermediate mixin applications (excluding the last). - DartType supertype = resolveSupertype(element, node.superclass); - Link<Node> link = node.mixins.nodes; - while (!link.tail.isEmpty) { - supertype = applyMixin(supertype, visit(link.head)); - link = link.tail; - } - doApplyMixinTo(element, supertype, visit(link.head)); - return element.computeType(compiler); - } - - DartType applyMixin(DartType supertype, DartType mixinType) { - String superName = supertype.name.slowToString(); - String mixinName = mixinType.name.slowToString(); - ClassElement mixinApplication = new MixinApplicationElementX( - new SourceString("${superName}_${mixinName}"), - element.getCompilationUnit(), - compiler.getNextFreeClassId(), - element.parseNode(compiler), - Modifiers.EMPTY); // TODO(kasperl): Should this be abstract? - doApplyMixinTo(mixinApplication, supertype, mixinType); - mixinApplication.resolutionState = STATE_DONE; - mixinApplication.supertypeLoadState = STATE_DONE; - return mixinApplication.computeType(compiler); - } - - void doApplyMixinTo(MixinApplicationElement mixinApplication, - DartType supertype, - DartType mixinType) { - assert(mixinApplication.supertype == null); - mixinApplication.supertype = supertype; - - // Named mixin application may have an 'implements' clause. - NamedMixinApplication namedMixinApplication = - mixinApplication.parseNode(compiler).asNamedMixinApplication(); - Link<DartType> interfaces = (namedMixinApplication != null) - ? resolveInterfaces(namedMixinApplication.interfaces, - namedMixinApplication.superclass) - : const Link<DartType>(); - - // The class that is the result of a mixin application implements - // the interface of the class that was mixed in so always prepend - // that to the interface list. - interfaces = interfaces.prepend(mixinType); - assert(mixinApplication.interfaces == null); - mixinApplication.interfaces = interfaces; - - assert(mixinApplication.mixin == null); - mixinApplication.mixin = resolveMixinFor(mixinApplication, mixinType); - mixinApplication.addDefaultConstructorIfNeeded(compiler); - calculateAllSupertypes(mixinApplication); - } - - ClassElement resolveMixinFor(MixinApplicationElement mixinApplication, - DartType mixinType) { - ClassElement mixin = mixinType.element; - mixin.ensureResolved(compiler); - - // Check for cycles in the mixin chain. - ClassElement previous = mixinApplication; // For better error messages. - ClassElement current = mixin; - while (current != null && current.isMixinApplication) { - MixinApplicationElement currentMixinApplication = current; - if (currentMixinApplication == mixinApplication) { - compiler.reportErrorCode( - mixinApplication, MessageKind.ILLEGAL_MIXIN_CYCLE, - {'mixinName1': current.name, 'mixinName2': previous.name}); - // We have found a cycle in the mixin chain. Return null as - // the mixin for this application to avoid getting into - // infinite recursion when traversing members. - return null; - } - previous = current; - current = currentMixinApplication.mixin; - } - compiler.world.registerMixinUse(mixinApplication, mixin); - return mixin; - } - - // TODO(johnniwinther): Remove when default class is no longer supported. - DartType visitTypeAnnotation(TypeAnnotation node) { - return visit(node.typeName); - } - - // TODO(johnniwinther): Remove when default class is no longer supported. - DartType visitIdentifier(Identifier node) { - Element element = scope.lookup(node.source); - if (element == null) { - error(node, MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': node}); - return null; - } else if (!element.impliesType() && !element.isTypeVariable()) { - error(node, MessageKind.NOT_A_TYPE, {'node': node}); - return null; - } else { - if (element.isTypeVariable()) { - TypeVariableElement variableElement = element; - return variableElement.type; - } else if (element.isTypedef()) { - compiler.unimplemented('visitIdentifier for typedefs', node: node); - } else { - // TODO(ngeoffray): Use type variables. - return element.computeType(compiler); - } - } - return null; - } - - // TODO(johnniwinther): Remove when default class is no longer supported. - DartType visitSend(Send node) { - Identifier prefix = node.receiver.asIdentifier(); - if (prefix == null) { - error(node.receiver, MessageKind.NOT_A_PREFIX, {'node': node.receiver}); - return null; - } - Element element = scope.lookup(prefix.source); - if (element == null || !identical(element.kind, ElementKind.PREFIX)) { - error(node.receiver, MessageKind.NOT_A_PREFIX, {'node': node.receiver}); - return null; - } - PrefixElement prefixElement = element; - Identifier selector = node.selector.asIdentifier(); - var e = prefixElement.lookupLocalMember(selector.source); - if (e == null || !e.impliesType()) { - error(node.selector, MessageKind.CANNOT_RESOLVE_TYPE, - {'typeName': node.selector}); - return null; - } - return e.computeType(compiler); - } - - DartType resolveSupertype(ClassElement cls, TypeAnnotation superclass) { - DartType supertype = typeResolver.resolveTypeAnnotation( - superclass, scope, cls, onFailure: error); - if (supertype != null) { - if (identical(supertype.kind, TypeKind.MALFORMED_TYPE)) { - // Error has already been reported. - return null; - } else if (!identical(supertype.kind, TypeKind.INTERFACE)) { - // TODO(johnniwinther): Handle dynamic. - error(superclass.typeName, MessageKind.CLASS_NAME_EXPECTED); - return null; - } else if (isBlackListed(supertype)) { - error(superclass, MessageKind.CANNOT_EXTEND, {'type': supertype}); - return null; - } - } - return supertype; - } - - Link<DartType> resolveInterfaces(NodeList interfaces, Node superclass) { - Link<DartType> result = const Link<DartType>(); - if (interfaces == null) return result; - for (Link<Node> link = interfaces.nodes; !link.isEmpty; link = link.tail) { - DartType interfaceType = typeResolver.resolveTypeAnnotation( - link.head, scope, element, onFailure: error); - if (interfaceType != null) { - if (identical(interfaceType.kind, TypeKind.MALFORMED_TYPE)) { - // Error has already been reported. - } else if (!identical(interfaceType.kind, TypeKind.INTERFACE)) { - // TODO(johnniwinther): Handle dynamic. - TypeAnnotation typeAnnotation = link.head; - error(typeAnnotation.typeName, MessageKind.CLASS_NAME_EXPECTED); - } else { - if (interfaceType == element.supertype) { - compiler.reportErrorCode( - superclass, - MessageKind.DUPLICATE_EXTENDS_IMPLEMENTS, - {'type': interfaceType}); - compiler.reportErrorCode( - link.head, - MessageKind.DUPLICATE_EXTENDS_IMPLEMENTS, - {'type': interfaceType}); - } - if (result.contains(interfaceType)) { - compiler.reportErrorCode( - link.head, - MessageKind.DUPLICATE_IMPLEMENTS, - {'type': interfaceType}); - } - result = result.prepend(interfaceType); - if (isBlackListed(interfaceType)) { - error(link.head, MessageKind.CANNOT_IMPLEMENT, - {'type': interfaceType}); - } - } - } - } - return result; - } - - void calculateAllSupertypes(ClassElement cls) { - // TODO(karlklose): Check if type arguments match, if a class - // element occurs more than once in the supertypes. - if (cls.allSupertypes != null) return; - final DartType supertype = cls.supertype; - if (supertype != null) { - var allSupertypes = new LinkBuilder<DartType>(); - addAllSupertypes(allSupertypes, supertype); - for (Link<DartType> interfaces = cls.interfaces; - !interfaces.isEmpty; - interfaces = interfaces.tail) { - addAllSupertypes(allSupertypes, interfaces.head); - } - cls.allSupertypes = allSupertypes.toLink(); - } else { - assert(identical(cls, compiler.objectClass)); - cls.allSupertypes = const Link<DartType>(); - } - } - - /** - * Adds [type] and all supertypes of [type] to [builder] while substituting - * type variables. - */ - void addAllSupertypes(LinkBuilder<DartType> builder, InterfaceType type) { - builder.addLast(type); - Link<DartType> typeArguments = type.typeArguments; - ClassElement classElement = type.element; - Link<DartType> typeVariables = classElement.typeVariables; - Link<DartType> supertypes = classElement.allSupertypes; - assert(invariant(element, supertypes != null, - message: "Supertypes not computed on $classElement " - "during resolution of $element")); - while (!supertypes.isEmpty) { - DartType supertype = supertypes.head; - builder.addLast(supertype.subst(typeArguments, typeVariables)); - supertypes = supertypes.tail; - } - } - - isBlackListed(DartType type) { - LibraryElement lib = element.getLibrary(); - return - !identical(lib, compiler.coreLibrary) && - !identical(lib, compiler.jsHelperLibrary) && - !identical(lib, compiler.interceptorsLibrary) && - (identical(type.element, compiler.dynamicClass) || - identical(type.element, compiler.boolClass) || - identical(type.element, compiler.numClass) || - identical(type.element, compiler.intClass) || - identical(type.element, compiler.doubleClass) || - identical(type.element, compiler.stringClass) || - identical(type.element, compiler.nullClass) || - identical(type.element, compiler.functionClass)); - } -} - -class ClassSupertypeResolver extends CommonResolverVisitor { - Scope context; - ClassElement classElement; - - ClassSupertypeResolver(Compiler compiler, ClassElement cls) - : context = Scope.buildEnclosingScope(cls), - this.classElement = cls, - super(compiler); - - void loadSupertype(ClassElement element, Node from) { - compiler.resolver.loadSupertypes(element, from); - element.ensureResolved(compiler); - } - - void visitNodeList(NodeList node) { - for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) { - link.head.accept(this); - } - } - - void visitClassNode(ClassNode node) { - if (node.superclass == null) { - if (!identical(classElement, compiler.objectClass)) { - loadSupertype(compiler.objectClass, node); - } - } else { - node.superclass.accept(this); - } - visitNodeList(node.interfaces); - } - - void visitMixinApplication(MixinApplication node) { - node.superclass.accept(this); - visitNodeList(node.mixins); - } - - void visitTypeAnnotation(TypeAnnotation node) { - node.typeName.accept(this); - } - - void visitIdentifier(Identifier node) { - Element element = context.lookup(node.source); - if (element == null) { - error(node, MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': node}); - } else if (!element.impliesType()) { - error(node, MessageKind.NOT_A_TYPE, {'node': node}); - } else { - if (element.isClass()) { - loadSupertype(element, node); - } else { - compiler.reportErrorCode(node, MessageKind.CLASS_NAME_EXPECTED); - } - } - } - - void visitSend(Send node) { - Identifier prefix = node.receiver.asIdentifier(); - if (prefix == null) { - error(node.receiver, MessageKind.NOT_A_PREFIX, {'node': node.receiver}); - return; - } - Element element = context.lookup(prefix.source); - if (element == null || !identical(element.kind, ElementKind.PREFIX)) { - error(node.receiver, MessageKind.NOT_A_PREFIX, {'node': node.receiver}); - return; - } - PrefixElement prefixElement = element; - Identifier selector = node.selector.asIdentifier(); - var e = prefixElement.lookupLocalMember(selector.source); - if (e == null || !e.impliesType()) { - error(node.selector, MessageKind.CANNOT_RESOLVE_TYPE, - {'typeName': node.selector}); - return; - } - loadSupertype(e, node); - } -} - -class VariableDefinitionsVisitor extends CommonResolverVisitor<SourceString> { - VariableDefinitions definitions; - ResolverVisitor resolver; - ElementKind kind; - VariableListElement variables; - - VariableDefinitionsVisitor(Compiler compiler, - this.definitions, this.resolver, this.kind) - : super(compiler) { - variables = new VariableListElementX.node( - definitions, ElementKind.VARIABLE_LIST, resolver.enclosingElement); - } - - SourceString visitSendSet(SendSet node) { - assert(node.arguments.tail.isEmpty); // Sanity check - resolver.visit(node.arguments.head); - return visit(node.selector); - } - - SourceString visitIdentifier(Identifier node) { - // The variable is initialized to null. - resolver.world.registerInstantiatedClass(compiler.nullClass); - return node.source; - } - - visitNodeList(NodeList node) { - for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) { - SourceString name = visit(link.head); - VariableElement element = - new VariableElementX(name, variables, kind, link.head); - resolver.defineElement(link.head, element); - } - } -} - -/** - * [SignatureResolver] resolves function signatures. - */ -class SignatureResolver extends CommonResolverVisitor<Element> { - final Element enclosingElement; - Link<Element> optionalParameters = const Link<Element>(); - int optionalParameterCount = 0; - bool optionalParametersAreNamed = false; - VariableDefinitions currentDefinitions; - - SignatureResolver(Compiler compiler, this.enclosingElement) : super(compiler); - - Element visitNodeList(NodeList node) { - // This must be a list of optional arguments. - String value = node.beginToken.stringValue; - if ((!identical(value, '[')) && (!identical(value, '{'))) { - internalError(node, "expected optional parameters"); - } - optionalParametersAreNamed = (identical(value, '{')); - LinkBuilder<Element> elements = analyzeNodes(node.nodes); - optionalParameterCount = elements.length; - optionalParameters = elements.toLink(); - return null; - } - - Element visitVariableDefinitions(VariableDefinitions node) { - Link<Node> definitions = node.definitions.nodes; - if (definitions.isEmpty) { - cancel(node, 'internal error: no parameter definition'); - return null; - } - if (!definitions.tail.isEmpty) { - cancel(definitions.tail.head, 'internal error: extra definition'); - return null; - } - Node definition = definitions.head; - if (definition is NodeList) { - cancel(node, 'optional parameters are not implemented'); - } - - if (currentDefinitions != null) { - cancel(node, 'function type parameters not supported'); - } - currentDefinitions = node; - Element element = definition.accept(this); - currentDefinitions = null; - return element; - } - - Element visitIdentifier(Identifier node) { - Element variables = new VariableListElementX.node(currentDefinitions, - ElementKind.VARIABLE_LIST, enclosingElement); - // Ensure a parameter is not typed 'void'. - variables.computeType(compiler); - return new VariableElementX(node.source, variables, - ElementKind.PARAMETER, node); - } - - SourceString getParameterName(Send node) { - var identifier = node.selector.asIdentifier(); - if (identifier != null) { - // Normal parameter: [:Type name:]. - return identifier.source; - } else { - // Function type parameter: [:void name(DartType arg):]. - var functionExpression = node.selector.asFunctionExpression(); - if (functionExpression != null && - functionExpression.name.asIdentifier() != null) { - return functionExpression.name.asIdentifier().source; - } else { - cancel(node, - 'internal error: unimplemented receiver on parameter send'); - } - } - } - - // The only valid [Send] can be in constructors and must be of the form - // [:this.x:] (where [:x:] represents an instance field). - FieldParameterElement visitSend(Send node) { - FieldParameterElement element; - if (node.receiver.asIdentifier() == null || - !node.receiver.asIdentifier().isThis()) { - error(node, MessageKind.INVALID_PARAMETER); - } else if (!identical(enclosingElement.kind, - ElementKind.GENERATIVE_CONSTRUCTOR)) { - error(node, MessageKind.FIELD_PARAMETER_NOT_ALLOWED); - } else { - SourceString name = getParameterName(node); - Element fieldElement = currentClass.lookupLocalMember(name); - if (fieldElement == null || - !identical(fieldElement.kind, ElementKind.FIELD)) { - error(node, MessageKind.NOT_A_FIELD, {'fieldName': name}); - } else if (!fieldElement.isInstanceMember()) { - error(node, MessageKind.NOT_INSTANCE_FIELD, {'fieldName': name}); - } - Element variables = new VariableListElementX.node(currentDefinitions, - ElementKind.VARIABLE_LIST, enclosingElement); - element = new FieldParameterElementX(name, fieldElement, variables, node); - } - return element; - } - - Element visitSendSet(SendSet node) { - Element element; - if (node.receiver != null) { - element = visitSend(node); - } else if (node.selector.asIdentifier() != null) { - Element variables = new VariableListElementX.node(currentDefinitions, - ElementKind.VARIABLE_LIST, enclosingElement); - element = new VariableElementX(node.selector.asIdentifier().source, - variables, ElementKind.PARAMETER, node); - } - // Visit the value. The compile time constant handler will - // make sure it's a compile time constant. - resolveExpression(node.arguments.head); - return element; - } - - Element visitFunctionExpression(FunctionExpression node) { - // This is a function typed parameter. - // TODO(ahe): Resolve the function type. - return visit(node.name); - } - - LinkBuilder<Element> analyzeNodes(Link<Node> link) { - LinkBuilder<Element> elements = new LinkBuilder<Element>(); - for (; !link.isEmpty; link = link.tail) { - Element element = link.head.accept(this); - if (element != null) { - elements.addLast(element); - } else { - // If parameter is null, the current node should be the last, - // and a list of optional named parameters. - if (!link.tail.isEmpty || (link.head is !NodeList)) { - internalError(link.head, "expected optional parameters"); - } - } - } - return elements; - } - - /** - * Resolves formal parameters and return type to a [FunctionSignature]. - */ - static FunctionSignature analyze(Compiler compiler, - NodeList formalParameters, - Node returnNode, - Element element) { - SignatureResolver visitor = new SignatureResolver(compiler, element); - Link<Element> parameters = const Link<Element>(); - int requiredParameterCount = 0; - if (formalParameters == null) { - if (!element.isGetter()) { - compiler.reportErrorCode(element, MessageKind.MISSING_FORMALS); - } - } else { - if (element.isGetter()) { - if (!identical(formalParameters.getEndToken().next.stringValue, - // TODO(ahe): Remove the check for native keyword. - 'native')) { - if (compiler.rejectDeprecatedFeatures && - // TODO(ahe): Remove isPlatformLibrary check. - !element.getLibrary().isPlatformLibrary) { - compiler.reportErrorCode(formalParameters, - MessageKind.EXTRA_FORMALS); - } else { - compiler.onDeprecatedFeature(formalParameters, 'getter parameters'); - } - } - } - LinkBuilder<Element> parametersBuilder = - visitor.analyzeNodes(formalParameters.nodes); - requiredParameterCount = parametersBuilder.length; - parameters = parametersBuilder.toLink(); - } - DartType returnType = compiler.resolveReturnType(element, returnNode); - if (element.isSetter() && (requiredParameterCount != 1 || - visitor.optionalParameterCount != 0)) { - // If there are no formal parameters, we already reported an error above. - if (formalParameters != null) { - compiler.reportErrorCode(formalParameters, - MessageKind.ILLEGAL_SETTER_FORMALS); - } - } - if (element.isGetter() && (requiredParameterCount != 0 - || visitor.optionalParameterCount != 0)) { - compiler.reportErrorCode(formalParameters, MessageKind.EXTRA_FORMALS); - } - return new FunctionSignatureX(parameters, - visitor.optionalParameters, - requiredParameterCount, - visitor.optionalParameterCount, - visitor.optionalParametersAreNamed, - returnType); - } - - // TODO(ahe): This is temporary. - void resolveExpression(Node node) { - if (node == null) return; - node.accept(new ResolverVisitor(compiler, enclosingElement, - new TreeElementMapping(enclosingElement))); - } - - // TODO(ahe): This is temporary. - ClassElement get currentClass { - return enclosingElement.isMember() - ? enclosingElement.getEnclosingClass() : null; - } -} - -class ConstructorResolver extends CommonResolverVisitor<Element> { - final ResolverVisitor resolver; - bool inConstContext = false; - DartType type; - - ConstructorResolver(Compiler compiler, this.resolver) : super(compiler); - - visitNode(Node node) { - throw 'not supported'; - } - - failOrReturnErroneousElement(Element enclosing, Node diagnosticNode, - SourceString targetName, MessageKind kind, - Map arguments) { - if (inConstContext) { - error(diagnosticNode, kind, arguments); - } else { - ResolutionWarning warning = new ResolutionWarning(kind, arguments); - compiler.reportWarning(diagnosticNode, warning); - return new ErroneousElementX(kind, arguments, targetName, enclosing); - } - } - - Selector createConstructorSelector(SourceString constructorName) { - return constructorName == const SourceString('') - ? new Selector.callDefaultConstructor( - resolver.enclosingElement.getLibrary()) - : new Selector.callConstructor( - constructorName, - resolver.enclosingElement.getLibrary()); - } - - // TODO(ngeoffray): method named lookup should not report errors. - FunctionElement lookupConstructor(ClassElement cls, - Node diagnosticNode, - SourceString constructorName) { - cls.ensureResolved(compiler); - Selector selector = createConstructorSelector(constructorName); - Element result = cls.lookupConstructor(selector); - if (result == null) { - String fullConstructorName = - resolver.compiler.resolver.constructorNameForDiagnostics( - cls.name, - constructorName); - return failOrReturnErroneousElement( - cls, - diagnosticNode, - new SourceString(fullConstructorName), - MessageKind.CANNOT_FIND_CONSTRUCTOR, - {'constructorName': fullConstructorName}); - } else if (inConstContext && !result.modifiers.isConst()) { - error(diagnosticNode, MessageKind.CONSTRUCTOR_IS_NOT_CONST); - } - return result; - } - - visitNewExpression(NewExpression node) { - inConstContext = node.isConst(); - Node selector = node.send.selector; - Element e = visit(selector); - return finishConstructorReference(e, node.send.selector, node); - } - - /// Finishes resolution of a constructor reference and records the - /// type of the constructed instance on [expression]. - FunctionElement finishConstructorReference(Element e, - Node diagnosticNode, - Node expression) { - // Find the unnamed constructor if the reference resolved to a - // class. - if (!Elements.isUnresolved(e) && e.isClass()) { - ClassElement cls = e; - cls.ensureResolved(compiler); - if (cls.isInterface() && (cls.defaultClass == null)) { - // TODO(ahe): Remove this check and error message when we - // don't have interfaces anymore. - error(diagnosticNode, - MessageKind.CANNOT_INSTANTIATE_INTERFACE, - {'interfaceName': cls.name}); - } - // The unnamed constructor may not exist, so [e] may become unresolved. - e = lookupConstructor(cls, diagnosticNode, const SourceString('')); - } - if (type == null) { - if (Elements.isUnresolved(e)) { - type = compiler.dynamicClass.computeType(compiler); - } else { - type = e.getEnclosingClass().computeType(compiler).asRaw(); - } - } - resolver.mapping.setType(expression, type); - return e; - } - - visitTypeAnnotation(TypeAnnotation node) { - assert(invariant(node, type == null)); - type = resolver.resolveTypeRequired(node); - return resolver.mapping[node]; - } - - visitSend(Send node) { - Element e = visit(node.receiver); - if (Elements.isUnresolved(e)) return e; - Identifier name = node.selector.asIdentifier(); - if (name == null) internalError(node.selector, 'unexpected node'); - - if (identical(e.kind, ElementKind.CLASS)) { - ClassElement cls = e; - cls.ensureResolved(compiler); - if (cls.isInterface() && (cls.defaultClass == null)) { - error(node.receiver, - MessageKind.CANNOT_INSTANTIATE_INTERFACE, - {'interfaceName': cls.name}); - } - return lookupConstructor(cls, name, name.source); - } else if (identical(e.kind, ElementKind.PREFIX)) { - PrefixElement prefix = e; - e = prefix.lookupLocalMember(name.source); - if (e == null) { - return failOrReturnErroneousElement(resolver.enclosingElement, name, - name.source, - MessageKind.CANNOT_RESOLVE, - {'name': name}); - } else if (!identical(e.kind, ElementKind.CLASS)) { - error(node, MessageKind.NOT_A_TYPE, {'node': name}); - } - } else { - internalError(node.receiver, 'unexpected element $e'); - } - return e; - } - - Element visitIdentifier(Identifier node) { - SourceString name = node.source; - Element e = resolver.lookup(node, name); - // TODO(johnniwinther): Change errors to warnings, cf. 11.11.1. - if (e == null) { - return failOrReturnErroneousElement(resolver.enclosingElement, node, name, - MessageKind.CANNOT_RESOLVE, - {'name': name}); - } else if (e.isErroneous()) { - return e; - } else if (identical(e.kind, ElementKind.TYPEDEF)) { - error(node, MessageKind.CANNOT_INSTANTIATE_TYPEDEF, - {'typedefName': name}); - } else if (identical(e.kind, ElementKind.TYPE_VARIABLE)) { - error(node, MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE, - {'typeVariableName': name}); - } else if (!identical(e.kind, ElementKind.CLASS) - && !identical(e.kind, ElementKind.PREFIX)) { - error(node, MessageKind.NOT_A_TYPE, {'node': name}); - } - return e; - } - - /// Assumed to be called by [resolveRedirectingFactory]. - Element visitReturn(Return node) { - Node expression = node.expression; - return finishConstructorReference(visit(expression), - expression, expression); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/resolution/resolution.dart b/pkgs/markdown/test/lib/src/compiler/implementation/resolution/resolution.dart deleted file mode 100644 index 130486c..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/resolution/resolution.dart +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library resolution; - -import 'dart:collection' show Queue, LinkedHashMap; - -import '../dart2jslib.dart' hide Diagnostic; -import '../dart_types.dart'; -import '../../compiler.dart' show Diagnostic; -import '../tree/tree.dart'; -import '../elements/elements.dart'; -import '../elements/modelx.dart' - show FunctionElementX, - ErroneousElementX, - VariableElementX, - FieldParameterElementX, - VariableListElementX, - FunctionSignatureX, - LabelElementX, - TargetElementX, - MixinApplicationElementX; -import '../util/util.dart'; -import '../scanner/scannerlib.dart' show PartialMetadataAnnotation; - -import 'secret_tree_element.dart' show getTreeElement, setTreeElement; - -part 'members.dart'; -part 'scope.dart';
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/resolution/scope.dart b/pkgs/markdown/test/lib/src/compiler/implementation/resolution/scope.dart deleted file mode 100644 index 92e7840..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/resolution/scope.dart +++ /dev/null
@@ -1,163 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of resolution; - -abstract class Scope { - /** - * Adds [element] to this scope. This operation is only allowed on mutable - * scopes such as [MethodScope] and [BlockScope]. - */ - Element add(Element element); - - /** - * Looks up the [Element] for [name] in this scope. - */ - Element lookup(SourceString name); - - static Scope buildEnclosingScope(Element element) { - return element.enclosingElement != null - ? element.enclosingElement.buildScope() : element.buildScope(); - } -} - -abstract class NestedScope extends Scope { - final Scope parent; - - NestedScope(this.parent); - - Element lookup(SourceString name) { - Element result = localLookup(name); - if (result != null) return result; - return parent.lookup(name); - } - - Element localLookup(SourceString name); - - static Scope buildEnclosingScope(Element element) { - return element.enclosingElement != null - ? element.enclosingElement.buildScope() : element.buildScope(); - } -} - -/** - * [TypeDeclarationScope] defines the outer scope of a type declaration in - * which the declared type variables and the entities in the enclosing scope are - * available but where declared and inherited members are not available. This - * scope is only used for class/interface declarations during resolution of the - * class hierarchy. In all other cases [ClassScope] is used. - */ -class TypeDeclarationScope extends NestedScope { - final TypeDeclarationElement element; - - TypeDeclarationScope(parent, this.element) - : super(parent) { - assert(parent != null); - } - - Element add(Element newElement) { - throw "Cannot add element to TypeDeclarationScope"; - } - - Element lookupTypeVariable(SourceString name) { - Link<DartType> typeVariableLink = element.typeVariables; - while (!typeVariableLink.isEmpty) { - TypeVariableType typeVariable = typeVariableLink.head; - if (typeVariable.name == name) { - return typeVariable.element; - } - typeVariableLink = typeVariableLink.tail; - } - return null; - } - - Element localLookup(SourceString name) => lookupTypeVariable(name); - - String toString() => - 'TypeDeclarationScope($element)'; -} - -abstract class MutableScope extends NestedScope { - final Map<SourceString, Element> elements; - - MutableScope(Scope parent) - : super(parent), - this.elements = new Map<SourceString, Element>() { - assert(parent != null); - } - - Element add(Element newElement) { - if (elements.containsKey(newElement.name)) { - return elements[newElement.name]; - } - elements[newElement.name] = newElement; - return newElement; - } - - Element localLookup(SourceString name) => elements[name]; -} - -class MethodScope extends MutableScope { - final Element element; - - MethodScope(Scope parent, this.element) - : super(parent); - - String toString() => 'MethodScope($element${elements.keys.toList()})'; -} - -class BlockScope extends MutableScope { - BlockScope(Scope parent) : super(parent); - - String toString() => 'BlockScope(${elements.keys.toList()})'; -} - -/** - * [ClassScope] defines the inner scope of a class/interface declaration in - * which declared members, declared type variables, entities in the enclosing - * scope and inherited members are available, in the given order. - */ -class ClassScope extends TypeDeclarationScope { - ClassElement get element => super.element; - - ClassScope(Scope parentScope, ClassElement element) - : super(parentScope, element) { - assert(parent != null); - } - - Element localLookup(SourceString name) { - Element result = element.lookupLocalMember(name); - if (result != null) return result; - return super.localLookup(name); - } - - Element lookup(SourceString name) { - Element result = localLookup(name); - if (result != null) return result; - result = parent.lookup(name); - if (result != null) return result; - return element.lookupSuperMember(name); - } - - Element add(Element newElement) { - throw "Cannot add an element in a class scope"; - } - - String toString() => 'ClassScope($element)'; -} - -class LibraryScope implements Scope { - final LibraryElement library; - - LibraryScope(LibraryElement this.library); - - Element localLookup(SourceString name) => library.find(name); - Element lookup(SourceString name) => localLookup(name); - - Element add(Element newElement) { - throw "Cannot add an element to a library scope"; - } - - String toString() => 'LibraryScope($library)'; -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/resolution/secret_tree_element.dart b/pkgs/markdown/test/lib/src/compiler/implementation/resolution/secret_tree_element.dart deleted file mode 100644 index e8ee0f1..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/resolution/secret_tree_element.dart +++ /dev/null
@@ -1,46 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/** - * Encapsulates the field [TreeElementMixin._element]. - * - * This library is an implementation detail of dart2js, and should not - * be imported except by resolution and tree node libraries, or for - * testing. - * - * We have taken great care to ensure AST nodes can be cached between - * compiler instances. Part of this is requires that we always access - * resolution results through [TreeElements]. - * - * So please, do not add additional elements to this library, and do - * not import it. - */ -library secret_tree_element; - -/** - * The superclass of all AST nodes. - */ -abstract class TreeElementMixin { - // Deliberately using [Object] here to thwart code completion. - // You're not really supposed to access this field anyways. - Object _element; -} - -/** - * Do not call this method directly. Instead, use an instance of - * [TreeElements]. - * - * Using [Object] as return type to thwart code completion. - */ -Object getTreeElement(TreeElementMixin node) { - return node._element; -} - -/** - * Do not call this method directly. Instead, use an instance of - * [TreeElements]. - */ -void setTreeElement(TreeElementMixin node, Object value) { - node._element = value; -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/resolved_visitor.dart b/pkgs/markdown/test/lib/src/compiler/implementation/resolved_visitor.dart deleted file mode 100644 index 3bfadb2..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/resolved_visitor.dart +++ /dev/null
@@ -1,67 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of dart2js; - -abstract class ResolvedVisitor<R> extends Visitor<R> { - TreeElements elements; - - ResolvedVisitor(this.elements); - - R visitSend(Send node) { - if (node.isSuperCall) { - return visitSuperSend(node); - } else if (node.isOperator) { - return visitOperatorSend(node); - } else if (node.isPropertyAccess) { - Element element = elements[node]; - if (!Elements.isUnresolved(element) && element.impliesType()) { - // A reference to a class literal, typedef or type variable. - return visitTypeReferenceSend(node); - } else { - return visitGetterSend(node); - } - } else if (Elements.isClosureSend(node, elements[node])) { - return visitClosureSend(node); - } else { - Element element = elements[node]; - if (Elements.isUnresolved(element)) { - if (element == null) { - // Example: f() with 'f' unbound. - // This can only happen inside an instance method. - return visitDynamicSend(node); - } else { - return visitStaticSend(node); - } - } else if (element.impliesType()) { - // A reference to a class literal, typedef or type variable. - return visitTypeReferenceSend(node); - } else if (element.isInstanceMember()) { - // Example: f() with 'f' bound to instance method. - return visitDynamicSend(node); - } else if (!element.isInstanceMember()) { - // Example: A.f() or f() with 'f' bound to a static function. - // Also includes new A() or new A.named() which is treated like a - // static call to a factory. - return visitStaticSend(node); - } else { - internalError("Cannot generate code for send", node: node); - } - } - } - - R visitSuperSend(Send node); - R visitOperatorSend(Send node); - R visitGetterSend(Send node); - R visitClosureSend(Send node); - R visitDynamicSend(Send node); - R visitStaticSend(Send node); - R visitTypeReferenceSend(Send node); - - void internalError(String reason, {Node node}); - - R visitNode(Node node) { - internalError("Unhandled node", node: node); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/array_based_scanner.dart b/pkgs/markdown/test/lib/src/compiler/implementation/scanner/array_based_scanner.dart deleted file mode 100644 index 01f8e9e..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/array_based_scanner.dart +++ /dev/null
@@ -1,183 +0,0 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of scanner_implementation; - -abstract -class ArrayBasedScanner<S extends SourceString> extends AbstractScanner<S> { - int get charOffset => byteOffset + extraCharOffset; - final Token tokens; - Token tail; - int tokenStart; - int byteOffset; - final bool includeComments; - - /** Since the input is UTF8, some characters are represented by more - * than one byte. [extraCharOffset] tracks the difference. */ - int extraCharOffset; - Link<BeginGroupToken> groupingStack = const Link<BeginGroupToken>(); - - ArrayBasedScanner(this.includeComments) - : this.extraCharOffset = 0, - this.tokenStart = -1, - this.byteOffset = -1, - this.tokens = new Token(EOF_INFO, -1) { - this.tail = this.tokens; - } - - int advance() { - int next = nextByte(); - return next; - } - - int select(int choice, PrecedenceInfo yes, PrecedenceInfo no) { - int next = advance(); - if (identical(next, choice)) { - appendPrecedenceToken(yes); - return advance(); - } else { - appendPrecedenceToken(no); - return next; - } - } - - void appendPrecedenceToken(PrecedenceInfo info) { - tail.next = new Token(info, tokenStart); - tail = tail.next; - } - - void appendStringToken(PrecedenceInfo info, String value) { - tail.next = new StringToken(info, value, tokenStart); - tail = tail.next; - } - - void appendKeywordToken(Keyword keyword) { - String syntax = keyword.syntax; - - // Type parameters and arguments cannot contain 'this' or 'super'. - if (identical(syntax, 'this') || identical(syntax, 'super')) discardOpenLt(); - tail.next = new KeywordToken(keyword, tokenStart); - tail = tail.next; - } - - void appendEofToken() { - tail.next = new Token(EOF_INFO, charOffset); - tail = tail.next; - // EOF points to itself so there's always infinite look-ahead. - tail.next = tail; - discardOpenLt(); - while (!groupingStack.isEmpty) { - unmatchedBeginGroup(groupingStack.head); - groupingStack = groupingStack.tail; - } - } - - void beginToken() { - tokenStart = charOffset; - } - - Token firstToken() { - return tokens.next; - } - - Token previousToken() { - return tail; - } - - void addToCharOffset(int offset) { - extraCharOffset += offset; - } - - void appendWhiteSpace(int next) { - // Do nothing, we don't collect white space. - } - - void appendBeginGroup(PrecedenceInfo info, String value) { - Token token = new BeginGroupToken(info, value, tokenStart); - tail.next = token; - tail = tail.next; - if (!identical(info.kind, LT_TOKEN)) discardOpenLt(); - groupingStack = groupingStack.prepend(token); - } - - int appendEndGroup(PrecedenceInfo info, String value, int openKind) { - assert(!identical(openKind, LT_TOKEN)); - appendStringToken(info, value); - discardOpenLt(); - if (groupingStack.isEmpty) { - return advance(); - } - BeginGroupToken begin = groupingStack.head; - if (!identical(begin.kind, openKind)) { - if (!identical(openKind, OPEN_CURLY_BRACKET_TOKEN) || - !identical(begin.kind, STRING_INTERPOLATION_TOKEN)) { - // Not ending string interpolation. - return error(new SourceString('Unmatched ${begin.stringValue}')); - } - // We're ending an interpolated expression. - begin.endGroup = tail; - groupingStack = groupingStack.tail; - // Using "start-of-text" to signal that we're back in string - // scanning mode. - return $STX; - } - begin.endGroup = tail; - groupingStack = groupingStack.tail; - return advance(); - } - - void appendGt(PrecedenceInfo info, String value) { - appendStringToken(info, value); - if (groupingStack.isEmpty) return; - if (identical(groupingStack.head.kind, LT_TOKEN)) { - groupingStack.head.endGroup = tail; - groupingStack = groupingStack.tail; - } - } - - void appendGtGt(PrecedenceInfo info, String value) { - appendStringToken(info, value); - if (groupingStack.isEmpty) return; - if (identical(groupingStack.head.kind, LT_TOKEN)) { - groupingStack = groupingStack.tail; - } - if (groupingStack.isEmpty) return; - if (identical(groupingStack.head.kind, LT_TOKEN)) { - groupingStack.head.endGroup = tail; - groupingStack = groupingStack.tail; - } - } - - void appendGtGtGt(PrecedenceInfo info, String value) { - appendStringToken(info, value); - if (groupingStack.isEmpty) return; - if (identical(groupingStack.head.kind, LT_TOKEN)) { - groupingStack = groupingStack.tail; - } - if (groupingStack.isEmpty) return; - if (identical(groupingStack.head.kind, LT_TOKEN)) { - groupingStack = groupingStack.tail; - } - if (groupingStack.isEmpty) return; - if (identical(groupingStack.head.kind, LT_TOKEN)) { - groupingStack.head.endGroup = tail; - groupingStack = groupingStack.tail; - } - } - - void appendComment() { - if (!includeComments) return; - SourceString value = utf8String(tokenStart, -1); - appendByteStringToken(COMMENT_INFO, value); - } - - void discardOpenLt() { - while (!groupingStack.isEmpty - && identical(groupingStack.head.kind, LT_TOKEN)) { - groupingStack = groupingStack.tail; - } - } - - void unmatchedBeginGroup(BeginGroupToken begin); -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/byte_array_scanner.dart b/pkgs/markdown/test/lib/src/compiler/implementation/scanner/byte_array_scanner.dart deleted file mode 100644 index 4cf9eeb..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/byte_array_scanner.dart +++ /dev/null
@@ -1,40 +0,0 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of parser; - -/** - * Scanner that reads from a byte array and creates tokens that points - * to the same array. - */ -class ByteArrayScanner extends ArrayBasedScanner<ByteString> { - final List<int> bytes; - - ByteArrayScanner(List<int> this.bytes, [bool includeComments = false]) - : super(includeComments); - - int nextByte() => byteAt(++byteOffset); - - int peek() => byteAt(byteOffset + 1); - - int byteAt(int index) => bytes[index]; - - AsciiString asciiString(int start, int offset) { - return AsciiString.of(bytes, start, byteOffset - start + offset); - } - - Utf8String utf8String(int start, int offset) { - return Utf8String.of(bytes, start, byteOffset - start + offset + 1); - } - - void appendByteStringToken(PrecedenceInfo info, ByteString value) { - tail.next = new ByteStringToken(info, value, tokenStart); - tail = tail.next; - } - - // This method should be equivalent to the one in super. However, - // this is a *HOT* method and Dart VM performs better if it is easy - // to inline. - int advance() => bytes[++byteOffset]; -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/byte_strings.dart b/pkgs/markdown/test/lib/src/compiler/implementation/scanner/byte_strings.dart deleted file mode 100644 index 4d79898..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/byte_strings.dart +++ /dev/null
@@ -1,154 +0,0 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/** - * An abstract string representation. - */ -abstract class ByteString extends Iterable<int> implements SourceString { - final List<int> bytes; - final int offset; - final int length; - int _hashCode; - - ByteString(List<int> this.bytes, int this.offset, int this.length); - - String get charset; - - String slowToString() => new String.fromCharCodes( - new Utf8Decoder(bytes, offset, length).decodeRest()); - - String toString() => "ByteString(${slowToString()})"; - - bool operator ==(other) { - throw "should be overridden in subclass"; - } - - Iterator<int> get iterator => new Utf8Decoder(bytes, offset, length); - - int get hashCode { - if (_hashCode == null) { - _hashCode = computeHashCode(); - } - return _hashCode; - } - - int computeHashCode() { - int code = 1; - int end = offset + length; - for (int i = offset; i < end; i++) { - code += 19 * code + bytes[i]; - } - return code; - } - - printOn(StringBuffer sb) { - sb.add(slowToString()); - } - - bool get isEmpty => length == 0; - bool isPrivate() => !isEmpty && identical(bytes[offset], $_); - - String get stringValue => null; -} - -/** - * A string that consists purely of 7bit ASCII characters. - */ -class AsciiString extends ByteString { - final String charset = "ASCII"; - - AsciiString(List<int> bytes, int offset, int length) - : super(bytes, offset, length); - - static AsciiString of(List<int> bytes, int offset, int length) { - AsciiString string = new AsciiString(bytes, offset, length); - return string; - } - - Iterator<int> get iterator => new AsciiStringIterator(bytes); - - SourceString copyWithoutQuotes(int initial, int terminal) { - return new AsciiString(bytes, offset + initial, - length - initial - terminal); - } - - - static AsciiString fromString(String string) { - List<int> bytes = string.charCodes; - return AsciiString.of(bytes, 0, bytes.length); - } -} - - -class AsciiStringIterator implements Iterator<int> { - final List<int> bytes; - int offset; - final int end; - int _current; - - AsciiStringIterator(List<int> bytes) - : this.bytes = bytes, offset = 0, end = bytes.length; - AsciiStringIterator.range(List<int> bytes, int from, int length) - : this.bytes = bytes, offset = from, end = from + length; - - int get current => _current; - bool moveNext() { - if (offset < end) { - _current = bytes[offset++]; - return true; - } - _current = null; - return false; - } -} - - -/** - * A string that consists of characters that can be encoded as UTF-8. - */ -class Utf8String extends ByteString { - final String charset = "UTF8"; - - Utf8String(List<int> bytes, int offset, int length) - : super(bytes, offset, length); - - static Utf8String of(List<int> bytes, int offset, int length) { - return new Utf8String(bytes, offset, length); - } - - static Utf8String fromString(String string) { - throw "not implemented yet"; - } - - Iterator<int> get iterator => new Utf8Decoder(bytes, 0, length); - - SourceString copyWithoutQuotes(int initial, int terminal) { - assert((){ - // Only allow dropping ASCII characters, to guarantee that - // the resulting Utf8String is still valid. - for (int i = 0; i < initial; i++) { - if (bytes[offset + i] >= 0x80) return false; - } - for (int i = 0; i < terminal; i++) { - if (bytes[offset + length - terminal + i] >= 0x80) return false; - } - return true; - }); - // TODO(lrn): Check that first and last bytes use the same type of quotes. - return new Utf8String(bytes, offset + initial, - length - initial - terminal); - } -} - -/** - * A ByteString-valued token. - */ -class ByteStringToken extends Token { - final ByteString value; - - ByteStringToken(PrecedenceInfo info, ByteString this.value, int charOffset) - : super(info, charOffset); - - String toString() => value.toString(); -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/class_element_parser.dart b/pkgs/markdown/test/lib/src/compiler/implementation/scanner/class_element_parser.dart deleted file mode 100644 index 1e359aa..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/class_element_parser.dart +++ /dev/null
@@ -1,197 +0,0 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of scanner; - -class ClassElementParser extends PartialParser { - ClassElementParser(Listener listener) : super(listener); - - Token parseClassBody(Token token) => fullParseClassBody(token); -} - -class PartialClassElement extends ClassElementX { - final Token beginToken; - final Token endToken; - ClassNode cachedNode; - - PartialClassElement(SourceString name, - Token this.beginToken, - Token this.endToken, - Element enclosing, - int id) - : super(name, enclosing, id, STATE_NOT_STARTED); - - void set supertypeLoadState(int state) { - assert(state == supertypeLoadState + 1); - assert(state <= STATE_DONE); - super.supertypeLoadState = state; - } - - void set resolutionState(int state) { - assert(state == resolutionState + 1); - assert(state <= STATE_DONE); - super.resolutionState = state; - } - - ClassNode parseNode(Compiler compiler) { - if (cachedNode != null) return cachedNode; - compiler.withCurrentElement(this, () { - compiler.parser.measure(() { - MemberListener listener = new MemberListener(compiler, this); - Parser parser = new ClassElementParser(listener); - Token token = parser.parseTopLevelDeclaration(beginToken); - assert(identical(token, endToken.next)); - cachedNode = listener.popNode(); - assert(listener.nodes.isEmpty); - }); - compiler.patchParser.measure(() { - if (isPatched) { - // TODO(lrn): Perhaps extract functionality so it doesn't - // need compiler. - compiler.patchParser.parsePatchClassNode(patch); - } - }); - }); - return cachedNode; - } - - Token position() => beginToken; - - // TODO(johnniwinther): Ensure that modifiers are always available. - Modifiers get modifiers => - cachedNode != null ? cachedNode.modifiers : Modifiers.EMPTY; - - bool isInterface() => identical(beginToken.stringValue, "interface"); -} - -class MemberListener extends NodeListener { - final ClassElement enclosingElement; - - MemberListener(DiagnosticListener listener, - Element enclosingElement) - : this.enclosingElement = enclosingElement, - super(listener, enclosingElement.getCompilationUnit()); - - bool isConstructorName(Node nameNode) { - if (enclosingElement == null || - enclosingElement.kind != ElementKind.CLASS) { - return false; - } - SourceString name; - if (nameNode.asIdentifier() != null) { - name = nameNode.asIdentifier().source; - } else { - Send send = nameNode.asSend(); - name = send.receiver.asIdentifier().source; - } - return enclosingElement.name == name; - } - - SourceString getMethodNameHack(Node methodName) { - Send send = methodName.asSend(); - if (send == null) return methodName.asIdentifier().source; - Identifier receiver = send.receiver.asIdentifier(); - Identifier selector = send.selector.asIdentifier(); - Operator operator = selector.asOperator(); - if (operator != null) { - assert(identical(receiver.source.stringValue, 'operator')); - // TODO(ahe): It is a hack to compare to ')', but it beats - // parsing the node. - bool isUnary = identical(operator.token.next.next.stringValue, ')'); - return Elements.constructOperatorName(operator.source, isUnary); - } else { - if (receiver == null) { - listener.cancel('library prefix in named factory constructor not ' - 'implemented', node: send.receiver); - } - if (receiver.source != enclosingElement.name) { - listener.onDeprecatedFeature(receiver, 'interface factories'); - } - return Elements.constructConstructorName(receiver.source, - selector.source); - } - } - - void endMethod(Token getOrSet, Token beginToken, Token endToken) { - super.endMethod(getOrSet, beginToken, endToken); - FunctionExpression method = popNode(); - pushNode(null); - bool isConstructor = isConstructorName(method.name); - SourceString name = getMethodNameHack(method.name); - ElementKind kind = ElementKind.FUNCTION; - if (isConstructor) { - if (getOrSet != null) { - recoverableError('illegal modifier', token: getOrSet); - } - kind = ElementKind.GENERATIVE_CONSTRUCTOR; - } else if (getOrSet != null) { - kind = (identical(getOrSet.stringValue, 'get')) - ? ElementKind.GETTER : ElementKind.SETTER; - } - Element memberElement = - new PartialFunctionElement(name, beginToken, getOrSet, endToken, - kind, method.modifiers, enclosingElement); - addMember(memberElement); - } - - void endFactoryMethod(Token beginToken, Token endToken) { - super.endFactoryMethod(beginToken, endToken); - FunctionExpression method = popNode(); - pushNode(null); - SourceString name = getMethodNameHack(method.name); - Identifier singleIdentifierName = method.name.asIdentifier(); - if (singleIdentifierName != null && singleIdentifierName.source == name) { - if (name != enclosingElement.name) { - listener.onDeprecatedFeature(method.name, 'interface factories'); - } - } - ElementKind kind = ElementKind.FUNCTION; - Element memberElement = - new PartialFunctionElement(name, beginToken, null, endToken, - kind, method.modifiers, enclosingElement); - addMember(memberElement); - } - - void endFields(int count, Token beginToken, Token endToken) { - super.endFields(count, beginToken, endToken); - VariableDefinitions variableDefinitions = popNode(); - Modifiers modifiers = variableDefinitions.modifiers; - pushNode(null); - void buildFieldElement(SourceString name, Element fields) { - Element element = - new VariableElementX(name, fields, ElementKind.FIELD, null); - addMember(element); - } - buildFieldElements(modifiers, variableDefinitions.definitions, - enclosingElement, - buildFieldElement, beginToken, endToken); - } - - void endInitializer(Token assignmentOperator) { - pushNode(null); // Super expects an expression, but - // ClassElementParser just skips expressions. - super.endInitializer(assignmentOperator); - } - - void endInitializers(int count, Token beginToken, Token endToken) { - pushNode(null); - } - - void addMember(Element memberElement) { - for (Link link = metadata; !link.isEmpty; link = link.tail) { - memberElement.addMetadata(link.head); - } - metadata = const Link<MetadataAnnotation>(); - enclosingElement.addMember(memberElement, listener); - } - - void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) { - popNode(); // Discard arguments. - if (periodBeforeName != null) { - popNode(); // Discard name. - } - popNode(); // Discard node (Send or Identifier). - pushMetadata(new PartialMetadataAnnotation(beginToken, endToken)); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/keyword.dart b/pkgs/markdown/test/lib/src/compiler/implementation/scanner/keyword.dart deleted file mode 100644 index 5d3c9a8..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/keyword.dart +++ /dev/null
@@ -1,235 +0,0 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of scanner; - -/** - * A keyword in the Dart programming language. - */ -class Keyword extends Iterable<int> implements SourceString { - static const List<Keyword> values = const <Keyword> [ - const Keyword("assert"), - const Keyword("break"), - const Keyword("case"), - const Keyword("catch"), - const Keyword("class"), - const Keyword("const"), - const Keyword("continue"), - const Keyword("default"), - const Keyword("do"), - const Keyword("else"), - const Keyword("extends"), - const Keyword("false"), - const Keyword("final"), - const Keyword("finally"), - const Keyword("for"), - const Keyword("if"), - const Keyword("in"), - const Keyword("new"), - const Keyword("null"), - const Keyword("return"), - const Keyword("super"), - const Keyword("switch"), - const Keyword("this"), - const Keyword("throw"), - const Keyword("true"), - const Keyword("try"), - const Keyword("var"), - const Keyword("void"), - const Keyword("while"), - const Keyword("with"), - - // TODO(ahe): Don't think this is a reserved word. - // See: http://dartbug.com/5579 - const Keyword("is", info: IS_INFO), - - const Keyword("abstract", isBuiltIn: true), - const Keyword("as", info: AS_INFO, isBuiltIn: true), - const Keyword("dynamic", isBuiltIn: true), - const Keyword("export", isBuiltIn: true), - const Keyword("external", isBuiltIn: true), - const Keyword("factory", isBuiltIn: true), - const Keyword("get", isBuiltIn: true), - const Keyword("implements", isBuiltIn: true), - const Keyword("import", isBuiltIn: true), - const Keyword("interface", isBuiltIn: true), - const Keyword("library", isBuiltIn: true), - const Keyword("operator", isBuiltIn: true), - const Keyword("part", isBuiltIn: true), - const Keyword("set", isBuiltIn: true), - const Keyword("static", isBuiltIn: true), - const Keyword("typedef", isBuiltIn: true), - - const Keyword("hide", isPseudo: true), - const Keyword("native", isPseudo: true), - const Keyword("of", isPseudo: true), - const Keyword("on", isPseudo: true), - const Keyword("show", isPseudo: true), - const Keyword("source", isPseudo: true) ]; - - // TODO(aprelev@gmail.com): Remove deprecated Dynamic keyword support. - static const DYNAMIC_DEPRECATED = const Keyword("Dynamic", isBuiltIn: true); - - final String syntax; - final bool isPseudo; - final bool isBuiltIn; - final PrecedenceInfo info; - - static Map<String, Keyword> _keywords; - static Map<String, Keyword> get keywords { - if (_keywords == null) { - _keywords = computeKeywordMap(); - } - return _keywords; - } - - const Keyword(String this.syntax, - {bool this.isPseudo: false, - bool this.isBuiltIn: false, - PrecedenceInfo this.info: KEYWORD_INFO}); - - static Map<String, Keyword> computeKeywordMap() { - Map<String, Keyword> result = new LinkedHashMap<String, Keyword>(); - for (Keyword keyword in values) { - result[keyword.syntax] = keyword; - } - return result; - } - - int get hashCode => syntax.hashCode; - - bool operator ==(other) { - return other is SourceString && toString() == other.slowToString(); - } - - Iterator<int> get iterator => new StringCodeIterator(syntax); - - void printOn(StringBuffer sb) { - sb.add(syntax); - } - - String toString() => syntax; - String slowToString() => syntax; - String get stringValue => syntax; - - SourceString copyWithoutQuotes(int initial, int terminal) { - // TODO(lrn): consider remodelling to avoid having this method in keywords. - return this; - } - - bool get isEmpty => false; - bool isPrivate() => false; -} - -/** - * Abstract state in a state machine for scanning keywords. - */ -abstract class KeywordState { - bool isLeaf(); - KeywordState next(int c); - Keyword get keyword; - - static KeywordState _KEYWORD_STATE; - static KeywordState get KEYWORD_STATE { - if (_KEYWORD_STATE == null) { - List<String> strings = - new List<String>.fixedLength(Keyword.values.length); - for (int i = 0; i < Keyword.values.length; i++) { - strings[i] = Keyword.values[i].syntax; - } - strings.sort((a,b) => a.compareTo(b)); - _KEYWORD_STATE = computeKeywordStateTable(0, strings, 0, strings.length); - } - return _KEYWORD_STATE; - } - - static KeywordState computeKeywordStateTable(int start, List<String> strings, - int offset, int length) { - List<KeywordState> result = new List<KeywordState>.fixedLength(26); - assert(length != 0); - int chunk = 0; - int chunkStart = -1; - bool isLeaf = false; - for (int i = offset; i < offset + length; i++) { - if (strings[i].length == start) { - isLeaf = true; - } - if (strings[i].length > start) { - int c = strings[i].charCodeAt(start); - if (chunk != c) { - if (chunkStart != -1) { - assert(result[chunk - $a] == null); - result[chunk - $a] = computeKeywordStateTable(start + 1, strings, - chunkStart, - i - chunkStart); - } - chunkStart = i; - chunk = c; - } - } - } - if (chunkStart != -1) { - assert(result[chunk - $a] == null); - result[chunk - $a] = - computeKeywordStateTable(start + 1, strings, chunkStart, - offset + length - chunkStart); - } else { - assert(length == 1); - return new LeafKeywordState(strings[offset]); - } - if (isLeaf) { - return new ArrayKeywordState(result, strings[offset]); - } else { - return new ArrayKeywordState(result, null); - } - } -} - -/** - * A state with multiple outgoing transitions. - */ -class ArrayKeywordState extends KeywordState { - final List<KeywordState> table; - final Keyword keyword; - - ArrayKeywordState(List<KeywordState> this.table, String syntax) - : keyword = (syntax == null) ? null : Keyword.keywords[syntax]; - - bool isLeaf() => false; - - KeywordState next(int c) => table[c - $a]; - - String toString() { - StringBuffer sb = new StringBuffer(); - sb.add("["); - if (keyword != null) { - sb.add("*"); - sb.add(keyword); - sb.add(" "); - } - List<KeywordState> foo = table; - for (int i = 0; i < foo.length; i++) { - if (foo[i] != null) { - sb.add("${new String.fromCharCodes([i + $a])}: ${foo[i]}; "); - } - } - sb.add("]"); - return sb.toString(); - } -} - -/** - * A state that has no outgoing transitions. - */ -class LeafKeywordState extends KeywordState { - final Keyword keyword; - - LeafKeywordState(String syntax) : keyword = Keyword.keywords[syntax]; - - bool isLeaf() => true; - - KeywordState next(int c) => null; - - String toString() => keyword.syntax; -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/listener.dart b/pkgs/markdown/test/lib/src/compiler/implementation/scanner/listener.dart deleted file mode 100644 index e535f62..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/listener.dart +++ /dev/null
@@ -1,2064 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of scanner; - -const bool VERBOSE = false; - -/** - * A parser event listener that does nothing except throw exceptions - * on parser errors. - */ -class Listener { - void beginArgumentDefinitionTest(Token token) { - } - - void endArgumentDefinitionTest(Token beginToken, Token endToken) { - } - - void beginArguments(Token token) { - } - - void endArguments(int count, Token beginToken, Token endToken) { - } - - void beginBlock(Token token) { - } - - void endBlock(int count, Token beginToken, Token endToken) { - } - - void beginCascade(Token token) { - } - - void endCascade() { - } - - void beginClassBody(Token token) { - } - - void endClassBody(int memberCount, Token beginToken, Token endToken) { - } - - void beginClassDeclaration(Token token) { - } - - void endClassDeclaration(int interfacesCount, Token beginToken, - Token extendsKeyword, Token implementsKeyword, - Token endToken) { - } - - void beginCombinators(Token token) { - } - - void endCombinators(int count) { - } - - void beginCompilationUnit(Token token) { - } - - void endCompilationUnit(int count, Token token) { - } - - void beginConstructorReference(Token start) { - } - - void endConstructorReference(Token start, Token periodBeforeName, - Token endToken) { - } - - void beginDoWhileStatement(Token token) { - } - - void endDoWhileStatement(Token doKeyword, Token whileKeyword, - Token endToken) { - } - - void beginExport(Token token) { - } - - void endExport(Token exportKeyword, Token semicolon) { - } - - void beginExpressionStatement(Token token) { - } - - void endExpressionStatement(Token token) { - } - - void beginDefaultClause(Token token) { - } - - void handleNoDefaultClause(Token token) { - } - - void endDefaultClause(Token defaultKeyword) { - } - - void beginFactoryMethod(Token token) { - } - - void endFactoryMethod(Token beginToken, Token endToken) { - } - - void beginFormalParameter(Token token) { - } - - void endFormalParameter(Token thisKeyword) { - } - - void handleNoFormalParameters(Token token) { - } - - void beginFormalParameters(Token token) { - } - - void endFormalParameters(int count, Token beginToken, Token endToken) { - } - - void endFields(int count, Token beginToken, Token endToken) { - } - - void beginForStatement(Token token) { - } - - void endForStatement(int updateExpressionCount, - Token beginToken, Token endToken) { - } - - void endForIn(Token beginToken, Token inKeyword, Token endToken) { - } - - void beginFunction(Token token) { - } - - void endFunction(Token getOrSet, Token endToken) { - } - - void beginFunctionDeclaration(Token token) { - } - - void endFunctionDeclaration(Token token) { - } - - void beginFunctionBody(Token token) { - } - - void endFunctionBody(int count, Token beginToken, Token endToken) { - } - - void handleNoFunctionBody(Token token) { - } - - void beginFunctionName(Token token) { - } - - void endFunctionName(Token token) { - } - - void beginFunctionTypeAlias(Token token) { - } - - void endFunctionTypeAlias(Token typedefKeyword, Token endToken) { - } - - void beginMixinApplication(Token token) { - } - - void endMixinApplication() { - } - - void beginNamedMixinApplication(Token token) { - } - - void endNamedMixinApplication(Token typedefKeyword, - Token implementsKeyword, - Token endToken) { - } - - void beginHide(Token hideKeyword) { - } - - void endHide(Token hideKeyword) { - } - - void beginIdentifierList(Token token) { - } - - void endIdentifierList(int count) { - } - - void beginTypeList(Token token) { - } - - void endTypeList(int count) { - } - - void beginIfStatement(Token token) { - } - - void endIfStatement(Token ifToken, Token elseToken) { - } - - void beginImport(Token importKeyword) { - } - - void endImport(Token importKeyword, Token asKeyword, Token semicolon) { - } - - void beginInitializedIdentifier(Token token) { - } - - void endInitializedIdentifier() { - } - - void beginInitializer(Token token) { - } - - void endInitializer(Token assignmentOperator) { - } - - void beginInitializers(Token token) { - } - - void endInitializers(int count, Token beginToken, Token endToken) { - } - - void handleNoInitializers() { - } - - void beginInterface(Token token) { - } - - void endInterface(int supertypeCount, Token interfaceKeyword, - Token extendsKeyword, Token endToken) { - } - - void handleLabel(Token token) { - } - - void beginLabeledStatement(Token token, int labelCount) { - } - - void endLabeledStatement(int labelCount) { - } - - void beginLibraryName(Token token) { - } - - void endLibraryName(Token libraryKeyword, Token semicolon) { - } - - void beginLiteralMapEntry(Token token) { - } - - void endLiteralMapEntry(Token colon, Token endToken) { - } - - void beginLiteralString(Token token) { - } - - void endLiteralString(int interpolationCount) { - } - - void handleStringJuxtaposition(int literalCount) { - } - - void beginMember(Token token) { - } - - void endMethod(Token getOrSet, Token beginToken, Token endToken) { - } - - void beginMetadata(Token token) { - } - - void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) { - } - - void beginOptionalFormalParameters(Token token) { - } - - void endOptionalFormalParameters(int count, - Token beginToken, Token endToken) { - } - - void beginPart(Token token) { - } - - void endPart(Token partKeyword, Token semicolon) { - } - - void beginPartOf(Token token) { - } - - void endPartOf(Token partKeyword, Token semicolon) { - } - - void beginRedirectingFactoryBody(Token token) { - } - - void endRedirectingFactoryBody(Token beginToken, Token endToken) { - } - - void beginReturnStatement(Token token) { - } - - void endReturnStatement(bool hasExpression, - Token beginToken, Token endToken) { - } - - void beginScriptTag(Token token) { - } - - void endScriptTag(bool hasPrefix, Token beginToken, Token endToken) { - } - - void beginSend(Token token) { - } - - void endSend(Token token) { - } - - void beginShow(Token showKeyword) { - } - - void endShow(Token showKeyword) { - } - - void beginSwitchStatement(Token token) { - } - - void endSwitchStatement(Token switchKeyword, Token endToken) { - } - - void beginSwitchBlock(Token token) { - } - - void endSwitchBlock(int caseCount, Token beginToken, Token endToken) { - } - - void beginThrowStatement(Token token) { - } - - void endThrowStatement(Token throwToken, Token endToken) { - } - - void endRethrowStatement(Token throwToken, Token endToken) { - } - - void endTopLevelDeclaration(Token token) { - } - - void beginTopLevelMember(Token token) { - } - - void endTopLevelFields(int count, Token beginToken, Token endToken) { - } - - void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) { - } - - void beginTryStatement(Token token) { - } - - void handleCaseMatch(Token caseKeyword, Token colon) { - } - - void handleCatchBlock(Token onKeyword, Token catchKeyword) { - } - - void handleFinallyBlock(Token finallyKeyword) { - } - - void endTryStatement(int catchCount, Token tryKeyword, Token finallyKeyword) { - } - - void endType(Token beginToken, Token endToken) { - } - - void beginTypeArguments(Token token) { - } - - void endTypeArguments(int count, Token beginToken, Token endToken) { - } - - void handleNoTypeArguments(Token token) { - } - - void beginTypeVariable(Token token) { - } - - void endTypeVariable(Token token) { - } - - void beginTypeVariables(Token token) { - } - - void endTypeVariables(int count, Token beginToken, Token endToken) { - } - - void beginUnamedFunction(Token token) { - } - - void endUnamedFunction(Token token) { - } - - void beginVariablesDeclaration(Token token) { - } - - void endVariablesDeclaration(int count, Token endToken) { - } - - void beginWhileStatement(Token token) { - } - - void endWhileStatement(Token whileKeyword, Token endToken) { - } - - void handleAsOperator(Token operathor, Token endToken) { - // TODO(ahe): Rename [operathor] to "operator" when VM bug is fixed. - } - - void handleAssignmentExpression(Token token) { - } - - void handleBinaryExpression(Token token) { - } - - void handleConditionalExpression(Token question, Token colon) { - } - - void handleConstExpression(Token token) { - } - - void handleFunctionTypedFormalParameter(Token token) { - } - - void handleIdentifier(Token token) { - } - - void handleIndexedExpression(Token openCurlyBracket, - Token closeCurlyBracket) { - } - - void handleIsOperator(Token operathor, Token not, Token endToken) { - // TODO(ahe): Rename [operathor] to "operator" when VM bug is fixed. - } - - void handleLiteralBool(Token token) { - } - - void handleBreakStatement(bool hasTarget, - Token breakKeyword, Token endToken) { - } - - void handleContinueStatement(bool hasTarget, - Token continueKeyword, Token endToken) { - } - - void handleEmptyStatement(Token token) { - } - - void handleAssertStatement(Token assertKeyword, Token semicolonToken) { - } - - /** Called with either the token containing a double literal, or - * an immediately preceding "unary plus" token. - */ - void handleLiteralDouble(Token token) { - } - - /** Called with either the token containing an integer literal, - * or an immediately preceding "unary plus" token. - */ - void handleLiteralInt(Token token) { - } - - void handleLiteralList(int count, Token beginToken, Token constKeyword, - Token endToken) { - } - - void handleLiteralMap(int count, Token beginToken, Token constKeyword, - Token endToken) { - } - - void handleLiteralNull(Token token) { - } - - void handleModifier(Token token) { - } - - void handleModifiers(int count) { - } - - void handleNamedArgument(Token colon) { - } - - void handleNewExpression(Token token) { - } - - void handleNoArguments(Token token) { - } - - void handleNoExpression(Token token) { - } - - void handleNoType(Token token) { - } - - void handleNoTypeVariables(Token token) { - } - - void handleOperatorName(Token operatorKeyword, Token token) { - } - - void handleParenthesizedExpression(BeginGroupToken token) { - } - - void handleQualified(Token period) { - } - - void handleStringPart(Token token) { - } - - void handleSuperExpression(Token token) { - } - - void handleSwitchCase(int labelCount, int expressionCount, - Token defaultKeyword, int statementCount, - Token firstToken, Token endToken) { - } - - void handleThisExpression(Token token) { - } - - void handleUnaryPostfixAssignmentExpression(Token token) { - } - - void handleUnaryPrefixExpression(Token token) { - } - - void handleUnaryPrefixAssignmentExpression(Token token) { - } - - void handleValuedFormalParameter(Token equals, Token token) { - } - - void handleVoidKeyword(Token token) { - } - - Token expected(String string, Token token) { - error("expected '$string', but got '${token.slowToString()}'", token); - return skipToEof(token); - } - - void expectedIdentifier(Token token) { - error("expected identifier, but got '${token.slowToString()}'", token); - } - - Token expectedType(Token token) { - error("expected a type, but got '${token.slowToString()}'", token); - return skipToEof(token); - } - - Token expectedExpression(Token token) { - error("expected an expression, but got '${token.slowToString()}'", token); - return skipToEof(token); - } - - Token unexpected(Token token) { - error("unexpected token '${token.slowToString()}'", token); - return skipToEof(token); - } - - Token expectedBlockToSkip(Token token) { - error("expected a block, but got '${token.slowToString()}'", token); - return skipToEof(token); - } - - Token expectedFunctionBody(Token token) { - error("expected a function body, but got '${token.slowToString()}'", token); - return skipToEof(token); - } - - Token expectedClassBody(Token token) { - error("expected a class body, but got '${token.slowToString()}'", token); - return skipToEof(token); - } - - Token expectedClassBodyToSkip(Token token) { - error("expected a class body, but got '${token.slowToString()}'", token); - return skipToEof(token); - } - - Link<Token> expectedDeclaration(Token token) { - error("expected a declaration, but got '${token.slowToString()}'", token); - return const Link<Token>(); - } - - Token unmatched(Token token) { - error("unmatched '${token.slowToString()}'", token); - return skipToEof(token); - } - - skipToEof(Token token) { - while (!identical(token.info, EOF_INFO)) { - token = token.next; - } - return token; - } - - void recoverableError(String message, {Token token, Node node}) { - if (token == null && node != null) { - token = node.getBeginToken(); - } - error(message, token); - } - - void error(String message, Token token) { - throw new ParserError("$message @ ${token.charOffset}"); - } -} - -class ParserError { - final String reason; - ParserError(this.reason); - toString() => reason; -} - -typedef int IdGenerator(); - -/** - * A parser event listener designed to work with [PartialParser]. It - * builds elements representing the top-level declarations found in - * the parsed compilation unit and records them in - * [compilationUnitElement]. - */ -class ElementListener extends Listener { - final IdGenerator idGenerator; - final DiagnosticListener listener; - final CompilationUnitElement compilationUnitElement; - final StringValidator stringValidator; - Link<StringQuoting> interpolationScope; - - Link<Node> nodes = const Link<Node>(); - - Link<MetadataAnnotation> metadata = const Link<MetadataAnnotation>(); - - ElementListener(DiagnosticListener listener, - this.compilationUnitElement, - this.idGenerator) - : this.listener = listener, - stringValidator = new StringValidator(listener), - interpolationScope = const Link<StringQuoting>(); - - void pushQuoting(StringQuoting quoting) { - interpolationScope = interpolationScope.prepend(quoting); - } - - StringQuoting popQuoting() { - StringQuoting result = interpolationScope.head; - interpolationScope = interpolationScope.tail; - return result; - } - - StringNode popLiteralString() { - StringNode node = popNode(); - // TODO(lrn): Handle interpolations in script tags. - if (node.isInterpolation) { - listener.cancel("String interpolation not supported in library tags", - node: node); - return null; - } - return node; - } - - bool allowLibraryTags() { - // Library tags are only allowed in the library file itself, not - // in sourced files. - LibraryElement library = compilationUnitElement.getLibrary(); - return !compilationUnitElement.hasMembers - && library.entryCompilationUnit == compilationUnitElement; - } - - void endLibraryName(Token libraryKeyword, Token semicolon) { - Expression name = popNode(); - addLibraryTag(new LibraryName(libraryKeyword, name, - popMetadata(compilationUnitElement))); - } - - void endImport(Token importKeyword, Token asKeyword, Token semicolon) { - NodeList combinators = popNode(); - Identifier prefix; - if (asKeyword != null) { - prefix = popNode(); - } - StringNode uri = popLiteralString(); - addLibraryTag(new Import(importKeyword, uri, prefix, combinators, - popMetadata(compilationUnitElement))); - } - - void endExport(Token exportKeyword, Token semicolon) { - NodeList combinators = popNode(); - StringNode uri = popNode(); - addLibraryTag(new Export(exportKeyword, uri, combinators, - popMetadata(compilationUnitElement))); - } - - void endCombinators(int count) { - if (0 == count) { - pushNode(null); - } else { - pushNode(makeNodeList(count, null, null, " ")); - } - } - - void endHide(Token hideKeyword) => pushCombinator(hideKeyword); - - void endShow(Token showKeyword) => pushCombinator(showKeyword); - - void pushCombinator(Token keywordToken) { - NodeList identifiers = popNode(); - pushNode(new Combinator(identifiers, keywordToken)); - } - - void endIdentifierList(int count) { - pushNode(makeNodeList(count, null, null, ",")); - } - - void endTypeList(int count) { - pushNode(makeNodeList(count, null, null, ",")); - } - - void endPart(Token partKeyword, Token semicolon) { - StringNode uri = popLiteralString(); - addLibraryTag(new Part(partKeyword, uri, - popMetadata(compilationUnitElement))); - } - - void endPartOf(Token partKeyword, Token semicolon) { - Expression name = popNode(); - addPartOfTag(new PartOf(partKeyword, name, - popMetadata(compilationUnitElement))); - } - - void addPartOfTag(PartOf tag) { - compilationUnitElement.setPartOf(tag, listener); - } - - void endScriptTag(bool hasPrefix, Token beginToken, Token endToken) { - LiteralString prefix = null; - Identifier argumentName = null; - if (hasPrefix) { - prefix = popLiteralString(); - argumentName = popNode(); - } - LiteralString firstArgument = popLiteralString(); - Identifier tag = popNode(); - ScriptTag scriptTag = new ScriptTag(tag, firstArgument, argumentName, - prefix, beginToken, endToken); - if (const SourceString('import') == tag.source || - const SourceString('source') == tag.source || - const SourceString('library') == tag.source) { - addScriptTag(scriptTag); - } else { - recoverableError('unknown tag: ${tag.source.slowToString()}', node: tag); - } - } - - void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) { - if (periodBeforeName != null) { - popNode(); // Discard name. - } - popNode(); // Discard node (Send or Identifier). - pushMetadata(new PartialMetadataAnnotation(beginToken, endToken)); - } - - void endTopLevelDeclaration(Token token) { - if (!metadata.isEmpty) { - recoverableError('Error: Metadata not supported here.', - token: metadata.head.beginToken); - metadata = const Link<MetadataAnnotation>(); - } - } - - void endClassDeclaration(int interfacesCount, Token beginToken, - Token extendsKeyword, Token implementsKeyword, - Token endToken) { - SourceString nativeTagInfo = native.checkForNativeClass(this); - NodeList interfaces = - makeNodeList(interfacesCount, implementsKeyword, null, ","); - Node supertype = popNode(); - NodeList typeParameters = popNode(); - Identifier name = popNode(); - int id = idGenerator(); - ClassElement element = new PartialClassElement( - name.source, beginToken, endToken, compilationUnitElement, id); - element.nativeTagInfo = nativeTagInfo; - pushElement(element); - rejectBuiltInIdentifier(name); - } - - void rejectBuiltInIdentifier(Identifier name) { - if (name.source is Keyword) { - Keyword keyword = name.source; - if (!keyword.isPseudo) { - recoverableError('illegal name ${keyword.syntax}', node: name); - } - } - } - - void endDefaultClause(Token defaultKeyword) { - NodeList typeParameters = popNode(); - Node name = popNode(); - pushNode(new TypeAnnotation(name, typeParameters)); - } - - void handleNoDefaultClause(Token token) { - pushNode(null); - } - - void endInterface(int supertypeCount, Token interfaceKeyword, - Token extendsKeyword, Token endToken) { - // TODO(ahe): Record the defaultClause. - Node defaultClause = popNode(); - NodeList supertypes = - makeNodeList(supertypeCount, extendsKeyword, null, ","); - NodeList typeParameters = popNode(); - Identifier name = popNode(); - int id = idGenerator(); - pushElement(new PartialClassElement( - name.source, interfaceKeyword, endToken, compilationUnitElement, id)); - rejectBuiltInIdentifier(name); - listener.onDeprecatedFeature(interfaceKeyword, 'interface declarations'); - } - - void endFunctionTypeAlias(Token typedefKeyword, Token endToken) { - NodeList typeVariables = popNode(); // TOOD(karlklose): do not throw away. - Identifier name = popNode(); - TypeAnnotation returnType = popNode(); - pushElement(new PartialTypedefElement(name.source, compilationUnitElement, - typedefKeyword)); - rejectBuiltInIdentifier(name); - } - - void endNamedMixinApplication(Token typedefKeyword, - Token implementsKeyword, - Token endToken) { - NodeList interfaces = (implementsKeyword != null) ? popNode() : null; - MixinApplication mixinApplication = popNode(); - Modifiers modifiers = popNode(); - NodeList typeParameters = popNode(); - Identifier name = popNode(); - NamedMixinApplication namedMixinApplication = new NamedMixinApplication( - name, typeParameters, modifiers, mixinApplication, interfaces, - typedefKeyword, endToken); - - int id = idGenerator(); - Element enclosing = compilationUnitElement; - pushElement(new MixinApplicationElementX(name.source, enclosing, id, - namedMixinApplication, - modifiers)); - rejectBuiltInIdentifier(name); - } - - void endMixinApplication() { - NodeList mixins = popNode(); - TypeAnnotation superclass = popNode(); - pushNode(new MixinApplication(superclass, mixins)); - } - - void handleVoidKeyword(Token token) { - pushNode(new TypeAnnotation(new Identifier(token), null)); - } - - void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) { - Identifier name = popNode(); - TypeAnnotation type = popNode(); - Modifiers modifiers = popNode(); - ElementKind kind; - if (getOrSet == null) { - kind = ElementKind.FUNCTION; - } else if (identical(getOrSet.stringValue, 'get')) { - kind = ElementKind.GETTER; - } else if (identical(getOrSet.stringValue, 'set')) { - kind = ElementKind.SETTER; - } - pushElement(new PartialFunctionElement(name.source, beginToken, getOrSet, - endToken, kind, - modifiers, compilationUnitElement)); - } - - void endTopLevelFields(int count, Token beginToken, Token endToken) { - void buildFieldElement(SourceString name, Element fields) { - pushElement(new VariableElementX(name, fields, ElementKind.FIELD, null)); - } - NodeList variables = makeNodeList(count, null, null, ","); - TypeAnnotation type = popNode(); - Modifiers modifiers = popNode(); - buildFieldElements(modifiers, variables, compilationUnitElement, - buildFieldElement, - beginToken, endToken); - } - - void buildFieldElements(Modifiers modifiers, - NodeList variables, - Element enclosingElement, - void buildFieldElement(SourceString name, - Element fields), - Token beginToken, Token endToken) { - Element fields = new PartialFieldListElement(beginToken, - endToken, - modifiers, - enclosingElement); - for (Link<Node> variableNodes = variables.nodes; - !variableNodes.isEmpty; - variableNodes = variableNodes.tail) { - Expression initializedIdentifier = variableNodes.head; - Identifier identifier = initializedIdentifier.asIdentifier(); - if (identifier == null) { - identifier = initializedIdentifier.asSendSet().selector.asIdentifier(); - } - SourceString name = identifier.source; - buildFieldElement(name, fields); - } - } - - void handleIdentifier(Token token) { - pushNode(new Identifier(token)); - } - - void handleQualified(Token period) { - Identifier last = popNode(); - Expression first = popNode(); - pushNode(new Send(first, last)); - } - - void handleNoType(Token token) { - pushNode(null); - } - - void endTypeVariable(Token token) { - TypeAnnotation bound = popNode(); - Identifier name = popNode(); - pushNode(new TypeVariable(name, bound)); - } - - void endTypeVariables(int count, Token beginToken, Token endToken) { - pushNode(makeNodeList(count, beginToken, endToken, ',')); - } - - void handleNoTypeVariables(token) { - pushNode(null); - } - - void endTypeArguments(int count, Token beginToken, Token endToken) { - pushNode(makeNodeList(count, beginToken, endToken, ',')); - } - - void handleNoTypeArguments(Token token) { - pushNode(null); - } - - void endType(Token beginToken, Token endToken) { - NodeList typeArguments = popNode(); - Expression typeName = popNode(); - pushNode(new TypeAnnotation(typeName, typeArguments)); - } - - void handleParenthesizedExpression(BeginGroupToken token) { - Expression expression = popNode(); - pushNode(new ParenthesizedExpression(expression, token)); - } - - void handleModifier(Token token) { - pushNode(new Identifier(token)); - } - - void handleModifiers(int count) { - if (count == 0) { - pushNode(Modifiers.EMPTY); - } else { - NodeList modifierNodes = makeNodeList(count, null, null, ' '); - pushNode(new Modifiers(modifierNodes)); - } - } - - Token expected(String string, Token token) { - listener.cancel("expected '$string', but got '${token.slowToString()}'", - token: token); - return skipToEof(token); - } - - void expectedIdentifier(Token token) { - listener.cancel("expected identifier, but got '${token.slowToString()}'", - token: token); - pushNode(null); - } - - Token expectedType(Token token) { - listener.cancel("expected a type, but got '${token.slowToString()}'", - token: token); - pushNode(null); - return skipToEof(token); - } - - Token expectedExpression(Token token) { - listener.cancel("expected an expression, but got '${token.slowToString()}'", - token: token); - pushNode(null); - return skipToEof(token); - } - - Token unexpected(Token token) { - String message = "unexpected token '${token.slowToString()}'"; - if (token.info == BAD_INPUT_INFO) { - message = token.stringValue; - } - listener.cancel(message, token: token); - return skipToEof(token); - } - - Token expectedBlockToSkip(Token token) { - if (identical(token.stringValue, 'native')) { - return native.handleNativeBlockToSkip(this, token); - } else { - return unexpected(token); - } - } - - Token expectedFunctionBody(Token token) { - String printString = token.slowToString(); - listener.cancel("expected a function body, but got '$printString'", - token: token); - return skipToEof(token); - } - - Token expectedClassBody(Token token) { - listener.cancel("expected a class body, but got '${token.slowToString()}'", - token: token); - return skipToEof(token); - } - - Token expectedClassBodyToSkip(Token token) { - if (identical(token.stringValue, 'native')) { - return native.handleNativeClassBodyToSkip(this, token); - } else { - return unexpected(token); - } - } - - Link<Token> expectedDeclaration(Token token) { - listener.cancel("expected a declaration, but got '${token.slowToString()}'", - token: token); - return const Link<Token>(); - } - - Token unmatched(Token token) { - listener.cancel("unmatched '${token.slowToString()}'", token: token); - return skipToEof(token); - } - - void recoverableError(String message, {Token token, Node node}) { - listener.cancel(message, token: token, node: node); - } - - void pushElement(Element element) { - popMetadata(element); - compilationUnitElement.addMember(element, listener); - } - - Link<MetadataAnnotation> popMetadata(Element element) { - var result = metadata; - for (Link link = metadata; !link.isEmpty; link = link.tail) { - element.addMetadata(link.head); - } - metadata = const Link<MetadataAnnotation>(); - return result; - } - - void pushMetadata(MetadataAnnotation annotation) { - metadata = metadata.prepend(annotation); - } - - // TODO(ahe): Remove this method. - void addScriptTag(ScriptTag tag) { - listener.onDeprecatedFeature(tag, '# tags'); - addLibraryTag(tag.toLibraryTag()); - } - - void addLibraryTag(LibraryTag tag) { - if (!allowLibraryTags()) { - recoverableError('library tags not allowed here', node: tag); - } - compilationUnitElement.getImplementationLibrary().addTag(tag, listener); - } - - void pushNode(Node node) { - nodes = nodes.prepend(node); - if (VERBOSE) log("push $nodes"); - } - - Node popNode() { - assert(!nodes.isEmpty); - Node node = nodes.head; - nodes = nodes.tail; - if (VERBOSE) log("pop $nodes"); - return node; - } - - Node peekNode() { - assert(!nodes.isEmpty); - Node node = nodes.head; - if (VERBOSE) log("peek $node"); - return node; - } - - void log(message) { - print(message); - } - - NodeList makeNodeList(int count, Token beginToken, Token endToken, - String delimiter) { - Link<Node> poppedNodes = const Link<Node>(); - for (; count > 0; --count) { - // This effectively reverses the order of nodes so they end up - // in correct (source) order. - poppedNodes = poppedNodes.prepend(popNode()); - } - SourceString sourceDelimiter = - (delimiter == null) ? null : new SourceString(delimiter); - return new NodeList(beginToken, poppedNodes, endToken, sourceDelimiter); - } - - void beginLiteralString(Token token) { - SourceString source = token.value; - StringQuoting quoting = StringValidator.quotingFromString(source); - pushQuoting(quoting); - // Just wrap the token for now. At the end of the interpolation, - // when we know how many there are, go back and validate the tokens. - pushNode(new LiteralString(token, null)); - } - - void handleStringPart(Token token) { - // Just push an unvalidated token now, and replace it when we know the - // end of the interpolation. - pushNode(new LiteralString(token, null)); - } - - void endLiteralString(int count) { - StringQuoting quoting = popQuoting(); - - Link<StringInterpolationPart> parts = - const Link<StringInterpolationPart>(); - // Parts of the string interpolation are popped in reverse order, - // starting with the last literal string part. - bool isLast = true; - for (int i = 0; i < count; i++) { - LiteralString string = popNode(); - DartString validation = - stringValidator.validateInterpolationPart(string.token, quoting, - isFirst: false, - isLast: isLast); - // Replace the unvalidated LiteralString with a new LiteralString - // object that has the validation result included. - string = new LiteralString(string.token, validation); - Expression expression = popNode(); - parts = parts.prepend(new StringInterpolationPart(expression, string)); - isLast = false; - } - - LiteralString string = popNode(); - DartString validation = - stringValidator.validateInterpolationPart(string.token, quoting, - isFirst: true, - isLast: isLast); - string = new LiteralString(string.token, validation); - if (isLast) { - pushNode(string); - } else { - NodeList partNodes = - new NodeList(null, parts, null, const SourceString("")); - pushNode(new StringInterpolation(string, partNodes)); - } - } - - void handleStringJuxtaposition(int stringCount) { - assert(stringCount != 0); - Expression accumulator = popNode(); - stringCount--; - while (stringCount > 0) { - Expression expression = popNode(); - accumulator = new StringJuxtaposition(expression, accumulator); - stringCount--; - } - pushNode(accumulator); - } -} - -class NodeListener extends ElementListener { - NodeListener(DiagnosticListener listener, CompilationUnitElement element) - : super(listener, element, null); - - void addLibraryTag(LibraryTag tag) { - pushNode(tag); - } - - void addPartOfTag(PartOf tag) { - pushNode(tag); - } - - void endArgumentDefinitionTest(Token beginToken, Token endToken) { - pushNode(new Send.prefix(popNode(), new Operator(beginToken))); - } - - void endClassDeclaration(int interfacesCount, Token beginToken, - Token extendsKeyword, Token implementsKeyword, - Token endToken) { - NodeList body = popNode(); - NodeList interfaces = - makeNodeList(interfacesCount, implementsKeyword, null, ","); - Node supertype = popNode(); - NodeList typeParameters = popNode(); - Identifier name = popNode(); - Modifiers modifiers = popNode(); - pushNode(new ClassNode(modifiers, name, typeParameters, supertype, - interfaces, null, beginToken, extendsKeyword, body, - endToken)); - } - - void endCompilationUnit(int count, Token token) { - pushNode(makeNodeList(count, null, null, '\n')); - } - - void endFunctionTypeAlias(Token typedefKeyword, Token endToken) { - NodeList formals = popNode(); - NodeList typeParameters = popNode(); - Identifier name = popNode(); - TypeAnnotation returnType = popNode(); - pushNode(new Typedef(returnType, name, typeParameters, formals, - typedefKeyword, endToken)); - } - - void endNamedMixinApplication(Token typedefKeyword, - Token implementsKeyword, - Token endToken) { - NodeList interfaces = (implementsKeyword != null) ? popNode() : null; - Node mixinApplication = popNode(); - Modifiers modifiers = popNode(); - NodeList typeParameters = popNode(); - Identifier name = popNode(); - pushNode(new NamedMixinApplication(name, typeParameters, - modifiers, mixinApplication, - interfaces, - typedefKeyword, endToken)); - } - - void endInterface(int supertypeCount, Token interfaceKeyword, - Token extendsKeyword, Token endToken) { - NodeList body = popNode(); - TypeAnnotation defaultClause = popNode(); - NodeList supertypes = makeNodeList(supertypeCount, extendsKeyword, - null, ','); - NodeList typeParameters = popNode(); - Identifier name = popNode(); - pushNode(new ClassNode(Modifiers.EMPTY, name, typeParameters, null, - supertypes, defaultClause, interfaceKeyword, null, - body, endToken)); - } - - void endClassBody(int memberCount, Token beginToken, Token endToken) { - pushNode(makeNodeList(memberCount, beginToken, endToken, null)); - } - - void endTopLevelFields(int count, Token beginToken, Token endToken) { - NodeList variables = makeNodeList(count, null, endToken, ","); - Modifiers modifiers = popNode(); - pushNode(new VariableDefinitions(null, modifiers, variables)); - } - - void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) { - Statement body = popNode(); - NodeList formalParameters = popNode(); - Identifier name = popNode(); - Modifiers modifiers = popNode(); - ElementKind kind; - if (getOrSet == null) { - kind = ElementKind.FUNCTION; - } else if (identical(getOrSet.stringValue, 'get')) { - kind = ElementKind.GETTER; - } else if (identical(getOrSet.stringValue, 'set')) { - kind = ElementKind.SETTER; - } - pushElement(new PartialFunctionElement(name.source, beginToken, getOrSet, - endToken, kind, - modifiers, compilationUnitElement)); - } - - void endFormalParameter(Token thisKeyword) { - Expression name = popNode(); - if (thisKeyword != null) { - Identifier thisIdentifier = new Identifier(thisKeyword); - if (name.asSend() == null) { - name = new Send(thisIdentifier, name); - } else { - name = name.asSend().copyWithReceiver(thisIdentifier); - } - } - TypeAnnotation type = popNode(); - Modifiers modifiers = popNode(); - pushNode( - new VariableDefinitions(type, modifiers, new NodeList.singleton(name))); - } - - void endFormalParameters(int count, Token beginToken, Token endToken) { - pushNode(makeNodeList(count, beginToken, endToken, ",")); - } - - void handleNoFormalParameters(Token token) { - pushNode(null); - } - - void endArguments(int count, Token beginToken, Token endToken) { - pushNode(makeNodeList(count, beginToken, endToken, ",")); - } - - void handleNoArguments(Token token) { - pushNode(null); - } - - void endConstructorReference(Token start, Token periodBeforeName, - Token endToken) { - Identifier name = null; - if (periodBeforeName != null) { - name = popNode(); - } - NodeList typeArguments = popNode(); - Node classReference = popNode(); - if (typeArguments != null) { - classReference = new TypeAnnotation(classReference, typeArguments); - } else { - Identifier identifier = classReference.asIdentifier(); - Send send = classReference.asSend(); - if (identifier != null) { - // TODO(ahe): Should be: - // classReference = new Send(null, identifier); - classReference = identifier; - } else if (send != null) { - classReference = send; - } else { - internalError(node: classReference); - } - } - Node constructor = classReference; - if (name != null) { - // Either typeName<args>.name or x.y.name. - constructor = new Send(classReference, name); - } - pushNode(constructor); - } - - void endRedirectingFactoryBody(Token beginToken, - Token endToken) { - pushNode(new Return(beginToken, endToken, popNode())); - } - - void endReturnStatement(bool hasExpression, - Token beginToken, Token endToken) { - Expression expression = hasExpression ? popNode() : null; - pushNode(new Return(beginToken, endToken, expression)); - } - - void endExpressionStatement(Token token) { - pushNode(new ExpressionStatement(popNode(), token)); - } - - void handleOnError(Token token, var errorInformation) { - listener.cancel("internal error: '${token.value}': ${errorInformation}", - token: token); - } - - Token expectedFunctionBody(Token token) { - if (identical(token.stringValue, 'native')) { - return native.handleNativeFunctionBody(this, token); - } else { - listener.cancel( - "expected a function body, but got '${token.slowToString()}'", - token: token); - return skipToEof(token); - } - } - - Token expectedClassBody(Token token) { - if (identical(token.stringValue, 'native')) { - return native.handleNativeClassBody(this, token); - } else { - listener.cancel( - "expected a class body, but got '${token.slowToString()}'", - token: token); - return skipToEof(token); - } - } - - void handleLiteralInt(Token token) { - pushNode(new LiteralInt(token, (t, e) => handleOnError(t, e))); - } - - void handleLiteralDouble(Token token) { - pushNode(new LiteralDouble(token, (t, e) => handleOnError(t, e))); - } - - void handleLiteralBool(Token token) { - pushNode(new LiteralBool(token, (t, e) => handleOnError(t, e))); - } - - void handleLiteralNull(Token token) { - pushNode(new LiteralNull(token)); - } - - void handleBinaryExpression(Token token) { - Node argument = popNode(); - Node receiver = popNode(); - String tokenString = token.stringValue; - if (identical(tokenString, '.') || identical(tokenString, '..')) { - Send argumentSend = argument.asSend(); - if (argumentSend == null) { - // TODO(ahe): The parser should diagnose this problem, not - // this listener. - listener.cancel('Syntax error: Expected an identifier.', - node: argument); - } - if (argumentSend.receiver != null) internalError(node: argument); - if (argument is SendSet) internalError(node: argument); - pushNode(argument.asSend().copyWithReceiver(receiver)); - } else { - NodeList arguments = new NodeList.singleton(argument); - pushNode(new Send(receiver, new Operator(token), arguments)); - } - if (identical(tokenString, '===') || identical(tokenString, '!==')) { - listener.onDeprecatedFeature(token, tokenString); - } - } - - void beginCascade(Token token) { - pushNode(new CascadeReceiver(popNode(), token)); - } - - void endCascade() { - pushNode(new Cascade(popNode())); - } - - void handleAsOperator(Token operathor, Token endToken) { - TypeAnnotation type = popNode(); - Expression expression = popNode(); - NodeList arguments = new NodeList.singleton(type); - pushNode(new Send(expression, new Operator(operathor), arguments)); - } - - void handleAssignmentExpression(Token token) { - Node arg = popNode(); - Node node = popNode(); - Send send = node.asSend(); - if (send == null || !(send.isPropertyAccess || send.isIndex)) { - reportNotAssignable(node); - } - if (send.asSendSet() != null) internalError(node: send); - NodeList arguments; - if (send.isIndex) { - Link<Node> link = const Link<Node>().prepend(arg); - link = link.prepend(send.arguments.head); - arguments = new NodeList(null, link); - } else { - arguments = new NodeList.singleton(arg); - } - Operator op = new Operator(token); - pushNode(new SendSet(send.receiver, send.selector, op, arguments)); - } - - void reportNotAssignable(Node node) { - // TODO(ahe): The parser should diagnose this problem, not this - // listener. - listener.cancel('Syntax error: Not assignable.', node: node); - } - - void handleConditionalExpression(Token question, Token colon) { - Node elseExpression = popNode(); - Node thenExpression = popNode(); - Node condition = popNode(); - pushNode(new Conditional( - condition, thenExpression, elseExpression, question, colon)); - } - - void endSend(Token token) { - NodeList arguments = popNode(); - Node selector = popNode(); - // TODO(ahe): Handle receiver. - pushNode(new Send(null, selector, arguments)); - } - - void endFunctionBody(int count, Token beginToken, Token endToken) { - if (count == 0 && beginToken == null) { - pushNode(new EmptyStatement(endToken)); - } else { - pushNode(new Block(makeNodeList(count, beginToken, endToken, null))); - } - } - - void handleNoFunctionBody(Token token) { - pushNode(null); - } - - void endFunction(Token getOrSet, Token endToken) { - Statement body = popNode(); - NodeList initializers = popNode(); - NodeList formals = popNode(); - // The name can be an identifier or a send in case of named constructors. - Expression name = popNode(); - TypeAnnotation type = popNode(); - Modifiers modifiers = popNode(); - pushNode(new FunctionExpression(name, formals, body, type, - modifiers, initializers, getOrSet)); - } - - void endFunctionDeclaration(Token endToken) { - pushNode(new FunctionDeclaration(popNode())); - } - - void endVariablesDeclaration(int count, Token endToken) { - // TODO(ahe): Pick one name for this concept, either - // VariablesDeclaration or VariableDefinitions. - NodeList variables = makeNodeList(count, null, endToken, ","); - TypeAnnotation type = popNode(); - Modifiers modifiers = popNode(); - pushNode(new VariableDefinitions(type, modifiers, variables)); - } - - void endInitializer(Token assignmentOperator) { - Expression initializer = popNode(); - NodeList arguments = new NodeList.singleton(initializer); - Expression name = popNode(); - Operator op = new Operator(assignmentOperator); - pushNode(new SendSet(null, name, op, arguments)); - } - - void endIfStatement(Token ifToken, Token elseToken) { - Statement elsePart = (elseToken == null) ? null : popNode(); - Statement thenPart = popNode(); - ParenthesizedExpression condition = popNode(); - pushNode(new If(condition, thenPart, elsePart, ifToken, elseToken)); - } - - void endForStatement(int updateExpressionCount, - Token beginToken, Token endToken) { - Statement body = popNode(); - NodeList updates = makeNodeList(updateExpressionCount, null, null, ','); - Statement condition = popNode(); - Node initializer = popNode(); - pushNode(new For(initializer, condition, updates, body, beginToken)); - } - - void handleNoExpression(Token token) { - pushNode(null); - } - - void endDoWhileStatement(Token doKeyword, Token whileKeyword, - Token endToken) { - Expression condition = popNode(); - Statement body = popNode(); - pushNode(new DoWhile(body, condition, doKeyword, whileKeyword, endToken)); - } - - void endWhileStatement(Token whileKeyword, Token endToken) { - Statement body = popNode(); - Expression condition = popNode(); - pushNode(new While(condition, body, whileKeyword)); - } - - void endBlock(int count, Token beginToken, Token endToken) { - pushNode(new Block(makeNodeList(count, beginToken, endToken, null))); - } - - void endThrowStatement(Token throwToken, Token endToken) { - Expression expression = popNode(); - pushNode(new Throw(expression, throwToken, endToken)); - } - - void endRethrowStatement(Token throwToken, Token endToken) { - pushNode(new Throw(null, throwToken, endToken)); - } - - void handleUnaryPrefixExpression(Token token) { - pushNode(new Send.prefix(popNode(), new Operator(token))); - } - - void handleSuperExpression(Token token) { - pushNode(new Identifier(token)); - } - - void handleThisExpression(Token token) { - pushNode(new Identifier(token)); - } - - void handleUnaryAssignmentExpression(Token token, bool isPrefix) { - Node node = popNode(); - Send send = node.asSend(); - if (send == null) { - reportNotAssignable(node); - } - if (!(send.isPropertyAccess || send.isIndex)) { - reportNotAssignable(node); - } - if (send.asSendSet() != null) internalError(node: send); - Node argument = null; - if (send.isIndex) argument = send.arguments.head; - Operator op = new Operator(token); - - if (isPrefix) { - pushNode(new SendSet.prefix(send.receiver, send.selector, op, argument)); - } else { - pushNode(new SendSet.postfix(send.receiver, send.selector, op, argument)); - } - } - - void handleUnaryPostfixAssignmentExpression(Token token) { - handleUnaryAssignmentExpression(token, false); - } - - void handleUnaryPrefixAssignmentExpression(Token token) { - handleUnaryAssignmentExpression(token, true); - } - - void endInitializers(int count, Token beginToken, Token endToken) { - pushNode(makeNodeList(count, beginToken, null, ',')); - } - - void handleNoInitializers() { - pushNode(null); - } - - void endFields(int count, Token beginToken, Token endToken) { - NodeList variables = makeNodeList(count, null, endToken, ","); - TypeAnnotation type = popNode(); - Modifiers modifiers = popNode(); - pushNode(new VariableDefinitions(type, modifiers, variables)); - } - - void endMethod(Token getOrSet, Token beginToken, Token endToken) { - Statement body = popNode(); - NodeList initializers = popNode(); - NodeList formalParameters = popNode(); - Expression name = popNode(); - TypeAnnotation returnType = popNode(); - Modifiers modifiers = popNode(); - pushNode(new FunctionExpression(name, formalParameters, body, returnType, - modifiers, initializers, getOrSet)); - } - - void handleLiteralMap(int count, Token beginToken, Token constKeyword, - Token endToken) { - NodeList entries = makeNodeList(count, beginToken, endToken, ','); - NodeList typeArguments = popNode(); - pushNode(new LiteralMap(typeArguments, entries, constKeyword)); - } - - void endLiteralMapEntry(Token colon, Token endToken) { - Expression value = popNode(); - Expression key = popNode(); - if (key.asStringNode() == null) { - recoverableError('expected a string', node: key); - } - pushNode(new LiteralMapEntry(key, colon, value)); - } - - void handleLiteralList(int count, Token beginToken, Token constKeyword, - Token endToken) { - NodeList elements = makeNodeList(count, beginToken, endToken, ','); - pushNode(new LiteralList(popNode(), elements, constKeyword)); - } - - void handleIndexedExpression(Token openSquareBracket, - Token closeSquareBracket) { - NodeList arguments = - makeNodeList(1, openSquareBracket, closeSquareBracket, null); - Node receiver = popNode(); - Token token = - new StringToken(INDEX_INFO, '[]', openSquareBracket.charOffset); - Node selector = new Operator(token); - pushNode(new Send(receiver, selector, arguments)); - } - - void handleNewExpression(Token token) { - NodeList arguments = popNode(); - Node name = popNode(); - pushNode(new NewExpression(token, new Send(null, name, arguments))); - } - - void handleConstExpression(Token token) { - // [token] carries the 'const' information. - handleNewExpression(token); - } - - void handleOperatorName(Token operatorKeyword, Token token) { - Operator op = new Operator(token); - pushNode(new Send(new Identifier(operatorKeyword), op, null)); - } - - void handleNamedArgument(Token colon) { - Expression expression = popNode(); - Identifier name = popNode(); - pushNode(new NamedArgument(name, colon, expression)); - } - - void endOptionalFormalParameters(int count, - Token beginToken, Token endToken) { - pushNode(makeNodeList(count, beginToken, endToken, ',')); - } - - void handleFunctionTypedFormalParameter(Token endToken) { - NodeList formals = popNode(); - Identifier name = popNode(); - TypeAnnotation returnType = popNode(); - pushNode(null); // Signal "no type" to endFormalParameter. - pushNode(new FunctionExpression(name, formals, null, returnType, - Modifiers.EMPTY, null, null)); - } - - void handleValuedFormalParameter(Token equals, Token token) { - Expression defaultValue = popNode(); - Expression parameterName = popNode(); - pushNode(new SendSet(null, parameterName, new Operator(equals), - new NodeList.singleton(defaultValue))); - } - - void endTryStatement(int catchCount, Token tryKeyword, Token finallyKeyword) { - Block finallyBlock = null; - if (finallyKeyword != null) { - finallyBlock = popNode(); - } - NodeList catchBlocks = makeNodeList(catchCount, null, null, null); - Block tryBlock = popNode(); - pushNode(new TryStatement(tryBlock, catchBlocks, finallyBlock, - tryKeyword, finallyKeyword)); - } - - void handleCaseMatch(Token caseKeyword, Token colon) { - pushNode(new CaseMatch(caseKeyword, popNode(), colon)); - } - - void handleCatchBlock(Token onKeyword, Token catchKeyword) { - Block block = popNode(); - NodeList formals = catchKeyword != null? popNode(): null; - TypeAnnotation type = onKeyword != null ? popNode() : null; - pushNode(new CatchBlock(type, formals, block, onKeyword, catchKeyword)); - } - - void endSwitchStatement(Token switchKeyword, Token endToken) { - NodeList cases = popNode(); - ParenthesizedExpression expression = popNode(); - pushNode(new SwitchStatement(expression, cases, switchKeyword)); - } - - void endSwitchBlock(int caseCount, Token beginToken, Token endToken) { - Link<Node> caseNodes = const Link<Node>(); - while (caseCount > 0) { - SwitchCase switchCase = popNode(); - caseNodes = caseNodes.prepend(switchCase); - caseCount--; - } - pushNode(new NodeList(beginToken, caseNodes, endToken, null)); - } - - void handleSwitchCase(int labelCount, int caseCount, - Token defaultKeyword, int statementCount, - Token firstToken, Token endToken) { - NodeList statements = makeNodeList(statementCount, null, null, null); - NodeList labelsAndCases = - makeNodeList(labelCount + caseCount, null, null, null); - pushNode(new SwitchCase(labelsAndCases, defaultKeyword, statements, - firstToken)); - } - - void handleBreakStatement(bool hasTarget, - Token breakKeyword, Token endToken) { - Identifier target = null; - if (hasTarget) { - target = popNode(); - } - pushNode(new BreakStatement(target, breakKeyword, endToken)); - } - - void handleContinueStatement(bool hasTarget, - Token continueKeyword, Token endToken) { - Identifier target = null; - if (hasTarget) { - target = popNode(); - } - pushNode(new ContinueStatement(target, continueKeyword, endToken)); - } - - void handleEmptyStatement(Token token) { - pushNode(new EmptyStatement(token)); - } - - void endFactoryMethod(Token beginToken, Token endToken) { - Statement body = popNode(); - NodeList formals = popNode(); - Node name = popNode(); - - // TODO(ahe): Move this parsing to the parser. - int modifierCount = 0; - Token modifier = beginToken; - if (modifier.stringValue == "external") { - handleModifier(modifier); - modifierCount++; - modifier = modifier.next; - } - if (modifier.stringValue == "const") { - handleModifier(modifier); - modifierCount++; - modifier = modifier.next; - } - assert(modifier.stringValue == "factory"); - handleModifier(modifier); - modifierCount++; - handleModifiers(modifierCount); - Modifiers modifiers = popNode(); - - pushNode(new FunctionExpression(name, formals, body, null, - modifiers, null, null)); - } - - void endForIn(Token beginToken, Token inKeyword, Token endToken) { - Statement body = popNode(); - Expression expression = popNode(); - Node declaredIdentifier = popNode(); - pushNode(new ForIn(declaredIdentifier, expression, body, - beginToken, inKeyword)); - } - - void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) { - NodeList arguments = popNode(); - if (arguments == null) { - // This is a constant expression. - Identifier name; - if (periodBeforeName != null) { - name = popNode(); - } - NodeList typeArguments = popNode(); - Node receiver = popNode(); - if (typeArguments != null) { - receiver = new TypeAnnotation(receiver, typeArguments); - recoverableError('Error: type arguments are not allowed here', - node: typeArguments); - } else { - Identifier identifier = receiver.asIdentifier(); - Send send = receiver.asSend(); - if (identifier != null) { - receiver = new Send(null, identifier); - } else if (send == null) { - internalError(node: receiver); - } - } - Send send = receiver; - if (name != null) { - send = new Send(receiver, name); - } - pushNode(send); - } else { - // This is a const constructor call. - endConstructorReference(beginToken, periodBeforeName, endToken); - Node constructor = popNode(); - pushNode(new NewExpression(beginToken, - new Send(null, constructor, arguments))); - } - } - - void handleAssertStatement(Token assertKeyword, Token semicolonToken) { - NodeList arguments = popNode(); - Node selector = new Identifier(assertKeyword); - Node send = new Send(null, selector, arguments); - pushNode(new ExpressionStatement(send, semicolonToken)); - } - - void endUnamedFunction(Token token) { - Statement body = popNode(); - NodeList formals = popNode(); - pushNode(new FunctionExpression(null, formals, body, null, - Modifiers.EMPTY, null, null)); - } - - void handleIsOperator(Token operathor, Token not, Token endToken) { - TypeAnnotation type = popNode(); - Expression expression = popNode(); - Node argument; - if (not != null) { - argument = new Send.prefix(type, new Operator(not)); - } else { - argument = type; - } - - NodeList arguments = new NodeList.singleton(argument); - pushNode(new Send(expression, new Operator(operathor), arguments)); - } - - void handleLabel(Token colon) { - Identifier name = popNode(); - pushNode(new Label(name, colon)); - } - - void endLabeledStatement(int labelCount) { - Statement statement = popNode(); - NodeList labels = makeNodeList(labelCount, null, null, null); - pushNode(new LabeledStatement(labels, statement)); - } - - void log(message) { - listener.log(message); - } - - void internalError({Token token, Node node}) { - // TODO(ahe): This should call listener.internalError. - Spannable spannable = (token == null) ? node : token; - throw new SpannableAssertionFailure(spannable, 'internal error in parser'); - } -} - -class PartialFunctionElement extends FunctionElementX { - final Token beginToken; - final Token getOrSet; - final Token endToken; - - PartialFunctionElement(SourceString name, - Token this.beginToken, - Token this.getOrSet, - Token this.endToken, - ElementKind kind, - Modifiers modifiers, - Element enclosing) - : super(name, kind, modifiers, enclosing); - - FunctionExpression parseNode(DiagnosticListener listener) { - if (cachedNode != null) return cachedNode; - parseFunction(Parser p) { - if (isMember() && modifiers.isFactory()) { - p.parseFactoryMethod(beginToken); - } else { - p.parseFunction(beginToken, getOrSet); - } - } - cachedNode = parse(listener, getCompilationUnit(), parseFunction); - return cachedNode; - } - - Token position() { - return findMyName(beginToken); - } - - PartialFunctionElement cloneTo(Element enclosing, - DiagnosticListener listener) { - if (patch != null) { - listener.cancel("Cloning a patched function.", element: this); - } - PartialFunctionElement result = new PartialFunctionElement( - name, beginToken, getOrSet, endToken, kind, modifiers, enclosing); - return result; - } -} - -class PartialFieldListElement extends VariableListElementX { - final Token beginToken; - final Token endToken; - - PartialFieldListElement(Token this.beginToken, - Token this.endToken, - Modifiers modifiers, - Element enclosing) - : super(ElementKind.VARIABLE_LIST, modifiers, enclosing); - - VariableDefinitions parseNode(DiagnosticListener listener) { - if (cachedNode != null) return cachedNode; - cachedNode = parse(listener, - getCompilationUnit(), - (p) => p.parseVariablesDeclaration(beginToken)); - if (!cachedNode.modifiers.isVar() && - !cachedNode.modifiers.isFinal() && - !cachedNode.modifiers.isConst() && - cachedNode.type == null) { - listener.cancel('A field declaration must start with var, final, ' - 'const, or a type annotation.', - node: cachedNode); - } - return cachedNode; - } - - Token position() => beginToken; // findMyName doesn't work. I'm nameless. - - PartialFieldListElement cloneTo(Element enclosing, - DiagnosticListener listener) { - PartialFieldListElement result = new PartialFieldListElement( - beginToken, endToken, modifiers, enclosing); - return result; - } -} - -class PartialTypedefElement extends TypedefElementX { - final Token token; - - PartialTypedefElement(SourceString name, Element enclosing, this.token) - : super(name, enclosing); - - Node parseNode(DiagnosticListener listener) { - if (cachedNode != null) return cachedNode; - cachedNode = parse(listener, - getCompilationUnit(), - (p) => p.parseTopLevelDeclaration(token)); - return cachedNode; - } - - position() => findMyName(token); - - PartialTypedefElement cloneTo(Element enclosing, - DiagnosticListener listener) { - PartialTypedefElement result = - new PartialTypedefElement(name, enclosing, token); - return result; - } -} - -/// A [MetadataAnnotation] which is constructed on demand. -class PartialMetadataAnnotation extends MetadataAnnotationX { - final Token beginToken; - final Token tokenAfterEndToken; - Expression cachedNode; - Constant value; - - PartialMetadataAnnotation(this.beginToken, this.tokenAfterEndToken); - - Token get endToken { - Token token = beginToken; - while (token.kind != EOF_TOKEN) { - if (identical(token.next, tokenAfterEndToken)) return token; - token = token.next; - } - } - - Node parseNode(DiagnosticListener listener) { - if (cachedNode != null) return cachedNode; - cachedNode = parse(listener, - annotatedElement.getCompilationUnit(), - (p) => p.parseMetadata(beginToken)); - return cachedNode; - } -} - -Node parse(DiagnosticListener diagnosticListener, - CompilationUnitElement element, - doParse(Parser parser)) { - NodeListener listener = new NodeListener(diagnosticListener, element); - doParse(new Parser(listener)); - Node node = listener.popNode(); - assert(listener.nodes.isEmpty); - return node; -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/parser.dart b/pkgs/markdown/test/lib/src/compiler/implementation/scanner/parser.dart deleted file mode 100644 index 5a85e00..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/parser.dart +++ /dev/null
@@ -1,2231 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of scanner; - -/** - * An event generating parser of Dart programs. This parser expects - * all tokens in a linked list (aka a token stream). - * - * The class [Scanner] is used to generate a token stream. See the - * file scanner.dart. - * - * Subclasses of the class [Listener] are used to listen to events. - * - * Most methods of this class belong in one of two major categories: - * parse metods and peek methods. Parse methods all have the prefix - * parse, and peek methods all have the prefix peek. - * - * Parse methods generate events (by calling methods on [listener]) - * and return the next token to parse. Peek methods do not generate - * events (except for errors) and may return null. - * - * Parse methods are generally named parseGrammarProductionSuffix. The - * suffix can be one of "opt", or "star". "opt" means zero or one - * matches, "star" means zero or more matches. For example, - * [parseMetadataStar] corresponds to this grammar snippet: [: - * metadata* :], and [parseTypeOpt] corresponds to: [: type? :]. - */ -class Parser { - final Listener listener; - bool mayParseFunctionExpressions = true; - - Parser(this.listener); - - Token parseUnit(Token token) { - listener.beginCompilationUnit(token); - int count = 0; - while (!identical(token.kind, EOF_TOKEN)) { - token = parseTopLevelDeclaration(token); - listener.endTopLevelDeclaration(token); - count++; - } - listener.endCompilationUnit(count, token); - return token; - } - - Token parseTopLevelDeclaration(Token token) { - token = parseMetadataStar(token); - final String value = token.stringValue; - if (identical(value, 'interface')) { - return parseInterface(token); - } else if ((identical(value, 'abstract')) || (identical(value, 'class'))) { - return parseClass(token); - } else if (identical(value, 'typedef')) { - return parseTypedef(token); - } else if (identical(value, '#')) { - return parseScriptTags(token); - } else if (identical(value, 'library')) { - return parseLibraryName(token); - } else if (identical(value, 'import')) { - return parseImport(token); - } else if (identical(value, 'export')) { - return parseExport(token); - } else if (identical(value, 'part')) { - return parsePartOrPartOf(token); - } else { - return parseTopLevelMember(token); - } - } - - /// library qualified ';' - Token parseLibraryName(Token token) { - Token libraryKeyword = token; - listener.beginLibraryName(libraryKeyword); - assert(optional('library', token)); - token = parseQualified(token.next); - Token semicolon = token; - token = expect(';', token); - listener.endLibraryName(libraryKeyword, semicolon); - return token; - } - - /// import uri (as identifier)? combinator* ';' - Token parseImport(Token token) { - Token importKeyword = token; - listener.beginImport(importKeyword); - assert(optional('import', token)); - token = parseLiteralStringOrRecoverExpression(token.next); - Token asKeyword; - if (optional('as', token)) { - asKeyword = token; - token = parseIdentifier(token.next); - } - token = parseCombinators(token); - Token semicolon = token; - token = expect(';', token); - listener.endImport(importKeyword, asKeyword, semicolon); - return token; - } - - /// export uri combinator* ';' - Token parseExport(Token token) { - Token exportKeyword = token; - listener.beginExport(exportKeyword); - assert(optional('export', token)); - token = parseLiteralStringOrRecoverExpression(token.next); - token = parseCombinators(token); - Token semicolon = token; - token = expect(';', token); - listener.endExport(exportKeyword, semicolon); - return token; - } - - Token parseCombinators(Token token) { - listener.beginCombinators(token); - int count = 0; - while (true) { - String value = token.stringValue; - if (identical('hide', value)) { - token = parseHide(token); - } else if (identical('show', value)) { - token = parseShow(token); - } else { - listener.endCombinators(count); - return token; - } - count++; - } - } - - /// hide identifierList - Token parseHide(Token token) { - Token hideKeyword = token; - listener.beginHide(hideKeyword); - assert(optional('hide', token)); - token = parseIdentifierList(token.next); - listener.endHide(hideKeyword); - return token; - } - - /// show identifierList - Token parseShow(Token token) { - Token showKeyword = token; - listener.beginShow(showKeyword); - assert(optional('show', token)); - token = parseIdentifierList(token.next); - listener.endShow(showKeyword); - return token; - } - - /// identifier (, identifier)* - Token parseIdentifierList(Token token) { - listener.beginIdentifierList(token); - token = parseIdentifier(token); - int count = 1; - while (optional(',', token)) { - token = parseIdentifier(token.next); - count++; - } - listener.endIdentifierList(count); - return token; - } - - /// type (, type)* - Token parseTypeList(Token token) { - listener.beginTypeList(token); - token = parseType(token); - int count = 1; - while (optional(',', token)) { - token = parseType(token.next); - count++; - } - listener.endTypeList(count); - return token; - } - - Token parsePartOrPartOf(Token token) { - assert(optional('part', token)); - if (optional('of', token.next)) { - return parsePartOf(token); - } else { - return parsePart(token); - } - } - - Token parsePart(Token token) { - Token partKeyword = token; - listener.beginPart(token); - assert(optional('part', token)); - token = parseLiteralStringOrRecoverExpression(token.next); - Token semicolon = token; - token = expect(';', token); - listener.endPart(partKeyword, semicolon); - return token; - } - - Token parsePartOf(Token token) { - listener.beginPartOf(token); - assert(optional('part', token)); - assert(optional('of', token.next)); - Token partKeyword = token; - token = parseQualified(token.next.next); - Token semicolon = token; - token = expect(';', token); - listener.endPartOf(partKeyword, semicolon); - return token; - } - - Token parseMetadataStar(Token token) { - while (optional('@', token)) { - token = parseMetadata(token); - } - return token; - } - - /** - * Parse - * [: '@' qualified (‘.’ identifier)? (arguments)? :] - */ - Token parseMetadata(Token token) { - listener.beginMetadata(token); - Token atToken = token; - assert(optional('@', token)); - token = parseIdentifier(token.next); - token = parseQualifiedRestOpt(token); - token = parseTypeArgumentsOpt(token); - Token period = null; - if (optional('.', token)) { - period = token; - token = parseIdentifier(token.next); - } - token = parseArgumentsOpt(token); - listener.endMetadata(atToken, period, token); - return token; - } - - Token parseInterface(Token token) { - Token interfaceKeyword = token; - listener.beginInterface(token); - token = parseIdentifier(token.next); - token = parseTypeVariablesOpt(token); - int supertypeCount = 0; - Token extendsKeyword = null; - if (optional('extends', token)) { - extendsKeyword = token; - do { - token = parseType(token.next); - ++supertypeCount; - } while (optional(',', token)); - } - token = parseDefaultClauseOpt(token); - token = parseInterfaceBody(token); - listener.endInterface(supertypeCount, interfaceKeyword, - extendsKeyword, token); - return token.next; - } - - Token parseInterfaceBody(Token token) { - return parseClassBody(token); - } - - Token parseTypedef(Token token) { - Token typedefKeyword = token; - if (optional('=', peekAfterType(token.next))) { - listener.beginNamedMixinApplication(token); - token = parseIdentifier(token.next); - token = parseTypeVariablesOpt(token); - token = expect('=', token); - token = parseModifiers(token); - token = parseMixinApplication(token); - Token implementsKeyword = null; - if (optional('implements', token)) { - implementsKeyword = token; - token = parseTypeList(token.next); - } - listener.endNamedMixinApplication( - typedefKeyword, implementsKeyword, token); - } else { - listener.beginFunctionTypeAlias(token); - token = parseReturnTypeOpt(token.next); - token = parseIdentifier(token); - token = parseTypeVariablesOpt(token); - token = parseFormalParameters(token); - listener.endFunctionTypeAlias(typedefKeyword, token); - } - return expect(';', token); - } - - Token parseMixinApplication(Token token) { - listener.beginMixinApplication(token); - token = parseType(token); - token = expect('with', token); - token = parseTypeList(token); - listener.endMixinApplication(); - return token; - } - - Token parseReturnTypeOpt(Token token) { - if (identical(token.stringValue, 'void')) { - listener.handleVoidKeyword(token); - return token.next; - } else { - return parseTypeOpt(token); - } - } - - Token parseFormalParametersOpt(Token token) { - if (optional('(', token)) { - return parseFormalParameters(token); - } else { - listener.handleNoFormalParameters(token); - return token; - } - } - - Token parseFormalParameters(Token token) { - Token begin = token; - listener.beginFormalParameters(begin); - expect('(', token); - int parameterCount = 0; - if (optional(')', token.next)) { - listener.endFormalParameters(parameterCount, begin, token.next); - return token.next.next; - } - do { - ++parameterCount; - token = token.next; - String value = token.stringValue; - if (identical(value, '[')) { - token = parseOptionalFormalParameters(token, false); - break; - } else if (identical(value, '{')) { - token = parseOptionalFormalParameters(token, true); - break; - } - token = parseFormalParameter(token); - } while (optional(',', token)); - listener.endFormalParameters(parameterCount, begin, token); - return expect(')', token); - } - - Token parseFormalParameter(Token token) { - listener.beginFormalParameter(token); - token = parseModifiers(token); - // TODO(ahe): Validate that there are formal parameters if void. - token = parseReturnTypeOpt(token); - Token thisKeyword = null; - if (optional('this', token)) { - thisKeyword = token; - // TODO(ahe): Validate field initializers are only used in - // constructors, and not for function-typed arguments. - token = expect('.', token.next); - } - token = parseIdentifier(token); - if (optional('(', token)) { - token = parseFormalParameters(token); - listener.handleFunctionTypedFormalParameter(token); - } - String value = token.stringValue; - if ((identical('=', value)) || (identical(':', value))) { - // TODO(ahe): Validate that these are only used for optional parameters. - Token equal = token; - token = parseExpression(token.next); - listener.handleValuedFormalParameter(equal, token); - } - listener.endFormalParameter(thisKeyword); - return token; - } - - Token parseOptionalFormalParameters(Token token, bool isNamed) { - Token begin = token; - listener.beginOptionalFormalParameters(begin); - assert((isNamed && optional('{', token)) || optional('[', token)); - int parameterCount = 0; - do { - token = token.next; - token = parseFormalParameter(token); - ++parameterCount; - } while (optional(',', token)); - listener.endOptionalFormalParameters(parameterCount, begin, token); - if (isNamed) { - return expect('}', token); - } else { - return expect(']', token); - } - } - - Token parseTypeOpt(Token token) { - String value = token.stringValue; - if (!identical(value, 'this')) { - Token peek = peekAfterExpectedType(token); - if (peek.isIdentifier() || optional('this', peek)) { - return parseType(token); - } - } - listener.handleNoType(token); - return token; - } - - bool isValidTypeReference(Token token) { - final kind = token.kind; - if (identical(kind, IDENTIFIER_TOKEN)) return true; - if (identical(kind, KEYWORD_TOKEN)) { - Keyword keyword = token.value; - String value = keyword.stringValue; - // TODO(aprelev@gmail.com): Remove deprecated Dynamic keyword support. - return keyword.isPseudo - || (identical(value, 'dynamic')) - || (identical(value, 'Dynamic')) - || (identical(value, 'void')); - } - return false; - } - - Token parseDefaultClauseOpt(Token token) { - if (isDefaultKeyword(token)) { - // TODO(ahe): Remove support for 'factory' in this position. - Token defaultKeyword = token; - listener.beginDefaultClause(defaultKeyword); - token = parseIdentifier(token.next); - token = parseQualifiedRestOpt(token); - token = parseTypeVariablesOpt(token); - listener.endDefaultClause(defaultKeyword); - } else { - listener.handleNoDefaultClause(token); - } - return token; - } - - Token parseQualified(Token token) { - token = parseIdentifier(token); - while (optional('.', token)) { - token = parseQualifiedRest(token); - } - return token; - } - - Token parseQualifiedRestOpt(Token token) { - if (optional('.', token)) { - return parseQualifiedRest(token); - } else { - return token; - } - } - - Token parseQualifiedRest(Token token) { - assert(optional('.', token)); - Token period = token; - token = parseIdentifier(token.next); - listener.handleQualified(period); - return token; - } - - bool isDefaultKeyword(Token token) { - String value = token.stringValue; - if (identical(value, 'default')) return true; - if (identical(value, 'factory')) { - listener.recoverableError("expected 'default'", token: token); - return true; - } - return false; - } - - Token skipBlock(Token token) { - if (!optional('{', token)) { - return listener.expectedBlockToSkip(token); - } - BeginGroupToken beginGroupToken = token; - Token endGroup = beginGroupToken.endGroup; - if (endGroup == null) { - return listener.unmatched(beginGroupToken); - } else if (!identical(endGroup.kind, $CLOSE_CURLY_BRACKET)) { - return listener.unmatched(beginGroupToken); - } - return beginGroupToken.endGroup; - } - - Token parseClass(Token token) { - Token begin = token; - listener.beginClassDeclaration(token); - int modifierCount = 0; - if (optional('abstract', token)) { - listener.handleModifier(token); - modifierCount++; - token = token.next; - } - listener.handleModifiers(modifierCount); - token = parseIdentifier(token.next); - token = parseTypeVariablesOpt(token); - Token extendsKeyword; - if (optional('extends', token)) { - extendsKeyword = token; - if (optional('with', peekAfterType(token.next))) { - token = parseMixinApplication(token.next); - } else { - token = parseType(token.next); - } - } else { - extendsKeyword = null; - listener.handleNoType(token); - } - Token implementsKeyword; - int interfacesCount = 0; - if (optional('implements', token)) { - implementsKeyword = token; - do { - token = parseType(token.next); - ++interfacesCount; - } while (optional(',', token)); - } - token = parseClassBody(token); - listener.endClassDeclaration(interfacesCount, begin, extendsKeyword, - implementsKeyword, token); - return token.next; - } - - Token parseStringPart(Token token) { - if (identical(token.kind, STRING_TOKEN)) { - listener.handleStringPart(token); - return token.next; - } else { - return listener.expected('string', token); - } - } - - Token parseIdentifier(Token token) { - if (token.isIdentifier()) { - listener.handleIdentifier(token); - } else { - listener.expectedIdentifier(token); - } - return token.next; - } - - Token expect(String string, Token token) { - if (!identical(string, token.stringValue)) { - return listener.expected(string, token); - } - return token.next; - } - - Token parseTypeVariable(Token token) { - listener.beginTypeVariable(token); - token = parseIdentifier(token); - if (optional('extends', token)) { - token = parseType(token.next); - } else { - listener.handleNoType(token); - } - listener.endTypeVariable(token); - return token; - } - - /** - * Returns true if the stringValue of the [token] is [value]. - */ - bool optional(String value, Token token) { - return identical(value, token.stringValue); - } - - /** - * Returns true if the stringValue of the [token] is either [value1], - * [value2], [value3], or [value4]. - */ - bool isOneOf4(Token token, - String value1, String value2, String value3, String value4) { - String stringValue = token.stringValue; - return identical(value1, stringValue) || - identical(value2, stringValue) || - identical(value3, stringValue) || - identical(value4, stringValue); - } - - bool notEofOrValue(String value, Token token) { - return !identical(token.kind, EOF_TOKEN) && - !identical(value, token.stringValue); - } - - Token parseType(Token token) { - Token begin = token; - if (isValidTypeReference(token)) { - token = parseIdentifier(token); - token = parseQualifiedRestOpt(token); - } else { - token = listener.expectedType(token); - } - token = parseTypeArgumentsOpt(token); - listener.endType(begin, token); - return token; - } - - Token parseTypeArgumentsOpt(Token token) { - return parseStuff(token, - (t) => listener.beginTypeArguments(t), - (t) => parseType(t), - (c, bt, et) => listener.endTypeArguments(c, bt, et), - (t) => listener.handleNoTypeArguments(t)); - } - - Token parseTypeVariablesOpt(Token token) { - return parseStuff(token, - (t) => listener.beginTypeVariables(t), - (t) => parseTypeVariable(t), - (c, bt, et) => listener.endTypeVariables(c, bt, et), - (t) => listener.handleNoTypeVariables(t)); - } - - // TODO(ahe): Clean this up. - Token parseStuff(Token token, Function beginStuff, Function stuffParser, - Function endStuff, Function handleNoStuff) { - if (optional('<', token)) { - Token begin = token; - beginStuff(begin); - int count = 0; - do { - token = stuffParser(token.next); - ++count; - } while (optional(',', token)); - Token next = token.next; - if (identical(token.stringValue, '>>')) { - token = new Token(GT_INFO, token.charOffset); - token.next = new Token(GT_INFO, token.charOffset + 1); - token.next.next = next; - } else if (identical(token.stringValue, '>>>')) { - token = new Token(GT_INFO, token.charOffset); - token.next = new Token(GT_GT_INFO, token.charOffset + 1); - token.next.next = next; - } - endStuff(count, begin, token); - return expect('>', token); - } - handleNoStuff(token); - return token; - } - - Token parseTopLevelMember(Token token) { - Token start = token; - listener.beginTopLevelMember(token); - - Link<Token> identifiers = findMemberName(token); - if (identifiers.isEmpty) { - return listener.unexpected(start); - } - Token name = identifiers.head; - identifiers = identifiers.tail; - Token getOrSet; - if (!identifiers.isEmpty) { - String value = identifiers.head.stringValue; - if ((identical(value, 'get')) || (identical(value, 'set'))) { - getOrSet = identifiers.head; - identifiers = identifiers.tail; - } - } - Token type; - if (!identifiers.isEmpty) { - if (isValidTypeReference(identifiers.head)) { - type = identifiers.head; - identifiers = identifiers.tail; - } - } - parseModifierList(identifiers.reverse()); - if (type == null) { - listener.handleNoType(token); - } else { - parseReturnTypeOpt(type); - } - token = parseIdentifier(name); - - bool isField; - while (true) { - // Loop to allow the listener to rewrite the token stream for - // error handling. - final String value = token.stringValue; - if ((identical(value, '(')) || (identical(value, '{')) - || (identical(value, '=>'))) { - isField = false; - break; - } else if ((identical(value, '=')) || (identical(value, ','))) { - isField = true; - break; - } else if (identical(value, ';')) { - if (getOrSet != null) { - // If we found a "get" keyword, this must be an abstract - // getter. - isField = (!identical(getOrSet.stringValue, 'get')); - // TODO(ahe): This feels like a hack. - } else { - isField = true; - } - break; - } else { - token = listener.unexpected(token); - if (identical(token.kind, EOF_TOKEN)) { - // TODO(ahe): This is a hack. It would be better to tell the - // listener more explicitly that it must pop an identifier. - listener.endTopLevelFields(1, start, token); - return token; - } - } - } - if (isField) { - int fieldCount = 1; - token = parseVariableInitializerOpt(token); - while (optional(',', token)) { - token = parseIdentifier(token.next); - token = parseVariableInitializerOpt(token); - ++fieldCount; - } - expectSemicolon(token); - listener.endTopLevelFields(fieldCount, start, token); - } else { - token = parseFormalParametersOpt(token); - token = parseFunctionBody(token, false); - listener.endTopLevelMethod(start, getOrSet, token); - } - return token.next; - } - - Link<Token> findMemberName(Token token) { - Token start = token; - Link<Token> identifiers = const Link<Token>(); - while (!identical(token.kind, EOF_TOKEN)) { - String value = token.stringValue; - if ((identical(value, '(')) || (identical(value, '{')) - || (identical(value, '=>'))) { - // A method. - return identifiers; - } else if ((identical(value, '=')) || (identical(value, ';')) - || (identical(value, ','))) { - // A field or abstract getter. - return identifiers; - } - identifiers = identifiers.prepend(token); - if (isValidTypeReference(token)) { - // type ... - if (optional('.', token.next)) { - // type '.' ... - if (token.next.next.isIdentifier()) { - // type '.' identifier - token = token.next.next; - } - } - if (optional('<', token.next)) { - if (token.next is BeginGroupToken) { - BeginGroupToken beginGroup = token.next; - token = beginGroup.endGroup; - } - } - } - token = token.next; - } - return listener.expectedDeclaration(start); - } - - Token parseVariableInitializerOpt(Token token) { - if (optional('=', token)) { - Token assignment = token; - listener.beginInitializer(token); - token = parseExpression(token.next); - listener.endInitializer(assignment); - } - return token; - } - - Token parseInitializersOpt(Token token) { - if (optional(':', token)) { - return parseInitializers(token); - } else { - listener.handleNoInitializers(); - return token; - } - } - - Token parseInitializers(Token token) { - Token begin = token; - listener.beginInitializers(begin); - expect(':', token); - int count = 0; - bool old = mayParseFunctionExpressions; - mayParseFunctionExpressions = false; - do { - token = parseExpression(token.next); - ++count; - } while (optional(',', token)); - mayParseFunctionExpressions = old; - listener.endInitializers(count, begin, token); - return token; - } - - Token parseScriptTags(Token token) { - Token begin = token; - listener.beginScriptTag(token); - token = parseIdentifier(token.next); - token = expect('(', token); - token = parseLiteralStringOrRecoverExpression(token); - bool hasPrefix = false; - if (optional(',', token)) { - hasPrefix = true; - token = parseIdentifier(token.next); - token = expect(':', token); - token = parseLiteralStringOrRecoverExpression(token); - } - token = expect(')', token); - listener.endScriptTag(hasPrefix, begin, token); - return expectSemicolon(token); - } - - Token parseLiteralStringOrRecoverExpression(Token token) { - if (identical(token.kind, STRING_TOKEN)) { - return parseLiteralString(token); - } else { - listener.recoverableError("unexpected", token: token); - return parseExpression(token); - } - } - - Token expectSemicolon(Token token) { - return expect(';', token); - } - - bool isModifier(Token token) { - final String value = token.stringValue; - return (identical('final', value)) || - (identical('var', value)) || - (identical('const', value)) || - (identical('abstract', value)) || - (identical('static', value)) || - (identical('external', value)); - } - - Token parseModifier(Token token) { - assert(isModifier(token)); - listener.handleModifier(token); - return token.next; - } - - void parseModifierList(Link<Token> tokens) { - int count = 0; - for (; !tokens.isEmpty; tokens = tokens.tail) { - Token token = tokens.head; - if (isModifier(token)) { - parseModifier(token); - } else { - listener.unexpected(token); - } - count++; - } - listener.handleModifiers(count); - } - - Token parseModifiers(Token token) { - int count = 0; - while (identical(token.kind, KEYWORD_TOKEN)) { - if (!isModifier(token)) - break; - token = parseModifier(token); - count++; - } - listener.handleModifiers(count); - return token; - } - - Token peekAfterType(Token token) { - // TODO(ahe): Also handle var? - // We are looking at "identifier ...". - Token peek = token.next; - if (identical(peek.kind, PERIOD_TOKEN)) { - if (peek.next.isIdentifier()) { - // Look past a library prefix. - peek = peek.next.next; - } - } - // We are looking at "qualified ...". - if (identical(peek.kind, LT_TOKEN)) { - // Possibly generic type. - // We are looking at "qualified '<'". - BeginGroupToken beginGroupToken = peek; - Token gtToken = beginGroupToken.endGroup; - if (gtToken != null) { - // We are looking at "qualified '<' ... '>' ...". - return gtToken.next; - } - } - return peek; - } - - /** - * Returns the token after the type which is expected to begin at [token]. - * If [token] is not the start of a type, [Listener.unexpectedType] is called. - */ - Token peekAfterExpectedType(Token token) { - if (!identical('void', token.stringValue) && !token.isIdentifier()) { - return listener.expectedType(token); - } - return peekAfterType(token); - } - - Token parseClassBody(Token token) { - Token begin = token; - listener.beginClassBody(token); - if (!optional('{', token)) { - token = listener.expectedClassBody(token); - } - token = token.next; - int count = 0; - while (notEofOrValue('}', token)) { - token = parseMember(token); - ++count; - } - expect('}', token); - listener.endClassBody(count, begin, token); - return token; - } - - bool isGetOrSet(Token token) { - final String value = token.stringValue; - return (identical(value, 'get')) || (identical(value, 'set')); - } - - bool isFactoryDeclaration(Token token) { - if (optional('external', token)) token = token.next; - if (optional('const', token)) token = token.next; - return optional('factory', token); - } - - Token parseMember(Token token) { - token = parseMetadataStar(token); - String value = token.stringValue; - if (isFactoryDeclaration(token)) { - return parseFactoryMethod(token); - } - Token start = token; - listener.beginMember(token); - - Link<Token> identifiers = findMemberName(token); - if (identifiers.isEmpty) { - return listener.unexpected(start); - } - Token name = identifiers.head; - identifiers = identifiers.tail; - if (!identifiers.isEmpty) { - if (optional('operator', identifiers.head)) { - name = identifiers.head; - identifiers = identifiers.tail; - } - } - Token getOrSet; - if (!identifiers.isEmpty) { - if (isGetOrSet(identifiers.head)) { - getOrSet = identifiers.head; - identifiers = identifiers.tail; - } - } - Token type; - if (!identifiers.isEmpty) { - if (isValidTypeReference(identifiers.head)) { - type = identifiers.head; - identifiers = identifiers.tail; - } - } - parseModifierList(identifiers.reverse()); - if (type == null) { - listener.handleNoType(token); - } else { - parseReturnTypeOpt(type); - } - - if (optional('operator', name)) { - token = parseOperatorName(name); - } else { - token = parseIdentifier(name); - } - bool isField; - while (true) { - // Loop to allow the listener to rewrite the token stream for - // error handling. - final String value = token.stringValue; - if ((identical(value, '(')) || (identical(value, '.')) - || (identical(value, '{')) || (identical(value, '=>'))) { - isField = false; - break; - } else if (identical(value, ';')) { - if (getOrSet != null) { - // If we found a "get" keyword, this must be an abstract - // getter. - isField = (!identical(getOrSet.stringValue, 'get')); - // TODO(ahe): This feels like a hack. - } else { - isField = true; - } - break; - } else if ((identical(value, '=')) || (identical(value, ','))) { - isField = true; - break; - } else { - token = listener.unexpected(token); - if (identical(token.kind, EOF_TOKEN)) { - // TODO(ahe): This is a hack, see parseTopLevelMember. - listener.endFields(1, start, token); - return token; - } - } - } - if (isField) { - int fieldCount = 1; - token = parseVariableInitializerOpt(token); - if (getOrSet != null) { - listener.recoverableError("unexpected", token: getOrSet); - } - while (optional(',', token)) { - // TODO(ahe): Count these. - token = parseIdentifier(token.next); - token = parseVariableInitializerOpt(token); - ++fieldCount; - } - expectSemicolon(token); - listener.endFields(fieldCount, start, token); - } else { - token = parseQualifiedRestOpt(token); - token = parseFormalParametersOpt(token); - token = parseInitializersOpt(token); - if (optional('=', token)) { - token = parseRedirectingFactoryBody(token); - } else { - token = parseFunctionBody(token, false); - } - listener.endMethod(getOrSet, start, token); - } - return token.next; - } - - Token parseFactoryMethod(Token token) { - assert(isFactoryDeclaration(token)); - Token start = token; - if (identical(token.stringValue, 'external')) token = token.next; - Token constKeyword = null; - if (optional('const', token)) { - constKeyword = token; - token = token.next; - } - Token factoryKeyword = token; - listener.beginFactoryMethod(factoryKeyword); - token = token.next; // Skip 'factory'. - token = parseConstructorReference(token); - token = parseFormalParameters(token); - if (optional('=', token)) { - token = parseRedirectingFactoryBody(token); - } else { - token = parseFunctionBody(token, false); - } - listener.endFactoryMethod(start, token); - return token.next; - } - - Token parseOperatorName(Token token) { - assert(optional('operator', token)); - if (isUserDefinableOperator(token.next.stringValue)) { - Token operator = token; - token = token.next; - listener.handleOperatorName(operator, token); - return token.next; - } else { - return parseIdentifier(token); - } - } - - Token parseFunction(Token token, Token getOrSet) { - listener.beginFunction(token); - token = parseModifiers(token); - if (identical(getOrSet, token)) token = token.next; - if (optional('operator', token)) { - listener.handleNoType(token); - listener.beginFunctionName(token); - token = parseOperatorName(token); - } else { - token = parseReturnTypeOpt(token); - if (identical(getOrSet, token)) token = token.next; - listener.beginFunctionName(token); - if (optional('operator', token)) { - token = parseOperatorName(token); - } else { - token = parseIdentifier(token); - } - } - token = parseQualifiedRestOpt(token); - listener.endFunctionName(token); - token = parseFormalParametersOpt(token); - token = parseInitializersOpt(token); - if (optional('=', token)) { - token = parseRedirectingFactoryBody(token); - } else { - token = parseFunctionBody(token, false); - } - listener.endFunction(getOrSet, token); - return token.next; - } - - Token parseUnamedFunction(Token token) { - listener.beginUnamedFunction(token); - token = parseFormalParameters(token); - bool isBlock = optional('{', token); - token = parseFunctionBody(token, true); - listener.endUnamedFunction(token); - return isBlock ? token.next : token; - } - - Token parseFunctionDeclaration(Token token) { - listener.beginFunctionDeclaration(token); - token = parseFunction(token, null); - listener.endFunctionDeclaration(token); - return token; - } - - Token parseFunctionExpression(Token token) { - listener.beginFunction(token); - listener.handleModifiers(0); - token = parseReturnTypeOpt(token); - listener.beginFunctionName(token); - token = parseIdentifier(token); - listener.endFunctionName(token); - token = parseFormalParameters(token); - listener.handleNoInitializers(); - bool isBlock = optional('{', token); - token = parseFunctionBody(token, true); - listener.endFunction(null, token); - return isBlock ? token.next : token; - } - - Token parseConstructorReference(Token token) { - Token start = token; - listener.beginConstructorReference(start); - token = parseIdentifier(token); - token = parseQualifiedRestOpt(token); - token = parseTypeArgumentsOpt(token); - Token period = null; - if (optional('.', token)) { - period = token; - token = parseIdentifier(token.next); - } - listener.endConstructorReference(start, period, token); - return token; - } - - Token parseRedirectingFactoryBody(Token token) { - listener.beginRedirectingFactoryBody(token); - assert(optional('=', token)); - Token equals = token; - token = parseConstructorReference(token.next); - Token semicolon = token; - expectSemicolon(token); - listener.endRedirectingFactoryBody(equals, semicolon); - return token; - } - - Token parseFunctionBody(Token token, bool isExpression) { - if (optional(';', token)) { - listener.endFunctionBody(0, null, token); - return token; - } else if (optional('=>', token)) { - Token begin = token; - token = parseExpression(token.next); - if (!isExpression) { - expectSemicolon(token); - listener.endReturnStatement(true, begin, token); - } else { - listener.endReturnStatement(true, begin, null); - } - return token; - } - Token begin = token; - int statementCount = 0; - if (!optional('{', token)) { - return listener.expectedFunctionBody(token); - } - - listener.beginFunctionBody(begin); - token = token.next; - while (notEofOrValue('}', token)) { - token = parseStatement(token); - ++statementCount; - } - listener.endFunctionBody(statementCount, begin, token); - expect('}', token); - return token; - } - - Token parseStatement(Token token) { - final value = token.stringValue; - if (identical(token.kind, IDENTIFIER_TOKEN)) { - return parseExpressionStatementOrDeclaration(token); - } else if (identical(value, '{')) { - return parseBlock(token); - } else if (identical(value, 'return')) { - return parseReturnStatement(token); - } else if (identical(value, 'var') || identical(value, 'final')) { - return parseVariablesDeclaration(token); - } else if (identical(value, 'if')) { - return parseIfStatement(token); - } else if (identical(value, 'for')) { - return parseForStatement(token); - } else if (identical(value, 'throw')) { - return parseThrowStatement(token); - } else if (identical(value, 'void')) { - return parseExpressionStatementOrDeclaration(token); - } else if (identical(value, 'while')) { - return parseWhileStatement(token); - } else if (identical(value, 'do')) { - return parseDoWhileStatement(token); - } else if (identical(value, 'try')) { - return parseTryStatement(token); - } else if (identical(value, 'switch')) { - return parseSwitchStatement(token); - } else if (identical(value, 'break')) { - return parseBreakStatement(token); - } else if (identical(value, 'continue')) { - return parseContinueStatement(token); - } else if (identical(value, 'assert')) { - return parseAssertStatement(token); - } else if (identical(value, ';')) { - return parseEmptyStatement(token); - } else if (identical(value, 'const')) { - return parseExpressionStatementOrConstDeclaration(token); - } else if (token.isIdentifier()) { - return parseExpressionStatementOrDeclaration(token); - } else { - return parseExpressionStatement(token); - } - } - - Token parseReturnStatement(Token token) { - Token begin = token; - listener.beginReturnStatement(begin); - assert(identical('return', token.stringValue)); - token = token.next; - if (optional(';', token)) { - listener.endReturnStatement(false, begin, token); - } else { - token = parseExpression(token); - listener.endReturnStatement(true, begin, token); - } - return expectSemicolon(token); - } - - Token peekIdentifierAfterType(Token token) { - Token peek = peekAfterType(token); - if (peek != null && peek.isIdentifier()) { - // We are looking at "type identifier". - return peek; - } else { - return null; - } - } - - Token peekIdentifierAfterOptionalType(Token token) { - Token peek = peekIdentifierAfterType(token); - if (peek != null) { - // We are looking at "type identifier". - return peek; - } else if (token.isIdentifier()) { - // We are looking at "identifier". - return token; - } else { - return null; - } - } - - Token parseExpressionStatementOrDeclaration(Token token) { - assert(token.isIdentifier() || identical(token.stringValue, 'void')); - Token identifier = peekIdentifierAfterType(token); - if (identifier != null) { - assert(identifier.isIdentifier()); - Token afterId = identifier.next; - int afterIdKind = afterId.kind; - if (identical(afterIdKind, EQ_TOKEN) || - identical(afterIdKind, SEMICOLON_TOKEN) || - identical(afterIdKind, COMMA_TOKEN)) { - // We are looking at "type identifier" followed by '=', ';', ','. - return parseVariablesDeclaration(token); - } else if (identical(afterIdKind, OPEN_PAREN_TOKEN)) { - // We are looking at "type identifier '('". - BeginGroupToken beginParen = afterId; - Token endParen = beginParen.endGroup; - Token afterParens = endParen.next; - if (optional('{', afterParens) || optional('=>', afterParens)) { - // We are looking at "type identifier '(' ... ')'" followed - // by '=>' or '{'. - return parseFunctionDeclaration(token); - } - } - // Fall-through to expression statement. - } else { - if (optional(':', token.next)) { - return parseLabeledStatement(token); - } else if (optional('(', token.next)) { - BeginGroupToken begin = token.next; - String afterParens = begin.endGroup.next.stringValue; - if (identical(afterParens, '{') || identical(afterParens, '=>')) { - return parseFunctionDeclaration(token); - } - } - } - return parseExpressionStatement(token); - } - - Token parseExpressionStatementOrConstDeclaration(Token token) { - assert(identical(token.stringValue, 'const')); - if (isModifier(token.next)) { - return parseVariablesDeclaration(token); - } - Token identifier = peekIdentifierAfterOptionalType(token.next); - if (identifier != null) { - assert(identifier.isIdentifier()); - Token afterId = identifier.next; - int afterIdKind = afterId.kind; - if (identical(afterIdKind, EQ_TOKEN) || - identical(afterIdKind, SEMICOLON_TOKEN) || - identical(afterIdKind, COMMA_TOKEN)) { - // We are looking at "const type identifier" followed by '=', ';', or - // ','. - return parseVariablesDeclaration(token); - } - // Fall-through to expression statement. - } - return parseExpressionStatement(token); - } - - Token parseLabel(Token token) { - token = parseIdentifier(token); - Token colon = token; - token = expect(':', token); - listener.handleLabel(colon); - return token; - } - - Token parseLabeledStatement(Token token) { - int labelCount = 0; - do { - token = parseLabel(token); - labelCount++; - } while (token.isIdentifier() && optional(':', token.next)); - listener.beginLabeledStatement(token, labelCount); - token = parseStatement(token); - listener.endLabeledStatement(labelCount); - return token; - } - - Token parseExpressionStatement(Token token) { - listener.beginExpressionStatement(token); - token = parseExpression(token); - listener.endExpressionStatement(token); - return expectSemicolon(token); - } - - Token parseExpression(Token token) { - return parsePrecedenceExpression(token, ASSIGNMENT_PRECEDENCE, true); - } - - Token parseExpressionWithoutCascade(Token token) { - return parsePrecedenceExpression(token, ASSIGNMENT_PRECEDENCE, false); - } - - Token parseConditionalExpressionRest(Token token) { - assert(optional('?', token)); - Token question = token; - token = parseExpressionWithoutCascade(token.next); - Token colon = token; - token = expect(':', token); - token = parseExpressionWithoutCascade(token); - listener.handleConditionalExpression(question, colon); - return token; - } - - Token parsePrecedenceExpression(Token token, int precedence, - bool allowCascades) { - assert(precedence >= 1); - assert(precedence <= POSTFIX_PRECEDENCE); - token = parseUnaryExpression(token, allowCascades); - PrecedenceInfo info = token.info; - int tokenLevel = info.precedence; - for (int level = tokenLevel; level >= precedence; --level) { - while (identical(tokenLevel, level)) { - Token operator = token; - if (identical(tokenLevel, CASCADE_PRECEDENCE)) { - if (!allowCascades) { - return token; - } - token = parseCascadeExpression(token); - } else if (identical(tokenLevel, ASSIGNMENT_PRECEDENCE)) { - // Right associative, so we recurse at the same precedence - // level. - token = parsePrecedenceExpression(token.next, level, allowCascades); - listener.handleAssignmentExpression(operator); - } else if (identical(tokenLevel, POSTFIX_PRECEDENCE)) { - if (identical(info, PERIOD_INFO)) { - // Left associative, so we recurse at the next higher - // precedence level. However, POSTFIX_PRECEDENCE is the - // highest level, so we just call parseUnaryExpression - // directly. - token = parseUnaryExpression(token.next, allowCascades); - listener.handleBinaryExpression(operator); - } else if ((identical(info, OPEN_PAREN_INFO)) || - (identical(info, OPEN_SQUARE_BRACKET_INFO))) { - token = parseArgumentOrIndexStar(token); - } else if ((identical(info, PLUS_PLUS_INFO)) || - (identical(info, MINUS_MINUS_INFO))) { - listener.handleUnaryPostfixAssignmentExpression(token); - token = token.next; - } else { - token = listener.unexpected(token); - } - } else if (identical(info, IS_INFO)) { - token = parseIsOperatorRest(token); - } else if (identical(info, AS_INFO)) { - token = parseAsOperatorRest(token); - } else if (identical(info, QUESTION_INFO)) { - token = parseConditionalExpressionRest(token); - } else { - // Left associative, so we recurse at the next higher - // precedence level. - token = parsePrecedenceExpression(token.next, level + 1, - allowCascades); - listener.handleBinaryExpression(operator); - } - info = token.info; - tokenLevel = info.precedence; - } - } - return token; - } - - Token parseCascadeExpression(Token token) { - listener.beginCascade(token); - assert(optional('..', token)); - Token cascadeOperator = token; - token = token.next; - if (optional('[', token)) { - token = parseArgumentOrIndexStar(token); - } else if (token.isIdentifier()) { - token = parseSend(token); - listener.handleBinaryExpression(cascadeOperator); - } else { - return listener.unexpected(token); - } - Token mark; - do { - mark = token; - if (optional('.', token)) { - Token period = token; - token = parseSend(token.next); - listener.handleBinaryExpression(period); - } - token = parseArgumentOrIndexStar(token); - } while (!identical(mark, token)); - - if (identical(token.info.precedence, ASSIGNMENT_PRECEDENCE)) { - Token assignment = token; - token = parseExpressionWithoutCascade(token.next); - listener.handleAssignmentExpression(assignment); - } - listener.endCascade(); - return token; - } - - Token parseUnaryExpression(Token token, bool allowCascades) { - String value = token.stringValue; - // Prefix: - if (identical(value, '+')) { - // Dart only allows "prefix plus" as an initial part of a - // decimal literal. We scan it as a separate token and let - // the parser listener combine it with the digits. - Token next = token.next; - if (identical(next.charOffset, token.charOffset + 1)) { - if (identical(next.kind, INT_TOKEN)) { - listener.handleLiteralInt(token); - return next.next; - } - if (identical(next.kind, DOUBLE_TOKEN)) { - listener.handleLiteralDouble(token); - return next.next; - } - } - listener.recoverableError("Unexpected token '+'", token: token); - return parsePrecedenceExpression(next, POSTFIX_PRECEDENCE, - allowCascades); - } else if ((identical(value, '!')) || - (identical(value, '-')) || - (identical(value, '~'))) { - Token operator = token; - // Right associative, so we recurse at the same precedence - // level. - token = parsePrecedenceExpression(token.next, POSTFIX_PRECEDENCE, - allowCascades); - listener.handleUnaryPrefixExpression(operator); - } else if ((identical(value, '++')) || identical(value, '--')) { - // TODO(ahe): Validate this is used correctly. - Token operator = token; - // Right associative, so we recurse at the same precedence - // level. - token = parsePrecedenceExpression(token.next, POSTFIX_PRECEDENCE, - allowCascades); - listener.handleUnaryPrefixAssignmentExpression(operator); - } else { - token = parsePrimary(token); - } - return token; - } - - Token parseArgumentOrIndexStar(Token token) { - while (true) { - if (optional('[', token)) { - Token openSquareBracket = token; - bool old = mayParseFunctionExpressions; - mayParseFunctionExpressions = true; - token = parseExpression(token.next); - mayParseFunctionExpressions = old; - listener.handleIndexedExpression(openSquareBracket, token); - token = expect(']', token); - } else if (optional('(', token)) { - token = parseArguments(token); - listener.endSend(token); - } else { - break; - } - } - return token; - } - - Token parsePrimary(Token token) { - final kind = token.kind; - if (identical(kind, IDENTIFIER_TOKEN)) { - return parseSendOrFunctionLiteral(token); - } else if (identical(kind, INT_TOKEN) - || identical(kind, HEXADECIMAL_TOKEN)) { - return parseLiteralInt(token); - } else if (identical(kind, DOUBLE_TOKEN)) { - return parseLiteralDouble(token); - } else if (identical(kind, STRING_TOKEN)) { - return parseLiteralString(token); - } else if (identical(kind, KEYWORD_TOKEN)) { - final value = token.stringValue; - if ((identical(value, 'true')) || (identical(value, 'false'))) { - return parseLiteralBool(token); - } else if (identical(value, 'null')) { - return parseLiteralNull(token); - } else if (identical(value, 'this')) { - return parseThisExpression(token); - } else if (identical(value, 'super')) { - return parseSuperExpression(token); - } else if (identical(value, 'new')) { - return parseNewExpression(token); - } else if (identical(value, 'const')) { - return parseConstExpression(token); - } else if (identical(value, 'void')) { - return parseFunctionExpression(token); - } else if (token.isIdentifier()) { - return parseSendOrFunctionLiteral(token); - } else { - return listener.expectedExpression(token); - } - } else if (identical(kind, OPEN_PAREN_TOKEN)) { - return parseParenthesizedExpressionOrFunctionLiteral(token); - } else if ((identical(kind, LT_TOKEN)) || - (identical(kind, OPEN_SQUARE_BRACKET_TOKEN)) || - (identical(kind, OPEN_CURLY_BRACKET_TOKEN)) || - identical(token.stringValue, '[]')) { - return parseLiteralListOrMap(token); - } else if (identical(kind, QUESTION_TOKEN)) { - return parseArgumentDefinitionTest(token); - } else { - return listener.expectedExpression(token); - } - } - - Token parseArgumentDefinitionTest(Token token) { - Token questionToken = token; - listener.beginArgumentDefinitionTest(questionToken); - assert(optional('?', token)); - token = parseIdentifier(token.next); - listener.endArgumentDefinitionTest(questionToken, token); - return token; - } - - Token parseParenthesizedExpressionOrFunctionLiteral(Token token) { - BeginGroupToken beginGroup = token; - int kind = beginGroup.endGroup.next.kind; - if (mayParseFunctionExpressions && - (identical(kind, FUNCTION_TOKEN) - || identical(kind, OPEN_CURLY_BRACKET_TOKEN))) { - return parseUnamedFunction(token); - } else { - bool old = mayParseFunctionExpressions; - mayParseFunctionExpressions = true; - token = parseParenthesizedExpression(token); - mayParseFunctionExpressions = old; - return token; - } - } - - Token parseParenthesizedExpression(Token token) { - var begin = token; - token = expect('(', token); - token = parseExpression(token); - if (!identical(begin.endGroup, token)) { - listener.unexpected(token); - token = begin.endGroup; - } - listener.handleParenthesizedExpression(begin); - return expect(')', token); - } - - Token parseThisExpression(Token token) { - listener.handleThisExpression(token); - token = token.next; - if (optional('(', token)) { - // Constructor forwarding. - token = parseArguments(token); - listener.endSend(token); - } - return token; - } - - Token parseSuperExpression(Token token) { - listener.handleSuperExpression(token); - token = token.next; - if (optional('(', token)) { - // Super constructor. - token = parseArguments(token); - listener.endSend(token); - } - return token; - } - - Token parseLiteralListOrMap(Token token) { - Token constKeyword = null; - if (optional('const', token)) { - constKeyword = token; - token = token.next; - } - token = parseTypeArgumentsOpt(token); - Token beginToken = token; - int count = 0; - if (optional('{', token)) { - bool old = mayParseFunctionExpressions; - mayParseFunctionExpressions = true; - do { - if (optional('}', token.next)) { - token = token.next; - break; - } - token = parseMapLiteralEntry(token.next); - ++count; - } while (optional(',', token)); - mayParseFunctionExpressions = old; - listener.handleLiteralMap(count, beginToken, constKeyword, token); - return expect('}', token); - } else if (optional('[', token)) { - bool old = mayParseFunctionExpressions; - mayParseFunctionExpressions = true; - do { - if (optional(']', token.next)) { - token = token.next; - break; - } - token = parseExpression(token.next); - ++count; - } while (optional(',', token)); - mayParseFunctionExpressions = old; - listener.handleLiteralList(count, beginToken, constKeyword, token); - return expect(']', token); - } else if (optional('[]', token)) { - listener.handleLiteralList(0, token, constKeyword, token); - return token.next; - } else { - listener.unexpected(token); - } - } - - Token parseMapLiteralEntry(Token token) { - listener.beginLiteralMapEntry(token); - // Assume the listener rejects non-string keys. - token = parseExpression(token); - Token colon = token; - token = expect(':', token); - token = parseExpression(token); - listener.endLiteralMapEntry(colon, token); - return token; - } - - Token parseSendOrFunctionLiteral(Token token) { - if (!mayParseFunctionExpressions) return parseSend(token); - Token peek = peekAfterExpectedType(token); - if (identical(peek.kind, IDENTIFIER_TOKEN) && isFunctionDeclaration(peek.next)) { - return parseFunctionExpression(token); - } else if (isFunctionDeclaration(token.next)) { - return parseFunctionExpression(token); - } else { - return parseSend(token); - } - } - - bool isFunctionDeclaration(Token token) { - if (optional('(', token)) { - BeginGroupToken begin = token; - String afterParens = begin.endGroup.next.stringValue; - if (identical(afterParens, '{') || identical(afterParens, '=>')) { - return true; - } - } - return false; - } - - Token parseRequiredArguments(Token token) { - if (optional('(', token)) { - token = parseArguments(token); - } else { - listener.handleNoArguments(token); - token = listener.unexpected(token); - } - return token; - } - - Token parseNewExpression(Token token) { - Token newKeyword = token; - token = expect('new', token); - token = parseConstructorReference(token); - token = parseRequiredArguments(token); - listener.handleNewExpression(newKeyword); - return token; - } - - Token parseConstExpression(Token token) { - Token constKeyword = token; - token = expect('const', token); - final String value = token.stringValue; - if ((identical(value, '<')) || - (identical(value, '[')) || - (identical(value, '[]')) || - (identical(value, '{'))) { - return parseLiteralListOrMap(constKeyword); - } - token = parseConstructorReference(token); - token = parseRequiredArguments(token); - listener.handleConstExpression(constKeyword); - return token; - } - - Token parseLiteralInt(Token token) { - listener.handleLiteralInt(token); - return token.next; - } - - Token parseLiteralDouble(Token token) { - listener.handleLiteralDouble(token); - return token.next; - } - - Token parseLiteralString(Token token) { - token = parseSingleLiteralString(token); - int count = 1; - while (identical(token.kind, STRING_TOKEN)) { - token = parseSingleLiteralString(token); - count++; - } - if (count > 1) { - listener.handleStringJuxtaposition(count); - } - return token; - } - - /** - * Only called when [:token.kind === STRING_TOKEN:]. - */ - Token parseSingleLiteralString(Token token) { - listener.beginLiteralString(token); - // Parsing the prefix, for instance 'x of 'x${id}y${id}z' - token = token.next; - int interpolationCount = 0; - var kind = token.kind; - while (kind != EOF_TOKEN) { - if (identical(kind, STRING_INTERPOLATION_TOKEN)) { - // Parsing ${expression}. - token = token.next; - token = parseExpression(token); - token = expect('}', token); - } else if (identical(kind, STRING_INTERPOLATION_IDENTIFIER_TOKEN)) { - // Parsing $identifier. - token = token.next; - token = parseExpression(token); - } else { - break; - } - ++interpolationCount; - // Parsing the infix/suffix, for instance y and z' of 'x${id}y${id}z' - token = parseStringPart(token); - kind = token.kind; - } - listener.endLiteralString(interpolationCount); - return token; - } - - Token parseLiteralBool(Token token) { - listener.handleLiteralBool(token); - return token.next; - } - - Token parseLiteralNull(Token token) { - listener.handleLiteralNull(token); - return token.next; - } - - Token parseSend(Token token) { - listener.beginSend(token); - token = parseIdentifier(token); - token = parseArgumentsOpt(token); - listener.endSend(token); - return token; - } - - Token parseArgumentsOpt(Token token) { - if (!optional('(', token)) { - listener.handleNoArguments(token); - return token; - } else { - return parseArguments(token); - } - } - - Token parseArguments(Token token) { - Token begin = token; - listener.beginArguments(begin); - assert(identical('(', token.stringValue)); - int argumentCount = 0; - if (optional(')', token.next)) { - listener.endArguments(argumentCount, begin, token.next); - return token.next.next; - } - bool old = mayParseFunctionExpressions; - mayParseFunctionExpressions = true; - do { - Token colon = null; - if (optional(':', token.next.next)) { - token = parseIdentifier(token.next); - colon = token; - } - token = parseExpression(token.next); - if (colon != null) listener.handleNamedArgument(colon); - ++argumentCount; - } while (optional(',', token)); - mayParseFunctionExpressions = old; - listener.endArguments(argumentCount, begin, token); - return expect(')', token); - } - - Token parseIsOperatorRest(Token token) { - assert(optional('is', token)); - Token operator = token; - Token not = null; - if (optional('!', token.next)) { - token = token.next; - not = token; - } - token = parseType(token.next); - listener.handleIsOperator(operator, not, token); - String value = token.stringValue; - if (identical(value, 'is') || identical(value, 'as')) { - // The is- and as-operators cannot be chained, but they can take part of - // expressions like: foo is Foo || foo is Bar. - listener.unexpected(token); - } - return token; - } - - Token parseAsOperatorRest(Token token) { - assert(optional('as', token)); - Token operator = token; - token = parseType(token.next); - listener.handleAsOperator(operator, token); - String value = token.stringValue; - if (identical(value, 'is') || identical(value, 'as')) { - // The is- and as-operators cannot be chained. - listener.unexpected(token); - } - return token; - } - - Token parseVariablesDeclaration(Token token) { - return parseVariablesDeclarationMaybeSemicolon(token, true); - } - - Token parseVariablesDeclarationNoSemicolon(Token token) { - return parseVariablesDeclarationMaybeSemicolon(token, false); - } - - Token parseVariablesDeclarationMaybeSemicolon(Token token, - bool endWithSemicolon) { - int count = 1; - listener.beginVariablesDeclaration(token); - token = parseModifiers(token); - token = parseTypeOpt(token); - token = parseOptionallyInitializedIdentifier(token); - while (optional(',', token)) { - token = parseOptionallyInitializedIdentifier(token.next); - ++count; - } - if (endWithSemicolon) { - Token semicolon = token; - token = expectSemicolon(semicolon); - listener.endVariablesDeclaration(count, semicolon); - return token; - } else { - listener.endVariablesDeclaration(count, null); - return token; - } - } - - Token parseOptionallyInitializedIdentifier(Token token) { - listener.beginInitializedIdentifier(token); - token = parseIdentifier(token); - token = parseVariableInitializerOpt(token); - listener.endInitializedIdentifier(); - return token; - } - - Token parseIfStatement(Token token) { - Token ifToken = token; - listener.beginIfStatement(ifToken); - token = expect('if', token); - token = parseParenthesizedExpression(token); - token = parseStatement(token); - Token elseToken = null; - if (optional('else', token)) { - elseToken = token; - token = parseStatement(token.next); - } - listener.endIfStatement(ifToken, elseToken); - return token; - } - - Token parseForStatement(Token token) { - Token forToken = token; - listener.beginForStatement(forToken); - token = expect('for', token); - token = expect('(', token); - token = parseVariablesDeclarationOrExpressionOpt(token); - if (optional('in', token)) { - return parseForInRest(forToken, token); - } else { - return parseForRest(forToken, token); - } - } - - Token parseVariablesDeclarationOrExpressionOpt(Token token) { - final String value = token.stringValue; - if (identical(value, ';')) { - listener.handleNoExpression(token); - return token; - } else if ((identical(value, 'var')) || (identical(value, 'final'))) { - return parseVariablesDeclarationNoSemicolon(token); - } - Token identifier = peekIdentifierAfterType(token); - if (identifier != null) { - assert(identifier.isIdentifier()); - if (isOneOf4(identifier.next, '=', ';', ',', 'in')) { - return parseVariablesDeclarationNoSemicolon(token); - } - } - return parseExpression(token); - } - - Token parseForRest(Token forToken, Token token) { - token = expectSemicolon(token); - if (optional(';', token)) { - token = parseEmptyStatement(token); - } else { - token = parseExpressionStatement(token); - } - int expressionCount = 0; - while (true) { - if (optional(')', token)) break; - token = parseExpression(token); - ++expressionCount; - if (optional(',', token)) { - token = token.next; - } else { - break; - } - } - token = expect(')', token); - token = parseStatement(token); - listener.endForStatement(expressionCount, forToken, token); - return token; - } - - Token parseForInRest(Token forToken, Token token) { - assert(optional('in', token)); - Token inKeyword = token; - token = parseExpression(token.next); - token = expect(')', token); - token = parseStatement(token); - listener.endForIn(forToken, inKeyword, token); - return token; - } - - Token parseWhileStatement(Token token) { - Token whileToken = token; - listener.beginWhileStatement(whileToken); - token = expect('while', token); - token = parseParenthesizedExpression(token); - token = parseStatement(token); - listener.endWhileStatement(whileToken, token); - return token; - } - - Token parseDoWhileStatement(Token token) { - Token doToken = token; - listener.beginDoWhileStatement(doToken); - token = expect('do', token); - token = parseStatement(token); - Token whileToken = token; - token = expect('while', token); - token = parseParenthesizedExpression(token); - listener.endDoWhileStatement(doToken, whileToken, token); - return expectSemicolon(token); - } - - Token parseBlock(Token token) { - Token begin = token; - listener.beginBlock(begin); - int statementCount = 0; - token = expect('{', token); - while (notEofOrValue('}', token)) { - token = parseStatement(token); - ++statementCount; - } - listener.endBlock(statementCount, begin, token); - return expect('}', token); - } - - Token parseThrowStatement(Token token) { - Token throwToken = token; - listener.beginThrowStatement(throwToken); - token = expect('throw', token); - if (optional(';', token)) { - listener.endRethrowStatement(throwToken, token); - return token.next; - } else { - token = parseExpression(token); - listener.endThrowStatement(throwToken, token); - return expectSemicolon(token); - } - } - - Token parseTryStatement(Token token) { - assert(optional('try', token)); - Token tryKeyword = token; - listener.beginTryStatement(tryKeyword); - token = parseBlock(token.next); - int catchCount = 0; - - String value = token.stringValue; - while (identical(value, 'catch') || identical(value, 'on')) { - var onKeyword = null; - if (identical(value, 'on')) { - // on qualified catchPart? - onKeyword = token; - token = parseType(token.next); - value = token.stringValue; - } - Token catchKeyword = null; - if (identical(value, 'catch')) { - catchKeyword = token; - // TODO(ahe): Validate the "parameters". - token = parseFormalParameters(token.next); - } - token = parseBlock(token); - ++catchCount; - listener.handleCatchBlock(onKeyword, catchKeyword); - value = token.stringValue; // while condition - } - - Token finallyKeyword = null; - if (optional('finally', token)) { - finallyKeyword = token; - token = parseBlock(token.next); - listener.handleFinallyBlock(finallyKeyword); - } - listener.endTryStatement(catchCount, tryKeyword, finallyKeyword); - return token; - } - - Token parseSwitchStatement(Token token) { - assert(optional('switch', token)); - Token switchKeyword = token; - listener.beginSwitchStatement(switchKeyword); - token = parseParenthesizedExpression(token.next); - token = parseSwitchBlock(token); - listener.endSwitchStatement(switchKeyword, token); - return token.next; - } - - Token parseSwitchBlock(Token token) { - Token begin = token; - listener.beginSwitchBlock(begin); - token = expect('{', token); - int caseCount = 0; - while (!identical(token.kind, EOF_TOKEN)) { - if (optional('}', token)) { - break; - } - token = parseSwitchCase(token); - ++caseCount; - } - listener.endSwitchBlock(caseCount, begin, token); - expect('}', token); - return token; - } - - /** - * Peek after the following labels (if any). The following token - * is used to determine if the labels belong to a statement or a - * switch case. - */ - Token peekPastLabels(Token token) { - while (token.isIdentifier() && optional(':', token.next)) { - token = token.next.next; - } - return token; - } - - /** - * Parse a group of labels, cases and possibly a default keyword and - * the statements that they select. - */ - Token parseSwitchCase(Token token) { - Token begin = token; - Token defaultKeyword = null; - int expressionCount = 0; - int labelCount = 0; - Token peek = peekPastLabels(token); - while (true) { - // Loop until we find something that can't be part of a switch case. - String value = peek.stringValue; - if (identical(value, 'default')) { - while (!identical(token, peek)) { - token = parseLabel(token); - labelCount++; - } - defaultKeyword = token; - token = expect(':', token.next); - peek = token; - break; - } else if (identical(value, 'case')) { - while (!identical(token, peek)) { - token = parseLabel(token); - labelCount++; - } - Token caseKeyword = token; - token = parseExpression(token.next); - Token colonToken = token; - token = expect(':', token); - listener.handleCaseMatch(caseKeyword, colonToken); - expressionCount++; - peek = peekPastLabels(token); - } else { - if (expressionCount == 0) { - listener.expected("case", token); - } - break; - } - } - // Finally zero or more statements. - int statementCount = 0; - while (!identical(token.kind, EOF_TOKEN)) { - String value = peek.stringValue; - if ((identical(value, 'case')) || - (identical(value, 'default')) || - ((identical(value, '}')) && (identical(token, peek)))) { - // A label just before "}" will be handled as a statement error. - break; - } else { - token = parseStatement(token); - } - statementCount++; - peek = peekPastLabels(token); - } - listener.handleSwitchCase(labelCount, expressionCount, defaultKeyword, - statementCount, begin, token); - return token; - } - - Token parseBreakStatement(Token token) { - assert(optional('break', token)); - Token breakKeyword = token; - token = token.next; - bool hasTarget = false; - if (token.isIdentifier()) { - token = parseIdentifier(token); - hasTarget = true; - } - listener.handleBreakStatement(hasTarget, breakKeyword, token); - return expectSemicolon(token); - } - - Token parseAssertStatement(Token token) { - Token assertKeyword = token; - token = expect('assert', token); - expect('(', token); - token = parseArguments(token); - listener.handleAssertStatement(assertKeyword, token); - return expectSemicolon(token); - } - - Token parseContinueStatement(Token token) { - assert(optional('continue', token)); - Token continueKeyword = token; - token = token.next; - bool hasTarget = false; - if (token.isIdentifier()) { - token = parseIdentifier(token); - hasTarget = true; - } - listener.handleContinueStatement(hasTarget, continueKeyword, token); - return expectSemicolon(token); - } - - Token parseEmptyStatement(Token token) { - listener.handleEmptyStatement(token); - return expectSemicolon(token); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/parser_task.dart b/pkgs/markdown/test/lib/src/compiler/implementation/scanner/parser_task.dart deleted file mode 100644 index eca572b..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/parser_task.dart +++ /dev/null
@@ -1,14 +0,0 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of scanner; - -class ParserTask extends CompilerTask { - ParserTask(Compiler compiler) : super(compiler); - String get name => 'Parser'; - - Node parse(Element element) { - return measure(() => element.parseNode(compiler)); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/partial_parser.dart b/pkgs/markdown/test/lib/src/compiler/implementation/scanner/partial_parser.dart deleted file mode 100644 index 02f409a..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/partial_parser.dart +++ /dev/null
@@ -1,130 +0,0 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of scanner; - -class PartialParser extends Parser { - PartialParser(Listener listener) : super(listener); - - Token parseClassBody(Token token) => skipClassBody(token); - - Token fullParseClassBody(Token token) => super.parseClassBody(token); - - Token parseExpression(Token token) => skipExpression(token); - - Token parseArgumentsOpt(Token token) { - // This method is overridden for two reasons: - // 1. Avoid generating events for arguments. - // 2. Avoid calling skip expression for each argument (which doesn't work). - if (optional('(', token)) { - BeginGroupToken begin = token; - return begin.endGroup.next; - } else { - return token; - } - } - - Token skipExpression(Token token) { - while (true) { - final kind = token.kind; - final value = token.stringValue; - if ((identical(kind, EOF_TOKEN)) || - (identical(value, ';')) || - (identical(value, ',')) || - (identical(value, ']'))) - return token; - if (identical(value, '=')) { - var nextValue = token.next.stringValue; - if (identical(nextValue, 'const')) { - token = token.next; - nextValue = token.next.stringValue; - } - if (identical(nextValue, '{')) { - // Handle cases like this: - // class Foo { - // var map; - // Foo() : map = {}; - // } - BeginGroupToken begin = token.next; - token = (begin.endGroup != null) ? begin.endGroup : token; - token = token.next; - continue; - } - if (identical(nextValue, '<')) { - // Handle cases like this: - // class Foo { - // var map; - // Foo() : map = <String, Foo>{}; - // } - BeginGroupToken begin = token.next; - token = (begin.endGroup != null) ? begin.endGroup : token; - token = token.next; - if (identical(token.stringValue, '{')) { - begin = token; - token = (begin.endGroup != null) ? begin.endGroup : token; - token = token.next; - } - continue; - } - } - if (!mayParseFunctionExpressions && identical(value, '{')) return token; - if (token is BeginGroupToken) { - BeginGroupToken begin = token; - token = (begin.endGroup != null) ? begin.endGroup : token; - } - token = token.next; - } - } - - Token skipClassBody(Token token) { - if (!optional('{', token)) { - return listener.expectedClassBodyToSkip(token); - } - BeginGroupToken beginGroupToken = token; - Token endGroup = beginGroupToken.endGroup; - if (endGroup == null) { - return listener.unmatched(beginGroupToken); - } else if (!identical(endGroup.kind, $CLOSE_CURLY_BRACKET)) { - return listener.unmatched(beginGroupToken); - } - return endGroup; - } - - Token parseFunctionBody(Token token, bool isExpression) { - assert(!isExpression); - String value = token.stringValue; - if (identical(value, ';')) { - // No body. - } else if (identical(value, '=>')) { - token = parseExpression(token.next); - expectSemicolon(token); - } else if (value == '=') { - token = parseRedirectingFactoryBody(token); - expectSemicolon(token); - } else { - token = skipBlock(token); - } - // There is no "skipped function body event", so we use - // handleNoFunctionBody instead. - listener.handleNoFunctionBody(token); - return token; - } - - Token parseFormalParameters(Token token) => skipFormals(token); - - Token skipFormals(Token token) { - listener.beginOptionalFormalParameters(token); - if (!optional('(', token)) { - if (optional(';', token)) { - listener.recoverableError("expected '('", token: token); - return token; - } - return listener.unexpected(token); - } - BeginGroupToken beginGroupToken = token; - Token endToken = beginGroupToken.endGroup; - listener.endFormalParameters(0, token, endToken); - return endToken.next; - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/scanner.dart b/pkgs/markdown/test/lib/src/compiler/implementation/scanner/scanner.dart deleted file mode 100644 index 123b650..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/scanner.dart +++ /dev/null
@@ -1,875 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of scanner; - -abstract class Scanner { - Token tokenize(); -} - -/** - * Common base class for a Dart scanner. - */ -abstract class AbstractScanner<T extends SourceString> implements Scanner { - int advance(); - int nextByte(); - - /** - * Returns the current character or byte depending on the underlying input - * kind. For example, [StringScanner] operates on [String] and thus returns - * characters (Unicode codepoints represented as int) whereas - * [ByteArrayScanner] operates on byte arrays and thus returns bytes. - */ - int peek(); - - /** - * Appends a fixed token based on whether the current char is [choice] or not. - * If the current char is [choice] a fixed token whose kind and content - * is determined by [yes] is appended, otherwise a fixed token whose kind - * and content is determined by [no] is appended. - */ - int select(int choice, PrecedenceInfo yes, PrecedenceInfo no); - - /** - * Appends a fixed token whose kind and content is determined by [info]. - */ - void appendPrecedenceToken(PrecedenceInfo info); - - /** - * Appends a token whose kind is determined by [info] and content is [value]. - */ - void appendStringToken(PrecedenceInfo info, String value); - - /** - * Appends a token whose kind is determined by [info] and content is defined - * by the SourceString [value]. - */ - void appendByteStringToken(PrecedenceInfo info, T value); - - /** - * Appends a keyword token whose kind is determined by [keyword]. - */ - void appendKeywordToken(Keyword keyword); - void appendWhiteSpace(int next); - void appendEofToken(); - - /** - * Creates an ASCII SourceString whose content begins at the source byte - * offset [start] and ends at [offset] bytes from the current byte offset of - * the scanner. For example, if the current byte offset is 10, - * [:asciiString(0,-1):] creates an ASCII SourceString whose content is found - * at the [0,9[ byte interval of the source text. - */ - T asciiString(int start, int offset); - T utf8String(int start, int offset); - Token firstToken(); - Token previousToken(); - void beginToken(); - void addToCharOffset(int offset); - int get charOffset; - int get byteOffset; - void appendBeginGroup(PrecedenceInfo info, String value); - int appendEndGroup(PrecedenceInfo info, String value, int openKind); - void appendGt(PrecedenceInfo info, String value); - void appendGtGt(PrecedenceInfo info, String value); - void appendGtGtGt(PrecedenceInfo info, String value); - void appendComment(); - - /** - * We call this method to discard '<' from the "grouping" stack - * (maintained by subclasses). - * - * [PartialParser.skipExpression] relies on the fact that we do not - * create groups for stuff like: - * [:a = b < c, d = e > f:]. - * - * In other words, this method is called when the scanner recognizes - * something which cannot possibly be part of a type - * parameter/argument list. - */ - void discardOpenLt(); - - // TODO(ahe): Move this class to implementation. - - Token tokenize() { - int next = advance(); - while (!identical(next, $EOF)) { - next = bigSwitch(next); - } - appendEofToken(); - return firstToken(); - } - - int bigSwitch(int next) { - beginToken(); - if (identical(next, $SPACE) || identical(next, $TAB) - || identical(next, $LF) || identical(next, $CR)) { - appendWhiteSpace(next); - next = advance(); - while (identical(next, $SPACE)) { - appendWhiteSpace(next); - next = advance(); - } - return next; - } - - if ($a <= next && next <= $z) { - if (identical($r, next)) { - return tokenizeRawStringKeywordOrIdentifier(next); - } - return tokenizeKeywordOrIdentifier(next, true); - } - - if (($A <= next && next <= $Z) || identical(next, $_) || identical(next, $$)) { - return tokenizeIdentifier(next, byteOffset, true); - } - - if (identical(next, $LT)) { - return tokenizeLessThan(next); - } - - if (identical(next, $GT)) { - return tokenizeGreaterThan(next); - } - - if (identical(next, $EQ)) { - return tokenizeEquals(next); - } - - if (identical(next, $BANG)) { - return tokenizeExclamation(next); - } - - if (identical(next, $PLUS)) { - return tokenizePlus(next); - } - - if (identical(next, $MINUS)) { - return tokenizeMinus(next); - } - - if (identical(next, $STAR)) { - return tokenizeMultiply(next); - } - - if (identical(next, $PERCENT)) { - return tokenizePercent(next); - } - - if (identical(next, $AMPERSAND)) { - return tokenizeAmpersand(next); - } - - if (identical(next, $BAR)) { - return tokenizeBar(next); - } - - if (identical(next, $CARET)) { - return tokenizeCaret(next); - } - - if (identical(next, $OPEN_SQUARE_BRACKET)) { - return tokenizeOpenSquareBracket(next); - } - - if (identical(next, $TILDE)) { - return tokenizeTilde(next); - } - - if (identical(next, $BACKSLASH)) { - appendPrecedenceToken(BACKSLASH_INFO); - return advance(); - } - - if (identical(next, $HASH)) { - return tokenizeTag(next); - } - - if (identical(next, $OPEN_PAREN)) { - appendBeginGroup(OPEN_PAREN_INFO, "("); - return advance(); - } - - if (identical(next, $CLOSE_PAREN)) { - return appendEndGroup(CLOSE_PAREN_INFO, ")", OPEN_PAREN_TOKEN); - } - - if (identical(next, $COMMA)) { - appendPrecedenceToken(COMMA_INFO); - return advance(); - } - - if (identical(next, $COLON)) { - appendPrecedenceToken(COLON_INFO); - return advance(); - } - - if (identical(next, $SEMICOLON)) { - appendPrecedenceToken(SEMICOLON_INFO); - // Type parameters and arguments cannot contain semicolon. - discardOpenLt(); - return advance(); - } - - if (identical(next, $QUESTION)) { - appendPrecedenceToken(QUESTION_INFO); - return advance(); - } - - if (identical(next, $CLOSE_SQUARE_BRACKET)) { - return appendEndGroup(CLOSE_SQUARE_BRACKET_INFO, "]", - OPEN_SQUARE_BRACKET_TOKEN); - } - - if (identical(next, $BACKPING)) { - appendPrecedenceToken(BACKPING_INFO); - return advance(); - } - - if (identical(next, $OPEN_CURLY_BRACKET)) { - appendBeginGroup(OPEN_CURLY_BRACKET_INFO, "{"); - return advance(); - } - - if (identical(next, $CLOSE_CURLY_BRACKET)) { - return appendEndGroup(CLOSE_CURLY_BRACKET_INFO, "}", - OPEN_CURLY_BRACKET_TOKEN); - } - - if (identical(next, $SLASH)) { - return tokenizeSlashOrComment(next); - } - - if (identical(next, $AT)) { - return tokenizeAt(next); - } - - if (identical(next, $DQ) || identical(next, $SQ)) { - return tokenizeString(next, byteOffset, false); - } - - if (identical(next, $PERIOD)) { - return tokenizeDotsOrNumber(next); - } - - if (identical(next, $0)) { - return tokenizeHexOrNumber(next); - } - - // TODO(ahe): Would a range check be faster? - if (identical(next, $1) || identical(next, $2) || identical(next, $3) - || identical(next, $4) || identical(next, $5) || identical(next, $6) - || identical(next, $7) || identical(next, $8) || identical(next, $9)) { - return tokenizeNumber(next); - } - - if (identical(next, $EOF)) { - return $EOF; - } - if (next < 0x1f) { - return error(new SourceString("unexpected character $next")); - } - - // The following are non-ASCII characters. - - if (identical(next, $NBSP)) { - appendWhiteSpace(next); - return advance(); - } - - return tokenizeIdentifier(next, byteOffset, true); - } - - int tokenizeTag(int next) { - // # or #!.*[\n\r] - if (byteOffset == 0) { - if (identical(peek(), $BANG)) { - do { - next = advance(); - } while (!identical(next, $LF) && !identical(next, $CR) && !identical(next, $EOF)); - return next; - } - } - appendPrecedenceToken(HASH_INFO); - return advance(); - } - - int tokenizeTilde(int next) { - // ~ ~/ ~/= - next = advance(); - if (identical(next, $SLASH)) { - return select($EQ, TILDE_SLASH_EQ_INFO, TILDE_SLASH_INFO); - } else { - appendPrecedenceToken(TILDE_INFO); - return next; - } - } - - int tokenizeOpenSquareBracket(int next) { - // [ [] []= - next = advance(); - if (identical(next, $CLOSE_SQUARE_BRACKET)) { - Token token = previousToken(); - if (token is KeywordToken && identical(token.value.stringValue, 'operator')) { - return select($EQ, INDEX_EQ_INFO, INDEX_INFO); - } - } - appendBeginGroup(OPEN_SQUARE_BRACKET_INFO, "["); - return next; - } - - int tokenizeCaret(int next) { - // ^ ^= - return select($EQ, CARET_EQ_INFO, CARET_INFO); - } - - int tokenizeBar(int next) { - // | || |= - next = advance(); - if (identical(next, $BAR)) { - appendPrecedenceToken(BAR_BAR_INFO); - return advance(); - } else if (identical(next, $EQ)) { - appendPrecedenceToken(BAR_EQ_INFO); - return advance(); - } else { - appendPrecedenceToken(BAR_INFO); - return next; - } - } - - int tokenizeAmpersand(int next) { - // && &= & - next = advance(); - if (identical(next, $AMPERSAND)) { - appendPrecedenceToken(AMPERSAND_AMPERSAND_INFO); - return advance(); - } else if (identical(next, $EQ)) { - appendPrecedenceToken(AMPERSAND_EQ_INFO); - return advance(); - } else { - appendPrecedenceToken(AMPERSAND_INFO); - return next; - } - } - - int tokenizePercent(int next) { - // % %= - return select($EQ, PERCENT_EQ_INFO, PERCENT_INFO); - } - - int tokenizeMultiply(int next) { - // * *= - return select($EQ, STAR_EQ_INFO, STAR_INFO); - } - - int tokenizeMinus(int next) { - // - -- -= - next = advance(); - if (identical(next, $MINUS)) { - appendPrecedenceToken(MINUS_MINUS_INFO); - return advance(); - } else if (identical(next, $EQ)) { - appendPrecedenceToken(MINUS_EQ_INFO); - return advance(); - } else { - appendPrecedenceToken(MINUS_INFO); - return next; - } - } - - - int tokenizePlus(int next) { - // + ++ += - next = advance(); - if (identical($PLUS, next)) { - appendPrecedenceToken(PLUS_PLUS_INFO); - return advance(); - } else if (identical($EQ, next)) { - appendPrecedenceToken(PLUS_EQ_INFO); - return advance(); - } else { - appendPrecedenceToken(PLUS_INFO); - return next; - } - } - - int tokenizeExclamation(int next) { - // ! != !== - next = advance(); - if (identical(next, $EQ)) { - return select($EQ, BANG_EQ_EQ_INFO, BANG_EQ_INFO); - } - appendPrecedenceToken(BANG_INFO); - return next; - } - - int tokenizeEquals(int next) { - // = == === - - // Type parameters and arguments cannot contain any token that - // starts with '='. - discardOpenLt(); - - next = advance(); - if (identical(next, $EQ)) { - return select($EQ, EQ_EQ_EQ_INFO, EQ_EQ_INFO); - } else if (identical(next, $GT)) { - appendPrecedenceToken(FUNCTION_INFO); - return advance(); - } - appendPrecedenceToken(EQ_INFO); - return next; - } - - int tokenizeGreaterThan(int next) { - // > >= >> >>= >>> >>>= - next = advance(); - if (identical($EQ, next)) { - appendPrecedenceToken(GT_EQ_INFO); - return advance(); - } else if (identical($GT, next)) { - next = advance(); - if (identical($EQ, next)) { - appendPrecedenceToken(GT_GT_EQ_INFO); - return advance(); - } else { - appendGtGt(GT_GT_INFO, ">>"); - return next; - } - } else { - appendGt(GT_INFO, ">"); - return next; - } - } - - int tokenizeLessThan(int next) { - // < <= << <<= - next = advance(); - if (identical($EQ, next)) { - appendPrecedenceToken(LT_EQ_INFO); - return advance(); - } else if (identical($LT, next)) { - return select($EQ, LT_LT_EQ_INFO, LT_LT_INFO); - } else { - appendBeginGroup(LT_INFO, "<"); - return next; - } - } - - int tokenizeNumber(int next) { - int start = byteOffset; - while (true) { - next = advance(); - if ($0 <= next && next <= $9) { - continue; - } else if (identical(next, $PERIOD)) { - return tokenizeFractionPart(advance(), start); - } else if (identical(next, $e) || identical(next, $E) - || identical(next, $d) || identical(next, $D)) { - return tokenizeFractionPart(next, start); - } else { - appendByteStringToken(INT_INFO, asciiString(start, 0)); - return next; - } - } - } - - int tokenizeHexOrNumber(int next) { - int x = peek(); - if (identical(x, $x) || identical(x, $X)) { - advance(); - return tokenizeHex(x); - } - return tokenizeNumber(next); - } - - int tokenizeHex(int next) { - int start = byteOffset - 1; - bool hasDigits = false; - while (true) { - next = advance(); - if (($0 <= next && next <= $9) - || ($A <= next && next <= $F) - || ($a <= next && next <= $f)) { - hasDigits = true; - } else { - if (!hasDigits) { - return error(const SourceString("hex digit expected")); - } - appendByteStringToken(HEXADECIMAL_INFO, asciiString(start, 0)); - return next; - } - } - } - - int tokenizeDotsOrNumber(int next) { - int start = byteOffset; - next = advance(); - if (($0 <= next && next <= $9)) { - return tokenizeFractionPart(next, start); - } else if (identical($PERIOD, next)) { - return select($PERIOD, PERIOD_PERIOD_PERIOD_INFO, PERIOD_PERIOD_INFO); - } else { - appendPrecedenceToken(PERIOD_INFO); - return next; - } - } - - int tokenizeFractionPart(int next, int start) { - bool done = false; - bool hasDigit = false; - LOOP: while (!done) { - if ($0 <= next && next <= $9) { - hasDigit = true; - } else if (identical($e, next) || identical($E, next)) { - hasDigit = true; - next = tokenizeExponent(advance()); - done = true; - continue LOOP; - } else { - done = true; - continue LOOP; - } - next = advance(); - } - if (!hasDigit) { - appendByteStringToken(INT_INFO, asciiString(start, -1)); - if (identical($PERIOD, next)) { - return select($PERIOD, PERIOD_PERIOD_PERIOD_INFO, PERIOD_PERIOD_INFO); - } - // TODO(ahe): Wrong offset for the period. - appendPrecedenceToken(PERIOD_INFO); - return bigSwitch(next); - } - if (identical(next, $d) || identical(next, $D)) { - next = advance(); - } - appendByteStringToken(DOUBLE_INFO, asciiString(start, 0)); - return next; - } - - int tokenizeExponent(int next) { - if (identical(next, $PLUS) || identical(next, $MINUS)) { - next = advance(); - } - bool hasDigits = false; - while (true) { - if ($0 <= next && next <= $9) { - hasDigits = true; - } else { - if (!hasDigits) { - return error(const SourceString("digit expected")); - } - return next; - } - next = advance(); - } - } - - int tokenizeSlashOrComment(int next) { - next = advance(); - if (identical($STAR, next)) { - return tokenizeMultiLineComment(next); - } else if (identical($SLASH, next)) { - return tokenizeSingleLineComment(next); - } else if (identical($EQ, next)) { - appendPrecedenceToken(SLASH_EQ_INFO); - return advance(); - } else { - appendPrecedenceToken(SLASH_INFO); - return next; - } - } - - int tokenizeSingleLineComment(int next) { - while (true) { - next = advance(); - if (identical($LF, next) || identical($CR, next) || identical($EOF, next)) { - appendComment(); - return next; - } - } - } - - int tokenizeMultiLineComment(int next) { - int nesting = 1; - next = advance(); - while (true) { - if (identical($EOF, next)) { - // TODO(ahe): Report error. - return next; - } else if (identical($STAR, next)) { - next = advance(); - if (identical($SLASH, next)) { - --nesting; - if (0 == nesting) { - next = advance(); - appendComment(); - return next; - } else { - next = advance(); - } - } - } else if (identical($SLASH, next)) { - next = advance(); - if (identical($STAR, next)) { - next = advance(); - ++nesting; - } - } else { - next = advance(); - } - } - } - - int tokenizeRawStringKeywordOrIdentifier(int next) { - int nextnext = peek(); - if (identical(nextnext, $DQ) || identical(nextnext, $SQ)) { - int start = byteOffset; - next = advance(); - return tokenizeString(next, start, true); - } - return tokenizeKeywordOrIdentifier(next, true); - } - - int tokenizeKeywordOrIdentifier(int next, bool allowDollar) { - KeywordState state = KeywordState.KEYWORD_STATE; - int start = byteOffset; - while (state != null && $a <= next && next <= $z) { - state = state.next(next); - next = advance(); - } - if (state == null || state.keyword == null) { - return tokenizeIdentifier(next, start, allowDollar); - } - if (($A <= next && next <= $Z) || - ($0 <= next && next <= $9) || - identical(next, $_) || - identical(next, $$)) { - return tokenizeIdentifier(next, start, allowDollar); - } else if (next < 128) { - appendKeywordToken(state.keyword); - return next; - } else { - return tokenizeIdentifier(next, start, allowDollar); - } - } - - int tokenizeIdentifier(int next, int start, bool allowDollar) { - bool isAscii = true; - - // TODO(aprelev@gmail.com): Remove deprecated Dynamic keyword support. - bool isDynamicBuiltIn = false; - - if (identical(next, $D)) { - next = advance(); - if (identical(next, $y)) { - next = advance(); - if (identical(next, $n)) { - next = advance(); - if (identical(next, $a)) { - next = advance(); - if (identical(next, $m)) { - next = advance(); - if (identical(next, $i)) { - next = advance(); - if (identical(next, $c)) { - isDynamicBuiltIn = true; - next = advance(); - } - } - } - } - } - } - } - - while (true) { - if (($a <= next && next <= $z) || - ($A <= next && next <= $Z) || - ($0 <= next && next <= $9) || - identical(next, $_) || - (identical(next, $$) && allowDollar)) { - isDynamicBuiltIn = false; - next = advance(); - } else if ((next < 128) || (identical(next, $NBSP))) { - // Identifier ends here. - if (start == byteOffset) { - return error(const SourceString("expected identifier")); - } else if (isDynamicBuiltIn) { - appendKeywordToken(Keyword.DYNAMIC_DEPRECATED); - } else if (isAscii) { - appendByteStringToken(IDENTIFIER_INFO, asciiString(start, 0)); - } else { - appendByteStringToken(BAD_INPUT_INFO, utf8String(start, -1)); - } - return next; - } else { - isDynamicBuiltIn = false; - int nonAsciiStart = byteOffset; - do { - next = nextByte(); - if (identical(next, $NBSP)) break; - } while (next > 127); - String string = utf8String(nonAsciiStart, -1).slowToString(); - isAscii = false; - int byteLength = nonAsciiStart - byteOffset; - addToCharOffset(string.length - byteLength); - } - } - } - - int tokenizeAt(int next) { - int start = byteOffset; - next = advance(); - appendPrecedenceToken(AT_INFO); - return next; - } - - int tokenizeString(int next, int start, bool raw) { - int quoteChar = next; - next = advance(); - if (identical(quoteChar, next)) { - next = advance(); - if (identical(quoteChar, next)) { - // Multiline string. - return tokenizeMultiLineString(quoteChar, start, raw); - } else { - // Empty string. - appendByteStringToken(STRING_INFO, utf8String(start, -1)); - return next; - } - } - if (raw) { - return tokenizeSingleLineRawString(next, quoteChar, start); - } else { - return tokenizeSingleLineString(next, quoteChar, start); - } - } - - static bool isHexDigit(int character) { - if ($0 <= character && character <= $9) return true; - character |= 0x20; - return ($a <= character && character <= $f); - } - - int tokenizeSingleLineString(int next, int quoteChar, int start) { - while (!identical(next, quoteChar)) { - if (identical(next, $BACKSLASH)) { - next = advance(); - } else if (identical(next, $$)) { - next = tokenizeStringInterpolation(start); - start = byteOffset; - continue; - } - if (next <= $CR - && (identical(next, $LF) || identical(next, $CR) || identical(next, $EOF))) { - return error(const SourceString("unterminated string literal")); - } - next = advance(); - } - appendByteStringToken(STRING_INFO, utf8String(start, 0)); - return advance(); - } - - int tokenizeStringInterpolation(int start) { - appendByteStringToken(STRING_INFO, utf8String(start, -1)); - beginToken(); // $ starts here. - int next = advance(); - if (identical(next, $OPEN_CURLY_BRACKET)) { - return tokenizeInterpolatedExpression(next, start); - } else { - return tokenizeInterpolatedIdentifier(next, start); - } - } - - int tokenizeInterpolatedExpression(int next, int start) { - appendBeginGroup(STRING_INTERPOLATION_INFO, "\${"); - beginToken(); // The expression starts here. - next = advance(); - while (!identical(next, $EOF) && !identical(next, $STX)) { - next = bigSwitch(next); - } - if (identical(next, $EOF)) return next; - next = advance(); - beginToken(); // The string interpolation suffix starts here. - return next; - } - - int tokenizeInterpolatedIdentifier(int next, int start) { - appendPrecedenceToken(STRING_INTERPOLATION_IDENTIFIER_INFO); - beginToken(); // The identifier starts here. - next = tokenizeKeywordOrIdentifier(next, false); - beginToken(); // The string interpolation suffix starts here. - return next; - } - - int tokenizeSingleLineRawString(int next, int quoteChar, int start) { - next = advance(); - while (next != $EOF) { - if (identical(next, quoteChar)) { - appendByteStringToken(STRING_INFO, utf8String(start, 0)); - return advance(); - } else if (identical(next, $LF) || identical(next, $CR)) { - return error(const SourceString("unterminated string literal")); - } - next = advance(); - } - return error(const SourceString("unterminated string literal")); - } - - int tokenizeMultiLineRawString(int quoteChar, int start) { - int next = advance(); - outer: while (!identical(next, $EOF)) { - while (!identical(next, quoteChar)) { - next = advance(); - if (identical(next, $EOF)) break outer; - } - next = advance(); - if (identical(next, quoteChar)) { - next = advance(); - if (identical(next, quoteChar)) { - appendByteStringToken(STRING_INFO, utf8String(start, 0)); - return advance(); - } - } - } - return error(const SourceString("unterminated string literal")); - } - - int tokenizeMultiLineString(int quoteChar, int start, bool raw) { - if (raw) return tokenizeMultiLineRawString(quoteChar, start); - int next = advance(); - while (!identical(next, $EOF)) { - if (identical(next, $$)) { - next = tokenizeStringInterpolation(start); - start = byteOffset; - continue; - } - if (identical(next, quoteChar)) { - next = advance(); - if (identical(next, quoteChar)) { - next = advance(); - if (identical(next, quoteChar)) { - appendByteStringToken(STRING_INFO, utf8String(start, 0)); - return advance(); - } - } - continue; - } - if (identical(next, $BACKSLASH)) { - next = advance(); - if (identical(next, $EOF)) break; - } - next = advance(); - } - return error(const SourceString("unterminated string literal")); - } - - int error(SourceString message) { - appendByteStringToken(BAD_INPUT_INFO, message); - return advance(); // Ensure progress. - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/scanner_implementation.dart b/pkgs/markdown/test/lib/src/compiler/implementation/scanner/scanner_implementation.dart deleted file mode 100644 index 1bd8327..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/scanner_implementation.dart +++ /dev/null
@@ -1,11 +0,0 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library scanner_implementation; - -import 'scannerlib.dart'; -import '../util/util.dart'; -import '../util/characters.dart'; - -part 'array_based_scanner.dart';
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/scanner_task.dart b/pkgs/markdown/test/lib/src/compiler/implementation/scanner/scanner_task.dart deleted file mode 100644 index 0738355..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/scanner_task.dart +++ /dev/null
@@ -1,53 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of scanner; - -class ScannerTask extends CompilerTask { - ScannerTask(Compiler compiler) : super(compiler); - String get name => 'Scanner'; - - void scanLibrary(LibraryElement library) { - var compilationUnit = library.entryCompilationUnit; - var canonicalUri = library.canonicalUri.toString(); - var resolvedUri = compilationUnit.script.uri.toString(); - if (canonicalUri == resolvedUri) { - compiler.log("scanning library $canonicalUri"); - } else { - compiler.log("scanning library $canonicalUri ($resolvedUri)"); - } - scan(compilationUnit); - } - - void scan(CompilationUnitElement compilationUnit) { - measure(() { - scanElements(compilationUnit); - }); - } - - void scanElements(CompilationUnitElement compilationUnit) { - Script script = compilationUnit.script; - Token tokens = new StringScanner(script.text, - includeComments: compiler.preserveComments).tokenize(); - if (compiler.preserveComments) { - tokens = compiler.processAndStripComments(tokens); - } - compiler.dietParser.dietParse(compilationUnit, tokens); - } -} - -class DietParserTask extends CompilerTask { - DietParserTask(Compiler compiler) : super(compiler); - final String name = 'Diet Parser'; - - dietParse(CompilationUnitElement compilationUnit, Token tokens) { - measure(() { - Function idGenerator = compiler.getNextFreeClassId; - ElementListener listener = - new ElementListener(compiler, compilationUnit, idGenerator); - PartialParser parser = new PartialParser(listener); - parser.parseUnit(tokens); - }); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/scannerlib.dart b/pkgs/markdown/test/lib/src/compiler/implementation/scanner/scannerlib.dart deleted file mode 100644 index e3cd591..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/scannerlib.dart +++ /dev/null
@@ -1,38 +0,0 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library scanner; - -import 'dart:collection' show LinkedHashMap; -import 'dart:uri'; - -import 'scanner_implementation.dart'; -import '../elements/elements.dart'; -import '../elements/modelx.dart' - show FunctionElementX, - TypedefElementX, - VariableElementX, - VariableListElementX, - ClassElementX, - MetadataAnnotationX, - MixinApplicationElementX; -import '../dart2jslib.dart'; -import '../native_handler.dart' as native; -import '../string_validator.dart'; -import '../tree/tree.dart'; -import '../util/characters.dart'; -import '../util/util.dart'; -// TODO(ahe): Rename prefix to 'api' when VM bug is fixed. -import '../../compiler.dart' as api_s; - -part 'class_element_parser.dart'; -part 'keyword.dart'; -part 'listener.dart'; -part 'parser.dart'; -part 'parser_task.dart'; -part 'partial_parser.dart'; -part 'scanner.dart'; -part 'scanner_task.dart'; -part 'string_scanner.dart'; -part 'token.dart';
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/string_scanner.dart b/pkgs/markdown/test/lib/src/compiler/implementation/scanner/string_scanner.dart deleted file mode 100644 index 0fa3489..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/string_scanner.dart +++ /dev/null
@@ -1,106 +0,0 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of scanner; - -/** - * Scanner that reads from a String and creates tokens that points to - * substrings. - */ -class StringScanner extends ArrayBasedScanner<SourceString> { - final String string; - - StringScanner(String this.string, {bool includeComments: false}) - : super(includeComments); - - int nextByte() => charAt(++byteOffset); - - int peek() => charAt(byteOffset + 1); - - int charAt(index) - => (string.length > index) ? string.charCodeAt(index) : $EOF; - - SourceString asciiString(int start, int offset) { - return new SubstringWrapper(string, start, byteOffset + offset); - } - - SourceString utf8String(int start, int offset) { - return new SubstringWrapper(string, start, byteOffset + offset + 1); - } - - void appendByteStringToken(PrecedenceInfo info, SourceString value) { - // assert(kind != $a || keywords.get(value) == null); - tail.next = new StringToken.fromSource(info, value, tokenStart); - tail = tail.next; - } - - void unmatchedBeginGroup(BeginGroupToken begin) { - SourceString error = new SourceString('unmatched "${begin.stringValue}"'); - Token close = - new StringToken.fromSource(BAD_INPUT_INFO, error, begin.charOffset); - // We want to ensure that unmatched BeginGroupTokens are reported - // as errors. However, the rest of the parser assume the groups - // are well-balanced and will never look at the endGroup - // token. This is a nice property that allows us to skip quickly - // over correct code. By inserting an additional error token in - // the stream, we can keep ignoring endGroup tokens. - Token next = - new StringToken.fromSource(BAD_INPUT_INFO, error, begin.charOffset); - begin.endGroup = close; - close.next = next; - next.next = begin.next; - } -} - -class SubstringWrapper extends Iterable<int> implements SourceString { - final String internalString; - final int begin; - final int end; - int cashedHash = 0; - String cachedSubString; - - SubstringWrapper(String this.internalString, - int this.begin, int this.end); - - int get hashCode { - if (0 == cashedHash) { - cashedHash = slowToString().hashCode; - } - return cashedHash; - } - - bool operator ==(other) { - return other is SourceString && slowToString() == other.slowToString(); - } - - void printOn(StringBuffer sb) { - sb.add(internalString.substring(begin, end)); - } - - String slowToString() { - if (cachedSubString == null) { - cachedSubString = internalString.substring(begin, end); - } - return cachedSubString; - } - - String toString() => "SubstringWrapper(${slowToString()})"; - - String get stringValue => null; - - Iterator<int> get iterator => - new StringCodeIterator.substring(internalString, begin, end); - - SourceString copyWithoutQuotes(int initial, int terminal) { - assert(0 <= initial); - assert(0 <= terminal); - assert(initial + terminal <= internalString.length); - return new SubstringWrapper(internalString, - begin + initial, end - terminal); - } - - bool get isEmpty => begin == end; - - bool isPrivate() => !isEmpty && identical(internalString.charCodeAt(begin), $_); -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/token.dart b/pkgs/markdown/test/lib/src/compiler/implementation/scanner/token.dart deleted file mode 100644 index a236eae..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/scanner/token.dart +++ /dev/null
@@ -1,530 +0,0 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of scanner; - -const int EOF_TOKEN = 0; - -const int KEYWORD_TOKEN = $k; -const int IDENTIFIER_TOKEN = $a; -const int BAD_INPUT_TOKEN = $X; -const int DOUBLE_TOKEN = $d; -const int INT_TOKEN = $i; -const int HEXADECIMAL_TOKEN = $x; -const int STRING_TOKEN = $SQ; - -const int AMPERSAND_TOKEN = $AMPERSAND; -const int BACKPING_TOKEN = $BACKPING; -const int BACKSLASH_TOKEN = $BACKSLASH; -const int BANG_TOKEN = $BANG; -const int BAR_TOKEN = $BAR; -const int COLON_TOKEN = $COLON; -const int COMMA_TOKEN = $COMMA; -const int EQ_TOKEN = $EQ; -const int GT_TOKEN = $GT; -const int HASH_TOKEN = $HASH; -const int OPEN_CURLY_BRACKET_TOKEN = $OPEN_CURLY_BRACKET; -const int OPEN_SQUARE_BRACKET_TOKEN = $OPEN_SQUARE_BRACKET; -const int OPEN_PAREN_TOKEN = $OPEN_PAREN; -const int LT_TOKEN = $LT; -const int MINUS_TOKEN = $MINUS; -const int PERIOD_TOKEN = $PERIOD; -const int PLUS_TOKEN = $PLUS; -const int QUESTION_TOKEN = $QUESTION; -const int AT_TOKEN = $AT; -const int CLOSE_CURLY_BRACKET_TOKEN = $CLOSE_CURLY_BRACKET; -const int CLOSE_SQUARE_BRACKET_TOKEN = $CLOSE_SQUARE_BRACKET; -const int CLOSE_PAREN_TOKEN = $CLOSE_PAREN; -const int SEMICOLON_TOKEN = $SEMICOLON; -const int SLASH_TOKEN = $SLASH; -const int TILDE_TOKEN = $TILDE; -const int STAR_TOKEN = $STAR; -const int PERCENT_TOKEN = $PERCENT; -const int CARET_TOKEN = $CARET; - -const int STRING_INTERPOLATION_TOKEN = 128; -const int LT_EQ_TOKEN = STRING_INTERPOLATION_TOKEN + 1; -const int FUNCTION_TOKEN = LT_EQ_TOKEN + 1; -const int SLASH_EQ_TOKEN = FUNCTION_TOKEN + 1; -const int PERIOD_PERIOD_PERIOD_TOKEN = SLASH_EQ_TOKEN + 1; -const int PERIOD_PERIOD_TOKEN = PERIOD_PERIOD_PERIOD_TOKEN + 1; -const int EQ_EQ_EQ_TOKEN = PERIOD_PERIOD_TOKEN + 1; -const int EQ_EQ_TOKEN = EQ_EQ_EQ_TOKEN + 1; -const int LT_LT_EQ_TOKEN = EQ_EQ_TOKEN + 1; -const int LT_LT_TOKEN = LT_LT_EQ_TOKEN + 1; -const int GT_EQ_TOKEN = LT_LT_TOKEN + 1; -const int GT_GT_EQ_TOKEN = GT_EQ_TOKEN + 1; -const int INDEX_EQ_TOKEN = GT_GT_EQ_TOKEN + 1; -const int INDEX_TOKEN = INDEX_EQ_TOKEN + 1; -const int BANG_EQ_EQ_TOKEN = INDEX_TOKEN + 1; -const int BANG_EQ_TOKEN = BANG_EQ_EQ_TOKEN + 1; -const int AMPERSAND_AMPERSAND_TOKEN = BANG_EQ_TOKEN + 1; -const int AMPERSAND_EQ_TOKEN = AMPERSAND_AMPERSAND_TOKEN + 1; -const int BAR_BAR_TOKEN = AMPERSAND_EQ_TOKEN + 1; -const int BAR_EQ_TOKEN = BAR_BAR_TOKEN + 1; -const int STAR_EQ_TOKEN = BAR_EQ_TOKEN + 1; -const int PLUS_PLUS_TOKEN = STAR_EQ_TOKEN + 1; -const int PLUS_EQ_TOKEN = PLUS_PLUS_TOKEN + 1; -const int MINUS_MINUS_TOKEN = PLUS_EQ_TOKEN + 1; -const int MINUS_EQ_TOKEN = MINUS_MINUS_TOKEN + 1; -const int TILDE_SLASH_EQ_TOKEN = MINUS_EQ_TOKEN + 1; -const int TILDE_SLASH_TOKEN = TILDE_SLASH_EQ_TOKEN + 1; -const int PERCENT_EQ_TOKEN = TILDE_SLASH_TOKEN + 1; -const int GT_GT_TOKEN = PERCENT_EQ_TOKEN + 1; -const int CARET_EQ_TOKEN = GT_GT_TOKEN + 1; -const int COMMENT_TOKEN = CARET_EQ_TOKEN + 1; -const int STRING_INTERPOLATION_IDENTIFIER_TOKEN = COMMENT_TOKEN + 1; - -// TODO(ahe): Get rid of this. -const int UNKNOWN_TOKEN = 1024; - -/** - * A token that doubles as a linked list. - */ -class Token implements Spannable { - /** - * The precedence info for this token. [info] determines the kind and the - * precedence level of this token. - */ - final PrecedenceInfo info; - - /** - * The character offset of the start of this token within the source text. - */ - final int charOffset; - - /** - * The next token in the token stream. - */ - Token next; - - Token(PrecedenceInfo this.info, int this.charOffset); - - get value => info.value; - - /** - * Returns the string value for keywords and symbols. For instance 'class' for - * the [CLASS] keyword token and '*' for a [Token] based on [STAR_INFO]. For - * other tokens, such identifiers, strings, numbers, etc, [stringValue] - * returns [:null:]. - * - * [stringValue] should only be used for testing keywords and symbols. - */ - String get stringValue => info.value.stringValue; - - /** - * The kind enum of this token as determined by its [info]. - */ - int get kind => info.kind; - - /** - * The precedence level for this token. - */ - int get precedence => info.precedence; - - bool isIdentifier() => identical(kind, IDENTIFIER_TOKEN); - - /** - * Returns a textual representation of this token to be used for debugging - * purposes. The resulting string might contain information about the - * structure of the token, for example 'StringToken(foo)' for the identifier - * token 'foo'. Use [slowToString] for the text actually parsed by the token. - */ - String toString() => info.value.toString(); - - /** - * The text parsed by this token. - */ - String slowToString() => toString(); - - /** - * The number of characters parsed by this token. - */ - int get slowCharCount { - if (info == BAD_INPUT_INFO) { - // This is a token that wraps around an error message. Return 1 - // instead of the size of the length of the error message. - return 1; - } else { - return slowToString().length; - } - } -} - -/** - * A keyword token. - */ -class KeywordToken extends Token { - final Keyword value; - String get stringValue => value.syntax; - - KeywordToken(Keyword value, int charOffset) - : this.value = value, super(value.info, charOffset); - - bool isIdentifier() => value.isPseudo || value.isBuiltIn; - - String toString() => value.syntax; -} - -/** - * A String-valued token. - */ -class StringToken extends Token { - final SourceString value; - String get stringValue => value.stringValue; - - StringToken(PrecedenceInfo info, String value, int charOffset) - : this.fromSource(info, new SourceString(value), charOffset); - - StringToken.fromSource(PrecedenceInfo info, this.value, int charOffset) - : super(info, charOffset); - - String toString() => "StringToken(${value.slowToString()})"; - - String slowToString() => value.slowToString(); -} - -abstract class SourceString extends Iterable<int> { - const factory SourceString(String string) = StringWrapper; - - void printOn(StringBuffer sb); - - /** Gives a [SourceString] that is not including the [initial] first and - * [terminal] last characters. This is only intended to be used to remove - * quotes from string literals (including an initial '@' for raw strings). - */ - SourceString copyWithoutQuotes(int initial, int terminal); - - String get stringValue; - - String slowToString(); - - bool get isEmpty; - - bool isPrivate(); -} - -class StringWrapper extends Iterable<int> implements SourceString { - final String stringValue; - - const StringWrapper(String this.stringValue); - - int get hashCode => stringValue.hashCode; - - bool operator ==(other) { - return other is SourceString && toString() == other.slowToString(); - } - - Iterator<int> get iterator => new StringCodeIterator(stringValue); - - void printOn(StringBuffer sb) { - sb.add(stringValue); - } - - String toString() => stringValue; - - String slowToString() => stringValue; - - SourceString copyWithoutQuotes(int initial, int terminal) { - assert(0 <= initial); - assert(0 <= terminal); - assert(initial + terminal <= stringValue.length); - return new StringWrapper( - stringValue.substring(initial, stringValue.length - terminal)); - } - - bool get isEmpty => stringValue.isEmpty; - - bool isPrivate() => !isEmpty && identical(stringValue.charCodeAt(0), $_); -} - -class StringCodeIterator implements Iterator<int> { - final String string; - int index; - final int end; - int _current; - - StringCodeIterator(String string) : - this.string = string, index = 0, end = string.length; - - StringCodeIterator.substring(this.string, this.index, this.end) { - assert(0 <= index); - assert(index <= end); - assert(end <= string.length); - } - - int get current => _current; - - bool moveNext() { - _current = null; - if (index >= end) return false; - _current = string.charCodeAt(index++); - return true; - } -} - -class BeginGroupToken extends StringToken { - Token endGroup; - BeginGroupToken(PrecedenceInfo info, String value, int charOffset) - : super(info, value, charOffset); -} - -bool isUserDefinableOperator(String value) { - return - isBinaryOperator(value) || - isMinusOperator(value) || - isTernaryOperator(value) || - isUnaryOperator(value); -} - -bool isUnaryOperator(String value) => identical(value, '~'); - -bool isBinaryOperator(String value) { - return - (identical(value, '==')) || - (identical(value, '[]')) || - (identical(value, '*')) || - (identical(value, '/')) || - (identical(value, '%')) || - (identical(value, '~/')) || - (identical(value, '+')) || - (identical(value, '<<')) || - (identical(value, '>>')) || - (identical(value, '>=')) || - (identical(value, '>')) || - (identical(value, '<=')) || - (identical(value, '<')) || - (identical(value, '&')) || - (identical(value, '^')) || - (identical(value, '|')); -} - -bool isTernaryOperator(String value) => identical(value, '[]='); - -bool isMinusOperator(String value) => identical(value, '-'); - -class PrecedenceInfo { - final SourceString value; - final int precedence; - final int kind; - - const PrecedenceInfo(this.value, this.precedence, this.kind); - - toString() => 'PrecedenceInfo($value, $precedence, $kind)'; -} - -// TODO(ahe): The following are not tokens in Dart. -const PrecedenceInfo BACKPING_INFO = - const PrecedenceInfo(const SourceString('`'), 0, BACKPING_TOKEN); -const PrecedenceInfo BACKSLASH_INFO = - const PrecedenceInfo(const SourceString('\\'), 0, BACKSLASH_TOKEN); -const PrecedenceInfo PERIOD_PERIOD_PERIOD_INFO = - const PrecedenceInfo(const SourceString('...'), 0, - PERIOD_PERIOD_PERIOD_TOKEN); - -/** - * The cascade operator has the lowest precedence of any operator - * except assignment. - */ -const int CASCADE_PRECEDENCE = 2; -const PrecedenceInfo PERIOD_PERIOD_INFO = - const PrecedenceInfo(const SourceString('..'), CASCADE_PRECEDENCE, - PERIOD_PERIOD_TOKEN); - -const PrecedenceInfo BANG_INFO = - const PrecedenceInfo(const SourceString('!'), 0, BANG_TOKEN); -const PrecedenceInfo COLON_INFO = - const PrecedenceInfo(const SourceString(':'), 0, COLON_TOKEN); -const PrecedenceInfo INDEX_INFO = - const PrecedenceInfo(const SourceString('[]'), 0, INDEX_TOKEN); -const PrecedenceInfo MINUS_MINUS_INFO = - const PrecedenceInfo(const SourceString('--'), POSTFIX_PRECEDENCE, - MINUS_MINUS_TOKEN); -const PrecedenceInfo PLUS_PLUS_INFO = - const PrecedenceInfo(const SourceString('++'), POSTFIX_PRECEDENCE, - PLUS_PLUS_TOKEN); -const PrecedenceInfo TILDE_INFO = - const PrecedenceInfo(const SourceString('~'), 0, TILDE_TOKEN); - -const PrecedenceInfo FUNCTION_INFO = - const PrecedenceInfo(const SourceString('=>'), 0, FUNCTION_TOKEN); -const PrecedenceInfo HASH_INFO = - const PrecedenceInfo(const SourceString('#'), 0, HASH_TOKEN); -const PrecedenceInfo INDEX_EQ_INFO = - const PrecedenceInfo(const SourceString('[]='), 0, INDEX_EQ_TOKEN); -const PrecedenceInfo SEMICOLON_INFO = - const PrecedenceInfo(const SourceString(';'), 0, SEMICOLON_TOKEN); -const PrecedenceInfo COMMA_INFO = - const PrecedenceInfo(const SourceString(','), 0, COMMA_TOKEN); - -const PrecedenceInfo AT_INFO = - const PrecedenceInfo(const SourceString('@'), 0, AT_TOKEN); - -// Assignment operators. -const int ASSIGNMENT_PRECEDENCE = 1; -const PrecedenceInfo AMPERSAND_EQ_INFO = - const PrecedenceInfo(const SourceString('&='), - ASSIGNMENT_PRECEDENCE, AMPERSAND_EQ_TOKEN); -const PrecedenceInfo BAR_EQ_INFO = - const PrecedenceInfo(const SourceString('|='), - ASSIGNMENT_PRECEDENCE, BAR_EQ_TOKEN); -const PrecedenceInfo CARET_EQ_INFO = - const PrecedenceInfo(const SourceString('^='), - ASSIGNMENT_PRECEDENCE, CARET_EQ_TOKEN); -const PrecedenceInfo EQ_INFO = - const PrecedenceInfo(const SourceString('='), - ASSIGNMENT_PRECEDENCE, EQ_TOKEN); -const PrecedenceInfo GT_GT_EQ_INFO = - const PrecedenceInfo(const SourceString('>>='), - ASSIGNMENT_PRECEDENCE, GT_GT_EQ_TOKEN); -const PrecedenceInfo LT_LT_EQ_INFO = - const PrecedenceInfo(const SourceString('<<='), - ASSIGNMENT_PRECEDENCE, LT_LT_EQ_TOKEN); -const PrecedenceInfo MINUS_EQ_INFO = - const PrecedenceInfo(const SourceString('-='), - ASSIGNMENT_PRECEDENCE, MINUS_EQ_TOKEN); -const PrecedenceInfo PERCENT_EQ_INFO = - const PrecedenceInfo(const SourceString('%='), - ASSIGNMENT_PRECEDENCE, PERCENT_EQ_TOKEN); -const PrecedenceInfo PLUS_EQ_INFO = - const PrecedenceInfo(const SourceString('+='), - ASSIGNMENT_PRECEDENCE, PLUS_EQ_TOKEN); -const PrecedenceInfo SLASH_EQ_INFO = - const PrecedenceInfo(const SourceString('/='), - ASSIGNMENT_PRECEDENCE, SLASH_EQ_TOKEN); -const PrecedenceInfo STAR_EQ_INFO = - const PrecedenceInfo(const SourceString('*='), - ASSIGNMENT_PRECEDENCE, STAR_EQ_TOKEN); -const PrecedenceInfo TILDE_SLASH_EQ_INFO = - const PrecedenceInfo(const SourceString('~/='), - ASSIGNMENT_PRECEDENCE, TILDE_SLASH_EQ_TOKEN); - -const PrecedenceInfo QUESTION_INFO = - const PrecedenceInfo(const SourceString('?'), 3, QUESTION_TOKEN); - -const PrecedenceInfo BAR_BAR_INFO = - const PrecedenceInfo(const SourceString('||'), 4, BAR_BAR_TOKEN); - -const PrecedenceInfo AMPERSAND_AMPERSAND_INFO = - const PrecedenceInfo(const SourceString('&&'), 5, AMPERSAND_AMPERSAND_TOKEN); - -const PrecedenceInfo BAR_INFO = - const PrecedenceInfo(const SourceString('|'), 6, BAR_TOKEN); - -const PrecedenceInfo CARET_INFO = - const PrecedenceInfo(const SourceString('^'), 7, CARET_TOKEN); - -const PrecedenceInfo AMPERSAND_INFO = - const PrecedenceInfo(const SourceString('&'), 8, AMPERSAND_TOKEN); - -// Equality operators. -const PrecedenceInfo BANG_EQ_EQ_INFO = - const PrecedenceInfo(const SourceString('!=='), 9, BANG_EQ_EQ_TOKEN); -const PrecedenceInfo BANG_EQ_INFO = - const PrecedenceInfo(const SourceString('!='), 9, BANG_EQ_TOKEN); -const PrecedenceInfo EQ_EQ_EQ_INFO = - const PrecedenceInfo(const SourceString('==='), 9, EQ_EQ_EQ_TOKEN); -const PrecedenceInfo EQ_EQ_INFO = - const PrecedenceInfo(const SourceString('=='), 9, EQ_EQ_TOKEN); - -// Relational operators. -const PrecedenceInfo GT_EQ_INFO = - const PrecedenceInfo(const SourceString('>='), 10, GT_EQ_TOKEN); -const PrecedenceInfo GT_INFO = - const PrecedenceInfo(const SourceString('>'), 10, GT_TOKEN); -const PrecedenceInfo IS_INFO = - const PrecedenceInfo(const SourceString('is'), 10, KEYWORD_TOKEN); -const PrecedenceInfo AS_INFO = - const PrecedenceInfo(const SourceString('as'), 10, KEYWORD_TOKEN); -const PrecedenceInfo LT_EQ_INFO = - const PrecedenceInfo(const SourceString('<='), 10, LT_EQ_TOKEN); -const PrecedenceInfo LT_INFO = - const PrecedenceInfo(const SourceString('<'), 10, LT_TOKEN); - -// Shift operators. -const PrecedenceInfo GT_GT_INFO = - const PrecedenceInfo(const SourceString('>>'), 11, GT_GT_TOKEN); -const PrecedenceInfo LT_LT_INFO = - const PrecedenceInfo(const SourceString('<<'), 11, LT_LT_TOKEN); - -// Additive operators. -const PrecedenceInfo MINUS_INFO = - const PrecedenceInfo(const SourceString('-'), 12, MINUS_TOKEN); -const PrecedenceInfo PLUS_INFO = - const PrecedenceInfo(const SourceString('+'), 12, PLUS_TOKEN); - -// Multiplicative operators. -const PrecedenceInfo PERCENT_INFO = - const PrecedenceInfo(const SourceString('%'), 13, PERCENT_TOKEN); -const PrecedenceInfo SLASH_INFO = - const PrecedenceInfo(const SourceString('/'), 13, SLASH_TOKEN); -const PrecedenceInfo STAR_INFO = - const PrecedenceInfo(const SourceString('*'), 13, STAR_TOKEN); -const PrecedenceInfo TILDE_SLASH_INFO = - const PrecedenceInfo(const SourceString('~/'), 13, TILDE_SLASH_TOKEN); - -const int POSTFIX_PRECEDENCE = 14; -const PrecedenceInfo PERIOD_INFO = - const PrecedenceInfo(const SourceString('.'), POSTFIX_PRECEDENCE, - PERIOD_TOKEN); - -const PrecedenceInfo KEYWORD_INFO = - const PrecedenceInfo(const SourceString('keyword'), 0, KEYWORD_TOKEN); - -const PrecedenceInfo EOF_INFO = - const PrecedenceInfo(const SourceString('EOF'), 0, EOF_TOKEN); - -const PrecedenceInfo IDENTIFIER_INFO = - const PrecedenceInfo(const SourceString('identifier'), 0, IDENTIFIER_TOKEN); - -const PrecedenceInfo BAD_INPUT_INFO = - const PrecedenceInfo(const SourceString('malformed input'), 0, - BAD_INPUT_TOKEN); - -const PrecedenceInfo OPEN_PAREN_INFO = - const PrecedenceInfo(const SourceString('('), POSTFIX_PRECEDENCE, - OPEN_PAREN_TOKEN); - -const PrecedenceInfo CLOSE_PAREN_INFO = - const PrecedenceInfo(const SourceString(')'), 0, CLOSE_PAREN_TOKEN); - -const PrecedenceInfo OPEN_CURLY_BRACKET_INFO = - const PrecedenceInfo(const SourceString('{'), 0, OPEN_CURLY_BRACKET_TOKEN); - -const PrecedenceInfo CLOSE_CURLY_BRACKET_INFO = - const PrecedenceInfo(const SourceString('}'), 0, CLOSE_CURLY_BRACKET_TOKEN); - -const PrecedenceInfo INT_INFO = - const PrecedenceInfo(const SourceString('int'), 0, INT_TOKEN); - -const PrecedenceInfo STRING_INFO = - const PrecedenceInfo(const SourceString('string'), 0, STRING_TOKEN); - -const PrecedenceInfo OPEN_SQUARE_BRACKET_INFO = - const PrecedenceInfo(const SourceString('['), POSTFIX_PRECEDENCE, - OPEN_SQUARE_BRACKET_TOKEN); - -const PrecedenceInfo CLOSE_SQUARE_BRACKET_INFO = - const PrecedenceInfo(const SourceString(']'), 0, CLOSE_SQUARE_BRACKET_TOKEN); - -const PrecedenceInfo DOUBLE_INFO = - const PrecedenceInfo(const SourceString('double'), 0, DOUBLE_TOKEN); - -const PrecedenceInfo STRING_INTERPOLATION_INFO = - const PrecedenceInfo(const SourceString('\${'), 0, - STRING_INTERPOLATION_TOKEN); - -const PrecedenceInfo STRING_INTERPOLATION_IDENTIFIER_INFO = - const PrecedenceInfo(const SourceString('\$'), 0, - STRING_INTERPOLATION_IDENTIFIER_TOKEN); - -const PrecedenceInfo HEXADECIMAL_INFO = - const PrecedenceInfo(const SourceString('hexadecimal'), 0, HEXADECIMAL_TOKEN); - -const PrecedenceInfo COMMENT_INFO = - const PrecedenceInfo(const SourceString('comment'), 0, COMMENT_TOKEN); - -// For reporting lexical errors. -const PrecedenceInfo ERROR_INFO = - const PrecedenceInfo(const SourceString('?'), 0, UNKNOWN_TOKEN);
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/script.dart b/pkgs/markdown/test/lib/src/compiler/implementation/script.dart deleted file mode 100644 index b130616..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/script.dart +++ /dev/null
@@ -1,24 +0,0 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of dart2js; - -class Script { - // TODO(kasperl): Once MockFile in tests/compiler/dart2js/parser_helper.dart - // implements SourceFile, we should be able to type the [file] field as - // such. - final file; - - /** - * The readable URI from which this script was loaded. - * - * See [LibraryLoader] for terminology on URIs. - */ - final Uri uri; - - Script(this.uri, this.file); - - String get text => (file == null) ? null : file.text; - String get name => (file == null) ? null : file.filename; -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/source_file.dart b/pkgs/markdown/test/lib/src/compiler/implementation/source_file.dart deleted file mode 100644 index 14a4175..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/source_file.dart +++ /dev/null
@@ -1,105 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library source_file; - -import 'dart:math'; - -import 'colors.dart' as colors; - -/** - * Represents a file of source code. - */ -class SourceFile { - - /** The name of the file. */ - final String filename; - - /** The text content of the file. */ - final String text; - - List<int> _lineStarts; - - SourceFile(this.filename, this.text); - - List<int> get lineStarts { - if (_lineStarts == null) { - var starts = [0]; - var index = 0; - while (index < text.length) { - index = text.indexOf('\n', index) + 1; - if (index <= 0) break; - starts.add(index); - } - starts.add(text.length + 1); - _lineStarts = starts; - } - return _lineStarts; - } - - int getLine(int position) { - List<int> starts = lineStarts; - if (position < 0 || starts.last <= position) { - throw 'bad position #$position in file $filename with ' - 'length ${text.length}.'; - } - int first = 0; - int count = starts.length; - while (count > 1) { - int step = count ~/ 2; - int middle = first + step; - int lineStart = starts[middle]; - if (position < lineStart) { - count = step; - } else { - first = middle; - count -= step; - } - } - return first; - } - - int getColumn(int line, int position) { - return position - lineStarts[line]; - } - - /** - * Create a pretty string representation from a character position - * in the file. - */ - String getLocationMessage(String message, int start, int end, - bool includeText, String color(String x)) { - var line = getLine(start); - var column = getColumn(line, start); - - var buf = new StringBuffer( - '${filename}:${line + 1}:${column + 1}: $message'); - if (includeText) { - buf.add('\n'); - var textLine; - // +1 for 0-indexing, +1 again to avoid the last line of the file - if ((line + 2) < _lineStarts.length) { - textLine = text.substring(_lineStarts[line], _lineStarts[line+1]); - } else { - textLine = '${text.substring(_lineStarts[line])}\n'; - } - - int toColumn = min(column + (end-start), textLine.length); - buf.add(textLine.substring(0, column)); - buf.add(color(textLine.substring(column, toColumn))); - buf.add(textLine.substring(toColumn)); - - int i = 0; - for (; i < column; i++) { - buf.add(' '); - } - - for (; i < toColumn; i++) { - buf.add(color('^')); - } - } - - return buf.toString(); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/source_file_provider.dart b/pkgs/markdown/test/lib/src/compiler/implementation/source_file_provider.dart deleted file mode 100644 index c100694..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/source_file_provider.dart +++ /dev/null
@@ -1,125 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library source_file_provider; - -import 'dart:async'; -import 'dart:uri'; -import 'dart:io'; -import 'dart:utf'; - -import '../compiler.dart' as api show Diagnostic; -import 'dart2js.dart' show AbortLeg; -import 'colors.dart' as colors; -import 'source_file.dart'; -import 'filenames.dart'; -import 'util/uri_extras.dart'; - -String readAll(String filename) { - var file = (new File(filename)).openSync(FileMode.READ); - var length = file.lengthSync(); - var buffer = new List<int>.fixedLength(length); - var bytes = file.readListSync(buffer, 0, length); - file.closeSync(); - return new String.fromCharCodes(new Utf8Decoder(buffer).decodeRest()); -} - -class SourceFileProvider { - bool isWindows = (Platform.operatingSystem == 'windows'); - Uri cwd = getCurrentDirectory(); - Map<String, SourceFile> sourceFiles = <String, SourceFile>{}; - int dartCharactersRead = 0; - - Future<String> readStringFromUri(Uri resourceUri) { - if (resourceUri.scheme != 'file') { - throw new ArgumentError("Unknown scheme in uri '$resourceUri'"); - } - String source; - try { - source = readAll(uriPathToNative(resourceUri.path)); - } on FileIOException catch (ex) { - throw 'Error: Cannot read "${relativize(cwd, resourceUri, isWindows)}" ' - '(${ex.osError}).'; - } - dartCharactersRead += source.length; - sourceFiles[resourceUri.toString()] = - new SourceFile(relativize(cwd, resourceUri, isWindows), source); - return new Future.immediate(source); - } -} - -void silentDiagnosticHandler(Uri uri, int begin, int end, String message, - api.Diagnostic kind) { -} - -class FormattingDiagnosticHandler { - final SourceFileProvider provider; - bool showWarnings = true; - bool verbose = false; - bool isAborting = false; - bool enableColors = false; - bool throwOnError = false; - - final int FATAL = api.Diagnostic.CRASH.ordinal | api.Diagnostic.ERROR.ordinal; - final int INFO = - api.Diagnostic.INFO.ordinal | api.Diagnostic.VERBOSE_INFO.ordinal; - - FormattingDiagnosticHandler(SourceFileProvider this.provider); - - void info(var message, [api.Diagnostic kind = api.Diagnostic.VERBOSE_INFO]) { - if (!verbose && identical(kind, api.Diagnostic.VERBOSE_INFO)) return; - if (enableColors) { - print('${colors.green("info:")} $message'); - } else { - print('info: $message'); - } - } - - void diagnosticHandler(Uri uri, int begin, int end, String message, - api.Diagnostic kind) { - // TODO(ahe): Remove this when source map is handled differently. - if (identical(kind.name, 'source map')) return; - - if (isAborting) return; - isAborting = identical(kind, api.Diagnostic.CRASH); - bool fatal = (kind.ordinal & FATAL) != 0; - bool isInfo = (kind.ordinal & INFO) != 0; - if (isInfo && uri == null && !identical(kind, api.Diagnostic.INFO)) { - info(message, kind); - return; - } - var color; - if (!enableColors) { - color = (x) => x; - } else if (identical(kind, api.Diagnostic.ERROR)) { - color = colors.red; - } else if (identical(kind, api.Diagnostic.WARNING)) { - color = colors.magenta; - } else if (identical(kind, api.Diagnostic.LINT)) { - color = colors.magenta; - } else if (identical(kind, api.Diagnostic.CRASH)) { - color = colors.red; - } else if (identical(kind, api.Diagnostic.INFO)) { - color = colors.green; - } else { - throw 'Unknown kind: $kind (${kind.ordinal})'; - } - if (uri == null) { - assert(fatal); - print(color(message)); - } else if (fatal || showWarnings) { - SourceFile file = provider.sourceFiles[uri.toString()]; - if (file == null) { - throw '$uri: file is null'; - } - print(file.getLocationMessage(color(message), begin, end, true, color)); - } - if (fatal && throwOnError) { - isAborting = true; - throw new AbortLeg(message); - } - } -} - -
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/source_map_builder.dart b/pkgs/markdown/test/lib/src/compiler/implementation/source_map_builder.dart deleted file mode 100644 index a2cd6fc..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/source_map_builder.dart +++ /dev/null
@@ -1,192 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library source_map_builder; - -import 'util/util.dart'; -import 'scanner/scannerlib.dart' show Token; -import 'source_file.dart'; - -class SourceMapBuilder { - static const int VLQ_BASE_SHIFT = 5; - static const int VLQ_BASE_MASK = (1 << 5) - 1; - static const int VLQ_CONTINUATION_BIT = 1 << 5; - static const int VLQ_CONTINUATION_MASK = 1 << 5; - static const String BASE64_DIGITS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn' - 'opqrstuvwxyz0123456789+/'; - - List<SourceMapEntry> entries; - - Map<String, int> sourceUrlMap; - List<String> sourceUrlList; - Map<String, int> sourceNameMap; - List<String> sourceNameList; - - int previousTargetLine; - int previousTargetColumn; - int previousSourceUrlIndex; - int previousSourceLine; - int previousSourceColumn; - int previousSourceNameIndex; - bool firstEntryInLine; - - SourceMapBuilder() { - entries = new List<SourceMapEntry>(); - - sourceUrlMap = new Map<String, int>(); - sourceUrlList = new List<String>(); - sourceNameMap = new Map<String, int>(); - sourceNameList = new List<String>(); - - previousTargetLine = 0; - previousTargetColumn = 0; - previousSourceUrlIndex = 0; - previousSourceLine = 0; - previousSourceColumn = 0; - previousSourceNameIndex = 0; - firstEntryInLine = true; - } - - void addMapping(int targetOffset, SourceFileLocation sourceLocation) { - entries.add(new SourceMapEntry(sourceLocation, targetOffset)); - } - - void printStringListOn(List<String> strings, StringBuffer buffer) { - bool first = true; - buffer.add('['); - for (String string in strings) { - if (!first) buffer.add(','); - buffer.add('"'); - writeJsonEscapedCharsOn(string, buffer); - buffer.add('"'); - first = false; - } - buffer.add(']'); - } - - String build(SourceFile targetFile) { - StringBuffer mappingsBuffer = new StringBuffer(); - entries.forEach((SourceMapEntry entry) => writeEntry(entry, targetFile, - mappingsBuffer)); - StringBuffer buffer = new StringBuffer(); - buffer.add('{\n'); - buffer.add(' "version": 3,\n'); - buffer.add(' "sourceRoot": "",\n'); - buffer.add(' "sources": '); - printStringListOn(sourceUrlList, buffer); - buffer.add(',\n'); - buffer.add(' "names": '); - printStringListOn(sourceNameList, buffer); - buffer.add(',\n'); - buffer.add(' "mappings": "'); - buffer.add(mappingsBuffer); - buffer.add('"\n}\n'); - return buffer.toString(); - } - - void writeEntry(SourceMapEntry entry, SourceFile targetFile, StringBuffer output) { - int targetLine = targetFile.getLine(entry.targetOffset); - int targetColumn = targetFile.getColumn(targetLine, entry.targetOffset); - - if (targetLine > previousTargetLine) { - for (int i = previousTargetLine; i < targetLine; ++i) { - output.add(';'); - } - previousTargetLine = targetLine; - previousTargetColumn = 0; - firstEntryInLine = true; - } - - if (!firstEntryInLine) { - output.add(','); - } - firstEntryInLine = false; - - encodeVLQ(output, targetColumn - previousTargetColumn); - previousTargetColumn = targetColumn; - - if (entry.sourceLocation == null) return; - - String sourceUrl = entry.sourceLocation.getSourceUrl(); - int sourceLine = entry.sourceLocation.getLine(); - int sourceColumn = entry.sourceLocation.getColumn(); - String sourceName = entry.sourceLocation.getSourceName(); - - int sourceUrlIndex = indexOf(sourceUrlList, sourceUrl, sourceUrlMap); - encodeVLQ(output, sourceUrlIndex - previousSourceUrlIndex); - previousSourceUrlIndex = sourceUrlIndex; - - encodeVLQ(output, sourceLine - previousSourceLine); - previousSourceLine = sourceLine; - encodeVLQ(output, sourceColumn - previousSourceColumn); - previousSourceColumn = sourceColumn; - - if (sourceName == null) { - return; - } - - int sourceNameIndex = indexOf(sourceNameList, sourceName, sourceNameMap); - encodeVLQ(output, sourceNameIndex - previousSourceNameIndex); - previousSourceNameIndex = sourceNameIndex; - } - - int indexOf(List<String> list, String value, Map<String, int> map) { - return map.putIfAbsent(value, () { - int index = list.length; - map[value] = index; - list.add(value); - return index; - }); - } - - static void encodeVLQ(StringBuffer output, int value) { - int signBit = 0; - if (value < 0) { - signBit = 1; - value = -value; - } - value = (value << 1) | signBit; - do { - int digit = value & VLQ_BASE_MASK; - value >>= VLQ_BASE_SHIFT; - if (value > 0) { - digit |= VLQ_CONTINUATION_BIT; - } - output.add(BASE64_DIGITS[digit]); - } while (value > 0); - } -} - -class SourceMapEntry { - SourceFileLocation sourceLocation; - int targetOffset; - - SourceMapEntry(this.sourceLocation, this.targetOffset); -} - -class SourceFileLocation { - SourceFile sourceFile; - Token token; - int line; - - SourceFileLocation(this.sourceFile, this.token) { - assert(isValid()); - } - - String getSourceUrl() => sourceFile.filename; - - int getLine() { - if (line == null) line = sourceFile.getLine(token.charOffset); - return line; - } - - int getColumn() => sourceFile.getColumn(getLine(), token.charOffset); - - String getSourceName() { - if (token.isIdentifier()) return token.slowToString(); - return null; - } - - bool isValid() => token.charOffset < sourceFile.text.length; -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/bailout.dart b/pkgs/markdown/test/lib/src/compiler/implementation/ssa/bailout.dart deleted file mode 100644 index 0e10ecf..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/bailout.dart +++ /dev/null
@@ -1,630 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of ssa; - -class BailoutInfo { - int instructionId; - int bailoutId; - BailoutInfo(this.instructionId, this.bailoutId); -} - -/** - * Keeps track of the execution environment for instructions. An - * execution environment contains the SSA instructions that are live. - */ -class Environment { - final Set<HInstruction> lives; - final List<HBasicBlock> loopMarkers; - Environment() : lives = new Set<HInstruction>(), - loopMarkers = new List<HBasicBlock>(); - Environment.from(Environment other) - : lives = new Set<HInstruction>.from(other.lives), - loopMarkers = new List<HBasicBlock>.from(other.loopMarkers); - - void remove(HInstruction instruction) { - lives.remove(instruction); - } - - void add(HInstruction instruction) { - // If the instruction is a check, we add its checked input - // instead. This allows sharing the same environment between - // different type guards. - // - // Also, we don't need to add code motion invariant instructions - // in the live set (because we generate them at use-site), except - // for parameters that are not 'this', which is always passed as - // the receiver. - if (instruction is HCheck) { - add(instruction.checkedInput); - } else if (!instruction.isCodeMotionInvariant() - || (instruction is HParameterValue && instruction is !HThis)) { - lives.add(instruction); - } else { - for (int i = 0, len = instruction.inputs.length; i < len; i++) { - add(instruction.inputs[i]); - } - } - } - - void addAll(Environment other) { - lives.addAll(other.lives); - } - - bool get isEmpty => lives.isEmpty && loopMarkers.isEmpty; -} - - -/** - * Visits the graph in dominator order and inserts TypeGuards in places where - * we consider the guard to be of value. - * - * Might modify the [types] in an inconsistent way. No further analysis should - * rely on them. - */ -class SsaTypeGuardInserter extends HGraphVisitor implements OptimizationPhase { - final Compiler compiler; - final String name = 'SsaTypeGuardInserter'; - final CodegenWorkItem work; - final HTypeMap types; - bool calledInLoop = false; - bool isRecursiveMethod = false; - int stateId = 1; - - SsaTypeGuardInserter(this.compiler, this.work, this.types); - - void visitGraph(HGraph graph) { - isRecursiveMethod = graph.isRecursiveMethod; - calledInLoop = graph.calledInLoop; - work.guards = <HTypeGuard>[]; - visitDominatorTree(graph); - } - - void visitBasicBlock(HBasicBlock block) { - block.forEachPhi(visitInstruction); - - HInstruction instruction = block.first; - while (instruction != null) { - // Note that visitInstruction (from the phis and here) might insert an - // HTypeGuard instruction. We have to skip those. - if (instruction is !HTypeGuard) visitInstruction(instruction); - instruction = instruction.next; - } - } - - // Primitive types that are not null are valuable. These include - // indexable arrays. - bool typeValuable(HType type) { - return type.isPrimitive() && !type.isNull(); - } - - bool get hasTypeGuards => work.guards.length != 0; - - bool typeGuardWouldBeValuable(HInstruction instruction, - HType speculativeType) { - // If the type itself is not valuable, do not generate a guard for it. - if (!typeValuable(speculativeType)) return false; - - // Do not insert a type guard if the instruction has a type - // annotation that disagrees with the speculated type. - Element source = instruction.sourceElement; - if (source != null) { - DartType sourceType = source.computeType(compiler); - DartType speculatedType = speculativeType.computeType(compiler); - JavaScriptBackend backend = compiler.backend; - if (speculatedType != null) { - // Use the num type instead of JSNumber because JSNumber - // is not assignment compatible with int and double, but we - // still want to generate a type guard. - if (speculatedType.element == backend.jsNumberClass) { - speculatedType = compiler.numClass.computeType(compiler); - } - if (!compiler.types.isAssignable(speculatedType, sourceType)) { - return false; - } - } - } - - // Insert type guards for recursive methods. - if (isRecursiveMethod) return true; - - // Insert type guards if there are uses in loops. - bool isNested(HBasicBlock inner, HBasicBlock outer) { - if (identical(inner, outer)) return false; - if (outer == null) return true; - while (inner != null) { - if (identical(inner, outer)) return true; - inner = inner.parentLoopHeader; - } - return false; - } - - // If the instruction is not in a loop then the header will be null. - HBasicBlock currentLoopHeader = instruction.block.enclosingLoopHeader; - for (HInstruction user in instruction.usedBy) { - HBasicBlock userLoopHeader = user.block.enclosingLoopHeader; - if (isNested(userLoopHeader, currentLoopHeader)) return true; - } - - bool isIndexOperatorOnIndexablePrimitive(instruction, types) { - return instruction is HIndex - || (instruction is HInvokeDynamicMethod - && instruction.isIndexOperatorOnIndexablePrimitive(types)); - } - - // To speed up computations on values loaded from arrays, we - // insert type guards for builtin array indexing operations in - // nested loops. Since this can blow up code size quite - // significantly, we only do it if type guards have already been - // inserted for this method. The code size price for an additional - // type guard is much smaller than the first one that causes the - // generation of a bailout method. - if (hasTypeGuards - && isIndexOperatorOnIndexablePrimitive(instruction, types)) { - HBasicBlock loopHeader = instruction.block.enclosingLoopHeader; - if (loopHeader != null && loopHeader.parentLoopHeader != null) { - return true; - } - } - - // If the instruction is used by a phi where a guard would be - // valuable, put the guard on that instruction. - for (HInstruction user in instruction.usedBy) { - if (user is HPhi - && user.block.id > instruction.id - && typeGuardWouldBeValuable(user, speculativeType)) { - return true; - } - } - - // Insert type guards if the method is likely to be called in a - // loop. - return calledInLoop; - } - - bool shouldInsertTypeGuard(HInstruction instruction, - HType speculativeType, - HType computedType) { - if (!speculativeType.isUseful()) return false; - // If the types agree we don't need to check. - if (speculativeType == computedType) return false; - // If a bailout check is more expensive than doing the actual operation - // don't do it either. - return typeGuardWouldBeValuable(instruction, speculativeType); - } - - void visitInstruction(HInstruction instruction) { - HType speculativeType = types[instruction]; - HType computedType = instruction.computeTypeFromInputTypes(types, compiler); - // Currently the type in [types] is the speculative type each instruction - // would like to have. We start by recomputing the type non-speculatively. - // If we add a type guard then the guard will expose the speculative type. - // If we don't add a type guard then this avoids that subsequent - // instructions use the wrong (speculative) type. - // - // Note that just setting the speculative type of the instruction is not - // complete since the type could lead to a phi node which in turn could - // change the speculative type. In this case we might miss some guards we - // would have liked to insert. Most of the time this should however be - // fine, due to dominator-order visiting. - types[instruction] = computedType; - - if (shouldInsertTypeGuard(instruction, speculativeType, computedType)) { - HInstruction insertionPoint; - if (instruction is HPhi) { - insertionPoint = instruction.block.first; - } else if (instruction is HParameterValue) { - // We insert the type guard at the end of the entry block - // because if a parameter is live, it must be kept in the live - // environment. Not doing so would mean we could visit a - // parameter and remove it from the environment before - // visiting a type guard. - insertionPoint = instruction.block.last; - } else { - insertionPoint = instruction.next; - } - // If the previous instruction is also a type guard, then both - // guards have the same environment, and can therefore share the - // same state id. - HBailoutTarget target; - int state; - if (insertionPoint.previous is HTypeGuard) { - HTypeGuard other = insertionPoint.previous; - target = other.bailoutTarget; - } else { - state = stateId++; - target = new HBailoutTarget(state); - insertionPoint.block.addBefore(insertionPoint, target); - } - HTypeGuard guard = new HTypeGuard(speculativeType, instruction, target); - types[guard] = speculativeType; - work.guards.add(guard); - instruction.block.rewrite(instruction, guard); - insertionPoint.block.addBefore(insertionPoint, guard); - } - } -} - -/** - * Computes the environment for each SSA instruction: visits the graph - * in post-dominator order. Removes an instruction from the environment - * and adds its inputs to the environment at the instruction's - * definition. - * - * At the end of the computation, insert type guards in the graph. - */ -class SsaEnvironmentBuilder extends HBaseVisitor implements OptimizationPhase { - final Compiler compiler; - final String name = 'SsaEnvironmentBuilder'; - - final Map<HBailoutTarget, Environment> capturedEnvironments; - final Map<HBasicBlock, Environment> liveInstructions; - Environment environment; - /** - * The set of current loop headers that dominate the current block. - */ - Set<HBasicBlock> loopMarkers; - - SsaEnvironmentBuilder(Compiler this.compiler) - : capturedEnvironments = new Map<HBailoutTarget, Environment>(), - liveInstructions = new Map<HBasicBlock, Environment>(), - loopMarkers = new Set<HBasicBlock>(); - - - void visitGraph(HGraph graph) { - visitPostDominatorTree(graph); - if (!liveInstructions[graph.entry].isEmpty) { - compiler.internalError('Bailout environment computation', - node: compiler.currentElement.parseNode(compiler)); - } - updateLoopMarkers(); - insertCapturedEnvironments(); - } - - void updateLoopMarkers() { - // If the block is a loop header, we need to merge the loop - // header's live instructions into every environment that contains - // the loop marker. - // For example with the following loop (read the example in - // reverse): - // - // while (true) { <-- (4) update the marker with the environment - // use(x); <-- (3) environment = {x} - // bailout; <-- (2) has the marker when computed - // } <-- (1) create a loop marker - // - // The bailout instruction first captures the marker, but it - // will be replaced by the live environment at the loop entry, - // in this case {x}. - capturedEnvironments.forEach((ignoredInstruction, env) { - env.loopMarkers.forEach((HBasicBlock header) { - env.addAll(liveInstructions[header]); - }); - env.loopMarkers.clear(); - }); - } - - void visitBasicBlock(HBasicBlock block) { - environment = new Environment(); - - // Add to the environment the live instructions of its successor, as well as - // the inputs of the phis of the successor that flow from this block. - for (int i = 0; i < block.successors.length; i++) { - HBasicBlock successor = block.successors[i]; - Environment successorEnv = liveInstructions[successor]; - if (successorEnv != null) { - environment.addAll(successorEnv); - } else { - // If we haven't computed the liveInstructions of that successor, we - // know it must be a loop header. - assert(successor.isLoopHeader()); - assert(!block.isLoopHeader()); - loopMarkers.add(successor); - } - - int index = successor.predecessors.indexOf(block); - for (HPhi phi = successor.phis.first; phi != null; phi = phi.next) { - environment.add(phi.inputs[index]); - } - } - - if (block.isLoopHeader()) { - loopMarkers.remove(block); - } - - // If the block is a loop header, we're adding all [loopMarkers] - // after removing it from the list of [loopMarkers], because - // it will just recompute the loop phis. - environment.loopMarkers.addAll(loopMarkers); - - // Iterate over all instructions to remove an instruction from the - // environment and add its inputs. - HInstruction instruction = block.last; - while (instruction != null) { - instruction.accept(this); - instruction = instruction.previous; - } - - // We just remove the phis from the environment. The inputs of the - // phis will be put in the environment of the predecessors. - for (HPhi phi = block.phis.first; phi != null; phi = phi.next) { - environment.remove(phi); - } - - // Finally save the liveInstructions of that block. - liveInstructions[block] = environment; - } - - void visitBailoutTarget(HBailoutTarget target) { - visitInstruction(target); - capturedEnvironments[target] = new Environment.from(environment); - } - - void visitInstruction(HInstruction instruction) { - environment.remove(instruction); - for (int i = 0, len = instruction.inputs.length; i < len; i++) { - environment.add(instruction.inputs[i]); - } - } - - /** - * Stores all live variables in the bailout target and the guards. - */ - void insertCapturedEnvironments() { - capturedEnvironments.forEach((HBailoutTarget target, Environment env) { - assert(target.inputs.length == 0); - target.inputs.addAll(env.lives); - // TODO(floitsch): we should add the bailout-target's input variables - // as input to the guards only in the optimized version. The - // non-optimized version does not use the bailout guards and it is - // unnecessary to keep the variables alive until the check. - for (HTypeGuard guard in target.usedBy) { - // A type-guard initially only has two inputs: the guarded instruction - // and the bailout-target. Only after adding the environment is it - // allowed to have more inputs. - assert(guard.inputs.length == 2); - guard.inputs.addAll(env.lives); - } - for (HInstruction live in env.lives) { - live.usedBy.add(target); - live.usedBy.addAll(target.usedBy); - } - }); - } -} - -/** - * Propagates bailout information to blocks that need it. This visitor - * is run before codegen, to know which blocks have to deal with - * bailouts. - */ -class SsaBailoutPropagator extends HBaseVisitor { - final Compiler compiler; - /** - * A list to propagate bailout information to blocks that start a - * guarded or labeled list of statements. Currently, these blocks - * are: - * - first block of a then branch, - * - first block of an else branch, - * - a loop header, - * - labeled block. - */ - final List<HBasicBlock> blocks; - - /** - * The current subgraph we are visiting. - */ - SubGraph subGraph; - - /** - * The current block information we are visiting. - */ - HBlockInformation currentBlockInformation; - - /** - * Max number of arguments to the bailout (not counting the state). - */ - int bailoutArity; - /** - * A map from variables to their names. These are the names in the - * unoptimized (bailout) version of the function. Their names could be - * different in the optimized version. - */ - VariableNames variableNames; - /** - * Maps from the variable names to their positions in the argument list of the - * bailout instruction. Because of the way the variable allocator works, - * several variables can end up with the same name (if their live ranges do - * not overlap), therefore they can have the same position in the bailout - * argument list - */ - Map<String, int> parameterNames; - - /** - * If set to true, the graph has either multiple bailouts in - * different places, or a bailout inside an if or a loop. For such a - * graph, the code generator will emit a generic switch. - */ - bool hasComplexBailoutTargets = false; - - /** - * The first type guard in the graph. - */ - HBailoutTarget firstBailoutTarget; - - /** - * If set, it is the first block in the graph where we generate - * code. Blocks before this one are dead code in the bailout - * version. - */ - - SsaBailoutPropagator(this.compiler, this.variableNames) - : blocks = <HBasicBlock>[], - bailoutArity = 0, - parameterNames = new Map<String, int>(); - - void visitGraph(HGraph graph) { - subGraph = new SubGraph(graph.entry, graph.exit); - visitBasicBlock(graph.entry); - if (!blocks.isEmpty) { - compiler.internalError('Bailout propagation', - node: compiler.currentElement.parseNode(compiler)); - } - } - - /** - * Returns true if we can visit the given [blockFlow]. False - * otherwise. Currently, try/catch and switch are not in bailout - * methods, so this method only deals with loops and labeled blocks. - * If [blockFlow] is a labeled block or a loop, we also visit the - * continuation of the block flow. - */ - bool handleBlockFlow(HBlockFlow blockFlow) { - HBlockInformation body = blockFlow.body; - - // We reach here again when starting to visit a subgraph. Just - // return to visiting the block. - if (currentBlockInformation == body) return false; - - HBlockInformation oldInformation = currentBlockInformation; - if (body is HLabeledBlockInformation) { - currentBlockInformation = body; - HLabeledBlockInformation info = body; - visitStatements(info.body, newFlow: true); - } else if (body is HLoopBlockInformation) { - currentBlockInformation = body; - HLoopBlockInformation info = body; - if (info.initializer != null) { - visitExpression(info.initializer); - } - blocks.addLast(info.loopHeader); - if (!info.isDoWhile()) { - visitExpression(info.condition); - } - visitStatements(info.body, newFlow: false); - if (info.isDoWhile()) { - visitExpression(info.condition); - } - if (info.updates != null) { - visitExpression(info.updates); - } - blocks.removeLast(); - } else { - assert(body is! HTryBlockInformation); - assert(body is! HSwitchBlockInformation); - // [HIfBlockInformation] is handled by visitIf. - return false; - } - - currentBlockInformation = oldInformation; - if (blockFlow.continuation != null) { - visitBasicBlock(blockFlow.continuation); - } - return true; - } - - void visitBasicBlock(HBasicBlock block) { - // Abort traversal if we are leaving the currently active sub-graph. - if (!subGraph.contains(block)) return; - - HBlockFlow blockFlow = block.blockFlow; - if (blockFlow != null && handleBlockFlow(blockFlow)) return; - - HInstruction instruction = block.first; - while (instruction != null) { - instruction.accept(this); - instruction = instruction.next; - } - } - - void visitExpression(HSubExpressionBlockInformation info) { - visitSubGraph(info.subExpression); - } - - /** - * Visit the statements in [info]. If [newFlow] is true, we add the - * first block of [statements] to the list of [blocks]. - */ - void visitStatements(HSubGraphBlockInformation info, {bool newFlow}) { - SubGraph graph = info.subGraph; - if (newFlow) blocks.addLast(graph.start); - visitSubGraph(graph); - if (newFlow) blocks.removeLast(); - } - - void visitSubGraph(SubGraph graph) { - SubGraph oldSubGraph = subGraph; - subGraph = graph; - visitBasicBlock(graph.start); - subGraph = oldSubGraph; - } - - void visitIf(HIf instruction) { - int preVisitedBlocks = 0; - HIfBlockInformation info = instruction.blockInformation.body; - visitStatements(info.thenGraph, newFlow: true); - preVisitedBlocks++; - visitStatements(info.elseGraph, newFlow: true); - preVisitedBlocks++; - - HBasicBlock joinBlock = instruction.joinBlock; - if (joinBlock != null - && !identical(joinBlock.dominator, instruction.block)) { - // The join block is dominated by a block in one of the branches. - // The subgraph traversal never reached it, so we visit it here - // instead. - visitBasicBlock(joinBlock); - } - - // Visit all the dominated blocks that are not part of the then or else - // branches, and is not the join block. - // Depending on how the then/else branches terminate - // (e.g., return/throw/break) there can be any number of these. - List<HBasicBlock> dominated = instruction.block.dominatedBlocks; - int dominatedCount = dominated.length; - for (int i = preVisitedBlocks; i < dominatedCount; i++) { - HBasicBlock dominatedBlock = dominated[i]; - visitBasicBlock(dominatedBlock); - } - } - - void visitGoto(HGoto goto) { - HBasicBlock block = goto.block; - HBasicBlock successor = block.successors[0]; - if (identical(successor.dominator, block)) { - visitBasicBlock(block.successors[0]); - } - } - - void visitLoopBranch(HLoopBranch branch) { - // For a do-while loop, the body has already been visited. - if (!branch.isDoWhile()) { - visitBasicBlock(branch.block.dominatedBlocks[0]); - } - } - - visitBailoutTarget(HBailoutTarget target) { - int inputLength = target.inputs.length; - for (HInstruction input in target.inputs) { - String inputName = variableNames.getName(input); - int position = parameterNames[inputName]; - if (position == null) { - position = parameterNames[inputName] = bailoutArity++; - } - } - - if (blocks.isEmpty) { - if (firstBailoutTarget == null) { - firstBailoutTarget = target; - } else { - hasComplexBailoutTargets = true; - } - } else { - hasComplexBailoutTargets = true; - blocks.forEach((HBasicBlock block) { - block.bailoutTargets.add(target); - }); - } - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/builder.dart b/pkgs/markdown/test/lib/src/compiler/implementation/ssa/builder.dart deleted file mode 100644 index ac19fea..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/builder.dart +++ /dev/null
@@ -1,5034 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of ssa; - -/** - * A special element for the extra parameter taken by intercepted - * methods. We need to override [Element.computeType] because our - * optimizers may look at its declared type. - */ -class InterceptedElement extends ElementX { - final HType ssaType; - InterceptedElement(this.ssaType, Element enclosing) - : super(const SourceString('receiver'), - ElementKind.PARAMETER, - enclosing); - - DartType computeType(Compiler compiler) => ssaType.computeType(compiler); -} - -class SsaBuilderTask extends CompilerTask { - final CodeEmitterTask emitter; - // Loop tracking information. - final Set<FunctionElement> functionsCalledInLoop; - final Map<SourceString, Selector> selectorsCalledInLoop; - final JavaScriptBackend backend; - - String get name => 'SSA builder'; - - SsaBuilderTask(JavaScriptBackend backend) - : emitter = backend.emitter, - functionsCalledInLoop = new Set<FunctionElement>(), - selectorsCalledInLoop = new Map<SourceString, Selector>(), - backend = backend, - super(backend.compiler); - - HGraph build(CodegenWorkItem work) { - return measure(() { - Element element = work.element.implementation; - HInstruction.idCounter = 0; - ConstantSystem constantSystem = compiler.backend.constantSystem; - SsaBuilder builder = new SsaBuilder(constantSystem, this, work); - HGraph graph; - ElementKind kind = element.kind; - if (identical(kind, ElementKind.GENERATIVE_CONSTRUCTOR)) { - graph = compileConstructor(builder, work); - } else if (identical(kind, ElementKind.GENERATIVE_CONSTRUCTOR_BODY) || - identical(kind, ElementKind.FUNCTION) || - identical(kind, ElementKind.GETTER) || - identical(kind, ElementKind.SETTER)) { - graph = builder.buildMethod(element); - } else if (identical(kind, ElementKind.FIELD)) { - graph = builder.buildLazyInitializer(element); - } else { - compiler.internalErrorOnElement(element, - 'unexpected element kind $kind'); - } - assert(graph.isValid()); - if (!identical(kind, ElementKind.FIELD)) { - bool inLoop = functionsCalledInLoop.contains(element.declaration); - if (!inLoop) { - Selector selector = selectorsCalledInLoop[element.name]; - inLoop = selector != null && selector.applies(element, compiler); - } - graph.calledInLoop = inLoop; - - // If there is an estimate of the parameter types assume these types - // when compiling. - // TODO(karlklose,ngeoffray): add a check to make sure that element is - // of type FunctionElement. - FunctionElement function = element; - OptionalParameterTypes defaultValueTypes = null; - FunctionSignature signature = function.computeSignature(compiler); - if (signature.optionalParameterCount > 0) { - defaultValueTypes = - new OptionalParameterTypes(signature.optionalParameterCount); - int index = 0; - signature.forEachOptionalParameter((Element parameter) { - Constant defaultValue = builder.compileVariable(parameter); - HType type = HGraph.mapConstantTypeToSsaType(defaultValue); - defaultValueTypes.update(index, parameter.name, type); - index++; - }); - } else { - // TODO(ahe): I have disabled type optimizations for - // optional arguments as the types are stored in the wrong - // order. - HTypeList parameterTypes = - backend.optimisticParameterTypes(element.declaration, - defaultValueTypes); - if (!parameterTypes.allUnknown) { - int i = 0; - signature.forEachParameter((Element param) { - builder.parameters[param].guaranteedType = parameterTypes[i++]; - }); - } - backend.registerParameterTypesOptimization( - element.declaration, parameterTypes, defaultValueTypes); - } - } - - if (compiler.tracer.enabled) { - String name; - if (element.isMember()) { - String className = element.getEnclosingClass().name.slowToString(); - String memberName = element.name.slowToString(); - name = "$className.$memberName"; - if (element.isGenerativeConstructorBody()) { - name = "$name (body)"; - } - } else { - name = "${element.name.slowToString()}"; - } - compiler.tracer.traceCompilation(name, work.compilationContext); - compiler.tracer.traceGraph('builder', graph); - } - return graph; - }); - } - - HGraph compileConstructor(SsaBuilder builder, CodegenWorkItem work) { - // The body of the constructor will be generated in a separate function. - final ClassElement classElement = work.element.getEnclosingClass(); - return builder.buildFactory(classElement.implementation, - work.element.implementation); - } -} - -/** - * Keeps track of locals (including parameters and phis) when building. The - * 'this' reference is treated as parameter and hence handled by this class, - * too. - */ -class LocalsHandler { - /** - * The values of locals that can be directly accessed (without redirections - * to boxes or closure-fields). - * - * [directLocals] is iterated, so it is a [LinkedHashMap] to make the - * iteration order a function only of insertions and not a function of - * e.g. Element hash codes. I'd prefer to use a SortedMap but some elements - * don't have source locations for [Elements.compareByPosition]. - */ - LinkedHashMap<Element, HInstruction> directLocals; - Map<Element, Element> redirectionMapping; - SsaBuilder builder; - ClosureClassMap closureData; - - LocalsHandler(this.builder) - : directLocals = new LinkedHashMap<Element, HInstruction>(), - redirectionMapping = new Map<Element, Element>(); - - get typesTask => builder.compiler.typesTask; - - /** - * Creates a new [LocalsHandler] based on [other]. We only need to - * copy the [directLocals], since the other fields can be shared - * throughout the AST visit. - */ - LocalsHandler.from(LocalsHandler other) - : directLocals = - new LinkedHashMap<Element, HInstruction>.from(other.directLocals), - redirectionMapping = other.redirectionMapping, - builder = other.builder, - closureData = other.closureData; - - /** - * Redirects accesses from element [from] to element [to]. The [to] element - * must be a boxed variable or a variable that is stored in a closure-field. - */ - void redirectElement(Element from, Element to) { - assert(redirectionMapping[from] == null); - redirectionMapping[from] = to; - assert(isStoredInClosureField(from) || isBoxed(from)); - } - - HInstruction createBox() { - // TODO(floitsch): Clean up this hack. Should we create a box-object by - // just creating an empty object literal? - HInstruction box = new HForeign(const LiteralDartString("{}"), - HType.UNKNOWN, - <HInstruction>[]); - builder.add(box); - return box; - } - - /** - * If the scope (function or loop) [node] has captured variables then this - * method creates a box and sets up the redirections. - */ - void enterScope(Node node, Element element) { - // See if any variable in the top-scope of the function is captured. If yes - // we need to create a box-object. - ClosureScope scopeData = closureData.capturingScopes[node]; - if (scopeData != null) { - HInstruction box; - // The scope has captured variables. - if (element != null && element.isGenerativeConstructorBody()) { - // The box is passed as a parameter to a generative - // constructor body. - box = builder.addParameter(scopeData.boxElement); - } else { - box = createBox(); - } - // Add the box to the known locals. - directLocals[scopeData.boxElement] = box; - // Make sure that accesses to the boxed locals go into the box. We also - // need to make sure that parameters are copied into the box if necessary. - scopeData.capturedVariableMapping.forEach((Element from, Element to) { - // The [from] can only be a parameter for function-scopes and not - // loop scopes. - if (from.isParameter() && !element.isGenerativeConstructorBody()) { - // Now that the redirection is set up, the update to the local will - // write the parameter value into the box. - // Store the captured parameter in the box. Get the current value - // before we put the redirection in place. - // We don't need to update the local for a generative - // constructor body, because it receives a box that already - // contains the updates as the last parameter. - HInstruction instruction = readLocal(from); - redirectElement(from, to); - updateLocal(from, instruction); - } else { - redirectElement(from, to); - } - }); - } - } - - /** - * Replaces the current box with a new box and copies over the given list - * of elements from the old box into the new box. - */ - void updateCaptureBox(Element boxElement, List<Element> toBeCopiedElements) { - // Create a new box and copy over the values from the old box into the - // new one. - HInstruction oldBox = readLocal(boxElement); - HInstruction newBox = createBox(); - for (Element boxedVariable in toBeCopiedElements) { - // [readLocal] uses the [boxElement] to find its box. By replacing it - // behind its back we can still get to the old values. - updateLocal(boxElement, oldBox); - HInstruction oldValue = readLocal(boxedVariable); - updateLocal(boxElement, newBox); - updateLocal(boxedVariable, oldValue); - } - updateLocal(boxElement, newBox); - } - - /** - * Documentation wanted -- johnniwinther - * - * Invariant: [function] must be an implementation element. - */ - void startFunction(Element element, Expression node) { - assert(invariant(node, element.isImplementation)); - Compiler compiler = builder.compiler; - closureData = compiler.closureToClassMapper.computeClosureToClassMapping( - element, node, builder.elements); - - if (element is FunctionElement) { - FunctionElement functionElement = element; - FunctionSignature params = functionElement.computeSignature(compiler); - params.orderedForEachParameter((Element parameterElement) { - if (element.isGenerativeConstructorBody()) { - ClosureScope scopeData = closureData.capturingScopes[node]; - if (scopeData != null - && scopeData.capturedVariableMapping.containsKey( - parameterElement)) { - // The parameter will be a field in the box passed as the - // last parameter. So no need to have it. - return; - } - } - HInstruction parameter = builder.addParameter(parameterElement); - builder.parameters[parameterElement] = parameter; - directLocals[parameterElement] = parameter; - parameter.guaranteedType = - builder.mapInferredType( - typesTask.getGuaranteedTypeOfElement(parameterElement)); - }); - } - - enterScope(node, element); - - // If the freeVariableMapping is not empty, then this function was a - // nested closure that captures variables. Redirect the captured - // variables to fields in the closure. - closureData.freeVariableMapping.forEach((Element from, Element to) { - redirectElement(from, to); - }); - if (closureData.isClosure()) { - // Inside closure redirect references to itself to [:this:]. - HThis thisInstruction = new HThis(closureData.thisElement); - builder.graph.thisInstruction = thisInstruction; - builder.graph.entry.addAtEntry(thisInstruction); - updateLocal(closureData.closureElement, thisInstruction); - } else if (element.isInstanceMember() - || element.isGenerativeConstructor()) { - // Once closures have been mapped to classes their instance members might - // not have any thisElement if the closure was created inside a static - // context. - ClassElement cls = element.getEnclosingClass(); - DartType type = cls.computeType(builder.compiler); - HThis thisInstruction = new HThis(closureData.thisElement, - new HBoundedType.nonNull(type)); - builder.graph.thisInstruction = thisInstruction; - builder.graph.entry.addAtEntry(thisInstruction); - directLocals[closureData.thisElement] = thisInstruction; - } - - // If this method is an intercepted method, add the extra - // parameter to it, that is the actual receiver. - ClassElement cls = element.getEnclosingClass(); - if (builder.backend.isInterceptorClass(cls)) { - HType type = HType.UNKNOWN; - if (cls == builder.backend.jsArrayClass) { - type = HType.READABLE_ARRAY; - } else if (cls == builder.backend.jsStringClass) { - type = HType.STRING; - } else if (cls == builder.backend.jsNumberClass) { - type = HType.NUMBER; - } else if (cls == builder.backend.jsIntClass) { - type = HType.INTEGER; - } else if (cls == builder.backend.jsDoubleClass) { - type = HType.DOUBLE; - } else if (cls == builder.backend.jsNullClass) { - type = HType.NULL; - } else if (cls == builder.backend.jsBoolClass) { - type = HType.BOOLEAN; - } - Element parameter = new InterceptedElement(type, element); - HParameterValue value = new HParameterValue(parameter); - builder.graph.entry.addAfter( - directLocals[closureData.thisElement], value); - directLocals[closureData.thisElement] = value; - value.guaranteedType = type; - } - } - - bool hasValueForDirectLocal(Element element) { - assert(element != null); - assert(isAccessedDirectly(element)); - return directLocals[element] != null; - } - - /** - * Returns true if the local can be accessed directly. Boxed variables or - * captured variables that are stored in the closure-field return [false]. - */ - bool isAccessedDirectly(Element element) { - assert(element != null); - return redirectionMapping[element] == null - && !closureData.usedVariablesInTry.contains(element); - } - - bool isStoredInClosureField(Element element) { - assert(element != null); - if (isAccessedDirectly(element)) return false; - Element redirectTarget = redirectionMapping[element]; - if (redirectTarget == null) return false; - if (redirectTarget.isMember()) { - assert(redirectTarget is ClosureFieldElement); - return true; - } - return false; - } - - bool isBoxed(Element element) { - if (isAccessedDirectly(element)) return false; - if (isStoredInClosureField(element)) return false; - return redirectionMapping[element] != null; - } - - bool isUsedInTry(Element element) { - return closureData.usedVariablesInTry.contains(element); - } - - /** - * Returns an [HInstruction] for the given element. If the element is - * boxed or stored in a closure then the method generates code to retrieve - * the value. - */ - HInstruction readLocal(Element element) { - if (isAccessedDirectly(element)) { - if (directLocals[element] == null) { - builder.compiler.internalError("Cannot find value $element", - element: element); - } - return directLocals[element]; - } else if (isStoredInClosureField(element)) { - Element redirect = redirectionMapping[element]; - HInstruction receiver = readLocal(closureData.closureElement); - HInstruction fieldGet = new HFieldGet(redirect, receiver); - builder.add(fieldGet); - return fieldGet; - } else if (isBoxed(element)) { - Element redirect = redirectionMapping[element]; - // In the function that declares the captured variable the box is - // accessed as direct local. Inside the nested closure the box is - // accessed through a closure-field. - // Calling [readLocal] makes sure we generate the correct code to get - // the box. - assert(redirect.enclosingElement.isVariable()); - HInstruction box = readLocal(redirect.enclosingElement); - HInstruction lookup = new HFieldGet(redirect, box); - builder.add(lookup); - return lookup; - } else { - assert(isUsedInTry(element)); - HLocalValue local = getLocal(element); - HInstruction variable = new HLocalGet(element, local); - builder.add(variable); - return variable; - } - } - - HType cachedTypeOfThis; - - HInstruction readThis() { - HInstruction res = readLocal(closureData.thisElement); - if (res.guaranteedType == null) { - if (cachedTypeOfThis == null) { - assert(closureData.isClosure()); - Element element = closureData.thisElement; - ClassElement cls = element.enclosingElement.getEnclosingClass(); - DartType type = cls.computeType(builder.compiler); - cachedTypeOfThis = new HBoundedType.nonNull(type); - } - res.guaranteedType = cachedTypeOfThis; - } - return res; - } - - HLocalValue getLocal(Element element) { - // If the element is a parameter, we already have a - // HParameterValue for it. We cannot create another one because - // it could then have another name than the real parameter. And - // the other one would not know it is just a copy of the real - // parameter. - if (element.isParameter()) return builder.parameters[element]; - - return builder.activationVariables.putIfAbsent(element, () { - HLocalValue local = new HLocalValue(element); - builder.graph.entry.addAtExit(local); - return local; - }); - } - - /** - * Sets the [element] to [value]. If the element is boxed or stored in a - * closure then the method generates code to set the value. - */ - void updateLocal(Element element, HInstruction value) { - assert(!isStoredInClosureField(element)); - if (isAccessedDirectly(element)) { - directLocals[element] = value; - } else if (isBoxed(element)) { - Element redirect = redirectionMapping[element]; - // The box itself could be captured, or be local. A local variable that - // is captured will be boxed, but the box itself will be a local. - // Inside the closure the box is stored in a closure-field and cannot - // be accessed directly. - assert(redirect.enclosingElement.isVariable()); - HInstruction box = readLocal(redirect.enclosingElement); - builder.add(new HFieldSet(redirect, box, value)); - } else { - assert(isUsedInTry(element)); - HLocalValue local = getLocal(element); - builder.add(new HLocalSet(element, local, value)); - } - } - - /** - * This function must be called before visiting any children of the loop. In - * particular it needs to be called before executing the initializers. - * - * The [LocalsHandler] will make the boxes and updates at the right moment. - * The builder just needs to call [enterLoopBody] and [enterLoopUpdates] (for - * [For] loops) at the correct places. For phi-handling [beginLoopHeader] and - * [endLoop] must also be called. - * - * The correct place for the box depends on the given loop. In most cases - * the box will be created when entering the loop-body: while, do-while, and - * for-in (assuming the call to [:next:] is inside the body) can always be - * constructed this way. - * - * Things are slightly more complicated for [For] loops. If no declared - * loop variable is boxed then the loop-body approach works here too. If a - * loop-variable is boxed we need to introduce a new box for the - * loop-variable before we enter the initializer so that the initializer - * writes the values into the box. In any case we need to create the box - * before the condition since the condition could box the variable. - * Since the first box is created outside the actual loop we have a second - * location where a box is created: just before the updates. This is - * necessary since updates are considered to be part of the next iteration - * (and can again capture variables). - * - * For example the following Dart code prints 1 3 -- 3 4. - * - * var fs = []; - * for (var i = 0; i < 3; (f() { fs.add(f); print(i); i++; })()) { - * i++; - * } - * print("--"); - * for (var i = 0; i < 2; i++) fs[i](); - * - * We solve this by emitting the following code (only for [For] loops): - * <Create box> <== move the first box creation outside the loop. - * <initializer>; - * loop-entry: - * if (!<condition>) goto loop-exit; - * <body> - * <update box> // create a new box and copy the captured loop-variables. - * <updates> - * goto loop-entry; - * loop-exit: - */ - void startLoop(Node node) { - ClosureScope scopeData = closureData.capturingScopes[node]; - if (scopeData == null) return; - if (scopeData.hasBoxedLoopVariables()) { - // If there are boxed loop variables then we set up the box and - // redirections already now. This way the initializer can write its - // values into the box. - // For other loops the box will be created when entering the body. - enterScope(node, null); - } - } - - void beginLoopHeader(Node node, HBasicBlock loopEntry) { - // Create a copy because we modify the map while iterating over it. - Map<Element, HInstruction> saved = - new LinkedHashMap<Element, HInstruction>.from(directLocals); - - // Create phis for all elements in the definitions environment. - saved.forEach((Element element, HInstruction instruction) { - if (isAccessedDirectly(element)) { - // We know 'this' cannot be modified. - if (!identical(element, closureData.thisElement)) { - HPhi phi = new HPhi.singleInput(element, instruction); - loopEntry.addPhi(phi); - directLocals[element] = phi; - } else { - directLocals[element] = instruction; - } - } - }); - } - - void enterLoopBody(Node node) { - ClosureScope scopeData = closureData.capturingScopes[node]; - if (scopeData == null) return; - // If there are no declared boxed loop variables then we did not create the - // box before the initializer and we have to create the box now. - if (!scopeData.hasBoxedLoopVariables()) { - enterScope(node, null); - } - } - - void enterLoopUpdates(Loop node) { - // If there are declared boxed loop variables then the updates might have - // access to the box and we must switch to a new box before executing the - // updates. - // In all other cases a new box will be created when entering the body of - // the next iteration. - ClosureScope scopeData = closureData.capturingScopes[node]; - if (scopeData == null) return; - if (scopeData.hasBoxedLoopVariables()) { - updateCaptureBox(scopeData.boxElement, scopeData.boxedLoopVariables); - } - } - - void endLoop(HBasicBlock loopEntry) { - // If the loop has an aborting body, we don't update the loop - // phis. - if (loopEntry.predecessors.length == 1) return; - loopEntry.forEachPhi((HPhi phi) { - Element element = phi.sourceElement; - HInstruction postLoopDefinition = directLocals[element]; - phi.addInput(postLoopDefinition); - }); - } - - /** - * Merge [otherLocals] into this locals handler, creating phi-nodes when - * there is a conflict. - * If a phi node is necessary, it will use this handler's instruction as the - * first input, and the otherLocals instruction as the second. - */ - void mergeWith(LocalsHandler otherLocals, HBasicBlock joinBlock) { - // If an element is in one map but not the other we can safely - // ignore it. It means that a variable was declared in the - // block. Since variable declarations are scoped the declared - // variable cannot be alive outside the block. Note: this is only - // true for nodes where we do joins. - Map<Element, HInstruction> joinedLocals = - new LinkedHashMap<Element, HInstruction>(); - otherLocals.directLocals.forEach((element, instruction) { - // We know 'this' cannot be modified. - if (identical(element, closureData.thisElement)) { - assert(directLocals[element] == instruction); - joinedLocals[element] = instruction; - } else { - HInstruction mine = directLocals[element]; - if (mine == null) return; - if (identical(instruction, mine)) { - joinedLocals[element] = instruction; - } else { - HInstruction phi = - new HPhi.manyInputs(element, <HInstruction>[mine, instruction]); - joinBlock.addPhi(phi); - joinedLocals[element] = phi; - } - } - }); - directLocals = joinedLocals; - } - - /** - * The current localsHandler is not used for its values, only for its - * declared variables. This is a way to exclude local values from the - * result when they are no longer in scope. - * Returns the new LocalsHandler to use (may not be [this]). - */ - LocalsHandler mergeMultiple(List<LocalsHandler> locals, - HBasicBlock joinBlock) { - assert(locals.length > 0); - if (locals.length == 1) return locals[0]; - Map<Element, HInstruction> joinedLocals = - new LinkedHashMap<Element,HInstruction>(); - HInstruction thisValue = null; - directLocals.forEach((Element element, HInstruction instruction) { - if (!identical(element, closureData.thisElement)) { - HPhi phi = new HPhi.noInputs(element); - joinedLocals[element] = phi; - joinBlock.addPhi(phi); - } else { - // We know that "this" never changes, if it's there. - // Save it for later. While merging, there is no phi for "this", - // so we don't have to special case it in the merge loop. - thisValue = instruction; - } - }); - for (LocalsHandler local in locals) { - local.directLocals.forEach((Element element, HInstruction instruction) { - HPhi phi = joinedLocals[element]; - if (phi != null) { - phi.addInput(instruction); - } - }); - } - if (thisValue != null) { - // If there was a "this" for the scope, add it to the new locals. - joinedLocals[closureData.thisElement] = thisValue; - } - directLocals = joinedLocals; - return this; - } -} - - -// Represents a single break/continue instruction. -class JumpHandlerEntry { - final HJump jumpInstruction; - final LocalsHandler locals; - bool isBreak() => jumpInstruction is HBreak; - bool isContinue() => jumpInstruction is HContinue; - JumpHandlerEntry(this.jumpInstruction, this.locals); -} - - -abstract class JumpHandler { - factory JumpHandler(SsaBuilder builder, TargetElement target) { - return new TargetJumpHandler(builder, target); - } - void generateBreak([LabelElement label]); - void generateContinue([LabelElement label]); - void forEachBreak(void action(HBreak instruction, LocalsHandler locals)); - void forEachContinue(void action(HContinue instruction, - LocalsHandler locals)); - bool hasAnyContinue(); - bool hasAnyBreak(); - void close(); - final TargetElement target; - List<LabelElement> labels(); -} - -// Insert break handler used to avoid null checks when a target isn't -// used as the target of a break, and therefore doesn't need a break -// handler associated with it. -class NullJumpHandler implements JumpHandler { - final Compiler compiler; - - NullJumpHandler(this.compiler); - - void generateBreak([LabelElement label]) { - compiler.internalError('generateBreak should not be called'); - } - - void generateContinue([LabelElement label]) { - compiler.internalError('generateContinue should not be called'); - } - - void forEachBreak(Function ignored) { } - void forEachContinue(Function ignored) { } - void close() { } - bool hasAnyContinue() => false; - bool hasAnyBreak() => false; - - List<LabelElement> labels() => const <LabelElement>[]; - TargetElement get target => null; -} - -// Records breaks until a target block is available. -// Breaks are always forward jumps. -// Continues in loops are implemented as breaks of the body. -// Continues in switches is currently not handled. -class TargetJumpHandler implements JumpHandler { - final SsaBuilder builder; - final TargetElement target; - final List<JumpHandlerEntry> jumps; - - TargetJumpHandler(SsaBuilder builder, this.target) - : this.builder = builder, - jumps = <JumpHandlerEntry>[] { - assert(builder.jumpTargets[target] == null); - builder.jumpTargets[target] = this; - } - - void generateBreak([LabelElement label]) { - HInstruction breakInstruction; - if (label == null) { - breakInstruction = new HBreak(target); - } else { - breakInstruction = new HBreak.toLabel(label); - } - LocalsHandler locals = new LocalsHandler.from(builder.localsHandler); - builder.close(breakInstruction); - jumps.add(new JumpHandlerEntry(breakInstruction, locals)); - } - - void generateContinue([LabelElement label]) { - HInstruction continueInstruction; - if (label == null) { - continueInstruction = new HContinue(target); - } else { - continueInstruction = new HContinue.toLabel(label); - } - LocalsHandler locals = new LocalsHandler.from(builder.localsHandler); - builder.close(continueInstruction); - jumps.add(new JumpHandlerEntry(continueInstruction, locals)); - } - - void forEachBreak(Function action) { - for (JumpHandlerEntry entry in jumps) { - if (entry.isBreak()) action(entry.jumpInstruction, entry.locals); - } - } - - void forEachContinue(Function action) { - for (JumpHandlerEntry entry in jumps) { - if (entry.isContinue()) action(entry.jumpInstruction, entry.locals); - } - } - - bool hasAnyContinue() { - for (JumpHandlerEntry entry in jumps) { - if (entry.isContinue()) return true; - } - return false; - } - - bool hasAnyBreak() { - for (JumpHandlerEntry entry in jumps) { - if (entry.isBreak()) return true; - } - return false; - } - - void close() { - // The mapping from TargetElement to JumpHandler is no longer needed. - builder.jumpTargets.remove(target); - } - - List<LabelElement> labels() { - List<LabelElement> result = null; - for (LabelElement element in target.labels) { - if (result == null) result = <LabelElement>[]; - result.add(element); - } - return (result == null) ? const <LabelElement>[] : result; - } -} - -class SsaBuilder extends ResolvedVisitor implements Visitor { - final SsaBuilderTask builder; - final JavaScriptBackend backend; - final CodegenWorkItem work; - final ConstantSystem constantSystem; - HGraph graph; - LocalsHandler localsHandler; - HInstruction rethrowableException; - Map<Element, HInstruction> parameters; - final RuntimeTypeInformation rti; - HParameterValue lastAddedParameter; - - Map<TargetElement, JumpHandler> jumpTargets; - - /** - * Variables stored in the current activation. These variables are - * being updated in try/catch blocks, and should be - * accessed indirectly through [HLocalGet] and [HLocalSet]. - */ - Map<Element, HLocalValue> activationVariables; - - // We build the Ssa graph by simulating a stack machine. - List<HInstruction> stack; - - // The current block to add instructions to. Might be null, if we are - // visiting dead code. - HBasicBlock current; - // The most recently opened block. Has the same value as [current] while - // the block is open, but unlike [current], it isn't cleared when the current - // block is closed. - HBasicBlock lastOpenedBlock; - - final List<Element> sourceElementStack; - - Element get currentElement => sourceElementStack.last.declaration; - Compiler get compiler => builder.compiler; - CodeEmitterTask get emitter => builder.emitter; - - SsaBuilder(this.constantSystem, SsaBuilderTask builder, CodegenWorkItem work) - : this.builder = builder, - this.backend = builder.backend, - this.work = work, - graph = new HGraph(), - stack = new List<HInstruction>(), - activationVariables = new Map<Element, HLocalValue>(), - jumpTargets = new Map<TargetElement, JumpHandler>(), - parameters = new Map<Element, HInstruction>(), - sourceElementStack = <Element>[work.element], - inliningStack = <InliningState>[], - rti = builder.backend.rti, - super(work.resolutionTree) { - localsHandler = new LocalsHandler(this); - } - - static const MAX_INLINING_DEPTH = 3; - static const MAX_INLINING_SOURCE_SIZE = 128; - List<InliningState> inliningStack; - Element returnElement; - DartType returnType; - bool inTryStatement = false; - - /** - * Compiles compile-time constants. Never returns [:null:]. If the - * initial value is not a compile-time constants, it reports an - * internal error. - */ - Constant compileConstant(VariableElement element) { - return compiler.constantHandler.compileConstant(element); - } - - Constant compileVariable(VariableElement element) { - return compiler.constantHandler.compileVariable(element); - } - - bool isLazilyInitialized(VariableElement element) { - Constant initialValue = compileVariable(element); - return initialValue == null; - } - - /** - * Documentation wanted -- johnniwinther - * - * Invariant: [functionElement] must be an implementation element. - */ - HGraph buildMethod(FunctionElement functionElement) { - assert(invariant(functionElement, functionElement.isImplementation)); - FunctionExpression function = functionElement.parseNode(compiler); - assert(function != null); - assert(!function.modifiers.isExternal()); - assert(elements[function] != null); - openFunction(functionElement, function); - SourceString name = functionElement.name; - // If [functionElement] is operator== we explicitely add a null - // check at the beginning of the method. This is to avoid having - // call sites do the null check. - if (name == const SourceString('==')) { - handleIf( - function, - () { - HParameterValue parameter = parameters.values.first; - push(new HIdentity( - parameter, graph.addConstantNull(constantSystem))); - }, - () { - HReturn ret = new HReturn( - graph.addConstantBool(false, constantSystem)); - close(ret).addSuccessor(graph.exit); - }, - null); - } - function.body.accept(this); - return closeFunction(); - } - - HGraph buildLazyInitializer(VariableElement variable) { - SendSet node = variable.parseNode(compiler); - openFunction(variable, node); - Link<Node> link = node.arguments; - assert(!link.isEmpty && link.tail.isEmpty); - visit(link.head); - HInstruction value = pop(); - value = potentiallyCheckType(value, variable.computeType(compiler)); - close(new HReturn(value)).addSuccessor(graph.exit); - return closeFunction(); - } - - /** - * Returns the constructor body associated with the given constructor or - * creates a new constructor body, if none can be found. - * - * Returns [:null:] if the constructor does not have a body. - */ - ConstructorBodyElement getConstructorBody(FunctionElement constructor) { - assert(constructor.isGenerativeConstructor()); - assert(invariant(constructor, constructor.isImplementation)); - if (constructor.isSynthesized) return null; - FunctionExpression node = constructor.parseNode(compiler); - // If we know the body doesn't have any code, we don't generate it. - if (!node.hasBody()) return null; - if (node.hasEmptyBody()) return null; - ClassElement classElement = constructor.getEnclosingClass(); - ConstructorBodyElement bodyElement; - classElement.forEachBackendMember((Element backendMember) { - if (backendMember.isGenerativeConstructorBody()) { - ConstructorBodyElement body = backendMember; - if (body.constructor == constructor) { - // TODO(kasperl): Find a way of stopping the iteration - // through the backend members. - bodyElement = backendMember; - } - } - }); - if (bodyElement == null) { - bodyElement = new ConstructorBodyElementX(constructor); - // [:resolveMethodElement:] require the passed element to be a - // declaration. - TreeElements treeElements = - compiler.enqueuer.resolution.getCachedElements( - constructor.declaration); - classElement.addBackendMember(bodyElement); - - if (constructor.isPatch) { - // Create origin body element for patched constructors. - bodyElement.origin = new ConstructorBodyElementX(constructor.origin); - bodyElement.origin.patch = bodyElement; - classElement.origin.addBackendMember(bodyElement.origin); - } - compiler.enqueuer.codegen.addToWorkList(bodyElement.declaration, - treeElements); - } - assert(bodyElement.isGenerativeConstructorBody()); - return bodyElement; - } - - HParameterValue addParameter(Element element) { - HParameterValue result = new HParameterValue(element); - if (lastAddedParameter == null) { - graph.entry.addBefore(graph.entry.first, result); - } else { - graph.entry.addAfter(lastAddedParameter, result); - } - lastAddedParameter = result; - return result; - } - - /** - * Documentation wanted -- johnniwinther - * - * Invariant: [function] must be an implementation element. - */ - InliningState enterInlinedMethod(PartialFunctionElement function, - Selector selector, - Link<Node> arguments, - Node currentNode) { - assert(invariant(function, function.isImplementation)); - - // Once we start to compile the arguments we must be sure that we don't - // abort. - List<HInstruction> compiledArguments = new List<HInstruction>(); - bool succeeded = addStaticSendArgumentsToList(selector, - arguments, - function, - compiledArguments); - assert(succeeded); - - FunctionSignature signature = function.computeSignature(compiler); - int index = 0; - signature.orderedForEachParameter((Element parameter) { - HInstruction argument = compiledArguments[index++]; - localsHandler.updateLocal(parameter, argument); - potentiallyCheckType(argument, parameter.computeType(compiler)); - }); - - if (function.isConstructor()) { - ClassElement enclosing = function.getEnclosingClass(); - if (compiler.world.needsRti(enclosing)) { - assert(currentNode is NewExpression); - InterfaceType type = elements.getType(currentNode); - Link<DartType> typeVariable = enclosing.typeVariables; - type.typeArguments.forEach((DartType argument) { - HInstruction instruction = - analyzeTypeArgument(argument, currentNode); - localsHandler.updateLocal(typeVariable.head.element, instruction); - typeVariable = typeVariable.tail; - }); - while (!typeVariable.isEmpty) { - localsHandler.updateLocal(typeVariable.head.element, - graph.addConstantNull(constantSystem)); - typeVariable = typeVariable.tail; - } - } - } - InliningState state = - new InliningState(function, returnElement, returnType, elements, stack); - - // TODO(kasperl): Bad smell. We shouldn't be constructing elements here. - returnElement = new ElementX(const SourceString("result"), - ElementKind.VARIABLE, - function); - localsHandler.updateLocal(returnElement, - graph.addConstantNull(constantSystem)); - elements = compiler.enqueuer.resolution.getCachedElements(function); - assert(elements != null); - returnType = signature.returnType; - stack = <HInstruction>[]; - inliningStack.add(state); - return state; - } - - void leaveInlinedMethod(InliningState state) { - InliningState poppedState = inliningStack.removeLast(); - assert(state == poppedState); - elements = state.oldElements; - stack.add(localsHandler.readLocal(returnElement)); - returnElement = state.oldReturnElement; - returnType = state.oldReturnType; - assert(stack.length == 1); - state.oldStack.add(stack[0]); - stack = state.oldStack; - } - - /** - * Try to inline [element] within the currect context of the - * builder. The insertion point is the state of the builder. - */ - bool tryInlineMethod(Element element, - Selector selector, - Link<Node> arguments, - Node currentNode) { - if (compiler.disableInlining) return false; - // Ensure that [element] is an implementation element. - element = element.implementation; - // TODO(floitsch): we should be able to inline inside lazy initializers. - if (!currentElement.isFunction()) return false; - // TODO(floitsch): find a cleaner way to know if the element is a function - // containing nodes. - // [PartialFunctionElement]s are [FunctionElement]s that have [Node]s. - if (element is !PartialFunctionElement) return false; - // TODO(ngeoffray): try to inline generative constructors. They - // don't have any body, which make it more difficult. - if (element.isGenerativeConstructor()) return false; - if (inliningStack.length > MAX_INLINING_DEPTH) return false; - // Don't inline recursive calls. We use the same elements for the inlined - // functions and would thus clobber our local variables. - // Use [:element.declaration:] since [work.element] is always a declaration. - if (currentElement == element.declaration) return false; - for (int i = 0; i < inliningStack.length; i++) { - if (inliningStack[i].function == element) return false; - } - PartialFunctionElement function = element; - int sourceSize = - function.endToken.charOffset - function.beginToken.charOffset; - if (sourceSize > MAX_INLINING_SOURCE_SIZE) return false; - if (!selector.applies(function, compiler)) return false; - FunctionExpression functionExpression = function.parseNode(compiler); - TreeElements newElements = - compiler.enqueuer.resolution.getCachedElements(function); - if (newElements == null) { - compiler.internalError("Element not resolved: $function"); - } - if (!InlineWeeder.canBeInlined(functionExpression, newElements)) { - return false; - } - - InliningState state = enterInlinedMethod( - function, selector, arguments, currentNode); - inlinedFrom(element, () { - functionExpression.body.accept(this); - }); - leaveInlinedMethod(state); - return true; - } - - inlinedFrom(Element element, f()) { - return compiler.withCurrentElement(element, () { - sourceElementStack.add(element); - var result = f(); - sourceElementStack.removeLast(); - return result; - }); - } - - /** - * Documentation wanted -- johnniwinther - * - * Invariant: [constructor] and [constructors] must all be implementation - * elements. - */ - void inlineSuperOrRedirect(FunctionElement constructor, - Selector selector, - Link<Node> arguments, - List<FunctionElement> constructors, - Map<Element, HInstruction> fieldValues, - FunctionElement inlinedFromElement) { - compiler.withCurrentElement(constructor, () { - assert(invariant(constructor, constructor.isImplementation)); - constructors.addLast(constructor); - - List<HInstruction> compiledArguments = new List<HInstruction>(); - bool succeeded = - inlinedFrom(inlinedFromElement, - () => addStaticSendArgumentsToList(selector, - arguments, - constructor, - compiledArguments)); - if (!succeeded) { - // Non-matching super and redirects are compile-time errors and thus - // checked by the resolver. - compiler.internalError( - "Parameters and arguments didn't match for super/redirect call", - element: constructor); - } - - sourceElementStack.add(constructor.enclosingElement); - buildFieldInitializers(constructor.enclosingElement.implementation, - fieldValues); - sourceElementStack.removeLast(); - - int index = 0; - FunctionSignature params = constructor.computeSignature(compiler); - params.orderedForEachParameter((Element parameter) { - HInstruction argument = compiledArguments[index++]; - // Because we are inlining the initializer, we must update - // what was given as parameter. This will be used in case - // there is a parameter check expression in the initializer. - parameters[parameter] = argument; - localsHandler.updateLocal(parameter, argument); - // Don't forget to update the field, if the parameter is of the - // form [:this.x:]. - if (parameter.kind == ElementKind.FIELD_PARAMETER) { - FieldParameterElement fieldParameterElement = parameter; - fieldValues[fieldParameterElement.fieldElement] = argument; - } - }); - - // Build the initializers in the context of the new constructor. - TreeElements oldElements = elements; - elements = - compiler.enqueuer.resolution.getCachedElements(constructor); - - ClosureClassMap oldClosureData = localsHandler.closureData; - Node node = constructor.parseNode(compiler); - ClosureClassMap newClosureData = - compiler.closureToClassMapper.computeClosureToClassMapping( - constructor, node, elements); - // The [:this:] element now refers to the one in the new closure - // data, that is the [:this:] of the super constructor. We - // update the element to refer to the current [:this:]. - localsHandler.updateLocal(newClosureData.thisElement, - localsHandler.readThis()); - localsHandler.closureData = newClosureData; - - params.orderedForEachParameter((Element parameterElement) { - if (elements.isParameterChecked(parameterElement)) { - addParameterCheckInstruction(parameterElement); - } - }); - localsHandler.enterScope(node, constructor); - buildInitializers(constructor, constructors, fieldValues); - localsHandler.closureData = oldClosureData; - elements = oldElements; - }); - } - - /** - * Run through the initializers and inline all field initializers. Recursively - * inlines super initializers. - * - * The constructors of the inlined initializers is added to [constructors] - * with sub constructors having a lower index than super constructors. - * - * Invariant: The [constructor] and elements in [constructors] must all be - * implementation elements. - */ - void buildInitializers(FunctionElement constructor, - List<FunctionElement> constructors, - Map<Element, HInstruction> fieldValues) { - assert(invariant(constructor, constructor.isImplementation)); - FunctionExpression functionNode = constructor.parseNode(compiler); - - bool foundSuperOrRedirect = false; - - if (functionNode.initializers != null) { - Link<Node> initializers = functionNode.initializers.nodes; - for (Link<Node> link = initializers; !link.isEmpty; link = link.tail) { - assert(link.head is Send); - if (link.head is !SendSet) { - // A super initializer or constructor redirection. - Send call = link.head; - assert(Initializers.isSuperConstructorCall(call) || - Initializers.isConstructorRedirect(call)); - FunctionElement target = elements[call]; - Selector selector = elements.getSelector(call); - Link<Node> arguments = call.arguments; - inlineSuperOrRedirect(target, selector, arguments, constructors, - fieldValues, constructor); - foundSuperOrRedirect = true; - } else { - // A field initializer. - SendSet init = link.head; - Link<Node> arguments = init.arguments; - assert(!arguments.isEmpty && arguments.tail.isEmpty); - sourceElementStack.add(constructor); - visit(arguments.head); - sourceElementStack.removeLast(); - fieldValues[elements[init]] = pop(); - } - } - } - - if (!foundSuperOrRedirect) { - // No super initializer found. Try to find the default constructor if - // the class is not Object. - ClassElement enclosingClass = constructor.getEnclosingClass(); - ClassElement superClass = enclosingClass.superclass; - if (!enclosingClass.isObject(compiler)) { - assert(superClass != null); - assert(superClass.resolutionState == STATE_DONE); - Selector selector = - new Selector.callDefaultConstructor(enclosingClass.getLibrary()); - // TODO(johnniwinther): Should we find injected constructors as well? - FunctionElement target = superClass.lookupConstructor(selector); - if (target == null) { - compiler.internalError("no default constructor available"); - } - inlineSuperOrRedirect(target.implementation, - selector, - const Link<Node>(), - constructors, - fieldValues, - constructor); - } - } - } - - /** - * Run through the fields of [cls] and add their potential - * initializers. - * - * Invariant: [classElement] must be an implementation element. - */ - void buildFieldInitializers(ClassElement classElement, - Map<Element, HInstruction> fieldValues) { - assert(invariant(classElement, classElement.isImplementation)); - classElement.forEachInstanceField( - (ClassElement enclosingClass, Element member) { - TreeElements definitions = compiler.analyzeElement(member); - Node node = member.parseNode(compiler); - SendSet assignment = node.asSendSet(); - HInstruction value; - if (assignment == null) { - value = graph.addConstantNull(constantSystem); - } else { - Node right = assignment.arguments.head; - TreeElements savedElements = elements; - elements = definitions; - right.accept(this); - elements = savedElements; - value = pop(); - } - fieldValues[member] = value; - }, - includeBackendMembers: true, - includeSuperMembers: false); - } - - - /** - * Build the factory function corresponding to the constructor - * [functionElement]: - * - Initialize fields with the values of the field initializers of the - * current constructor and super constructors or constructors redirected - * to, starting from the current constructor. - * - Call the the constructor bodies, starting from the constructor(s) in the - * super class(es). - * - * Invariant: Both [classElement] and [functionElement] must be - * implementation elements. - */ - HGraph buildFactory(ClassElement classElement, - FunctionElement functionElement) { - assert(invariant(classElement, classElement.isImplementation)); - assert(invariant(functionElement, functionElement.isImplementation)); - FunctionExpression function = functionElement.parseNode(compiler); - // Note that constructors (like any other static function) do not need - // to deal with optional arguments. It is the callers job to provide all - // arguments as if they were positional. - - // The initializer list could contain closures. - openFunction(functionElement, function); - - Map<Element, HInstruction> fieldValues = new Map<Element, HInstruction>(); - - // Compile the possible initialization code for local fields and - // super fields. - buildFieldInitializers(classElement, fieldValues); - - // Compile field-parameters such as [:this.x:]. - FunctionSignature params = functionElement.computeSignature(compiler); - params.orderedForEachParameter((Element element) { - if (element.kind == ElementKind.FIELD_PARAMETER) { - // If the [element] is a field-parameter then - // initialize the field element with its value. - FieldParameterElement fieldParameterElement = element; - HInstruction parameterValue = localsHandler.readLocal(element); - fieldValues[fieldParameterElement.fieldElement] = parameterValue; - } - }); - - // Analyze the constructor and all referenced constructors and collect - // initializers and constructor bodies. - List<FunctionElement> constructors = <FunctionElement>[functionElement]; - buildInitializers(functionElement, constructors, fieldValues); - - // Call the JavaScript constructor with the fields as argument. - List<HInstruction> constructorArguments = <HInstruction>[]; - classElement.forEachInstanceField( - (ClassElement enclosingClass, Element member) { - constructorArguments.add(potentiallyCheckType( - fieldValues[member], member.computeType(compiler))); - }, - includeBackendMembers: true, - includeSuperMembers: true); - - InterfaceType type = classElement.computeType(compiler); - HType ssaType = new HBoundedType.exact(type); - HForeignNew newObject = new HForeignNew(classElement, - ssaType, - constructorArguments); - add(newObject); - - // Create the runtime type information, if needed. - List<HInstruction> inputs = <HInstruction>[]; - if (compiler.world.needsRti(classElement)) { - classElement.typeVariables.forEach((TypeVariableType typeVariable) { - inputs.add(localsHandler.directLocals[typeVariable.element]); - }); - callSetRuntimeTypeInfo(classElement, inputs, newObject); - } - - // Generate calls to the constructor bodies. - for (int index = constructors.length - 1; index >= 0; index--) { - FunctionElement constructor = constructors[index]; - assert(invariant(functionElement, constructor.isImplementation)); - ConstructorBodyElement body = getConstructorBody(constructor); - if (body == null) continue; - List bodyCallInputs = <HInstruction>[]; - bodyCallInputs.add(newObject); - FunctionSignature functionSignature = body.computeSignature(compiler); - functionSignature.orderedForEachParameter((parameter) { - if (!localsHandler.isBoxed(parameter)) { - // The parameter will be a field in the box passed as the - // last parameter. So no need to pass it. - bodyCallInputs.add(localsHandler.readLocal(parameter)); - } - }); - - // If parameters are checked, we pass the already computed - // boolean to the constructor body. - TreeElements elements = - compiler.enqueuer.resolution.getCachedElements(constructor); - Node node = constructor.parseNode(compiler); - ClosureClassMap parameterClosureData = - compiler.closureToClassMapper.getMappingForNestedFunction(node); - functionSignature.orderedForEachParameter((parameter) { - if (elements.isParameterChecked(parameter)) { - Element fieldCheck = - parameterClosureData.parametersWithSentinel[parameter]; - bodyCallInputs.add(localsHandler.readLocal(fieldCheck)); - } - }); - - // If there are locals that escape (ie used in closures), we - // pass the box to the constructor. - ClosureScope scopeData = parameterClosureData.capturingScopes[node]; - if (scopeData != null) { - bodyCallInputs.add(localsHandler.readLocal(scopeData.boxElement)); - } - - // TODO(ahe): The constructor name is statically resolved. See - // SsaCodeGenerator.visitInvokeDynamicMethod. Is there a cleaner - // way to do this? - SourceString name = - new SourceString(backend.namer.getName(body.declaration)); - // TODO(kasperl): This seems fishy. We shouldn't be inventing all - // these selectors. Maybe the resolver can do more of the work - // for us here? - LibraryElement library = body.getLibrary(); - Selector selector = new Selector.call( - name, library, bodyCallInputs.length - 1); - HInvokeDynamic invoke = - new HInvokeDynamicMethod(selector, bodyCallInputs); - invoke.element = body; - add(invoke); - } - close(new HReturn(newObject)).addSuccessor(graph.exit); - return closeFunction(); - } - - void addParameterCheckInstruction(Element element) { - HInstruction check; - Element checkResultElement = - localsHandler.closureData.parametersWithSentinel[element]; - if (currentElement.isGenerativeConstructorBody()) { - // A generative constructor body receives extra parameters that - // indicate if a parameter was passed to the factory. - check = addParameter(checkResultElement); - } else { - // This is the code we emit for a parameter that is being checked - // on whether it was given at value at the call site: - // - // foo([a = 42]) { - // if (?a) print('parameter passed $a'); - // } - // - // foo([a = 42]) { - // var t1 = identical(a, sentinel); - // if (t1) a = 42; - // if (!t1) print('parameter passed ' + a); - // } - - // Fetch the original default value of [element]; - Constant constant = compileVariable(element); - HConstant defaultValue = constant == null - ? graph.addConstantNull(constantSystem) - : graph.addConstant(constant); - - // Emit the equality check with the sentinel. - HConstant sentinel = graph.addConstant(SentinelConstant.SENTINEL); - HInstruction operand = parameters[element]; - check = new HIdentity(sentinel, operand); - add(check); - - // If the check succeeds, we must update the parameter with the - // default value. - handleIf(element.parseNode(compiler), - () => stack.add(check), - () => localsHandler.updateLocal(element, defaultValue), - null); - - // Create the instruction that parameter checks will use. - check = new HNot(check); - add(check); - } - - localsHandler.updateLocal(checkResultElement, check); - } - - /** - * Documentation wanted -- johnniwinther - * - * Invariant: [functionElement] must be the implementation element. - */ - void openFunction(Element element, Expression node) { - assert(invariant(element, element.isImplementation)); - HBasicBlock block = graph.addNewBlock(); - open(graph.entry); - - localsHandler.startFunction(element, node); - close(new HGoto()).addSuccessor(block); - - open(block); - - if (element is FunctionElement) { - FunctionElement functionElement = element; - FunctionSignature signature = functionElement.computeSignature(compiler); - signature.orderedForEachParameter((Element parameterElement) { - if (elements.isParameterChecked(parameterElement)) { - addParameterCheckInstruction(parameterElement); - } - }); - - // Put the type checks in the first successor of the entry, - // because that is where the type guards will also be inserted. - // This way we ensure that a type guard will dominate the type - // check. - signature.orderedForEachParameter((Element parameterElement) { - if (element.isGenerativeConstructorBody()) { - ClosureScope scopeData = - localsHandler.closureData.capturingScopes[node]; - if (scopeData != null - && scopeData.capturedVariableMapping.containsKey( - parameterElement)) { - // The parameter will be a field in the box passed as the - // last parameter. So no need to have it. - return; - } - } - HInstruction newParameter = potentiallyCheckType( - localsHandler.directLocals[parameterElement], - parameterElement.computeType(compiler)); - localsHandler.directLocals[parameterElement] = newParameter; - }); - - returnType = signature.returnType; - } else { - // Otherwise it is a lazy initializer which does not have parameters. - assert(element is VariableElement); - } - - // Add the type parameters of the class as parameters of this - // method. - var enclosing = element.enclosingElement; - if (element.isConstructor() && compiler.world.needsRti(enclosing)) { - enclosing.typeVariables.forEach((TypeVariableType typeVariable) { - HParameterValue param = addParameter(typeVariable.element); - localsHandler.directLocals[typeVariable.element] = param; - }); - } - } - - HInstruction potentiallyCheckType( - HInstruction original, DartType type, - { int kind: HTypeConversion.CHECKED_MODE_CHECK }) { - if (!compiler.enableTypeAssertions) return original; - HInstruction other = original.convertType(compiler, type, kind); - if (other != original) add(other); - return other; - } - - HGraph closeFunction() { - // TODO(kasperl): Make this goto an implicit return. - if (!isAborted()) close(new HGoto()).addSuccessor(graph.exit); - graph.finalize(); - return graph; - } - - HBasicBlock addNewBlock() { - HBasicBlock block = graph.addNewBlock(); - // If adding a new block during building of an expression, it is due to - // conditional expressions or short-circuit logical operators. - return block; - } - - void open(HBasicBlock block) { - block.open(); - current = block; - lastOpenedBlock = block; - } - - HBasicBlock close(HControlFlow end) { - HBasicBlock result = current; - current.close(end); - current = null; - return result; - } - - void goto(HBasicBlock from, HBasicBlock to) { - from.close(new HGoto()); - from.addSuccessor(to); - } - - bool isAborted() { - return current == null; - } - - /** - * Creates a new block, transitions to it from any current block, and - * opens the new block. - */ - HBasicBlock openNewBlock() { - HBasicBlock newBlock = addNewBlock(); - if (!isAborted()) goto(current, newBlock); - open(newBlock); - return newBlock; - } - - void add(HInstruction instruction) { - current.add(instruction); - } - - void addWithPosition(HInstruction instruction, Node node) { - add(attachPosition(instruction, node)); - } - - void push(HInstruction instruction) { - add(instruction); - stack.add(instruction); - } - - void pushWithPosition(HInstruction instruction, Node node) { - push(attachPosition(instruction, node)); - } - - HInstruction pop() { - return stack.removeLast(); - } - - void dup() { - stack.add(stack.last); - } - - HInstruction popBoolified() { - HInstruction value = pop(); - if (compiler.enableTypeAssertions) { - return potentiallyCheckType( - value, - compiler.boolClass.computeType(compiler), - kind: HTypeConversion.BOOLEAN_CONVERSION_CHECK); - } - HInstruction result = new HBoolify(value); - add(result); - return result; - } - - HInstruction attachPosition(HInstruction target, Node node) { - target.sourcePosition = sourceFileLocationForBeginToken(node); - return target; - } - - SourceFileLocation sourceFileLocationForBeginToken(Node node) => - sourceFileLocationForToken(node, node.getBeginToken()); - - SourceFileLocation sourceFileLocationForEndToken(Node node) => - sourceFileLocationForToken(node, node.getEndToken()); - - SourceFileLocation sourceFileLocationForToken(Node node, Token token) { - Element element = sourceElementStack.last; - // TODO(johnniwinther): remove the 'element.patch' hack. - if (element is FunctionElement) { - FunctionElement functionElement = element; - if (functionElement.patch != null) element = functionElement.patch; - } - Script script = element.getCompilationUnit().script; - SourceFile sourceFile = script.file; - SourceFileLocation location = new SourceFileLocation(sourceFile, token); - if (!location.isValid()) { - throw MessageKind.INVALID_SOURCE_FILE_LOCATION.message( - {'offset': token.charOffset, - 'fileName': sourceFile.filename, - 'length': sourceFile.text.length}); - } - return location; -} - - void visit(Node node) { - if (node != null) node.accept(this); - } - - visitBlock(Block node) { - for (Link<Node> link = node.statements.nodes; - !link.isEmpty; - link = link.tail) { - visit(link.head); - if (isAborted()) { - // The block has been aborted by a return or a throw. - if (!stack.isEmpty) compiler.cancel('non-empty instruction stack'); - return; - } - } - assert(!current.isClosed()); - if (!stack.isEmpty) compiler.cancel('non-empty instruction stack'); - } - - visitClassNode(ClassNode node) { - compiler.internalError('visitClassNode should not be called', node: node); - } - - visitExpressionStatement(ExpressionStatement node) { - visit(node.expression); - pop(); - } - - /** - * Creates a new loop-header block. The previous [current] block - * is closed with an [HGoto] and replaced by the newly created block. - * Also notifies the locals handler that we're entering a loop. - */ - JumpHandler beginLoopHeader(Node node) { - assert(!isAborted()); - HBasicBlock previousBlock = close(new HGoto()); - - JumpHandler jumpHandler = createJumpHandler(node); - HBasicBlock loopEntry = graph.addNewLoopHeaderBlock( - jumpHandler.target, - jumpHandler.labels()); - previousBlock.addSuccessor(loopEntry); - open(loopEntry); - - localsHandler.beginLoopHeader(node, loopEntry); - return jumpHandler; - } - - /** - * Ends the loop: - * - creates a new block and adds it as successor to the [branchBlock]. - * - opens the new block (setting as [current]). - * - notifies the locals handler that we're exiting a loop. - */ - void endLoop(HBasicBlock loopEntry, - HBasicBlock branchBlock, - JumpHandler jumpHandler, - LocalsHandler savedLocals) { - if (branchBlock == null && !jumpHandler.hasAnyBreak()) return; - - HBasicBlock loopExitBlock = addNewBlock(); - assert(branchBlock == null || branchBlock.successors.length == 1); - List<LocalsHandler> breakLocals = <LocalsHandler>[]; - jumpHandler.forEachBreak((HBreak breakInstruction, LocalsHandler locals) { - breakInstruction.block.addSuccessor(loopExitBlock); - breakLocals.add(locals); - }); - if (branchBlock != null) { - branchBlock.addSuccessor(loopExitBlock); - } - open(loopExitBlock); - localsHandler.endLoop(loopEntry); - if (!breakLocals.isEmpty) { - breakLocals.add(savedLocals); - localsHandler = savedLocals.mergeMultiple(breakLocals, loopExitBlock); - } else { - localsHandler = savedLocals; - } - } - - HSubGraphBlockInformation wrapStatementGraph(SubGraph statements) { - if (statements == null) return null; - return new HSubGraphBlockInformation(statements); - } - - HSubExpressionBlockInformation wrapExpressionGraph(SubExpression expression) { - if (expression == null) return null; - return new HSubExpressionBlockInformation(expression); - } - - // For while loops, initializer and update are null. - // The condition function must return a boolean result. - // None of the functions must leave anything on the stack. - void handleLoop(Node loop, - void initialize(), - HInstruction condition(), - void update(), - void body()) { - // Generate: - // <initializer> - // loop-entry: - // if (!<condition>) goto loop-exit; - // <body> - // <updates> - // goto loop-entry; - // loop-exit: - - localsHandler.startLoop(loop); - - // The initializer. - SubExpression initializerGraph = null; - HBasicBlock startBlock; - if (initialize != null) { - HBasicBlock initializerBlock = openNewBlock(); - startBlock = initializerBlock; - initialize(); - assert(!isAborted()); - initializerGraph = - new SubExpression(initializerBlock, current); - } - - JumpHandler jumpHandler = beginLoopHeader(loop); - HLoopInformation loopInfo = current.loopInformation; - HBasicBlock conditionBlock = current; - if (startBlock == null) startBlock = conditionBlock; - - HInstruction conditionInstruction = condition(); - HBasicBlock conditionExitBlock = - close(new HLoopBranch(conditionInstruction)); - SubExpression conditionExpression = - new SubExpression(conditionBlock, conditionExitBlock); - - LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); - - // The body. - HBasicBlock beginBodyBlock = addNewBlock(); - conditionExitBlock.addSuccessor(beginBodyBlock); - open(beginBodyBlock); - - localsHandler.enterLoopBody(loop); - body(); - - SubGraph bodyGraph = new SubGraph(beginBodyBlock, lastOpenedBlock); - HBasicBlock bodyBlock = current; - if (current != null) close(new HGoto()); - - SubExpression updateGraph; - - // Check that the loop has at least one back-edge. - if (jumpHandler.hasAnyContinue() || bodyBlock != null) { - // Update. - // We create an update block, even when we are in a while loop. There the - // update block is the jump-target for continue statements. We could avoid - // the creation if there is no continue, but for now we always create it. - HBasicBlock updateBlock = addNewBlock(); - - List<LocalsHandler> continueLocals = <LocalsHandler>[]; - jumpHandler.forEachContinue((HContinue instruction, - LocalsHandler locals) { - instruction.block.addSuccessor(updateBlock); - continueLocals.add(locals); - }); - - - if (bodyBlock != null) { - continueLocals.add(localsHandler); - bodyBlock.addSuccessor(updateBlock); - } - - open(updateBlock); - localsHandler = - continueLocals[0].mergeMultiple(continueLocals, updateBlock); - - HLabeledBlockInformation labelInfo; - List<LabelElement> labels = jumpHandler.labels(); - TargetElement target = elements[loop]; - if (!labels.isEmpty) { - beginBodyBlock.setBlockFlow( - new HLabeledBlockInformation( - new HSubGraphBlockInformation(bodyGraph), - jumpHandler.labels(), - isContinue: true), - updateBlock); - } else if (target != null && target.isContinueTarget) { - beginBodyBlock.setBlockFlow( - new HLabeledBlockInformation.implicit( - new HSubGraphBlockInformation(bodyGraph), - target, - isContinue: true), - updateBlock); - } - - localsHandler.enterLoopUpdates(loop); - - update(); - - HBasicBlock updateEndBlock = close(new HGoto()); - // The back-edge completing the cycle. - updateEndBlock.addSuccessor(conditionBlock); - updateGraph = new SubExpression(updateBlock, updateEndBlock); - } - - if (jumpHandler.hasAnyContinue() || bodyBlock != null) { - endLoop(conditionBlock, conditionExitBlock, jumpHandler, savedLocals); - conditionBlock.postProcessLoopHeader(); - HLoopBlockInformation info = - new HLoopBlockInformation( - HLoopBlockInformation.loopType(loop), - wrapExpressionGraph(initializerGraph), - wrapExpressionGraph(conditionExpression), - wrapStatementGraph(bodyGraph), - wrapExpressionGraph(updateGraph), - conditionBlock.loopInformation.target, - conditionBlock.loopInformation.labels, - sourceFileLocationForBeginToken(loop), - sourceFileLocationForEndToken(loop)); - - startBlock.setBlockFlow(info, current); - loopInfo.loopBlockInformation = info; - } else { - // There is no back edge for the loop, so we turn the code into: - // if (condition) { - // body; - // } else { - // // We always create an empty else block to avoid critical edges. - // } - // - // If there is any break in the body, we attach a synthetic - // label to the if. - HBasicBlock elseBlock = addNewBlock(); - open(elseBlock); - close(new HGoto()); - endLoop(conditionBlock, null, jumpHandler, savedLocals); - - // [endLoop] will not create an exit block if there are no - // breaks. - if (current == null) open(addNewBlock()); - elseBlock.addSuccessor(current); - SubGraph elseGraph = new SubGraph(elseBlock, elseBlock); - // Remove the loop information attached to the header. - conditionBlock.loopInformation = null; - - // Remove the [HLoopBranch] instruction and replace it with - // [HIf]. - HInstruction condition = conditionExitBlock.last.inputs[0]; - conditionExitBlock.addAtExit(new HIf(condition)); - conditionExitBlock.addSuccessor(elseBlock); - conditionExitBlock.remove(conditionExitBlock.last); - HIfBlockInformation info = - new HIfBlockInformation( - wrapExpressionGraph(conditionExpression), - wrapStatementGraph(bodyGraph), - wrapStatementGraph(elseGraph)); - - conditionBlock.setBlockFlow(info, current); - HIf ifBlock = conditionBlock.last; - ifBlock.blockInformation = conditionBlock.blockFlow; - - // If the body has any break, attach a synthesized label to the - // if block. - if (jumpHandler.hasAnyBreak()) { - TargetElement target = elements[loop]; - LabelElement label = target.addLabel(null, 'loop'); - label.setBreakTarget(); - SubGraph labelGraph = new SubGraph(conditionBlock, current); - HLabeledBlockInformation labelInfo = new HLabeledBlockInformation( - new HSubGraphBlockInformation(labelGraph), - <LabelElement>[label]); - - conditionBlock.setBlockFlow(labelInfo, current); - - jumpHandler.forEachBreak((HBreak breakInstruction, _) { - HBasicBlock block = breakInstruction.block; - block.addAtExit(new HBreak.toLabel(label)); - block.remove(breakInstruction); - }); - } - } - jumpHandler.close(); - } - - visitFor(For node) { - assert(node.body != null); - void buildInitializer() { - if (node.initializer == null) return; - Node initializer = node.initializer; - if (initializer != null) { - visit(initializer); - if (initializer.asExpression() != null) { - pop(); - } - } - } - HInstruction buildCondition() { - if (node.condition == null) { - return graph.addConstantBool(true, constantSystem); - } - visit(node.condition); - return popBoolified(); - } - void buildUpdate() { - for (Expression expression in node.update) { - visit(expression); - assert(!isAborted()); - // The result of the update instruction isn't used, and can just - // be dropped. - HInstruction updateInstruction = pop(); - } - } - void buildBody() { - visit(node.body); - } - handleLoop(node, buildInitializer, buildCondition, buildUpdate, buildBody); - } - - visitWhile(While node) { - HInstruction buildCondition() { - visit(node.condition); - return popBoolified(); - } - handleLoop(node, - () {}, - buildCondition, - () {}, - () { visit(node.body); }); - } - - visitDoWhile(DoWhile node) { - LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); - localsHandler.startLoop(node); - JumpHandler jumpHandler = beginLoopHeader(node); - HLoopInformation loopInfo = current.loopInformation; - HBasicBlock loopEntryBlock = current; - HBasicBlock bodyEntryBlock = current; - TargetElement target = elements[node]; - bool hasContinues = target != null && target.isContinueTarget; - if (hasContinues) { - // Add extra block to hang labels on. - // It doesn't currently work if they are on the same block as the - // HLoopInfo. The handling of HLabeledBlockInformation will visit a - // SubGraph that starts at the same block again, so the HLoopInfo is - // either handled twice, or it's handled after the labeled block info, - // both of which generate the wrong code. - // Using a separate block is just a simple workaround. - bodyEntryBlock = openNewBlock(); - } - localsHandler.enterLoopBody(node); - visit(node.body); - - // If there are no continues we could avoid the creation of the condition - // block. This could also lead to a block having multiple entries and exits. - HBasicBlock bodyExitBlock; - bool isAbortingBody = false; - if (current != null) { - bodyExitBlock = close(new HGoto()); - } else { - isAbortingBody = true; - bodyExitBlock = lastOpenedBlock; - } - - SubExpression conditionExpression; - HBasicBlock conditionEndBlock; - if (!isAbortingBody || hasContinues) { - HBasicBlock conditionBlock = addNewBlock(); - - List<LocalsHandler> continueLocals = <LocalsHandler>[]; - jumpHandler.forEachContinue((HContinue instruction, - LocalsHandler locals) { - instruction.block.addSuccessor(conditionBlock); - continueLocals.add(locals); - }); - - if (!isAbortingBody) { - bodyExitBlock.addSuccessor(conditionBlock); - } - - if (!continueLocals.isEmpty) { - if (!isAbortingBody) continueLocals.add(localsHandler); - localsHandler = - savedLocals.mergeMultiple(continueLocals, conditionBlock); - SubGraph bodyGraph = new SubGraph(bodyEntryBlock, bodyExitBlock); - List<LabelElement> labels = jumpHandler.labels(); - HSubGraphBlockInformation bodyInfo = - new HSubGraphBlockInformation(bodyGraph); - HLabeledBlockInformation info; - if (!labels.isEmpty) { - info = new HLabeledBlockInformation(bodyInfo, labels, - isContinue: true); - } else { - info = new HLabeledBlockInformation.implicit(bodyInfo, target, - isContinue: true); - } - bodyEntryBlock.setBlockFlow(info, conditionBlock); - } - open(conditionBlock); - - visit(node.condition); - assert(!isAborted()); - HInstruction conditionInstruction = popBoolified(); - conditionEndBlock = close( - new HLoopBranch(conditionInstruction, HLoopBranch.DO_WHILE_LOOP)); - - HBasicBlock avoidCriticalEdge = addNewBlock(); - conditionEndBlock.addSuccessor(avoidCriticalEdge); - open(avoidCriticalEdge); - close(new HGoto()); - avoidCriticalEdge.addSuccessor(loopEntryBlock); // The back-edge. - - conditionExpression = - new SubExpression(conditionBlock, conditionEndBlock); - } - - endLoop(loopEntryBlock, conditionEndBlock, jumpHandler, localsHandler); - if (!isAbortingBody || hasContinues) { - loopEntryBlock.postProcessLoopHeader(); - SubGraph bodyGraph = new SubGraph(loopEntryBlock, bodyExitBlock); - HLoopBlockInformation loopBlockInfo = - new HLoopBlockInformation( - HLoopBlockInformation.DO_WHILE_LOOP, - null, - wrapExpressionGraph(conditionExpression), - wrapStatementGraph(bodyGraph), - null, - loopEntryBlock.loopInformation.target, - loopEntryBlock.loopInformation.labels, - sourceFileLocationForBeginToken(node), - sourceFileLocationForEndToken(node)); - loopEntryBlock.setBlockFlow(loopBlockInfo, current); - loopInfo.loopBlockInformation = loopBlockInfo; - } else { - // If the loop has no back edge, we remove the loop information - // on the header. - loopEntryBlock.loopInformation = null; - - // If the body of the loop has any break, we attach a - // synthesized label to the body. - if (jumpHandler.hasAnyBreak()) { - SubGraph bodyGraph = new SubGraph(bodyEntryBlock, bodyExitBlock); - TargetElement target = elements[node]; - LabelElement label = target.addLabel(null, 'loop'); - label.setBreakTarget(); - HLabeledBlockInformation info = new HLabeledBlockInformation( - new HSubGraphBlockInformation(bodyGraph), <LabelElement>[label]); - loopEntryBlock.setBlockFlow(info, current); - jumpHandler.forEachBreak((HBreak breakInstruction, _) { - HBasicBlock block = breakInstruction.block; - block.addAtExit(new HBreak.toLabel(label)); - block.remove(breakInstruction); - }); - } - } - jumpHandler.close(); - } - - visitFunctionExpression(FunctionExpression node) { - ClosureClassMap nestedClosureData = - compiler.closureToClassMapper.getMappingForNestedFunction(node); - assert(nestedClosureData != null); - assert(nestedClosureData.closureClassElement != null); - ClassElement closureClassElement = - nestedClosureData.closureClassElement; - FunctionElement callElement = nestedClosureData.callElement; - // TODO(ahe): This should be registered in codegen, not here. - compiler.enqueuer.codegen.addToWorkList(callElement, elements); - // TODO(ahe): This should be registered in codegen, not here. - compiler.enqueuer.codegen.registerInstantiatedClass(closureClassElement); - assert(!closureClassElement.hasLocalScopeMembers); - - List<HInstruction> capturedVariables = <HInstruction>[]; - closureClassElement.forEachBackendMember((Element member) { - // The backendMembers also contains the call method(s). We are only - // interested in the fields. - if (member.isField()) { - Element capturedLocal = nestedClosureData.capturedFieldMapping[member]; - assert(capturedLocal != null); - capturedVariables.add(localsHandler.readLocal(capturedLocal)); - } - }); - - HType type = new HBoundedType.exact( - compiler.functionClass.computeType(compiler)); - push(new HForeignNew(closureClassElement, type, capturedVariables)); - } - - visitFunctionDeclaration(FunctionDeclaration node) { - visit(node.function); - localsHandler.updateLocal(elements[node], pop()); - } - - visitIdentifier(Identifier node) { - if (node.isThis()) { - stack.add(localsHandler.readThis()); - } else { - compiler.internalError("SsaBuilder.visitIdentifier on non-this", - node: node); - } - } - - visitIf(If node) { - handleIf(node, - () => visit(node.condition), - () => visit(node.thenPart), - node.elsePart != null ? () => visit(node.elsePart) : null); - } - - void handleIf(Node diagnosticNode, - void visitCondition(), void visitThen(), void visitElse()) { - SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, diagnosticNode); - branchBuilder.handleIf(visitCondition, visitThen, visitElse); - } - - void visitLogicalAndOr(Send node, Operator op) { - SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, node); - branchBuilder.handleLogicalAndOrWithLeftNode( - node.receiver, - () { visit(node.argumentsNode); }, - isAnd: (const SourceString("&&") == op.source)); - } - - - void visitLogicalNot(Send node) { - assert(node.argumentsNode is Prefix); - visit(node.receiver); - HNot not = new HNot(popBoolified()); - pushWithPosition(not, node); - } - - void visitUnary(Send node, Operator op) { - if (node.isParameterCheck) { - Element element = elements[node.receiver]; - Node function = element.enclosingElement.parseNode(compiler); - ClosureClassMap parameterClosureData = - compiler.closureToClassMapper.getMappingForNestedFunction(function); - Element fieldCheck = - parameterClosureData.parametersWithSentinel[element]; - stack.add(localsHandler.readLocal(fieldCheck)); - return; - } - assert(node.argumentsNode is Prefix); - visit(node.receiver); - assert(!identical(op.token.kind, PLUS_TOKEN)); - HInstruction operand = pop(); - - // See if we can constant-fold right away. This avoids rewrites later on. - if (operand is HConstant) { - UnaryOperation operation = constantSystem.lookupUnary(op.source); - HConstant constant = operand; - Constant folded = operation.fold(constant.constant); - if (folded != null) { - stack.add(graph.addConstant(folded)); - return; - } - } - - HInvokeDynamicMethod result = - buildInvokeDynamic(node, elements.getSelector(node), operand, []); - pushWithPosition(result, node); - } - - void visitBinary( - HInstruction left, Operator op, HInstruction right, Send send) { - Selector selector = null; - // TODO(ngeoffray): The resolver creates these selectors already - // but does not put them on the [send] instruction. - switch (op.source.stringValue) { - case "+": - case "+=": - case "++": - selector = new Selector.binaryOperator(const SourceString('+')); - break; - case "-": - case "-=": - case "--": - selector = new Selector.binaryOperator(const SourceString('-')); - break; - case "*": - case "*=": - selector = new Selector.binaryOperator(const SourceString('*')); - break; - case "/": - case "/=": - selector = new Selector.binaryOperator(const SourceString('/')); - break; - case "~/": - case "~/=": - selector = new Selector.binaryOperator(const SourceString('~/')); - break; - case "%": - case "%=": - selector = new Selector.binaryOperator(const SourceString('%')); - break; - case "<<": - case "<<=": - selector = new Selector.binaryOperator(const SourceString('<<')); - break; - case ">>": - case ">>=": - selector = new Selector.binaryOperator(const SourceString('>>')); - break; - case "|": - case "|=": - selector = new Selector.binaryOperator(const SourceString('|')); - break; - case "&": - case "&=": - selector = new Selector.binaryOperator(const SourceString('&')); - break; - case "^": - case "^=": - selector = new Selector.binaryOperator(const SourceString('^')); - break; - case "==": - case "!=": - selector = new Selector.binaryOperator(const SourceString('==')); - break; - case "<": - selector = new Selector.binaryOperator(const SourceString('<')); - break; - case "<=": - selector = new Selector.binaryOperator(const SourceString('<=')); - break; - case ">": - selector = new Selector.binaryOperator(const SourceString('>')); - break; - case ">=": - selector = new Selector.binaryOperator(const SourceString('>=')); - break; - case "===": - pushWithPosition(new HIdentity(left, right), op); - return; - case "!==": - HIdentity eq = new HIdentity(left, right); - add(eq); - pushWithPosition(new HNot(eq), op); - return; - default: - compiler.internalError("Unexpected operator $op", node: op); - break; - } - - pushWithPosition( - buildInvokeDynamic(send, selector, left, [right]), - op); - if (op.source.stringValue == '!=') { - HBoolify bl = new HBoolify(pop()); - add(bl); - pushWithPosition(new HNot(bl), op); - } - } - - HInstruction generateInstanceSendReceiver(Send send) { - assert(Elements.isInstanceSend(send, elements)); - if (send.receiver == null) { - return localsHandler.readThis(); - } - visit(send.receiver); - return pop(); - } - - String getTargetName(ErroneousElement error, [String prefix]) { - String result = error.name.slowToString(); - if (?prefix) { - result = '$prefix $result'; - } - return result; - } - - /** - * Returns a set of interceptor classes that contain a member whose - * signature matches the given [selector]. - */ - Set<ClassElement> getInterceptedClassesOn(Selector selector) { - return backend.getInterceptedClassesOn(selector); - } - - void generateInstanceGetterWithCompiledReceiver(Send send, - HInstruction receiver) { - assert(Elements.isInstanceSend(send, elements)); - // TODO(kasperl): This is a convoluted way of checking if we're - // generating code for a compound assignment. If we are, we need - // to get the selector from the mapping for the AST selector node. - Selector selector = (send.asSendSet() == null) - ? elements.getSelector(send) - : elements.getSelector(send.selector); - assert(selector.isGetter()); - SourceString getterName = selector.name; - Set<ClassElement> interceptedClasses = getInterceptedClassesOn(selector); - - bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector); - if (interceptedClasses != null) { - // If we're using an interceptor class, emit a call to the - // interceptor method and then the actual dynamic call on the - // interceptor object. - HInstruction instruction = - invokeInterceptor(interceptedClasses, receiver, send); - instruction = new HInvokeDynamicGetter( - selector, null, instruction, !hasGetter); - // Add the receiver as an argument to the getter call on the - // interceptor. - instruction.inputs.add(receiver); - pushWithPosition(instruction, send); - } else { - pushWithPosition( - new HInvokeDynamicGetter(selector, null, receiver, !hasGetter), send); - } - } - - void generateGetter(Send send, Element element) { - if (Elements.isStaticOrTopLevelField(element)) { - Constant value; - if (element.isField() && !element.isAssignable()) { - // A static final or const. Get its constant value and inline it if - // the value can be compiled eagerly. - value = compileVariable(element); - } - if (value != null) { - stack.add(graph.addConstant(value)); - } else if (element.isField() && isLazilyInitialized(element)) { - push(new HLazyStatic(element)); - } else { - if (element.isGetter()) { - Selector selector = elements.getSelector(send); - if (tryInlineMethod(element, selector, const Link<Node>(), send)) { - return; - } - } - // TODO(5346): Try to avoid the need for calling [declaration] before - // creating an [HStatic]. - push(new HStatic(element.declaration)); - if (element.isGetter()) { - push(new HInvokeStatic(<HInstruction>[pop()], HType.UNKNOWN)); - } - } - } else if (Elements.isInstanceSend(send, elements)) { - HInstruction receiver = generateInstanceSendReceiver(send); - generateInstanceGetterWithCompiledReceiver(send, receiver); - } else if (Elements.isStaticOrTopLevelFunction(element)) { - // TODO(5346): Try to avoid the need for calling [declaration] before - // creating an [HStatic]. - push(new HStatic(element.declaration)); - // TODO(ahe): This should be registered in codegen. - compiler.enqueuer.codegen.registerGetOfStaticFunction(element); - } else if (Elements.isErroneousElement(element)) { - // An erroneous element indicates an unresolved static getter. - generateThrowNoSuchMethod(send, - getTargetName(element, 'get'), - argumentNodes: const Link<Node>()); - } else { - stack.add(localsHandler.readLocal(element)); - } - } - - void generateInstanceSetterWithCompiledReceiver(Send send, - HInstruction receiver, - HInstruction value) { - assert(Elements.isInstanceSend(send, elements)); - Selector selector = elements.getSelector(send); - assert(selector.isSetter()); - SourceString setterName = selector.name; - bool hasSetter = compiler.world.hasAnyUserDefinedSetter(selector); - Set<ClassElement> interceptedClasses = getInterceptedClassesOn(selector); - if (interceptedClasses != null) { - // If we're using an interceptor class, emit a call to the - // getInterceptor method and then the actual dynamic call on the - // interceptor object. - HInstruction instruction = - invokeInterceptor(interceptedClasses, receiver, send); - instruction = new HInvokeDynamicSetter( - selector, null, instruction, receiver, !hasSetter); - // Add the value as an argument to the setter call on the - // interceptor. - instruction.inputs.add(value); - addWithPosition(instruction, send); - } else { - addWithPosition( - new HInvokeDynamicSetter(selector, null, receiver, value, !hasSetter), - send); - } - stack.add(value); - } - - void generateSetter(SendSet send, Element element, HInstruction value) { - if (Elements.isStaticOrTopLevelField(element)) { - if (element.isSetter()) { - HStatic target = new HStatic(element); - add(target); - addWithPosition( - new HInvokeStatic(<HInstruction>[target, value], HType.UNKNOWN), - send); - } else { - value = potentiallyCheckType(value, element.computeType(compiler)); - addWithPosition(new HStaticStore(element, value), send); - } - stack.add(value); - } else if (element == null || Elements.isInstanceField(element)) { - HInstruction receiver = generateInstanceSendReceiver(send); - generateInstanceSetterWithCompiledReceiver(send, receiver, value); - } else if (Elements.isErroneousElement(element)) { - // An erroneous element indicates an unresolved static setter. - generateThrowNoSuchMethod(send, - getTargetName(element, 'set'), - argumentNodes: send.arguments); - } else { - stack.add(value); - // If the value does not already have a name, give it here. - if (value.sourceElement == null) { - value.sourceElement = element; - } - HInstruction checked = potentiallyCheckType( - value, element.computeType(compiler)); - if (!identical(checked, value)) { - pop(); - stack.add(checked); - } - localsHandler.updateLocal(element, checked); - } - } - - HInstruction invokeInterceptor(Set<ClassElement> intercepted, - HInstruction receiver, - Send send) { - HInterceptor interceptor = new HInterceptor(intercepted, receiver); - add(interceptor); - return interceptor; - } - - void pushInvokeHelper0(Element helper, HType type) { - HInstruction reference = new HStatic(helper); - add(reference); - List<HInstruction> inputs = <HInstruction>[reference]; - HInstruction result = new HInvokeStatic(inputs, type); - push(result); - } - - void pushInvokeHelper1(Element helper, HInstruction a0, HType type) { - HInstruction reference = new HStatic(helper); - add(reference); - List<HInstruction> inputs = <HInstruction>[reference, a0]; - HInstruction result = new HInvokeStatic(inputs, type); - push(result); - } - - void pushInvokeHelper2(Element helper, - HInstruction a0, - HInstruction a1, - HType type) { - HInstruction reference = new HStatic(helper); - add(reference); - List<HInstruction> inputs = <HInstruction>[reference, a0, a1]; - HInstruction result = new HInvokeStatic(inputs, type); - push(result); - } - - void pushInvokeHelper3(Element helper, - HInstruction a0, - HInstruction a1, - HInstruction a2, - HType type) { - HInstruction reference = new HStatic(helper); - add(reference); - List<HInstruction> inputs = <HInstruction>[reference, a0, a1, a2]; - HInstruction result = new HInvokeStatic(inputs, type); - push(result); - } - - void pushInvokeHelper4(Element helper, - HInstruction a0, - HInstruction a1, - HInstruction a2, - HInstruction a3, - HType type) { - HInstruction reference = new HStatic(helper); - add(reference); - List<HInstruction> inputs = <HInstruction>[reference, a0, a1, a2, a3]; - HInstruction result = new HInvokeStatic(inputs, type); - push(result); - } - - void pushInvokeHelper5(Element helper, - HInstruction a0, - HInstruction a1, - HInstruction a2, - HInstruction a3, - HInstruction a4, - HType type) { - HInstruction reference = new HStatic(helper); - add(reference); - List<HInstruction> inputs = <HInstruction>[reference, a0, a1, a2, a3, a4]; - HInstruction result = new HInvokeStatic(inputs, type); - push(result); - } - - HForeign createForeign(String code, HType type, List<HInstruction> inputs) { - return new HForeign(new LiteralDartString(code), type, inputs); - } - - HInstruction getRuntimeTypeInfo(HInstruction target) { - pushInvokeHelper1(backend.getGetRuntimeTypeInfo(), target, HType.UNKNOWN); - return pop(); - } - - // TODO(karlklose): change construction of the representations to be GVN'able - // (dartbug.com/7182). - List<HInstruction> buildTypeArgumentRepresentations(DartType type) { - HInstruction createForeignArray(String code, inputs) { - return createForeign(code, HType.READABLE_ARRAY, inputs); - } - HInstruction typeInfo; - - /// Helper to create an instruction that contains the runtime value of - /// the type variable [variable]. - HInstruction getTypeArgument(TypeVariableType variable) { - if (typeInfo == null) { - typeInfo = getRuntimeTypeInfo(localsHandler.readThis()); - } - int intIndex = RuntimeTypeInformation.getTypeVariableIndex(variable); - HInstruction index = graph.addConstantInt(intIndex, constantSystem); - return createForeignArray('#[#]', <HInstruction>[typeInfo, index]); - } - - // Compute the representation of the type arguments, including access - // to the runtime type information for type variables as instructions. - HInstruction representations; - if (type.element.isTypeVariable()) { - return <HInstruction>[getTypeArgument(type)]; - } else { - assert(type.element.isClass()); - List<HInstruction> arguments = <HInstruction>[]; - InterfaceType interface = type; - for (DartType argument in interface.typeArguments) { - List<HInstruction> inputs = <HInstruction>[]; - String template = rti.getTypeRepresentation(argument, (variable) { - HInstruction runtimeType = getTypeArgument(variable); - add(runtimeType); - inputs.add(runtimeType); - }); - HInstruction representation = createForeignArray(template, inputs); - add(representation); - arguments.add(representation); - } - return arguments; - } - } - - visitOperatorSend(node) { - Operator op = node.selector; - if (const SourceString("[]") == op.source) { - visitDynamicSend(node); - } else if (const SourceString("&&") == op.source || - const SourceString("||") == op.source) { - visitLogicalAndOr(node, op); - } else if (const SourceString("!") == op.source) { - visitLogicalNot(node); - } else if (node.argumentsNode is Prefix) { - visitUnary(node, op); - } else if (const SourceString("is") == op.source) { - visit(node.receiver); - HInstruction expression = pop(); - Node argument = node.arguments.head; - TypeAnnotation typeAnnotation = argument.asTypeAnnotation(); - bool isNot = false; - // TODO(ngeoffray): Duplicating pattern in resolver. We should - // add a new kind of node. - if (typeAnnotation == null) { - typeAnnotation = argument.asSend().receiver; - isNot = true; - } - DartType type = elements.getType(typeAnnotation); - if (type.isMalformed) { - String reasons = Types.fetchReasonsFromMalformedType(type); - if (compiler.enableTypeAssertions) { - generateMalformedSubtypeError(node, expression, type, reasons); - } else { - generateRuntimeError(node, '$type is malformed: $reasons'); - } - return; - } - if (type.element.isTypeVariable()) { - // TODO(karlklose): remove this check when the backend can deal with - // checks of the form [:o is T:] where [:T:] is a type variable. - stack.add(graph.addConstantBool(true, constantSystem)); - return; - } - - HInstruction instruction; - if (type.element.isTypeVariable() || - RuntimeTypeInformation.hasTypeArguments(type)) { - HInstruction typeInfo = getRuntimeTypeInfo(expression); - // TODO(karlklose): make isSubtype a HInstruction to enable - // optimizations? - Element helper = compiler.findHelper(const SourceString('isSubtype')); - HInstruction isSubtype = new HStatic(helper); - add(isSubtype); - // Build a list of representations for the type arguments. - List<HInstruction> representations = - buildTypeArgumentRepresentations(type); - // For each type argument, build a call to isSubtype, with the type - // argument as first and the representation of the tested type as - // second argument. - List<HInstruction> checks = <HInstruction>[]; - int index = 0; - representations.forEach((HInstruction representation) { - HInstruction position = graph.addConstantInt(index, constantSystem); - // Get the index'th type argument from the runtime type information. - HInstruction typeArgument = - createForeign('#[#]', HType.UNKNOWN, [typeInfo, position]); - add(typeArgument); - // Create the call to isSubtype. - List<HInstruction> inputs = - <HInstruction>[isSubtype, typeArgument, representation]; - HInstruction call = new HInvokeStatic(inputs, HType.BOOLEAN); - add(call); - checks.add(call); - index++; - }); - instruction = new HIs(type, <HInstruction>[expression]..addAll(checks)); - } else { - instruction = new HIs(type, <HInstruction>[expression]); - } - if (isNot) { - add(instruction); - instruction = new HNot(instruction); - } - push(instruction); - } else if (const SourceString("as") == op.source) { - visit(node.receiver); - HInstruction expression = pop(); - Node argument = node.arguments.head; - TypeAnnotation typeAnnotation = argument.asTypeAnnotation(); - DartType type = elements.getType(typeAnnotation); - HInstruction converted = expression.convertType( - compiler, type, HTypeConversion.CAST_TYPE_CHECK); - if (converted != expression) add(converted); - stack.add(converted); - } else { - visit(node.receiver); - visit(node.argumentsNode); - var right = pop(); - var left = pop(); - visitBinary(left, op, right, node); - } - } - - void addDynamicSendArgumentsToList(Send node, List<HInstruction> list) { - Selector selector = elements.getSelector(node); - if (selector.namedArgumentCount == 0) { - addGenericSendArgumentsToList(node.arguments, list); - } else { - // Visit positional arguments and add them to the list. - Link<Node> arguments = node.arguments; - int positionalArgumentCount = selector.positionalArgumentCount; - for (int i = 0; - i < positionalArgumentCount; - arguments = arguments.tail, i++) { - visit(arguments.head); - list.add(pop()); - } - - // Visit named arguments and add them into a temporary map. - Map<SourceString, HInstruction> instructions = - new Map<SourceString, HInstruction>(); - List<SourceString> namedArguments = selector.namedArguments; - int nameIndex = 0; - for (; !arguments.isEmpty; arguments = arguments.tail) { - visit(arguments.head); - instructions[namedArguments[nameIndex++]] = pop(); - } - - // Iterate through the named arguments to add them to the list - // of instructions, in an order that can be shared with - // selectors with the same named arguments. - List<SourceString> orderedNames = selector.getOrderedNamedArguments(); - for (SourceString name in orderedNames) { - list.add(instructions[name]); - } - } - } - - /** - * Returns true if the arguments were compatible with the function signature. - * - * Invariant: [element] must be an implementation element. - */ - bool addStaticSendArgumentsToList(Selector selector, - Link<Node> arguments, - FunctionElement element, - List<HInstruction> list) { - assert(invariant(element, element.isImplementation)); - - HInstruction compileArgument(Node argument) { - visit(argument); - return pop(); - } - - HInstruction handleConstant(Element parameter) { - Constant constant; - TreeElements calleeElements = - compiler.enqueuer.resolution.getCachedElements(element); - if (calleeElements.isParameterChecked(parameter)) { - constant = SentinelConstant.SENTINEL; - } else { - constant = compileConstant(parameter); - } - return graph.addConstant(constant); - } - - return selector.addArgumentsToList(arguments, - list, - element, - compileArgument, - handleConstant, - compiler); - } - - void addGenericSendArgumentsToList(Link<Node> link, List<HInstruction> list) { - for (; !link.isEmpty; link = link.tail) { - visit(link.head); - list.add(pop()); - } - } - - visitDynamicSend(Send node) { - Selector selector = elements.getSelector(node); - - SourceString dartMethodName; - bool isNotEquals = false; - if (node.isIndex && !node.arguments.tail.isEmpty) { - dartMethodName = Elements.constructOperatorName( - const SourceString('[]='), false); - } else if (node.selector.asOperator() != null) { - SourceString name = node.selector.asIdentifier().source; - isNotEquals = identical(name.stringValue, '!='); - dartMethodName = Elements.constructOperatorName( - name, node.argumentsNode is Prefix); - } else { - dartMethodName = node.selector.asIdentifier().source; - } - - Element element = elements[node]; - bool isClosureCall = false; - if (element != null && compiler.world.hasNoOverridingMember(element)) { - if (tryInlineMethod(element, selector, node.arguments, node)) { - if (element.isGetter()) { - // If the element is a getter, we are doing a closure call - // on what this getter returns. - assert(selector.isCall()); - isClosureCall = true; - } else { - return; - } - } - } - - List<HInstruction> inputs = <HInstruction>[]; - if (isClosureCall) inputs.add(pop()); - - HInstruction receiver; - if (!isClosureCall) { - if (node.receiver == null) { - receiver = localsHandler.readThis(); - } else { - visit(node.receiver); - receiver = pop(); - } - } - - addDynamicSendArgumentsToList(node, inputs); - - HInstruction invoke; - if (isClosureCall) { - Selector closureSelector = new Selector.callClosureFrom(selector); - invoke = new HInvokeClosure(closureSelector, inputs); - } else { - invoke = buildInvokeDynamic(node, selector, receiver, inputs); - } - - pushWithPosition(invoke, node); - - if (isNotEquals) { - HNot not = new HNot(popBoolified()); - push(not); - } - } - - visitClosureSend(Send node) { - Selector selector = elements.getSelector(node); - assert(node.receiver == null); - Element element = elements[node]; - HInstruction closureTarget; - if (element == null) { - visit(node.selector); - closureTarget = pop(); - } else { - assert(Elements.isLocal(element)); - closureTarget = localsHandler.readLocal(element); - } - var inputs = <HInstruction>[]; - inputs.add(closureTarget); - addDynamicSendArgumentsToList(node, inputs); - Selector closureSelector = new Selector.callClosureFrom(selector); - pushWithPosition(new HInvokeClosure(closureSelector, inputs), node); - } - - void handleForeignJs(Send node) { - Link<Node> link = node.arguments; - // If the invoke is on foreign code, don't visit the first - // argument, which is the type, and the second argument, - // which is the foreign code. - if (link.isEmpty || link.tail.isEmpty) { - compiler.cancel('At least two arguments expected', - node: node.argumentsNode); - } - List<HInstruction> inputs = <HInstruction>[]; - Node type = link.head; - Node code = link.tail.head; - addGenericSendArgumentsToList(link.tail.tail, inputs); - - native.NativeBehavior nativeBehavior = - compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node); - HType ssaType = mapNativeBehaviorType(nativeBehavior); - if (code is StringNode) { - StringNode codeString = code; - if (!codeString.isInterpolation) { - // codeString may not be an interpolation, but may be a juxtaposition. - push(new HForeign(codeString.dartString, ssaType, inputs)); - return; - } - } - compiler.cancel('JS code must be a string literal', node: code); - } - - void handleForeignJsCurrentIsolate(Send node) { - if (!node.arguments.isEmpty) { - compiler.cancel( - 'Too many arguments to JS_CURRENT_ISOLATE', node: node); - } - - if (!compiler.hasIsolateSupport()) { - // If the isolate library is not used, we just generate code - // to fetch the Leg's current isolate. - String name = backend.namer.CURRENT_ISOLATE; - push(new HForeign(new DartString.literal(name), - HType.UNKNOWN, - <HInstruction>[])); - } else { - // Call a helper method from the isolate library. The isolate - // library uses its own isolate structure, that encapsulates - // Leg's isolate. - Element element = compiler.isolateHelperLibrary.find( - const SourceString('_currentIsolate')); - if (element == null) { - compiler.cancel( - 'Isolate library and compiler mismatch', node: node); - } - pushInvokeHelper0(element, HType.UNKNOWN); - } - } - - void handleForeignJsCallInIsolate(Send node) { - Link<Node> link = node.arguments; - if (!compiler.hasIsolateSupport()) { - // If the isolate library is not used, we just invoke the - // closure. - visit(link.tail.head); - Selector selector = new Selector.callClosure(0); - push(new HInvokeClosure(selector, <HInstruction>[pop()])); - } else { - // Call a helper method from the isolate library. - Element element = compiler.isolateHelperLibrary.find( - const SourceString('_callInIsolate')); - if (element == null) { - compiler.cancel( - 'Isolate library and compiler mismatch', node: node); - } - HStatic target = new HStatic(element); - add(target); - List<HInstruction> inputs = <HInstruction>[target]; - addGenericSendArgumentsToList(link, inputs); - push(new HInvokeStatic(inputs, HType.UNKNOWN)); - } - } - - FunctionSignature handleForeignRawFunctionRef(Send node, String name) { - if (node.arguments.isEmpty || !node.arguments.tail.isEmpty) { - compiler.cancel('"$name" requires exactly one argument', - node: node.argumentsNode); - } - Node closure = node.arguments.head; - Element element = elements[closure]; - if (!Elements.isStaticOrTopLevelFunction(element)) { - compiler.cancel( - '"$name" requires a static or top-level method', - node: closure); - } - FunctionElement function = element; - // TODO(johnniwinther): Try to eliminate the need to distinguish declaration - // and implementation signatures. Currently it is need because the - // signatures have different elements for parameters. - FunctionElement implementation = function.implementation; - FunctionSignature params = implementation.computeSignature(compiler); - if (params.optionalParameterCount != 0) { - compiler.cancel( - '"$name" does not handle closure with optional parameters', - node: closure); - } - visit(closure); - return params; - } - - void handleForeignDartClosureToJs(Send node, String name) { - FunctionSignature params = handleForeignRawFunctionRef(node, name); - List<HInstruction> inputs = <HInstruction>[pop()]; - String invocationName = backend.namer.invocationName( - new Selector.callClosure(params.requiredParameterCount)); - push(new HForeign(new DartString.literal('#.$invocationName'), - HType.UNKNOWN, - inputs)); - } - - void handleForeignSetCurrentIsolate(Send node) { - if (node.arguments.isEmpty || !node.arguments.tail.isEmpty) { - compiler.cancel('Exactly one argument required', - node: node.argumentsNode); - } - visit(node.arguments.head); - String isolateName = backend.namer.CURRENT_ISOLATE; - push(new HForeign(new DartString.literal("$isolateName = #"), - HType.UNKNOWN, - <HInstruction>[pop()])); - } - - void handleForeignCreateIsolate(Send node) { - if (!node.arguments.isEmpty) { - compiler.cancel('Too many arguments', - node: node.argumentsNode); - } - String constructorName = backend.namer.isolateName; - push(new HForeign(new DartString.literal("new $constructorName"), - HType.UNKNOWN, - <HInstruction>[])); - } - - visitForeignSend(Send node) { - Selector selector = elements.getSelector(node); - SourceString name = selector.name; - if (name == const SourceString('JS')) { - handleForeignJs(node); - } else if (name == const SourceString('JS_CURRENT_ISOLATE')) { - handleForeignJsCurrentIsolate(node); - } else if (name == const SourceString('JS_CALL_IN_ISOLATE')) { - handleForeignJsCallInIsolate(node); - } else if (name == const SourceString('DART_CLOSURE_TO_JS')) { - handleForeignDartClosureToJs(node, 'DART_CLOSURE_TO_JS'); - } else if (name == const SourceString('RAW_DART_FUNCTION_REF')) { - handleForeignRawFunctionRef(node, 'RAW_DART_FUNCTION_REF'); - } else if (name == const SourceString('JS_SET_CURRENT_ISOLATE')) { - handleForeignSetCurrentIsolate(node); - } else if (name == const SourceString('JS_CREATE_ISOLATE')) { - handleForeignCreateIsolate(node); - } else if (name == const SourceString('JS_OPERATOR_IS_PREFIX')) { - stack.add(addConstantString(node, backend.namer.operatorIsPrefix())); - } else { - throw "Unknown foreign: ${selector}"; - } - } - - generateSuperNoSuchMethodSend(Send node) { - Selector selector = elements.getSelector(node); - SourceString name = selector.name; - - ClassElement cls = currentElement.getEnclosingClass(); - Element element = cls.lookupSuperMember(Compiler.NO_SUCH_METHOD); - if (element.enclosingElement.declaration != compiler.objectClass) { - // Register the call as dynamic if [:noSuchMethod:] on the super class - // is _not_ the default implementation from [:Object:]. - compiler.enqueuer.codegen.registerDynamicInvocation(name, selector); - } - HStatic target = new HStatic(element); - add(target); - HInstruction self = localsHandler.readThis(); - Constant nameConstant = constantSystem.createString( - new DartString.literal(name.slowToString()), node); - - String internalName = backend.namer.invocationName(selector); - Constant internalNameConstant = - constantSystem.createString(new DartString.literal(internalName), node); - - Element createInvocationMirror = - compiler.findHelper(Compiler.CREATE_INVOCATION_MIRROR); - - var arguments = new List<HInstruction>(); - if (node.argumentsNode != null) { - addGenericSendArgumentsToList(node.arguments, arguments); - } - var argumentsInstruction = new HLiteralList(arguments); - add(argumentsInstruction); - - var argumentNames = new List<HInstruction>(); - for (SourceString argumentName in selector.namedArguments) { - Constant argumentNameConstant = - constantSystem.createString(new DartString.literal( - argumentName.slowToString()), node); - argumentNames.add(graph.addConstant(argumentNameConstant)); - } - var argumentNamesInstruction = new HLiteralList(argumentNames); - add(argumentNamesInstruction); - - Constant kindConstant = - constantSystem.createInt(selector.invocationMirrorKind); - - pushInvokeHelper5(createInvocationMirror, - graph.addConstant(nameConstant), - graph.addConstant(internalNameConstant), - graph.addConstant(kindConstant), - argumentsInstruction, - argumentNamesInstruction, - HType.UNKNOWN); - - var inputs = <HInstruction>[ - target, - self, - pop()]; - push(new HInvokeSuper(inputs)); - } - - visitSend(Send node) { - Element element = elements[node]; - if (element != null && identical(element, currentElement)) { - graph.isRecursiveMethod = true; - } - super.visitSend(node); - } - - visitSuperSend(Send node) { - Selector selector = elements.getSelector(node); - Element element = elements[node]; - if (element == null) return generateSuperNoSuchMethodSend(node); - // TODO(5346): Try to avoid the need for calling [declaration] before - // creating an [HStatic]. - HInstruction target = new HStatic(element.declaration); - HInstruction context = localsHandler.readThis(); - add(target); - var inputs = <HInstruction>[target, context]; - if (node.isPropertyAccess) { - push(new HInvokeSuper(inputs)); - } else if (element.isFunction() || element.isGenerativeConstructor()) { - // TODO(5347): Try to avoid the need for calling [implementation] before - // calling [addStaticSendArgumentsToList]. - FunctionElement function = element.implementation; - bool succeeded = addStaticSendArgumentsToList(selector, node.arguments, - function, inputs); - if (!succeeded) { - generateWrongArgumentCountError(node, element, node.arguments); - } else { - push(new HInvokeSuper(inputs)); - } - } else { - target = new HInvokeSuper(inputs); - add(target); - inputs = <HInstruction>[target]; - addDynamicSendArgumentsToList(node, inputs); - Selector closureSelector = new Selector.callClosureFrom(selector); - push(new HInvokeClosure(closureSelector, inputs)); - } - } - - /** - * Documentation wanted -- johnniwinther - * - * Invariant: [argument] must not be malformed in checked mode. - */ - HInstruction analyzeTypeArgument(DartType argument, Node currentNode) { - assert(invariant(currentNode, - !compiler.enableTypeAssertions || !argument.isMalformed, - message: '$argument is malformed in checked mode')); - if (argument == compiler.types.dynamicType || argument.isMalformed) { - // Represent [dynamic] as [null]. - return graph.addConstantNull(constantSystem); - } - - // These variables are shared between invocations of the helper. - HInstruction typeInfo; - List<HInstruction> inputs = <HInstruction>[]; - - /** - * Helper to create an instruction that gets the value of a type variable. - */ - void addTypeVariableReference(TypeVariableType type) { - Element member = currentElement; - if (member.enclosingElement.isClosure()) { - ClosureClassElement closureClass = member.enclosingElement; - member = closureClass.methodElement; - member = member.getOutermostEnclosingMemberOrTopLevel(); - } - if (member.isFactoryConstructor()) { - // The type variable is stored in a parameter of the factory. - inputs.add(localsHandler.readLocal(type.element)); - } else if (member.isInstanceMember() - || member.isGenerativeConstructor()) { - // The type variable is stored in [this]. - if (typeInfo == null) { - pushInvokeHelper1(backend.getGetRuntimeTypeInfo(), - localsHandler.readThis(), - HType.UNKNOWN); - typeInfo = pop(); - } - int index = RuntimeTypeInformation.getTypeVariableIndex(type); - HInstruction foreign = createForeign('#[$index]', HType.STRING, - <HInstruction>[typeInfo]); - add(foreign); - inputs.add(foreign); - } else { - // TODO(ngeoffray): Match the VM behavior and throw an - // exception at runtime. - compiler.cancel('Unimplemented unresolved type variable', - node: currentNode); - } - } - - String template = rti.getTypeRepresentation(argument, - addTypeVariableReference); - HInstruction result = createForeign(template, HType.STRING, inputs); - add(result); - return result; - } - - void handleListConstructor(InterfaceType type, - Node currentNode, - HInstruction newObject) { - if (!compiler.world.needsRti(type.element)) return; - List<HInstruction> inputs = <HInstruction>[]; - if (!type.isRaw) { - type.typeArguments.forEach((DartType argument) { - inputs.add(analyzeTypeArgument(argument, currentNode)); - }); - } - callSetRuntimeTypeInfo(type.element, inputs, newObject); - } - - void callSetRuntimeTypeInfo(ClassElement element, - List<HInstruction> rtiInputs, - HInstruction newObject) { - if (!compiler.world.needsRti(element) || element.typeVariables.isEmpty) { - return; - } - - HInstruction typeInfo = new HLiteralList(rtiInputs); - add(typeInfo); - - // Set the runtime type information on the object. - Element typeInfoSetterElement = backend.getSetRuntimeTypeInfo(); - HInstruction typeInfoSetter = new HStatic(typeInfoSetterElement); - add(typeInfoSetter); - add(new HInvokeStatic( - <HInstruction>[typeInfoSetter, newObject, typeInfo], HType.UNKNOWN)); - } - - /** - * Documentation wanted -- johnniwinther - * - * Invariant: [type] must not be malformed in checked mode. - */ - visitNewSend(Send node, InterfaceType type) { - assert(invariant(node, - !compiler.enableTypeAssertions || !type.isMalformed, - message: '$type is malformed in checked mode')); - bool isListConstructor = false; - computeType(element) { - Element originalElement = elements[node]; - if (identical(originalElement.getEnclosingClass(), compiler.listClass)) { - isListConstructor = true; - if (node.arguments.isEmpty) { - return HType.EXTENDABLE_ARRAY; - } else { - return HType.MUTABLE_ARRAY; - } - } else if (element.isGenerativeConstructor()) { - ClassElement cls = element.getEnclosingClass(); - return new HBoundedType.exact(cls.thisType); - } else { - return HType.UNKNOWN; - } - } - - Element constructor = elements[node]; - Selector selector = elements.getSelector(node); - if (compiler.enqueuer.resolution.getCachedElements(constructor) == null) { - compiler.internalError("Unresolved element: $constructor", node: node); - } - FunctionElement functionElement = constructor; - constructor = functionElement.redirectionTarget; - // TODO(5346): Try to avoid the need for calling [declaration] before - // creating an [HStatic]. - HInstruction target = new HStatic(constructor.declaration); - add(target); - var inputs = <HInstruction>[]; - inputs.add(target); - // TODO(5347): Try to avoid the need for calling [implementation] before - // calling [addStaticSendArgumentsToList]. - bool succeeded = addStaticSendArgumentsToList(selector, node.arguments, - constructor.implementation, - inputs); - if (!succeeded) { - generateWrongArgumentCountError(node, constructor, node.arguments); - return; - } - - ClassElement cls = constructor.getEnclosingClass(); - if (cls.isAbstract(compiler) && constructor.isGenerativeConstructor()) { - generateAbstractClassInstantiationError(node, cls.name.slowToString()); - return; - } - if (compiler.world.needsRti(cls)) { - Link<DartType> typeVariable = cls.typeVariables; - type.typeArguments.forEach((DartType argument) { - inputs.add(analyzeTypeArgument(argument, node)); - typeVariable = typeVariable.tail; - }); - // Also add null to non-provided type variables to call the - // constructor with the right number of arguments. - while (!typeVariable.isEmpty) { - inputs.add(graph.addConstantNull(constantSystem)); - typeVariable = typeVariable.tail; - } - } - - HType elementType = computeType(constructor); - HInstruction newInstance = new HInvokeStatic(inputs, elementType); - pushWithPosition(newInstance, node); - - // The List constructor forwards to a Dart static method that does - // not know about the type argument. Therefore we special case - // this constructor to have the setRuntimeTypeInfo called where - // the 'new' is done. - if (isListConstructor && compiler.world.needsRti(compiler.listClass)) { - handleListConstructor(type, node, newInstance); - } - } - - visitStaticSend(Send node) { - Selector selector = elements.getSelector(node); - Element element = elements[node]; - if (element.isForeign(compiler)) { - visitForeignSend(node); - return; - } - if (element.isErroneous()) { - generateThrowNoSuchMethod(node, - getTargetName(element), - argumentNodes: node.arguments); - return; - } - if (identical(element, compiler.assertMethod) - && !compiler.enableUserAssertions) { - stack.add(graph.addConstantNull(constantSystem)); - return; - } - compiler.ensure(!element.isGenerativeConstructor()); - if (element.isFunction()) { - bool isIdenticalFunction = element == compiler.identicalFunction; - - if (!isIdenticalFunction - && tryInlineMethod(element, selector, node.arguments, node)) { - return; - } - - HInstruction target = new HStatic(element); - add(target); - var inputs = <HInstruction>[target]; - // TODO(5347): Try to avoid the need for calling [implementation] before - // calling [addStaticSendArgumentsToList]. - bool succeeded = addStaticSendArgumentsToList(selector, node.arguments, - element.implementation, - inputs); - if (!succeeded) { - generateWrongArgumentCountError(node, element, node.arguments); - return; - } - - if (isIdenticalFunction) { - pushWithPosition(new HIdentity(inputs[1], inputs[2]), node); - return; - } - - HInvokeStatic instruction = new HInvokeStatic(inputs, HType.UNKNOWN); - // TODO(ngeoffray): Only do this if knowing the return type is - // useful. - HType returnType = - builder.backend.optimisticReturnTypesWithRecompilationOnTypeChange( - currentElement, element); - if (returnType != null) instruction.guaranteedType = returnType; - pushWithPosition(instruction, node); - } else { - generateGetter(node, element); - List<HInstruction> inputs = <HInstruction>[pop()]; - addDynamicSendArgumentsToList(node, inputs); - Selector closureSelector = new Selector.callClosureFrom(selector); - pushWithPosition(new HInvokeClosure(closureSelector, inputs), node); - } - } - - HConstant addConstantString(Node node, String string) { - DartString dartString = new DartString.literal(string); - Constant constant = constantSystem.createString(dartString, node); - return graph.addConstant(constant); - } - - visitTypeReferenceSend(Send node) { - Element element = elements[node]; - if (element.isClass() || element.isTypedef()) { - // TODO(karlklose): add type representation - ConstantHandler handler = compiler.constantHandler; - Constant constant = handler.compileNodeWithDefinitions(node, elements); - stack.add(graph.addConstant(constant)); - } else if (element.isTypeVariable()) { - // TODO(6248): implement support for type variables. - compiler.unimplemented('first class type for type variable', node: node); - } else { - internalError('unexpected element kind $element', node: node); - } - if (node.isCall) { - // This send is of the form 'e(...)', where e is resolved to a type - // reference. We create a regular closure call on the result of the type - // reference instead of creating a NoSuchMethodError to avoid pulling it - // in if it is not used (e.g., in a try/catch). - HInstruction target = pop(); - Selector selector = elements.getSelector(node); - List<HInstruction> inputs = <HInstruction>[target]; - addDynamicSendArgumentsToList(node, inputs); - Selector closureSelector = new Selector.callClosureFrom(selector); - push(new HInvokeClosure(closureSelector, inputs)); - } - } - - visitGetterSend(Send node) { - generateGetter(node, elements[node]); - } - - // TODO(antonm): migrate rest of SsaBuilder to internalError. - internalError(String reason, {Node node}) { - compiler.internalError(reason, node: node); - } - - void generateError(Node node, String message, Element helper) { - HInstruction errorMessage = addConstantString(node, message); - pushInvokeHelper1(helper, errorMessage, HType.UNKNOWN); - } - - void generateRuntimeError(Node node, String message) { - generateError(node, message, backend.getThrowRuntimeError()); - } - - void generateAbstractClassInstantiationError(Node node, String message) { - generateError(node, - message, - backend.getThrowAbstractClassInstantiationError()); - } - - void generateThrowNoSuchMethod(Node diagnosticNode, - String methodName, - {Link<Node> argumentNodes, - List<HInstruction> argumentValues, - List<String> existingArguments}) { - Element helper = - compiler.findHelper(const SourceString('throwNoSuchMethod')); - Constant receiverConstant = - constantSystem.createString(new DartString.empty(), diagnosticNode); - HInstruction receiver = graph.addConstant(receiverConstant); - DartString dartString = new DartString.literal(methodName); - Constant nameConstant = - constantSystem.createString(dartString, diagnosticNode); - HInstruction name = graph.addConstant(nameConstant); - if (argumentValues == null) { - argumentValues = <HInstruction>[]; - argumentNodes.forEach((argumentNode) { - visit(argumentNode); - HInstruction value = pop(); - argumentValues.add(value); - }); - } - HInstruction arguments = new HLiteralList(argumentValues); - add(arguments); - HInstruction existingNamesList; - if (existingArguments != null) { - List<HInstruction> existingNames = <HInstruction>[]; - for (String name in existingArguments) { - HInstruction nameConstant = - graph.addConstantString(new DartString.literal(name), - diagnosticNode, constantSystem); - existingNames.add(nameConstant); - } - existingNamesList = new HLiteralList(existingNames); - add(existingNamesList); - } else { - existingNamesList = graph.addConstantNull(constantSystem); - } - pushInvokeHelper4( - helper, receiver, name, arguments, existingNamesList, HType.UNKNOWN); - } - - /** - * Generate code to throw a [NoSuchMethodError] exception for calling a - * method with a wrong number of arguments or mismatching named optional - * arguments. - */ - void generateWrongArgumentCountError(Node diagnosticNode, - FunctionElement function, - Link<Node> argumentNodes) { - List<String> existingArguments = <String>[]; - FunctionSignature signature = function.computeSignature(compiler); - signature.forEachParameter((Element parameter) { - existingArguments.add(parameter.name.slowToString()); - }); - generateThrowNoSuchMethod(diagnosticNode, - function.name.slowToString(), - argumentNodes: argumentNodes, - existingArguments: existingArguments); - } - - void generateMalformedSubtypeError(Node node, HInstruction value, - DartType type, String reasons) { - HInstruction typeString = addConstantString(node, type.toString()); - HInstruction reasonsString = addConstantString(node, reasons); - Element helper = backend.getThrowMalformedSubtypeError(); - pushInvokeHelper3(helper, value, typeString, reasonsString, HType.UNKNOWN); - } - - visitNewExpression(NewExpression node) { - Element element = elements[node.send]; - if (!Elements.isErroneousElement(element)) { - FunctionElement function = element; - element = function.redirectionTarget; - } - if (Elements.isErroneousElement(element)) { - ErroneousElement error = element; - if (error.messageKind == MessageKind.CANNOT_FIND_CONSTRUCTOR) { - generateThrowNoSuchMethod(node.send, - getTargetName(error, 'constructor'), - argumentNodes: node.send.arguments); - } else { - Message message = error.messageKind.message(error.messageArguments); - generateRuntimeError(node.send, message.toString()); - } - } else if (node.isConst()) { - // TODO(karlklose): add type representation - ConstantHandler handler = compiler.constantHandler; - Constant constant = handler.compileNodeWithDefinitions(node, elements); - stack.add(graph.addConstant(constant)); - } else { - DartType type = elements.getType(node); - if (compiler.enableTypeAssertions && type.isMalformed) { - String reasons = Types.fetchReasonsFromMalformedType(type); - // TODO(johnniwinther): Change to resemble type errors from bounds check - // on type arguments. - generateRuntimeError(node, '$type is malformed: $reasons'); - } else { - // TODO(karlklose): move this type registration to the codegen. - compiler.codegenWorld.instantiatedTypes.add(type); - Send send = node.send; - Element constructor = elements[send]; - Selector selector = elements.getSelector(send); - if (!tryInlineMethod(constructor, selector, send.arguments, node)) { - visitNewSend(send, type); - } - } - } - } - - HInvokeDynamicMethod buildInvokeDynamic(Node node, - Selector selector, - HInstruction receiver, - List<HInstruction> arguments) { - Set<ClassElement> interceptedClasses = getInterceptedClassesOn(selector); - List<HInstruction> inputs = <HInstruction>[]; - bool isIntercepted = interceptedClasses != null; - if (isIntercepted) { - assert(!interceptedClasses.isEmpty); - inputs.add(invokeInterceptor(interceptedClasses, receiver, node)); - } - inputs.add(receiver); - inputs.addAll(arguments); - return new HInvokeDynamicMethod(selector, inputs, isIntercepted); - } - - visitSendSet(SendSet node) { - Element element = elements[node]; - if (!Elements.isUnresolved(element) && element.impliesType()) { - Identifier selector = node.selector; - generateThrowNoSuchMethod(node, selector.source.slowToString(), - argumentNodes: node.arguments); - return; - } - Operator op = node.assignmentOperator; - if (node.isSuperCall) { - if (element == null) return generateSuperNoSuchMethodSend(node); - HInstruction target = new HStatic(element); - HInstruction context = localsHandler.readThis(); - add(target); - var inputs = <HInstruction>[target, context]; - addDynamicSendArgumentsToList(node, inputs); - if (!identical(node.assignmentOperator.source.stringValue, '=')) { - compiler.unimplemented('complex super assignment', - node: node.assignmentOperator); - } - push(new HInvokeSuper(inputs, isSetter: true)); - } else if (node.isIndex) { - if (const SourceString("=") == op.source) { - visitDynamicSend(node); - HInvokeDynamicMethod method = pop(); - // Push the value. - stack.add(method.inputs.last); - } else { - visit(node.receiver); - HInstruction receiver = pop(); - visit(node.argumentsNode); - HInstruction value; - HInstruction index; - // Compound assignments are considered as being prefix. - bool isCompoundAssignment = op.source.stringValue.endsWith('='); - bool isPrefix = !node.isPostfix; - Element getter = elements[node.selector]; - if (isCompoundAssignment) { - value = pop(); - index = pop(); - } else { - index = pop(); - value = graph.addConstantInt(1, constantSystem); - } - - HInvokeDynamicMethod left = buildInvokeDynamic( - node, new Selector.index(), receiver, [index]); - add(left); - visitBinary(left, op, value, node); - value = pop(); - HInvokeDynamicMethod assign = buildInvokeDynamic( - node, new Selector.indexSet(), receiver, [index, value]); - add(assign); - if (isPrefix) { - stack.add(value); - } else { - stack.add(left); - } - } - } else if (const SourceString("=") == op.source) { - Element element = elements[node]; - Link<Node> link = node.arguments; - assert(!link.isEmpty && link.tail.isEmpty); - visit(link.head); - HInstruction value = pop(); - generateSetter(node, element, value); - } else if (identical(op.source.stringValue, "is")) { - compiler.internalError("is-operator as SendSet", node: op); - } else { - assert(const SourceString("++") == op.source || - const SourceString("--") == op.source || - node.assignmentOperator.source.stringValue.endsWith("=")); - Element element = elements[node]; - bool isCompoundAssignment = !node.arguments.isEmpty; - bool isPrefix = !node.isPostfix; // Compound assignments are prefix. - - // [receiver] is only used if the node is an instance send. - HInstruction receiver = null; - Element selectorElement = elements[node]; - if (Elements.isInstanceSend(node, elements)) { - receiver = generateInstanceSendReceiver(node); - generateInstanceGetterWithCompiledReceiver(node, receiver); - } else { - generateGetter(node, elements[node.selector]); - } - HInstruction left = pop(); - HInstruction right; - if (isCompoundAssignment) { - visit(node.argumentsNode); - right = pop(); - } else { - right = graph.addConstantInt(1, constantSystem); - } - visitBinary(left, op, right, node); - HInstruction operation = pop(); - assert(operation != null); - if (Elements.isInstanceSend(node, elements)) { - assert(receiver != null); - generateInstanceSetterWithCompiledReceiver(node, receiver, operation); - } else { - assert(receiver == null); - generateSetter(node, element, operation); - } - if (!isPrefix) { - pop(); - stack.add(left); - } - } - } - - void visitLiteralInt(LiteralInt node) { - stack.add(graph.addConstantInt(node.value, constantSystem)); - } - - void visitLiteralDouble(LiteralDouble node) { - stack.add(graph.addConstantDouble(node.value, constantSystem)); - } - - void visitLiteralBool(LiteralBool node) { - stack.add(graph.addConstantBool(node.value, constantSystem)); - } - - void visitLiteralString(LiteralString node) { - stack.add(graph.addConstantString(node.dartString, node, constantSystem)); - } - - void visitStringJuxtaposition(StringJuxtaposition node) { - if (!node.isInterpolation) { - // This is a simple string with no interpolations. - stack.add(graph.addConstantString(node.dartString, node, constantSystem)); - return; - } - StringBuilderVisitor stringBuilder = new StringBuilderVisitor(this, node); - stringBuilder.visit(node); - stack.add(stringBuilder.result); - } - - void visitLiteralNull(LiteralNull node) { - stack.add(graph.addConstantNull(constantSystem)); - } - - visitNodeList(NodeList node) { - for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) { - if (isAborted()) { - compiler.reportWarning(link.head, 'dead code'); - } else { - visit(link.head); - } - } - } - - void visitParenthesizedExpression(ParenthesizedExpression node) { - visit(node.expression); - } - - visitOperator(Operator node) { - // Operators are intercepted in their surrounding Send nodes. - compiler.internalError('visitOperator should not be called', node: node); - } - - visitCascade(Cascade node) { - visit(node.expression); - // Remove the result and reveal the duplicated receiver on the stack. - pop(); - } - - visitCascadeReceiver(CascadeReceiver node) { - visit(node.expression); - dup(); - } - - void handleInTryStatement() { - if (!inTryStatement) return; - HBasicBlock block = close(new HExitTry()); - HBasicBlock newBlock = graph.addNewBlock(); - block.addSuccessor(newBlock); - open(newBlock); - } - - visitReturn(Return node) { - if (identical(node.getBeginToken().stringValue, 'native')) { - native.handleSsaNative(this, node.expression); - return; - } - assert(invariant(node, !node.isRedirectingFactoryBody)); - HInstruction value; - if (node.expression == null) { - value = graph.addConstantNull(constantSystem); - } else { - visit(node.expression); - value = pop(); - value = potentiallyCheckType(value, returnType); - } - - handleInTryStatement(); - - if (!inliningStack.isEmpty) { - localsHandler.updateLocal(returnElement, value); - } else { - close(attachPosition(new HReturn(value), node)).addSuccessor(graph.exit); - } - } - - visitThrow(Throw node) { - if (node.expression == null) { - HInstruction exception = rethrowableException; - if (exception == null) { - exception = graph.addConstantNull(constantSystem); - compiler.internalError( - 'rethrowableException should not be null', node: node); - } - close(new HThrow(exception, isRethrow: true)); - } else { - visit(node.expression); - close(new HThrow(pop())); - } - } - - visitTypeAnnotation(TypeAnnotation node) { - compiler.internalError('visiting type annotation in SSA builder', - node: node); - } - - visitVariableDefinitions(VariableDefinitions node) { - for (Link<Node> link = node.definitions.nodes; - !link.isEmpty; - link = link.tail) { - Node definition = link.head; - if (definition is Identifier) { - HInstruction initialValue = graph.addConstantNull(constantSystem); - localsHandler.updateLocal(elements[definition], initialValue); - } else { - assert(definition is SendSet); - visitSendSet(definition); - pop(); // Discard value. - } - } - } - - visitLiteralList(LiteralList node) { - if (node.isConst()) { - ConstantHandler handler = compiler.constantHandler; - Constant constant = handler.compileNodeWithDefinitions(node, elements); - stack.add(graph.addConstant(constant)); - return; - } - - List<HInstruction> inputs = <HInstruction>[]; - for (Link<Node> link = node.elements.nodes; - !link.isEmpty; - link = link.tail) { - visit(link.head); - inputs.add(pop()); - } - push(new HLiteralList(inputs)); - } - - visitConditional(Conditional node) { - SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); - brancher.handleConditional(() => visit(node.condition), - () => visit(node.thenExpression), - () => visit(node.elseExpression)); - } - - visitStringInterpolation(StringInterpolation node) { - StringBuilderVisitor stringBuilder = new StringBuilderVisitor(this, node); - stringBuilder.visit(node); - stack.add(stringBuilder.result); - } - - visitStringInterpolationPart(StringInterpolationPart node) { - // The parts are iterated in visitStringInterpolation. - compiler.internalError('visitStringInterpolation should not be called', - node: node); - } - - visitEmptyStatement(EmptyStatement node) { - // Do nothing, empty statement. - } - - visitModifiers(Modifiers node) { - compiler.unimplemented('SsaBuilder.visitModifiers', node: node); - } - - visitBreakStatement(BreakStatement node) { - assert(!isAborted()); - handleInTryStatement(); - TargetElement target = elements[node]; - assert(target != null); - JumpHandler handler = jumpTargets[target]; - assert(handler != null); - if (node.target == null) { - handler.generateBreak(); - } else { - LabelElement label = elements[node.target]; - handler.generateBreak(label); - } - } - - visitContinueStatement(ContinueStatement node) { - handleInTryStatement(); - TargetElement target = elements[node]; - assert(target != null); - JumpHandler handler = jumpTargets[target]; - assert(handler != null); - if (node.target == null) { - handler.generateContinue(); - } else { - LabelElement label = elements[node.target]; - assert(label != null); - handler.generateContinue(label); - } - } - - /** - * Creates a [JumpHandler] for a statement. The node must be a jump - * target. If there are no breaks or continues targeting the statement, - * a special "null handler" is returned. - */ - JumpHandler createJumpHandler(Statement node) { - TargetElement element = elements[node]; - if (element == null || !identical(element.statement, node)) { - // No breaks or continues to this node. - return new NullJumpHandler(compiler); - } - return new JumpHandler(this, element); - } - - visitForIn(ForIn node) { - // Generate a structure equivalent to: - // Iterator<E> $iter = <iterable>.iterator; - // while ($iter.moveNext()) { - // E <declaredIdentifier> = $iter.current; - // <body> - // } - - // The iterator is shared between initializer, condition and body. - HInstruction iterator; - void buildInitializer() { - SourceString iteratorName = const SourceString("iterator"); - Selector selector = - new Selector.getter(iteratorName, currentElement.getLibrary()); - Set<ClassElement> interceptedClasses = getInterceptedClassesOn(selector); - visit(node.expression); - HInstruction receiver = pop(); - bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector); - if (interceptedClasses == null) { - iterator = - new HInvokeDynamicGetter(selector, null, receiver, hasGetter); - } else { - HInterceptor interceptor = - invokeInterceptor(interceptedClasses, receiver, null); - iterator = - new HInvokeDynamicGetter(selector, null, interceptor, hasGetter); - // Add the receiver as an argument to the getter call on the - // interceptor. - iterator.inputs.add(receiver); - } - add(iterator); - } - HInstruction buildCondition() { - SourceString name = const SourceString('moveNext'); - Selector selector = new Selector.call( - name, currentElement.getLibrary(), 0); - bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector); - push(new HInvokeDynamicMethod(selector, <HInstruction>[iterator])); - return popBoolified(); - } - void buildBody() { - SourceString name = const SourceString('current'); - Selector call = new Selector.getter(name, currentElement.getLibrary()); - bool hasGetter = compiler.world.hasAnyUserDefinedGetter(call); - push(new HInvokeDynamicGetter(call, null, iterator, hasGetter)); - - Element variable; - if (node.declaredIdentifier.asSend() != null) { - variable = elements[node.declaredIdentifier]; - } else { - assert(node.declaredIdentifier.asVariableDefinitions() != null); - VariableDefinitions variableDefinitions = node.declaredIdentifier; - variable = elements[variableDefinitions.definitions.nodes.head]; - } - HInstruction oldVariable = pop(); - if (variable.isErroneous()) { - generateThrowNoSuchMethod(node, - getTargetName(variable, 'set'), - argumentValues: <HInstruction>[oldVariable]); - pop(); - } else { - localsHandler.updateLocal(variable, oldVariable); - } - - visit(node.body); - } - handleLoop(node, buildInitializer, buildCondition, () {}, buildBody); - } - - visitLabel(Label node) { - compiler.internalError('SsaBuilder.visitLabel', node: node); - } - - visitLabeledStatement(LabeledStatement node) { - Statement body = node.statement; - if (body is Loop || body is SwitchStatement) { - // Loops and switches handle their own labels. - visit(body); - return; - } - // Non-loop statements can only be break targets, not continue targets. - TargetElement targetElement = elements[body]; - if (targetElement == null || !identical(targetElement.statement, body)) { - // Labeled statements with no element on the body have no breaks. - // A different target statement only happens if the body is itself - // a break or continue for a different target. In that case, this - // label is also always unused. - visit(body); - return; - } - LocalsHandler beforeLocals = new LocalsHandler.from(localsHandler); - assert(targetElement.isBreakTarget); - JumpHandler handler = new JumpHandler(this, targetElement); - // Introduce a new basic block. - HBasicBlock entryBlock = openNewBlock(); - visit(body); - SubGraph bodyGraph = new SubGraph(entryBlock, lastOpenedBlock); - - HBasicBlock joinBlock = graph.addNewBlock(); - List<LocalsHandler> breakLocals = <LocalsHandler>[]; - handler.forEachBreak((HBreak breakInstruction, LocalsHandler locals) { - breakInstruction.block.addSuccessor(joinBlock); - breakLocals.add(locals); - }); - bool hasBreak = breakLocals.length > 0; - if (!isAborted()) { - goto(current, joinBlock); - breakLocals.add(localsHandler); - } - open(joinBlock); - localsHandler = beforeLocals.mergeMultiple(breakLocals, joinBlock); - - if (hasBreak) { - // There was at least one reachable break, so the label is needed. - entryBlock.setBlockFlow( - new HLabeledBlockInformation(new HSubGraphBlockInformation(bodyGraph), - handler.labels()), - joinBlock); - } - handler.close(); - } - - visitLiteralMap(LiteralMap node) { - if (node.isConst()) { - ConstantHandler handler = compiler.constantHandler; - Constant constant = handler.compileNodeWithDefinitions(node, elements); - stack.add(graph.addConstant(constant)); - return; - } - List<HInstruction> inputs = <HInstruction>[]; - for (Link<Node> link = node.entries.nodes; - !link.isEmpty; - link = link.tail) { - visit(link.head); - inputs.addLast(pop()); - inputs.addLast(pop()); - } - HLiteralList keyValuePairs = new HLiteralList(inputs); - add(keyValuePairs); - pushInvokeHelper1(backend.getMapMaker(), keyValuePairs, - new HType.fromBoundedType(compiler.mapClass.computeType(compiler), - compiler, - false)); - } - - visitLiteralMapEntry(LiteralMapEntry node) { - visit(node.value); - visit(node.key); - } - - visitNamedArgument(NamedArgument node) { - visit(node.expression); - } - - visitSwitchStatement(SwitchStatement node) { - if (tryBuildConstantSwitch(node)) return; - - LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); - HBasicBlock startBlock = openNewBlock(); - visit(node.expression); - HInstruction expression = pop(); - if (node.cases.isEmpty) { - return; - } - - Link<Node> cases = node.cases.nodes; - JumpHandler jumpHandler = createJumpHandler(node); - - buildSwitchCases(cases, expression); - - HBasicBlock lastBlock = lastOpenedBlock; - - // Create merge block for break targets. - HBasicBlock joinBlock = new HBasicBlock(); - List<LocalsHandler> caseLocals = <LocalsHandler>[]; - jumpHandler.forEachBreak((HBreak instruction, LocalsHandler locals) { - instruction.block.addSuccessor(joinBlock); - caseLocals.add(locals); - }); - if (!isAborted()) { - // The current flow is only aborted if the switch has a default that - // aborts (all previous cases must abort, and if there is no default, - // it's possible to miss all the cases). - caseLocals.add(localsHandler); - goto(current, joinBlock); - } - if (caseLocals.length != 0) { - graph.addBlock(joinBlock); - open(joinBlock); - if (caseLocals.length == 1) { - localsHandler = caseLocals[0]; - } else { - localsHandler = savedLocals.mergeMultiple(caseLocals, joinBlock); - } - } else { - // The joinblock is not used. - joinBlock = null; - } - startBlock.setBlockFlow( - new HLabeledBlockInformation.implicit( - new HSubGraphBlockInformation(new SubGraph(startBlock, lastBlock)), - elements[node]), - joinBlock); - jumpHandler.close(); - } - - bool tryBuildConstantSwitch(SwitchStatement node) { - Map<CaseMatch, Constant> constants = new Map<CaseMatch, Constant>(); - // First check whether all case expressions are compile-time constants, - // and all have the same type that doesn't override operator==. - // TODO(lrn): Move the constant resolution to the resolver, so - // we can report an error before reaching the backend. - DartType firstConstantType = null; - bool failure = false; - for (SwitchCase switchCase in node.cases) { - for (Node labelOrCase in switchCase.labelsAndCases) { - if (labelOrCase is CaseMatch) { - CaseMatch match = labelOrCase; - Constant constant = - compiler.constantHandler.tryCompileNodeWithDefinitions( - match.expression, elements); - if (constant == null) { - compiler.reportWarning(match.expression, - MessageKind.NOT_A_COMPILE_TIME_CONSTANT.error()); - failure = true; - continue; - } - if (firstConstantType == null) { - firstConstantType = constant.computeType(compiler); - if (nonPrimitiveTypeOverridesEquals(constant)) { - compiler.reportWarning(match.expression, - MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS.error()); - failure = true; - } - } else { - DartType constantType = - constant.computeType(compiler); - if (constantType != firstConstantType) { - compiler.reportWarning(match.expression, - MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL.error()); - failure = true; - } - } - constants[labelOrCase] = constant; - } else { - compiler.reportWarning(node, "Unsupported: Labels on cases"); - failure = true; - } - } - } - if (failure) { - return false; - } - - // TODO(ngeoffray): Handle switch-instruction in bailout code. - work.allowSpeculativeOptimization = false; - // Then build a switch structure. - HBasicBlock expressionStart = openNewBlock(); - visit(node.expression); - HInstruction expression = pop(); - if (node.cases.isEmpty) { - return true; - } - HBasicBlock expressionEnd = current; - - HSwitch switchInstruction = new HSwitch(<HInstruction>[expression]); - HBasicBlock expressionBlock = close(switchInstruction); - JumpHandler jumpHandler = createJumpHandler(node); - LocalsHandler savedLocals = localsHandler; - - List<List<Constant>> matchExpressions = <List<Constant>>[]; - List<HStatementInformation> statements = <HStatementInformation>[]; - bool hasDefault = false; - Element getFallThroughErrorElement = - compiler.findHelper(const SourceString("getFallThroughError")); - HasNextIterator<Node> caseIterator = - new HasNextIterator<Node>(node.cases.iterator); - while (caseIterator.hasNext) { - SwitchCase switchCase = caseIterator.next(); - List<Constant> caseConstants = <Constant>[]; - HBasicBlock block = graph.addNewBlock(); - for (Node labelOrCase in switchCase.labelsAndCases) { - if (labelOrCase is CaseMatch) { - Constant constant = constants[labelOrCase]; - caseConstants.add(constant); - HConstant hConstant = graph.addConstant(constant); - switchInstruction.inputs.add(hConstant); - hConstant.usedBy.add(switchInstruction); - expressionBlock.addSuccessor(block); - } - } - matchExpressions.add(caseConstants); - - if (switchCase.isDefaultCase) { - // An HSwitch has n inputs and n+1 successors, the last being the - // default case. - expressionBlock.addSuccessor(block); - hasDefault = true; - } - open(block); - localsHandler = new LocalsHandler.from(savedLocals); - visit(switchCase.statements); - if (!isAborted() && caseIterator.hasNext) { - pushInvokeHelper0(getFallThroughErrorElement, HType.UNKNOWN); - HInstruction error = pop(); - close(new HThrow(error)); - } - statements.add( - new HSubGraphBlockInformation(new SubGraph(block, lastOpenedBlock))); - } - - // Add a join-block if necessary. - // We create [joinBlock] early, and then go through the cases that might - // want to jump to it. In each case, if we add [joinBlock] as a successor - // of another block, we also add an element to [caseLocals] that is used - // to create the phis in [joinBlock]. - // If we never jump to the join block, [caseLocals] will stay empty, and - // the join block is never added to the graph. - HBasicBlock joinBlock = new HBasicBlock(); - List<LocalsHandler> caseLocals = <LocalsHandler>[]; - jumpHandler.forEachBreak((HBreak instruction, LocalsHandler locals) { - instruction.block.addSuccessor(joinBlock); - caseLocals.add(locals); - }); - if (!isAborted()) { - current.close(new HGoto()); - lastOpenedBlock.addSuccessor(joinBlock); - caseLocals.add(localsHandler); - } - if (!hasDefault) { - // The current flow is only aborted if the switch has a default that - // aborts (all previous cases must abort, and if there is no default, - // it's possible to miss all the cases). - expressionEnd.addSuccessor(joinBlock); - caseLocals.add(savedLocals); - } - assert(caseLocals.length == joinBlock.predecessors.length); - if (caseLocals.length != 0) { - graph.addBlock(joinBlock); - open(joinBlock); - if (caseLocals.length == 1) { - localsHandler = caseLocals[0]; - } else { - localsHandler = savedLocals.mergeMultiple(caseLocals, joinBlock); - } - } else { - // The joinblock is not used. - joinBlock = null; - } - - HSubExpressionBlockInformation expressionInfo = - new HSubExpressionBlockInformation(new SubExpression(expressionStart, - expressionEnd)); - expressionStart.setBlockFlow( - new HSwitchBlockInformation(expressionInfo, - matchExpressions, - statements, - hasDefault, - jumpHandler.target, - jumpHandler.labels()), - joinBlock); - - jumpHandler.close(); - return true; - } - - bool nonPrimitiveTypeOverridesEquals(Constant constant) { - // Function values override equals. Even static ones, since - // they inherit from [Function]. - if (constant.isFunction()) return true; - - // [Map] and [List] do not override equals. - // If constant is primitive, just return false. We know - // about the equals methods of num/String classes. - if (!constant.isConstructedObject()) return false; - - ConstructedConstant constructedConstant = constant; - DartType type = constructedConstant.type; - assert(type != null); - Element element = type.element; - // If the type is not a class, we'll just assume it overrides - // operator==. Typedefs do, since [Function] does. - if (!element.isClass()) return true; - ClassElement classElement = element; - return typeOverridesObjectEquals(classElement); - } - - bool typeOverridesObjectEquals(ClassElement classElement) { - Element operatorEq = - lookupOperator(classElement, const SourceString('==')); - if (operatorEq == null) return false; - // If the operator== declaration is in Object, it's not overridden. - return (operatorEq.getEnclosingClass() != compiler.objectClass); - } - - Element lookupOperator(ClassElement classElement, SourceString operatorName) { - SourceString dartMethodName = - Elements.constructOperatorName(operatorName, false); - return classElement.lookupMember(dartMethodName); - } - - - // Recursively build an if/else structure to match the cases. - void buildSwitchCases(Link<Node> cases, HInstruction expression, - [int encounteredCaseTypes = 0]) { - final int NO_TYPE = 0; - final int INT_TYPE = 1; - final int STRING_TYPE = 2; - final int CONFLICT_TYPE = 3; - int combine(int type1, int type2) => type1 | type2; - - SwitchCase node = cases.head; - // Called for the statements on all but the last case block. - // Ensures that a user expecting a fallthrough gets an error. - void visitStatementsAndAbort() { - visit(node.statements); - if (!isAborted()) { - compiler.reportWarning(node, 'Missing break at end of switch case'); - Element element = - compiler.findHelper(const SourceString("getFallThroughError")); - pushInvokeHelper0(element, HType.UNKNOWN); - HInstruction error = pop(); - close(new HThrow(error)); - } - } - - Link<Node> skipLabels(Link<Node> labelsAndCases) { - while (!labelsAndCases.isEmpty && labelsAndCases.head is Label) { - labelsAndCases = labelsAndCases.tail; - } - return labelsAndCases; - } - - Link<Node> labelsAndCases = skipLabels(node.labelsAndCases.nodes); - if (labelsAndCases.isEmpty) { - // Default case with no expressions. - if (!node.isDefaultCase) { - compiler.internalError("Case with no expression and not default", - node: node); - } - visit(node.statements); - // This must be the final case (otherwise "default" would be invalid), - // so we don't need to check for fallthrough. - return; - } - - // Recursively build the test conditions. Leaves the result on the - // expression stack. - void buildTests(Link<Node> remainingCases) { - // Build comparison for one case expression. - void left() { - CaseMatch match = remainingCases.head; - // TODO(lrn): Move the constant resolution to the resolver, so - // we can report an error before reaching the backend. - Constant constant = - compiler.constantHandler.tryCompileNodeWithDefinitions( - match.expression, elements); - if (constant != null) { - stack.add(graph.addConstant(constant)); - } else { - visit(match.expression); - } - push(new HIdentity(pop(), expression)); - } - - // If this is the last expression, just return it. - Link<Node> tail = skipLabels(remainingCases.tail); - if (tail.isEmpty) { - left(); - return; - } - - void right() { - buildTests(tail); - } - SsaBranchBuilder branchBuilder = - new SsaBranchBuilder(this, remainingCases.head); - branchBuilder.handleLogicalAndOr(left, right, isAnd: false); - } - - if (node.isDefaultCase) { - // Default case must be last. - assert(cases.tail.isEmpty); - // Perform the tests until one of them match, but then always execute the - // statements. - // TODO(lrn): Stop performing tests when all expressions are compile-time - // constant strings or integers. - handleIf(node, () { buildTests(labelsAndCases); }, (){}, null); - visit(node.statements); - } else { - if (cases.tail.isEmpty) { - handleIf(node, - () { buildTests(labelsAndCases); }, - () { visit(node.statements); }, - null); - } else { - handleIf(node, - () { buildTests(labelsAndCases); }, - () { visitStatementsAndAbort(); }, - () { buildSwitchCases(cases.tail, expression, - encounteredCaseTypes); }); - } - } - } - - visitSwitchCase(SwitchCase node) { - compiler.internalError('SsaBuilder.visitSwitchCase'); - } - - visitCaseMatch(CaseMatch node) { - compiler.internalError('SsaBuilder.visitCaseMatch'); - } - - visitTryStatement(TryStatement node) { - work.allowSpeculativeOptimization = false; - // Save the current locals. The catch block and the finally block - // must not reuse the existing locals handler. None of the variables - // that have been defined in the body-block will be used, but for - // loops we will add (unnecessary) phis that will reference the body - // variables. This makes it look as if the variables were used - // in a non-dominated block. - LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); - HBasicBlock enterBlock = openNewBlock(); - HTry tryInstruction = new HTry(); - close(tryInstruction); - bool oldInTryStatement = inTryStatement; - inTryStatement = true; - - HBasicBlock startTryBlock; - HBasicBlock endTryBlock; - HBasicBlock startCatchBlock; - HBasicBlock endCatchBlock; - HBasicBlock startFinallyBlock; - HBasicBlock endFinallyBlock; - - startTryBlock = graph.addNewBlock(); - open(startTryBlock); - visit(node.tryBlock); - if (!isAborted()) endTryBlock = close(new HGoto()); - SubGraph bodyGraph = new SubGraph(startTryBlock, lastOpenedBlock); - SubGraph catchGraph = null; - HLocalValue exception = null; - - if (!node.catchBlocks.isEmpty) { - localsHandler = new LocalsHandler.from(savedLocals); - startCatchBlock = graph.addNewBlock(); - open(startCatchBlock); - // TODO(kasperl): Bad smell. We shouldn't be constructing elements here. - // Note that the name of this element is irrelevant. - Element element = new ElementX(const SourceString('exception'), - ElementKind.PARAMETER, - currentElement); - exception = new HLocalValue(element); - add(exception); - HInstruction oldRethrowableException = rethrowableException; - rethrowableException = exception; - - pushInvokeHelper1( - backend.getExceptionUnwrapper(), exception, HType.UNKNOWN); - HInvokeStatic unwrappedException = pop(); - tryInstruction.exception = exception; - Link<Node> link = node.catchBlocks.nodes; - - void pushCondition(CatchBlock catchBlock) { - if (catchBlock.onKeyword != null) { - DartType type = elements.getType(catchBlock.type); - if (type == null) { - compiler.cancel('On with unresolved type', - node: catchBlock.type); - } - HInstruction condition = - new HIs(type, <HInstruction>[unwrappedException]); - push(condition); - } - else { - VariableDefinitions declaration = catchBlock.formals.nodes.head; - HInstruction condition = null; - if (declaration.type == null) { - condition = graph.addConstantBool(true, constantSystem); - stack.add(condition); - } else { - // TODO(aprelev@gmail.com): Once old catch syntax is removed - // "if" condition above and this "else" branch should be deleted as - // type of declared variable won't matter for the catch - // condition. - DartType type = elements.getType(declaration.type); - if (type == null) { - compiler.cancel('Catch with unresolved type', node: catchBlock); - } - condition = - new HIs(type, <HInstruction>[unwrappedException], nullOk: true); - push(condition); - } - } - } - - void visitThen() { - CatchBlock catchBlock = link.head; - link = link.tail; - if (catchBlock.exception != null) { - localsHandler.updateLocal(elements[catchBlock.exception], - unwrappedException); - } - Node trace = catchBlock.trace; - if (trace != null) { - pushInvokeHelper1( - backend.getTraceFromException(), exception, HType.UNKNOWN); - HInstruction traceInstruction = pop(); - localsHandler.updateLocal(elements[trace], traceInstruction); - } - visit(catchBlock); - } - - void visitElse() { - if (link.isEmpty) { - close(new HThrow(exception, isRethrow: true)); - } else { - CatchBlock newBlock = link.head; - handleIf(node, - () { pushCondition(newBlock); }, - visitThen, visitElse); - } - } - - CatchBlock firstBlock = link.head; - handleIf(node, () { pushCondition(firstBlock); }, visitThen, visitElse); - if (!isAborted()) endCatchBlock = close(new HGoto()); - - rethrowableException = oldRethrowableException; - tryInstruction.catchBlock = startCatchBlock; - catchGraph = new SubGraph(startCatchBlock, lastOpenedBlock); - } - - SubGraph finallyGraph = null; - if (node.finallyBlock != null) { - localsHandler = new LocalsHandler.from(savedLocals); - startFinallyBlock = graph.addNewBlock(); - open(startFinallyBlock); - visit(node.finallyBlock); - if (!isAborted()) endFinallyBlock = close(new HGoto()); - tryInstruction.finallyBlock = startFinallyBlock; - finallyGraph = new SubGraph(startFinallyBlock, lastOpenedBlock); - } - - HBasicBlock exitBlock = graph.addNewBlock(); - - addOptionalSuccessor(b1, b2) { if (b2 != null) b1.addSuccessor(b2); } - addExitTrySuccessor(successor) { - if (successor == null) return; - // Iterate over all blocks created inside this try/catch, and - // attach successor information to blocks that end with - // [HExitTry]. - for (int i = startTryBlock.id; i < successor.id; i++) { - HBasicBlock block = graph.blocks[i]; - var last = block.last; - if (last is HExitTry) { - block.addSuccessor(successor); - } else if (last is HTry) { - // Skip all blocks inside this nested try/catch. - i = last.joinBlock.id; - } - } - } - - // Setup all successors. The entry block that contains the [HTry] - // has 1) the body, 2) the catch, 3) the finally, and 4) the exit - // blocks as successors. - enterBlock.addSuccessor(startTryBlock); - addOptionalSuccessor(enterBlock, startCatchBlock); - addOptionalSuccessor(enterBlock, startFinallyBlock); - enterBlock.addSuccessor(exitBlock); - - // The body has either the catch or the finally block as successor. - if (endTryBlock != null) { - assert(startCatchBlock != null || startFinallyBlock != null); - endTryBlock.addSuccessor( - startCatchBlock != null ? startCatchBlock : startFinallyBlock); - } - - // The catch block has either the finally or the exit block as - // successor. - if (endCatchBlock != null) { - endCatchBlock.addSuccessor( - startFinallyBlock != null ? startFinallyBlock : exitBlock); - } - - // The finally block has the exit block as successor. - if (endFinallyBlock != null) { - endFinallyBlock.addSuccessor(exitBlock); - } - - // If a block inside try/catch aborts (eg with a return statement), - // we explicitely mark this block a predecessor of the catch - // block and the finally block. - addExitTrySuccessor(startCatchBlock); - addExitTrySuccessor(startFinallyBlock); - - // Use the locals handler not altered by the catch and finally - // blocks. - localsHandler = savedLocals; - open(exitBlock); - enterBlock.setBlockFlow( - new HTryBlockInformation( - wrapStatementGraph(bodyGraph), - exception, - wrapStatementGraph(catchGraph), - wrapStatementGraph(finallyGraph)), - exitBlock); - inTryStatement = oldInTryStatement; - } - - visitScriptTag(ScriptTag node) { - compiler.unimplemented('SsaBuilder.visitScriptTag', node: node); - } - - visitCatchBlock(CatchBlock node) { - visit(node.block); - } - - visitTypedef(Typedef node) { - compiler.unimplemented('SsaBuilder.visitTypedef', node: node); - } - - visitTypeVariable(TypeVariable node) { - compiler.internalError('SsaBuilder.visitTypeVariable'); - } - - HType mapBaseType(BaseType baseType) { - if (!baseType.isClass()) return HType.UNKNOWN; - ClassBaseType classBaseType = baseType; - return new HType.fromBoundedType( - classBaseType.element.computeType(compiler), compiler, false); - } - - HType mapInferredType(ConcreteType concreteType) { - if (concreteType == null) return HType.UNKNOWN; - HType ssaType = HType.CONFLICTING; - for (BaseType baseType in concreteType.baseTypes) { - ssaType = ssaType.union(mapBaseType(baseType), compiler); - } - assert(!ssaType.isConflicting()); - return ssaType; - } - - HType mapNativeType(type) { - if (type == native.SpecialType.JsObject) { - return new HBoundedType.exact( - compiler.objectClass.computeType(compiler)); - } else if (type == native.SpecialType.JsArray) { - return HType.READABLE_ARRAY; - } else { - return new HType.fromBoundedType(type, compiler, false); - } - } - - HType mapNativeBehaviorType(native.NativeBehavior nativeBehavior) { - if (nativeBehavior.typesInstantiated.isEmpty) return HType.UNKNOWN; - - HType ssaType = HType.CONFLICTING; - for (final type in nativeBehavior.typesInstantiated) { - ssaType = ssaType.union(mapNativeType(type), compiler); - } - assert(!ssaType.isConflicting()); - return ssaType; - } -} - -/** - * Visitor that handles generation of string literals (LiteralString, - * StringInterpolation), and otherwise delegates to the given visitor for - * non-literal subexpressions. - * TODO(lrn): Consider whether to handle compile time constant int/boolean - * expressions as well. - */ -class StringBuilderVisitor extends Visitor { - final SsaBuilder builder; - final Node diagnosticNode; - - /** - * The string value generated so far. - */ - HInstruction result = null; - - StringBuilderVisitor(this.builder, this.diagnosticNode); - - void visit(Node node) { - node.accept(this); - } - - visitNode(Node node) { - builder.compiler.internalError('unexpected node', node: node); - } - - void visitExpression(Node node) { - node.accept(builder); - HInstruction expression = builder.pop(); - result = (result == null) ? expression : concat(result, expression); - } - - void visitStringInterpolation(StringInterpolation node) { - node.visitChildren(this); - } - - void visitStringInterpolationPart(StringInterpolationPart node) { - visit(node.expression); - visit(node.string); - } - - void visitStringJuxtaposition(StringJuxtaposition node) { - node.visitChildren(this); - } - - void visitNodeList(NodeList node) { - node.visitChildren(this); - } - - HInstruction concat(HInstruction left, HInstruction right) { - HInstruction instruction = new HStringConcat(left, right, diagnosticNode); - builder.add(instruction); - return instruction; - } -} - -/** - * This class visits the method that is a candidate for inlining and - * finds whether it is too difficult to inline. - */ -class InlineWeeder extends Visitor { - final TreeElements elements; - bool seenReturn = false; - bool tooDifficult = false; - - InlineWeeder(this.elements); - - static bool canBeInlined(FunctionExpression functionExpression, - TreeElements elements) { - InlineWeeder weeder = new InlineWeeder(elements); - weeder.visit(functionExpression.body); - if (weeder.tooDifficult) return false; - return true; - } - - void visit(Node node) { - node.accept(this); - } - - void visitNode(Node node) { - if (seenReturn) { - tooDifficult = true; - } else { - node.visitChildren(this); - } - } - - void visitFunctionExpression(Node node) { - tooDifficult = true; - } - - void visitFunctionDeclaration(Node node) { - tooDifficult = true; - } - - void visitSend(Send node) { - if (node.isParameterCheck) { - tooDifficult = true; - return; - } - node.visitChildren(this); - } - - visitLoop(Node node) { - node.visitChildren(this); - if (seenReturn) tooDifficult = true; - } - - void visitReturn(Return node) { - if (seenReturn - || identical(node.getBeginToken().stringValue, 'native') - || node.isRedirectingFactoryBody) { - tooDifficult = true; - return; - } - node.visitChildren(this); - seenReturn = true; - } - - void visitTryStatement(Node node) { - tooDifficult = true; - } - - void visitThrow(Node node) { - tooDifficult = true; - } -} - -class InliningState { - /** - * Documentation wanted -- johnniwinther - * - * Invariant: [function] must be an implementation element. - */ - final PartialFunctionElement function; - final Element oldReturnElement; - final DartType oldReturnType; - final TreeElements oldElements; - final List<HInstruction> oldStack; - - InliningState(this.function, - this.oldReturnElement, - this.oldReturnType, - this.oldElements, - this.oldStack) { - assert(function.isImplementation); - } -} - -class SsaBranch { - final SsaBranchBuilder branchBuilder; - final HBasicBlock block; - LocalsHandler startLocals; - LocalsHandler exitLocals; - SubGraph graph; - - SsaBranch(this.branchBuilder) : block = new HBasicBlock(); -} - -class SsaBranchBuilder { - final SsaBuilder builder; - final Node diagnosticNode; - - SsaBranchBuilder(this.builder, [this.diagnosticNode]); - - Compiler get compiler => builder.compiler; - - void checkNotAborted() { - if (builder.isAborted()) { - compiler.unimplemented("aborted control flow", node: diagnosticNode); - } - } - - void buildCondition(void visitCondition(), - SsaBranch conditionBranch, - SsaBranch thenBranch, - SsaBranch elseBranch) { - startBranch(conditionBranch); - visitCondition(); - checkNotAborted(); - assert(identical(builder.current, builder.lastOpenedBlock)); - HInstruction conditionValue = builder.popBoolified(); - HIf branch = new HIf(conditionValue); - HBasicBlock conditionExitBlock = builder.current; - builder.close(branch); - conditionBranch.exitLocals = builder.localsHandler; - conditionExitBlock.addSuccessor(thenBranch.block); - conditionExitBlock.addSuccessor(elseBranch.block); - bool conditionBranchLocalsCanBeReused = - mergeLocals(conditionBranch, thenBranch, mayReuseFromLocals: true); - mergeLocals(conditionBranch, elseBranch, - mayReuseFromLocals: conditionBranchLocalsCanBeReused); - - conditionBranch.graph = - new SubExpression(conditionBranch.block, conditionExitBlock); - } - - /** - * Returns true if the locals of the [fromBranch] may be reused. A [:true:] - * return value implies that [mayReuseFromLocals] was set to [:true:]. - */ - bool mergeLocals(SsaBranch fromBranch, SsaBranch toBranch, - {bool mayReuseFromLocals}) { - LocalsHandler fromLocals = fromBranch.exitLocals; - if (toBranch.startLocals == null) { - if (mayReuseFromLocals) { - toBranch.startLocals = fromLocals; - return false; - } else { - toBranch.startLocals = new LocalsHandler.from(fromLocals); - return true; - } - } else { - toBranch.startLocals.mergeWith(fromLocals, toBranch.block); - return true; - } - } - - void startBranch(SsaBranch branch) { - builder.graph.addBlock(branch.block); - builder.localsHandler = branch.startLocals; - builder.open(branch.block); - } - - HInstruction buildBranch(SsaBranch branch, - void visitBranch(), - SsaBranch joinBranch, - bool isExpression) { - startBranch(branch); - visitBranch(); - branch.graph = new SubGraph(branch.block, builder.lastOpenedBlock); - branch.exitLocals = builder.localsHandler; - if (!builder.isAborted()) { - builder.goto(builder.current, joinBranch.block); - mergeLocals(branch, joinBranch, mayReuseFromLocals: true); - } - if (isExpression) { - checkNotAborted(); - return builder.pop(); - } - return null; - } - - handleIf(void visitCondition(), void visitThen(), void visitElse()) { - if (visitElse == null) { - // Make sure to have an else part to avoid a critical edge. A - // critical edge is an edge that connects a block with multiple - // successors to a block with multiple predecessors. We avoid - // such edges because they prevent inserting copies during code - // generation of phi instructions. - visitElse = () {}; - } - - _handleDiamondBranch(visitCondition, visitThen, visitElse, false); - } - - handleConditional(void visitCondition(), void visitThen(), void visitElse()) { - assert(visitElse != null); - _handleDiamondBranch(visitCondition, visitThen, visitElse, true); - } - - void handleLogicalAndOr(void left(), void right(), {bool isAnd}) { - // x && y is transformed into: - // t0 = boolify(x); - // if (t0) { - // t1 = boolify(y); - // } - // result = phi(t1, false); - // - // x || y is transformed into: - // t0 = boolify(x); - // if (not(t0)) { - // t1 = boolify(y); - // } - // result = phi(t1, true); - HInstruction boolifiedLeft; - HInstruction boolifiedRight; - - void visitCondition() { - left(); - boolifiedLeft = builder.popBoolified(); - builder.stack.add(boolifiedLeft); - if (!isAnd) { - builder.push(new HNot(builder.pop())); - } - } - - void visitThen() { - right(); - boolifiedRight = builder.popBoolified(); - } - - handleIf(visitCondition, visitThen, null); - HConstant notIsAnd = - builder.graph.addConstantBool(!isAnd, builder.constantSystem); - HPhi result = new HPhi.manyInputs(null, - <HInstruction>[boolifiedRight, notIsAnd]); - builder.current.addPhi(result); - builder.stack.add(result); - } - - void handleLogicalAndOrWithLeftNode(Node left, - void visitRight(), - {bool isAnd}) { - // This method is similar to [handleLogicalAndOr] but optimizes the case - // where left is a logical "and" or logical "or". - // - // For example (x && y) && z is transformed into x && (y && z): - // t0 = boolify(x); - // if (t0) { - // t1 = boolify(y); - // if (t1) { - // t2 = boolify(z); - // } - // t3 = phi(t2, false); - // } - // result = phi(t3, false); - - Send send = left.asSend(); - if (send != null && - (isAnd ? send.isLogicalAnd : send.isLogicalOr)) { - Node newLeft = send.receiver; - Link<Node> link = send.argumentsNode.nodes; - assert(link.tail.isEmpty); - Node middle = link.head; - handleLogicalAndOrWithLeftNode( - newLeft, - () => handleLogicalAndOrWithLeftNode(middle, visitRight, - isAnd: isAnd), - isAnd: isAnd); - } else { - handleLogicalAndOr(() => builder.visit(left), visitRight, isAnd: isAnd); - } - } - - void _handleDiamondBranch(void visitCondition(), - void visitThen(), - void visitElse(), - bool isExpression) { - SsaBranch conditionBranch = new SsaBranch(this); - SsaBranch thenBranch = new SsaBranch(this); - SsaBranch elseBranch = new SsaBranch(this); - SsaBranch joinBranch = new SsaBranch(this); - - conditionBranch.startLocals = builder.localsHandler; - builder.goto(builder.current, conditionBranch.block); - - buildCondition(visitCondition, conditionBranch, thenBranch, elseBranch); - HInstruction thenValue = - buildBranch(thenBranch, visitThen, joinBranch, isExpression); - HInstruction elseValue = - buildBranch(elseBranch, visitElse, joinBranch, isExpression); - - if (isExpression) { - assert(thenValue != null && elseValue != null); - HPhi phi = - new HPhi.manyInputs(null, <HInstruction>[thenValue, elseValue]); - joinBranch.block.addPhi(phi); - builder.stack.add(phi); - } - - HBasicBlock thenBlock = thenBranch.block; - HBasicBlock elseBlock = elseBranch.block; - HBasicBlock joinBlock; - // If at least one branch did not abort, open the joinBranch. - if (!joinBranch.block.predecessors.isEmpty) { - startBranch(joinBranch); - joinBlock = joinBranch.block; - } - - HIfBlockInformation info = - new HIfBlockInformation( - new HSubExpressionBlockInformation(conditionBranch.graph), - new HSubGraphBlockInformation(thenBranch.graph), - new HSubGraphBlockInformation(elseBranch.graph)); - - HBasicBlock conditionStartBlock = conditionBranch.block; - conditionStartBlock.setBlockFlow(info, joinBlock); - SubGraph conditionGraph = conditionBranch.graph; - HIf branch = conditionGraph.end.last; - assert(branch is HIf); - branch.blockInformation = conditionStartBlock.blockFlow; - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/codegen.dart b/pkgs/markdown/test/lib/src/compiler/implementation/ssa/codegen.dart deleted file mode 100644 index e5caac1..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/codegen.dart +++ /dev/null
@@ -1,3006 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of ssa; - -class SsaCodeGeneratorTask extends CompilerTask { - - final JavaScriptBackend backend; - - SsaCodeGeneratorTask(JavaScriptBackend backend) - : this.backend = backend, - super(backend.compiler); - String get name => 'SSA code generator'; - NativeEmitter get nativeEmitter => backend.emitter.nativeEmitter; - - - js.Fun buildJavaScriptFunction(FunctionElement element, - List<js.Parameter> parameters, - js.Block body) { - FunctionExpression expression = - element.implementation.parseNode(backend.compiler); - js.Fun result = new js.Fun(parameters, body); - // TODO(johnniwinther): remove the 'element.patch' hack. - Element sourceElement = element.patch == null ? element : element.patch; - SourceFile sourceFile = sourceElement.getCompilationUnit().script.file; - // TODO(podivilov): find the right sourceFile here and remove offset checks - // below. - if (expression.getBeginToken().charOffset < sourceFile.text.length) { - result.sourcePosition = new SourceFileLocation( - sourceFile, expression.getBeginToken()); - } - if (expression.getEndToken().charOffset < sourceFile.text.length) { - result.endSourcePosition = new SourceFileLocation( - sourceFile, expression.getEndToken()); - } - return result; - } - - CodeBuffer prettyPrint(js.Node node) { - var code = js.prettyPrint(node, compiler, allowVariableMinification: true); - return code; - } - - js.Expression generateCode(CodegenWorkItem work, HGraph graph) { - if (work.element.isField()) { - return generateLazyInitializer(work, graph); - } else { - return generateMethod(work, graph); - } - } - - js.Expression generateLazyInitializer(work, graph) { - return measure(() { - compiler.tracer.traceGraph("codegen", graph); - SsaOptimizedCodeGenerator codegen = - new SsaOptimizedCodeGenerator(backend, work); - codegen.visitGraph(graph); - return new js.Fun(codegen.parameters, codegen.body); - }); - } - - js.Expression generateMethod(CodegenWorkItem work, HGraph graph) { - return measure(() { - compiler.tracer.traceGraph("codegen", graph); - SsaOptimizedCodeGenerator codegen = - new SsaOptimizedCodeGenerator(backend, work); - codegen.visitGraph(graph); - - FunctionElement element = work.element; - js.Block body; - ClassElement enclosingClass = element.getEnclosingClass(); - - if (element.isInstanceMember() - && enclosingClass.isNative() - && native.isOverriddenMethod( - element, enclosingClass, nativeEmitter)) { - // Record that this method is overridden. In case of optional - // arguments, the emitter will generate stubs to handle them, - // and needs to know if the method is overridden. - nativeEmitter.overriddenMethods.add(element); - StringBuffer buffer = new StringBuffer(); - body = - nativeEmitter.generateMethodBodyWithPrototypeCheckForElement( - element, codegen.body, codegen.parameters); - } else { - body = codegen.body; - } - - return buildJavaScriptFunction(element, codegen.parameters, body); - }); - } - - js.Expression generateBailoutMethod(CodegenWorkItem work, HGraph graph) { - return measure(() { - compiler.tracer.traceGraph("codegen-bailout", graph); - - SsaUnoptimizedCodeGenerator codegen = - new SsaUnoptimizedCodeGenerator(backend, work); - codegen.visitGraph(graph); - - js.Block body = new js.Block(<js.Statement>[]); - body.statements.add(codegen.body); - js.Fun fun = - buildJavaScriptFunction(work.element, codegen.newParameters, body); - return fun; - }); - } -} - -// Stop-gap until the core classes have such a class. -class OrderedSet<T> { - final LinkedHashMap<T, bool> map = new LinkedHashMap<T, bool>(); - - void add(T x) { - if (!map.containsKey(x)) { - map[x] = true; - } - } - - bool contains(T x) => map.containsKey(x); - - bool remove(T x) => map.remove(x) != null; - - bool get isEmpty => map.isEmpty; - - void forEach(f) => map.keys.forEach(f); - - T get first { - var iterator = map.keys.iterator; - if (!iterator.moveNext()) throw new StateError("No elements"); - return iterator.current; - } - - get length => map.length; -} - -typedef void ElementAction(Element element); - -abstract class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { - /** - * Returned by [expressionType] to tell how code can be generated for - * a subgraph. - * - [TYPE_STATEMENT] means that the graph must be generated as a statement, - * which is always possible. - * - [TYPE_EXPRESSION] means that the graph can be generated as an expression, - * or possibly several comma-separated expressions. - * - [TYPE_DECLARATION] means that the graph can be generated as an - * expression, and that it only generates expressions of the form - * variable = expression - * which are also valid as parts of a "var" declaration. - */ - static const int TYPE_STATEMENT = 0; - static const int TYPE_EXPRESSION = 1; - static const int TYPE_DECLARATION = 2; - - /** - * Whether we are currently generating expressions instead of statements. - * This includes declarations, which are generated as expressions. - */ - bool isGeneratingExpression = false; - - final JavaScriptBackend backend; - final CodegenWorkItem work; - final HTypeMap types; - - final Set<HInstruction> generateAtUseSite; - final Set<HInstruction> controlFlowOperators; - final Map<Element, ElementAction> breakAction; - final Map<Element, ElementAction> continueAction; - final List<js.Parameter> parameters; - - js.Block currentContainer; - js.Block get body => currentContainer; - List<js.Expression> expressionStack; - List<js.Block> oldContainerStack; - - /** - * Contains the names of the instructions, as well as the parallel - * copies to perform on block transitioning. - */ - VariableNames variableNames; - bool shouldGroupVarDeclarations = false; - - /** - * While generating expressions, we can't insert variable declarations. - * Instead we declare them at the start of the function. When minifying - * we do this most of the time, because it reduces the size unless there - * is only one variable. - */ - final OrderedSet<String> collectedVariableDeclarations; - - /** - * Set of variables and parameters that have already been declared. - */ - final Set<String> declaredLocals; - - int indent = 0; - HGraph currentGraph; - - // Records a block-information that is being handled specially. - // Used to break bad recursion. - HBlockInformation currentBlockInformation; - // The subgraph is used to delimit traversal for some constructions, e.g., - // if branches. - SubGraph subGraph; - - SsaCodeGenerator(this.backend, CodegenWorkItem work) - : this.work = work, - this.types = - (work.compilationContext as JavaScriptItemCompilationContext).types, - declaredLocals = new Set<String>(), - collectedVariableDeclarations = new OrderedSet<String>(), - currentContainer = new js.Block.empty(), - parameters = <js.Parameter>[], - expressionStack = <js.Expression>[], - oldContainerStack = <js.Block>[], - generateAtUseSite = new Set<HInstruction>(), - controlFlowOperators = new Set<HInstruction>(), - breakAction = new Map<Element, ElementAction>(), - continueAction = new Map<Element, ElementAction>(); - - Compiler get compiler => backend.compiler; - NativeEmitter get nativeEmitter => backend.emitter.nativeEmitter; - CodegenEnqueuer get world => backend.compiler.enqueuer.codegen; - - bool isGenerateAtUseSite(HInstruction instruction) { - return generateAtUseSite.contains(instruction); - } - - bool isNonNegativeInt32Constant(HInstruction instruction) { - if (instruction.isConstantInteger()) { - HConstant constantInstruction = instruction; - PrimitiveConstant primitiveConstant = constantInstruction.constant; - int value = primitiveConstant.value; - if (value >= 0 && value < (1 << 31)) { - return true; - } - } - return false; - } - - bool hasNonBitOpUser(HInstruction instruction, Set<HPhi> phiSet) { - for (HInstruction user in instruction.usedBy) { - if (user is HPhi) { - if (!phiSet.contains(user)) { - phiSet.add(user); - if (hasNonBitOpUser(user, phiSet)) return true; - } - } else if (user is! HBitNot && user is! HBinaryBitOp) { - return true; - } - } - return false; - } - - // We want the outcome of bit-operations to be positive. However, if - // the result of a bit-operation is only used by other bit - // operations we do not have to convert to an unsigned - // integer. Also, if we are using & with a positive constant we know - // that the result is positive already and need no conversion. - bool requiresUintConversion(HInstruction instruction) { - if (instruction is HBitAnd) { - HBitAnd bitAnd = instruction; - if (isNonNegativeInt32Constant(bitAnd.left) || - isNonNegativeInt32Constant(bitAnd.right)) { - return false; - } - } - return hasNonBitOpUser(instruction, new Set<HPhi>()); - } - - /** - * If the [instruction] is not `null` it will be used to attach the position - * to the [statement]. - */ - void pushStatement(js.Statement statement, [HInstruction instruction]) { - assert(expressionStack.isEmpty); - if (instruction != null) { - attachLocation(statement, instruction); - } - currentContainer.statements.add(statement); - } - - void insertStatementAtStart(js.Statement statement) { - currentContainer.statements.insertRange(0, 1, statement); - } - - /** - * If the [instruction] is not `null` it will be used to attach the position - * to the [expression]. - */ - pushExpressionAsStatement(js.Expression expression, - [HInstruction instruction]) { - pushStatement(new js.ExpressionStatement(expression), instruction); - } - - /** - * If the [instruction] is not `null` it will be used to attach the position - * to the [expression]. - */ - push(js.Expression expression, [HInstruction instruction]) { - if (instruction != null) { - attachLocation(expression, instruction); - } - expressionStack.add(expression); - } - - js.Expression pop() { - return expressionStack.removeLast(); - } - - attachLocationToLast(HInstruction instruction) { - attachLocation(expressionStack.last, instruction); - } - - js.Node attachLocation(js.Node jsNode, HInstruction instruction) { - jsNode.sourcePosition = instruction.sourcePosition; - return jsNode; - } - - js.Node attachLocationRange(js.Node jsNode, - SourceFileLocation sourcePosition, - SourceFileLocation endSourcePosition) { - jsNode.sourcePosition = sourcePosition; - jsNode.endSourcePosition = endSourcePosition; - return jsNode; - } - - visitTypeGuard(HTypeGuard node); - visitBailoutTarget(HBailoutTarget node); - - beginGraph(HGraph graph); - endGraph(HGraph graph); - - preLabeledBlock(HLabeledBlockInformation labeledBlockInfo); - startLabeledBlock(HLabeledBlockInformation labeledBlockInfo); - endLabeledBlock(HLabeledBlockInformation labeledBlockInfo); - - void preGenerateMethod(HGraph graph) { - new SsaInstructionMerger(types, generateAtUseSite).visitGraph(graph); - new SsaConditionMerger( - types, generateAtUseSite, controlFlowOperators).visitGraph(graph); - SsaLiveIntervalBuilder intervalBuilder = - new SsaLiveIntervalBuilder(compiler, generateAtUseSite); - intervalBuilder.visitGraph(graph); - SsaVariableAllocator allocator = new SsaVariableAllocator( - compiler, - intervalBuilder.liveInstructions, - intervalBuilder.liveIntervals, - generateAtUseSite); - allocator.visitGraph(graph); - variableNames = allocator.names; - shouldGroupVarDeclarations = allocator.names.numberOfVariables > 1; - - // Don't register a return type for lazily initialized variables. - if (work.element is! FunctionElement) return; - - // Register return types to the backend. - graph.exit.predecessors.forEach((HBasicBlock block) { - HInstruction last = block.last; - assert(last is HGoto || last is HReturn); - if (last is HReturn) { - backend.registerReturnType(work.element, types[last.inputs[0]]); - } else { - backend.registerReturnType(work.element, HType.NULL); - } - }); - } - - void handleDelayedVariableDeclarations() { - // If we have only one variable declaration and the first statement is an - // assignment to that variable then we can merge the two. We count the - // number of variables in the variable allocator to try to avoid this issue, - // but it sometimes happens that the variable allocator introduces a - // temporary variable that it later eliminates. - if (!collectedVariableDeclarations.isEmpty) { - if (collectedVariableDeclarations.length == 1 && - currentContainer.statements.length >= 1 && - currentContainer.statements[0] is js.ExpressionStatement) { - String name = collectedVariableDeclarations.first; - js.ExpressionStatement statement = currentContainer.statements[0]; - if (statement.expression is js.Assignment) { - js.Assignment assignment = statement.expression; - if (!assignment.isCompound && - assignment.leftHandSide is js.VariableReference) { - js.VariableReference variableReference = assignment.leftHandSide; - if (variableReference.name == name) { - js.VariableDeclaration decl = new js.VariableDeclaration(name); - js.VariableInitialization initialization = - new js.VariableInitialization(decl, assignment.value); - currentContainer.statements[0] = new js.ExpressionStatement( - new js.VariableDeclarationList([initialization])); - return; - } - } - } - } - // If we can't merge the declaration with the first assignment then we - // just do it with a new var z,y,x; statement. - List<js.VariableInitialization> declarations = - <js.VariableInitialization>[]; - collectedVariableDeclarations.forEach((String name) { - declarations.add(new js.VariableInitialization( - new js.VariableDeclaration(name), null)); - }); - var declarationList = new js.VariableDeclarationList(declarations); - insertStatementAtStart(new js.ExpressionStatement(declarationList)); - } - } - - visitGraph(HGraph graph) { - preGenerateMethod(graph); - currentGraph = graph; - indent++; // We are already inside a function. - subGraph = new SubGraph(graph.entry, graph.exit); - HBasicBlock start = beginGraph(graph); - visitBasicBlock(start); - handleDelayedVariableDeclarations(); - endGraph(graph); - } - - void visitSubGraph(SubGraph newSubGraph) { - SubGraph oldSubGraph = subGraph; - subGraph = newSubGraph; - visitBasicBlock(subGraph.start); - subGraph = oldSubGraph; - } - - /** - * Check whether a sub-graph can be generated as an expression, or even - * as a declaration, or if it has to fall back to being generated as - * a statement. - * Expressions are anything that doesn't generate control flow constructs. - * Declarations must only generate assignments on the form "id = expression", - * and not, e.g., expressions where the value isn't assigned, or where it's - * assigned to something that's not a simple variable. - */ - int expressionType(HExpressionInformation info) { - // The only HExpressionInformation used as part of a HBlockInformation is - // current HSubExpressionBlockInformation, so it's the only one reaching - // here. If we start using the other HExpressionInformation types too, - // this code should be generalized. - assert(info is HSubExpressionBlockInformation); - HSubExpressionBlockInformation expressionInfo = info; - SubGraph limits = expressionInfo.subExpression; - - // Start assuming that we can generate declarations. If we find a - // counter-example, we degrade our assumption to either expression or - // statement, and in the latter case, we can return immediately since - // it can't get any worse. E.g., a function call where the return value - // isn't used can't be in a declaration. A bailout can't be in an - // expression. - int result = TYPE_DECLARATION; - HBasicBlock basicBlock = limits.start; - do { - HInstruction current = basicBlock.first; - while (current != basicBlock.last) { - // E.g, type guards. - if (current.isControlFlow()) { - return TYPE_STATEMENT; - } - // HFieldSet generates code on the form x.y = ..., which isn't - // valid in a declaration, but it also always have no uses, so - // it's caught by that test too. - assert(current is! HFieldSet || current.usedBy.isEmpty); - if (current.usedBy.isEmpty) { - result = TYPE_EXPRESSION; - } - current = current.next; - } - if (current is HGoto) { - basicBlock = basicBlock.successors[0]; - } else if (current is HConditionalBranch) { - if (generateAtUseSite.contains(current)) { - // Short-circuit control flow operator trickery. - // Check the second half, which will continue into the join. - // (The first half is [inputs[0]], the second half is [successors[0]], - // and [successors[1]] is the join-block). - basicBlock = basicBlock.successors[0]; - } else { - // We allow an expression to end on an HIf (a condition expression). - return identical(basicBlock, limits.end) ? result : TYPE_STATEMENT; - } - } else { - // Expression-incompatible control flow. - return TYPE_STATEMENT; - } - } while (limits.contains(basicBlock)); - return result; - } - - bool isJSExpression(HExpressionInformation info) { - return !identical(expressionType(info), TYPE_STATEMENT); - } - - bool isJSDeclaration(HExpressionInformation info) { - return identical(expressionType(info), TYPE_DECLARATION); - } - - bool isJSCondition(HExpressionInformation info) { - HSubExpressionBlockInformation graph = info; - SubExpression limits = graph.subExpression; - return !identical(expressionType(info), TYPE_STATEMENT) && - (limits.end.last is HConditionalBranch); - } - - /** - * Generate statements from block information. - * If the block information contains expressions, generate only - * assignments, and if it ends in a conditional branch, don't generate - * the condition. - */ - void generateStatements(HBlockInformation block) { - if (block is HStatementInformation) { - block.accept(this); - } else { - HSubExpressionBlockInformation expression = block; - visitSubGraph(expression.subExpression); - } - } - - js.Block generateStatementsInNewBlock(HBlockInformation block) { - js.Block result = new js.Block.empty(); - js.Block oldContainer = currentContainer; - currentContainer = result; - generateStatements(block); - currentContainer = oldContainer; - return result; - } - - /** - * If the [block] only contains one statement returns that statement. If the - * that statement itself is a block, recursively calls this method. - * - * If the block is empty, returns a new instance of [js.NOP]. - */ - js.Statement unwrapStatement(js.Block block) { - int len = block.statements.length; - if (len == 0) return new js.EmptyStatement(); - if (len == 1) { - js.Statement result = block.statements[0]; - if (result is Block) return unwrapStatement(result); - return result; - } - return block; - } - - /** - * Generate expressions from block information. - */ - js.Expression generateExpression(HExpressionInformation expression) { - // Currently we only handle sub-expression graphs. - assert(expression is HSubExpressionBlockInformation); - - bool oldIsGeneratingExpression = isGeneratingExpression; - isGeneratingExpression = true; - List<js.Expression> oldExpressionStack = expressionStack; - List<js.Expression> sequenceElements = <js.Expression>[]; - expressionStack = sequenceElements; - HSubExpressionBlockInformation expressionSubGraph = expression; - visitSubGraph(expressionSubGraph.subExpression); - expressionStack = oldExpressionStack; - isGeneratingExpression = oldIsGeneratingExpression; - if (sequenceElements.isEmpty) { - // Happens when the initializer, condition or update of a loop is empty. - return null; - } else if (sequenceElements.length == 1) { - return sequenceElements[0]; - } else { - return new js.Sequence(sequenceElements); - } - } - - /** - * Only visits the arguments starting at inputs[HInvoke.ARGUMENTS_OFFSET]. - */ - List<js.Expression> visitArguments(List<HInstruction> inputs) { - assert(inputs.length >= HInvoke.ARGUMENTS_OFFSET); - List<js.Expression> result = <js.Expression>[]; - for (int i = HInvoke.ARGUMENTS_OFFSET; i < inputs.length; i++) { - use(inputs[i]); - result.add(pop()); - } - return result; - } - - bool isVariableDeclared(String variableName) { - return declaredLocals.contains(variableName) || - collectedVariableDeclarations.contains(variableName); - } - - js.Expression generateExpressionAssignment(String variableName, - js.Expression value) { - if (value is js.Binary) { - js.Binary binary = value; - String op = binary.op; - if (op == '+' || op == '-' || op == '/' || op == '*' || op == '%' || - op == '^' || op == '&' || op == '|') { - if (binary.left is js.VariableUse && - (binary.left as js.VariableUse).name == variableName) { - // We know now, that we can shorten x = x + y into x += y. - // Also check for the shortcut where y equals 1: x++ and x--. - if ((op == '+' || op == '-') && - binary.right is js.LiteralNumber && - (binary.right as js.LiteralNumber).value == "1") { - return new js.Prefix(op == '+' ? '++' : '--', binary.left); - } - return new js.Assignment.compound(binary.left, op, binary.right); - } - } - } - return new js.Assignment(new js.VariableUse(variableName), value); - } - - void assignVariable(String variableName, js.Expression value) { - if (isGeneratingExpression) { - // If we are in an expression then we can't declare the variable here. - // We have no choice, but to use it and then declare it separately. - if (!isVariableDeclared(variableName)) { - collectedVariableDeclarations.add(variableName); - } - push(generateExpressionAssignment(variableName, value)); - // Otherwise if we are trying to declare inline and we are in a statement - // then we declare (unless it was already declared). - } else if (!shouldGroupVarDeclarations && - !declaredLocals.contains(variableName)) { - // It may be necessary to remove it from the ones to be declared later. - collectedVariableDeclarations.remove(variableName); - declaredLocals.add(variableName); - js.VariableDeclaration decl = new js.VariableDeclaration(variableName); - js.VariableInitialization initialization = - new js.VariableInitialization(decl, value); - - pushExpressionAsStatement(new js.VariableDeclarationList( - <js.VariableInitialization>[initialization])); - } else { - // Otherwise we are just going to use it. If we have not already declared - // it then we make sure we will declare it later. - if (!declaredLocals.contains(variableName)) { - collectedVariableDeclarations.add(variableName); - } - pushExpressionAsStatement( - generateExpressionAssignment(variableName, value)); - } - } - - void define(HInstruction instruction) { - // For simple type checks like i = intTypeCheck(i), we don't have to - // emit an assignment, because the intTypeCheck just returns its - // argument. - bool needsAssignment = true; - if (instruction is HTypeConversion) { - String inputName = variableNames.getName(instruction.checkedInput); - if (variableNames.getName(instruction) == inputName) { - needsAssignment = false; - } - } - if (instruction is HLocalValue) { - needsAssignment = false; - } - - if (needsAssignment && - !instruction.isControlFlow() && variableNames.hasName(instruction)) { - visitExpression(instruction); - assignVariable(variableNames.getName(instruction), pop()); - return; - } - - if (isGeneratingExpression) { - visitExpression(instruction); - } else { - visitStatement(instruction); - } - } - - void use(HInstruction argument) { - if (isGenerateAtUseSite(argument)) { - visitExpression(argument); - } else if (argument is HCheck && argument.isControlFlow()) { - // A [HCheck] that has control flow can never be used as an - // expression and may not have a name. Therefore we just use the - // checked instruction. - HCheck check = argument; - use(check.checkedInput); - } else { - push(new js.VariableUse(variableNames.getName(argument))); - } - } - - visit(HInstruction node) { - node.accept(this); - } - - visitExpression(HInstruction node) { - bool oldIsGeneratingExpression = isGeneratingExpression; - isGeneratingExpression = true; - visit(node); - isGeneratingExpression = oldIsGeneratingExpression; - } - - visitStatement(HInstruction node) { - assert(!isGeneratingExpression); - visit(node); - if (!expressionStack.isEmpty) { - assert(expressionStack.length == 1); - pushExpressionAsStatement(pop()); - } - } - - void continueAsBreak(LabelElement target) { - pushStatement(new js.Break(backend.namer.continueLabelName(target))); - } - - void implicitContinueAsBreak(TargetElement target) { - pushStatement(new js.Break( - backend.namer.implicitContinueLabelName(target))); - } - - void implicitBreakWithLabel(TargetElement target) { - pushStatement(new js.Break(backend.namer.implicitBreakLabelName(target))); - } - - js.Statement wrapIntoLabels(js.Statement result, List<LabelElement> labels) { - for (LabelElement label in labels) { - if (label.isTarget) { - String breakLabelString = backend.namer.breakLabelName(label); - result = new js.LabeledStatement(breakLabelString, result); - } - } - return result; - } - - - // The regular [visitIf] method implements the needed logic. - bool visitIfInfo(HIfBlockInformation info) => false; - - bool visitSwitchInfo(HSwitchBlockInformation info) { - bool isExpression = isJSExpression(info.expression); - if (!isExpression) { - generateStatements(info.expression); - } - - if (isExpression) { - push(generateExpression(info.expression)); - } else { - use(info.expression.conditionExpression); - } - js.Expression key = pop(); - List<js.SwitchClause> cases = <js.SwitchClause>[]; - - js.Block oldContainer = currentContainer; - for (int i = 0; i < info.matchExpressions.length; i++) { - for (Constant constant in info.matchExpressions[i]) { - generateConstant(constant); - currentContainer = new js.Block.empty(); - cases.add(new js.Case(pop(), currentContainer)); - } - if (i == info.matchExpressions.length - 1 && info.hasDefault) { - currentContainer = new js.Block.empty(); - cases.add(new js.Default(currentContainer)); - } - generateStatements(info.statements[i]); - } - currentContainer = oldContainer; - - js.Statement result = new js.Switch(key, cases); - pushStatement(wrapIntoLabels(result, info.labels)); - return true; - } - - bool visitSequenceInfo(HStatementSequenceInformation info) { - return false; - } - - bool visitSubGraphInfo(HSubGraphBlockInformation info) { - visitSubGraph(info.subGraph); - return true; - } - - bool visitSubExpressionInfo(HSubExpressionBlockInformation info) { - return false; - } - - bool visitAndOrInfo(HAndOrBlockInformation info) { - return false; - } - - bool visitTryInfo(HTryBlockInformation info) { - js.Block body = generateStatementsInNewBlock(info.body); - js.Catch catchPart = null; - js.Block finallyPart = null; - if (info.catchBlock != null) { - HLocalValue exception = info.catchVariable; - String name = variableNames.getName(exception); - js.VariableDeclaration decl = new js.VariableDeclaration(name); - js.Block catchBlock = generateStatementsInNewBlock(info.catchBlock); - catchPart = new js.Catch(decl, catchBlock); - } - if (info.finallyBlock != null) { - finallyPart = generateStatementsInNewBlock(info.finallyBlock); - } - pushStatement(new js.Try(body, catchPart, finallyPart)); - return true; - } - - void visitBodyIgnoreLabels(HLoopBlockInformation info) { - if (info.body.start.isLabeledBlock()) { - HBlockInformation oldInfo = currentBlockInformation; - currentBlockInformation = info.body.start.blockFlow.body; - generateStatements(info.body); - currentBlockInformation = oldInfo; - } else { - generateStatements(info.body); - } - } - - bool visitLoopInfo(HLoopBlockInformation info) { - HExpressionInformation condition = info.condition; - bool isConditionExpression = isJSCondition(condition); - - js.Loop loop; - - switch (info.kind) { - // Treate all three "test-first" loops the same way. - case HLoopBlockInformation.FOR_LOOP: - case HLoopBlockInformation.WHILE_LOOP: - case HLoopBlockInformation.FOR_IN_LOOP: - HBlockInformation initialization = info.initializer; - int initializationType = TYPE_STATEMENT; - if (initialization != null) { - initializationType = expressionType(initialization); - if (initializationType == TYPE_STATEMENT) { - generateStatements(initialization); - initialization = null; - } - } - if (isConditionExpression && - info.updates != null && isJSExpression(info.updates)) { - // If we have an updates graph, and it's expressible as an - // expression, generate a for-loop. - js.Expression jsInitialization = null; - if (initialization != null) { - int delayedVariablesCount = collectedVariableDeclarations.length; - jsInitialization = generateExpression(initialization); - if (!shouldGroupVarDeclarations && - delayedVariablesCount < collectedVariableDeclarations.length) { - // We just added a new delayed variable-declaration. See if we - // can put in a 'var' in front of the initialization to make it - // go away. - List<js.Expression> expressions; - if (jsInitialization is js.Sequence) { - expressions = jsInitialization.expressions; - } else { - expressions = <js.Expression>[jsInitialization]; - } - bool canTransformToVariableDeclaration = true; - for (js.Expression expression in expressions) { - bool expressionIsVariableAssignment = false; - if (expression is js.Assignment) { - js.Assignment assignment = expression; - if (assignment.leftHandSide is js.VariableUse && - assignment.compoundTarget == null) { - expressionIsVariableAssignment = true; - } - } - if (!expressionIsVariableAssignment) { - canTransformToVariableDeclaration = false; - break; - } - } - if (canTransformToVariableDeclaration) { - List<js.VariableInitialization> inits = - <js.VariableInitialization>[]; - for (js.Assignment assignment in expressions) { - String id = (assignment.leftHandSide as js.VariableUse).name; - js.Node declaration = new js.VariableDeclaration(id); - inits.add(new js.VariableInitialization(declaration, - assignment.value)); - collectedVariableDeclarations.remove(id); - } - jsInitialization = new js.VariableDeclarationList(inits); - } - } - } - js.Expression jsCondition = generateExpression(condition); - js.Expression jsUpdates = generateExpression(info.updates); - // The body might be labeled. Ignore this when recursing on the - // subgraph. - // TODO(lrn): Remove this extra labeling when handling all loops - // using subgraphs. - js.Block oldContainer = currentContainer; - js.Statement body = new js.Block.empty(); - currentContainer = body; - visitBodyIgnoreLabels(info); - currentContainer = oldContainer; - body = unwrapStatement(body); - loop = new js.For(jsInitialization, jsCondition, jsUpdates, body); - } else { - // We have either no update graph, or it's too complex to - // put in an expression. - if (initialization != null) { - generateStatements(initialization); - } - js.Expression jsCondition; - js.Block oldContainer = currentContainer; - js.Statement body = new js.Block.empty(); - if (isConditionExpression) { - jsCondition = generateExpression(condition); - currentContainer = body; - } else { - jsCondition = newLiteralBool(true); - currentContainer = body; - generateStatements(condition); - use(condition.conditionExpression); - js.Expression ifTest = new js.Prefix("!", pop()); - js.Break jsBreak = new js.Break(null); - pushStatement(new js.If.noElse(ifTest, jsBreak)); - } - if (info.updates != null) { - wrapLoopBodyForContinue(info); - generateStatements(info.updates); - } else { - visitBodyIgnoreLabels(info); - } - currentContainer = oldContainer; - body = unwrapStatement(body); - loop = new js.While(jsCondition, body); - } - break; - case HLoopBlockInformation.DO_WHILE_LOOP: - if (info.initializer != null) { - generateStatements(info.initializer); - } - js.Block oldContainer = currentContainer; - js.Block body = new js.Block.empty(); - // If there are phi copies in the block that jumps to the - // loop entry, we must emit the condition like this: - // do { - // body; - // if (condition) { - // phi updates; - // continue; - // } else { - // break; - // } - // } while (true); - HBasicBlock avoidEdge = info.end.successors[0]; - js.Block updateBody = new js.Block.empty(); - currentContainer = updateBody; - assignPhisOfSuccessors(avoidEdge); - bool hasPhiUpdates = !updateBody.statements.isEmpty; - currentContainer = body; - visitBodyIgnoreLabels(info); - if (info.updates != null) { - generateStatements(info.updates); - } - if (isConditionExpression) { - push(generateExpression(condition)); - } else { - generateStatements(condition); - use(condition.conditionExpression); - } - js.Expression jsCondition = pop(); - if (hasPhiUpdates) { - updateBody.statements.add(new js.Continue(null)); - body.statements.add( - new js.If(jsCondition, updateBody, new js.Break(null))); - jsCondition = newLiteralBool(true); - } - loop = new js.Do(unwrapStatement(body), jsCondition); - currentContainer = oldContainer; - break; - default: - compiler.internalError( - 'Unexpected loop kind: ${info.kind}', - instruction: condition.conditionExpression); - } - attachLocationRange(loop, info.sourcePosition, info.endSourcePosition); - pushStatement(wrapIntoLabels(loop, info.labels)); - return true; - } - - bool visitLabeledBlockInfo(HLabeledBlockInformation labeledBlockInfo) { - preLabeledBlock(labeledBlockInfo); - Link<Element> continueOverrides = const Link<Element>(); - - js.Block oldContainer = currentContainer; - js.Block body = new js.Block.empty(); - js.Statement result = body; - - currentContainer = body; - - // If [labeledBlockInfo.isContinue], the block is an artificial - // block around the body of a loop with an update block, so that - // continues of the loop can be written as breaks of the body - // block. - if (labeledBlockInfo.isContinue) { - for (LabelElement label in labeledBlockInfo.labels) { - if (label.isContinueTarget) { - String labelName = backend.namer.continueLabelName(label); - result = new js.LabeledStatement(labelName, result); - continueAction[label] = continueAsBreak; - continueOverrides = continueOverrides.prepend(label); - } - } - // For handling unlabeled continues from the body of a loop. - // TODO(lrn): Consider recording whether the target is in fact - // a target of an unlabeled continue, and not generate this if it isn't. - TargetElement target = labeledBlockInfo.target; - String labelName = backend.namer.implicitContinueLabelName(target); - result = new js.LabeledStatement(labelName, result); - continueAction[target] = implicitContinueAsBreak; - continueOverrides = continueOverrides.prepend(target); - } else { - for (LabelElement label in labeledBlockInfo.labels) { - if (label.isBreakTarget) { - String labelName = backend.namer.breakLabelName(label); - result = new js.LabeledStatement(labelName, result); - } - } - TargetElement target = labeledBlockInfo.target; - if (target.isSwitch) { - // This is an extra block around a switch that is generated - // as a nested if/else chain. We add an extra break target - // so that case code can break. - String labelName = backend.namer.implicitBreakLabelName(target); - result = new js.LabeledStatement(labelName, result); - breakAction[target] = implicitBreakWithLabel; - } - } - - currentContainer = body; - startLabeledBlock(labeledBlockInfo); - generateStatements(labeledBlockInfo.body); - endLabeledBlock(labeledBlockInfo); - - if (labeledBlockInfo.isContinue) { - while (!continueOverrides.isEmpty) { - continueAction.remove(continueOverrides.head); - continueOverrides = continueOverrides.tail; - } - } else { - breakAction.remove(labeledBlockInfo.target); - } - - currentContainer = oldContainer; - pushStatement(result); - return true; - } - - // Wraps a loop body in a block to make continues have a target to break - // to (if necessary). - void wrapLoopBodyForContinue(HLoopBlockInformation info) { - TargetElement target = info.target; - if (target != null && target.isContinueTarget) { - js.Block oldContainer = currentContainer; - js.Block body = new js.Block.empty(); - currentContainer = body; - js.Statement result = body; - for (LabelElement label in info.labels) { - if (label.isContinueTarget) { - String labelName = backend.namer.continueLabelName(label); - result = new js.LabeledStatement(labelName, result); - continueAction[label] = continueAsBreak; - } - } - String labelName = backend.namer.implicitContinueLabelName(target); - result = new js.LabeledStatement(labelName, result); - continueAction[info.target] = implicitContinueAsBreak; - visitBodyIgnoreLabels(info); - continueAction.remove(info.target); - for (LabelElement label in info.labels) { - if (label.isContinueTarget) { - continueAction.remove(label); - } - } - currentContainer = oldContainer; - pushStatement(result); - } else { - // Loop body contains no continues, so we don't need a break target. - generateStatements(info.body); - } - } - - bool handleBlockFlow(HBlockFlow block) { - HBlockInformation info = block.body; - // If we reach here again while handling the attached information, - // e.g., because we call visitSubGraph on a subgraph starting on - // the same block, don't handle it again. - // When the structure graph is complete, we will be able to have - // different structures starting on the same basic block (e.g., an - // "if" and its condition). - if (identical(info, currentBlockInformation)) return false; - - HBlockInformation oldBlockInformation = currentBlockInformation; - currentBlockInformation = info; - bool success = info.accept(this); - currentBlockInformation = oldBlockInformation; - if (success) { - HBasicBlock continuation = block.continuation; - if (continuation != null) { - visitBasicBlock(continuation); - } - } - return success; - } - - void visitBasicBlock(HBasicBlock node) { - // Abort traversal if we are leaving the currently active sub-graph. - if (!subGraph.contains(node)) return; - - // If this node has block-structure based information attached, - // try using that to traverse from here. - if (node.blockFlow != null && handleBlockFlow(node.blockFlow)) { - return; - } - iterateBasicBlock(node); - } - - void emitAssignment(String destination, String source) { - assignVariable(destination, new js.VariableUse(source)); - } - - /** - * Sequentialize a list of conceptually parallel copies. Parallel - * copies may contain cycles, that this method breaks. - */ - void sequentializeCopies(Iterable<Copy> copies, - String tempName, - void doAssignment(String target, String source)) { - // Map to keep track of the current location (ie the variable that - // holds the initial value) of a variable. - Map<String, String> currentLocation = new Map<String, String>(); - - // Map to keep track of the initial value of a variable. - Map<String, String> initialValue = new Map<String, String>(); - - // List of variables to assign a value. - List<String> worklist = <String>[]; - - // List of variables that we can assign a value to (ie are not - // being used anymore). - List<String> ready = <String>[]; - - // Prune [copies] by removing self-copies. - List<Copy> prunedCopies = <Copy>[]; - for (Copy copy in copies) { - if (copy.source != copy.destination) { - prunedCopies.add(copy); - } - } - copies = prunedCopies; - - - // For each copy, set the current location of the source to - // itself, and the initial value of the destination to the source. - // Add the destination to the list of copies to make. - for (Copy copy in copies) { - currentLocation[copy.source] = copy.source; - initialValue[copy.destination] = copy.source; - worklist.add(copy.destination); - } - - // For each copy, if the destination does not have a current - // location, then we can safely assign to it. - for (Copy copy in copies) { - if (currentLocation[copy.destination] == null) { - ready.add(copy.destination); - } - } - - while (!worklist.isEmpty) { - while (!ready.isEmpty) { - String destination = ready.removeLast(); - String source = initialValue[destination]; - // Since [source] might have been updated, use the current - // location of [source] - String copy = currentLocation[source]; - doAssignment(destination, copy); - // Now [destination] is the current location of [source]. - currentLocation[source] = destination; - // If [source] hasn't been updated and needs to have a value, - // add it to the list of variables that can be updated. Copies - // of [source] will now use [destination]. - if (source == copy && initialValue[source] != null) { - ready.add(source); - } - } - - // Check if we have a cycle. - String current = worklist.removeLast(); - // If [current] is used as a source, and the assignment has been - // done, we are done with this variable. Otherwise there is a - // cycle that we break by using a temporary name. - if (currentLocation[current] != null - && current != currentLocation[initialValue[current]]) { - doAssignment(tempName, current); - currentLocation[current] = tempName; - // [current] can now be safely updated. Copies of [current] - // will now use [tempName]. - ready.add(current); - } - } - } - - void assignPhisOfSuccessors(HBasicBlock node) { - CopyHandler handler = variableNames.getCopyHandler(node); - if (handler == null) return; - - // Map the instructions to strings. - Iterable<Copy> copies = handler.copies.map((Copy copy) { - return new Copy(variableNames.getName(copy.source), - variableNames.getName(copy.destination)); - }); - - sequentializeCopies(copies, variableNames.getSwapTemp(), emitAssignment); - - for (Copy copy in handler.assignments) { - String name = variableNames.getName(copy.destination); - use(copy.source); - assignVariable(name, pop()); - } - } - - void iterateBasicBlock(HBasicBlock node) { - HInstruction instruction = node.first; - while (!identical(instruction, node.last)) { - if (instruction is HTypeGuard || instruction is HBailoutTarget) { - visit(instruction); - } else if (!isGenerateAtUseSite(instruction)) { - define(instruction); - } - instruction = instruction.next; - } - assignPhisOfSuccessors(node); - visit(instruction); - } - - visitInvokeBinary(HInvokeBinary node, String op) { - use(node.left); - js.Expression jsLeft = pop(); - use(node.right); - push(new js.Binary(op, jsLeft, pop()), node); - } - - visitRelational(HRelational node, String op) => visitInvokeBinary(node, op); - - // We want the outcome of bit-operations to be positive. We use the unsigned - // shift operator to achieve this. - visitBitInvokeBinary(HBinaryBitOp node, String op) { - visitInvokeBinary(node, op); - if (requiresUintConversion(node)) { - push(new js.Binary(">>>", pop(), new js.LiteralNumber("0")), node); - } - } - - visitInvokeUnary(HInvokeUnary node, String op) { - use(node.operand); - push(new js.Prefix(op, pop()), node); - } - - // We want the outcome of bit-operations to be positive. We use the unsigned - // shift operator to achieve this. - visitBitInvokeUnary(HInvokeUnary node, String op) { - visitInvokeUnary(node, op); - if (requiresUintConversion(node)) { - push(new js.Binary(">>>", pop(), new js.LiteralNumber("0")), node); - } - } - - void emitIdentityComparison(HInstruction left, HInstruction right) { - String op = singleIdentityComparison(left, right, types); - if (op != null) { - use(left); - js.Expression jsLeft = pop(); - use(right); - push(new js.Binary(op, jsLeft, pop())); - } else { - assert(NullConstant.JsNull == 'null'); - use(left); - js.Binary leftEqualsNull = - new js.Binary("==", pop(), new js.LiteralNull()); - use(right); - js.Binary rightEqualsNull = - new js.Binary("==", pop(), new js.LiteralNull()); - use(right); - use(left); - js.Binary tripleEq = new js.Binary("===", pop(), pop()); - - push(new js.Conditional(leftEqualsNull, rightEqualsNull, tripleEq)); - } - } - - visitIdentity(HIdentity node) { - emitIdentityComparison(node.left, node.right); - } - - visitAdd(HAdd node) => visitInvokeBinary(node, '+'); - visitDivide(HDivide node) => visitInvokeBinary(node, '/'); - visitMultiply(HMultiply node) => visitInvokeBinary(node, '*'); - visitSubtract(HSubtract node) => visitInvokeBinary(node, '-'); - visitBitAnd(HBitAnd node) => visitBitInvokeBinary(node, '&'); - visitBitNot(HBitNot node) => visitBitInvokeUnary(node, '~'); - visitBitOr(HBitOr node) => visitBitInvokeBinary(node, '|'); - visitBitXor(HBitXor node) => visitBitInvokeBinary(node, '^'); - visitShiftLeft(HShiftLeft node) => visitBitInvokeBinary(node, '<<'); - - visitNegate(HNegate node) => visitInvokeUnary(node, '-'); - - visitLess(HLess node) => visitRelational(node, '<'); - visitLessEqual(HLessEqual node) => visitRelational(node, '<='); - visitGreater(HGreater node) => visitRelational(node, '>'); - visitGreaterEqual(HGreaterEqual node) => visitRelational(node, '>='); - - visitBoolify(HBoolify node) { - assert(node.inputs.length == 1); - use(node.inputs[0]); - push(new js.Binary('===', pop(), newLiteralBool(true)), node); - } - - visitExit(HExit node) { - // Don't do anything. - } - - visitGoto(HGoto node) { - HBasicBlock block = node.block; - assert(block.successors.length == 1); - List<HBasicBlock> dominated = block.dominatedBlocks; - // With the exception of the entry-node which dominates its successor - // and the exit node, no block finishing with a 'goto' can have more than - // one dominated block (since it has only one successor). - // If the successor is dominated by another block, then the other block - // is responsible for visiting the successor. - if (dominated.isEmpty) return; - if (dominated.length > 2) { - compiler.internalError('dominated.length = ${dominated.length}', - instruction: node); - } - if (dominated.length == 2 && block != currentGraph.entry) { - compiler.internalError('node.block != currentGraph.entry', - instruction: node); - } - assert(dominated[0] == block.successors[0]); - visitBasicBlock(dominated[0]); - } - - visitLoopBranch(HLoopBranch node) { - assert(node.block == subGraph.end); - // We are generating code for a loop condition. - // If we are generating the subgraph as an expression, the - // condition will be generated as the expression. - // Otherwise, we don't generate the expression, and leave that - // to the code that called [visitSubGraph]. - if (isGeneratingExpression) { - use(node.inputs[0]); - } - } - - /** - * Checks if [map] contains an [ElementAction] for [element], and - * if so calls that action and returns true. - * Otherwise returns false. - */ - bool tryCallAction(Map<Element, ElementAction> map, Element element) { - ElementAction action = map[element]; - if (action == null) return false; - action(element); - return true; - } - - visitBreak(HBreak node) { - assert(node.block.successors.length == 1); - if (node.label != null) { - LabelElement label = node.label; - if (!tryCallAction(breakAction, label)) { - pushStatement(new js.Break(backend.namer.breakLabelName(label)), node); - } - } else { - TargetElement target = node.target; - if (!tryCallAction(breakAction, target)) { - pushStatement(new js.Break(null), node); - } - } - } - - visitContinue(HContinue node) { - assert(node.block.successors.length == 1); - if (node.label != null) { - LabelElement label = node.label; - if (!tryCallAction(continueAction, label)) { - // TODO(floitsch): should this really be the breakLabelName? - pushStatement(new js.Continue(backend.namer.breakLabelName(label)), - node); - } - } else { - TargetElement target = node.target; - if (!tryCallAction(continueAction, target)) { - pushStatement(new js.Continue(null), node); - } - } - } - - visitExitTry(HExitTry node) { - // An [HExitTry] is used to represent the control flow graph of a - // try/catch block, ie the try body is always a predecessor - // of the catch and finally. Here, we continue visiting the try - // body by visiting the block that contains the user-level control - // flow instruction. - visitBasicBlock(node.bodyTrySuccessor); - } - - visitTry(HTry node) { - // We should never get here. Try/catch/finally is always handled using block - // information in [visitTryInfo], or not at all, in the case of the bailout - // generator. - compiler.internalError('visitTry should not be called', instruction: node); - } - - bool tryControlFlowOperation(HIf node) { - if (!controlFlowOperators.contains(node)) return false; - HPhi phi = node.joinBlock.phis.first; - bool atUseSite = isGenerateAtUseSite(phi); - // Don't generate a conditional operator in this situation: - // i = condition ? bar() : i; - // But generate this instead: - // if (condition) i = bar(); - // Usually, the variable name is longer than 'if' and it takes up - // more space to duplicate the name. - if (!atUseSite - && variableNames.getName(phi) == variableNames.getName(phi.inputs[1])) { - return false; - } - if (!atUseSite) define(phi); - visitBasicBlock(node.joinBlock); - return true; - } - - void generateIf(HIf node, HIfBlockInformation info) { - use(node.inputs[0]); - js.Expression test = pop(); - - HStatementInformation thenGraph = info.thenGraph; - HStatementInformation elseGraph = info.elseGraph; - js.Statement thenPart = - unwrapStatement(generateStatementsInNewBlock(thenGraph)); - js.Statement elsePart = - unwrapStatement(generateStatementsInNewBlock(elseGraph)); - - pushStatement(new js.If(test, thenPart, elsePart), node); - } - - visitIf(HIf node) { - if (tryControlFlowOperation(node)) return; - - HInstruction condition = node.inputs[0]; - HIfBlockInformation info = node.blockInformation.body; - - if (condition.isConstant()) { - HConstant constant = condition; - if (constant.constant.isTrue()) { - generateStatements(info.thenGraph); - } else { - generateStatements(info.elseGraph); - } - } else { - generateIf(node, info); - } - - HBasicBlock joinBlock = node.joinBlock; - if (joinBlock != null && !identical(joinBlock.dominator, node.block)) { - // The join block is dominated by a block in one of the branches. - // The subgraph traversal never reached it, so we visit it here - // instead. - visitBasicBlock(joinBlock); - } - - // Visit all the dominated blocks that are not part of the then or else - // branches, and is not the join block. - // Depending on how the then/else branches terminate - // (e.g., return/throw/break) there can be any number of these. - List<HBasicBlock> dominated = node.block.dominatedBlocks; - for (int i = 2; i < dominated.length; i++) { - visitBasicBlock(dominated[i]); - } - } - - js.Call jsPropertyCall(js.Expression receiver, - String fieldName, - List<js.Expression> arguments) { - return new js.Call(new js.PropertyAccess.field(receiver, fieldName), - arguments); - } - - void visitInterceptor(HInterceptor node) { - backend.registerSpecializedGetInterceptor(node.interceptedClasses); - String name = backend.namer.getInterceptorName( - backend.getInterceptorMethod, node.interceptedClasses); - var isolate = new js.VariableUse(backend.namer.CURRENT_ISOLATE); - use(node.receiver); - List<js.Expression> arguments = <js.Expression>[pop()]; - push(jsPropertyCall(isolate, name, arguments), node); - } - - visitInvokeDynamicMethod(HInvokeDynamicMethod node) { - use(node.receiver); - js.Expression object = pop(); - SourceString name = node.selector.name; - String methodName; - List<js.Expression> arguments = visitArguments(node.inputs); - Element target = node.element; - - if (target != null) { - // Avoid adding the generative constructor name to the list of - // seen selectors. - if (target.isGenerativeConstructorBody()) { - methodName = name.slowToString(); - } else if (!node.isInterceptorCall) { - if (target == backend.jsArrayAdd) { - methodName = 'push'; - } else if (target == backend.jsArrayRemoveLast) { - methodName = 'pop'; - } else if (target == backend.jsStringSplit) { - methodName = 'split'; - // Split returns a List, so we make sure the backend knows the - // list class is instantiated. - world.registerInstantiatedClass(compiler.listClass); - } else if (target == backend.jsStringConcat) { - push(new js.Binary('+', object, arguments[0]), node); - return; - } - } - } - - if (methodName == null) { - methodName = backend.namer.invocationName(node.selector); - registerMethodInvoke(node); - } - push(jsPropertyCall(object, methodName, arguments), node); - } - - void visitOneShotInterceptor(HOneShotInterceptor node) { - List<js.Expression> arguments = visitArguments(node.inputs); - var isolate = new js.VariableUse(backend.namer.CURRENT_ISOLATE); - Selector selector = node.selector; - String methodName = backend.namer.oneShotInterceptorName(selector); - push(jsPropertyCall(isolate, methodName, arguments), node); - backend.registerSpecializedGetInterceptor(node.interceptedClasses); - backend.addOneShotInterceptor(selector); - if (selector.isGetter()) { - registerGetter(node); - } else if (selector.isSetter()) { - registerSetter(node); - } else { - registerMethodInvoke(node); - } - } - - Selector getOptimizedSelectorFor(HInvokeDynamic node, - Selector defaultSelector) { - // If [JSInvocationMirror.invokeOn] has been called, we must not create a - // typed selector based on the receiver type. - if (node.element == null && // Invocation is not exact. - backend.compiler.enabledInvokeOn) { - return defaultSelector; - } - int receiverIndex = node.isInterceptorCall ? 1 : 0; - HType receiverHType = types[node.inputs[receiverIndex]]; - DartType receiverType = receiverHType.computeType(compiler); - if (receiverType != null && - !identical(receiverType.kind, TypeKind.MALFORMED_TYPE)) { - return new TypedSelector(receiverType, defaultSelector); - } else { - return defaultSelector; - } - } - - void registerInvoke(HInvokeDynamic node) { - bool inLoop = node.block.enclosingLoopHeader != null; - SourceString name = node.selector.name; - if (inLoop) { - Element target = node.element; - if (target != null) { - backend.builder.functionsCalledInLoop.add(target); - } else { - backend.builder.selectorsCalledInLoop[name] = node.selector; - } - } - - if (node.isInterceptorCall) { - backend.addInterceptedSelector(node.selector); - } - } - - void registerMethodInvoke(HInvokeDynamic node) { - Selector selector = getOptimizedSelectorFor(node, node.selector); - // Register this invocation to collect the types used at all call sites. - backend.registerDynamicInvocation(node, selector, types); - - // If we don't know what we're calling or if we are calling a getter, - // we need to register that fact that we may be calling a closure - // with the same arguments. - Element target = node.element; - if (target == null || target.isGetter()) { - // TODO(kasperl): If we have a typed selector for the call, we - // may know something about the types of closures that need - // the specific closure call method. - Selector call = new Selector.callClosureFrom(selector); - world.registerDynamicInvocation(call.name, call); - } - - if (target != null) { - // If we know we're calling a specific method, register that - // method only. - world.registerDynamicInvocationOf(target, selector); - } else { - SourceString name = node.selector.name; - world.registerDynamicInvocation(name, selector); - } - registerInvoke(node); - } - - void registerSetter(HInvokeDynamic node) { - Selector selector = getOptimizedSelectorFor(node, node.selector); - world.registerDynamicSetter(selector.name, selector); - HType valueType = node.isInterceptorCall - ? types[node.inputs[2]] - : types[node.inputs[1]]; - backend.addedDynamicSetter(selector, valueType); - registerInvoke(node); - } - - void registerGetter(HInvokeDynamic node) { - Selector getter = node.selector; - world.registerDynamicGetter( - getter.name, getOptimizedSelectorFor(node, getter)); - world.registerInstantiatedClass(compiler.functionClass); - registerInvoke(node); - } - - visitInvokeDynamicSetter(HInvokeDynamicSetter node) { - use(node.receiver); - Selector setter = node.selector; - String name = backend.namer.invocationName(setter); - push(jsPropertyCall(pop(), name, visitArguments(node.inputs)), node); - registerSetter(node); - } - - visitInvokeDynamicGetter(HInvokeDynamicGetter node) { - use(node.receiver); - Selector getter = node.selector; - String name = backend.namer.invocationName(getter); - push(jsPropertyCall(pop(), name, visitArguments(node.inputs)), node); - registerGetter(node); - } - - visitInvokeClosure(HInvokeClosure node) { - Selector call = new Selector.callClosureFrom(node.selector); - use(node.receiver); - push(jsPropertyCall(pop(), - backend.namer.invocationName(call), - visitArguments(node.inputs)), - node); - world.registerDynamicInvocation(call.name, call); - } - - visitInvokeStatic(HInvokeStatic node) { - if (node.typeCode() == HInstruction.INVOKE_STATIC_TYPECODE) { - // Register this invocation to collect the types used at all call sites. - backend.registerStaticInvocation(node, types); - } - use(node.target); - push(new js.Call(pop(), visitArguments(node.inputs)), node); - } - - visitInvokeSuper(HInvokeSuper node) { - Element superMethod = node.element; - Element superClass = superMethod.getEnclosingClass(); - if (superMethod.kind == ElementKind.FIELD) { - ClassElement currentClass = work.element.getEnclosingClass(); - if (currentClass.isClosure()) { - ClosureClassElement closure = currentClass; - currentClass = closure.methodElement.getEnclosingClass(); - } - String fieldName = currentClass.isShadowedByField(superMethod) - ? backend.namer.shadowedFieldName(superMethod) - : backend.namer.instanceFieldName(superMethod); - use(node.inputs[1]); - js.PropertyAccess access = - new js.PropertyAccess.field(pop(), fieldName); - if (node.isSetter) { - use(node.value); - push(new js.Assignment(access, pop()), node); - } else { - push(access, node); - } - } else { - String methodName = backend.namer.getName(superMethod); - String className = backend.namer.isolateAccess(superClass); - js.VariableUse classReference = new js.VariableUse(className); - js.PropertyAccess prototype = - new js.PropertyAccess.field(classReference, "prototype"); - js.PropertyAccess method = - new js.PropertyAccess.field(prototype, methodName); - push(jsPropertyCall(method, "call", visitArguments(node.inputs)), node); - } - world.registerStaticUse(superMethod); - } - - visitFieldGet(HFieldGet node) { - use(node.receiver); - if (node.element == backend.jsArrayLength - || node.element == backend.jsStringLength) { - // We're accessing a native JavaScript property called 'length' - // on a JS String or a JS array. Therefore, the name of that - // property should not be mangled. - push(new js.PropertyAccess.field(pop(), 'length'), node); - } else { - String name = _fieldPropertyName(node.element); - push(new js.PropertyAccess.field(pop(), name), node); - HType receiverHType = types[node.receiver]; - DartType type = receiverHType.computeType(compiler); - if (type != null && !identical(type.kind, TypeKind.MALFORMED_TYPE)) { - world.registerFieldGetter( - node.element.name, node.element.getLibrary(), type); - } - } - } - - visitFieldSet(HFieldSet node) { - String name = _fieldPropertyName(node.element); - DartType type = types[node.receiver].computeType(compiler); - if (type != null && !identical(type.kind, TypeKind.MALFORMED_TYPE)) { - // Field setters in the generative constructor body are handled in a - // step "SsaConstructionFieldTypes" in the ssa optimizer. - if (!work.element.isGenerativeConstructorBody()) { - world.registerFieldSetter( - node.element.name, node.element.getLibrary(), type); - backend.registerFieldSetter( - work.element, node.element, types[node.value]); - } - } - use(node.receiver); - js.Expression receiver = pop(); - use(node.value); - push(new js.Assignment(new js.PropertyAccess.field(receiver, name), pop()), - node); - } - - String _fieldPropertyName(Element element) => element.hasFixedBackendName() - ? element.fixedBackendName() - : backend.namer.getName(element); - - visitLocalGet(HLocalGet node) { - use(node.receiver); - } - - visitLocalSet(HLocalSet node) { - use(node.value); - assignVariable(variableNames.getName(node.receiver), pop()); - } - - void registerForeignType(HType type) { - DartType dartType = type.computeType(compiler); - if (dartType == null) { - assert(type == HType.UNKNOWN); - return; - } - world.registerInstantiatedClass(dartType.element); - } - - visitForeign(HForeign node) { - String code = node.code.slowToString(); - List<HInstruction> inputs = node.inputs; - if (node.isJsStatement()) { - if (!inputs.isEmpty) { - compiler.internalError("foreign statement with inputs: $code", - instruction: node); - } - pushStatement(new js.LiteralStatement(code), node); - } else { - List<js.Expression> data = <js.Expression>[]; - for (int i = 0; i < inputs.length; i++) { - use(inputs[i]); - data.add(pop()); - } - push(new js.LiteralExpression.withData(code, data), node); - } - registerForeignType(types[node]); - // TODO(sra): Tell world.nativeEnqueuer about the types created here. - } - - visitForeignNew(HForeignNew node) { - String jsClassReference = backend.namer.isolateAccess(node.element); - List<HInstruction> inputs = node.inputs; - // We can't use 'visitArguments', since our arguments start at input[0]. - List<js.Expression> arguments = <js.Expression>[]; - for (int i = 0; i < inputs.length; i++) { - use(inputs[i]); - arguments.add(pop()); - } - // TODO(floitsch): jsClassReference is an Access. We shouldn't treat it - // as if it was a string. - push(new js.New(new js.VariableUse(jsClassReference), arguments), node); - registerForeignType(types[node]); - } - - js.Expression newLiteralBool(bool value) { - if (compiler.enableMinification) { - // Use !0 for true, !1 for false. - return new js.Prefix("!", new js.LiteralNumber(value ? "0" : "1")); - } else { - return new js.LiteralBool(value); - } - } - - void generateConstant(Constant constant) { - if (constant.isFunction()) { - FunctionConstant function = constant; - world.registerStaticUse(function.element); - } - push(backend.emitter.constantReference(constant)); - } - - visitConstant(HConstant node) { - assert(isGenerateAtUseSite(node)); - generateConstant(node.constant); - DartType type = node.constant.computeType(compiler); - if (node.constant is ConstructedConstant) { - ConstantHandler handler = compiler.constantHandler; - handler.registerCompileTimeConstant(node.constant); - } - world.registerInstantiatedClass(type.element); - } - - visitNot(HNot node) { - assert(node.inputs.length == 1); - generateNot(node.inputs[0]); - attachLocationToLast(node); - } - - void generateNot(HInstruction input) { - bool canGenerateOptimizedComparison(HInstruction instruction) { - if (instruction is !HRelational) return false; - HRelational relational = instruction; - HInstruction left = relational.left; - HInstruction right = relational.right; - // This optimization doesn't work for NaN, so we only do it if the - // type is known to be an integer. - return types[left].isUseful() && left.isInteger(types) - && types[right].isUseful() && right.isInteger(types); - } - - if (input is HBoolify && isGenerateAtUseSite(input)) { - use(input.inputs[0]); - push(new js.Binary("!==", pop(), newLiteralBool(true)), input); - } else if (canGenerateOptimizedComparison(input) && - isGenerateAtUseSite(input)) { - Map<String, String> inverseOperator = const <String, String>{ - "==" : "!=", - "!=" : "==", - "===": "!==", - "!==": "===", - "<" : ">=", - "<=" : ">", - ">" : "<=", - ">=" : "<" - }; - HRelational relational = input; - BinaryOperation operation = relational.operation(backend.constantSystem); - visitRelational(input, inverseOperator[operation.name.stringValue]); - } else { - use(input); - push(new js.Prefix("!", pop())); - } - } - - visitParameterValue(HParameterValue node) { - assert(!isGenerateAtUseSite(node)); - String name = variableNames.getName(node); - parameters.add(new js.Parameter(name)); - declaredLocals.add(name); - } - - visitLocalValue(HLocalValue node) { - assert(!isGenerateAtUseSite(node)); - String name = variableNames.getName(node); - collectedVariableDeclarations.add(name); - } - - visitPhi(HPhi node) { - // This method is only called for phis that are generated at use - // site. A phi can be generated at use site only if it is the - // result of a control flow operation. - HBasicBlock ifBlock = node.block.dominator; - assert(controlFlowOperators.contains(ifBlock.last)); - HInstruction input = ifBlock.last.inputs[0]; - if (input.isConstantFalse()) { - use(node.inputs[1]); - } else if (input.isConstantTrue()) { - use(node.inputs[0]); - } else if (node.inputs[1].isConstantBoolean()) { - String operation = node.inputs[1].isConstantFalse() ? '&&' : '||'; - if (operation == '||') { - if (input is HNot) { - use(input.inputs[0]); - } else { - generateNot(input); - } - } else { - use(input); - } - js.Expression left = pop(); - use(node.inputs[0]); - push(new js.Binary(operation, left, pop())); - } else { - use(input); - js.Expression test = pop(); - use(node.inputs[0]); - js.Expression then = pop(); - use(node.inputs[1]); - push(new js.Conditional(test, then, pop())); - } - } - - visitReturn(HReturn node) { - assert(node.inputs.length == 1); - HInstruction input = node.inputs[0]; - if (input.isConstantNull()) { - pushStatement(new js.Return(null), node); - } else { - use(node.inputs[0]); - pushStatement(new js.Return(pop()), node); - } - } - - visitThis(HThis node) { - push(new js.This()); - } - - visitThrow(HThrow node) { - if (node.isRethrow) { - use(node.inputs[0]); - pushStatement(new js.Throw(pop()), node); - } else { - generateThrowWithHelper(r'$throw', node.inputs[0]); - } - } - - visitRangeConversion(HRangeConversion node) { - // Range conversion instructions are removed by the value range - // analyzer. - assert(false); - } - - visitBoundsCheck(HBoundsCheck node) { - // TODO(ngeoffray): Separate the two checks of the bounds check, so, - // e.g., the zero checks can be shared if possible. - - // If the checks always succeeds, we would have removed the bounds check - // completely. - assert(node.staticChecks != HBoundsCheck.ALWAYS_TRUE); - if (node.staticChecks != HBoundsCheck.ALWAYS_FALSE) { - js.Expression under; - js.Expression over; - if (node.staticChecks != HBoundsCheck.ALWAYS_ABOVE_ZERO) { - use(node.index); - under = new js.Binary("<", pop(), new js.LiteralNumber("0")); - } - if (node.staticChecks != HBoundsCheck.ALWAYS_BELOW_LENGTH) { - var index = node.index; - use(index); - js.Expression jsIndex = pop(); - use(node.length); - over = new js.Binary(">=", jsIndex, pop()); - } - assert(over != null || under != null); - js.Expression underOver = under == null - ? over - : over == null - ? under - : new js.Binary("||", under, over); - js.Statement thenBody = new js.Block.empty(); - js.Block oldContainer = currentContainer; - currentContainer = thenBody; - generateThrowWithHelper('ioore', node.index); - currentContainer = oldContainer; - thenBody = unwrapStatement(thenBody); - pushStatement(new js.If.noElse(underOver, thenBody), node); - } else { - generateThrowWithHelper('ioore', node.index); - } - } - - visitIntegerCheck(HIntegerCheck node) { - if (!node.alwaysFalse) { - checkInt(node.value, '!=='); - js.Expression test = pop(); - js.Statement thenBody = new js.Block.empty(); - js.Block oldContainer = currentContainer; - currentContainer = thenBody; - generateThrowWithHelper('iae', node.value); - currentContainer = oldContainer; - thenBody = unwrapStatement(thenBody); - pushStatement(new js.If.noElse(test, thenBody), node); - } else { - generateThrowWithHelper('iae', node.value); - } - } - - void generateThrowWithHelper(String helperName, HInstruction argument) { - Element helper = compiler.findHelper(new SourceString(helperName)); - world.registerStaticUse(helper); - js.VariableUse jsHelper = - new js.VariableUse(backend.namer.isolateAccess(helper)); - js.Call value = new js.Call(jsHelper, visitArguments([null, argument])); - attachLocation(value, argument); - // BUG(4906): Using throw here adds to the size of the generated code - // but it has the advantage of explicitly telling the JS engine that - // this code path will terminate abruptly. Needs more work. - pushStatement(new js.Throw(value)); - } - - void visitSwitch(HSwitch node) { - // Switches are handled using [visitSwitchInfo]. - } - - void visitStatic(HStatic node) { - // Check whether this static is used for anything else than as a target in - // a static call. - node.usedBy.forEach((HInstruction instr) { - if (instr is !HInvokeStatic) { - backend.registerNonCallStaticUse(node); - if (node.element.isFunction()) { - world.registerInstantiatedClass(compiler.functionClass); - } - } else if (instr.target != node) { - backend.registerNonCallStaticUse(node); - } - }); - Element element = node.element; - world.registerStaticUse(element); - ClassElement cls = element.getEnclosingClass(); - if (element.isGenerativeConstructor() - || (element.isFactoryConstructor() && cls == compiler.listClass)) { - world.registerInstantiatedClass(cls); - } - push(new js.VariableUse(backend.namer.isolateAccess(node.element))); - } - - void visitLazyStatic(HLazyStatic node) { - Element element = node.element; - world.registerStaticUse(element); - String lazyGetter = backend.namer.isolateLazyInitializerAccess(element); - js.VariableUse target = new js.VariableUse(lazyGetter); - js.Call call = new js.Call(target, <js.Expression>[]); - push(call, node); - } - - void visitStaticStore(HStaticStore node) { - world.registerStaticUse(node.element); - js.VariableUse variableUse = - new js.VariableUse(backend.namer.isolateAccess(node.element)); - use(node.inputs[0]); - push(new js.Assignment(variableUse, pop()), node); - } - - void visitStringConcat(HStringConcat node) { - if (isEmptyString(node.left)) { - useStringified(node.right); - } else if (isEmptyString(node.right)) { - useStringified(node.left); - } else { - useStringified(node.left); - js.Expression left = pop(); - useStringified(node.right); - push(new js.Binary("+", left, pop()), node); - } - } - - bool isEmptyString(HInstruction node) { - if (!node.isConstantString()) return false; - HConstant constant = node; - StringConstant string = constant.constant; - return string.value.length == 0; - } - - void useStringified(HInstruction node) { - if (node.isString(types)) { - use(node); - } else { - Element convertToString = compiler.findHelper(const SourceString("S")); - world.registerStaticUse(convertToString); - js.VariableUse variableUse = - new js.VariableUse(backend.namer.isolateAccess(convertToString)); - use(node); - push(new js.Call(variableUse, <js.Expression>[pop()]), node); - } - } - - void visitLiteralList(HLiteralList node) { - world.registerInstantiatedClass(compiler.listClass); - generateArrayLiteral(node); - } - - void generateArrayLiteral(HLiteralList node) { - int len = node.inputs.length; - List<js.ArrayElement> elements = <js.ArrayElement>[]; - for (int i = 0; i < len; i++) { - use(node.inputs[i]); - elements.add(new js.ArrayElement(i, pop())); - } - push(new js.ArrayInitializer(len, elements), node); - } - - void visitIndex(HIndex node) { - use(node.receiver); - js.Expression receiver = pop(); - use(node.index); - push(new js.PropertyAccess(receiver, pop()), node); - } - - void visitIndexAssign(HIndexAssign node) { - use(node.receiver); - js.Expression receiver = pop(); - use(node.index); - js.Expression index = pop(); - use(node.value); - push(new js.Assignment(new js.PropertyAccess(receiver, index), pop()), - node); - } - - void checkInt(HInstruction input, String cmp) { - use(input); - js.Expression left = pop(); - use(input); - js.Expression or0 = new js.Binary("|", pop(), new js.LiteralNumber("0")); - push(new js.Binary(cmp, left, or0)); - } - - void checkBigInt(HInstruction input, String cmp) { - use(input); - js.Expression left = pop(); - use(input); - js.Expression right = pop(); - // TODO(4984): Deal with infinity and -0.0. - push(new js.LiteralExpression.withData('Math.floor(#) === #', - <js.Expression>[left, right])); - } - - void checkTypeOf(HInstruction input, String cmp, String typeName) { - use(input); - js.Expression typeOf = new js.Prefix("typeof", pop()); - push(new js.Binary(cmp, typeOf, js.string(typeName))); - } - - void checkNum(HInstruction input, String cmp) - => checkTypeOf(input, cmp, 'number'); - - void checkDouble(HInstruction input, String cmp) => checkNum(input, cmp); - - void checkString(HInstruction input, String cmp) - => checkTypeOf(input, cmp, 'string'); - - void checkBool(HInstruction input, String cmp) - => checkTypeOf(input, cmp, 'boolean'); - - void checkObject(HInstruction input, String cmp) { - assert(NullConstant.JsNull == 'null'); - if (cmp == "===") { - checkTypeOf(input, '===', 'object'); - js.Expression left = pop(); - use(input); - js.Expression notNull = new js.Binary("!==", pop(), new js.LiteralNull()); - push(new js.Binary("&&", left, notNull)); - } else { - assert(cmp == "!=="); - checkTypeOf(input, '!==', 'object'); - js.Expression left = pop(); - use(input); - js.Expression eqNull = new js.Binary("===", pop(), new js.LiteralNull()); - push(new js.Binary("||", left, eqNull)); - } - } - - void checkArray(HInstruction input, String cmp) { - use(input); - js.PropertyAccess constructor = - new js.PropertyAccess.field(pop(), 'constructor'); - push(new js.Binary(cmp, constructor, new js.VariableUse('Array'))); - } - - void checkFieldExists(HInstruction input, String fieldName) { - use(input); - js.PropertyAccess field = new js.PropertyAccess.field(pop(), fieldName); - // Double negate to boolify the result. - push(new js.Prefix('!', new js.Prefix('!', field))); - } - - void checkImmutableArray(HInstruction input) { - checkFieldExists(input, 'immutable\$list'); - } - - void checkExtendableArray(HInstruction input) { - checkFieldExists(input, 'fixed\$length'); - } - - void checkFixedArray(HInstruction input) { - checkFieldExists(input, 'fixed\$length'); - } - - void checkNull(HInstruction input) { - use(input); - push(new js.Binary('==', pop(), new js.LiteralNull())); - } - - void checkNonNull(HInstruction input) { - use(input); - push(new js.Binary('!=', pop(), new js.LiteralNull())); - } - - void checkFunction(HInstruction input, DartType type) { - checkTypeOf(input, '===', 'function'); - js.Expression functionTest = pop(); - checkObject(input, '==='); - js.Expression objectTest = pop(); - checkType(input, type); - push(new js.Binary('||', - functionTest, - new js.Binary('&&', objectTest, pop()))); - } - - void checkType(HInstruction input, DartType type, {bool negative: false}) { - assert(invariant(input, !type.isMalformed, - message: 'Attempt to check malformed type $type')); - world.registerIsCheck(type); - Element element = type.element; - use(input); - js.PropertyAccess field = - new js.PropertyAccess.field(pop(), backend.namer.operatorIs(element)); - if (backend.emitter.nativeEmitter.requiresNativeIsCheck(element)) { - push(new js.Call(field, <js.Expression>[])); - if (negative) push(new js.Prefix('!', pop())); - } else { - // We always negate at least once so that the result is boolified. - push(new js.Prefix('!', field)); - // If the result is not negated, put another '!' in front. - if (!negative) push(new js.Prefix('!', pop())); - } - } - - void handleNumberOrStringSupertypeCheck(HInstruction input, DartType type) { - assert(!identical(type.element, compiler.listClass) - && !Elements.isListSupertype(type.element, compiler) - && !Elements.isStringOnlySupertype(type.element, compiler)); - checkNum(input, '==='); - js.Expression numberTest = pop(); - checkString(input, '==='); - js.Expression stringTest = pop(); - checkObject(input, '==='); - js.Expression objectTest = pop(); - checkType(input, type); - push(new js.Binary('||', - new js.Binary('||', numberTest, stringTest), - new js.Binary('&&', objectTest, pop()))); - } - - void handleStringSupertypeCheck(HInstruction input, DartType type) { - assert(!identical(type.element, compiler.listClass) - && !Elements.isListSupertype(type.element, compiler) - && !Elements.isNumberOrStringSupertype(type.element, compiler)); - checkString(input, '==='); - js.Expression stringTest = pop(); - checkObject(input, '==='); - js.Expression objectTest = pop(); - checkType(input, type); - push(new js.Binary('||', - stringTest, - new js.Binary('&&', objectTest, pop()))); - } - - void handleListOrSupertypeCheck(HInstruction input, DartType type) { - assert(!identical(type.element, compiler.stringClass) - && !Elements.isStringOnlySupertype(type.element, compiler) - && !Elements.isNumberOrStringSupertype(type.element, compiler)); - checkObject(input, '==='); - js.Expression objectTest = pop(); - checkArray(input, '==='); - js.Expression arrayTest = pop(); - checkType(input, type); - push(new js.Binary('&&', - objectTest, - new js.Binary('||', arrayTest, pop()))); - } - - void visitIs(HIs node) { - DartType type = node.typeExpression; - world.registerIsCheck(type); - Element element = type.element; - if (identical(element.kind, ElementKind.TYPE_VARIABLE)) { - compiler.unimplemented("visitIs for type variables", - instruction: node.expression); - } - LibraryElement coreLibrary = compiler.coreLibrary; - ClassElement objectClass = compiler.objectClass; - HInstruction input = node.expression; - - if (identical(element, objectClass) || - identical(element, compiler.dynamicClass)) { - // The constant folder also does this optimization, but we make - // it safe by assuming it may have not run. - push(newLiteralBool(true), node); - } else if (element == compiler.stringClass) { - checkString(input, '==='); - attachLocationToLast(node); - } else if (element == compiler.doubleClass) { - checkDouble(input, '==='); - attachLocationToLast(node); - } else if (element == compiler.numClass) { - checkNum(input, '==='); - attachLocationToLast(node); - } else if (element == compiler.boolClass) { - checkBool(input, '==='); - attachLocationToLast(node); - } else if (element == compiler.functionClass) { - checkFunction(input, type); - attachLocationToLast(node); - } else if (element == compiler.intClass) { - // The is check in the code tells us that it might not be an - // int. So we do a typeof first to avoid possible - // deoptimizations on the JS engine due to the Math.floor check. - checkNum(input, '==='); - js.Expression numTest = pop(); - checkBigInt(input, '==='); - push(new js.Binary('&&', numTest, pop()), node); - } else if (Elements.isNumberOrStringSupertype(element, compiler)) { - handleNumberOrStringSupertypeCheck(input, type); - attachLocationToLast(node); - } else if (Elements.isStringOnlySupertype(element, compiler)) { - handleStringSupertypeCheck(input, type); - attachLocationToLast(node); - } else if (identical(element, compiler.listClass) - || Elements.isListSupertype(element, compiler)) { - handleListOrSupertypeCheck(input, type); - attachLocationToLast(node); - } else if (element.isTypedef()) { - checkNonNull(input); - js.Expression nullTest = pop(); - checkType(input, type); - push(new js.Binary('&&', nullTest, pop())); - attachLocationToLast(node); - } else if (types[input].canBePrimitive() || types[input].canBeNull()) { - checkObject(input, '==='); - js.Expression objectTest = pop(); - checkType(input, type); - push(new js.Binary('&&', objectTest, pop()), node); - } else { - checkType(input, type); - attachLocationToLast(node); - } - if (node.hasArgumentChecks()) { - InterfaceType interfaceType = type; - ClassElement cls = type.element; - Link<DartType> arguments = interfaceType.typeArguments; - js.Expression result = pop(); - for (int i = 0; i < node.checkCount; i++) { - use(node.getCheck(i)); - result = new js.Binary('&&', result, pop()); - } - push(result, node); - } - if (node.nullOk) { - checkNull(input); - push(new js.Binary('||', pop(), pop()), node); - } - } - - // TODO(johnniwinther): Refactor this method. - void visitTypeConversion(HTypeConversion node) { - Map<String, SourceString> castNames = const <String, SourceString> { - "stringTypeCheck": - const SourceString("stringTypeCast"), - "doubleTypeCheck": - const SourceString("doubleTypeCast"), - "numTypeCheck": - const SourceString("numTypeCast"), - "boolTypeCheck": - const SourceString("boolTypeCast"), - "functionTypeCheck": - const SourceString("functionTypeCast"), - "intTypeCheck": - const SourceString("intTypeCast"), - "numberOrStringSuperNativeTypeCheck": - const SourceString("numberOrStringSuperNativeTypeCast"), - "numberOrStringSuperTypeCheck": - const SourceString("numberOrStringSuperTypeCast"), - "stringSuperNativeTypeCheck": - const SourceString("stringSuperNativeTypeCast"), - "stringSuperTypeCheck": - const SourceString("stringSuperTypeCast"), - "listTypeCheck": - const SourceString("listTypeCast"), - "listSuperNativeTypeCheck": - const SourceString("listSuperNativeTypeCast"), - "listSuperTypeCheck": - const SourceString("listSuperTypeCast"), - "callTypeCheck": - const SourceString("callTypeCast"), - "propertyTypeCheck": - const SourceString("propertyTypeCast"), - // TODO(johnniwinther): Add a malformedTypeCast which produces a TypeError - // with another message. - "malformedTypeCheck": - const SourceString("malformedTypeCheck") - }; - - if (node.isChecked) { - DartType type = node.type.computeType(compiler); - Element element = type.element; - world.registerIsCheck(type); - - if (node.isArgumentTypeCheck) { - if (element == backend.jsIntClass) { - checkInt(node.checkedInput, '!=='); - } else { - assert(element == backend.jsNumberClass); - checkNum(node.checkedInput, '!=='); - } - js.Expression test = pop(); - js.Block oldContainer = currentContainer; - js.Statement body = new js.Block.empty(); - currentContainer = body; - generateThrowWithHelper('iae', node.checkedInput); - currentContainer = oldContainer; - body = unwrapStatement(body); - pushStatement(new js.If.noElse(test, body), node); - return; - } - assert(node.isCheckedModeCheck || node.isCastTypeCheck); - - SourceString helper; - if (node.isBooleanConversionCheck) { - helper = const SourceString('boolConversionCheck'); - } else { - helper = backend.getCheckedModeHelper(type); - if (node.isCastTypeCheck) { - helper = castNames[helper.stringValue]; - } - } - FunctionElement helperElement = compiler.findHelper(helper); - world.registerStaticUse(helperElement); - List<js.Expression> arguments = <js.Expression>[]; - use(node.checkedInput); - arguments.add(pop()); - int parameterCount = - helperElement.computeSignature(compiler).parameterCount; - if (parameterCount == 2) { - // 2 arguments implies that the method is either [propertyTypeCheck] - // or [propertyTypeCast]. - assert(!type.isMalformed); - String additionalArgument = backend.namer.operatorIs(element); - arguments.add(js.string(additionalArgument)); - } else if (parameterCount == 3) { - // 3 arguments implies that the method is [malformedTypeCheck]. - assert(type.isMalformed); - String reasons = Types.fetchReasonsFromMalformedType(type); - arguments.add(js.string('$type')); - // TODO(johnniwinther): Handle escaping correctly. - arguments.add(js.string(reasons)); - } else { - assert(!type.isMalformed); - } - String helperName = backend.namer.isolateAccess(helperElement); - push(new js.Call(new js.VariableUse(helperName), arguments)); - } else { - use(node.checkedInput); - } - } -} - -class SsaOptimizedCodeGenerator extends SsaCodeGenerator { - SsaOptimizedCodeGenerator(backend, work) : super(backend, work); - - HBasicBlock beginGraph(HGraph graph) { - return graph.entry; - } - - void endGraph(HGraph graph) {} - - // Called by visitTypeGuard to generate the actual bailout call, something - // like "return $.foo$bailout(t0, t1);" - js.Statement bailout(HTypeGuard guard, String reason) { - HBailoutTarget target = guard.bailoutTarget; - List<js.Expression> arguments = <js.Expression>[]; - arguments.add(new js.LiteralNumber("${guard.state}")); - - for (int i = 0; i < target.inputs.length; i++) { - HInstruction parameter = target.inputs[i]; - for (int pad = target.padding[i]; pad != 0; pad--) { - // This argument will not be used by the bailout function, because - // of the control flow (controlled by the state argument passed - // above). We need to pass it to get later arguments in the right - // position. - arguments.add(new js.LiteralNumber('0')); - } - use(parameter); - arguments.add(pop()); - } - // Don't bother emitting the rest of the pending nulls. Doing so might make - // the function invocation a little faster by having the call site and - // function defintion have the same number of arguments, but it would be - // more verbose and we don't expect the calls to bailout functions to be - // hot. - - Element method = work.element; - js.Expression bailoutTarget; // Receiver of the bailout call. - Namer namer = backend.namer; - if (method.isInstanceMember()) { - String bailoutName = namer.getBailoutName(method); - bailoutTarget = new js.PropertyAccess.field(new js.This(), bailoutName); - } else { - assert(!method.isField()); - bailoutTarget = new js.VariableUse(namer.isolateBailoutAccess(method)); - } - js.Call call = new js.Call(bailoutTarget, arguments); - attachLocation(call, guard); - return new js.Return(call); - } - - // Generate a type guard, something like "if (typeof t0 == 'number')" and the - // corresponding bailout call, something like "return $.foo$bailout(t0, t1);" - void visitTypeGuard(HTypeGuard node) { - HInstruction input = node.guarded; - DartType indexingBehavior = - backend.jsIndexingBehaviorInterface.computeType(compiler); - if (node.isInteger(types)) { - // if (input is !int) bailout - checkInt(input, '!=='); - js.Statement then = bailout(node, 'Not an integer'); - pushStatement(new js.If.noElse(pop(), then), node); - } else if (node.isNumber(types)) { - // if (input is !num) bailout - checkNum(input, '!=='); - js.Statement then = bailout(node, 'Not a number'); - pushStatement(new js.If.noElse(pop(), then), node); - } else if (node.isBoolean(types)) { - // if (input is !bool) bailout - checkBool(input, '!=='); - js.Statement then = bailout(node, 'Not a boolean'); - pushStatement(new js.If.noElse(pop(), then), node); - } else if (node.isString(types)) { - // if (input is !string) bailout - checkString(input, '!=='); - js.Statement then = bailout(node, 'Not a string'); - pushStatement(new js.If.noElse(pop(), then), node); - } else if (node.isExtendableArray(types)) { - // if (input is !Object || input is !Array || input.isFixed) bailout - checkObject(input, '!=='); - js.Expression objectTest = pop(); - checkArray(input, '!=='); - js.Expression arrayTest = pop(); - checkFixedArray(input); - js.Binary test = new js.Binary('||', objectTest, arrayTest); - test = new js.Binary('||', test, pop()); - js.Statement then = bailout(node, 'Not an extendable array'); - pushStatement(new js.If.noElse(test, then), node); - } else if (node.isMutableArray(types)) { - // if (input is !Object - // || ((input is !Array || input.isImmutable) - // && input is !JsIndexingBehavior)) bailout - checkObject(input, '!=='); - js.Expression objectTest = pop(); - checkArray(input, '!=='); - js.Expression arrayTest = pop(); - checkImmutableArray(input); - js.Binary notArrayOrImmutable = new js.Binary('||', arrayTest, pop()); - checkType(input, indexingBehavior, negative: true); - js.Binary notIndexing = new js.Binary('&&', notArrayOrImmutable, pop()); - js.Binary test = new js.Binary('||', objectTest, notIndexing); - js.Statement then = bailout(node, 'Not a mutable array'); - pushStatement(new js.If.noElse(test, then), node); - } else if (node.isReadableArray(types)) { - // if (input is !Object - // || (input is !Array && input is !JsIndexingBehavior)) bailout - checkObject(input, '!=='); - js.Expression objectTest = pop(); - checkArray(input, '!=='); - js.Expression arrayTest = pop(); - checkType(input, indexingBehavior, negative: true); - js.Expression notIndexing = new js.Binary('&&', arrayTest, pop()); - js.Binary test = new js.Binary('||', objectTest, notIndexing); - js.Statement then = bailout(node, 'Not an array'); - pushStatement(new js.If.noElse(test, then), node); - } else if (node.isIndexablePrimitive(types)) { - // if (input is !String - // && (input is !Object - // || (input is !Array && input is !JsIndexingBehavior))) bailout - checkString(input, '!=='); - js.Expression stringTest = pop(); - checkObject(input, '!=='); - js.Expression objectTest = pop(); - checkArray(input, '!=='); - js.Expression arrayTest = pop(); - checkType(input, indexingBehavior, negative: true); - js.Binary notIndexingTest = new js.Binary('&&', arrayTest, pop()); - js.Binary notObjectOrIndexingTest = - new js.Binary('||', objectTest, notIndexingTest); - js.Binary test = - new js.Binary('&&', stringTest, notObjectOrIndexingTest); - js.Statement then = bailout(node, 'Not a string or array'); - pushStatement(new js.If.noElse(test, then), node); - } else { - compiler.internalError('Unexpected type guard', instruction: input); - } - } - - void visitBailoutTarget(HBailoutTarget target) { - // Do nothing. Bailout targets are only used in the non-optimized version. - } - - void preLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { - } - - void startLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { - } - - void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { - } -} - -class SsaUnoptimizedCodeGenerator extends SsaCodeGenerator { - - js.Switch currentBailoutSwitch; - final List<js.Switch> oldBailoutSwitches; - final List<js.Parameter> newParameters; - final List<String> labels; - int labelId = 0; - /** - * Keeps track if a bailout switch already used its [:default::] clause. New - * bailout-switches just push [:false:] on the stack and replace it when - * they used the [:default::] clause. - */ - final List<bool> defaultClauseUsedInBailoutStack; - - SsaBailoutPropagator propagator; - HInstruction savedFirstInstruction; - - SsaUnoptimizedCodeGenerator(backend, work) - : super(backend, work), - oldBailoutSwitches = <js.Switch>[], - newParameters = <js.Parameter>[], - labels = <String>[], - defaultClauseUsedInBailoutStack = <bool>[]; - - String pushLabel() { - String label = 'L${labelId++}'; - labels.addLast(label); - return label; - } - - String popLabel() { - return labels.removeLast(); - } - - String currentLabel() { - return labels.last; - } - - js.VariableUse generateStateUse() - => new js.VariableUse(variableNames.stateName); - - HBasicBlock beginGraph(HGraph graph) { - propagator = new SsaBailoutPropagator(compiler, variableNames); - propagator.visitGraph(graph); - // TODO(ngeoffray): We could avoid generating the state at the - // call site for non-complex bailout methods. - newParameters.add(new js.Parameter(variableNames.stateName)); - - List<String> names = new List<String>(propagator.bailoutArity); - for (String variable in propagator.parameterNames.keys) { - int index = propagator.parameterNames[variable]; - assert(names[index] == null); - names[index] = variable; - } - for (int i = 0; i < names.length; i++) { - declaredLocals.add(names[i]); - newParameters.add(new js.Parameter(names[i])); - } - - if (propagator.hasComplexBailoutTargets) { - startBailoutSwitch(); - - return graph.entry; - } else { - // We change the first instruction of the first guard to be the - // bailout target. We will change it back in the call to [endGraph]. - HBasicBlock block = propagator.firstBailoutTarget.block; - savedFirstInstruction = block.first; - block.first = propagator.firstBailoutTarget; - return block; - } - } - - // If argument is a [HCheck] and it does not have a name, we try to - // find the name of its checked input. Note that there must be a - // name, otherwise the instruction would not be in the live - // environment. - HInstruction unwrap(HInstruction argument) { - while (argument is HCheck && !variableNames.hasName(argument)) { - argument = argument.checkedInput; - } - assert(variableNames.hasName(argument)); - return argument; - } - - void endGraph(HGraph graph) { - if (propagator.hasComplexBailoutTargets) { - endBailoutSwitch(); - } else { - // Put back the original first instruction of the block. - propagator.firstBailoutTarget.block.first = savedFirstInstruction; - } - } - - visitParameterValue(HParameterValue node) { - // Nothing to do, parameters are dealt with specially in a bailout - // method. - } - - bool visitAndOrInfo(HAndOrBlockInformation info) => false; - - visitLoopBranch(HLoopBranch node) { - if (node.computeLoopHeader().hasBailoutTargets()) { - // The graph visitor in [visitLoopInfo] does not handle the - // condition. We must instead manually emit it here. - handleLoopCondition(node); - // We must also visit the body from here. - // For a do while loop, the body has already been visited. - if (!node.isDoWhile()) { - visitBasicBlock(node.block.dominatedBlocks[0]); - } - } else { - super.visitLoopBranch(node); - } - } - - - bool visitIfInfo(HIfBlockInformation info) { - if (info.thenGraph.start.hasBailoutTargets()) return false; - if (info.elseGraph.start.hasBailoutTargets()) return false; - return super.visitIfInfo(info); - } - - bool visitLoopInfo(HLoopBlockInformation info) { - // Always emit with block flow traversal. - if (info.loopHeader.hasBailoutTargets()) { - // If there are any bailout targets in the loop, we cannot use - // the pretty [SsaCodeGenerator.visitLoopInfo] printer. - if (info.initializer != null) { - generateStatements(info.initializer); - } - beginLoop(info.loopHeader); - if (!info.isDoWhile()) { - generateStatements(info.condition); - } - generateStatements(info.body); - if (info.isDoWhile()) { - generateStatements(info.condition); - } - if (info.updates != null) { - generateStatements(info.updates); - } - endLoop(info.end); - return true; - } - return super.visitLoopInfo(info); - } - - bool visitTryInfo(HTryBlockInformation info) => false; - bool visitSequenceInfo(HStatementSequenceInformation info) => false; - - void visitTypeGuard(HTypeGuard node) { - // Do nothing. Type guards are only used in the optimized version. - } - - void visitBailoutTarget(HBailoutTarget node) { - if (propagator.hasComplexBailoutTargets) { - js.Block nextBlock = new js.Block.empty(); - js.Case clause = new js.Case(new js.LiteralNumber('${node.state}'), - nextBlock); - currentBailoutSwitch.cases.add(clause); - currentContainer = nextBlock; - pushExpressionAsStatement(new js.Assignment(generateStateUse(), - new js.LiteralNumber('0'))); - } - // Here we need to rearrange the inputs of the bailout target, so that they - // are output in the correct order, perhaps with interspersed nulls, to - // match the order in the bailout function, which is of course common to all - // the bailout points. - var newInputs = new List<HInstruction>(propagator.bailoutArity); - for (HInstruction input in node.inputs) { - int index = propagator.parameterNames[variableNames.getName(input)]; - newInputs[index] = input; - } - // We record the count of unused arguments instead of just filling in the - // inputs list with dummy arguments because it is useful to be able easily - // to distinguish between a dummy argument (eg 0 or null) and a real - // argument that happens to have the same value. The dummy arguments are - // not going to be accessed by the bailout function due to the control flow - // implied by the state argument, so we can put anything there, including - // just not emitting enough arguments and letting the JS engine insert - // undefined for the trailing arguments. - node.padding = new List<int>(node.inputs.length); - int j = 0; - int pendingUnusedArguments = 0; - for (int i = 0; i < newInputs.length; i++) { - HInstruction input = newInputs[i]; - if (input == null) { - pendingUnusedArguments++; - } else { - node.padding[j] = pendingUnusedArguments; - pendingUnusedArguments = 0; - node.updateInput(j, input); - j++; - } - } - assert(j == node.inputs.length); - } - - void startBailoutCase(List<HBailoutTarget> bailouts1, - [List<HBailoutTarget> bailouts2 = const []]) { - if (!defaultClauseUsedInBailoutStack.last && - bailouts1.length + bailouts2.length >= 2) { - currentContainer = new js.Block.empty(); - currentBailoutSwitch.cases.add(new js.Default(currentContainer)); - int len = defaultClauseUsedInBailoutStack.length; - defaultClauseUsedInBailoutStack[len - 1] = true; - } else { - _handleBailoutCase(bailouts1); - _handleBailoutCase(bailouts2); - currentContainer = currentBailoutSwitch.cases.last.body; - } - } - - void _handleBailoutCase(List<HBailoutTarget> targets) { - for (int i = 0, len = targets.length; i < len; i++) { - js.LiteralNumber expr = new js.LiteralNumber('${targets[i].state}'); - currentBailoutSwitch.cases.add(new js.Case(expr, new js.Block.empty())); - } - } - - void startBailoutSwitch() { - defaultClauseUsedInBailoutStack.add(false); - oldBailoutSwitches.add(currentBailoutSwitch); - List<js.SwitchClause> cases = <js.SwitchClause>[]; - js.Block firstBlock = new js.Block.empty(); - cases.add(new js.Case(new js.LiteralNumber("0"), firstBlock)); - currentBailoutSwitch = new js.Switch(generateStateUse(), cases); - pushStatement(currentBailoutSwitch); - oldContainerStack.add(currentContainer); - currentContainer = firstBlock; - } - - js.Switch endBailoutSwitch() { - js.Switch result = currentBailoutSwitch; - currentBailoutSwitch = oldBailoutSwitches.removeLast(); - defaultClauseUsedInBailoutStack.removeLast(); - currentContainer = oldContainerStack.removeLast(); - return result; - } - - void beginLoop(HBasicBlock block) { - String loopLabel = pushLabel(); - if (block.hasBailoutTargets()) { - startBailoutCase(block.bailoutTargets); - } - oldContainerStack.add(currentContainer); - currentContainer = new js.Block.empty(); - if (block.hasBailoutTargets()) { - startBailoutSwitch(); - HLoopInformation loopInformation = block.loopInformation; - if (loopInformation.target != null) { - breakAction[loopInformation.target] = (TargetElement target) { - pushStatement(new js.Break(loopLabel)); - }; - } - } - } - - void endLoop(HBasicBlock block) { - String loopLabel = popLabel(); - - HBasicBlock header = block.isLoopHeader() ? block : block.parentLoopHeader; - HLoopInformation info = header.loopInformation; - if (header.hasBailoutTargets()) { - endBailoutSwitch(); - if (info.target != null) breakAction.remove(info.target); - } - - js.Statement body = unwrapStatement(currentContainer); - currentContainer = oldContainerStack.removeLast(); - - js.Statement result = new js.While(newLiteralBool(true), body); - attachLocationRange(result, - info.loopBlockInformation.sourcePosition, - info.loopBlockInformation.endSourcePosition); - result = new js.LabeledStatement(loopLabel, result); - result = wrapIntoLabels(result, info.labels); - pushStatement(result); - } - - void handleLoopCondition(HLoopBranch node) { - use(node.inputs[0]); - js.Expression test = new js.Prefix('!', pop()); - js.Statement then = new js.Break(currentLabel()); - pushStatement(new js.If.noElse(test, then), node); - } - - void generateIf(HIf node, HIfBlockInformation info) { - HStatementInformation thenGraph = info.thenGraph; - HStatementInformation elseGraph = info.elseGraph; - bool thenHasGuards = thenGraph.start.hasBailoutTargets(); - bool elseHasGuards = elseGraph.start.hasBailoutTargets(); - bool hasGuards = thenHasGuards || elseHasGuards; - if (!hasGuards) { - super.generateIf(node, info); - return; - } - - startBailoutCase(thenGraph.start.bailoutTargets, - elseGraph.start.bailoutTargets); - - use(node.inputs[0]); - js.Binary stateEquals0 = - new js.Binary('===', generateStateUse(), new js.LiteralNumber('0')); - js.Expression condition = new js.Binary('&&', stateEquals0, pop()); - // TODO(ngeoffray): Put the condition initialization in the - // arguments? - List<HBailoutTarget> targets = node.thenBlock.bailoutTargets; - for (int i = 0, len = targets.length; i < len; i++) { - js.VariableUse stateRef = generateStateUse(); - js.Expression targetState = new js.LiteralNumber('${targets[i].state}'); - js.Binary stateTest = new js.Binary('===', stateRef, targetState); - condition = new js.Binary('||', stateTest, condition); - } - - js.Statement thenBody = new js.Block.empty(); - js.Block oldContainer = currentContainer; - currentContainer = thenBody; - if (thenHasGuards) startBailoutSwitch(); - generateStatements(thenGraph); - if (thenHasGuards) endBailoutSwitch(); - thenBody = unwrapStatement(thenBody); - - js.Statement elseBody = null; - elseBody = new js.Block.empty(); - currentContainer = elseBody; - if (elseHasGuards) startBailoutSwitch(); - generateStatements(elseGraph); - if (elseHasGuards) endBailoutSwitch(); - elseBody = unwrapStatement(elseBody); - - currentContainer = oldContainer; - pushStatement(new js.If(condition, thenBody, elseBody), node); - } - - void preLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { - if (labeledBlockInfo.body.start.hasBailoutTargets()) { - indent--; - startBailoutCase(labeledBlockInfo.body.start.bailoutTargets); - indent++; - } - } - - void startLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { - if (labeledBlockInfo.body.start.hasBailoutTargets()) { - startBailoutSwitch(); - } - } - - void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { - if (labeledBlockInfo.body.start.hasBailoutTargets()) { - endBailoutSwitch(); - } - } -} - -String singleIdentityComparison(HInstruction left, - HInstruction right, - HTypeMap propagatedTypes) { - // Returns the single identity comparison (== or ===) or null if a more - // complex expression is required. - if ((left.isConstant() && left.isConstantSentinel()) || - (right.isConstant() && right.isConstantSentinel())) return '==='; - HType leftType = propagatedTypes[left]; - HType rightType = propagatedTypes[right]; - if (leftType.canBeNull() && rightType.canBeNull()) { - if (left.isConstantNull() || right.isConstantNull() || - (leftType.isPrimitive() && leftType == rightType)) { - return '=='; - } - return null; - } else { - return '==='; - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/codegen_helpers.dart b/pkgs/markdown/test/lib/src/compiler/implementation/ssa/codegen_helpers.dart deleted file mode 100644 index 625eafb..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/codegen_helpers.dart +++ /dev/null
@@ -1,380 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of ssa; - -/** - * Instead of emitting each SSA instruction with a temporary variable - * mark instructions that can be emitted at their use-site. - * For example, in: - * t0 = 4; - * t1 = 3; - * t2 = add(t0, t1); - * t0 and t1 would be marked and the resulting code would then be: - * t2 = add(4, 3); - */ -class SsaInstructionMerger extends HBaseVisitor { - HTypeMap types; - /** - * List of [HInstruction] that the instruction merger expects in - * order when visiting the inputs of an instruction. - */ - List<HInstruction> expectedInputs; - /** - * Set of pure [HInstruction] that the instruction merger expects to - * find. The order of pure instructions do not matter, as they will - * not be affected by side effects. - */ - Set<HInstruction> pureInputs; - Set<HInstruction> generateAtUseSite; - - void markAsGenerateAtUseSite(HInstruction instruction) { - assert(!instruction.isJsStatement()); - generateAtUseSite.add(instruction); - } - - SsaInstructionMerger(this.types, this.generateAtUseSite); - - void visitGraph(HGraph graph) { - visitDominatorTree(graph); - } - - void analyzeInputs(HInstruction user, int start) { - List<HInstruction> inputs = user.inputs; - for (int i = start; i < inputs.length; i++) { - HInstruction input = inputs[i]; - if (!generateAtUseSite.contains(input) - && !input.isCodeMotionInvariant() - && input.usedBy.length == 1 - && input is !HPhi - && input is !HLocalValue - && !input.isJsStatement()) { - if (input.isPure()) { - // Only consider a pure input if it is in the same loop. - // Otherwise, we might move GVN'ed instruction back into the - // loop. - if (user.hasSameLoopHeaderAs(input)) { - // Move it closer to [user], so that instructions in - // between do not prevent making it generate at use site. - input.moveBefore(user); - pureInputs.add(input); - // Visit the pure input now so that the expected inputs - // are after the expected inputs of [user]. - input.accept(this); - } - } else { - expectedInputs.add(input); - } - } - } - } - - void visitInstruction(HInstruction instruction) { - // A code motion invariant instruction is dealt before visiting it. - assert(!instruction.isCodeMotionInvariant()); - analyzeInputs(instruction, 0); - } - - // The codegen might use the input multiple times, so it must not be - // set generate at use site. - void visitIs(HIs instruction) {} - - // A bounds check method must not have its first input generated at use site, - // because it's using it twice. - void visitBoundsCheck(HBoundsCheck instruction) { - analyzeInputs(instruction, 1); - } - - // An integer check method must not have its input generated at use site, - // because it's using it twice. - void visitIntegerCheck(HIntegerCheck instruction) {} - - // A type guard should not generate its input at use site, otherwise - // they would not be alive. - void visitTypeGuard(HTypeGuard instruction) {} - - // An identity operation must only have its inputs generated at use site if - // does not require an expression with multiple uses (because of null / - // undefined). - void visitIdentity(HIdentity instruction) { - HInstruction left = instruction.left; - HInstruction right = instruction.right; - if (singleIdentityComparison(left, right, types) != null) { - super.visitIdentity(instruction); - } - // Do nothing. - } - - void visitTypeConversion(HTypeConversion instruction) { - if (!instruction.isChecked) { - markAsGenerateAtUseSite(instruction); - } else if (!instruction.isArgumentTypeCheck) { - assert(instruction.isCheckedModeCheck || instruction.isCastTypeCheck); - // Checked mode checks and cast checks compile to code that - // only use their input once, so we can safely visit them - // and try to merge the input. - visitInstruction(instruction); - } - } - - void tryGenerateAtUseSite(HInstruction instruction) { - if (instruction.isControlFlow()) return; - markAsGenerateAtUseSite(instruction); - } - - bool isBlockSinglePredecessor(HBasicBlock block) { - return block.successors.length == 1 - && block.successors[0].predecessors.length == 1; - } - - void visitBasicBlock(HBasicBlock block) { - // Compensate from not merging blocks: if the block is the - // single predecessor of its single successor, let the successor - // visit it. - if (isBlockSinglePredecessor(block)) return; - - tryMergingExpressions(block); - } - - void tryMergingExpressions(HBasicBlock block) { - // Visit each instruction of the basic block in last-to-first order. - // Keep a list of expected inputs of the current "expression" being - // merged. If instructions occur in the expected order, they are - // included in the expression. - - // The expectedInputs list holds non-trivial instructions that may - // be generated at their use site, if they occur in the correct order. - if (expectedInputs == null) expectedInputs = new List<HInstruction>(); - if (pureInputs == null) pureInputs = new Set<HInstruction>(); - - // Pop instructions from expectedInputs until instruction is found. - // Return true if it is found, or false if not. - bool findInInputsAndPopNonMatching(HInstruction instruction) { - assert(!instruction.isPure()); - while (!expectedInputs.isEmpty) { - HInstruction nextInput = expectedInputs.removeLast(); - assert(!generateAtUseSite.contains(nextInput)); - assert(nextInput.usedBy.length == 1); - if (identical(nextInput, instruction)) { - return true; - } - } - return false; - } - - block.last.accept(this); - bool dontVisitPure = false; - for (HInstruction instruction = block.last.previous; - instruction != null; - instruction = instruction.previous) { - if (generateAtUseSite.contains(instruction)) { - continue; - } - if (instruction.isCodeMotionInvariant()) { - markAsGenerateAtUseSite(instruction); - continue; - } - if (instruction.isJsStatement()) { - expectedInputs.clear(); - } - if (instruction.isPure()) { - if (pureInputs.contains(instruction)) { - tryGenerateAtUseSite(instruction); - } else { - // If the input is not in the [pureInputs] set, it has not - // been visited. - instruction.accept(this); - } - } else { - if (findInInputsAndPopNonMatching(instruction)) { - // The current instruction is the next non-trivial - // expected input. - tryGenerateAtUseSite(instruction); - } else { - assert(expectedInputs.isEmpty); - } - instruction.accept(this); - } - } - - if (block.predecessors.length == 1 - && isBlockSinglePredecessor(block.predecessors[0])) { - assert(block.phis.isEmpty); - tryMergingExpressions(block.predecessors[0]); - } else { - expectedInputs = null; - pureInputs = null; - } - } -} - -/** - * Detect control flow arising from short-circuit logical and - * conditional operators, and prepare the program to be generated - * using these operators instead of nested ifs and boolean variables. - */ -class SsaConditionMerger extends HGraphVisitor { - final HTypeMap types; - Set<HInstruction> generateAtUseSite; - Set<HInstruction> controlFlowOperators; - - void markAsGenerateAtUseSite(HInstruction instruction) { - assert(!instruction.isJsStatement()); - generateAtUseSite.add(instruction); - } - - SsaConditionMerger(this.types, - this.generateAtUseSite, - this.controlFlowOperators); - - void visitGraph(HGraph graph) { - visitPostDominatorTree(graph); - } - - /** - * Check if a block has at least one statement other than - * [instruction]. - */ - bool hasAnyStatement(HBasicBlock block, HInstruction instruction) { - // If [instruction] is not in [block], then if the block is not - // empty, we know there will be a statement to emit. - if (!identical(instruction.block, block)) return !identical(block.last, block.first); - - // If [instruction] is not the last instruction of the block - // before the control flow instruction, or the last instruction, - // then we will have to emit a statement for that last instruction. - if (instruction != block.last - && !identical(instruction, block.last.previous)) return true; - - // If one of the instructions in the block until [instruction] is - // not generated at use site, then we will have to emit a - // statement for it. - // TODO(ngeoffray): we could generate a comma separated - // list of expressions. - for (HInstruction temp = block.first; - !identical(temp, instruction); - temp = temp.next) { - if (!generateAtUseSite.contains(temp)) return true; - } - - return false; - } - - bool isSafeToGenerateAtUseSite(HInstruction user, HInstruction input) { - // A [HForeign] instruction uses operators and if we generate - // [input] at use site, the precedence might be wrong. - if (user is HForeign) return false; - // A [HCheck] instruction with control flow uses its input - // multiple times, so we avoid generating it at use site. - if (user is HCheck && user.isControlFlow()) return false; - // A [HIs] instruction uses its input multiple times, so we - // avoid generating it at use site. - if (user is HIs) return false; - return true; - } - - void visitBasicBlock(HBasicBlock block) { - if (block.last is !HIf) return; - HIf startIf = block.last; - HBasicBlock end = startIf.joinBlock; - - // We check that the structure is the following: - // If - // / \ - // / \ - // 1 expr goto - // goto / - // \ / - // \ / - // phi(expr, true|false) - // - // and the same for nested nodes: - // - // If - // / \ - // / \ - // 1 expr1 \ - // If \ - // / \ \ - // / \ goto - // 1 expr2 | - // goto goto | - // \ / | - // \ / | - // phi1(expr2, true|false) - // \ | - // \ | - // phi(phi1, true|false) - - if (end == null) return; - if (end.phis.isEmpty) return; - if (!identical(end.phis.first, end.phis.last)) return; - HBasicBlock elseBlock = startIf.elseBlock; - - if (!identical(end.predecessors[1], elseBlock)) return; - HPhi phi = end.phis.first; - HInstruction thenInput = phi.inputs[0]; - HInstruction elseInput = phi.inputs[1]; - if (thenInput.isJsStatement() || elseInput.isJsStatement()) return; - - if (hasAnyStatement(elseBlock, elseInput)) return; - assert(elseBlock.successors.length == 1); - assert(end.predecessors.length == 2); - - HBasicBlock thenBlock = startIf.thenBlock; - // Skip trivial goto blocks. - while (thenBlock.successors[0] != end && thenBlock.first is HGoto) { - thenBlock = thenBlock.successors[0]; - } - - // If the [thenBlock] is already a control flow operation, and does not - // have any statement and its join block is [end], we can emit a - // sequence of control flow operation. - if (controlFlowOperators.contains(thenBlock.last)) { - HIf otherIf = thenBlock.last; - if (!identical(otherIf.joinBlock, end)) { - // This could be a join block that just feeds into our join block. - HBasicBlock otherJoin = otherIf.joinBlock; - if (otherJoin.first != otherJoin.last) return; - if (otherJoin.successors.length != 1) return; - if (otherJoin.successors[0] != end) return; - if (otherJoin.phis.isEmpty) return; - if (!identical(otherJoin.phis.first, otherJoin.phis.last)) return; - HPhi otherPhi = otherJoin.phis.first; - if (thenInput != otherPhi) return; - if (elseInput != otherPhi.inputs[1]) return; - } - if (hasAnyStatement(thenBlock, otherIf)) return; - } else { - if (!identical(end.predecessors[0], thenBlock)) return; - if (hasAnyStatement(thenBlock, thenInput)) return; - assert(thenBlock.successors.length == 1); - } - - // From now on, we have recognized a control flow operation built from - // the builder. Mark the if instruction as such. - controlFlowOperators.add(startIf); - - // If the operation is only used by the first instruction - // of its block and is safe to be generated at use site, mark it - // so. - if (phi.usedBy.length == 1 - && identical(phi.usedBy[0], phi.block.first) - && isSafeToGenerateAtUseSite(phi.usedBy[0], phi)) { - markAsGenerateAtUseSite(phi); - } - - if (identical(elseInput.block, elseBlock)) { - assert(elseInput.usedBy.length == 1); - markAsGenerateAtUseSite(elseInput); - } - - // If [thenInput] is defined in the first predecessor, then it is only used - // by [phi] and can be generated at use site. - if (identical(thenInput.block, end.predecessors[0])) { - assert(thenInput.usedBy.length == 1); - markAsGenerateAtUseSite(thenInput); - } - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/invoke_dynamic_specializers.dart b/pkgs/markdown/test/lib/src/compiler/implementation/ssa/invoke_dynamic_specializers.dart deleted file mode 100644 index 375f617..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/invoke_dynamic_specializers.dart +++ /dev/null
@@ -1,620 +0,0 @@ -// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of ssa; - -/** - * [InvokeDynamicSpecializer] and its subclasses are helpers to - * optimize intercepted dynamic calls. It knows what input types - * would be beneficial for performance, and how to change a invoke - * dynamic to a builtin instruction (e.g. HIndex, HBitNot). - */ -class InvokeDynamicSpecializer { - const InvokeDynamicSpecializer(); - - HType computeDesiredTypeForInput(HInvokeDynamic instruction, - HInstruction input, - HTypeMap types, - Compiler compiler) { - return HType.UNKNOWN; - } - - HType computeTypeFromInputTypes(HInvokeDynamic instruction, - HTypeMap types, - Compiler compiler) { - return HType.UNKNOWN; - } - - HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, - HTypeMap types) { - return null; - } - - Operation operation(ConstantSystem constantSystem) => null; - - static InvokeDynamicSpecializer lookupSpecializer(Selector selector) { - if (selector.kind == SelectorKind.INDEX) { - return selector.name == const SourceString('[]') - ? const IndexSpecializer() - : const IndexAssignSpecializer(); - } else if (selector.kind == SelectorKind.OPERATOR) { - if (selector.name == const SourceString('unary-')) { - return const UnaryNegateSpecializer(); - } else if (selector.name == const SourceString('~')) { - return const BitNotSpecializer(); - } else if (selector.name == const SourceString('+')) { - return const AddSpecializer(); - } else if (selector.name == const SourceString('-')) { - return const SubtractSpecializer(); - } else if (selector.name == const SourceString('*')) { - return const MultiplySpecializer(); - } else if (selector.name == const SourceString('/')) { - return const DivideSpecializer(); - } else if (selector.name == const SourceString('~/')) { - return const TruncatingDivideSpecializer(); - } else if (selector.name == const SourceString('%')) { - return const ModuloSpecializer(); - } else if (selector.name == const SourceString('>>')) { - return const ShiftRightSpecializer(); - } else if (selector.name == const SourceString('<<')) { - return const ShiftLeftSpecializer(); - } else if (selector.name == const SourceString('&')) { - return const BitAndSpecializer(); - } else if (selector.name == const SourceString('|')) { - return const BitOrSpecializer(); - } else if (selector.name == const SourceString('^')) { - return const BitXorSpecializer(); - } else if (selector.name == const SourceString('==')) { - return const EqualsSpecializer(); - } else if (selector.name == const SourceString('<')) { - return const LessSpecializer(); - } else if (selector.name == const SourceString('<=')) { - return const LessEqualSpecializer(); - } else if (selector.name == const SourceString('>')) { - return const GreaterSpecializer(); - } else if (selector.name == const SourceString('>=')) { - return const GreaterEqualSpecializer(); - } - } - return const InvokeDynamicSpecializer(); - } -} - -class IndexAssignSpecializer extends InvokeDynamicSpecializer { - const IndexAssignSpecializer(); - - HType computeDesiredTypeForInput(HInvokeDynamic instruction, - HInstruction input, - HTypeMap types, - Compiler compiler) { - HInstruction index = instruction.inputs[2]; - if (input == instruction.inputs[1] && - (index.isTypeUnknown(types) || index.isNumber(types))) { - return HType.MUTABLE_ARRAY; - } - // The index should be an int when the receiver is a string or array. - // However it turns out that inserting an integer check in the optimized - // version is cheaper than having another bailout case. This is true, - // because the integer check will simply throw if it fails. - return HType.UNKNOWN; - } - - HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, - HTypeMap types) { - if (instruction.inputs[1].isMutableArray(types)) { - return new HIndexAssign(instruction.inputs[1], - instruction.inputs[2], - instruction.inputs[3]); - } - return null; - } -} - -class IndexSpecializer extends InvokeDynamicSpecializer { - const IndexSpecializer(); - - HType computeDesiredTypeForInput(HInvokeDynamic instruction, - HInstruction input, - HTypeMap types, - Compiler compiler) { - HInstruction index = instruction.inputs[2]; - if (input == instruction.inputs[1] && - (index.isTypeUnknown(types) || index.isNumber(types))) { - return HType.INDEXABLE_PRIMITIVE; - } - // The index should be an int when the receiver is a string or array. - // However it turns out that inserting an integer check in the optimized - // version is cheaper than having another bailout case. This is true, - // because the integer check will simply throw if it fails. - return HType.UNKNOWN; - } - - HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, - HTypeMap types) { - if (instruction.inputs[1].isIndexablePrimitive(types)) { - return new HIndex(instruction.inputs[1], instruction.inputs[2]); - } - return null; - } -} - -class BitNotSpecializer extends InvokeDynamicSpecializer { - const BitNotSpecializer(); - - UnaryOperation operation(ConstantSystem constantSystem) { - return constantSystem.bitNot; - } - - HType computeDesiredTypeForInput(HInvokeDynamic instruction, - HInstruction input, - HTypeMap types, - Compiler compiler) { - if (input == instruction.inputs[1]) { - HType propagatedType = types[instruction]; - if (propagatedType.isUnknown() || propagatedType.isNumber()) { - return HType.INTEGER; - } - } - return HType.UNKNOWN; - } - - HType computeTypeFromInputTypes(HInvokeDynamic instruction, - HTypeMap types, - Compiler compiler) { - // All bitwise operations on primitive types either produce an - // integer or throw an error. - if (instruction.inputs[1].isPrimitive(types)) return HType.INTEGER; - return HType.UNKNOWN; - } - - HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, - HTypeMap types) { - HInstruction input = instruction.inputs[1]; - if (input.isNumber(types)) return new HBitNot(input); - return null; - } -} - -class UnaryNegateSpecializer extends InvokeDynamicSpecializer { - const UnaryNegateSpecializer(); - - UnaryOperation operation(ConstantSystem constantSystem) { - return constantSystem.negate; - } - - HType computeDesiredTypeForInput(HInvokeDynamic instruction, - HInstruction input, - HTypeMap types, - Compiler compiler) { - if (input == instruction.inputs[1]) { - HType propagatedType = types[instruction]; - // If the outgoing type should be a number (integer, double or both) we - // want the outgoing type to be the input too. - // If we don't know the outgoing type we try to make it a number. - if (propagatedType.isNumber()) return propagatedType; - if (propagatedType.isUnknown()) return HType.NUMBER; - } - return HType.UNKNOWN; - } - - HType computeTypeFromInputTypes(HInvokeDynamic instruction, - HTypeMap types, - Compiler compiler) { - HType operandType = types[instruction.inputs[1]]; - if (operandType.isNumber()) return operandType; - return HType.UNKNOWN; - } - - HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, - HTypeMap types) { - HInstruction input = instruction.inputs[1]; - if (input.isNumber(types)) return new HNegate(input); - return null; - } -} - -abstract class BinaryArithmeticSpecializer extends InvokeDynamicSpecializer { - const BinaryArithmeticSpecializer(); - - HType computeTypeFromInputTypes(HInvokeDynamic instruction, - HTypeMap types, - Compiler compiler) { - HInstruction left = instruction.inputs[1]; - HInstruction right = instruction.inputs[2]; - if (left.isInteger(types) && right.isInteger(types)) return HType.INTEGER; - if (left.isNumber(types)) { - if (left.isDouble(types) || right.isDouble(types)) return HType.DOUBLE; - return HType.NUMBER; - } - return HType.UNKNOWN; - } - - HType computeDesiredTypeForInput(HInvokeDynamic instruction, - HInstruction input, - HTypeMap types, - Compiler compiler) { - if (input == instruction.inputs[0]) return HType.UNKNOWN; - - HType propagatedType = types[instruction]; - // If the desired output type should be an integer we want to get two - // integers as arguments. - if (propagatedType.isInteger()) return HType.INTEGER; - // If the outgoing type should be a number we can get that if both inputs - // are numbers. If we don't know the outgoing type we try to make it a - // number. - if (propagatedType.isUnknown() || propagatedType.isNumber()) { - return HType.NUMBER; - } - // Even if the desired outgoing type is not a number we still want the - // second argument to be a number if the first one is a number. This will - // not help for the outgoing type, but at least the binary arithmetic - // operation will not have type problems. - // TODO(floitsch): normally we shouldn't request a number, but simply - // throw an ArgumentError if it isn't. This would be similar - // to the array case. - HInstruction left = instruction.inputs[1]; - HInstruction right = instruction.inputs[2]; - if (input == right && left.isNumber(types)) return HType.NUMBER; - return HType.UNKNOWN; - } - - bool isBuiltin(HInvokeDynamic instruction, HTypeMap types) { - return instruction.inputs[1].isNumber(types) - && instruction.inputs[2].isNumber(types); - } - - HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, - HTypeMap types) { - if (isBuiltin(instruction, types)) { - HInstruction builtin = - newBuiltinVariant(instruction.inputs[1], instruction.inputs[2]); - if (builtin != null) return builtin; - // Even if there is no builtin equivalent instruction, we know - // the instruction does not have any side effect, and that it - // can be GVN'ed. - instruction.clearAllSideEffects(); - instruction.clearAllDependencies(); - instruction.setUseGvn(); - } - return null; - } - - HInstruction newBuiltinVariant(HInstruction left, HInstruction right); -} - -class AddSpecializer extends BinaryArithmeticSpecializer { - const AddSpecializer(); - - BinaryOperation operation(ConstantSystem constantSystem) { - return constantSystem.add; - } - - HInstruction newBuiltinVariant(HInstruction left, HInstruction right) { - return new HAdd(left, right); - } -} - -class DivideSpecializer extends BinaryArithmeticSpecializer { - const DivideSpecializer(); - - BinaryOperation operation(ConstantSystem constantSystem) { - return constantSystem.divide; - } - - HType computeTypeFromInputTypes(HInstruction instruction, - HTypeMap types, - Compiler compiler) { - HInstruction left = instruction.inputs[1]; - if (left.isNumber(types)) return HType.DOUBLE; - return HType.UNKNOWN; - } - - HType computeDesiredTypeForInput(HInstruction instruction, - HInstruction input, - HTypeMap types, - Compiler compiler) { - if (input == instruction.inputs[0]) return HType.UNKNOWN; - // A division can never return an integer. So don't ask for integer inputs. - if (instruction.isInteger(types)) return HType.UNKNOWN; - return super.computeDesiredTypeForInput( - instruction, input, types, compiler); - } - - HInstruction newBuiltinVariant(HInstruction left, HInstruction right) { - return new HDivide(left, right); - } -} - -class ModuloSpecializer extends BinaryArithmeticSpecializer { - const ModuloSpecializer(); - - BinaryOperation operation(ConstantSystem constantSystem) { - return constantSystem.modulo; - } - - HInstruction newBuiltinVariant(HInstruction left, HInstruction right) { - // Modulo cannot be mapped to the native operator (different semantics). - return null; - } -} - -class MultiplySpecializer extends BinaryArithmeticSpecializer { - const MultiplySpecializer(); - - BinaryOperation operation(ConstantSystem constantSystem) { - return constantSystem.multiply; - } - - HInstruction newBuiltinVariant(HInstruction left, HInstruction right) { - return new HMultiply(left, right); - } -} - -class SubtractSpecializer extends BinaryArithmeticSpecializer { - const SubtractSpecializer(); - - BinaryOperation operation(ConstantSystem constantSystem) { - return constantSystem.subtract; - } - - HInstruction newBuiltinVariant(HInstruction left, HInstruction right) { - return new HSubtract(left, right); - } -} - -class TruncatingDivideSpecializer extends BinaryArithmeticSpecializer { - const TruncatingDivideSpecializer(); - - BinaryOperation operation(ConstantSystem constantSystem) { - return constantSystem.truncatingDivide; - } - - HInstruction newBuiltinVariant(HInstruction left, HInstruction right) { - // Truncating divide does not have a JS equivalent. - return null; - } -} - -abstract class BinaryBitOpSpecializer extends BinaryArithmeticSpecializer { - const BinaryBitOpSpecializer(); - - HType computeTypeFromInputTypes(HInvokeDynamic instruction, - HTypeMap types, - Compiler compiler) { - // All bitwise operations on primitive types either produce an - // integer or throw an error. - HInstruction left = instruction.inputs[1]; - if (left.isPrimitive(types)) return HType.INTEGER; - return HType.UNKNOWN; - } - - HType computeDesiredTypeForInput(HInvokeDynamic instruction, - HInstruction input, - HTypeMap types, - Compiler compiler) { - if (input == instruction.inputs[0]) return HType.UNKNOWN; - HType propagatedType = types[instruction]; - // If the outgoing type should be a number we can get that only if both - // inputs are integers. If we don't know the outgoing type we try to make - // it an integer. - if (propagatedType.isUnknown() || propagatedType.isNumber()) { - return HType.INTEGER; - } - return HType.UNKNOWN; - } -} - -class ShiftLeftSpecializer extends BinaryBitOpSpecializer { - const ShiftLeftSpecializer(); - - BinaryOperation operation(ConstantSystem constantSystem) { - return constantSystem.shiftLeft; - } - - HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, - HTypeMap types) { - HInstruction left = instruction.inputs[1]; - HInstruction right = instruction.inputs[2]; - if (!left.isNumber(types) || !right.isConstantInteger()) return null; - HConstant rightConstant = right; - IntConstant intConstant = rightConstant.constant; - int count = intConstant.value; - if (count >= 0 && count <= 31) { - return newBuiltinVariant(left, right); - } - return null; - } - - HInstruction newBuiltinVariant(HInstruction left, HInstruction right) { - return new HShiftLeft(left, right); - } -} - -class ShiftRightSpecializer extends BinaryBitOpSpecializer { - const ShiftRightSpecializer(); - - HInstruction newBuiltinVariant(HInstruction left, HInstruction right) { - // Shift right cannot be mapped to the native operator easily. - return null; - } - - BinaryOperation operation(ConstantSystem constantSystem) { - return constantSystem.shiftRight; - } -} - -class BitOrSpecializer extends BinaryBitOpSpecializer { - const BitOrSpecializer(); - - BinaryOperation operation(ConstantSystem constantSystem) { - return constantSystem.bitOr; - } - - HInstruction newBuiltinVariant(HInstruction left, HInstruction right) { - return new HBitOr(left, right); - } -} - -class BitAndSpecializer extends BinaryBitOpSpecializer { - const BitAndSpecializer(); - - BinaryOperation operation(ConstantSystem constantSystem) { - return constantSystem.bitAnd; - } - - HInstruction newBuiltinVariant(HInstruction left, HInstruction right) { - return new HBitAnd(left, right); - } -} - -class BitXorSpecializer extends BinaryBitOpSpecializer { - const BitXorSpecializer(); - - BinaryOperation operation(ConstantSystem constantSystem) { - return constantSystem.bitXor; - } - - HInstruction newBuiltinVariant(HInstruction left, HInstruction right) { - return new HBitXor(left, right); - } -} - -abstract class RelationalSpecializer extends InvokeDynamicSpecializer { - const RelationalSpecializer(); - - HType computeTypeFromInputTypes(HInvokeDynamic instruction, - HTypeMap types, - Compiler compiler) { - if (types[instruction.inputs[1]].isPrimitiveOrNull()) return HType.BOOLEAN; - return HType.UNKNOWN; - } - - HType computeDesiredTypeForInput(HInvokeDynamic instruction, - HInstruction input, - HTypeMap types, - Compiler compiler) { - if (input == instruction.inputs[0]) return HType.UNKNOWN; - HType propagatedType = types[instruction]; - // For all relational operations except HIdentity, we expect to get numbers - // only. With numbers the outgoing type is a boolean. If something else - // is desired, then numbers are incorrect, though. - if (propagatedType.isUnknown() || propagatedType.isBoolean()) { - HInstruction left = instruction.inputs[1]; - if (left.isTypeUnknown(types) || left.isNumber(types)) { - return HType.NUMBER; - } - } - return HType.UNKNOWN; - } - - HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, - HTypeMap types) { - HInstruction left = instruction.inputs[1]; - HInstruction right = instruction.inputs[2]; - if (left.isNumber(types) && right.isNumber(types)) { - return newBuiltinVariant(left, right); - } - return null; - } - - HInstruction newBuiltinVariant(HInstruction left, HInstruction right); -} - -class EqualsSpecializer extends RelationalSpecializer { - const EqualsSpecializer(); - - HType computeDesiredTypeForInput(HInvokeDynamic instruction, - HInstruction input, - HTypeMap types, - Compiler compiler) { - HInstruction left = instruction.inputs[1]; - HInstruction right = instruction.inputs[2]; - HType propagatedType = types[instruction]; - if (input == left && types[right].isUseful()) { - // All our useful types have 'identical' semantics. But we don't want to - // speculatively test for all possible types. Therefore we try to match - // the two types. That is, if we see x == 3, then we speculatively test - // if x is a number and bailout if it isn't. - // If right is a number we don't need more than a number (no need to match - // the exact type of right). - if (right.isNumber(types)) return HType.NUMBER; - return types[right]; - } - // String equality testing is much more common than array equality testing. - if (input == left && left.isIndexablePrimitive(types)) { - return HType.READABLE_ARRAY; - } - // String equality testing is much more common than array equality testing. - if (input == right && right.isIndexablePrimitive(types)) { - return HType.STRING; - } - return HType.UNKNOWN; - } - - HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, - HTypeMap types) { - HInstruction left = instruction.inputs[1]; - HInstruction right = instruction.inputs[2]; - if (types[left].isPrimitiveOrNull() || right.isConstantNull()) { - return newBuiltinVariant(left, right); - } - return null; - } - - BinaryOperation operation(ConstantSystem constantSystem) { - return constantSystem.equal; - } - - HInstruction newBuiltinVariant(HInstruction left, HInstruction right) { - return new HIdentity(left, right); - } -} - -class LessSpecializer extends RelationalSpecializer { - const LessSpecializer(); - - BinaryOperation operation(ConstantSystem constantSystem) { - return constantSystem.less; - } - - HInstruction newBuiltinVariant(HInstruction left, HInstruction right) { - return new HLess(left, right); - } -} - -class GreaterSpecializer extends RelationalSpecializer { - const GreaterSpecializer(); - - BinaryOperation operation(ConstantSystem constantSystem) { - return constantSystem.greater; - } - - HInstruction newBuiltinVariant(HInstruction left, HInstruction right) { - return new HGreater(left, right); - } -} - -class GreaterEqualSpecializer extends RelationalSpecializer { - const GreaterEqualSpecializer(); - - BinaryOperation operation(ConstantSystem constantSystem) { - return constantSystem.greaterEqual; - } - - HInstruction newBuiltinVariant(HInstruction left, HInstruction right) { - return new HGreaterEqual(left, right); - } -} - -class LessEqualSpecializer extends RelationalSpecializer { - const LessEqualSpecializer(); - - BinaryOperation operation(ConstantSystem constantSystem) { - return constantSystem.lessEqual; - } - - HInstruction newBuiltinVariant(HInstruction left, HInstruction right) { - return new HLessEqual(left, right); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/nodes.dart b/pkgs/markdown/test/lib/src/compiler/implementation/ssa/nodes.dart deleted file mode 100644 index afbd2e1..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/nodes.dart +++ /dev/null
@@ -1,2711 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of ssa; - -abstract class HVisitor<R> { - R visitAdd(HAdd node); - R visitBailoutTarget(HBailoutTarget node); - R visitBitAnd(HBitAnd node); - R visitBitNot(HBitNot node); - R visitBitOr(HBitOr node); - R visitBitXor(HBitXor node); - R visitBoolify(HBoolify node); - R visitBoundsCheck(HBoundsCheck node); - R visitBreak(HBreak node); - R visitConstant(HConstant node); - R visitContinue(HContinue node); - R visitDivide(HDivide node); - R visitExit(HExit node); - R visitExitTry(HExitTry node); - R visitFieldGet(HFieldGet node); - R visitFieldSet(HFieldSet node); - R visitForeign(HForeign node); - R visitForeignNew(HForeignNew node); - R visitGoto(HGoto node); - R visitGreater(HGreater node); - R visitGreaterEqual(HGreaterEqual node); - R visitIdentity(HIdentity node); - R visitIf(HIf node); - R visitIndex(HIndex node); - R visitIndexAssign(HIndexAssign node); - R visitIntegerCheck(HIntegerCheck node); - R visitInterceptor(HInterceptor node); - R visitInvokeClosure(HInvokeClosure node); - R visitInvokeDynamicGetter(HInvokeDynamicGetter node); - R visitInvokeDynamicMethod(HInvokeDynamicMethod node); - R visitInvokeDynamicSetter(HInvokeDynamicSetter node); - R visitInvokeStatic(HInvokeStatic node); - R visitInvokeSuper(HInvokeSuper node); - R visitIs(HIs node); - R visitLazyStatic(HLazyStatic node); - R visitLess(HLess node); - R visitLessEqual(HLessEqual node); - R visitLiteralList(HLiteralList node); - R visitLocalGet(HLocalGet node); - R visitLocalSet(HLocalSet node); - R visitLocalValue(HLocalValue node); - R visitLoopBranch(HLoopBranch node); - R visitMultiply(HMultiply node); - R visitNegate(HNegate node); - R visitNot(HNot node); - R visitOneShotInterceptor(HOneShotInterceptor); - R visitParameterValue(HParameterValue node); - R visitPhi(HPhi node); - R visitRangeConversion(HRangeConversion node); - R visitReturn(HReturn node); - R visitShiftLeft(HShiftLeft node); - R visitStatic(HStatic node); - R visitStaticStore(HStaticStore node); - R visitStringConcat(HStringConcat node); - R visitSubtract(HSubtract node); - R visitSwitch(HSwitch node); - R visitThis(HThis node); - R visitThrow(HThrow node); - R visitTry(HTry node); - R visitTypeGuard(HTypeGuard node); - R visitTypeConversion(HTypeConversion node); -} - -abstract class HGraphVisitor { - visitDominatorTree(HGraph graph) { - void visitBasicBlockAndSuccessors(HBasicBlock block) { - visitBasicBlock(block); - List dominated = block.dominatedBlocks; - for (int i = 0; i < dominated.length; i++) { - visitBasicBlockAndSuccessors(dominated[i]); - } - } - - visitBasicBlockAndSuccessors(graph.entry); - } - - visitPostDominatorTree(HGraph graph) { - void visitBasicBlockAndSuccessors(HBasicBlock block) { - List dominated = block.dominatedBlocks; - for (int i = dominated.length - 1; i >= 0; i--) { - visitBasicBlockAndSuccessors(dominated[i]); - } - visitBasicBlock(block); - } - - visitBasicBlockAndSuccessors(graph.entry); - } - - visitBasicBlock(HBasicBlock block); -} - -abstract class HInstructionVisitor extends HGraphVisitor { - HBasicBlock currentBlock; - - visitInstruction(HInstruction node); - - visitBasicBlock(HBasicBlock node) { - void visitInstructionList(HInstructionList list) { - HInstruction instruction = list.first; - while (instruction != null) { - visitInstruction(instruction); - instruction = instruction.next; - assert(instruction != list.first); - } - } - - currentBlock = node; - visitInstructionList(node); - } -} - -class HGraph { - HBasicBlock entry; - HBasicBlock exit; - HThis thisInstruction; - bool isRecursiveMethod = false; - bool calledInLoop = false; - final List<HBasicBlock> blocks; - - // We canonicalize all constants used within a graph so we do not - // have to worry about them for global value numbering. - Map<Constant, HConstant> constants; - - HGraph() - : blocks = new List<HBasicBlock>(), - constants = new Map<Constant, HConstant>() { - entry = addNewBlock(); - // The exit block will be added later, so it has an id that is - // after all others in the system. - exit = new HBasicBlock(); - } - - void addBlock(HBasicBlock block) { - int id = blocks.length; - block.id = id; - blocks.add(block); - assert(identical(blocks[id], block)); - } - - HBasicBlock addNewBlock() { - HBasicBlock result = new HBasicBlock(); - addBlock(result); - return result; - } - - HBasicBlock addNewLoopHeaderBlock(TargetElement target, - List<LabelElement> labels) { - HBasicBlock result = addNewBlock(); - result.loopInformation = - new HLoopInformation(result, target, labels); - return result; - } - - static HType mapConstantTypeToSsaType(Constant constant) { - if (constant.isNull()) return HType.NULL; - if (constant.isBool()) return HType.BOOLEAN; - if (constant.isInt()) return HType.INTEGER; - if (constant.isDouble()) return HType.DOUBLE; - if (constant.isString()) return HType.STRING; - if (constant.isList()) return HType.READABLE_ARRAY; - if (constant.isFunction()) return HType.UNKNOWN; - if (constant.isSentinel()) return HType.UNKNOWN; - ObjectConstant objectConstant = constant; - return new HBoundedType.exact(objectConstant.type); - } - - HConstant addConstant(Constant constant) { - HConstant result = constants[constant]; - if (result == null) { - HType type = mapConstantTypeToSsaType(constant); - result = new HConstant.internal(constant, type); - entry.addAtExit(result); - constants[constant] = result; - } else if (result.block == null) { - // The constant was not used anymore. - entry.addAtExit(result); - } - return result; - } - - HConstant addConstantInt(int i, ConstantSystem constantSystem) { - return addConstant(constantSystem.createInt(i)); - } - - HConstant addConstantDouble(double d, ConstantSystem constantSystem) { - return addConstant(constantSystem.createDouble(d)); - } - - HConstant addConstantString(DartString str, - Node diagnosticNode, - ConstantSystem constantSystem) { - return addConstant(constantSystem.createString(str, diagnosticNode)); - } - - HConstant addConstantBool(bool value, ConstantSystem constantSystem) { - return addConstant(constantSystem.createBool(value)); - } - - HConstant addConstantNull(ConstantSystem constantSystem) { - return addConstant(constantSystem.createNull()); - } - - void finalize() { - addBlock(exit); - exit.open(); - exit.close(new HExit()); - assignDominators(); - } - - void assignDominators() { - // Run through the blocks in order of increasing ids so we are - // guaranteed that we have computed dominators for all blocks - // higher up in the dominator tree. - for (int i = 0, length = blocks.length; i < length; i++) { - HBasicBlock block = blocks[i]; - List<HBasicBlock> predecessors = block.predecessors; - if (block.isLoopHeader()) { - block.assignCommonDominator(predecessors[0]); - } else { - for (int j = predecessors.length - 1; j >= 0; j--) { - block.assignCommonDominator(predecessors[j]); - } - } - } - } - - bool isValid() { - HValidator validator = new HValidator(); - validator.visitGraph(this); - return validator.isValid; - } -} - -class HBaseVisitor extends HGraphVisitor implements HVisitor { - HBasicBlock currentBlock; - - visitBasicBlock(HBasicBlock node) { - currentBlock = node; - - HInstruction instruction = node.first; - while (instruction != null) { - instruction.accept(this); - instruction = instruction.next; - } - } - - visitInstruction(HInstruction instruction) {} - - visitBinaryArithmetic(HBinaryArithmetic node) => visitInvokeBinary(node); - visitBinaryBitOp(HBinaryBitOp node) => visitBinaryArithmetic(node); - visitInvoke(HInvoke node) => visitInstruction(node); - visitInvokeBinary(HInvokeBinary node) => visitInstruction(node); - visitInvokeDynamic(HInvokeDynamic node) => visitInvoke(node); - visitInvokeDynamicField(HInvokeDynamicField node) => visitInvokeDynamic(node); - visitInvokeUnary(HInvokeUnary node) => visitInstruction(node); - visitConditionalBranch(HConditionalBranch node) => visitControlFlow(node); - visitControlFlow(HControlFlow node) => visitInstruction(node); - visitFieldAccess(HFieldAccess node) => visitInstruction(node); - visitRelational(HRelational node) => visitInvokeBinary(node); - - visitAdd(HAdd node) => visitBinaryArithmetic(node); - visitBailoutTarget(HBailoutTarget node) => visitInstruction(node); - visitBitAnd(HBitAnd node) => visitBinaryBitOp(node); - visitBitNot(HBitNot node) => visitInvokeUnary(node); - visitBitOr(HBitOr node) => visitBinaryBitOp(node); - visitBitXor(HBitXor node) => visitBinaryBitOp(node); - visitBoolify(HBoolify node) => visitInstruction(node); - visitBoundsCheck(HBoundsCheck node) => visitCheck(node); - visitBreak(HBreak node) => visitJump(node); - visitContinue(HContinue node) => visitJump(node); - visitCheck(HCheck node) => visitInstruction(node); - visitConstant(HConstant node) => visitInstruction(node); - visitDivide(HDivide node) => visitBinaryArithmetic(node); - visitExit(HExit node) => visitControlFlow(node); - visitExitTry(HExitTry node) => visitControlFlow(node); - visitFieldGet(HFieldGet node) => visitFieldAccess(node); - visitFieldSet(HFieldSet node) => visitFieldAccess(node); - visitForeign(HForeign node) => visitInstruction(node); - visitForeignNew(HForeignNew node) => visitForeign(node); - visitGoto(HGoto node) => visitControlFlow(node); - visitGreater(HGreater node) => visitRelational(node); - visitGreaterEqual(HGreaterEqual node) => visitRelational(node); - visitIdentity(HIdentity node) => visitRelational(node); - visitIf(HIf node) => visitConditionalBranch(node); - visitIndex(HIndex node) => visitInstruction(node); - visitIndexAssign(HIndexAssign node) => visitInstruction(node); - visitIntegerCheck(HIntegerCheck node) => visitCheck(node); - visitInterceptor(HInterceptor node) => visitInstruction(node); - visitInvokeClosure(HInvokeClosure node) - => visitInvokeDynamic(node); - visitInvokeDynamicMethod(HInvokeDynamicMethod node) - => visitInvokeDynamic(node); - visitInvokeDynamicGetter(HInvokeDynamicGetter node) - => visitInvokeDynamicField(node); - visitInvokeDynamicSetter(HInvokeDynamicSetter node) - => visitInvokeDynamicField(node); - visitInvokeStatic(HInvokeStatic node) => visitInvoke(node); - visitInvokeSuper(HInvokeSuper node) => visitInvoke(node); - visitJump(HJump node) => visitControlFlow(node); - visitLazyStatic(HLazyStatic node) => visitInstruction(node); - visitLess(HLess node) => visitRelational(node); - visitLessEqual(HLessEqual node) => visitRelational(node); - visitLiteralList(HLiteralList node) => visitInstruction(node); - visitLocalGet(HLocalGet node) => visitFieldAccess(node); - visitLocalSet(HLocalSet node) => visitFieldAccess(node); - visitLocalValue(HLocalValue node) => visitInstruction(node); - visitLoopBranch(HLoopBranch node) => visitConditionalBranch(node); - visitNegate(HNegate node) => visitInvokeUnary(node); - visitNot(HNot node) => visitInstruction(node); - visitOneShotInterceptor(HOneShotInterceptor node) - => visitInvokeDynamic(node); - visitPhi(HPhi node) => visitInstruction(node); - visitMultiply(HMultiply node) => visitBinaryArithmetic(node); - visitParameterValue(HParameterValue node) => visitLocalValue(node); - visitRangeConversion(HRangeConversion node) => visitCheck(node); - visitReturn(HReturn node) => visitControlFlow(node); - visitShiftLeft(HShiftLeft node) => visitBinaryBitOp(node); - visitSubtract(HSubtract node) => visitBinaryArithmetic(node); - visitSwitch(HSwitch node) => visitControlFlow(node); - visitStatic(HStatic node) => visitInstruction(node); - visitStaticStore(HStaticStore node) => visitInstruction(node); - visitStringConcat(HStringConcat node) => visitInstruction(node); - visitThis(HThis node) => visitParameterValue(node); - visitThrow(HThrow node) => visitControlFlow(node); - visitTry(HTry node) => visitControlFlow(node); - visitTypeGuard(HTypeGuard node) => visitCheck(node); - visitIs(HIs node) => visitInstruction(node); - visitTypeConversion(HTypeConversion node) => visitCheck(node); -} - -class SubGraph { - // The first and last block of the sub-graph. - final HBasicBlock start; - final HBasicBlock end; - - const SubGraph(this.start, this.end); - - bool contains(HBasicBlock block) { - assert(start != null); - assert(end != null); - assert(block != null); - return start.id <= block.id && block.id <= end.id; - } -} - -class SubExpression extends SubGraph { - const SubExpression(HBasicBlock start, HBasicBlock end) - : super(start, end); - - /** Find the condition expression if this sub-expression is a condition. */ - HInstruction get conditionExpression { - HInstruction last = end.last; - if (last is HConditionalBranch || last is HSwitch) return last.inputs[0]; - return null; - } -} - -class HInstructionList { - HInstruction first = null; - HInstruction last = null; - - bool get isEmpty { - return first == null; - } - - void internalAddAfter(HInstruction cursor, HInstruction instruction) { - if (cursor == null) { - assert(isEmpty); - first = last = instruction; - } else if (identical(cursor, last)) { - last.next = instruction; - instruction.previous = last; - last = instruction; - } else { - instruction.previous = cursor; - instruction.next = cursor.next; - cursor.next.previous = instruction; - cursor.next = instruction; - } - } - - void internalAddBefore(HInstruction cursor, HInstruction instruction) { - if (cursor == null) { - assert(isEmpty); - first = last = instruction; - } else if (identical(cursor, first)) { - first.previous = instruction; - instruction.next = first; - first = instruction; - } else { - instruction.next = cursor; - instruction.previous = cursor.previous; - cursor.previous.next = instruction; - cursor.previous = instruction; - } - } - - void detach(HInstruction instruction) { - assert(contains(instruction)); - assert(instruction.isInBasicBlock()); - if (instruction.previous == null) { - first = instruction.next; - } else { - instruction.previous.next = instruction.next; - } - if (instruction.next == null) { - last = instruction.previous; - } else { - instruction.next.previous = instruction.previous; - } - instruction.previous = null; - instruction.next = null; - } - - void remove(HInstruction instruction) { - assert(instruction.usedBy.isEmpty); - detach(instruction); - } - - /** Linear search for [instruction]. */ - bool contains(HInstruction instruction) { - HInstruction cursor = first; - while (cursor != null) { - if (identical(cursor, instruction)) return true; - cursor = cursor.next; - } - return false; - } -} - -class HBasicBlock extends HInstructionList { - // The [id] must be such that any successor's id is greater than - // this [id]. The exception are back-edges. - int id; - - static const int STATUS_NEW = 0; - static const int STATUS_OPEN = 1; - static const int STATUS_CLOSED = 2; - int status = STATUS_NEW; - - HInstructionList phis; - - HLoopInformation loopInformation = null; - HBlockFlow blockFlow = null; - HBasicBlock parentLoopHeader = null; - List<HBailoutTarget> bailoutTargets; - - final List<HBasicBlock> predecessors; - List<HBasicBlock> successors; - - HBasicBlock dominator = null; - final List<HBasicBlock> dominatedBlocks; - - HBasicBlock() : this.withId(null); - HBasicBlock.withId(this.id) - : phis = new HInstructionList(), - predecessors = <HBasicBlock>[], - successors = const <HBasicBlock>[], - dominatedBlocks = <HBasicBlock>[], - bailoutTargets = <HBailoutTarget>[]; - - int get hashCode => id; - - bool isNew() => status == STATUS_NEW; - bool isOpen() => status == STATUS_OPEN; - bool isClosed() => status == STATUS_CLOSED; - - bool isLoopHeader() { - return loopInformation != null; - } - - void setBlockFlow(HBlockInformation blockInfo, HBasicBlock continuation) { - blockFlow = new HBlockFlow(blockInfo, continuation); - } - - bool isLabeledBlock() => - blockFlow != null && - blockFlow.body is HLabeledBlockInformation; - - HBasicBlock get enclosingLoopHeader { - if (isLoopHeader()) return this; - return parentLoopHeader; - } - - bool hasBailoutTargets() => !bailoutTargets.isEmpty; - - void open() { - assert(isNew()); - status = STATUS_OPEN; - } - - void close(HControlFlow end) { - assert(isOpen()); - addAfter(last, end); - status = STATUS_CLOSED; - } - - void addAtEntry(HInstruction instruction) { - assert(instruction is !HPhi); - internalAddBefore(first, instruction); - instruction.notifyAddedToBlock(this); - } - - void addAtExit(HInstruction instruction) { - assert(isClosed()); - assert(last is HControlFlow); - assert(instruction is !HPhi); - internalAddBefore(last, instruction); - instruction.notifyAddedToBlock(this); - } - - void moveAtExit(HInstruction instruction) { - assert(instruction is !HPhi); - assert(instruction.isInBasicBlock()); - assert(isClosed()); - assert(last is HControlFlow); - internalAddBefore(last, instruction); - instruction.block = this; - assert(isValid()); - } - - void add(HInstruction instruction) { - assert(instruction is !HControlFlow); - assert(instruction is !HPhi); - internalAddAfter(last, instruction); - instruction.notifyAddedToBlock(this); - } - - void addPhi(HPhi phi) { - phis.internalAddAfter(phis.last, phi); - phi.notifyAddedToBlock(this); - } - - void removePhi(HPhi phi) { - phis.remove(phi); - assert(phi.block == this); - phi.notifyRemovedFromBlock(); - } - - void addAfter(HInstruction cursor, HInstruction instruction) { - assert(cursor is !HPhi); - assert(instruction is !HPhi); - assert(isOpen() || isClosed()); - internalAddAfter(cursor, instruction); - instruction.notifyAddedToBlock(this); - } - - void addBefore(HInstruction cursor, HInstruction instruction) { - assert(cursor is !HPhi); - assert(instruction is !HPhi); - assert(isOpen() || isClosed()); - internalAddBefore(cursor, instruction); - instruction.notifyAddedToBlock(this); - } - - void remove(HInstruction instruction) { - assert(isOpen() || isClosed()); - assert(instruction is !HPhi); - super.remove(instruction); - assert(instruction.block == this); - instruction.notifyRemovedFromBlock(); - } - - void addSuccessor(HBasicBlock block) { - if (successors.isEmpty) { - successors = [block]; - } else { - successors.add(block); - } - block.predecessors.add(this); - } - - void postProcessLoopHeader() { - assert(isLoopHeader()); - // Only the first entry into the loop is from outside the - // loop. All other entries must be back edges. - for (int i = 1, length = predecessors.length; i < length; i++) { - loopInformation.addBackEdge(predecessors[i]); - } - } - - /** - * Rewrites all uses of the [from] instruction to using the [to] - * instruction instead. - */ - void rewrite(HInstruction from, HInstruction to) { - for (HInstruction use in from.usedBy) { - use.rewriteInput(from, to); - } - to.usedBy.addAll(from.usedBy); - from.usedBy.clear(); - } - - /** - * Rewrites all uses of the [from] instruction to using either the - * [to] instruction, or a [HCheck] instruction that has better type - * information on [to], and that dominates the user. - */ - void rewriteWithBetterUser(HInstruction from, HInstruction to) { - Link<HCheck> better = const Link<HCheck>(); - for (HInstruction user in to.usedBy) { - if (user is HCheck && identical((user as HCheck).checkedInput, to)) { - better = better.prepend(user); - } - } - - if (better.isEmpty) return rewrite(from, to); - - L1: for (HInstruction user in from.usedBy) { - for (HCheck check in better) { - if (check.dominates(user)) { - user.rewriteInput(from, check); - check.usedBy.add(user); - continue L1; - } - } - user.rewriteInput(from, to); - to.usedBy.add(user); - } - from.usedBy.clear(); - } - - bool isExitBlock() { - return identical(first, last) && first is HExit; - } - - void addDominatedBlock(HBasicBlock block) { - assert(isClosed()); - assert(id != null && block.id != null); - assert(dominatedBlocks.indexOf(block) < 0); - // Keep the list of dominated blocks sorted such that if there are two - // succeeding blocks in the list, the predecessor is before the successor. - // Assume that we add the dominated blocks in the right order. - int index = dominatedBlocks.length; - while (index > 0 && dominatedBlocks[index - 1].id > block.id) { - index--; - } - if (index == dominatedBlocks.length) { - dominatedBlocks.add(block); - } else { - dominatedBlocks.insertRange(index, 1, block); - } - assert(block.dominator == null); - block.dominator = this; - } - - void removeDominatedBlock(HBasicBlock block) { - assert(isClosed()); - assert(id != null && block.id != null); - int index = dominatedBlocks.indexOf(block); - assert(index >= 0); - if (index == dominatedBlocks.length - 1) { - dominatedBlocks.removeLast(); - } else { - dominatedBlocks.removeRange(index, 1); - } - assert(identical(block.dominator, this)); - block.dominator = null; - } - - void assignCommonDominator(HBasicBlock predecessor) { - assert(isClosed()); - if (dominator == null) { - // If this basic block doesn't have a dominator yet we use the - // given predecessor as the dominator. - predecessor.addDominatedBlock(this); - } else if (predecessor.dominator != null) { - // If the predecessor has a dominator and this basic block has a - // dominator, we find a common parent in the dominator tree and - // use that as the dominator. - HBasicBlock block0 = dominator; - HBasicBlock block1 = predecessor; - while (!identical(block0, block1)) { - if (block0.id > block1.id) { - block0 = block0.dominator; - } else { - block1 = block1.dominator; - } - assert(block0 != null && block1 != null); - } - if (!identical(dominator, block0)) { - dominator.removeDominatedBlock(this); - block0.addDominatedBlock(this); - } - } - } - - void forEachPhi(void f(HPhi phi)) { - HPhi current = phis.first; - while (current != null) { - HInstruction saved = current.next; - f(current); - current = saved; - } - } - - void forEachInstruction(void f(HInstruction instruction)) { - HInstruction current = first; - while (current != null) { - HInstruction saved = current.next; - f(current); - current = saved; - } - } - - bool isValid() { - assert(isClosed()); - HValidator validator = new HValidator(); - validator.visitBasicBlock(this); - return validator.isValid; - } - - // TODO(ngeoffray): Cache the information if this method ends up - // being hot. - bool dominates(HBasicBlock other) { - do { - if (identical(this, other)) return true; - other = other.dominator; - } while (other != null && other.id >= id); - return false; - } -} - - -abstract class HInstruction implements Spannable { - Element sourceElement; - SourceFileLocation sourcePosition; - - final int id; - static int idCounter; - - final List<HInstruction> inputs; - final List<HInstruction> usedBy; - - HBasicBlock block; - HInstruction previous = null; - HInstruction next = null; - int flags = 0; - - // Changes flags. - static const int FLAG_CHANGES_INDEX = 0; - static const int FLAG_CHANGES_INSTANCE_PROPERTY = FLAG_CHANGES_INDEX + 1; - static const int FLAG_CHANGES_STATIC_PROPERTY - = FLAG_CHANGES_INSTANCE_PROPERTY + 1; - static const int FLAG_CHANGES_COUNT = FLAG_CHANGES_STATIC_PROPERTY + 1; - - // Depends flags (one for each changes flag). - static const int FLAG_DEPENDS_ON_INDEX_STORE = FLAG_CHANGES_COUNT; - static const int FLAG_DEPENDS_ON_INSTANCE_PROPERTY_STORE = - FLAG_DEPENDS_ON_INDEX_STORE + 1; - static const int FLAG_DEPENDS_ON_STATIC_PROPERTY_STORE = - FLAG_DEPENDS_ON_INSTANCE_PROPERTY_STORE + 1; - static const int FLAG_DEPENDS_ON_COUNT = - FLAG_DEPENDS_ON_STATIC_PROPERTY_STORE + 1; - - // Other flags. - static const int FLAG_USE_GVN = FLAG_DEPENDS_ON_COUNT; - - // Type codes. - static const int UNDEFINED_TYPECODE = -1; - static const int BOOLIFY_TYPECODE = 0; - static const int TYPE_GUARD_TYPECODE = 1; - static const int BOUNDS_CHECK_TYPECODE = 2; - static const int INTEGER_CHECK_TYPECODE = 3; - static const int INTERCEPTOR_TYPECODE = 4; - static const int ADD_TYPECODE = 5; - static const int DIVIDE_TYPECODE = 6; - static const int MULTIPLY_TYPECODE = 7; - static const int SUBTRACT_TYPECODE = 8; - static const int SHIFT_LEFT_TYPECODE = 9; - static const int BIT_OR_TYPECODE = 10; - static const int BIT_AND_TYPECODE = 11; - static const int BIT_XOR_TYPECODE = 12; - static const int NEGATE_TYPECODE = 13; - static const int BIT_NOT_TYPECODE = 14; - static const int NOT_TYPECODE = 15; - static const int IDENTITY_TYPECODE = 16; - static const int GREATER_TYPECODE = 17; - static const int GREATER_EQUAL_TYPECODE = 18; - static const int LESS_TYPECODE = 19; - static const int LESS_EQUAL_TYPECODE = 20; - static const int STATIC_TYPECODE = 21; - static const int STATIC_STORE_TYPECODE = 22; - static const int FIELD_GET_TYPECODE = 23; - static const int TYPE_CONVERSION_TYPECODE = 24; - static const int BAILOUT_TARGET_TYPECODE = 25; - static const int INVOKE_STATIC_TYPECODE = 26; - static const int INDEX_TYPECODE = 27; - static const int IS_TYPECODE = 28; - static const int INVOKE_DYNAMIC_TYPECODE = 29; - - HInstruction(this.inputs) : id = idCounter++, usedBy = <HInstruction>[]; - - int get hashCode => id; - - bool getFlag(int position) => (flags & (1 << position)) != 0; - void setFlag(int position) { flags |= (1 << position); } - void clearFlag(int position) { flags &= ~(1 << position); } - - static int computeDependsOnFlags(int flags) => flags << FLAG_CHANGES_COUNT; - - int getChangesFlags() => flags & ((1 << FLAG_CHANGES_COUNT) - 1); - int getDependsOnFlags() { - return (flags & ((1 << FLAG_DEPENDS_ON_COUNT) - 1)) >> FLAG_CHANGES_COUNT; - } - - bool hasSideEffects() => getChangesFlags() != 0; - bool dependsOnSomething() => getDependsOnFlags() != 0; - - void setAllSideEffects() { flags |= ((1 << FLAG_CHANGES_COUNT) - 1); } - void clearAllSideEffects() { flags &= ~((1 << FLAG_CHANGES_COUNT) - 1); } - - void setDependsOnSomething() { - int count = FLAG_DEPENDS_ON_COUNT - FLAG_CHANGES_COUNT; - flags |= (((1 << count) - 1) << FLAG_CHANGES_COUNT); - } - void clearAllDependencies() { - int count = FLAG_DEPENDS_ON_COUNT - FLAG_CHANGES_COUNT; - flags &= ~(((1 << count) - 1) << FLAG_CHANGES_COUNT); - } - - bool dependsOnStaticPropertyStore() { - return getFlag(FLAG_DEPENDS_ON_STATIC_PROPERTY_STORE); - } - void setDependsOnStaticPropertyStore() { - setFlag(FLAG_DEPENDS_ON_STATIC_PROPERTY_STORE); - } - void setChangesStaticProperty() { setFlag(FLAG_CHANGES_STATIC_PROPERTY); } - - bool dependsOnIndexStore() => getFlag(FLAG_DEPENDS_ON_INDEX_STORE); - void setDependsOnIndexStore() { setFlag(FLAG_DEPENDS_ON_INDEX_STORE); } - void setChangesIndex() { setFlag(FLAG_CHANGES_INDEX); } - - bool dependsOnInstancePropertyStore() { - return getFlag(FLAG_DEPENDS_ON_INSTANCE_PROPERTY_STORE); - } - void setDependsOnInstancePropertyStore() { - setFlag(FLAG_DEPENDS_ON_INSTANCE_PROPERTY_STORE); - } - void setChangesInstanceProperty() { setFlag(FLAG_CHANGES_INSTANCE_PROPERTY); } - - bool useGvn() => getFlag(FLAG_USE_GVN); - void setUseGvn() { setFlag(FLAG_USE_GVN); } - - void updateInput(int i, HInstruction insn) { - inputs[i] = insn; - } - - /** - * A pure instruction is an instruction that does not have any side - * effect, nor any dependency. They can be moved anywhere in the - * graph. - */ - bool isPure() => !hasSideEffects() && !dependsOnSomething() && !canThrow(); - - // Can this node throw an exception? - bool canThrow() => false; - - // Does this node potentially affect control flow. - bool isControlFlow() => false; - - // All isFunctions work on the propagated types. - bool isArray(HTypeMap types) => types[this].isArray(); - bool isReadableArray(HTypeMap types) => types[this].isReadableArray(); - bool isMutableArray(HTypeMap types) => types[this].isMutableArray(); - bool isExtendableArray(HTypeMap types) => types[this].isExtendableArray(); - bool isFixedArray(HTypeMap types) => types[this].isFixedArray(); - bool isBoolean(HTypeMap types) => types[this].isBoolean(); - bool isInteger(HTypeMap types) => types[this].isInteger(); - bool isDouble(HTypeMap types) => types[this].isDouble(); - bool isNumber(HTypeMap types) => types[this].isNumber(); - bool isNumberOrNull(HTypeMap types) => types[this].isNumberOrNull(); - bool isString(HTypeMap types) => types[this].isString(); - bool isTypeUnknown(HTypeMap types) => types[this].isUnknown(); - bool isIndexablePrimitive(HTypeMap types) - => types[this].isIndexablePrimitive(); - bool isPrimitive(HTypeMap types) => types[this].isPrimitive(); - bool canBePrimitive(HTypeMap types) => types[this].canBePrimitive(); - bool canBeNull(HTypeMap types) => types[this].canBeNull(); - - /** - * This is the type the instruction is guaranteed to have. It does not - * take any propagation into account. - */ - HType guaranteedType = HType.UNKNOWN; - bool hasGuaranteedType() => !guaranteedType.isUnknown(); - - /** - * Some instructions have a good idea of their return type, but cannot - * guarantee the type. The computed does not need to be more specialized - * than the provided type for [this]. - * - * Examples: the likely type of [:x == y:] is a boolean. In most cases this - * cannot be guaranteed, but when merging types we still want to use this - * information. - * - * Similarily the [HAdd] instruction is likely a number. Note that, even if - * the incoming type is already set to integer, the likely type might still - * just return the number type. - */ - HType computeLikelyType(HTypeMap types, Compiler compiler) => types[this]; - - /** - * Compute the type of the instruction by propagating the input types through - * the instruction. - * - * By default just copy the guaranteed type. - */ - HType computeTypeFromInputTypes(HTypeMap types, Compiler compiler) { - return guaranteedType; - } - - /** - * Compute the desired type for the the given [input]. Aside from using - * other inputs to compute the desired type one should also use - * the given [types] which, during the invocation of this method, - * represents the desired type of [this]. - */ - HType computeDesiredTypeForInput(HInstruction input, - HTypeMap types, - Compiler compiler) { - return HType.UNKNOWN; - } - - bool isInBasicBlock() => block != null; - - String inputsToString() { - void addAsCommaSeparated(StringBuffer buffer, List<HInstruction> list) { - for (int i = 0; i < list.length; i++) { - if (i != 0) buffer.add(', '); - buffer.add("@${list[i].id}"); - } - } - - StringBuffer buffer = new StringBuffer(); - buffer.add('('); - addAsCommaSeparated(buffer, inputs); - buffer.add(') - used at ['); - addAsCommaSeparated(buffer, usedBy); - buffer.add(']'); - return buffer.toString(); - } - - bool gvnEquals(HInstruction other) { - assert(useGvn() && other.useGvn()); - // Check that the type and the flags match. - bool hasSameType = typeEquals(other); - assert(hasSameType == (typeCode() == other.typeCode())); - if (!hasSameType) return false; - if (flags != other.flags) return false; - // Check that the inputs match. - final int inputsLength = inputs.length; - final List<HInstruction> otherInputs = other.inputs; - if (inputsLength != otherInputs.length) return false; - for (int i = 0; i < inputsLength; i++) { - if (!identical(inputs[i], otherInputs[i])) return false; - } - // Check that the data in the instruction matches. - return dataEquals(other); - } - - int gvnHashCode() { - int result = typeCode(); - int length = inputs.length; - for (int i = 0; i < length; i++) { - result = (result * 19) + (inputs[i].id) + (result >> 7); - } - return result; - } - - // These methods should be overwritten by instructions that - // participate in global value numbering. - int typeCode() => HInstruction.UNDEFINED_TYPECODE; - bool typeEquals(HInstruction other) => false; - bool dataEquals(HInstruction other) => false; - - accept(HVisitor visitor); - - void notifyAddedToBlock(HBasicBlock targetBlock) { - assert(!isInBasicBlock()); - assert(block == null); - // Add [this] to the inputs' uses. - for (int i = 0; i < inputs.length; i++) { - assert(inputs[i].isInBasicBlock()); - inputs[i].usedBy.add(this); - } - block = targetBlock; - assert(isValid()); - } - - void notifyRemovedFromBlock() { - assert(isInBasicBlock()); - assert(usedBy.isEmpty); - - // Remove [this] from the inputs' uses. - for (int i = 0; i < inputs.length; i++) { - inputs[i].removeUser(this); - } - this.block = null; - assert(isValid()); - } - - void rewriteInput(HInstruction from, HInstruction to) { - for (int i = 0; i < inputs.length; i++) { - if (identical(inputs[i], from)) inputs[i] = to; - } - } - - /** Removes all occurrences of [user] from [usedBy]. */ - void removeUser(HInstruction user) { - List<HInstruction> users = usedBy; - int length = users.length; - for (int i = 0; i < length; i++) { - if (identical(users[i], user)) { - users[i] = users[length - 1]; - length--; - } - } - users.length = length; - } - - // Change all uses of [oldInput] by [this] to [newInput]. Also - // updates the [usedBy] of [oldInput] and [newInput]. - void changeUse(HInstruction oldInput, HInstruction newInput) { - for (int i = 0; i < inputs.length; i++) { - if (identical(inputs[i], oldInput)) { - inputs[i] = newInput; - newInput.usedBy.add(this); - } - } - List<HInstruction> oldInputUsers = oldInput.usedBy; - int i = 0; - while (i < oldInputUsers.length) { - if (oldInputUsers[i] == this) { - oldInputUsers[i] = oldInputUsers[oldInput.usedBy.length - 1]; - oldInputUsers.length--; - } else { - i++; - } - } - } - - // Compute the set of users of this instruction that is dominated by - // [other]. If [other] is a user of [this], it is included in the - // returned set. - Set<HInstruction> dominatedUsers(HInstruction other) { - // Keep track of all instructions that we have to deal with later - // and count the number of them that are in the current block. - Set<HInstruction> users = new Set<HInstruction>(); - int usersInCurrentBlock = 0; - - // Run through all the users and see if they are dominated or - // potentially dominated by [other]. - HBasicBlock otherBlock = other.block; - for (int i = 0, length = usedBy.length; i < length; i++) { - HInstruction current = usedBy[i]; - if (otherBlock.dominates(current.block)) { - if (identical(current.block, otherBlock)) usersInCurrentBlock++; - users.add(current); - } - } - - // Run through all the phis in the same block as [other] and remove them - // from the users set. - if (usersInCurrentBlock > 0) { - for (HPhi phi = otherBlock.phis.first; phi != null; phi = phi.next) { - if (users.contains(phi)) { - users.remove(phi); - if (--usersInCurrentBlock == 0) break; - } - } - } - - // Run through all the instructions before [other] and remove them - // from the users set. - if (usersInCurrentBlock > 0) { - HInstruction current = otherBlock.first; - while (!identical(current, other)) { - if (users.contains(current)) { - users.remove(current); - if (--usersInCurrentBlock == 0) break; - } - current = current.next; - } - } - - return users; - } - - void moveBefore(HInstruction other) { - assert(this is !HControlFlow); - assert(this is !HPhi); - assert(other is !HPhi); - block.detach(this); - other.block.internalAddBefore(other, this); - block = other.block; - } - - bool isConstant() => false; - bool isConstantBoolean() => false; - bool isConstantNull() => false; - bool isConstantNumber() => false; - bool isConstantInteger() => false; - bool isConstantString() => false; - bool isConstantList() => false; - bool isConstantMap() => false; - bool isConstantFalse() => false; - bool isConstantTrue() => false; - bool isConstantSentinel() => false; - - bool isValid() { - HValidator validator = new HValidator(); - validator.currentBlock = block; - validator.visitInstruction(this); - return validator.isValid; - } - - /** - * The code for computing a bailout environment, and the code - * generation must agree on what does not need to be captured, - * so should always be generated at use site. - */ - bool isCodeMotionInvariant() => false; - - bool isJsStatement() => false; - - bool dominates(HInstruction other) { - // An instruction does not dominates itself. - if (this == other) return false; - if (block != other.block) return block.dominates(other.block); - - HInstruction current = this.next; - while (current != null) { - if (current == other) return true; - current = current.next; - } - return false; - } - - - HInstruction convertType(Compiler compiler, DartType type, int kind) { - if (type == null) return this; - if (identical(type.element, compiler.dynamicClass)) return this; - if (identical(type.element, compiler.objectClass)) return this; - - // If the original can't be null, type conversion also can't produce null. - bool canBeNull = this.guaranteedType.canBeNull(); - HType convertedType = - new HType.fromBoundedType(type, compiler, canBeNull); - - // No need to convert if we know the instruction has - // [convertedType] as a bound. - if (this.guaranteedType == convertedType) { - return this; - } - - return new HTypeConversion(convertedType, this, kind); - } - - /** - * Return whether the instructions do not belong to a loop or - * belong to the same loop. - */ - bool hasSameLoopHeaderAs(HInstruction other) { - return block.enclosingLoopHeader == other.block.enclosingLoopHeader; - } -} - -class HBoolify extends HInstruction { - HBoolify(HInstruction value) : super(<HInstruction>[value]) { - assert(!hasSideEffects()); - setUseGvn(); - } - - HType get guaranteedType => HType.BOOLEAN; - - accept(HVisitor visitor) => visitor.visitBoolify(this); - int typeCode() => HInstruction.BOOLIFY_TYPECODE; - bool typeEquals(other) => other is HBoolify; - bool dataEquals(HInstruction other) => true; -} - -/** - * A [HCheck] instruction is an instruction that might do a dynamic - * check at runtime on another instruction. To have proper instruction - * dependencies in the graph, instructions that depend on the check - * being done reference the [HCheck] instruction instead of the - * instruction itself. - */ -abstract class HCheck extends HInstruction { - HCheck(inputs) : super(inputs) { - assert(!hasSideEffects()); - setUseGvn(); - } - HInstruction get checkedInput => inputs[0]; - bool isJsStatement() => true; - bool canThrow() => true; -} - -class HBailoutTarget extends HInstruction { - final int state; - bool isEnabled = true; - // For each argument we record how many dummy (unused) arguments should - // precede it, to make sure it lands in the correctly named parameter in the - // bailout function. - List<int> padding; - HBailoutTarget(this.state) : super(<HInstruction>[]) { - assert(!hasSideEffects()); - setUseGvn(); - } - - bool isControlFlow() => isEnabled; - bool isJsStatement() => isEnabled; - - accept(HVisitor visitor) => visitor.visitBailoutTarget(this); - int typeCode() => HInstruction.BAILOUT_TARGET_TYPECODE; - bool typeEquals(other) => other is HBailoutTarget; - bool dataEquals(HBailoutTarget other) => other.state == state; -} - -class HTypeGuard extends HCheck { - final HType guardedType; - bool isEnabled = false; - - HTypeGuard(this.guardedType, HInstruction guarded, HInstruction bailoutTarget) - : super(<HInstruction>[guarded, bailoutTarget]); - - HInstruction get guarded => inputs[0]; - HInstruction get checkedInput => guarded; - HBailoutTarget get bailoutTarget => inputs[1]; - int get state => bailoutTarget.state; - - HType computeTypeFromInputTypes(HTypeMap types, Compiler compiler) { - return isEnabled ? guardedType : types[guarded]; - } - - HType get guaranteedType => isEnabled ? guardedType : HType.UNKNOWN; - - bool isControlFlow() => true; - bool isJsStatement() => isEnabled; - bool canThrow() => isEnabled; - - accept(HVisitor visitor) => visitor.visitTypeGuard(this); - int typeCode() => HInstruction.TYPE_GUARD_TYPECODE; - bool typeEquals(other) => other is HTypeGuard; - bool dataEquals(HTypeGuard other) => guardedType == other.guardedType; -} - -class HBoundsCheck extends HCheck { - static const int ALWAYS_FALSE = 0; - static const int FULL_CHECK = 1; - static const int ALWAYS_ABOVE_ZERO = 2; - static const int ALWAYS_BELOW_LENGTH = 3; - static const int ALWAYS_TRUE = 4; - /** - * Details which tests have been done statically during compilation. - * Default is that all checks must be performed dynamically. - */ - int staticChecks = FULL_CHECK; - - HBoundsCheck(length, index) : super(<HInstruction>[length, index]); - - HInstruction get length => inputs[1]; - HInstruction get index => inputs[0]; - bool isControlFlow() => true; - - HType get guaranteedType => HType.INTEGER; - - accept(HVisitor visitor) => visitor.visitBoundsCheck(this); - int typeCode() => HInstruction.BOUNDS_CHECK_TYPECODE; - bool typeEquals(other) => other is HBoundsCheck; - bool dataEquals(HInstruction other) => true; -} - -class HIntegerCheck extends HCheck { - bool alwaysFalse = false; - - HIntegerCheck(value) : super(<HInstruction>[value]); - - HInstruction get value => inputs[0]; - bool isControlFlow() => true; - - HType get guaranteedType => HType.INTEGER; - - HType computeDesiredTypeForInput(HInstruction input, - HTypeMap types, - Compiler compiler) { - // If the desired type of the input is already a number, we want - // to specialize it to an integer. - return input.isNumber(types) - ? HType.INTEGER - : super.computeDesiredTypeForInput(input, types, compiler); - } - - accept(HVisitor visitor) => visitor.visitIntegerCheck(this); - int typeCode() => HInstruction.INTEGER_CHECK_TYPECODE; - bool typeEquals(other) => other is HIntegerCheck; - bool dataEquals(HInstruction other) => true; -} - -abstract class HConditionalBranch extends HControlFlow { - HConditionalBranch(inputs) : super(inputs); - HInstruction get condition => inputs[0]; - HBasicBlock get trueBranch => block.successors[0]; - HBasicBlock get falseBranch => block.successors[1]; -} - -abstract class HControlFlow extends HInstruction { - HControlFlow(inputs) : super(inputs); - bool isControlFlow() => true; - bool isJsStatement() => true; -} - -abstract class HInvoke extends HInstruction { - /** - * The first argument must be the target: either an [HStatic] node, or - * the receiver of a method-call. The remaining inputs are the arguments - * to the invocation. - */ - HInvoke(List<HInstruction> inputs) : super(inputs) { - setAllSideEffects(); - setDependsOnSomething(); - } - static const int ARGUMENTS_OFFSET = 1; - bool canThrow() => true; -} - -abstract class HInvokeDynamic extends HInvoke { - final InvokeDynamicSpecializer specializer; - final Selector selector; - Element element; - - HInvokeDynamic(Selector selector, - this.element, - List<HInstruction> inputs, - [bool isIntercepted = false]) - : super(inputs), - this.selector = selector, - specializer = isIntercepted - ? InvokeDynamicSpecializer.lookupSpecializer(selector) - : const InvokeDynamicSpecializer(); - toString() => 'invoke dynamic: $selector'; - HInstruction get receiver => inputs[0]; - - bool get isInterceptorCall { - // We know it's a selector call if it follows the interceptor - // calling convention, which adds the actual receiver as a - // parameter to the call. - return inputs.length - 2 == selector.argumentCount; - } - - int typeCode() => HInstruction.INVOKE_DYNAMIC_TYPECODE; - bool typeEquals(other) => other is HInvokeDynamic; - bool dataEquals(HInvokeDynamic other) { - return selector == other.selector - && element == other.element; - } - - HType computeDesiredTypeForInput(HInstruction input, - HTypeMap types, - Compiler compiler) { - return specializer.computeDesiredTypeForInput(this, input, types, compiler); - } - - HType computeTypeFromInputTypes(HTypeMap types, Compiler compiler) { - return specializer.computeTypeFromInputTypes(this, types, compiler); - } -} - -class HInvokeClosure extends HInvokeDynamic { - HInvokeClosure(Selector selector, List<HInstruction> inputs) - : super(selector, null, inputs) { - assert(selector.isClosureCall()); - } - accept(HVisitor visitor) => visitor.visitInvokeClosure(this); -} - -class HInvokeDynamicMethod extends HInvokeDynamic { - HInvokeDynamicMethod(Selector selector, - List<HInstruction> inputs, - [bool isIntercepted = false]) - : super(selector, null, inputs, isIntercepted); - - String toString() => 'invoke dynamic method: $selector'; - accept(HVisitor visitor) => visitor.visitInvokeDynamicMethod(this); - - bool isIndexOperatorOnIndexablePrimitive(HTypeMap types) { - return isInterceptorCall - && selector.kind == SelectorKind.INDEX - && selector.name == const SourceString('[]') - && inputs[1].isIndexablePrimitive(types); - } -} - -abstract class HInvokeDynamicField extends HInvokeDynamic { - final bool isSideEffectFree; - HInvokeDynamicField( - Selector selector, Element element, List<HInstruction> inputs, - this.isSideEffectFree) - : super(selector, element, inputs); - toString() => 'invoke dynamic field: $selector'; -} - -class HInvokeDynamicGetter extends HInvokeDynamicField { - HInvokeDynamicGetter(selector, element, receiver, isSideEffectFree) - : super(selector, element, [receiver], isSideEffectFree) { - clearAllSideEffects(); - if (isSideEffectFree) { - setUseGvn(); - setDependsOnInstancePropertyStore(); - } else { - setDependsOnSomething(); - setAllSideEffects(); - } - } - toString() => 'invoke dynamic getter: $selector'; - accept(HVisitor visitor) => visitor.visitInvokeDynamicGetter(this); -} - -class HInvokeDynamicSetter extends HInvokeDynamicField { - HInvokeDynamicSetter(selector, element, receiver, value, isSideEffectFree) - : super(selector, element, [receiver, value], isSideEffectFree) { - clearAllSideEffects(); - if (isSideEffectFree) { - setChangesInstanceProperty(); - } else { - setAllSideEffects(); - setDependsOnSomething(); - } - } - toString() => 'invoke dynamic setter: $selector'; - accept(HVisitor visitor) => visitor.visitInvokeDynamicSetter(this); -} - -class HInvokeStatic extends HInvoke { - /** The first input must be the target. */ - HInvokeStatic(inputs, HType type) : super(inputs) { - guaranteedType = type; - } - - toString() => 'invoke static: ${element.name}'; - accept(HVisitor visitor) => visitor.visitInvokeStatic(this); - int typeCode() => HInstruction.INVOKE_STATIC_TYPECODE; - Element get element => target.element; - HStatic get target => inputs[0]; -} - -class HInvokeSuper extends HInvokeStatic { - final bool isSetter; - HInvokeSuper(inputs, {this.isSetter: false}) : super(inputs, HType.UNKNOWN); - toString() => 'invoke super: ${element.name}'; - accept(HVisitor visitor) => visitor.visitInvokeSuper(this); - - HInstruction get value { - assert(isSetter); - // Index 0: the element, index 1: 'this'. - return inputs[2]; - } -} - -abstract class HFieldAccess extends HInstruction { - final Element element; - - HFieldAccess(Element element, List<HInstruction> inputs) - : this.element = element, super(inputs); - - HInstruction get receiver => inputs[0]; -} - -class HFieldGet extends HFieldAccess { - final bool isAssignable; - - HFieldGet(Element element, HInstruction receiver, {bool isAssignable}) - : this.isAssignable = (isAssignable != null) - ? isAssignable - : element.isAssignable(), - super(element, <HInstruction>[receiver]) { - clearAllSideEffects(); - setUseGvn(); - if (this.isAssignable) { - setDependsOnInstancePropertyStore(); - } - } - - // TODO(ngeoffray): Only if input can be null. - bool canThrow() => true; - - accept(HVisitor visitor) => visitor.visitFieldGet(this); - - int typeCode() => HInstruction.FIELD_GET_TYPECODE; - bool typeEquals(other) => other is HFieldGet; - bool dataEquals(HFieldGet other) => element == other.element; - String toString() => "FieldGet $element"; -} - -class HFieldSet extends HFieldAccess { - HFieldSet(Element element, - HInstruction receiver, - HInstruction value) - : super(element, <HInstruction>[receiver, value]) { - clearAllSideEffects(); - setChangesInstanceProperty(); - } - - // TODO(ngeoffray): Only if input can be null. - bool canThrow() => true; - - HInstruction get value => inputs[1]; - accept(HVisitor visitor) => visitor.visitFieldSet(this); - - bool isJsStatement() => true; - String toString() => "FieldSet $element"; -} - -class HLocalGet extends HFieldAccess { - // No need to use GVN for a [HLocalGet], it is just a local - // access. - HLocalGet(Element element, HLocalValue local) - : super(element, <HInstruction>[local]); - - accept(HVisitor visitor) => visitor.visitLocalGet(this); - - HLocalValue get local => inputs[0]; -} - -class HLocalSet extends HFieldAccess { - HLocalSet(Element element, HLocalValue local, HInstruction value) - : super(element, <HInstruction>[local, value]); - - accept(HVisitor visitor) => visitor.visitLocalSet(this); - - HLocalValue get local => inputs[0]; - HInstruction get value => inputs[1]; - bool isJsStatement() => true; -} - -class HForeign extends HInstruction { - final DartString code; - final HType type; - final bool isStatement; - - HForeign(this.code, - this.type, - List<HInstruction> inputs, - {this.isStatement: false}) - : super(inputs) { - setAllSideEffects(); - setDependsOnSomething(); - } - - HForeign.statement(code, List<HInstruction> inputs) - : this(code, HType.UNKNOWN, inputs, isStatement: true); - - accept(HVisitor visitor) => visitor.visitForeign(this); - - HType get guaranteedType => type; - - bool isJsStatement() => isStatement; - bool canThrow() => true; -} - -class HForeignNew extends HForeign { - ClassElement element; - HForeignNew(this.element, HType type, List<HInstruction> inputs) - : super(const LiteralDartString("new"), type, inputs); - accept(HVisitor visitor) => visitor.visitForeignNew(this); -} - -abstract class HInvokeBinary extends HInstruction { - HInvokeBinary(HInstruction left, HInstruction right) - : super(<HInstruction>[left, right]) { - clearAllSideEffects(); - setUseGvn(); - } - - HInstruction get left => inputs[0]; - HInstruction get right => inputs[1]; - - BinaryOperation operation(ConstantSystem constantSystem); -} - -abstract class HBinaryArithmetic extends HInvokeBinary { - HBinaryArithmetic(HInstruction left, HInstruction right) : super(left, right); - - HType computeTypeFromInputTypes(HTypeMap types, Compiler compiler) { - if (left.isInteger(types) && right.isInteger(types)) return HType.INTEGER; - if (left.isDouble(types)) return HType.DOUBLE; - return HType.NUMBER; - } - - BinaryOperation operation(ConstantSystem constantSystem); -} - -class HAdd extends HBinaryArithmetic { - HAdd(HInstruction left, HInstruction right) : super(left, right); - accept(HVisitor visitor) => visitor.visitAdd(this); - - BinaryOperation operation(ConstantSystem constantSystem) - => constantSystem.add; - int typeCode() => HInstruction.ADD_TYPECODE; - bool typeEquals(other) => other is HAdd; - bool dataEquals(HInstruction other) => true; -} - -class HDivide extends HBinaryArithmetic { - HDivide(HInstruction left, HInstruction right) : super(left, right); - accept(HVisitor visitor) => visitor.visitDivide(this); - - HType get guaranteedType => HType.DOUBLE; - - BinaryOperation operation(ConstantSystem constantSystem) - => constantSystem.divide; - int typeCode() => HInstruction.DIVIDE_TYPECODE; - bool typeEquals(other) => other is HDivide; - bool dataEquals(HInstruction other) => true; -} - -class HMultiply extends HBinaryArithmetic { - HMultiply(HInstruction left, HInstruction right) : super(left, right); - accept(HVisitor visitor) => visitor.visitMultiply(this); - - BinaryOperation operation(ConstantSystem operations) - => operations.multiply; - int typeCode() => HInstruction.MULTIPLY_TYPECODE; - bool typeEquals(other) => other is HMultiply; - bool dataEquals(HInstruction other) => true; -} - -class HSubtract extends HBinaryArithmetic { - HSubtract(HInstruction left, HInstruction right) : super(left, right); - accept(HVisitor visitor) => visitor.visitSubtract(this); - - BinaryOperation operation(ConstantSystem constantSystem) - => constantSystem.subtract; - int typeCode() => HInstruction.SUBTRACT_TYPECODE; - bool typeEquals(other) => other is HSubtract; - bool dataEquals(HInstruction other) => true; -} - -/** - * An [HSwitch] instruction has one input for the incoming - * value, and one input per constant that it can switch on. - * Its block has one successor per constant, and one for the default. - */ -class HSwitch extends HControlFlow { - HSwitch(List<HInstruction> inputs) : super(inputs); - - HConstant constant(int index) => inputs[index + 1]; - HInstruction get expression => inputs[0]; - - /** - * Provides the target to jump to if none of the constants match - * the expression. If the switch had no default case, this is the - * following join-block. - */ - HBasicBlock get defaultTarget => block.successors.last; - - accept(HVisitor visitor) => visitor.visitSwitch(this); - - String toString() => "HSwitch cases = $inputs"; -} - -// TODO(floitsch): Should HBinaryArithmetic really be the super class of -// HBinaryBitOp? -abstract class HBinaryBitOp extends HBinaryArithmetic { - HBinaryBitOp(HInstruction left, HInstruction right) : super(left, right); - HType get guaranteedType => HType.INTEGER; -} - -class HShiftLeft extends HBinaryBitOp { - HShiftLeft(HInstruction left, HInstruction right) : super(left, right); - accept(HVisitor visitor) => visitor.visitShiftLeft(this); - - BinaryOperation operation(ConstantSystem constantSystem) - => constantSystem.shiftLeft; - int typeCode() => HInstruction.SHIFT_LEFT_TYPECODE; - bool typeEquals(other) => other is HShiftLeft; - bool dataEquals(HInstruction other) => true; -} - -class HBitOr extends HBinaryBitOp { - HBitOr(HInstruction left, HInstruction right) : super(left, right); - accept(HVisitor visitor) => visitor.visitBitOr(this); - - BinaryOperation operation(ConstantSystem constantSystem) - => constantSystem.bitOr; - int typeCode() => HInstruction.BIT_OR_TYPECODE; - bool typeEquals(other) => other is HBitOr; - bool dataEquals(HInstruction other) => true; -} - -class HBitAnd extends HBinaryBitOp { - HBitAnd(HInstruction left, HInstruction right) : super(left, right); - accept(HVisitor visitor) => visitor.visitBitAnd(this); - - BinaryOperation operation(ConstantSystem constantSystem) - => constantSystem.bitAnd; - int typeCode() => HInstruction.BIT_AND_TYPECODE; - bool typeEquals(other) => other is HBitAnd; - bool dataEquals(HInstruction other) => true; -} - -class HBitXor extends HBinaryBitOp { - HBitXor(HInstruction left, HInstruction right) : super(left, right); - accept(HVisitor visitor) => visitor.visitBitXor(this); - - BinaryOperation operation(ConstantSystem constantSystem) - => constantSystem.bitXor; - int typeCode() => HInstruction.BIT_XOR_TYPECODE; - bool typeEquals(other) => other is HBitXor; - bool dataEquals(HInstruction other) => true; -} - -abstract class HInvokeUnary extends HInstruction { - HInvokeUnary(HInstruction input) : super(<HInstruction>[input]) { - clearAllSideEffects(); - setUseGvn(); - } - - HInstruction get operand => inputs[0]; - - UnaryOperation operation(ConstantSystem constantSystem); -} - -class HNegate extends HInvokeUnary { - HNegate(HInstruction input) : super(input); - accept(HVisitor visitor) => visitor.visitNegate(this); - - HType computeTypeFromInputTypes(HTypeMap types, Compiler compiler) { - return types[operand]; - } - - UnaryOperation operation(ConstantSystem constantSystem) - => constantSystem.negate; - int typeCode() => HInstruction.NEGATE_TYPECODE; - bool typeEquals(other) => other is HNegate; - bool dataEquals(HInstruction other) => true; -} - -class HBitNot extends HInvokeUnary { - HBitNot(HInstruction input) : super(input); - accept(HVisitor visitor) => visitor.visitBitNot(this); - - HType get guaranteedType => HType.INTEGER; - UnaryOperation operation(ConstantSystem constantSystem) - => constantSystem.bitNot; - int typeCode() => HInstruction.BIT_NOT_TYPECODE; - bool typeEquals(other) => other is HBitNot; - bool dataEquals(HInstruction other) => true; -} - -class HExit extends HControlFlow { - HExit() : super(const <HInstruction>[]); - toString() => 'exit'; - accept(HVisitor visitor) => visitor.visitExit(this); -} - -class HGoto extends HControlFlow { - HGoto() : super(const <HInstruction>[]); - toString() => 'goto'; - accept(HVisitor visitor) => visitor.visitGoto(this); -} - -abstract class HJump extends HControlFlow { - final TargetElement target; - final LabelElement label; - HJump(this.target) : label = null, super(const <HInstruction>[]); - HJump.toLabel(LabelElement label) - : label = label, target = label.target, super(const <HInstruction>[]); -} - -class HBreak extends HJump { - HBreak(TargetElement target) : super(target); - HBreak.toLabel(LabelElement label) : super.toLabel(label); - toString() => (label != null) ? 'break ${label.labelName}' : 'break'; - accept(HVisitor visitor) => visitor.visitBreak(this); -} - -class HContinue extends HJump { - HContinue(TargetElement target) : super(target); - HContinue.toLabel(LabelElement label) : super.toLabel(label); - toString() => (label != null) ? 'continue ${label.labelName}' : 'continue'; - accept(HVisitor visitor) => visitor.visitContinue(this); -} - -class HTry extends HControlFlow { - HLocalValue exception; - HBasicBlock catchBlock; - HBasicBlock finallyBlock; - HTry() : super(const <HInstruction>[]); - toString() => 'try'; - accept(HVisitor visitor) => visitor.visitTry(this); - HBasicBlock get joinBlock => this.block.successors.last; -} - -// An [HExitTry] control flow node is used when the body of a try or -// the body of a catch contains a return, break or continue. To build -// the control flow graph, we explicitly mark the body that -// leads to one of this instruction a predecessor of catch and -// finally. -class HExitTry extends HControlFlow { - HExitTry() : super(const <HInstruction>[]); - toString() => 'exit try'; - accept(HVisitor visitor) => visitor.visitExitTry(this); - HBasicBlock get bodyTrySuccessor => block.successors[0]; -} - -class HIf extends HConditionalBranch { - HBlockFlow blockInformation = null; - HIf(HInstruction condition) : super(<HInstruction>[condition]); - toString() => 'if'; - accept(HVisitor visitor) => visitor.visitIf(this); - - HBasicBlock get thenBlock { - assert(identical(block.dominatedBlocks[0], block.successors[0])); - return block.successors[0]; - } - - HBasicBlock get elseBlock { - assert(identical(block.dominatedBlocks[1], block.successors[1])); - return block.successors[1]; - } - - HBasicBlock get joinBlock => blockInformation.continuation; -} - -class HLoopBranch extends HConditionalBranch { - static const int CONDITION_FIRST_LOOP = 0; - static const int DO_WHILE_LOOP = 1; - - final int kind; - HLoopBranch(HInstruction condition, [this.kind = CONDITION_FIRST_LOOP]) - : super(<HInstruction>[condition]); - toString() => 'loop-branch'; - accept(HVisitor visitor) => visitor.visitLoopBranch(this); - - bool isDoWhile() { - return identical(kind, DO_WHILE_LOOP); - } - - HBasicBlock computeLoopHeader() { - HBasicBlock result; - if (isDoWhile()) { - // In case of a do/while, the successor is a block that avoids - // a critical edge and branchs to the loop header. - result = block.successors[0].successors[0]; - } else { - // For other loops, the loop header might be up the dominator - // tree if the loop condition has control flow. - result = block; - while (!result.isLoopHeader()) result = result.dominator; - } - - assert(result.isLoopHeader()); - return result; - } -} - -class HConstant extends HInstruction { - final Constant constant; - final HType constantType; - HConstant.internal(this.constant, HType this.constantType) - : super(<HInstruction>[]); - - toString() => 'literal: $constant'; - accept(HVisitor visitor) => visitor.visitConstant(this); - - HType get guaranteedType => constantType; - - bool isConstant() => true; - bool isConstantBoolean() => constant.isBool(); - bool isConstantNull() => constant.isNull(); - bool isConstantNumber() => constant.isNum(); - bool isConstantInteger() => constant.isInt(); - bool isConstantString() => constant.isString(); - bool isConstantList() => constant.isList(); - bool isConstantMap() => constant.isMap(); - bool isConstantFalse() => constant.isFalse(); - bool isConstantTrue() => constant.isTrue(); - bool isConstantSentinel() => constant.isSentinel(); - - // Maybe avoid this if the literal is big? - bool isCodeMotionInvariant() => true; -} - -class HNot extends HInstruction { - HNot(HInstruction value) : super(<HInstruction>[value]) { - setUseGvn(); - } - - HType get guaranteedType => HType.BOOLEAN; - - // 'Not' only works on booleans. That's what we want as input. - HType computeDesiredTypeForInput(HInstruction input, - HTypeMap types, - Compiler compiler) { - return HType.BOOLEAN; - } - - accept(HVisitor visitor) => visitor.visitNot(this); - int typeCode() => HInstruction.NOT_TYPECODE; - bool typeEquals(other) => other is HNot; - bool dataEquals(HInstruction other) => true; -} - -/** - * An [HLocalValue] represents a local. Unlike [HParameterValue]s its - * first use must be in an HLocalSet. That is, [HParameterValue]s have a - * value from the start, whereas [HLocalValue]s need to be initialized first. - */ -class HLocalValue extends HInstruction { - HLocalValue(Element element) : super(<HInstruction>[]) { - sourceElement = element; - } - - toString() => 'local ${sourceElement.name}'; - accept(HVisitor visitor) => visitor.visitLocalValue(this); -} - -class HParameterValue extends HLocalValue { - HParameterValue(Element element) : super(element); - - toString() => 'parameter ${sourceElement.name.slowToString()}'; - accept(HVisitor visitor) => visitor.visitParameterValue(this); -} - -class HThis extends HParameterValue { - HThis(Element element, [HType type = HType.UNKNOWN]) : super(element) { - guaranteedType = type; - } - toString() => 'this'; - accept(HVisitor visitor) => visitor.visitThis(this); - bool isCodeMotionInvariant() => true; -} - -class HPhi extends HInstruction { - static const IS_NOT_LOGICAL_OPERATOR = 0; - static const IS_AND = 1; - static const IS_OR = 2; - - int logicalOperatorType = IS_NOT_LOGICAL_OPERATOR; - - // The order of the [inputs] must correspond to the order of the - // predecessor-edges. That is if an input comes from the first predecessor - // of the surrounding block, then the input must be the first in the [HPhi]. - HPhi(Element element, List<HInstruction> inputs) : super(inputs) { - sourceElement = element; - } - HPhi.noInputs(Element element) : this(element, <HInstruction>[]); - HPhi.singleInput(Element element, HInstruction input) - : this(element, <HInstruction>[input]); - HPhi.manyInputs(Element element, List<HInstruction> inputs) - : this(element, inputs); - - void addInput(HInstruction input) { - assert(isInBasicBlock()); - inputs.add(input); - input.usedBy.add(this); - } - - // Compute the (shared) type of the inputs if any. If all inputs - // have the same known type return it. If any two inputs have - // different known types, we'll return a conflict -- otherwise we'll - // simply return an unknown type. - HType computeInputsType(bool ignoreUnknowns, - HTypeMap types, - Compiler compiler) { - HType candidateType = HType.CONFLICTING; - for (int i = 0, length = inputs.length; i < length; i++) { - HType inputType = types[inputs[i]]; - if (ignoreUnknowns && inputType.isUnknown()) continue; - // Phis need to combine the incoming types using the union operation. - // For example, if one incoming edge has type integer and the other has - // type double, then the phi is either an integer or double and thus has - // type number. - candidateType = candidateType.union(inputType, compiler); - if (candidateType.isUnknown()) return HType.UNKNOWN; - } - return candidateType; - } - - HType computeTypeFromInputTypes(HTypeMap types, Compiler compiler) { - HType inputsType = computeInputsType(false, types, compiler); - if (inputsType.isConflicting()) return HType.UNKNOWN; - return inputsType; - } - - HType computeDesiredTypeForInput(HInstruction input, - HTypeMap types, - Compiler compiler) { - HType propagatedType = types[this]; - // Best case scenario for a phi is, when all inputs have the same type. If - // there is no desired outgoing type we therefore try to unify the input - // types (which is basically the [likelyType]). - if (propagatedType.isUnknown()) return computeLikelyType(types, compiler); - // When the desired outgoing type is conflicting we don't need to give any - // requirements on the inputs. - if (propagatedType.isConflicting()) return HType.UNKNOWN; - // Otherwise the input type must match the desired outgoing type. - return propagatedType; - } - - HType computeLikelyType(HTypeMap types, Compiler compiler) { - HType agreedType = computeInputsType(true, types, compiler); - if (agreedType.isConflicting()) return HType.UNKNOWN; - // Don't be too restrictive. If the agreed type is integer or double just - // say that the likely type is number. If more is expected the type will be - // propagated back. - if (agreedType.isNumber()) return HType.NUMBER; - return agreedType; - } - - bool isLogicalOperator() => logicalOperatorType != IS_NOT_LOGICAL_OPERATOR; - - String logicalOperator() { - assert(isLogicalOperator()); - if (logicalOperatorType == IS_AND) return "&&"; - assert(logicalOperatorType == IS_OR); - return "||"; - } - - toString() => 'phi'; - accept(HVisitor visitor) => visitor.visitPhi(this); -} - -abstract class HRelational extends HInvokeBinary { - bool usesBoolifiedInterceptor = false; - HRelational(HInstruction left, HInstruction right) : super(left, right); - HType get guaranteedType => HType.BOOLEAN; -} - -class HIdentity extends HRelational { - HIdentity(HInstruction left, HInstruction right) : super(left, right); - accept(HVisitor visitor) => visitor.visitIdentity(this); - - BinaryOperation operation(ConstantSystem constantSystem) - => constantSystem.identity; - int typeCode() => HInstruction.IDENTITY_TYPECODE; - bool typeEquals(other) => other is HIdentity; - bool dataEquals(HInstruction other) => true; -} - -class HGreater extends HRelational { - HGreater(HInstruction left, HInstruction right) : super(left, right); - accept(HVisitor visitor) => visitor.visitGreater(this); - - BinaryOperation operation(ConstantSystem constantSystem) - => constantSystem.greater; - int typeCode() => HInstruction.GREATER_TYPECODE; - bool typeEquals(other) => other is HGreater; - bool dataEquals(HInstruction other) => true; -} - -class HGreaterEqual extends HRelational { - HGreaterEqual(HInstruction left, HInstruction right) : super(left, right); - accept(HVisitor visitor) => visitor.visitGreaterEqual(this); - - BinaryOperation operation(ConstantSystem constantSystem) - => constantSystem.greaterEqual; - int typeCode() => HInstruction.GREATER_EQUAL_TYPECODE; - bool typeEquals(other) => other is HGreaterEqual; - bool dataEquals(HInstruction other) => true; -} - -class HLess extends HRelational { - HLess(HInstruction left, HInstruction right) : super(left, right); - accept(HVisitor visitor) => visitor.visitLess(this); - - BinaryOperation operation(ConstantSystem constantSystem) - => constantSystem.less; - int typeCode() => HInstruction.LESS_TYPECODE; - bool typeEquals(other) => other is HLess; - bool dataEquals(HInstruction other) => true; -} - -class HLessEqual extends HRelational { - HLessEqual(HInstruction left, HInstruction right) : super(left, right); - accept(HVisitor visitor) => visitor.visitLessEqual(this); - - BinaryOperation operation(ConstantSystem constantSystem) - => constantSystem.lessEqual; - int typeCode() => HInstruction.LESS_EQUAL_TYPECODE; - bool typeEquals(other) => other is HLessEqual; - bool dataEquals(HInstruction other) => true; -} - -class HReturn extends HControlFlow { - HReturn(value) : super(<HInstruction>[value]); - toString() => 'return'; - accept(HVisitor visitor) => visitor.visitReturn(this); -} - -class HThrow extends HControlFlow { - final bool isRethrow; - HThrow(value, {this.isRethrow: false}) : super(<HInstruction>[value]); - toString() => 'throw'; - accept(HVisitor visitor) => visitor.visitThrow(this); -} - -class HStatic extends HInstruction { - final Element element; - HStatic(this.element) : super(<HInstruction>[]) { - assert(element != null); - assert(invariant(this, element.isDeclaration)); - clearAllSideEffects(); - if (element.isAssignable()) { - setDependsOnStaticPropertyStore(); - } - setUseGvn(); - } - toString() => 'static ${element.name}'; - accept(HVisitor visitor) => visitor.visitStatic(this); - - int gvnHashCode() => super.gvnHashCode() ^ element.hashCode; - int typeCode() => HInstruction.STATIC_TYPECODE; - bool typeEquals(other) => other is HStatic; - bool dataEquals(HStatic other) => element == other.element; - bool isCodeMotionInvariant() => !element.isAssignable(); -} - -class HInterceptor extends HInstruction { - Set<ClassElement> interceptedClasses; - HInterceptor(this.interceptedClasses, HInstruction receiver) - : super(<HInstruction>[receiver]) { - clearAllSideEffects(); - setUseGvn(); - } - String toString() => 'interceptor on $interceptedClasses'; - accept(HVisitor visitor) => visitor.visitInterceptor(this); - HInstruction get receiver => inputs[0]; - - HType computeDesiredTypeForInput(HInstruction input, - HTypeMap types, - Compiler compiler) { - if (interceptedClasses.length != 1) return HType.UNKNOWN; - // If the only class being intercepted is of type number, we - // make this interceptor call say it wants that class as input. - Element interceptor = interceptedClasses.toList()[0]; - JavaScriptBackend backend = compiler.backend; - if (interceptor == backend.jsNumberClass) { - return HType.NUMBER; - } else if (interceptor == backend.jsIntClass) { - return HType.INTEGER; - } else if (interceptor == backend.jsDoubleClass) { - return HType.DOUBLE; - } - return HType.UNKNOWN; - } - - int typeCode() => HInstruction.INTERCEPTOR_TYPECODE; - bool typeEquals(other) => other is HInterceptor; - bool dataEquals(HInterceptor other) { - return interceptedClasses == other.interceptedClasses - || (interceptedClasses.length == other.interceptedClasses.length - && interceptedClasses.containsAll(other.interceptedClasses)); - } -} - -/** - * A "one-shot" interceptor is a call to a synthetized method that - * will fetch the interceptor of its first parameter, and make a call - * on a given selector with the remaining parameters. - * - * In order to share the same optimizations with regular interceptor - * calls, this class extends [HInvokeDynamic] and also has the null - * constant as the first input. - */ -class HOneShotInterceptor extends HInvokeDynamic { - Set<ClassElement> interceptedClasses; - HOneShotInterceptor(Selector selector, - List<HInstruction> inputs, - this.interceptedClasses) - : super(selector, null, inputs, true) { - assert(inputs[0] is HConstant); - assert(inputs[0].guaranteedType == HType.NULL); - } - - String toString() => 'one shot interceptor on $selector'; - accept(HVisitor visitor) => visitor.visitOneShotInterceptor(this); -} - -/** An [HLazyStatic] is a static that is initialized lazily at first read. */ -class HLazyStatic extends HInstruction { - final Element element; - HLazyStatic(this.element) : super(<HInstruction>[]) { - // TODO(4931): The first access has side-effects, but we afterwards we - // should be able to GVN. - setAllSideEffects(); - setDependsOnSomething(); - } - - toString() => 'lazy static ${element.name}'; - accept(HVisitor visitor) => visitor.visitLazyStatic(this); - - int typeCode() => 30; - // TODO(4931): can we do better here? - bool isCodeMotionInvariant() => false; - bool canThrow() => true; -} - -class HStaticStore extends HInstruction { - Element element; - HStaticStore(this.element, HInstruction value) - : super(<HInstruction>[value]) { - clearAllSideEffects(); - setChangesStaticProperty(); - } - toString() => 'static store ${element.name}'; - accept(HVisitor visitor) => visitor.visitStaticStore(this); - - int typeCode() => HInstruction.STATIC_STORE_TYPECODE; - bool typeEquals(other) => other is HStaticStore; - bool dataEquals(HStaticStore other) => element == other.element; - bool isJsStatement() => true; -} - -class HLiteralList extends HInstruction { - HLiteralList(inputs) : super(inputs); - toString() => 'literal list'; - accept(HVisitor visitor) => visitor.visitLiteralList(this); - - HType get guaranteedType => HType.EXTENDABLE_ARRAY; -} - -/** - * The primitive array indexing operation. Note that this instruction - * does not throw because we generate the checks explicitly. - */ -class HIndex extends HInstruction { - HIndex(HInstruction receiver, HInstruction index) - : super(<HInstruction>[receiver, index]) { - clearAllSideEffects(); - setDependsOnIndexStore(); - setUseGvn(); - } - - String toString() => 'index operator'; - accept(HVisitor visitor) => visitor.visitIndex(this); - - HInstruction get receiver => inputs[0]; - HInstruction get index => inputs[1]; - - int typeCode() => HInstruction.INDEX_TYPECODE; - bool typeEquals(HInstruction other) => other is HIndex; - bool dataEquals(HIndex other) => true; -} - -/** - * The primitive array assignment operation. Note that this instruction - * does not throw because we generate the checks explicitly. - */ -class HIndexAssign extends HInstruction { - HIndexAssign(HInstruction receiver, - HInstruction index, - HInstruction value) - : super(<HInstruction>[receiver, index, value]) { - clearAllSideEffects(); - setChangesIndex(); - } - String toString() => 'index assign operator'; - accept(HVisitor visitor) => visitor.visitIndexAssign(this); - - HInstruction get receiver => inputs[0]; - HInstruction get index => inputs[1]; - HInstruction get value => inputs[2]; -} - -class HIs extends HInstruction { - final DartType typeExpression; - final bool nullOk; - - HIs(this.typeExpression, List<HInstruction> inputs, {this.nullOk: false}) - : super(inputs) { - setUseGvn(); - } - - HInstruction get expression => inputs[0]; - HInstruction getCheck(int index) => inputs[index + 1]; - int get checkCount => inputs.length - 1; - - bool hasArgumentChecks() => inputs.length > 1; - - HType get guaranteedType => HType.BOOLEAN; - - accept(HVisitor visitor) => visitor.visitIs(this); - - toString() => "$expression is $typeExpression"; - - int typeCode() => HInstruction.IS_TYPECODE; - bool typeEquals(HInstruction other) => other is HIs; - bool dataEquals(HIs other) { - return typeExpression == other.typeExpression - && nullOk == other.nullOk; - } -} - -class HTypeConversion extends HCheck { - HType type; - final int kind; - - static const int NO_CHECK = 0; - static const int CHECKED_MODE_CHECK = 1; - static const int ARGUMENT_TYPE_CHECK = 2; - static const int CAST_TYPE_CHECK = 3; - static const int BOOLEAN_CONVERSION_CHECK = 4; - - HTypeConversion(this.type, HInstruction input, [this.kind = NO_CHECK]) - : super(<HInstruction>[input]) { - sourceElement = input.sourceElement; - } - HTypeConversion.checkedModeCheck(HType type, HInstruction input) - : this(type, input, CHECKED_MODE_CHECK); - HTypeConversion.argumentTypeCheck(HType type, HInstruction input) - : this(type, input, ARGUMENT_TYPE_CHECK); - HTypeConversion.castCheck(HType type, HInstruction input) - : this(type, input, CAST_TYPE_CHECK); - - - bool get isChecked => kind != NO_CHECK; - bool get isCheckedModeCheck { - return kind == CHECKED_MODE_CHECK || kind == BOOLEAN_CONVERSION_CHECK; - } - bool get isArgumentTypeCheck => kind == ARGUMENT_TYPE_CHECK; - bool get isCastTypeCheck => kind == CAST_TYPE_CHECK; - bool get isBooleanConversionCheck => kind == BOOLEAN_CONVERSION_CHECK; - - HType get guaranteedType => type; - - accept(HVisitor visitor) => visitor.visitTypeConversion(this); - - bool isJsStatement() => kind == ARGUMENT_TYPE_CHECK; - bool isControlFlow() => kind == ARGUMENT_TYPE_CHECK; - bool canThrow() => isChecked; - - int typeCode() => HInstruction.TYPE_CONVERSION_TYPECODE; - bool typeEquals(HInstruction other) => other is HTypeConversion; - bool dataEquals(HTypeConversion other) { - return type == other.type && kind == other.kind; - } -} - -class HRangeConversion extends HCheck { - HRangeConversion(HInstruction input) : super(<HInstruction>[input]) { - sourceElement = input.sourceElement; - } - accept(HVisitor visitor) => visitor.visitRangeConversion(this); - - // We currently only do range analysis for integers. - HType get guaranteedType => HType.INTEGER; -} - -class HStringConcat extends HInstruction { - final Node node; - HStringConcat(HInstruction left, HInstruction right, this.node) - : super(<HInstruction>[left, right]) { - setAllSideEffects(); - setDependsOnSomething(); - } - HType get guaranteedType => HType.STRING; - - HInstruction get left => inputs[0]; - HInstruction get right => inputs[1]; - - accept(HVisitor visitor) => visitor.visitStringConcat(this); - toString() => "string concat"; -} - -/** Non-block-based (aka. traditional) loop information. */ -class HLoopInformation { - final HBasicBlock header; - final List<HBasicBlock> blocks; - final List<HBasicBlock> backEdges; - final List<LabelElement> labels; - final TargetElement target; - - /** Corresponding block information for the loop. */ - HLoopBlockInformation loopBlockInformation; - - HLoopInformation(this.header, this.target, this.labels) - : blocks = new List<HBasicBlock>(), - backEdges = new List<HBasicBlock>(); - - void addBackEdge(HBasicBlock predecessor) { - backEdges.add(predecessor); - addBlock(predecessor); - } - - // Adds a block and transitively all its predecessors in the loop as - // loop blocks. - void addBlock(HBasicBlock block) { - if (identical(block, header)) return; - HBasicBlock parentHeader = block.parentLoopHeader; - if (identical(parentHeader, header)) { - // Nothing to do in this case. - } else if (parentHeader != null) { - addBlock(parentHeader); - } else { - block.parentLoopHeader = header; - blocks.add(block); - for (int i = 0, length = block.predecessors.length; i < length; i++) { - addBlock(block.predecessors[i]); - } - } - } - - HBasicBlock getLastBackEdge() { - int maxId = -1; - HBasicBlock result = null; - for (int i = 0, length = backEdges.length; i < length; i++) { - HBasicBlock current = backEdges[i]; - if (current.id > maxId) { - maxId = current.id; - result = current; - } - } - return result; - } -} - - -/** - * Embedding of a [HBlockInformation] for block-structure based traversal - * in a dominator based flow traversal by attaching it to a basic block. - * To go back to dominator-based traversal, a [HSubGraphBlockInformation] - * structure can be added in the block structure. - */ -class HBlockFlow { - final HBlockInformation body; - final HBasicBlock continuation; - HBlockFlow(this.body, this.continuation); -} - - -/** - * Information about a syntactic-like structure. - */ -abstract class HBlockInformation { - HBasicBlock get start; - HBasicBlock get end; - bool accept(HBlockInformationVisitor visitor); -} - - -/** - * Information about a statement-like structure. - */ -abstract class HStatementInformation extends HBlockInformation { - bool accept(HStatementInformationVisitor visitor); -} - - -/** - * Information about an expression-like structure. - */ -abstract class HExpressionInformation extends HBlockInformation { - bool accept(HExpressionInformationVisitor visitor); - HInstruction get conditionExpression; -} - - -abstract class HStatementInformationVisitor { - bool visitLabeledBlockInfo(HLabeledBlockInformation info); - bool visitLoopInfo(HLoopBlockInformation info); - bool visitIfInfo(HIfBlockInformation info); - bool visitTryInfo(HTryBlockInformation info); - bool visitSwitchInfo(HSwitchBlockInformation info); - bool visitSequenceInfo(HStatementSequenceInformation info); - // Pseudo-structure embedding a dominator-based traversal into - // the block-structure traversal. This will eventually go away. - bool visitSubGraphInfo(HSubGraphBlockInformation info); -} - - -abstract class HExpressionInformationVisitor { - bool visitAndOrInfo(HAndOrBlockInformation info); - bool visitSubExpressionInfo(HSubExpressionBlockInformation info); -} - - -abstract class HBlockInformationVisitor - implements HStatementInformationVisitor, HExpressionInformationVisitor { -} - - -/** - * Generic class wrapping a [SubGraph] as a block-information until - * all structures are handled properly. - */ -class HSubGraphBlockInformation implements HStatementInformation { - final SubGraph subGraph; - HSubGraphBlockInformation(this.subGraph); - - HBasicBlock get start => subGraph.start; - HBasicBlock get end => subGraph.end; - - bool accept(HStatementInformationVisitor visitor) => - visitor.visitSubGraphInfo(this); -} - - -/** - * Generic class wrapping a [SubExpression] as a block-information until - * expressions structures are handled properly. - */ -class HSubExpressionBlockInformation implements HExpressionInformation { - final SubExpression subExpression; - HSubExpressionBlockInformation(this.subExpression); - - HBasicBlock get start => subExpression.start; - HBasicBlock get end => subExpression.end; - - HInstruction get conditionExpression => subExpression.conditionExpression; - - bool accept(HExpressionInformationVisitor visitor) => - visitor.visitSubExpressionInfo(this); -} - - -/** A sequence of separate statements. */ -class HStatementSequenceInformation implements HStatementInformation { - final List<HStatementInformation> statements; - HStatementSequenceInformation(this.statements); - - HBasicBlock get start => statements[0].start; - HBasicBlock get end => statements.last.end; - - bool accept(HStatementInformationVisitor visitor) => - visitor.visitSequenceInfo(this); -} - - -class HLabeledBlockInformation implements HStatementInformation { - final HStatementInformation body; - final List<LabelElement> labels; - final TargetElement target; - final bool isContinue; - - HLabeledBlockInformation(this.body, - List<LabelElement> labels, - {this.isContinue: false}) : - this.labels = labels, this.target = labels[0].target; - - HLabeledBlockInformation.implicit(this.body, - this.target, - {this.isContinue: false}) - : this.labels = const<LabelElement>[]; - - HBasicBlock get start => body.start; - HBasicBlock get end => body.end; - - bool accept(HStatementInformationVisitor visitor) => - visitor.visitLabeledBlockInfo(this); -} - -class LoopTypeVisitor extends Visitor { - const LoopTypeVisitor(); - int visitNode(Node node) => HLoopBlockInformation.NOT_A_LOOP; - int visitWhile(While node) => HLoopBlockInformation.WHILE_LOOP; - int visitFor(For node) => HLoopBlockInformation.FOR_LOOP; - int visitDoWhile(DoWhile node) => HLoopBlockInformation.DO_WHILE_LOOP; - int visitForIn(ForIn node) => HLoopBlockInformation.FOR_IN_LOOP; -} - -class HLoopBlockInformation implements HStatementInformation { - static const int WHILE_LOOP = 0; - static const int FOR_LOOP = 1; - static const int DO_WHILE_LOOP = 2; - static const int FOR_IN_LOOP = 3; - static const int NOT_A_LOOP = -1; - - final int kind; - final HExpressionInformation initializer; - final HExpressionInformation condition; - final HStatementInformation body; - final HExpressionInformation updates; - final TargetElement target; - final List<LabelElement> labels; - final SourceFileLocation sourcePosition; - final SourceFileLocation endSourcePosition; - - HLoopBlockInformation(this.kind, - this.initializer, - this.condition, - this.body, - this.updates, - this.target, - this.labels, - this.sourcePosition, - this.endSourcePosition) { - assert( - (kind == DO_WHILE_LOOP ? body.start : condition.start).isLoopHeader()); - } - - HBasicBlock get start { - if (initializer != null) return initializer.start; - if (kind == DO_WHILE_LOOP) { - return body.start; - } - return condition.start; - } - - HBasicBlock get loopHeader { - return kind == DO_WHILE_LOOP ? body.start : condition.start; - } - - HBasicBlock get end { - if (updates != null) return updates.end; - if (kind == DO_WHILE_LOOP && condition != null) { - return condition.end; - } - return body.end; - } - - static int loopType(Node node) { - return node.accept(const LoopTypeVisitor()); - } - - bool isDoWhile() => kind == DO_WHILE_LOOP; - - bool accept(HStatementInformationVisitor visitor) => - visitor.visitLoopInfo(this); -} - -class HIfBlockInformation implements HStatementInformation { - final HExpressionInformation condition; - final HStatementInformation thenGraph; - final HStatementInformation elseGraph; - HIfBlockInformation(this.condition, - this.thenGraph, - this.elseGraph); - - HBasicBlock get start => condition.start; - HBasicBlock get end => elseGraph == null ? thenGraph.end : elseGraph.end; - - bool accept(HStatementInformationVisitor visitor) => - visitor.visitIfInfo(this); -} - -class HAndOrBlockInformation implements HExpressionInformation { - final bool isAnd; - final HExpressionInformation left; - final HExpressionInformation right; - HAndOrBlockInformation(this.isAnd, - this.left, - this.right); - - HBasicBlock get start => left.start; - HBasicBlock get end => right.end; - - // We don't currently use HAndOrBlockInformation. - HInstruction get conditionExpression { - return null; - } - bool accept(HExpressionInformationVisitor visitor) => - visitor.visitAndOrInfo(this); -} - -class HTryBlockInformation implements HStatementInformation { - final HStatementInformation body; - final HLocalValue catchVariable; - final HStatementInformation catchBlock; - final HStatementInformation finallyBlock; - HTryBlockInformation(this.body, - this.catchVariable, - this.catchBlock, - this.finallyBlock); - - HBasicBlock get start => body.start; - HBasicBlock get end => - finallyBlock == null ? catchBlock.end : finallyBlock.end; - - bool accept(HStatementInformationVisitor visitor) => - visitor.visitTryInfo(this); -} - - - -class HSwitchBlockInformation implements HStatementInformation { - final HExpressionInformation expression; - final List<List<Constant>> matchExpressions; - final List<HStatementInformation> statements; - // If the switch has a default, it's the last statement block, which - // may or may not have other expresions. - final bool hasDefault; - final TargetElement target; - final List<LabelElement> labels; - - HSwitchBlockInformation(this.expression, - this.matchExpressions, - this.statements, - this.hasDefault, - this.target, - this.labels); - - HBasicBlock get start => expression.start; - HBasicBlock get end { - // We don't create a switch block if there are no cases. - assert(!statements.isEmpty); - return statements.last.end; - } - - bool accept(HStatementInformationVisitor visitor) => - visitor.visitSwitchInfo(this); -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/optimize.dart b/pkgs/markdown/test/lib/src/compiler/implementation/ssa/optimize.dart deleted file mode 100644 index 35ba2cb..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/optimize.dart +++ /dev/null
@@ -1,1545 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of ssa; - -abstract class OptimizationPhase { - String get name; - void visitGraph(HGraph graph); -} - -class SsaOptimizerTask extends CompilerTask { - final JavaScriptBackend backend; - SsaOptimizerTask(JavaScriptBackend backend) - : this.backend = backend, - super(backend.compiler); - String get name => 'SSA optimizer'; - Compiler get compiler => backend.compiler; - - void runPhases(HGraph graph, List<OptimizationPhase> phases) { - for (OptimizationPhase phase in phases) { - runPhase(graph, phase); - } - } - - void runPhase(HGraph graph, OptimizationPhase phase) { - phase.visitGraph(graph); - compiler.tracer.traceGraph(phase.name, graph); - assert(graph.isValid()); - } - - void optimize(CodegenWorkItem work, HGraph graph, bool speculative) { - ConstantSystem constantSystem = compiler.backend.constantSystem; - JavaScriptItemCompilationContext context = work.compilationContext; - HTypeMap types = context.types; - measure(() { - List<OptimizationPhase> phases = <OptimizationPhase>[ - // Run trivial constant folding first to optimize - // some patterns useful for type conversion. - new SsaConstantFolder(constantSystem, backend, work, types), - new SsaTypeConversionInserter(compiler), - new SsaTypePropagator(compiler, types), - new SsaConstantFolder(constantSystem, backend, work, types), - // The constant folder affects the types of instructions, so - // we run the type propagator again. Note that this would - // not be necessary if types were directly stored on - // instructions. - new SsaTypePropagator(compiler, types), - new SsaCheckInserter(backend, work, types, context.boundsChecked), - new SsaRedundantPhiEliminator(), - new SsaDeadPhiEliminator(), - new SsaConstantFolder(constantSystem, backend, work, types), - new SsaTypePropagator(compiler, types), - new SsaReceiverSpecialization(compiler), - new SsaGlobalValueNumberer(compiler, types), - new SsaCodeMotion(), - new SsaValueRangeAnalyzer(constantSystem, types, work), - // Previous optimizations may have generated new - // opportunities for constant folding. - new SsaConstantFolder(constantSystem, backend, work, types), - new SsaSimplifyInterceptors(constantSystem), - new SsaDeadCodeEliminator(types)]; - runPhases(graph, phases); - if (!speculative) { - runPhase(graph, new SsaConstructionFieldTypes(backend, work, types)); - } - }); - } - - bool trySpeculativeOptimizations(CodegenWorkItem work, HGraph graph) { - if (work.element.isField()) { - // Lazy initializers may not have bailout methods. - return false; - } - JavaScriptItemCompilationContext context = work.compilationContext; - HTypeMap types = context.types; - return measure(() { - // Run the phases that will generate type guards. - List<OptimizationPhase> phases = <OptimizationPhase>[ - new SsaSpeculativeTypePropagator(compiler, types), - new SsaTypeGuardInserter(compiler, work, types), - new SsaEnvironmentBuilder(compiler), - // Change the propagated types back to what they were before we - // speculatively propagated, so that we can generate the bailout - // version. - // Note that we do this even if there were no guards inserted. If a - // guard is not beneficial enough we don't emit one, but there might - // still be speculative types on the instructions. - new SsaTypePropagator(compiler, types), - // Then run the [SsaCheckInserter] because the type propagator also - // propagated types non-speculatively. For example, it might have - // propagated the type array for a call to the List constructor. - new SsaCheckInserter(backend, work, types, context.boundsChecked)]; - runPhases(graph, phases); - return !work.guards.isEmpty; - }); - } - - void prepareForSpeculativeOptimizations(CodegenWorkItem work, HGraph graph) { - JavaScriptItemCompilationContext context = work.compilationContext; - HTypeMap types = context.types; - measure(() { - // In order to generate correct code for the bailout version, we did not - // propagate types from the instruction to the type guard. We do it - // now to be able to optimize further. - work.guards.forEach((HTypeGuard guard) { - guard.bailoutTarget.isEnabled = false; - guard.isEnabled = true; - }); - // We also need to insert range and integer checks for the type - // guards. Now that they claim to have a certain type, some - // depending instructions might become builtin (like native array - // accesses) and need to be checked. - // Also run the type propagator, to please the codegen in case - // no other optimization is run. - runPhases(graph, <OptimizationPhase>[ - new SsaCheckInserter(backend, work, types, context.boundsChecked), - new SsaTypePropagator(compiler, types)]); - }); - } -} - -/** - * If both inputs to known operations are available execute the operation at - * compile-time. - */ -class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { - final String name = "SsaConstantFolder"; - final JavaScriptBackend backend; - final CodegenWorkItem work; - final ConstantSystem constantSystem; - final HTypeMap types; - HGraph graph; - Compiler get compiler => backend.compiler; - - SsaConstantFolder(this.constantSystem, this.backend, this.work, this.types); - - void visitGraph(HGraph visitee) { - graph = visitee; - visitDominatorTree(visitee); - } - - visitBasicBlock(HBasicBlock block) { - HInstruction instruction = block.first; - while (instruction != null) { - HInstruction next = instruction.next; - HInstruction replacement = instruction.accept(this); - if (replacement != instruction) { - block.rewrite(instruction, replacement); - - // If we can replace [instruction] with [replacement], then - // [replacement]'s type can be narrowed. - types[replacement] = - types[replacement].intersection(types[instruction], compiler); - - // If the replacement instruction does not know its - // source element, use the source element of the - // instruction. - if (replacement.sourceElement == null) { - replacement.sourceElement = instruction.sourceElement; - } - if (replacement.sourcePosition == null) { - replacement.sourcePosition = instruction.sourcePosition; - } - if (!replacement.isInBasicBlock()) { - // The constant folding can return an instruction that is already - // part of the graph (like an input), so we only add the replacement - // if necessary. - block.addAfter(instruction, replacement); - // Visit the replacement as the next instruction in case it - // can also be constant folded away. - next = replacement; - } - block.remove(instruction); - } - instruction = next; - } - } - - HInstruction visitInstruction(HInstruction node) { - return node; - } - - HInstruction visitBoolify(HBoolify node) { - List<HInstruction> inputs = node.inputs; - assert(inputs.length == 1); - HInstruction input = inputs[0]; - HType type = types[input]; - if (type.isBoolean()) return input; - // All values !== true are boolified to false. - if (!type.isBooleanOrNull() && !type.isUnknown()) { - return graph.addConstantBool(false, constantSystem); - } - return node; - } - - HInstruction visitNot(HNot node) { - List<HInstruction> inputs = node.inputs; - assert(inputs.length == 1); - HInstruction input = inputs[0]; - if (input is HConstant) { - HConstant constant = input; - bool isTrue = constant.constant.isTrue(); - return graph.addConstantBool(!isTrue, constantSystem); - } else if (input is HNot) { - return input.inputs[0]; - } - return node; - } - - HInstruction visitInvokeUnary(HInvokeUnary node) { - HInstruction folded = - foldUnary(node.operation(constantSystem), node.operand); - return folded != null ? folded : node; - } - - HInstruction foldUnary(UnaryOperation operation, HInstruction operand) { - if (operand is HConstant) { - HConstant receiver = operand; - Constant folded = operation.fold(receiver.constant); - if (folded != null) return graph.addConstant(folded); - } - return null; - } - - HInstruction optimizeLengthInterceptedGetter(HInvokeDynamic node) { - HInstruction actualReceiver = node.inputs[1]; - if (actualReceiver.isIndexablePrimitive(types)) { - if (actualReceiver.isConstantString()) { - HConstant constantInput = actualReceiver; - StringConstant constant = constantInput.constant; - return graph.addConstantInt(constant.length, constantSystem); - } else if (actualReceiver.isConstantList()) { - HConstant constantInput = actualReceiver; - ListConstant constant = constantInput.constant; - return graph.addConstantInt(constant.length, constantSystem); - } - Element element; - bool isAssignable; - if (actualReceiver.isString(types)) { - element = backend.jsStringLength; - isAssignable = false; - } else { - element = backend.jsArrayLength; - isAssignable = !actualReceiver.isFixedArray(types); - } - HFieldGet result = new HFieldGet( - element, actualReceiver, isAssignable: isAssignable); - result.guaranteedType = HType.INTEGER; - types[result] = HType.INTEGER; - return result; - } else if (actualReceiver.isConstantMap()) { - HConstant constantInput = actualReceiver; - MapConstant constant = constantInput.constant; - return graph.addConstantInt(constant.length, constantSystem); - } - return node; - } - - HInstruction handleInterceptorCall(HInvokeDynamic node) { - // We only optimize for intercepted method calls in this method. - Selector selector = node.selector; - - // Try constant folding the instruction. - Operation operation = node.specializer.operation(constantSystem); - if (operation != null) { - HInstruction instruction = node.inputs.length == 2 - ? foldUnary(operation, node.inputs[1]) - : foldBinary(operation, node.inputs[1], node.inputs[2]); - if (instruction != null) return instruction; - } - - // Try converting the instruction to a builtin instruction. - HInstruction instruction = - node.specializer.tryConvertToBuiltin(node, types); - if (instruction != null) return instruction; - - // Check if this call does not need to be intercepted. - HInstruction input = node.inputs[1]; - HType type = types[input]; - var interceptor = node.inputs[0]; - - if (interceptor.isConstant() && selector.isCall()) { - DartType type = types[interceptor].computeType(compiler); - ClassElement cls = type.element; - node.element = cls.lookupSelector(selector); - } - - if (interceptor is !HThis && !type.canBePrimitive()) { - // If the type can be null, and the intercepted method can be in - // the object class, keep the interceptor. - if (type.canBeNull()) { - Set<ClassElement> interceptedClasses; - if (interceptor is HInterceptor) { - interceptedClasses = interceptor.interceptedClasses; - } else if (node is HOneShotInterceptor) { - var oneShotInterceptor = node; - interceptedClasses = oneShotInterceptor.interceptedClasses; - } - if (interceptedClasses.contains(compiler.objectClass)) return node; - } - if (selector.isGetter()) { - // Change the call to a regular invoke dynamic call. - return new HInvokeDynamicGetter(selector, null, input, false); - } else if (selector.isSetter()) { - return new HInvokeDynamicSetter( - selector, null, input, node.inputs[2], false); - } else { - // Change the call to a regular invoke dynamic call. - return new HInvokeDynamicMethod( - selector, node.inputs.getRange(1, node.inputs.length - 1)); - } - } - - if (selector.isCall()) { - Element target; - if (input.isExtendableArray(types)) { - if (selector.applies(backend.jsArrayRemoveLast, compiler)) { - target = backend.jsArrayRemoveLast; - } else if (selector.applies(backend.jsArrayAdd, compiler)) { - // The codegen special cases array calls, but does not - // inline argument type checks. - if (!compiler.enableTypeAssertions) { - target = backend.jsArrayAdd; - } - } - } else if (input.isString(types)) { - if (selector.applies(backend.jsStringSplit, compiler)) { - if (node.inputs[2].isString(types)) { - target = backend.jsStringSplit; - } - } else if (selector.applies(backend.jsStringConcat, compiler)) { - if (node.inputs[2].isString(types)) { - target = backend.jsStringConcat; - } - } else if (selector.applies(backend.jsStringToString, compiler)) { - return input; - } - } - if (target != null) { - // TODO(ngeoffray): There is a strong dependency between codegen - // and this optimization that the dynamic invoke does not need an - // interceptor. We currently need to keep a - // HInvokeDynamicMethod and not create a HForeign because - // HForeign is too opaque for the SssaCheckInserter (that adds a - // bounds check on removeLast). Once we start inlining, the - // bounds check will become explicit, so we won't need this - // optimization. - HInvokeDynamicMethod result = new HInvokeDynamicMethod( - node.selector, node.inputs.getRange(1, node.inputs.length - 1)); - result.element = target; - return result; - } - } else if (selector.isGetter()) { - if (selector.applies(backend.jsArrayLength, compiler)) { - return optimizeLengthInterceptedGetter(node); - } - } - return node; - } - - bool isFixedSizeListConstructor(HInvokeStatic node) { - Element element = node.target.element; - if (backend.fixedLengthListConstructor == null) { - backend.fixedLengthListConstructor = - compiler.listClass.lookupConstructor( - new Selector.callConstructor(const SourceString("fixedLength"), - compiler.listClass.getLibrary())); - } - // TODO(ngeoffray): checking if the second input is an integer - // should not be necessary but it currently makes it easier for - // other optimizations to reason on a fixed length constructor - // that we know takes an int. - return element == backend.fixedLengthListConstructor - && node.inputs[1].isInteger(types); - } - - HInstruction visitInvokeStatic(HInvokeStatic node) { - if (isFixedSizeListConstructor(node)) { - node.guaranteedType = HType.FIXED_ARRAY; - } - return node; - } - - HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) { - if (node.isInterceptorCall) return handleInterceptorCall(node); - HType receiverType = types[node.receiver]; - if (receiverType.isExact()) { - HBoundedType type = receiverType; - Element element = type.lookupMember(node.selector.name); - // TODO(ngeoffray): Also fold if it's a getter or variable. - if (element != null && element.isFunction()) { - if (node.selector.applies(element, compiler)) { - FunctionElement method = element; - FunctionSignature parameters = method.computeSignature(compiler); - if (parameters.optionalParameterCount == 0) { - node.element = element; - } - // TODO(ngeoffray): If the method has optional parameters, - // we should pass the default values here. - } - } - } - return node; - } - - HInstruction visitIntegerCheck(HIntegerCheck node) { - HInstruction value = node.value; - if (value.isInteger(types)) return value; - if (value.isConstant()) { - HConstant constantInstruction = value; - assert(!constantInstruction.constant.isInt()); - if (!constantSystem.isInt(constantInstruction.constant)) { - // -0.0 is a double but will pass the runtime integer check. - node.alwaysFalse = true; - } - } - return node; - } - - HInstruction foldBinary(BinaryOperation operation, - HInstruction left, - HInstruction right) { - if (left is HConstant && right is HConstant) { - HConstant op1 = left; - HConstant op2 = right; - Constant folded = operation.fold(op1.constant, op2.constant); - if (folded != null) return graph.addConstant(folded); - } - return null; - } - - HInstruction visitInvokeBinary(HInvokeBinary node) { - HInstruction left = node.left; - HInstruction right = node.right; - BinaryOperation operation = node.operation(constantSystem); - HConstant folded = foldBinary(operation, left, right); - if (folded != null) return folded; - return node; - } - - bool allUsersAreBoolifies(HInstruction instruction) { - List<HInstruction> users = instruction.usedBy; - int length = users.length; - for (int i = 0; i < length; i++) { - if (users[i] is! HBoolify) return false; - } - return true; - } - - HInstruction visitRelational(HRelational node) { - if (allUsersAreBoolifies(node)) { - // TODO(ngeoffray): Call a boolified selector. - // This node stays the same, but the Boolify node will go away. - } - // Note that we still have to call [super] to make sure that we end up - // in the remaining optimizations. - return super.visitRelational(node); - } - - HInstruction handleIdentityCheck(HRelational node) { - HInstruction left = node.left; - HInstruction right = node.right; - HType leftType = types[left]; - HType rightType = types[right]; - - // We don't optimize on numbers to preserve the runtime semantics. - if (!(left.isNumberOrNull(types) && right.isNumberOrNull(types)) && - leftType.intersection(rightType, compiler).isConflicting()) { - return graph.addConstantBool(false, constantSystem); - } - - if (left.isConstantBoolean() && right.isBoolean(types)) { - HConstant constant = left; - if (constant.constant.isTrue()) { - return right; - } else { - return new HNot(right); - } - } - - if (right.isConstantBoolean() && left.isBoolean(types)) { - HConstant constant = right; - if (constant.constant.isTrue()) { - return left; - } else { - return new HNot(left); - } - } - - return null; - } - - HInstruction visitIdentity(HIdentity node) { - HInstruction newInstruction = handleIdentityCheck(node); - return newInstruction == null ? super.visitIdentity(node) : newInstruction; - } - - HInstruction visitTypeGuard(HTypeGuard node) { - HInstruction value = node.guarded; - // If the intersection of the types is still the incoming type then - // the incoming type was a subtype of the guarded type, and no check - // is required. - HType combinedType = types[value].intersection(node.guardedType, compiler); - return (combinedType == types[value]) ? value : node; - } - - HInstruction visitIs(HIs node) { - DartType type = node.typeExpression; - Element element = type.element; - if (element.isTypeVariable()) { - compiler.unimplemented("visitIs for type variables"); - } if (element.isTypedef()) { - return node; - } - - HType expressionType = types[node.expression]; - if (identical(element, compiler.objectClass) - || identical(element, compiler.dynamicClass)) { - return graph.addConstantBool(true, constantSystem); - } else if (expressionType.isInteger()) { - if (identical(element, compiler.intClass) - || identical(element, compiler.numClass) - || Elements.isNumberOrStringSupertype(element, compiler)) { - return graph.addConstantBool(true, constantSystem); - } else if (identical(element, compiler.doubleClass)) { - // We let the JS semantics decide for that check. Currently - // the code we emit will always return true. - return node; - } else { - return graph.addConstantBool(false, constantSystem); - } - } else if (expressionType.isDouble()) { - if (identical(element, compiler.doubleClass) - || identical(element, compiler.numClass) - || Elements.isNumberOrStringSupertype(element, compiler)) { - return graph.addConstantBool(true, constantSystem); - } else if (identical(element, compiler.intClass)) { - // We let the JS semantics decide for that check. Currently - // the code we emit will return true for a double that can be - // represented as a 31-bit integer and for -0.0. - return node; - } else { - return graph.addConstantBool(false, constantSystem); - } - } else if (expressionType.isNumber()) { - if (identical(element, compiler.numClass)) { - return graph.addConstantBool(true, constantSystem); - } - // We cannot just return false, because the expression may be of - // type int or double. - } else if (expressionType.isString()) { - if (identical(element, compiler.stringClass) - || Elements.isStringOnlySupertype(element, compiler) - || Elements.isNumberOrStringSupertype(element, compiler)) { - return graph.addConstantBool(true, constantSystem); - } else { - return graph.addConstantBool(false, constantSystem); - } - } else if (expressionType.isArray()) { - if (identical(element, compiler.listClass) - || Elements.isListSupertype(element, compiler)) { - return graph.addConstantBool(true, constantSystem); - } else { - return graph.addConstantBool(false, constantSystem); - } - // TODO(karlklose): remove the hasTypeArguments check. - } else if (expressionType.isUseful() - && !expressionType.canBeNull() - && !RuntimeTypeInformation.hasTypeArguments(type)) { - DartType receiverType = expressionType.computeType(compiler); - if (receiverType != null) { - if (!receiverType.isMalformed && - !type.isMalformed && - compiler.types.isSubtype(receiverType, type)) { - return graph.addConstantBool(true, constantSystem); - } else if (expressionType.isExact()) { - return graph.addConstantBool(false, constantSystem); - } - } - } - return node; - } - - HInstruction visitTypeConversion(HTypeConversion node) { - HInstruction value = node.inputs[0]; - DartType type = types[node].computeType(compiler); - if (identical(type.element, compiler.dynamicClass) - || identical(type.element, compiler.objectClass)) { - return value; - } - if (types[value].canBeNull() && node.isBooleanConversionCheck) { - return node; - } - HType combinedType = types[value].intersection(types[node], compiler); - return (combinedType == types[value]) ? value : node; - } - - Element findConcreteFieldForDynamicAccess(HInstruction receiver, - Selector selector) { - HType receiverType = types[receiver]; - if (!receiverType.isUseful()) return null; - if (receiverType.canBeNull()) return null; - DartType type = receiverType.computeType(compiler); - if (type == null) return null; - return compiler.world.locateSingleField(type, selector); - } - - HInstruction visitFieldGet(HFieldGet node) { - if (node.element == backend.jsArrayLength) { - if (node.receiver is HInvokeStatic) { - // Try to recognize the length getter with input - // [:new List.fixedLength(int):]. - HInvokeStatic call = node.receiver; - if (isFixedSizeListConstructor(call)) { - return call.inputs[1]; - } - } - } - return node; - } - - HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) { - if (node.isInterceptorCall) return handleInterceptorCall(node); - - Element field = - findConcreteFieldForDynamicAccess(node.receiver, node.selector); - if (field == null) return node; - - Modifiers modifiers = field.modifiers; - bool isFinalOrConst = modifiers.isFinal() || modifiers.isConst(); - if (!compiler.resolverWorld.hasInvokedSetter(field, compiler)) { - // If no setter is ever used for this field it is only initialized in the - // initializer list. - isFinalOrConst = true; - } - HFieldGet result = new HFieldGet( - field, node.inputs[0], isAssignable: !isFinalOrConst); - HType type = backend.optimisticFieldType(field); - if (type != null) { - result.guaranteedType = type; - backend.registerFieldTypesOptimization( - work.element, field, result.guaranteedType); - } - return result; - } - - HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) { - if (node.isInterceptorCall) return handleInterceptorCall(node); - - Element field = - findConcreteFieldForDynamicAccess(node.receiver, node.selector); - if (field == null || !field.isAssignable()) return node; - HInstruction value = node.inputs[1]; - if (compiler.enableTypeAssertions) { - HInstruction other = value.convertType( - compiler, - field.computeType(compiler), - HTypeConversion.CHECKED_MODE_CHECK); - if (other != value) { - node.block.addBefore(node, other); - value = other; - } - } - return new HFieldSet(field, node.inputs[0], value); - } - - HInstruction visitStringConcat(HStringConcat node) { - DartString folded = const LiteralDartString(""); - for (int i = 0; i < node.inputs.length; i++) { - HInstruction part = node.inputs[i]; - if (!part.isConstant()) return node; - HConstant constant = part; - if (!constant.constant.isPrimitive()) return node; - PrimitiveConstant primitive = constant.constant; - folded = new DartString.concat(folded, primitive.toDartString()); - } - return graph.addConstant(constantSystem.createString(folded, node.node)); - } - - HInstruction visitInterceptor(HInterceptor node) { - if (node.isConstant()) return node; - HInstruction constant = tryComputeConstantInterceptor( - node.inputs[0], node.interceptedClasses); - if (constant == null) return node; - return constant; - } - - HInstruction tryComputeConstantInterceptor(HInstruction input, - Set<ClassElement> intercepted) { - HType type = types[input]; - ClassElement constantInterceptor; - if (type.isInteger()) { - constantInterceptor = backend.jsIntClass; - } else if (type.isDouble()) { - constantInterceptor = backend.jsDoubleClass; - } else if (type.isBoolean()) { - constantInterceptor = backend.jsBoolClass; - } else if (type.isString()) { - constantInterceptor = backend.jsStringClass; - } else if (type.isArray()) { - constantInterceptor = backend.jsArrayClass; - } else if (type.isNull()) { - constantInterceptor = backend.jsNullClass; - } else if (type.isNumber()) { - // If the method being intercepted is not defined in [int] or - // [double] we can safely use the number interceptor. - if (!intercepted.contains(compiler.intClass) - && !intercepted.contains(compiler.doubleClass)) { - constantInterceptor = backend.jsNumberClass; - } - } - - if (constantInterceptor == null) return null; - if (constantInterceptor == work.element.getEnclosingClass()) { - return graph.thisInstruction; - } - - Constant constant = new ConstructedConstant( - constantInterceptor.computeType(compiler), <Constant>[]); - return graph.addConstant(constant); - } - - HInstruction visitOneShotInterceptor(HOneShotInterceptor node) { - HInstruction newInstruction = handleInterceptorCall(node); - if (newInstruction != node) return newInstruction; - - HInstruction constant = tryComputeConstantInterceptor( - node.inputs[1], node.interceptedClasses); - - if (constant == null) return node; - - Selector selector = node.selector; - // TODO(ngeoffray): make one shot interceptors know whether - // they have side effects. - if (selector.isGetter()) { - HInstruction res = new HInvokeDynamicGetter( - selector, node.element, constant, false); - res.inputs.add(node.inputs[1]); - return res; - } else if (node.selector.isSetter()) { - HInstruction res = new HInvokeDynamicSetter( - selector, node.element, constant, node.inputs[1], false); - res.inputs.add(node.inputs[2]); - return res; - } else { - List<HInstruction> inputs = new List<HInstruction>.from(node.inputs); - inputs[0] = constant; - return new HInvokeDynamicMethod(selector, inputs, true); - } - } -} - -class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { - final HTypeMap types; - final Set<HInstruction> boundsChecked; - final CodegenWorkItem work; - final JavaScriptBackend backend; - final String name = "SsaCheckInserter"; - HGraph graph; - - SsaCheckInserter(this.backend, - this.work, - this.types, - this.boundsChecked); - - void visitGraph(HGraph graph) { - this.graph = graph; - visitDominatorTree(graph); - } - - void visitBasicBlock(HBasicBlock block) { - HInstruction instruction = block.first; - while (instruction != null) { - HInstruction next = instruction.next; - instruction = instruction.accept(this); - instruction = next; - } - } - - HBoundsCheck insertBoundsCheck(HInstruction node, - HInstruction receiver, - HInstruction index) { - bool isAssignable = !receiver.isFixedArray(types); - HFieldGet length = new HFieldGet( - backend.jsArrayLength, receiver, isAssignable: isAssignable); - length.guaranteedType = HType.INTEGER; - types[length] = HType.INTEGER; - node.block.addBefore(node, length); - - HBoundsCheck check = new HBoundsCheck(index, length); - node.block.addBefore(node, check); - boundsChecked.add(node); - return check; - } - - HIntegerCheck insertIntegerCheck(HInstruction node, HInstruction value) { - HIntegerCheck check = new HIntegerCheck(value); - node.block.addBefore(node, check); - Set<HInstruction> dominatedUsers = value.dominatedUsers(node); - for (HInstruction user in dominatedUsers) { - user.changeUse(value, check); - } - return check; - } - - void visitIndex(HIndex node) { - if (boundsChecked.contains(node)) return; - HInstruction index = node.index; - if (!node.index.isInteger(types)) { - index = insertIntegerCheck(node, index); - } - index = insertBoundsCheck(node, node.receiver, index); - node.changeUse(node.index, index); - } - - void visitIndexAssign(HIndexAssign node) { - if (!node.receiver.isMutableArray(types)) return; - if (boundsChecked.contains(node)) return; - HInstruction index = node.index; - if (!node.index.isInteger(types)) { - index = insertIntegerCheck(node, index); - } - index = insertBoundsCheck(node, node.receiver, index); - node.changeUse(node.index, index); - } - - void visitInvokeDynamicMethod(HInvokeDynamicMethod node) { - Element element = node.element; - if (node.isInterceptorCall) return; - if (element != backend.jsArrayRemoveLast) return; - if (boundsChecked.contains(node)) return; - insertBoundsCheck( - node, node.receiver, graph.addConstantInt(0, backend.constantSystem)); - } -} - -class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase { - final HTypeMap types; - final String name = "SsaDeadCodeEliminator"; - - SsaDeadCodeEliminator(this.types); - - bool isDeadCode(HInstruction instruction) { - return !instruction.hasSideEffects() - && !instruction.canThrow() - && instruction.usedBy.isEmpty - && instruction is !HTypeGuard - && instruction is !HParameterValue - && instruction is !HLocalSet - && !instruction.isControlFlow(); - } - - void visitGraph(HGraph graph) { - visitPostDominatorTree(graph); - } - - void visitBasicBlock(HBasicBlock block) { - HInstruction instruction = block.last; - while (instruction != null) { - var previous = instruction.previous; - if (isDeadCode(instruction)) block.remove(instruction); - instruction = previous; - } - } -} - -class SsaDeadPhiEliminator implements OptimizationPhase { - final String name = "SsaDeadPhiEliminator"; - - void visitGraph(HGraph graph) { - final List<HPhi> worklist = <HPhi>[]; - // A set to keep track of the live phis that we found. - final Set<HPhi> livePhis = new Set<HPhi>(); - - // Add to the worklist all live phis: phis referenced by non-phi - // instructions. - for (final block in graph.blocks) { - block.forEachPhi((HPhi phi) { - for (final user in phi.usedBy) { - if (user is !HPhi) { - worklist.add(phi); - livePhis.add(phi); - break; - } - } - }); - } - - // Process the worklist by propagating liveness to phi inputs. - while (!worklist.isEmpty) { - HPhi phi = worklist.removeLast(); - for (final input in phi.inputs) { - if (input is HPhi && !livePhis.contains(input)) { - worklist.add(input); - livePhis.add(input); - } - } - } - - // Remove phis that are not live. - // Traverse in reverse order to remove phis with no uses before the - // phis that they might use. - // NOTICE: Doesn't handle circular references, but we don't currently - // create any. - List<HBasicBlock> blocks = graph.blocks; - for (int i = blocks.length - 1; i >= 0; i--) { - HBasicBlock block = blocks[i]; - HPhi current = block.phis.first; - HPhi next = null; - while (current != null) { - next = current.next; - if (!livePhis.contains(current) - // TODO(ahe): Not sure the following is correct. - && current.usedBy.isEmpty) { - block.removePhi(current); - } - current = next; - } - } - } -} - -class SsaRedundantPhiEliminator implements OptimizationPhase { - final String name = "SsaRedundantPhiEliminator"; - - void visitGraph(HGraph graph) { - final List<HPhi> worklist = <HPhi>[]; - - // Add all phis in the worklist. - for (final block in graph.blocks) { - block.forEachPhi((HPhi phi) => worklist.add(phi)); - } - - while (!worklist.isEmpty) { - HPhi phi = worklist.removeLast(); - - // If the phi has already been processed, continue. - if (!phi.isInBasicBlock()) continue; - - // Find if the inputs of the phi are the same instruction. - // The builder ensures that phi.inputs[0] cannot be the phi - // itself. - assert(!identical(phi.inputs[0], phi)); - HInstruction candidate = phi.inputs[0]; - for (int i = 1; i < phi.inputs.length; i++) { - HInstruction input = phi.inputs[i]; - // If the input is the phi, the phi is still candidate for - // elimination. - if (!identical(input, candidate) && !identical(input, phi)) { - candidate = null; - break; - } - } - - // If the inputs are not the same, continue. - if (candidate == null) continue; - - // Because we're updating the users of this phi, we may have new - // phis candidate for elimination. Add phis that used this phi - // to the worklist. - for (final user in phi.usedBy) { - if (user is HPhi) worklist.add(user); - } - phi.block.rewrite(phi, candidate); - phi.block.removePhi(phi); - } - } -} - -class SsaGlobalValueNumberer implements OptimizationPhase { - final String name = "SsaGlobalValueNumberer"; - final Compiler compiler; - final HTypeMap types; - final Set<int> visited; - - List<int> blockChangesFlags; - List<int> loopChangesFlags; - - SsaGlobalValueNumberer(this.compiler, this.types) : visited = new Set<int>(); - - void visitGraph(HGraph graph) { - computeChangesFlags(graph); - moveLoopInvariantCode(graph); - visitBasicBlock(graph.entry, new ValueSet()); - } - - void moveLoopInvariantCode(HGraph graph) { - for (int i = graph.blocks.length - 1; i >= 0; i--) { - HBasicBlock block = graph.blocks[i]; - if (block.isLoopHeader()) { - int changesFlags = loopChangesFlags[block.id]; - HLoopInformation info = block.loopInformation; - // Iterate over all blocks of this loop. Note that blocks in - // inner loops are not visited here, but we know they - // were visited before because we are iterating in post-order. - // So instructions that are GVN'ed in an inner loop are in their - // loop entry, and [info.blocks] contains this loop entry. - for (HBasicBlock other in info.blocks) { - moveLoopInvariantCodeFromBlock(other, block, changesFlags); - } - } - } - } - - void moveLoopInvariantCodeFromBlock(HBasicBlock block, - HBasicBlock loopHeader, - int changesFlags) { - assert(block.parentLoopHeader == loopHeader); - HBasicBlock preheader = loopHeader.predecessors[0]; - int dependsFlags = HInstruction.computeDependsOnFlags(changesFlags); - HInstruction instruction = block.first; - while (instruction != null) { - HInstruction next = instruction.next; - if (instruction.useGvn() - && (instruction is !HCheck) - && (instruction.flags & dependsFlags) == 0) { - bool loopInvariantInputs = true; - List<HInstruction> inputs = instruction.inputs; - for (int i = 0, length = inputs.length; i < length; i++) { - if (isInputDefinedAfterDominator(inputs[i], preheader)) { - loopInvariantInputs = false; - break; - } - } - - // If the inputs are loop invariant, we can move the - // instruction from the current block to the pre-header block. - if (loopInvariantInputs) { - block.detach(instruction); - preheader.moveAtExit(instruction); - } - } - int oldChangesFlags = changesFlags; - changesFlags |= instruction.getChangesFlags(); - if (oldChangesFlags != changesFlags) { - dependsFlags = HInstruction.computeDependsOnFlags(changesFlags); - } - instruction = next; - } - } - - bool isInputDefinedAfterDominator(HInstruction input, - HBasicBlock dominator) { - return input.block.id > dominator.id; - } - - void visitBasicBlock(HBasicBlock block, ValueSet values) { - HInstruction instruction = block.first; - if (block.isLoopHeader()) { - int flags = loopChangesFlags[block.id]; - values.kill(flags); - } - while (instruction != null) { - HInstruction next = instruction.next; - int flags = instruction.getChangesFlags(); - assert(flags == 0 || !instruction.useGvn()); - values.kill(flags); - if (instruction.useGvn()) { - HInstruction other = values.lookup(instruction); - if (other != null) { - assert(other.gvnEquals(instruction) && instruction.gvnEquals(other)); - block.rewriteWithBetterUser(instruction, other); - block.remove(instruction); - } else { - values.add(instruction); - } - } - instruction = next; - } - - List<HBasicBlock> dominatedBlocks = block.dominatedBlocks; - for (int i = 0, length = dominatedBlocks.length; i < length; i++) { - HBasicBlock dominated = dominatedBlocks[i]; - // No need to copy the value set for the last child. - ValueSet successorValues = (i == length - 1) ? values : values.copy(); - // If we have no values in our set, we do not have to kill - // anything. Also, if the range of block ids from the current - // block to the dominated block is empty, there is no blocks on - // any path from the current block to the dominated block so we - // don't have to do anything either. - assert(block.id < dominated.id); - if (!successorValues.isEmpty && block.id + 1 < dominated.id) { - visited.clear(); - int changesFlags = getChangesFlagsForDominatedBlock(block, dominated); - successorValues.kill(changesFlags); - } - visitBasicBlock(dominated, successorValues); - } - } - - void computeChangesFlags(HGraph graph) { - // Create the changes flags lists. Make sure to initialize the - // loop changes flags list to zero so we can use bitwise or when - // propagating loop changes upwards. - final int length = graph.blocks.length; - blockChangesFlags = new List<int>.fixedLength(length); - loopChangesFlags = new List<int>.fixedLength(length); - for (int i = 0; i < length; i++) loopChangesFlags[i] = 0; - - // Run through all the basic blocks in the graph and fill in the - // changes flags lists. - for (int i = length - 1; i >= 0; i--) { - final HBasicBlock block = graph.blocks[i]; - final int id = block.id; - - // Compute block changes flags for the block. - int changesFlags = 0; - HInstruction instruction = block.first; - while (instruction != null) { - changesFlags |= instruction.getChangesFlags(); - instruction = instruction.next; - } - assert(blockChangesFlags[id] == null); - blockChangesFlags[id] = changesFlags; - - // Loop headers are part of their loop, so update the loop - // changes flags accordingly. - if (block.isLoopHeader()) { - loopChangesFlags[id] |= changesFlags; - } - - // Propagate loop changes flags upwards. - HBasicBlock parentLoopHeader = block.parentLoopHeader; - if (parentLoopHeader != null) { - loopChangesFlags[parentLoopHeader.id] |= (block.isLoopHeader()) - ? loopChangesFlags[id] - : changesFlags; - } - } - } - - int getChangesFlagsForDominatedBlock(HBasicBlock dominator, - HBasicBlock dominated) { - int changesFlags = 0; - List<HBasicBlock> predecessors = dominated.predecessors; - for (int i = 0, length = predecessors.length; i < length; i++) { - HBasicBlock block = predecessors[i]; - int id = block.id; - // If the current predecessor block is on the path from the - // dominator to the dominated, it must have an id that is in the - // range from the dominator to the dominated. - if (dominator.id < id && id < dominated.id && !visited.contains(id)) { - visited.add(id); - changesFlags |= blockChangesFlags[id]; - // Loop bodies might not be on the path from dominator to dominated, - // but they can invalidate values. - changesFlags |= loopChangesFlags[id]; - changesFlags |= getChangesFlagsForDominatedBlock(dominator, block); - } - } - return changesFlags; - } -} - -// This phase merges equivalent instructions on different paths into -// one instruction in a dominator block. It runs through the graph -// post dominator order and computes a ValueSet for each block of -// instructions that can be moved to a dominator block. These -// instructions are the ones that: -// 1) can be used for GVN, and -// 2) do not use definitions of their own block. -// -// A basic block looks at its sucessors and finds the intersection of -// these computed ValueSet. It moves all instructions of the -// intersection into its own list of instructions. -class SsaCodeMotion extends HBaseVisitor implements OptimizationPhase { - final String name = "SsaCodeMotion"; - - List<ValueSet> values; - - void visitGraph(HGraph graph) { - values = new List<ValueSet>.fixedLength(graph.blocks.length); - for (int i = 0; i < graph.blocks.length; i++) { - values[graph.blocks[i].id] = new ValueSet(); - } - visitPostDominatorTree(graph); - } - - void visitBasicBlock(HBasicBlock block) { - List<HBasicBlock> successors = block.successors; - - // Phase 1: get the ValueSet of all successors (if there are more than one), - // compute the intersection and move the instructions of the intersection - // into this block. - if (successors.length > 1) { - ValueSet instructions = values[successors[0].id]; - for (int i = 1; i < successors.length; i++) { - ValueSet other = values[successors[i].id]; - instructions = instructions.intersection(other); - } - - if (!instructions.isEmpty) { - List<HInstruction> list = instructions.toList(); - for (HInstruction instruction in list) { - // Move the instruction to the current block. - instruction.block.detach(instruction); - block.moveAtExit(instruction); - // Go through all successors and rewrite their instruction - // to the shared one. - for (final successor in successors) { - HInstruction toRewrite = values[successor.id].lookup(instruction); - if (toRewrite != instruction) { - successor.rewriteWithBetterUser(toRewrite, instruction); - successor.remove(toRewrite); - } - } - } - } - } - - // Don't try to merge instructions to a dominator if we have - // multiple predecessors. - if (block.predecessors.length != 1) return; - - // Phase 2: Go through all instructions of this block and find - // which instructions can be moved to a dominator block. - ValueSet set_ = values[block.id]; - HInstruction instruction = block.first; - int flags = 0; - while (instruction != null) { - int dependsFlags = HInstruction.computeDependsOnFlags(flags); - flags |= instruction.getChangesFlags(); - - HInstruction current = instruction; - instruction = instruction.next; - - // TODO(ngeoffray): this check is needed because we currently do - // not have flags to express 'Gvn'able', but not movable. - if (current is HCheck) continue; - if (!current.useGvn()) continue; - if ((current.flags & dependsFlags) != 0) continue; - - bool canBeMoved = true; - for (final HInstruction input in current.inputs) { - if (input.block == block) { - canBeMoved = false; - break; - } - } - if (!canBeMoved) continue; - - // This is safe because we are running after GVN. - // TODO(ngeoffray): ensure GVN has been run. - set_.add(current); - } - } -} - -class SsaTypeConversionInserter extends HBaseVisitor - implements OptimizationPhase { - final String name = "SsaTypeconversionInserter"; - final Compiler compiler; - - SsaTypeConversionInserter(this.compiler); - - void visitGraph(HGraph graph) { - visitDominatorTree(graph); - } - - - // Update users of [input] that are dominated by [:dominator.first:] - // to use [newInput] instead. - void changeUsesDominatedBy(HBasicBlock dominator, - HInstruction input, - HType convertedType) { - Set<HInstruction> dominatedUsers = input.dominatedUsers(dominator.first); - if (dominatedUsers.isEmpty) return; - - HTypeConversion newInput = new HTypeConversion(convertedType, input); - dominator.addBefore(dominator.first, newInput); - dominatedUsers.forEach((HInstruction user) { - user.changeUse(input, newInput); - }); - } - - void visitIs(HIs instruction) { - HInstruction input = instruction.expression; - HType convertedType = - new HType.fromBoundedType(instruction.typeExpression, compiler); - - List<HInstruction> ifUsers = <HInstruction>[]; - List<HInstruction> notIfUsers = <HInstruction>[]; - - for (HInstruction user in instruction.usedBy) { - if (user is HIf) { - ifUsers.add(user); - } else if (user is HNot) { - for (HInstruction notUser in user.usedBy) { - if (notUser is HIf) notIfUsers.add(notUser); - } - } - } - - if (ifUsers.isEmpty && notIfUsers.isEmpty) return; - - for (HIf ifUser in ifUsers) { - changeUsesDominatedBy(ifUser.thenBlock, input, convertedType); - // TODO(ngeoffray): Also change uses for the else block on a HType - // that knows it is not of a specific Type. - } - - for (HIf ifUser in notIfUsers) { - changeUsesDominatedBy(ifUser.elseBlock, input, convertedType); - // TODO(ngeoffray): Also change uses for the then block on a HType - // that knows it is not of a specific Type. - } - } -} - - -// Analyze the constructors to see if some fields will always have a specific -// type after construction. If this is the case we can ignore the type given -// by the field initializer. This is especially useful when the field -// initializer is initializing the field to null. -class SsaConstructionFieldTypes - extends HBaseVisitor implements OptimizationPhase { - final JavaScriptBackend backend; - final CodegenWorkItem work; - final HTypeMap types; - final String name = "SsaConstructionFieldTypes"; - final Set<HInstruction> thisUsers; - final Set<Element> allSetters; - final Map<HBasicBlock, Map<Element, HType>> blockFieldSetters; - bool thisExposed = false; - HGraph currentGraph; - Map<Element, HType> currentFieldSetters; - - SsaConstructionFieldTypes(JavaScriptBackend this.backend, - CodegenWorkItem this.work, - HTypeMap this.types) - : thisUsers = new Set<HInstruction>(), - allSetters = new Set<Element>(), - blockFieldSetters = new Map<HBasicBlock, Map<Element, HType>>(); - - void visitGraph(HGraph graph) { - currentGraph = graph; - if (!work.element.isGenerativeConstructorBody() && - !work.element.isGenerativeConstructor()) return; - visitDominatorTree(graph); - if (work.element.isGenerativeConstructor()) { - backend.registerConstructor(work.element); - } - } - - visitBasicBlock(HBasicBlock block) { - if (block.predecessors.length == 0) { - // Create a new empty map for the first block. - currentFieldSetters = new Map<Element, HType>(); - } else { - // Build a map which intersects the fields from all predecessors. For - // each field in this intersection it unions the types. - currentFieldSetters = - new Map.from(blockFieldSetters[block.predecessors[0]]); - // Loop headers are the only nodes with back edges. - if (!block.isLoopHeader()) { - for (int i = 1; i < block.predecessors.length; i++) { - Map<Element, HType> predecessorsFieldSetters = - blockFieldSetters[block.predecessors[i]]; - Map<Element, HType> newFieldSetters = new Map<Element, HType>(); - predecessorsFieldSetters.forEach((Element element, HType type) { - HType currentType = currentFieldSetters[element]; - if (currentType != null) { - newFieldSetters[element] = - currentType.union(type, backend.compiler); - } - }); - currentFieldSetters = newFieldSetters; - } - } else { - assert(block.predecessors.length <= 2); - } - } - block.forEachPhi((HPhi phi) => phi.accept(this)); - block.forEachInstruction( - (HInstruction instruction) => instruction.accept(this)); - assert(currentFieldSetters != null); - blockFieldSetters[block] = currentFieldSetters; - } - - visitInstruction(HInstruction instruction) { - // All instructions not explicitly handled below will flag the this - // exposure if using this. - thisExposed = thisExposed || thisUsers.contains(instruction); - } - - visitPhi(HPhi phi) { - if (thisUsers.contains(phi)) { - thisUsers.addAll(phi.usedBy); - } - } - - visitThis(HThis instruction) { - // Collect all users of this in a set to make the this exposed check simple - // and cheap. - thisUsers.addAll(instruction.usedBy); - } - - visitFieldGet(HInstruction _) { - // The field get instruction is allowed to use this. - } - - visitForeignNew(HForeignNew node) { - // The HForeignNew instruction is used in the generative constructor to - // initialize all fields in newly created objects. The fields are - // initialized to the value present in the initializer list or set to null - // if not otherwise initialized. - // Here we handle members in superclasses as well, as the handling of - // the generative constructor bodies will ensure, that the initializer - // type will not be used if the field is in any of these. - int j = 0; - node.element.forEachInstanceField( - (ClassElement enclosingClass, Element element) { - backend.registerFieldInitializer(element, types[node.inputs[j]]); - j++; - }, - includeBackendMembers: false, - includeSuperMembers: true); - } - - visitFieldSet(HFieldSet node) { - Element field = node.element; - HInstruction value = node.value; - HType type = types[value]; - // [HFieldSet] is also used for variables in try/catch. - if (field.isField()) allSetters.add(field); - // Don't handle fields defined in superclasses. Given that the field is - // always added to the [allSetters] set, setting a field defined in a - // superclass will get an inferred type of UNKNOWN. - if (identical(work.element.getEnclosingClass(), field.getEnclosingClass()) && - value.hasGuaranteedType()) { - currentFieldSetters[field] = type; - } - } - - visitExit(HExit node) { - // If this has been exposed then we cannot say anything about types after - // construction. - if (!thisExposed) { - // Register the known field types. - currentFieldSetters.forEach((Element element, HType type) { - backend.registerFieldConstructor(element, type); - allSetters.remove(element); - }); - } - - // For other fields having setters in the generative constructor body, set - // the type to UNKNOWN to avoid relying on the type set in the initializer - // list. - allSetters.forEach((Element element) { - backend.registerFieldConstructor(element, HType.UNKNOWN); - }); - } -} - -/** - * This phase specializes dominated uses of a call, where the call - * can give us some type information of what the receiver might be. - * For example, after a call to [:a.foo():], if [:foo:] is only - * in class [:A:], a can be of type [:A:]. - */ -class SsaReceiverSpecialization extends HBaseVisitor - implements OptimizationPhase { - final String name = "SsaReceiverSpecialization"; - final Compiler compiler; - - SsaReceiverSpecialization(this.compiler); - - void visitGraph(HGraph graph) { - visitDominatorTree(graph); - } - - void visitInterceptor(HInterceptor interceptor) { - HInstruction receiver = interceptor.receiver; - JavaScriptBackend backend = compiler.backend; - for (var user in receiver.usedBy) { - if (user is HInterceptor && interceptor.dominates(user)) { - Set<ClassElement> otherIntercepted = user.interceptedClasses; - // If the dominated interceptor intercepts the int class or - // the double class, we make sure these classes are also being - // intercepted by the dominating interceptor. Otherwise, the - // dominating interceptor could just intercept the number - // class and therefore not implement the methods in the int or - // double class. - if (otherIntercepted.contains(backend.jsIntClass) - || otherIntercepted.contains(backend.jsDoubleClass)) { - interceptor.interceptedClasses.addAll(user.interceptedClasses); - } - user.interceptedClasses = interceptor.interceptedClasses; - } - } - } - - // TODO(ngeoffray): Also implement it for non-intercepted calls. -} - -/** - * This phase replaces all interceptors that are used only once with - * one-shot interceptors. It saves code size and makes the receiver of - * an intercepted call a candidate for being generated at use site. - */ -class SsaSimplifyInterceptors extends HBaseVisitor - implements OptimizationPhase { - final String name = "SsaSimplifyInterceptors"; - final ConstantSystem constantSystem; - HGraph graph; - - SsaSimplifyInterceptors(this.constantSystem); - - void visitGraph(HGraph graph) { - this.graph = graph; - visitDominatorTree(graph); - } - - void visitInterceptor(HInterceptor node) { - if (node.usedBy.length != 1) return; - // [HBailoutTarget] instructions might have the interceptor as - // input. In such situation we let the dead code analyzer find out - // the interceptor is not needed. - if (node.usedBy[0] is !HInvokeDynamic) return; - - HInvokeDynamic user = node.usedBy[0]; - - // If [node] was loop hoisted, we keep the interceptor. - if (!user.hasSameLoopHeaderAs(node)) return; - - // Replace the user with a [HOneShotInterceptor]. - HConstant nullConstant = graph.addConstantNull(constantSystem); - List<HInstruction> inputs = new List<HInstruction>.from(user.inputs); - inputs[0] = nullConstant; - HOneShotInterceptor interceptor = new HOneShotInterceptor( - user.selector, inputs, node.interceptedClasses); - interceptor.sourcePosition = user.sourcePosition; - interceptor.sourceElement = user.sourceElement; - - HBasicBlock block = user.block; - block.addAfter(user, interceptor); - block.rewrite(user, interceptor); - block.remove(user); - - // The interceptor will be removed in the dead code elimination - // phase. Note that removing it here would not work because of how - // the [visitBasicBlock] is implemented. - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/ssa.dart b/pkgs/markdown/test/lib/src/compiler/implementation/ssa/ssa.dart deleted file mode 100644 index 13de8b6..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/ssa.dart +++ /dev/null
@@ -1,43 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library ssa; - -import 'dart:collection'; - -import '../closure.dart'; -import '../js/js.dart' as js; -import '../dart2jslib.dart' hide Selector; -import '../dart_types.dart'; -import '../source_file.dart'; -import '../source_map_builder.dart'; -import '../elements/elements.dart'; -import '../js_backend/js_backend.dart'; -import '../native_handler.dart' as native; -import '../tree/tree.dart'; -import '../types/types.dart'; -import '../universe/universe.dart'; -import '../util/util.dart'; -import '../util/characters.dart'; - -import '../scanner/scannerlib.dart' - show PartialFunctionElement, Token, PLUS_TOKEN; - -import '../elements/modelx.dart' - show ElementX, - ConstructorBodyElementX; - -part 'bailout.dart'; -part 'builder.dart'; -part 'codegen.dart'; -part 'codegen_helpers.dart'; -part 'invoke_dynamic_specializers.dart'; -part 'nodes.dart'; -part 'optimize.dart'; -part 'types.dart'; -part 'types_propagation.dart'; -part 'validate.dart'; -part 'variable_allocator.dart'; -part 'value_range_analyzer.dart'; -part 'value_set.dart';
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/tracer.dart b/pkgs/markdown/test/lib/src/compiler/implementation/ssa/tracer.dart deleted file mode 100644 index 7a8f6bc..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/tracer.dart +++ /dev/null
@@ -1,563 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library tracer; - -import 'dart:io'; -import 'ssa.dart'; -import '../js_backend/js_backend.dart'; -import '../dart2jslib.dart'; - -const bool GENERATE_SSA_TRACE = false; -const String SSA_TRACE_FILTER = null; - -class HTracer extends HGraphVisitor implements Tracer { - JavaScriptItemCompilationContext context; - int indent = 0; - final RandomAccessFile output; - final bool enabled = GENERATE_SSA_TRACE; - bool traceActive = false; - - HTracer([String path = "dart.cfg"]) - : output = GENERATE_SSA_TRACE ? new File(path).openSync(FileMode.WRITE) - : null; - - void close() { - if (enabled) output.closeSync(); - } - - void traceCompilation(String methodName, - JavaScriptItemCompilationContext compilationContext) { - if (!enabled) return; - this.context = compilationContext; - traceActive = - SSA_TRACE_FILTER == null || methodName.contains(SSA_TRACE_FILTER); - if (!traceActive) return; - tag("compilation", () { - printProperty("name", methodName); - printProperty("method", methodName); - printProperty("date", new DateTime.now().millisecondsSinceEpoch); - }); - } - - void traceGraph(String name, HGraph graph) { - if (!traceActive) return; - tag("cfg", () { - printProperty("name", name); - visitDominatorTree(graph); - }); - } - - void addPredecessors(HBasicBlock block) { - if (block.predecessors.isEmpty) { - printEmptyProperty("predecessors"); - } else { - addIndent(); - add("predecessors"); - for (HBasicBlock predecessor in block.predecessors) { - add(' "B${predecessor.id}"'); - } - add("\n"); - } - } - - void addSuccessors(HBasicBlock block) { - if (block.successors.isEmpty) { - printEmptyProperty("successors"); - } else { - addIndent(); - add("successors"); - for (HBasicBlock successor in block.successors) { - add(' "B${successor.id}"'); - } - add("\n"); - } - } - - void addInstructions(HInstructionStringifier stringifier, - HInstructionList list) { - HTypeMap types = context.types; - for (HInstruction instruction = list.first; - instruction != null; - instruction = instruction.next) { - int bci = 0; - int uses = instruction.usedBy.length; - String changes = instruction.hasSideEffects() ? '!' : ' '; - String depends = instruction.dependsOnSomething() ? '?' : ''; - addIndent(); - String temporaryId = stringifier.temporaryId(instruction); - String instructionString = stringifier.visit(instruction); - add("$bci $uses $temporaryId $instructionString $changes $depends <|@\n"); - } - } - - void visitBasicBlock(HBasicBlock block) { - HInstructionStringifier stringifier = - new HInstructionStringifier(context, block); - assert(block.id != null); - tag("block", () { - printProperty("name", "B${block.id}"); - printProperty("from_bci", -1); - printProperty("to_bci", -1); - addPredecessors(block); - addSuccessors(block); - printEmptyProperty("xhandlers"); - printEmptyProperty("flags"); - if (block.dominator != null) { - printProperty("dominator", "B${block.dominator.id}"); - } - tag("states", () { - tag("locals", () { - printProperty("size", 0); - printProperty("method", "None"); - block.forEachPhi((phi) { - String phiId = stringifier.temporaryId(phi); - StringBuffer inputIds = new StringBuffer(); - for (int i = 0; i < phi.inputs.length; i++) { - inputIds.add(stringifier.temporaryId(phi.inputs[i])); - inputIds.add(" "); - } - println("${phi.id} $phiId [ $inputIds]"); - }); - }); - }); - tag("HIR", () { - addInstructions(stringifier, block.phis); - addInstructions(stringifier, block); - }); - }); - } - - void tag(String tagName, Function f) { - println("begin_$tagName"); - indent++; - f(); - indent--; - println("end_$tagName"); - } - - void println(String string) { - addIndent(); - add(string); - add("\n"); - } - - void printEmptyProperty(String propertyName) { - println(propertyName); - } - - void printProperty(String propertyName, var value) { - if (value is num) { - println("$propertyName $value"); - } else { - println('$propertyName "$value"'); - } - } - - void add(String string) { - output.writeStringSync(string); - } - - void addIndent() { - for (int i = 0; i < indent; i++) { - add(" "); - } - } -} - -class HInstructionStringifier implements HVisitor<String> { - JavaScriptItemCompilationContext context; - HBasicBlock currentBlock; - - HInstructionStringifier(this.context, this.currentBlock); - - visit(HInstruction node) => node.accept(this); - - String temporaryId(HInstruction instruction) { - String prefix; - HType type = context.types[instruction]; - if (!type.isPrimitive()) { - prefix = 'U'; - } else { - if (type == HType.MUTABLE_ARRAY) { - prefix = 'm'; - } else if (type == HType.READABLE_ARRAY) { - prefix = 'a'; - } else if (type == HType.EXTENDABLE_ARRAY) { - prefix = 'e'; - } else if (type == HType.BOOLEAN) { - prefix = 'b'; - } else if (type == HType.INTEGER) { - prefix = 'i'; - } else if (type == HType.DOUBLE) { - prefix = 'd'; - } else if (type == HType.NUMBER) { - prefix = 'n'; - } else if (type == HType.STRING) { - prefix = 's'; - } else if (type == HType.UNKNOWN) { - prefix = 'v'; - } else if (type == HType.CONFLICTING) { - prefix = 'c'; - } else if (type == HType.INDEXABLE_PRIMITIVE) { - prefix = 'r'; - } else if (type == HType.NULL) { - prefix = 'u'; - } else { - prefix = 'x'; - } - } - return "$prefix${instruction.id}"; - } - - String visitBailoutTarget(HBailoutTarget node) { - StringBuffer envBuffer = new StringBuffer(); - List<HInstruction> inputs = node.inputs; - for (int i = 0; i < inputs.length; i++) { - envBuffer.add(" ${temporaryId(inputs[i])}"); - } - String on = node.isEnabled ? "enabled" : "disabled"; - return "BailoutTarget($on): id: ${node.state} env: $envBuffer"; - } - - String visitBoolify(HBoolify node) { - return "Boolify: ${temporaryId(node.inputs[0])}"; - } - - String handleInvokeBinary(HInvokeBinary node, String op) { - String left = temporaryId(node.left); - String right= temporaryId(node.right); - return '$left $op $right'; - } - - String visitAdd(HAdd node) => handleInvokeBinary(node, '+'); - - String visitBitAnd(HBitAnd node) => handleInvokeBinary(node, '&'); - - String visitBitNot(HBitNot node) { - String operand = temporaryId(node.operand); - return "~$operand"; - } - - String visitBitOr(HBitOr node) => handleInvokeBinary(node, '|'); - - String visitBitXor(HBitXor node) => handleInvokeBinary(node, '^'); - - String visitBoundsCheck(HBoundsCheck node) { - String lengthId = temporaryId(node.length); - String indexId = temporaryId(node.index); - return "Bounds check: length = $lengthId, index = $indexId"; - } - - String visitBreak(HBreak node) { - HBasicBlock target = currentBlock.successors[0]; - if (node.label != null) { - return "Break ${node.label.labelName}: (B${target.id})"; - } - return "Break: (B${target.id})"; - } - - String visitConstant(HConstant constant) => "Constant ${constant.constant}"; - - String visitContinue(HContinue node) { - HBasicBlock target = currentBlock.successors[0]; - if (node.label != null) { - return "Continue ${node.label.labelName}: (B${target.id})"; - } - return "Continue: (B${target.id})"; - } - - String visitDivide(HDivide node) => handleInvokeBinary(node, '/'); - - String visitExit(HExit node) => "exit"; - - String visitFieldGet(HFieldGet node) { - String fieldName = node.element.name.slowToString(); - return 'field get ${temporaryId(node.receiver)}.$fieldName'; - } - - String visitFieldSet(HFieldSet node) { - String valueId = temporaryId(node.value); - String fieldName = node.element.name.slowToString(); - return 'field set ${temporaryId(node.receiver)}.$fieldName to $valueId'; - } - - String visitLocalGet(HLocalGet node) { - String localName = node.element.name.slowToString(); - return 'local get ${temporaryId(node.local)}.$localName'; - } - - String visitLocalSet(HLocalSet node) { - String valueId = temporaryId(node.value); - String localName = node.element.name.slowToString(); - return 'local set ${temporaryId(node.local)}.$localName to $valueId'; - } - - String visitGoto(HGoto node) { - HBasicBlock target = currentBlock.successors[0]; - return "Goto: (B${target.id})"; - } - - String visitGreater(HGreater node) => handleInvokeBinary(node, '>'); - String visitGreaterEqual(HGreaterEqual node) { - handleInvokeBinary(node, '>='); - } - String visitIdentity(HIdentity node) => handleInvokeBinary(node, '==='); - - String visitIf(HIf node) { - HBasicBlock thenBlock = currentBlock.successors[0]; - HBasicBlock elseBlock = currentBlock.successors[1]; - String conditionId = temporaryId(node.inputs[0]); - return "If ($conditionId): (B${thenBlock.id}) else (B${elseBlock.id})"; - } - - String visitGenericInvoke(String invokeType, String functionName, - List<HInstruction> arguments) { - StringBuffer argumentsString = new StringBuffer(); - for (int i = 0; i < arguments.length; i++) { - if (i != 0) argumentsString.add(", "); - argumentsString.add(temporaryId(arguments[i])); - } - return "$invokeType: $functionName($argumentsString)"; - } - - String visitIndex(HIndex node) { - String receiver = temporaryId(node.receiver); - String index = temporaryId(node.index); - return "Index: $receiver[$index]"; - } - - String visitIndexAssign(HIndexAssign node) { - String receiver = temporaryId(node.receiver); - String index = temporaryId(node.index); - String value = temporaryId(node.value); - return "IndexAssign: $receiver[$index] = $value"; - } - - String visitIntegerCheck(HIntegerCheck node) { - String value = temporaryId(node.value); - return "Integer check: $value"; - } - - String visitInterceptor(HInterceptor node) { - String value = temporaryId(node.inputs[0]); - return "Intercept: $value"; - } - - String visitInvokeClosure(HInvokeClosure node) - => visitInvokeDynamic(node, "closure"); - - String visitInvokeDynamic(HInvokeDynamic invoke, String kind) { - String receiver = temporaryId(invoke.receiver); - String name = invoke.selector.name.slowToString(); - String target = "($kind) $receiver.$name"; - int offset = HInvoke.ARGUMENTS_OFFSET; - List arguments = - invoke.inputs.getRange(offset, invoke.inputs.length - offset); - return visitGenericInvoke("Invoke", target, arguments); - } - - String visitInvokeDynamicMethod(HInvokeDynamicMethod node) - => visitInvokeDynamic(node, "method"); - String visitInvokeDynamicGetter(HInvokeDynamicGetter node) - => visitInvokeDynamic(node, "get"); - String visitInvokeDynamicSetter(HInvokeDynamicSetter node) - => visitInvokeDynamic(node, "set"); - - String visitInvokeStatic(HInvokeStatic invoke) { - String target = temporaryId(invoke.target); - int offset = HInvoke.ARGUMENTS_OFFSET; - List arguments = - invoke.inputs.getRange(offset, invoke.inputs.length - offset); - return visitGenericInvoke("Invoke", target, arguments); - } - - String visitInvokeSuper(HInvokeSuper invoke) { - String target = temporaryId(invoke.target); - int offset = HInvoke.ARGUMENTS_OFFSET + 1; - List arguments = - invoke.inputs.getRange(offset, invoke.inputs.length - offset); - return visitGenericInvoke("Invoke super", target, arguments); - } - - String visitForeign(HForeign foreign) { - return visitGenericInvoke("Foreign", "${foreign.code}", foreign.inputs); - } - - String visitForeignNew(HForeignNew node) { - return visitGenericInvoke("New", - "${node.element.name.slowToString()}", - node.inputs); - } - - String visitLess(HLess node) => handleInvokeBinary(node, '<'); - String visitLessEqual(HLessEqual node) => handleInvokeBinary(node, '<='); - - String visitLiteralList(HLiteralList node) { - StringBuffer elementsString = new StringBuffer(); - for (int i = 0; i < node.inputs.length; i++) { - if (i != 0) elementsString.add(", "); - elementsString.add(temporaryId(node.inputs[i])); - } - return "Literal list: [$elementsString]"; - } - - String visitLoopBranch(HLoopBranch branch) { - HBasicBlock bodyBlock = currentBlock.successors[0]; - HBasicBlock exitBlock = currentBlock.successors[1]; - String conditionId = temporaryId(branch.inputs[0]); - return "While ($conditionId): (B${bodyBlock.id}) then (B${exitBlock.id})"; - } - - String visitMultiply(HMultiply node) => handleInvokeBinary(node, '*'); - - String visitNegate(HNegate node) { - String operand = temporaryId(node.operand); - return "-$operand"; - } - - String visitNot(HNot node) => "Not: ${temporaryId(node.inputs[0])}"; - - String visitParameterValue(HParameterValue node) { - return "p${node.sourceElement.name.slowToString()}"; - } - - String visitLocalValue(HLocalValue node) { - return "l${node.sourceElement.name.slowToString()}"; - } - - String visitPhi(HPhi phi) { - StringBuffer buffer = new StringBuffer(); - buffer.add("Phi("); - for (int i = 0; i < phi.inputs.length; i++) { - if (i > 0) buffer.add(", "); - buffer.add(temporaryId(phi.inputs[i])); - } - buffer.add(")"); - return buffer.toString(); - } - - String visitReturn(HReturn node) => "Return ${temporaryId(node.inputs[0])}"; - - String visitShiftLeft(HShiftLeft node) => handleInvokeBinary(node, '<<'); - - String visitStatic(HStatic node) - => "Static ${node.element.name.slowToString()}"; - - String visitLazyStatic(HLazyStatic node) - => "LazyStatic ${node.element.name.slowToString()}"; - - String visitOneShotInterceptor(HOneShotInterceptor node) - => visitInvokeDynamic(node, "one shot interceptor"); - - String visitStaticStore(HStaticStore node) { - String lhs = node.element.name.slowToString(); - return "Static $lhs = ${temporaryId(node.inputs[0])}"; - } - - String visitStringConcat(HStringConcat node) { - var leftId = temporaryId(node.left); - var rightId = temporaryId(node.right); - return "StringConcat: $leftId + $rightId"; - } - - String visitSubtract(HSubtract node) => handleInvokeBinary(node, '-'); - - String visitSwitch(HSwitch node) { - StringBuffer buf = new StringBuffer(); - buf.add("Switch: ("); - buf.add(temporaryId(node.inputs[0])); - buf.add(") "); - for (int i = 1; i < node.inputs.length; i++) { - buf.add(temporaryId(node.inputs[i])); - buf.add(": B"); - buf.add(node.block.successors[i - 1].id); - buf.add(", "); - } - buf.add("default: B"); - buf.add(node.block.successors.last.id); - return buf.toString(); - } - - String visitThis(HThis node) => "this"; - - String visitThrow(HThrow node) => "Throw ${temporaryId(node.inputs[0])}"; - - String visitExitTry(HExitTry node) { - return "Exit try"; - } - - String visitTry(HTry node) { - List<HBasicBlock> successors = currentBlock.successors; - String tryBlock = 'B${successors[0].id}'; - String catchBlock = 'none'; - if (node.catchBlock != null) { - catchBlock = 'B${successors[1].id}'; - } - - String finallyBlock = 'none'; - if (node.finallyBlock != null) { - finallyBlock = 'B${node.finallyBlock.id}'; - } - - return "Try: $tryBlock, Catch: $catchBlock, Finally: $finallyBlock, " - "Join: B${successors.last.id}"; - } - - String visitTypeGuard(HTypeGuard node) { - String type; - HType guardedType = node.guardedType; - if (guardedType == HType.MUTABLE_ARRAY) { - type = "mutable_array"; - } else if (guardedType == HType.READABLE_ARRAY) { - type = "readable_array"; - } else if (guardedType == HType.EXTENDABLE_ARRAY) { - type = "extendable_array"; - } else if (guardedType == HType.BOOLEAN) { - type = "bool"; - } else if (guardedType == HType.INTEGER) { - type = "integer"; - } else if (guardedType == HType.DOUBLE) { - type = "double"; - } else if (guardedType == HType.NUMBER) { - type = "number"; - } else if (guardedType == HType.STRING) { - type = "string"; - } else if (guardedType == HType.INDEXABLE_PRIMITIVE) { - type = "string_or_array"; - } else if (guardedType == HType.UNKNOWN) { - type = 'unknown'; - } else { - throw new CompilerCancelledException('Unexpected type guard: $type'); - } - HInstruction guarded = node.guarded; - HInstruction bailoutTarget = node.bailoutTarget; - StringBuffer envBuffer = new StringBuffer(); - List<HInstruction> inputs = node.inputs; - assert(inputs.length >= 2); - assert(inputs[0] == guarded); - assert(inputs[1] == bailoutTarget); - for (int i = 2; i < inputs.length; i++) { - envBuffer.add(" ${temporaryId(inputs[i])}"); - } - String on = node.isEnabled ? "enabled" : "disabled"; - String guardedId = temporaryId(node.guarded); - String bailoutId = temporaryId(node.bailoutTarget); - return "TypeGuard($on): $guardedId is $type bailout: $bailoutId " - "env: $envBuffer"; - } - - String visitIs(HIs node) { - String type = node.typeExpression.toString(); - return "TypeTest: ${temporaryId(node.expression)} is $type"; - } - - String visitTypeConversion(HTypeConversion node) { - return "TypeConversion: ${temporaryId(node.checkedInput)} to ${node.type}"; - } - - String visitRangeConversion(HRangeConversion node) { - return "RangeConversion: ${node.checkedInput}"; - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/types.dart b/pkgs/markdown/test/lib/src/compiler/implementation/ssa/types.dart deleted file mode 100644 index b6d4746..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/types.dart +++ /dev/null
@@ -1,997 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of ssa; - -abstract class HType { - const HType(); - - /** - * Returns an [HType] that represents [type] and all types that have - * [type] as supertype. - */ - factory HType.fromBoundedType(DartType type, - Compiler compiler, - [bool canBeNull = false]) { - Element element = type.element; - if (element.kind == ElementKind.TYPE_VARIABLE) { - // TODO(ngeoffray): Replace object type with [type]. - return new HBoundedPotentialPrimitiveType( - compiler.objectClass.computeType(compiler), canBeNull, true); - } - - if (element == compiler.intClass) { - return canBeNull ? HType.INTEGER_OR_NULL : HType.INTEGER; - } else if (element == compiler.numClass) { - return canBeNull ? HType.NUMBER_OR_NULL : HType.NUMBER; - } else if (element == compiler.doubleClass) { - return canBeNull ? HType.DOUBLE_OR_NULL : HType.DOUBLE; - } else if (element == compiler.stringClass) { - return canBeNull ? HType.STRING_OR_NULL : HType.STRING; - } else if (element == compiler.boolClass) { - return canBeNull ? HType.BOOLEAN_OR_NULL : HType.BOOLEAN; - } else if (element == compiler.nullClass) { - return HType.NULL; - } else if (element == compiler.listClass - || Elements.isListSupertype(element, compiler)) { - return new HBoundedPotentialPrimitiveArray(type, canBeNull); - } else if (Elements.isNumberOrStringSupertype(element, compiler)) { - return new HBoundedPotentialPrimitiveNumberOrString(type, canBeNull); - } else if (Elements.isStringOnlySupertype(element, compiler)) { - return new HBoundedPotentialPrimitiveString(type, canBeNull); - } else if (element == compiler.objectClass) { - return new HBoundedPotentialPrimitiveType( - compiler.objectClass.computeType(compiler), canBeNull, true); - } else { - return canBeNull ? new HBoundedType.withNull(type) - : new HBoundedType.nonNull(type); - } - } - - static const HType CONFLICTING = const HConflictingType(); - static const HType UNKNOWN = const HUnknownType(); - static const HType BOOLEAN = const HBooleanType(); - static const HType NUMBER = const HNumberType(); - static const HType INTEGER = const HIntegerType(); - static const HType DOUBLE = const HDoubleType(); - static const HType INDEXABLE_PRIMITIVE = const HIndexablePrimitiveType(); - static const HType STRING = const HStringType(); - static const HType READABLE_ARRAY = const HReadableArrayType(); - static const HType MUTABLE_ARRAY = const HMutableArrayType(); - static const HType FIXED_ARRAY = const HFixedArrayType(); - static const HType EXTENDABLE_ARRAY = const HExtendableArrayType(); - static const HType NULL = const HNullType(); - - static const HType BOOLEAN_OR_NULL = const HBooleanOrNullType(); - static const HType NUMBER_OR_NULL = const HNumberOrNullType(); - static const HType INTEGER_OR_NULL = const HIntegerOrNullType(); - static const HType DOUBLE_OR_NULL = const HDoubleOrNullType(); - static const HType STRING_OR_NULL = const HStringOrNullType(); - - bool isConflicting() => identical(this, CONFLICTING); - bool isUnknown() => identical(this, UNKNOWN); - bool isNull() => false; - bool isBoolean() => false; - bool isNumber() => false; - bool isInteger() => false; - bool isDouble() => false; - bool isString() => false; - bool isBooleanOrNull() => false; - bool isNumberOrNull() => false; - bool isIntegerOrNull() => false; - bool isDoubleOrNull() => false; - bool isStringOrNull() => false; - bool isIndexablePrimitive() => false; - bool isFixedArray() => false; - bool isReadableArray() => false; - bool isMutableArray() => false; - bool isExtendableArray() => false; - bool isPrimitive() => false; - bool isExact() => false; - bool isPrimitiveOrNull() => false; - bool isTop() => false; - - bool canBePrimitive() => false; - bool canBeNull() => false; - - /** A type is useful it is not unknown, not conflicting, and not null. */ - bool isUseful() => !isUnknown() && !isConflicting() && !isNull(); - /** Alias for isReadableArray. */ - bool isArray() => isReadableArray(); - - DartType computeType(Compiler compiler); - - /** - * The intersection of two types is the intersection of its values. For - * example: - * * INTEGER.intersect(NUMBER) => INTEGER. - * * DOUBLE.intersect(INTEGER) => CONFLICTING. - * * MUTABLE_ARRAY.intersect(READABLE_ARRAY) => MUTABLE_ARRAY. - * - * When there is no predefined type to represent the intersection returns - * [CONFLICTING]. - * - * An intersection with [UNKNOWN] returns the non-UNKNOWN type. An - * intersection with [CONFLICTING] returns [CONFLICTING]. - */ - HType intersection(HType other, Compiler compiler); - - /** - * The union of two types is the union of its values. For example: - * * INTEGER.union(NUMBER) => NUMBER. - * * DOUBLE.union(INTEGER) => NUMBER. - * * MUTABLE_ARRAY.union(READABLE_ARRAY) => READABLE_ARRAY. - * - * When there is no predefined type to represent the union returns - * [UNKNOWN]. - * - * A union with [UNKNOWN] returns [UNKNOWN]. - * A union of [CONFLICTING] with any other types returns the other type. - */ - HType union(HType other, Compiler compiler); -} - -/** Used to represent [HType.UNKNOWN] and [HType.CONFLICTING]. */ -abstract class HAnalysisType extends HType { - final String name; - const HAnalysisType(this.name); - String toString() => name; - - DartType computeType(Compiler compiler) => null; -} - -class HUnknownType extends HAnalysisType { - const HUnknownType() : super("unknown"); - bool canBePrimitive() => true; - bool canBeNull() => true; - - HType union(HType other, Compiler compiler) => this; - HType intersection(HType other, Compiler compiler) => other; -} - -class HConflictingType extends HAnalysisType { - const HConflictingType() : super("conflicting"); - bool canBePrimitive() => true; - bool canBeNull() => true; - - HType union(HType other, Compiler compiler) => other; - HType intersection(HType other, Compiler compiler) => this; -} - -abstract class HPrimitiveType extends HType { - const HPrimitiveType(); - bool isPrimitive() => true; - bool canBePrimitive() => true; - bool isPrimitiveOrNull() => true; -} - -class HNullType extends HPrimitiveType { - const HNullType(); - bool canBeNull() => true; - bool isNull() => true; - String toString() => 'null'; - - DartType computeType(Compiler compiler) { - JavaScriptBackend backend = compiler.backend; - return backend.jsNullClass.computeType(compiler); - } - - HType union(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.NULL; - if (other.isUnknown()) return HType.UNKNOWN; - if (other.isString()) return HType.STRING_OR_NULL; - if (other.isInteger()) return HType.INTEGER_OR_NULL; - if (other.isDouble()) return HType.DOUBLE_OR_NULL; - if (other.isNumber()) return HType.NUMBER_OR_NULL; - if (other.isBoolean()) return HType.BOOLEAN_OR_NULL; - // TODO(ngeoffray): Deal with the type of null more generally. - if (other.isReadableArray()) return other.union(this, compiler); - if (!other.canBeNull()) return HType.UNKNOWN; - return other; - } - - HType intersection(HType other, Compiler compiler) { - if (other.isUnknown()) return HType.NULL; - if (other.isConflicting()) return HType.CONFLICTING; - if (!other.canBeNull()) return HType.CONFLICTING; - return HType.NULL; - } -} - -abstract class HPrimitiveOrNullType extends HType { - const HPrimitiveOrNullType(); - bool canBePrimitive() => true; - bool canBeNull() => true; - bool isPrimitiveOrNull() => true; -} - -class HBooleanOrNullType extends HPrimitiveOrNullType { - const HBooleanOrNullType(); - String toString() => "boolean or null"; - bool isBooleanOrNull() => true; - - DartType computeType(Compiler compiler) { - JavaScriptBackend backend = compiler.backend; - return backend.jsBoolClass.computeType(compiler); - } - - HType union(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.BOOLEAN_OR_NULL; - if (other.isUnknown()) return HType.UNKNOWN; - if (other.isBooleanOrNull()) return HType.BOOLEAN_OR_NULL; - if (other.isBoolean()) return HType.BOOLEAN_OR_NULL; - if (other.isNull()) return HType.BOOLEAN_OR_NULL; - return HType.UNKNOWN; - } - - HType intersection(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.CONFLICTING; - if (other.isUnknown()) return HType.BOOLEAN_OR_NULL; - if (other.isBoolean()) return HType.BOOLEAN; - if (other.isBooleanOrNull()) return HType.BOOLEAN_OR_NULL; - if (other.isTop()) { - return other.canBeNull() ? this : HType.BOOLEAN; - } - if (other.canBeNull()) return HType.NULL; - return HType.CONFLICTING; - } -} - -class HBooleanType extends HPrimitiveType { - const HBooleanType(); - bool isBoolean() => true; - bool isBooleanOrNull() => true; - String toString() => "boolean"; - - DartType computeType(Compiler compiler) { - JavaScriptBackend backend = compiler.backend; - return backend.jsBoolClass.computeType(compiler); - } - - HType union(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.BOOLEAN; - if (other.isUnknown()) return HType.UNKNOWN; - if (other.isBoolean()) return HType.BOOLEAN; - if (other.isBooleanOrNull()) return HType.BOOLEAN_OR_NULL; - if (other.isNull()) return HType.BOOLEAN_OR_NULL; - return HType.UNKNOWN; - } - - HType intersection(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.CONFLICTING; - if (other.isUnknown()) return HType.BOOLEAN; - if (other.isBooleanOrNull()) return HType.BOOLEAN; - if (other.isBoolean()) return HType.BOOLEAN; - return HType.CONFLICTING; - } -} - -class HNumberOrNullType extends HPrimitiveOrNullType { - const HNumberOrNullType(); - bool isNumberOrNull() => true; - String toString() => "number or null"; - - DartType computeType(Compiler compiler) { - JavaScriptBackend backend = compiler.backend; - return backend.jsNumberClass.computeType(compiler); - } - - HType union(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.NUMBER_OR_NULL; - if (other.isUnknown()) return HType.UNKNOWN; - if (other.isNumberOrNull()) return HType.NUMBER_OR_NULL; - if (other.isNumber()) return HType.NUMBER_OR_NULL; - if (other.isNull()) return HType.NUMBER_OR_NULL; - return HType.UNKNOWN; - } - - HType intersection(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.CONFLICTING; - if (other.isUnknown()) return HType.NUMBER_OR_NULL; - if (other.isInteger()) return HType.INTEGER; - if (other.isDouble()) return HType.DOUBLE; - if (other.isNumber()) return HType.NUMBER; - if (other.isIntegerOrNull()) return HType.INTEGER_OR_NULL; - if (other.isDoubleOrNull()) return HType.DOUBLE_OR_NULL; - if (other.isNumberOrNull()) return HType.NUMBER_OR_NULL; - if (other.isTop()) { - return other.canBeNull() ? this : HType.NUMBER; - } - if (other.canBeNull()) return HType.NULL; - return HType.CONFLICTING; - } -} - -class HNumberType extends HPrimitiveType { - const HNumberType(); - bool isNumber() => true; - bool isNumberOrNull() => true; - String toString() => "number"; - - DartType computeType(Compiler compiler) { - JavaScriptBackend backend = compiler.backend; - return backend.jsNumberClass.computeType(compiler); - } - - HType union(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.NUMBER; - if (other.isUnknown()) return HType.UNKNOWN; - if (other.isNumber()) return HType.NUMBER; - if (other.isNumberOrNull()) return HType.NUMBER_OR_NULL; - if (other.isNull()) return HType.NUMBER_OR_NULL; - return HType.UNKNOWN; - } - - HType intersection(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.CONFLICTING; - if (other.isUnknown()) return HType.NUMBER; - if (other.isNumber()) return other; - if (other.isIntegerOrNull()) return HType.INTEGER; - if (other.isDoubleOrNull()) return HType.DOUBLE; - if (other.isNumberOrNull()) return HType.NUMBER; - return HType.CONFLICTING; - } -} - -class HIntegerOrNullType extends HNumberOrNullType { - const HIntegerOrNullType(); - bool isIntegerOrNull() => true; - String toString() => "integer or null"; - - DartType computeType(Compiler compiler) { - JavaScriptBackend backend = compiler.backend; - return backend.jsIntClass.computeType(compiler); - } - - HType union(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.INTEGER_OR_NULL; - if (other.isUnknown()) return HType.UNKNOWN; - if (other.isIntegerOrNull()) return HType.INTEGER_OR_NULL; - if (other.isInteger()) return HType.INTEGER_OR_NULL; - if (other.isNumber()) return HType.NUMBER_OR_NULL; - if (other.isNumberOrNull()) return HType.NUMBER_OR_NULL; - if (other.isNull()) return HType.INTEGER_OR_NULL; - return HType.UNKNOWN; - } - - HType intersection(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.CONFLICTING; - if (other.isUnknown()) return HType.INTEGER_OR_NULL; - if (other.isInteger()) return HType.INTEGER; - if (other.isIntegerOrNull()) return HType.INTEGER_OR_NULL; - if (other.isDouble()) return HType.CONFLICTING; - if (other.isDoubleOrNull()) return HType.NULL; - if (other.isNumber()) return HType.INTEGER; - if (other.isNumberOrNull()) return HType.INTEGER_OR_NULL; - if (other.isTop()) { - return other.canBeNull() ? this : HType.INTEGER; - } - if (other.canBeNull()) return HType.NULL; - return HType.CONFLICTING; - } -} - -class HIntegerType extends HNumberType { - const HIntegerType(); - bool isInteger() => true; - bool isIntegerOrNull() => true; - String toString() => "integer"; - - DartType computeType(Compiler compiler) { - JavaScriptBackend backend = compiler.backend; - return backend.jsIntClass.computeType(compiler); - } - - HType union(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.INTEGER; - if (other.isUnknown()) return HType.UNKNOWN; - if (other.isInteger()) return HType.INTEGER; - if (other.isIntegerOrNull()) return HType.INTEGER_OR_NULL; - if (other.isNumber()) return HType.NUMBER; - if (other.isNumberOrNull()) return HType.NUMBER_OR_NULL; - if (other.isNull()) return HType.INTEGER_OR_NULL; - return HType.UNKNOWN; - } - - HType intersection(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.CONFLICTING; - if (other.isUnknown()) return HType.INTEGER; - if (other.isIntegerOrNull()) return HType.INTEGER; - if (other.isInteger()) return HType.INTEGER; - if (other.isDouble()) return HType.CONFLICTING; - if (other.isDoubleOrNull()) return HType.CONFLICTING; - if (other.isNumber()) return HType.INTEGER; - if (other.isNumberOrNull()) return HType.INTEGER; - return HType.CONFLICTING; - } -} - -class HDoubleOrNullType extends HNumberOrNullType { - const HDoubleOrNullType(); - bool isDoubleOrNull() => true; - String toString() => "double or null"; - - DartType computeType(Compiler compiler) { - JavaScriptBackend backend = compiler.backend; - return backend.jsDoubleClass.computeType(compiler); - } - - HType union(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.DOUBLE_OR_NULL; - if (other.isUnknown()) return HType.UNKNOWN; - if (other.isDoubleOrNull()) return HType.DOUBLE_OR_NULL; - if (other.isDouble()) return HType.DOUBLE_OR_NULL; - if (other.isNumber()) return HType.NUMBER_OR_NULL; - if (other.isNumberOrNull()) return HType.NUMBER_OR_NULL; - if (other.isNull()) return HType.DOUBLE_OR_NULL; - return HType.UNKNOWN; - } - - HType intersection(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.CONFLICTING; - if (other.isUnknown()) return HType.DOUBLE_OR_NULL; - if (other.isInteger()) return HType.CONFLICTING; - if (other.isIntegerOrNull()) return HType.NULL; - if (other.isDouble()) return HType.DOUBLE; - if (other.isDoubleOrNull()) return HType.DOUBLE_OR_NULL; - if (other.isNumber()) return HType.DOUBLE; - if (other.isNumberOrNull()) return HType.DOUBLE_OR_NULL; - if (other.isTop()) { - return other.canBeNull() ? this : HType.DOUBLE; - } - if (other.canBeNull()) return HType.NULL; - return HType.CONFLICTING; - } -} - -class HDoubleType extends HNumberType { - const HDoubleType(); - bool isDouble() => true; - bool isDoubleOrNull() => true; - String toString() => "double"; - - DartType computeType(Compiler compiler) { - JavaScriptBackend backend = compiler.backend; - return backend.jsDoubleClass.computeType(compiler); - } - - HType union(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.DOUBLE; - if (other.isUnknown()) return HType.UNKNOWN; - if (other.isDouble()) return HType.DOUBLE; - if (other.isDoubleOrNull()) return HType.DOUBLE_OR_NULL; - if (other.isNumber()) return HType.NUMBER; - if (other.isNumberOrNull()) return HType.NUMBER_OR_NULL; - if (other.isNull()) return HType.DOUBLE_OR_NULL; - return HType.UNKNOWN; - } - - HType intersection(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.CONFLICTING; - if (other.isUnknown()) return HType.DOUBLE; - if (other.isIntegerOrNull()) return HType.CONFLICTING; - if (other.isInteger()) return HType.CONFLICTING; - if (other.isDouble()) return HType.DOUBLE; - if (other.isDoubleOrNull()) return HType.DOUBLE; - if (other.isNumber()) return HType.DOUBLE; - if (other.isNumberOrNull()) return HType.DOUBLE; - return HType.CONFLICTING; - } -} - -class HIndexablePrimitiveType extends HPrimitiveType { - const HIndexablePrimitiveType(); - bool isIndexablePrimitive() => true; - String toString() => "indexable"; - - DartType computeType(Compiler compiler) { - // TODO(ngeoffray): Represent union types. - return null; - } - - HType union(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.INDEXABLE_PRIMITIVE; - if (other.isUnknown()) return HType.UNKNOWN; - if (other.isIndexablePrimitive()) return HType.INDEXABLE_PRIMITIVE; - if (other is HBoundedPotentialPrimitiveString) { - // TODO(ngeoffray): Represent union types. - return HType.UNKNOWN; - } - if (other is HBoundedPotentialPrimitiveArray) { - // TODO(ngeoffray): Represent union types. - return HType.UNKNOWN; - } - return HType.UNKNOWN; - } - - HType intersection(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.CONFLICTING; - if (other.isUnknown()) return HType.INDEXABLE_PRIMITIVE; - if (other.isIndexablePrimitive()) return other; - if (other is HBoundedPotentialPrimitiveString) return HType.STRING; - if (other is HBoundedPotentialPrimitiveArray) return HType.READABLE_ARRAY; - return HType.CONFLICTING; - } -} - -class HStringOrNullType extends HPrimitiveOrNullType { - const HStringOrNullType(); - bool isStringOrNull() => true; - String toString() => "String or null"; - - DartType computeType(Compiler compiler) { - JavaScriptBackend backend = compiler.backend; - return backend.jsStringClass.computeType(compiler); - } - - HType union(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.STRING_OR_NULL; - if (other.isUnknown()) return HType.UNKNOWN; - if (other.isString()) return HType.STRING_OR_NULL; - if (other.isStringOrNull()) return HType.STRING_OR_NULL; - if (other.isIndexablePrimitive()) { - // We don't have a type that represents the nullable indexable - // primitive. - return HType.UNKNOWN; - } - if (other is HBoundedPotentialPrimitiveString) { - if (other.canBeNull()) { - return other; - } else { - HBoundedType boundedType = other; - return new HBoundedPotentialPrimitiveString(boundedType.type, true); - } - } - if (other.isNull()) return HType.STRING_OR_NULL; - return HType.UNKNOWN; - } - - HType intersection(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.CONFLICTING; - if (other.isUnknown()) return HType.STRING_OR_NULL; - if (other.isString()) return HType.STRING; - if (other.isStringOrNull()) return HType.STRING_OR_NULL; - if (other.isArray()) return HType.CONFLICTING; - if (other.isIndexablePrimitive()) return HType.STRING; - if (other is HBoundedPotentialPrimitiveString) { - return other.canBeNull() ? HType.STRING_OR_NULL : HType.STRING; - } - if (other.isTop()) { - return other.canBeNull() ? this : HType.STRING; - } - if (other.canBeNull()) return HType.NULL; - return HType.CONFLICTING; - } -} - -class HStringType extends HIndexablePrimitiveType { - const HStringType(); - bool isString() => true; - bool isStringOrNull() => true; - String toString() => "String"; - - DartType computeType(Compiler compiler) { - JavaScriptBackend backend = compiler.backend; - return backend.jsStringClass.computeType(compiler); - } - - HType union(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.STRING; - if (other.isUnknown()) return HType.UNKNOWN; - if (other.isString()) return HType.STRING; - if (other.isStringOrNull()) return HType.STRING_OR_NULL; - if (other.isIndexablePrimitive()) return HType.INDEXABLE_PRIMITIVE; - if (other is HBoundedPotentialPrimitiveString) return other; - if (other.isNull()) return HType.STRING_OR_NULL; - return HType.UNKNOWN; - } - - HType intersection(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.CONFLICTING; - if (other.isUnknown()) return HType.STRING; - if (other.isString()) return HType.STRING; - if (other.isArray()) return HType.CONFLICTING; - if (other.isIndexablePrimitive()) return HType.STRING; - if (other.isStringOrNull()) return HType.STRING; - if (other is HBoundedPotentialPrimitiveString) return HType.STRING; - return HType.CONFLICTING; - } -} - -class HReadableArrayType extends HIndexablePrimitiveType { - const HReadableArrayType(); - bool isReadableArray() => true; - String toString() => "readable array"; - - DartType computeType(Compiler compiler) { - JavaScriptBackend backend = compiler.backend; - return backend.jsArrayClass.computeType(compiler); - } - - HType union(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.READABLE_ARRAY; - if (other.isUnknown()) return HType.UNKNOWN; - if (other.isReadableArray()) return HType.READABLE_ARRAY; - if (other.isIndexablePrimitive()) return HType.INDEXABLE_PRIMITIVE; - if (other is HBoundedPotentialPrimitiveArray) return other; - if (other.isNull()) { - // TODO(ngeoffray): This should be readable array or null. - return new HBoundedPotentialPrimitiveArray( - compiler.listClass.computeType(compiler), true); - } - return HType.UNKNOWN; - } - - HType intersection(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.CONFLICTING; - if (other.isUnknown()) return HType.READABLE_ARRAY; - if (other.isString()) return HType.CONFLICTING; - if (other.isReadableArray()) return other; - if (other.isIndexablePrimitive()) return HType.READABLE_ARRAY; - if (other is HBoundedPotentialPrimitiveArray) return HType.READABLE_ARRAY; - return HType.CONFLICTING; - } -} - -class HMutableArrayType extends HReadableArrayType { - const HMutableArrayType(); - bool isMutableArray() => true; - String toString() => "mutable array"; - - HType union(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.MUTABLE_ARRAY; - if (other.isUnknown()) return HType.UNKNOWN; - if (other.isMutableArray()) return HType.MUTABLE_ARRAY; - if (other.isReadableArray()) return HType.READABLE_ARRAY; - if (other.isIndexablePrimitive()) return HType.INDEXABLE_PRIMITIVE; - if (other is HBoundedPotentialPrimitiveArray) return other; - if (other.isNull()) { - // TODO(ngeoffray): This should be mutable array or null. - return new HBoundedPotentialPrimitiveArray( - compiler.listClass.computeType(compiler), true); - } - return HType.UNKNOWN; - } - - HType intersection(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.CONFLICTING; - if (other.isUnknown()) return HType.MUTABLE_ARRAY; - if (other.isMutableArray()) return other; - if (other.isString()) return HType.CONFLICTING; - if (other.isIndexablePrimitive()) return HType.MUTABLE_ARRAY; - if (other is HBoundedPotentialPrimitiveArray) return HType.MUTABLE_ARRAY; - return HType.CONFLICTING; - } -} - -class HFixedArrayType extends HMutableArrayType { - const HFixedArrayType(); - bool isFixedArray() => true; - String toString() => "fixed array"; - - HType union(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.FIXED_ARRAY; - if (other.isUnknown()) return HType.UNKNOWN; - if (other.isFixedArray()) return HType.FIXED_ARRAY; - if (other.isMutableArray()) return HType.MUTABLE_ARRAY; - if (other.isReadableArray()) return HType.READABLE_ARRAY; - if (other.isIndexablePrimitive()) return HType.INDEXABLE_PRIMITIVE; - if (other is HBoundedPotentialPrimitiveArray) return other; - if (other.isNull()) { - // TODO(ngeoffray): This should be fixed array or null. - return new HBoundedPotentialPrimitiveArray( - compiler.listClass.computeType(compiler), true); - } - return HType.UNKNOWN; - } - - HType intersection(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.CONFLICTING; - if (other.isUnknown()) return HType.FIXED_ARRAY; - if (other.isFixedArray()) return HType.FIXED_ARRAY; - if (other.isExtendableArray()) return HType.CONFLICTING; - if (other.isString()) return HType.CONFLICTING; - if (other.isIndexablePrimitive()) return HType.FIXED_ARRAY; - if (other is HBoundedPotentialPrimitiveArray) return HType.FIXED_ARRAY; - return HType.CONFLICTING; - } -} - -class HExtendableArrayType extends HMutableArrayType { - const HExtendableArrayType(); - bool isExtendableArray() => true; - String toString() => "extendable array"; - - HType union(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.EXTENDABLE_ARRAY; - if (other.isUnknown()) return HType.UNKNOWN; - if (other.isExtendableArray()) return HType.EXTENDABLE_ARRAY; - if (other.isMutableArray()) return HType.MUTABLE_ARRAY; - if (other.isReadableArray()) return HType.READABLE_ARRAY; - if (other.isIndexablePrimitive()) return HType.INDEXABLE_PRIMITIVE; - if (other is HBoundedPotentialPrimitiveArray) return other; - if (other.isNull()) { - // TODO(ngeoffray): This should be extendable array or null. - return new HBoundedPotentialPrimitiveArray( - compiler.listClass.computeType(compiler), true); - } - return HType.UNKNOWN; - } - - HType intersection(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.CONFLICTING; - if (other.isUnknown()) return HType.EXTENDABLE_ARRAY; - if (other.isExtendableArray()) return HType.EXTENDABLE_ARRAY; - if (other.isString()) return HType.CONFLICTING; - if (other.isFixedArray()) return HType.CONFLICTING; - if (other.isIndexablePrimitive()) return HType.EXTENDABLE_ARRAY; - if (other is HBoundedPotentialPrimitiveArray) return HType.EXTENDABLE_ARRAY; - return HType.CONFLICTING; - } -} - -class HBoundedType extends HType { - final DartType type; - final bool _canBeNull; - final bool _isExact; - - String toString() { - return 'BoundedType($type, canBeNull: $_canBeNull, isExact: $_isExact)'; - } - - bool canBeNull() => _canBeNull; - - bool isExact() => _isExact; - - const HBoundedType(DartType this.type, - [bool canBeNull = false, isExact = false]) - : _canBeNull = canBeNull, _isExact = isExact; - const HBoundedType.exact(DartType type) : this(type, false, true); - const HBoundedType.withNull(DartType type) : this(type, true, false); - const HBoundedType.nonNull(DartType type) : this(type); - - DartType computeType(Compiler compiler) => type; - - Element lookupMember(SourceString name) { - if (!isExact()) return null; - ClassElement classElement = type.element; - return classElement.lookupMember(name); - } - - HType intersection(HType other, Compiler compiler) { - assert(!(isExact() && canBeNull())); - if (other.isConflicting()) return HType.CONFLICTING; - if (other.isNull()) return canBeNull() ? HType.NULL : HType.CONFLICTING; - - if (other is HBoundedType) { - HBoundedType temp = other; - if (identical(this.type, temp.type)) { - // If the types are the same, we return the [HBoundedType] - // that has the most restrictive representation: if it's exact - // (eg cannot be a subtype), and if it cannot be null. - if (isExact()) { - return this; - } else if (other.isExact()) { - return other; - } else if (canBeNull()) { - return other; - } else { - return this; - } - // If one type is a subtype of the other, we return the former, - // which is the narrower type. - } else if (!type.isMalformed && !other.type.isMalformed) { - if (compiler.types.isSubtype(type, other.type)) { - return this; - } else if (compiler.types.isSubtype(other.type, type)) { - return other; - } - } - } - if (other.isUnknown()) return this; - if (other.canBeNull() && canBeNull()) return HType.NULL; - return HType.CONFLICTING; - } - - bool operator ==(HType other) { - if (other is !HBoundedType) return false; - HBoundedType bounded = other; - return (identical(type, bounded.type) - && identical(canBeNull(), bounded.canBeNull()) - && identical(isExact(), other.isExact())); - } - - HType union(HType other, Compiler compiler) { - if (other.isNull()) { - if (canBeNull()) { - return this; - } else { - return new HBoundedType.withNull(type); - } - } - if (other is HBoundedType) { - HBoundedType temp = other; - if (!identical(type, temp.type)) return HType.UNKNOWN; - if (isExact()) return other; - if (other.isExact()) return this; - return canBeNull() ? this : other; - } - if (other.isConflicting()) return this; - return HType.UNKNOWN; - } -} - -class HBoundedPotentialPrimitiveType extends HBoundedType { - final bool _isObject; - const HBoundedPotentialPrimitiveType(DartType type, - bool canBeNull, - this._isObject) - : super(type, canBeNull, false); - - String toString() { - return 'BoundedPotentialPrimitiveType($type, canBeNull: $_canBeNull)'; - } - - bool canBePrimitive() => true; - bool isTop() => _isObject; - - HType union(HType other, Compiler compiler) { - if (isTop()) { - // The union of the top type and another type is the top type. - if (!canBeNull() && other.canBeNull()) { - return new HBoundedPotentialPrimitiveType(type, true, true); - } else { - return this; - } - } else { - return super.union(other, compiler); - } - } - - HType intersection(HType other, Compiler compiler) { - if (isTop()) { - // The intersection of the top type and any other type is the other type. - // TODO(ngeoffray): Also update the canBeNull information. - return other; - } else { - return super.intersection(other, compiler); - } - } -} - -class HBoundedPotentialPrimitiveNumberOrString - extends HBoundedPotentialPrimitiveType { - const HBoundedPotentialPrimitiveNumberOrString(DartType type, bool canBeNull) - : super(type, canBeNull, false); - - HType union(HType other, Compiler compiler) { - if (other.isNumber()) return this; - if (other.isNumberOrNull()) { - if (canBeNull()) return this; - return new HBoundedPotentialPrimitiveNumberOrString(type, true); - } - - if (other.isString()) return this; - if (other.isStringOrNull()) { - if (canBeNull()) return this; - return new HBoundedPotentialPrimitiveNumberOrString(type, true); - } - - if (other.isNull()) { - if (canBeNull()) return this; - return new HBoundedPotentialPrimitiveNumberOrString(type, true); - } - - return super.union(other, compiler); - } - - HType intersection(HType other, Compiler compiler) { - if (other.isNumber()) return other; - if (other.isNumberOrNull()) { - if (!canBeNull()) return HType.NUMBER; - return other; - } - if (other.isString()) return other; - if (other.isStringOrNull()) { - if (!canBeNull()) return HType.STRING; - return other; - } - return super.intersection(other, compiler); - } -} - -class HBoundedPotentialPrimitiveArray extends HBoundedPotentialPrimitiveType { - const HBoundedPotentialPrimitiveArray(DartType type, bool canBeNull) - : super(type, canBeNull, false); - - HType union(HType other, Compiler compiler) { - if (other.isString()) return HType.UNKNOWN; - if (other.isReadableArray()) return this; - // TODO(ngeoffray): implement union types. - if (other.isIndexablePrimitive()) return HType.UNKNOWN; - if (other.isNull()) { - if (canBeNull()) { - return this; - } else { - return new HBoundedPotentialPrimitiveArray(type, true); - } - } - return super.union(other, compiler); - } - - HType intersection(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.CONFLICTING; - if (other.isString()) return HType.CONFLICTING; - if (other.isReadableArray()) return other; - if (other.isIndexablePrimitive()) return HType.READABLE_ARRAY; - return super.intersection(other, compiler); - } -} - -class HBoundedPotentialPrimitiveString extends HBoundedPotentialPrimitiveType { - const HBoundedPotentialPrimitiveString(DartType type, bool canBeNull) - : super(type, canBeNull, false); - - bool isPrimitiveOrNull() => true; - - HType union(HType other, Compiler compiler) { - if (other.isString()) return this; - if (other.isStringOrNull()) { - if (canBeNull()) { - return this; - } else { - return new HBoundedPotentialPrimitiveString(type, true); - } - } - if (other.isNull()) { - if (canBeNull()) { - return this; - } else { - return new HBoundedPotentialPrimitiveString(type, true); - } - } - // TODO(ngeoffray): implement union types. - if (other.isIndexablePrimitive()) return HType.UNKNOWN; - return super.union(other, compiler); - } - - HType intersection(HType other, Compiler compiler) { - if (other.isConflicting()) return HType.CONFLICTING; - if (other.isString()) return HType.STRING; - if (other.isStringOrNull()) { - return canBeNull() ? HType.STRING_OR_NULL : HType.STRING; - } - if (other.isReadableArray()) return HType.CONFLICTING; - if (other.isIndexablePrimitive()) return HType.STRING; - return super.intersection(other, compiler); - } -} - -class HTypeMap { - // Approximately 85% of methods in the sample "swarm" have less than - // 32 instructions. - static const int INITIAL_SIZE = 32; - - List<HType> _list = new List<HType>()..length = INITIAL_SIZE; - - operator [](HInstruction instruction) { - HType result; - if (instruction.id < _list.length) result = _list[instruction.id]; - if (result == null) return instruction.guaranteedType; - return result; - } - - operator []=(HInstruction instruction, HType value) { - int length = _list.length; - int id = instruction.id; - if (length <= id) { - if (id + 1 < length * 2) { - _list.length = length * 2; - } else { - _list.length = id + 1; - } - } - _list[id] = value; - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/types_propagation.dart b/pkgs/markdown/test/lib/src/compiler/implementation/ssa/types_propagation.dart deleted file mode 100644 index ee0f1a1..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/types_propagation.dart +++ /dev/null
@@ -1,210 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of ssa; - -class SsaTypePropagator extends HGraphVisitor implements OptimizationPhase { - - final Map<int, HInstruction> workmap; - final List<int> worklist; - final Map<HInstruction, Function> pendingOptimizations; - final HTypeMap types; - - final Compiler compiler; - String get name => 'type propagator'; - - SsaTypePropagator(this.compiler, this.types) - : workmap = new Map<int, HInstruction>(), - worklist = new List<int>(), - pendingOptimizations = new Map<HInstruction, Function>(); - - HType computeType(HInstruction instruction) { - if (instruction.hasGuaranteedType()) return instruction.guaranteedType; - return instruction.computeTypeFromInputTypes(types, compiler); - } - - // Re-compute and update the type of the instruction. Returns - // whether or not the type was changed. - bool updateType(HInstruction instruction) { - // The [updateType] method is invoked when one of the inputs of - // the instruction changes its type. That gives us a new - // opportunity to consider this instruction for optimizations. - considerForArgumentTypeOptimization(instruction); - // Compute old and new types. - HType oldType = types[instruction]; - HType newType = computeType(instruction); - // We unconditionally replace the propagated type with the new type. The - // computeType must make sure that we eventually reach a stable state. - types[instruction] = newType; - return oldType != newType; - } - - void considerForArgumentTypeOptimization(HInstruction instruction) { - // Update the pending optimizations map based on the potentially - // new types of the operands. If the operand types no longer allow - // us to optimize, we remove the pending optimization. - if (instruction is !HInvokeDynamicMethod) return; - HInvokeDynamicMethod invoke = instruction; - if (instruction.specializer is !BinaryArithmeticSpecializer) return; - HInstruction left = instruction.inputs[1]; - HInstruction right = instruction.inputs[2]; - if (left.isNumber(types) && !right.isNumber(types)) { - pendingOptimizations[instruction] = () { - // This callback function is invoked after we're done - // propagating types. The types shouldn't have changed. - assert(left.isNumber(types) && !right.isNumber(types)); - convertInput(instruction, right, HType.NUMBER); - }; - } else { - pendingOptimizations.remove(instruction); - } - } - - void visitGraph(HGraph graph) { - visitDominatorTree(graph); - processWorklist(); - } - - visitBasicBlock(HBasicBlock block) { - if (block.isLoopHeader()) { - block.forEachPhi((HPhi phi) { - // Set the initial type for the phi. We're not using the type - // the phi thinks it has because new optimizations may imply - // changing it. - // In theory we would need to mark - // the type of all other incoming edges as "unitialized" and take this - // into account when doing the propagation inside the phis. Just - // setting the propagated type is however easier. - types[phi] = types[phi.inputs[0]]; - addToWorkList(phi); - }); - } else { - block.forEachPhi((HPhi phi) { - if (updateType(phi)) { - addDependentInstructionsToWorkList(phi); - } - }); - } - - HInstruction instruction = block.first; - while (instruction != null) { - if (updateType(instruction)) { - addDependentInstructionsToWorkList(instruction); - } - instruction = instruction.next; - } - } - - void processWorklist() { - do { - while (!worklist.isEmpty) { - int id = worklist.removeLast(); - HInstruction instruction = workmap[id]; - assert(instruction != null); - workmap.remove(id); - if (updateType(instruction)) { - addDependentInstructionsToWorkList(instruction); - } - } - // While processing the optimizable arithmetic instructions, we - // may discover better type information for dominated users of - // replaced operands, so we may need to take another stab at - // emptying the worklist afterwards. - processPendingOptimizations(); - } while (!worklist.isEmpty); - } - - void addDependentInstructionsToWorkList(HInstruction instruction) { - for (int i = 0, length = instruction.usedBy.length; i < length; i++) { - // The non-speculative type propagator only propagates types forward. We - // thus only need to add the users of the [instruction] to the list. - addToWorkList(instruction.usedBy[i]); - } - } - - void addToWorkList(HInstruction instruction) { - final int id = instruction.id; - if (!workmap.containsKey(id)) { - worklist.add(id); - workmap[id] = instruction; - } - } - - void processPendingOptimizations() { - pendingOptimizations.forEach((instruction, action) => action()); - pendingOptimizations.clear(); - } - - void convertInput(HInstruction instruction, HInstruction input, HType type) { - HTypeConversion converted = - new HTypeConversion.argumentTypeCheck(type, input); - instruction.block.addBefore(instruction, converted); - Set<HInstruction> dominatedUsers = input.dominatedUsers(instruction); - for (HInstruction user in dominatedUsers) { - user.changeUse(input, converted); - addToWorkList(user); - } - } -} - -class SsaSpeculativeTypePropagator extends SsaTypePropagator { - final String name = 'speculative type propagator'; - SsaSpeculativeTypePropagator(Compiler compiler, HTypeMap types) - : super(compiler, types); - - void addDependentInstructionsToWorkList(HInstruction instruction) { - // The speculative type propagator propagates types forward and backward. - // Not only do we need to add the users of the [instruction] to the list. - // We also need to add the inputs fo the [instruction], since they might - // want to propagate the desired outgoing type. - for (int i = 0, length = instruction.usedBy.length; i < length; i++) { - addToWorkList(instruction.usedBy[i]); - } - for (int i = 0, length = instruction.inputs.length; i < length; i++) { - addToWorkList(instruction.inputs[i]); - } - } - - HType computeDesiredType(HInstruction instruction) { - HType desiredType = HType.UNKNOWN; - for (final user in instruction.usedBy) { - HType userType = - user.computeDesiredTypeForInput(instruction, types, compiler); - // Mainly due to the "if (true)" added by hackAroundPossiblyAbortingBody - // in builder.dart uninitialized variables will propagate a type of null - // which will result in a conflicting type when combined with a primitive - // type. Avoid this to improve generated code. - // TODO(sgjesse): Reconcider this when hackAroundPossiblyAbortingBody - // has been removed. - if (desiredType.isPrimitive() && userType == HType.NULL) continue; - desiredType = desiredType.intersection(userType, compiler); - // No need to continue if two users disagree on the type. - if (desiredType.isConflicting()) break; - } - return desiredType; - } - - HType computeType(HInstruction instruction) { - // Once we are in a conflicting state don't update the type anymore. - HType oldType = types[instruction]; - if (oldType.isConflicting()) return oldType; - - HType newType = super.computeType(instruction); - // [computeDesiredType] goes to all usedBys and lets them compute their - // desired type. By setting the [newType] here we give them more context to - // work with. - types[instruction] = newType; - HType desiredType = computeDesiredType(instruction); - // If the desired type is conflicting just return the computed type. - if (desiredType.isConflicting()) return newType; - // TODO(ngeoffray): Allow speculative optimizations on - // non-primitive types? - if (!desiredType.isPrimitive()) return newType; - return newType.intersection(desiredType, compiler); - } - - // Do not use speculative argument type optimization for now. - void considerForArgumentTypeOptimization(HInstruction instruction) { } - -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/validate.dart b/pkgs/markdown/test/lib/src/compiler/implementation/ssa/validate.dart deleted file mode 100644 index 5e9598e..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/validate.dart +++ /dev/null
@@ -1,181 +0,0 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of ssa; - -class HValidator extends HInstructionVisitor { - bool isValid = true; - HGraph graph; - - void visitGraph(HGraph visitee) { - graph = visitee; - visitDominatorTree(visitee); - } - - void markInvalid(String reason) { - print(reason); - isValid = false; - } - - // Note that during construction of the Ssa graph the basic blocks are - // not required to be valid yet. - void visitBasicBlock(HBasicBlock block) { - currentBlock = block; - if (!isValid) return; // Don't need to continue if we are already invalid. - - // Test that the last instruction is a branching instruction and that the - // basic block contains the branch-target. - if (block.first == null || block.last == null) { - markInvalid("empty block"); - } - if (block.last is !HControlFlow) { - markInvalid("block ends with non-tail node."); - } - if (block.last is HIf && block.successors.length != 2) { - markInvalid("If node without two successors"); - } - if (block.last is HConditionalBranch && block.successors.length != 2) { - markInvalid("Conditional node without two successors"); - } - if (block.last is HGoto && block.successors.length != 1) { - markInvalid("Goto node with not exactly one successor"); - } - if (block.last is HJump && block.successors.length != 1) { - markInvalid("Break or continue node without one successor"); - } - if (block.last is HReturn && - (block.successors.length != 1 || !block.successors[0].isExitBlock())) { - markInvalid("Return node with > 1 succesor or not going to exit-block"); - } - if (block.last is HExit && !block.successors.isEmpty) { - markInvalid("Exit block with successor"); - } - if (block.last is HThrow && !block.successors.isEmpty) { - markInvalid("Throw block with successor"); - } - - if (block.successors.isEmpty && - block.last is !HThrow && - !block.isExitBlock()) { - markInvalid("Non-exit or throw block without successor"); - } - - // Check that successors ids are always higher than the current one. - // TODO(floitsch): this is, of course, not true for back-branches. - if (block.id == null) markInvalid("block without id"); - for (HBasicBlock successor in block.successors) { - if (!isValid) break; - if (successor.id == null) markInvalid("successor without id"); - if (successor.id <= block.id && !successor.isLoopHeader()) { - markInvalid("successor with lower id, but not a loop-header"); - } - } - - // Check that the entries in the dominated-list are sorted. - int lastId = 0; - for (HBasicBlock dominated in block.dominatedBlocks) { - if (!isValid) break; - if (!identical(dominated.dominator, block)) { - markInvalid("dominated block not pointing back"); - } - if (dominated.id == null || dominated.id <= lastId) { - markInvalid("dominated.id == null or dominated has <= id"); - } - lastId = dominated.id; - } - - if (!isValid) return; - block.forEachPhi(visitInstruction); - - // Check that the blocks of the parameters of a phi are dominating the - // corresponding predecessor block. Note that a block dominates - // itself. - block.forEachPhi((HPhi phi) { - for (int i = 0; i < phi.inputs.length; i++) { - HInstruction input = phi.inputs[i]; - if (!input.block.dominates(block.predecessors[i])) { - markInvalid("Definition does not dominate use"); - } - } - }); - - // Check that the blocks of the inputs of an instruction dominate the - // instruction's block. - block.forEachInstruction((HInstruction instruction) { - for (HInstruction input in instruction.inputs) { - if (!input.block.dominates(block)) { - markInvalid("Definition does not dominate use"); - } - } - }); - - super.visitBasicBlock(block); - } - - /** Returns how often [instruction] is contained in [instructions]. */ - static int countInstruction(List<HInstruction> instructions, - HInstruction instruction) { - int result = 0; - for (int i = 0; i < instructions.length; i++) { - if (identical(instructions[i], instruction)) result++; - } - return result; - } - - /** - * Returns true if the predicate returns true for every instruction in the - * list. The argument to [f] is an instruction with the count of how often - * it appeared in the list [instructions]. - */ - static bool everyInstruction(List<HInstruction> instructions, Function f) { - var copy = new List<HInstruction>.from(instructions); - // TODO(floitsch): there is currently no way to sort HInstructions before - // we have assigned an ID. The loop is therefore O(n^2) for now. - for (int i = 0; i < copy.length; i++) { - var current = copy[i]; - if (current == null) continue; - int count = 1; - for (int j = i + 1; j < copy.length; j++) { - if (identical(copy[j], current)) { - copy[j] = null; - count++; - } - } - if (!f(current, count)) return false; - } - return true; - } - - void visitInstruction(HInstruction instruction) { - // Verifies that we are in the use list of our inputs. - bool hasCorrectInputs() { - bool inBasicBlock = instruction.isInBasicBlock(); - return everyInstruction(instruction.inputs, (input, count) { - if (inBasicBlock) { - return countInstruction(input.usedBy, instruction) == count; - } else { - return countInstruction(input.usedBy, instruction) == 0; - } - }); - } - - // Verifies that all our uses have us in their inputs. - bool hasCorrectUses() { - if (!instruction.isInBasicBlock()) return true; - return everyInstruction(instruction.usedBy, (use, count) { - return countInstruction(use.inputs, instruction) == count; - }); - } - - if (!identical(instruction.block, currentBlock)) { - markInvalid("Instruction in wrong block"); - } - if (!hasCorrectInputs()) { - markInvalid("Incorrect inputs"); - } - if (!hasCorrectUses()) { - markInvalid("Incorrect uses"); - } - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/value_range_analyzer.dart b/pkgs/markdown/test/lib/src/compiler/implementation/ssa/value_range_analyzer.dart deleted file mode 100644 index c28d5c4..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/value_range_analyzer.dart +++ /dev/null
@@ -1,996 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of ssa; - - -class ValueRangeInfo { - final ConstantSystem constantSystem; - - IntValue intZero; - IntValue intOne; - - ValueRangeInfo(this.constantSystem) { - intZero = newIntValue(0); - intOne = newIntValue(1); - } - - Value newIntValue(int value) { - return new IntValue(value, this); - } - - Value newInstructionValue(HInstruction instruction) { - return new InstructionValue(instruction, this); - } - - Value newLengthValue(HInstruction instruction) { - return new LengthValue(instruction, this); - } - - Value newAddValue(Value left, Value right) { - return new AddValue(left, right, this); - } - - Value newSubtractValue(Value left, Value right) { - return new SubtractValue(left, right, this); - } - - Value newNegateValue(Value value) { - return new NegateValue(value, this); - } - - Range newRange(Value low, Value up) { - return new Range(low, up, this); - } - - Range newUnboundRange() { - return new Range.unbound(this); - } - - Range newNormalizedRange(Value low, Value up) { - return new Range.normalize(low, up, this); - } -} - -/** - * A [Value] represents both symbolic values like the value of a - * parameter, or the length of an array, and concrete values, like - * constants. - */ -abstract class Value { - final ValueRangeInfo info; - const Value([this.info = null]); - - Value operator +(Value other) => const UnknownValue(); - Value operator -(Value other) => const UnknownValue(); - Value operator -() => const UnknownValue(); - Value operator &(Value other) => const UnknownValue(); - - Value min(Value other) { - if (this == other) return this; - if (other == const MinIntValue()) return other; - if (other == const MaxIntValue()) return this; - Value value = this - other; - if (value.isPositive) return other; - if (value.isNegative) return this; - return const UnknownValue(); - } - - Value max(Value other) { - if (this == other) return this; - if (other == const MinIntValue()) return this; - if (other == const MaxIntValue()) return other; - Value value = this - other; - if (value.isPositive) return this; - if (value.isNegative) return other; - return const UnknownValue(); - } - - bool get isNegative => false; - bool get isPositive => false; - bool get isZero => false; -} - -/** - * An [IntValue] contains a constant integer value. - */ -class IntValue extends Value { - final int value; - - const IntValue(this.value, info) : super(info); - - Value operator +(other) { - if (other.isZero) return this; - if (other is !IntValue) return other + this; - ConstantSystem constantSystem = info.constantSystem; - var constant = constantSystem.add.fold( - constantSystem.createInt(value), constantSystem.createInt(other.value)); - if (!constant.isInt()) return const UnknownValue(); - return info.newIntValue(constant.value); - } - - Value operator -(other) { - if (other.isZero) return this; - if (other is !IntValue) return -other + this; - ConstantSystem constantSystem = info.constantSystem; - var constant = constantSystem.subtract.fold( - constantSystem.createInt(value), constantSystem.createInt(other.value)); - if (!constant.isInt()) return const UnknownValue(); - return info.newIntValue(constant.value); - } - - Value operator -() { - if (isZero) return this; - ConstantSystem constantSystem = info.constantSystem; - var constant = constantSystem.negate.fold( - constantSystem.createInt(value)); - if (!constant.isInt()) return const UnknownValue(); - return info.newIntValue(constant.value); - } - - Value operator &(other) { - if (other is !IntValue) return const UnknownValue(); - ConstantSystem constantSystem = info.constantSystem; - var constant = constantSystem.bitAnd.fold( - constantSystem.createInt(value), constantSystem.createInt(other.value)); - return info.newIntValue(constant.value); - } - - Value min(other) { - if (other is !IntValue) return other.min(this); - return this.value < other.value ? this : other; - } - - Value max(other) { - if (other is !IntValue) return other.max(this); - return this.value < other.value ? other : this; - } - - bool operator ==(other) { - if (other is !IntValue) return false; - return this.value == other.value; - } - - String toString() => 'IntValue $value'; - bool get isNegative => value < 0; - bool get isPositive => value >= 0; - bool get isZero => value == 0; -} - -/** - * The [MaxIntValue] represents the maximum value an integer can have, - * which is currently +infinity. - */ -class MaxIntValue extends Value { - const MaxIntValue() : super(null); - Value operator +(Value other) => this; - Value operator -(Value other) => this; - Value operator -() => const MinIntValue(); - Value min(Value other) => other; - Value max(Value other) => this; - String toString() => 'Max'; - bool get isNegative => false; - bool get isPositive => true; -} - -/** - * The [MinIntValue] represents the minimum value an integer can have, - * which is currently -infinity. - */ -class MinIntValue extends Value { - const MinIntValue() : super(null); - Value operator +(Value other) => this; - Value operator -(Value other) => this; - Value operator -() => const MaxIntValue(); - Value min(Value other) => this; - Value max(Value other) => other; - String toString() => 'Min'; - bool get isNegative => true; - bool get isPositive => false; -} - -/** - * The [UnknownValue] is the sentinel in our analysis to mark an - * operation that could not be done because of too much complexity. - */ -class UnknownValue extends Value { - const UnknownValue() : super(null); - Value operator +(Value other) => const UnknownValue(); - Value operator -(Value other) => const UnknownValue(); - Value operator -() => const UnknownValue(); - Value min(Value other) => const UnknownValue(); - Value max(Value other) => const UnknownValue(); - bool get isNegative => false; - bool get isPositive => false; - String toString() => 'Unknown'; -} - -/** - * A symbolic value representing an [HInstruction]. - */ -class InstructionValue extends Value { - final HInstruction instruction; - InstructionValue(this.instruction, info) : super(info); - - bool operator ==(other) { - if (other is !InstructionValue) return false; - return this.instruction == other.instruction; - } - - Value operator +(Value other) { - if (other.isZero) return this; - if (other is IntValue) { - if (other.isNegative) { - return info.newSubtractValue(this, -other); - } - return info.newAddValue(this, other); - } - if (other is InstructionValue) { - return info.newAddValue(this, other); - } - return other + this; - } - - Value operator -(Value other) { - if (other.isZero) return this; - if (this == other) return info.intZero; - if (other is IntValue) { - if (other.isNegative) { - return info.newAddValue(this, -other); - } - return info.newSubtractValue(this, other); - } - if (other is InstructionValue) { - return info.newSubtractValue(this, other); - } - return -other + this; - } - - Value operator -() { - return info.newNegateValue(this); - } - - bool get isNegative => false; - bool get isPositive => false; - - String toString() => 'Instruction: $instruction'; -} - -/** - * Special value for instructions that represent the length of an - * array. The difference with an [InstructionValue] is that we know - * the value is positive. - */ -class LengthValue extends InstructionValue { - LengthValue(HInstruction instruction, info) : super(instruction, info); - bool get isPositive => true; - String toString() => 'Length: $instruction'; -} - -/** - * Represents a binary operation on two [Value], where the operation - * did not yield a canonical value. - */ -class BinaryOperationValue extends Value { - final Value left; - final Value right; - BinaryOperationValue(this.left, this.right, info) : super(info); -} - -class AddValue extends BinaryOperationValue { - AddValue(left, right, info) : super(left, right, info); - - bool operator ==(other) { - if (other is !AddValue) return false; - return (left == other.left && right == other.right) - || (left == other.right && right == other.left); - } - - Value operator -() => -left - right; - - Value operator +(Value other) { - if (other.isZero) return this; - Value value = left + other; - if (value != const UnknownValue() && value is! BinaryOperationValue) { - return value + right; - } - // If the result is not simple enough, we try the same approach - // with [right]. - value = right + other; - if (value != const UnknownValue() && value is! BinaryOperationValue) { - return left + value; - } - return const UnknownValue(); - } - - Value operator -(Value other) { - if (other.isZero) return this; - Value value = left - other; - if (value != const UnknownValue() && value is! BinaryOperationValue) { - return value + right; - } - // If the result is not simple enough, we try the same approach - // with [right]. - value = right - other; - if (value != const UnknownValue() && value is! BinaryOperationValue) { - return left + value; - } - return const UnknownValue(); - } - - bool get isNegative => left.isNegative && right.isNegative; - bool get isPositive => left.isPositive && right.isPositive; - String toString() => '$left + $right'; -} - -class SubtractValue extends BinaryOperationValue { - SubtractValue(left, right, info) : super(left, right, info); - - bool operator ==(other) { - if (other is !SubtractValue) return false; - return left == other.left && right == other.right; - } - - Value operator -() => right - left; - - Value operator +(Value other) { - if (other.isZero) return this; - Value value = left + other; - if (value != const UnknownValue() && value is! BinaryOperationValue) { - return value - right; - } - // If the result is not simple enough, we try the same approach - // with [right]. - value = other - right; - if (value != const UnknownValue() && value is! BinaryOperationValue) { - return left + value; - } - return const UnknownValue(); - } - - Value operator -(Value other) { - if (other.isZero) return this; - Value value = left - other; - if (value != const UnknownValue() && value is! BinaryOperationValue) { - return value - right; - } - // If the result is not simple enough, we try the same approach - // with [right]. - value = right + other; - if (value != const UnknownValue() && value is! BinaryOperationValue) { - return left - value; - } - return const UnknownValue(); - } - - bool get isNegative => left.isNegative && right.isPositive; - bool get isPositive => left.isPositive && right.isNegative; - String toString() => '$left - $right'; -} - -class NegateValue extends Value { - final Value value; - NegateValue(this.value, info) : super(info); - - bool operator ==(other) { - if (other is !NegateValue) return false; - return value == other.value; - } - - Value operator +(other) { - if (other.isZero) return this; - if (other == value) return info.intZero; - if (other is NegateValue) return this - other.value; - if (other is IntValue) { - if (other.isNegative) { - return info.newSubtractValue(this, -other); - } - return info.newSubtractValue(other, value); - } - if (other is InstructionValue) { - return info.newSubtractValue(other, value); - } - return other - value; - } - - Value operator &(Value other) => const UnknownValue(); - - Value operator -(other) { - if (other.isZero) return this; - if (other is IntValue) { - if (other.isNegative) { - return info.newSubtractValue(-other, value); - } - return info.newSubtractValue(this, other); - } - if (other is InstructionValue) { - return info.newSubtractValue(this, other); - } - if (other is NegateValue) return this + other.value; - return -other - value; - } - - Value operator -() => value; - - bool get isNegative => value.isPositive; - bool get isPositive => value.isNegative; - String toString() => '-$value'; -} - -/** - * A [Range] represents the possible integer values an instruction - * can have, from its [lower] bound to its [upper] bound, both - * included. - */ -class Range { - final Value lower; - final Value upper; - final ValueRangeInfo info; - Range(this.lower, this.upper, this.info); - - Range.unbound(info) : this(const MinIntValue(), const MaxIntValue(), info); - - /** - * Checks if the given values are unknown, and creates a - * range that does not have any unknown values. - */ - Range.normalize(Value low, Value up, info) : this( - low == const UnknownValue() ? const MinIntValue() : low, - up == const UnknownValue() ? const MaxIntValue() : up, - info); - - Range union(Range other) { - return info.newNormalizedRange( - lower.min(other.lower), upper.max(other.upper)); - } - - intersection(Range other) { - Value low = lower.max(other.lower); - Value up = upper.min(other.upper); - // If we could not compute max or min, pick a value in the two - // ranges, with priority to [IntValue]s because they are simpler. - if (low == const UnknownValue()) { - if (lower is IntValue) low = lower; - else if (other.lower is IntValue) low = other.lower; - else low = lower; - } - if (up == const UnknownValue()) { - if (upper is IntValue) up = upper; - else if (other.upper is IntValue) up = other.upper; - else up = upper; - } - return info.newRange(low, up); - } - - Range operator +(Range other) { - return info.newNormalizedRange(lower + other.lower, upper + other.upper); - } - - Range operator -(Range other) { - return info.newNormalizedRange(lower - other.upper, upper - other.lower); - } - - Range operator -() { - return info.newNormalizedRange(-upper, -lower); - } - - Range operator &(Range other) { - if (isSingleValue - && other.isSingleValue - && lower is IntValue - && other.lower is IntValue) { - return info.newRange(lower & other.lower, upper & other.upper); - } - if (isPositive && other.isPositive) { - Value up = upper.min(other.upper); - if (up == const UnknownValue()) { - // If we could not find a trivial bound, just try to use the - // one that is an int. - up = upper is IntValue ? upper : other.upper; - // Make sure we get the same upper bound, whether it's a & b - // or b & a. - if (up is! IntValue && upper != other.upper) up = const MaxIntValue(); - } - return info.newRange(info.intZero, up); - } else if (isPositive) { - return info.newRange(info.intZero, upper); - } else if (other.isPositive) { - return info.newRange(info.intZero, other.upper); - } else { - return info.newUnboundRange(); - } - } - - bool operator ==(other) { - if (other is! Range) return false; - return other.lower == lower && other.upper == upper; - } - - bool operator <(Range other) { - return upper != other.lower && upper.min(other.lower) == upper; - } - - bool operator >(Range other) { - return lower != other.upper && lower.max(other.upper) == lower; - } - - bool operator <=(Range other) { - return upper.min(other.lower) == upper; - } - - bool operator >=(Range other) { - return lower.max(other.upper) == lower; - } - - bool get isNegative => upper.isNegative; - bool get isPositive => lower.isPositive; - bool get isSingleValue => lower == upper; - - String toString() => '[$lower, $upper]'; -} - -/** - * Visits the graph in dominator order, and computes value ranges for - * integer instructions. While visiting the graph, this phase also - * removes unnecessary bounds checks, and comparisons that are proven - * to be true or false. - */ -class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase { - String get name => 'SSA value range builder'; - - /** - * List of [HRangeConversion] instructions created by the phase. We - * save them here in order to remove them once the phase is done. - */ - final List<HRangeConversion> conversions = <HRangeConversion>[]; - - /** - * Value ranges for integer instructions. This map gets populated by - * the dominator tree visit. - */ - final Map<HInstruction, Range> ranges = new Map<HInstruction, Range>(); - - final ConstantSystem constantSystem; - final HTypeMap types; - final ValueRangeInfo info; - - CodegenWorkItem work; - HGraph graph; - - SsaValueRangeAnalyzer(constantSystem, this.types, this.work) - : info = new ValueRangeInfo(constantSystem), - this.constantSystem = constantSystem; - - void visitGraph(HGraph graph) { - this.graph = graph; - visitDominatorTree(graph); - // We remove the range conversions after visiting the graph so - // that the graph does not get polluted with these instructions - // only necessary for this phase. - removeRangeConversion(); - } - - void removeRangeConversion() { - conversions.forEach((HRangeConversion instruction) { - instruction.block.rewrite(instruction, instruction.inputs[0]);; - instruction.block.remove(instruction); - }); - } - - void visitBasicBlock(HBasicBlock block) { - - void visit(HInstruction instruction) { - Range range = instruction.accept(this); - if (instruction.isInteger(types)) { - assert(range != null); - ranges[instruction] = range; - } - } - - block.forEachPhi(visit); - block.forEachInstruction(visit); - } - - Range visitInstruction(HInstruction instruction) { - return info.newUnboundRange(); - } - - Range visitParameterValue(HParameterValue parameter) { - if (!parameter.isInteger(types)) return info.newUnboundRange(); - Value value = info.newInstructionValue(parameter); - return info.newRange(value, value); - } - - Range visitPhi(HPhi phi) { - if (!phi.isInteger(types)) return info.newUnboundRange(); - if (phi.block.isLoopHeader()) { - Range range = tryInferLoopPhiRange(phi); - if (range == null) return info.newUnboundRange(); - return range; - } - - Range range = ranges[phi.inputs[0]]; - for (int i = 1; i < phi.inputs.length; i++) { - range = range.union(ranges[phi.inputs[i]]); - } - return range; - } - - Range tryInferLoopPhiRange(HPhi phi) { - HInstruction update = phi.inputs[1]; - return update.accept(new LoopUpdateRecognizer(phi, ranges, types, info)); - } - - Range visitConstant(HConstant constant) { - if (!constant.isInteger(types)) return info.newUnboundRange(); - IntConstant constantInt = constant.constant; - Value value = info.newIntValue(constantInt.value); - return info.newRange(value, value); - } - - Range visitFieldGet(HFieldGet fieldGet) { - if (!fieldGet.isInteger(types)) return info.newUnboundRange(); - if (!fieldGet.receiver.isIndexablePrimitive(types)) { - return visitInstruction(fieldGet); - } - LengthValue value = info.newLengthValue(fieldGet); - // We know this range is above zero. To simplify the analysis, we - // put the zero value as the lower bound of this range. This - // allows to easily remove the second bound check in the following - // expression: a[1] + a[0]. - return info.newRange(info.intZero, value); - } - - Range visitBoundsCheck(HBoundsCheck check) { - // Save the next instruction, in case the check gets removed. - HInstruction next = check.next; - Range indexRange = ranges[check.index]; - Range lengthRange = ranges[check.length]; - - // Check if the index is strictly below the upper bound of the length - // range. - Value maxIndex = lengthRange.upper - info.intOne; - bool belowLength = maxIndex != const MaxIntValue() - && indexRange.upper.min(maxIndex) == indexRange.upper; - - // Check if the index is strictly below the lower bound of the length - // range. - belowLength = belowLength - || (indexRange.upper != lengthRange.lower - && indexRange.upper.min(lengthRange.lower) == indexRange.upper); - if (indexRange.isPositive && belowLength) { - check.block.rewrite(check, check.index); - check.block.remove(check); - } else if (indexRange.isNegative || lengthRange < indexRange) { - check.staticChecks = HBoundsCheck.ALWAYS_FALSE; - // The check is always false, and whatever instruction it - // dominates is dead code. - return indexRange; - } else if (indexRange.isPositive) { - check.staticChecks = HBoundsCheck.ALWAYS_ABOVE_ZERO; - } else if (belowLength) { - check.staticChecks = HBoundsCheck.ALWAYS_BELOW_LENGTH; - } - - if (indexRange.isPositive) { - // If the test passes, we know the lower bound of the length is - // greater or equal than the lower bound of the index. - Value low = lengthRange.lower.max(indexRange.lower); - if (low != const UnknownValue()) { - HInstruction instruction = - createRangeConversion(next, check.length); - ranges[instruction] = info.newRange(low, lengthRange.upper); - } - } - - if (!belowLength) { - // Update the range of the index if using the maximum index - // narrows it. - Range newIndexRange = indexRange.intersection( - info.newRange(info.intZero, maxIndex)); - if (indexRange == newIndexRange) return indexRange; - HInstruction instruction = createRangeConversion(next, check.index); - ranges[instruction] = newIndexRange; - return newIndexRange; - } - - return indexRange; - } - - Range visitRelational(HRelational relational) { - HInstruction right = relational.right; - HInstruction left = relational.left; - if (!left.isInteger(types)) return info.newUnboundRange(); - if (!right.isInteger(types)) return info.newUnboundRange(); - BinaryOperation operation = relational.operation(constantSystem); - Range rightRange = ranges[relational.right]; - Range leftRange = ranges[relational.left]; - - if (relational is HIdentity) { - handleEqualityCheck(relational); - } else if (operation.apply(leftRange, rightRange)) { - relational.block.rewrite( - relational, graph.addConstantBool(true, constantSystem)); - relational.block.remove(relational); - } else if (reverseOperation(operation).apply(leftRange, rightRange)) { - relational.block.rewrite( - relational, graph.addConstantBool(false, constantSystem)); - relational.block.remove(relational); - } - return info.newUnboundRange(); - } - - void handleEqualityCheck(HRelational node) { - Range right = ranges[node.right]; - Range left = ranges[node.left]; - if (left.isSingleValue && right.isSingleValue && left == right) { - node.block.rewrite( - node, graph.addConstantBool(true, constantSystem)); - node.block.remove(node); - } - } - - Range handleBinaryOperation(HBinaryArithmetic instruction) { - if (!instruction.isInteger(types)) return info.newUnboundRange(); - return instruction.operation(constantSystem).apply( - ranges[instruction.left], ranges[instruction.right]); - } - - Range visitAdd(HAdd add) { - return handleBinaryOperation(add); - } - - Range visitSubtract(HSubtract sub) { - return handleBinaryOperation(sub); - } - - Range visitBitAnd(HBitAnd node) { - if (!node.isInteger(types)) return info.newUnboundRange(); - HInstruction right = node.right; - HInstruction left = node.left; - if (left.isInteger(types) && right.isInteger(types)) { - return ranges[left] & ranges[right]; - } - - Range tryComputeRange(HInstruction instruction) { - Range range = ranges[instruction]; - if (range.isPositive) { - return info.newRange(info.intZero, range.upper); - } else if (range.isNegative) { - return info.newRange(range.lower, info.intZero); - } - return info.newUnboundRange(); - } - - if (left.isInteger(types)) { - return tryComputeRange(left); - } else if (right.isInteger(types)) { - return tryComputeRange(right); - } - return info.newUnboundRange(); - } - - Range visitCheck(HCheck instruction) { - if (ranges[instruction.checkedInput] == null) { - return info.newUnboundRange(); - } - return ranges[instruction.checkedInput]; - } - - HInstruction createRangeConversion(HInstruction cursor, - HInstruction instruction) { - HRangeConversion newInstruction = new HRangeConversion(instruction); - conversions.add(newInstruction); - cursor.block.addBefore(cursor, newInstruction); - // Update the users of the instruction dominated by [cursor] to - // use the new instruction, that has an narrower range. - Set<HInstruction> dominatedUsers = instruction.dominatedUsers(cursor); - for (HInstruction user in dominatedUsers) { - user.changeUse(instruction, newInstruction); - } - return newInstruction; - } - - static BinaryOperation reverseOperation(BinaryOperation operation) { - if (operation == const LessOperation()) { - return const GreaterEqualOperation(); - } else if (operation == const LessEqualOperation()) { - return const GreaterOperation(); - } else if (operation == const GreaterOperation()) { - return const LessEqualOperation(); - } else if (operation == const GreaterEqualOperation()) { - return const LessOperation(); - } else { - return null; - } - } - - Range computeConstrainedRange(BinaryOperation operation, - Range leftRange, - Range rightRange) { - Range range; - if (operation == const LessOperation()) { - range = info.newRange( - const MinIntValue(), rightRange.upper - info.intOne); - } else if (operation == const LessEqualOperation()) { - range = info.newRange(const MinIntValue(), rightRange.upper); - } else if (operation == const GreaterOperation()) { - range = info.newRange( - rightRange.lower + info.intOne, const MaxIntValue()); - } else if (operation == const GreaterEqualOperation()) { - range = info.newRange(rightRange.lower, const MaxIntValue()); - } else { - range = info.newUnboundRange(); - } - return range.intersection(leftRange); - } - - Range visitConditionalBranch(HConditionalBranch branch) { - var condition = branch.condition; - // TODO(ngeoffray): Handle complex conditions. - if (condition is !HRelational) return info.newUnboundRange(); - if (condition is HIdentity) return info.newUnboundRange(); - HInstruction right = condition.right; - HInstruction left = condition.left; - if (!left.isInteger(types)) return info.newUnboundRange(); - if (!right.isInteger(types)) return info.newUnboundRange(); - - Range rightRange = ranges[right]; - Range leftRange = ranges[left]; - Operation operation = condition.operation(constantSystem); - Operation reverse = reverseOperation(operation); - // Only update the true branch if this block is the only - // predecessor. - if (branch.trueBranch.predecessors.length == 1) { - assert(branch.trueBranch.predecessors[0] == branch.block); - // Update the true branch to use narrower ranges for [left] and - // [right]. - Range range = computeConstrainedRange(operation, leftRange, rightRange); - if (leftRange != range) { - HInstruction instruction = - createRangeConversion(branch.trueBranch.first, left); - ranges[instruction] = range; - } - - range = computeConstrainedRange(reverse, rightRange, leftRange); - if (rightRange != range) { - HInstruction instruction = - createRangeConversion(branch.trueBranch.first, right); - ranges[instruction] = range; - } - } - - // Only update the false branch if this block is the only - // predecessor. - if (branch.falseBranch.predecessors.length == 1) { - assert(branch.falseBranch.predecessors[0] == branch.block); - // Update the false branch to use narrower ranges for [left] and - // [right]. - Range range = computeConstrainedRange(reverse, leftRange, rightRange); - if (leftRange != range) { - HInstruction instruction = - createRangeConversion(branch.falseBranch.first, left); - ranges[instruction] = range; - } - - range = computeConstrainedRange(operation, rightRange, leftRange); - if (rightRange != range) { - HInstruction instruction = - createRangeConversion(branch.falseBranch.first, right); - ranges[instruction] = range; - } - } - - return info.newUnboundRange(); - } - - Range visitRangeConversion(HRangeConversion conversion) { - return ranges[conversion]; - } -} - -/** - * Recognizes a number of patterns in a loop update instruction and - * tries to infer a range for the loop phi. - */ -class LoopUpdateRecognizer extends HBaseVisitor { - final HPhi loopPhi; - final Map<HInstruction, Range> ranges; - final HTypeMap types; - final ValueRangeInfo info; - LoopUpdateRecognizer(this.loopPhi, this.ranges, this.types, this.info); - - Range visitAdd(HAdd operation) { - Range range = getRangeForRecognizableOperation(operation); - if (range == null) return info.newUnboundRange(); - Range initial = ranges[loopPhi.inputs[0]]; - if (range.isPositive) { - return info.newRange(initial.lower, const MaxIntValue()); - } else if (range.isNegative) { - return info.newRange(const MinIntValue(), initial.upper); - } - return info.newUnboundRange(); - } - - Range visitSubtract(HSubtract operation) { - Range range = getRangeForRecognizableOperation(operation); - if (range == null) return info.newUnboundRange(); - Range initial = ranges[loopPhi.inputs[0]]; - if (range.isPositive) { - return info.newRange(const MinIntValue(), initial.upper); - } else if (range.isNegative) { - return info.newRange(initial.lower, const MaxIntValue()); - } - return info.newUnboundRange(); - } - - Range visitPhi(HPhi phi) { - Range phiRange; - for (HInstruction input in phi.inputs) { - HInstruction instruction = unwrap(input); - // If one of the inputs is the loop phi, then we're only - // interested in the other inputs: a loop phi feeding itself means - // it is not being updated. - if (instruction == loopPhi) continue; - - // If another loop phi is involved, it's too complex to analyze. - if (instruction is HPhi && instruction.block.isLoopHeader()) return null; - - Range inputRange = instruction.accept(this); - if (inputRange == null) return null; - if (phiRange == null) { - phiRange = inputRange; - } else { - phiRange = phiRange.union(inputRange); - } - } - return phiRange; - } - - /** - * If [operation] is recognizable, returns the inferred range. - * Otherwise returns [null]. - */ - Range getRangeForRecognizableOperation(HBinaryArithmetic operation) { - if (!operation.left.isInteger(types)) return null; - if (!operation.right.isInteger(types)) return null; - HInstruction left = unwrap(operation.left); - HInstruction right = unwrap(operation.right); - // We only recognize operations that operate on the loop phi. - bool isLeftLoopPhi = (left == loopPhi); - bool isRightLoopPhi = (right == loopPhi); - if (!isLeftLoopPhi && !isRightLoopPhi) return null; - - var other = isLeftLoopPhi ? right : left; - // If the analysis already computed range for the update, use it. - if (ranges[other] != null) return ranges[other]; - - // We currently only handle constants in updates if the - // update does not have a range. - if (other.isConstant()) { - Value value = info.newIntValue(other.constant.value); - return info.newRange(value, value); - } - return null; - } - - /** - * [HCheck] instructions may check the loop phi. Since we only - * recognize updates on the loop phi, we must [unwrap] the [HCheck] - * instruction to check if it references the loop phi. - */ - HInstruction unwrap(instruction) { - if (instruction is HCheck) return unwrap(instruction.checkedInput); - // [HPhi] might have two different [HCheck] instructions as - // inputs, checking the same instruction. - if (instruction is HPhi && !instruction.block.isLoopHeader()) { - HInstruction result = unwrap(instruction.inputs[0]); - for (int i = 1; i < instruction.inputs.length; i++) { - if (result != unwrap(instruction.inputs[i])) return instruction; - } - return result; - } - return instruction; - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/value_set.dart b/pkgs/markdown/test/lib/src/compiler/implementation/ssa/value_set.dart deleted file mode 100644 index d565de7..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/value_set.dart +++ /dev/null
@@ -1,157 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of ssa; - -class ValueSet { - int size = 0; - List<HInstruction> table; - ValueSetNode collisions; - ValueSet() : table = new List<HInstruction>.fixedLength(8); - - bool get isEmpty => size == 0; - int get length => size; - - void add(HInstruction instruction) { - assert(lookup(instruction) == null); - int hashCode = instruction.gvnHashCode(); - int capacity = table.length; - // Resize when half of the hash table is in use. - if (size >= capacity >> 1) { - capacity = capacity << 1; - resize(capacity); - } - // Try to insert in the hash table first. - int index = hashCode % capacity; - if (table[index] == null) { - table[index] = instruction; - } else { - collisions = new ValueSetNode(instruction, hashCode, collisions); - } - size++; - } - - HInstruction lookup(HInstruction instruction) { - int hashCode = instruction.gvnHashCode(); - int index = hashCode % table.length; - // Look in the hash table. - HInstruction probe = table[index]; - if (probe != null && probe.gvnEquals(instruction)) return probe; - // Look in the collisions list. - for (ValueSetNode node = collisions; node != null; node = node.next) { - if (node.hashCode == hashCode) { - HInstruction cached = node.value; - if (cached.gvnEquals(instruction)) return cached; - } - } - return null; - } - - void kill(int flags) { - if (flags == 0) return; - int depends = HInstruction.computeDependsOnFlags(flags); - // Kill in the hash table. - for (int index = 0, length = table.length; index < length; index++) { - HInstruction instruction = table[index]; - if (instruction != null && (instruction.flags & depends) != 0) { - table[index] = null; - size--; - } - } - // Kill in the collisions list. - ValueSetNode previous = null; - ValueSetNode current = collisions; - while (current != null) { - ValueSetNode next = current.next; - HInstruction cached = current.value; - if ((cached.flags & depends) != 0) { - if (previous == null) { - collisions = next; - } else { - previous.next = next; - } - size--; - } else { - previous = current; - } - current = next; - } - } - - ValueSet copy() { - return copyTo(new ValueSet(), table, collisions); - } - - List<HInstruction> toList() { - return copyTo(<HInstruction>[], table, collisions); - } - - // Copy the instructions in value set defined by [table] and - // [collisions] into [other] and returns [other]. The copy is done - // by iterating through the hash table and the collisions list and - // calling [:other.add:]. - static copyTo(var other, List<HInstruction> table, ValueSetNode collisions) { - // Copy elements from the hash table. - for (int index = 0, length = table.length; index < length; index++) { - HInstruction instruction = table[index]; - if (instruction != null) other.add(instruction); - } - // Copy elements from the collision list. - ValueSetNode current = collisions; - while (current != null) { - // TODO(kasperl): Maybe find a way of reusing the hash code - // rather than recomputing it every time. - other.add(current.value); - current = current.next; - } - return other; - } - - ValueSet intersection(ValueSet other) { - if (size > other.size) return other.intersection(this); - ValueSet result = new ValueSet(); - // Look in the hash table. - for (int index = 0, length = table.length; index < length; index++) { - HInstruction instruction = table[index]; - if (instruction != null && other.lookup(instruction) != null) { - result.add(instruction); - } - } - // Look in the collision list. - ValueSetNode current = collisions; - while (current != null) { - HInstruction value = current.value; - if (other.lookup(value) != null) { - result.add(value); - } - current = current.next; - } - return result; - } - - void resize(int capacity) { - var oldSize = size; - var oldTable = table; - var oldCollisions = collisions; - // Reset the table with a bigger capacity. - assert(capacity > table.length); - size = 0; - table = new List<HInstruction>.fixedLength(capacity); - collisions = null; - // Add the old instructions to the new table. - copyTo(this, oldTable, oldCollisions); - // Make sure we preserved all elements and that no resizing - // happened as part of this resizing. - assert(size == oldSize); - assert(table.length == capacity); - } -} - -class ValueSetNode { - final HInstruction value; - final int hash; - int get hashCode => hash; - ValueSetNode next; - ValueSetNode(this.value, this.hash, this.next); -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/variable_allocator.dart b/pkgs/markdown/test/lib/src/compiler/implementation/ssa/variable_allocator.dart deleted file mode 100644 index 34f960d..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/ssa/variable_allocator.dart +++ /dev/null
@@ -1,669 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of ssa; - -/** - * The [LiveRange] class covers a range where an instruction is live. - */ -class LiveRange { - final int start; - // [end] is not final because it can be updated due to loops. - int end; - LiveRange(this.start, this.end) { - assert(start <= end); - } - - String toString() => '[$start $end['; -} - -/** - * The [LiveInterval] class contains the list of ranges where an - * instruction is live. - */ -class LiveInterval { - /** - * The id where the instruction is defined. - */ - int start; - final List<LiveRange> ranges; - LiveInterval() : ranges = <LiveRange>[]; - - /** - * Update all ranges that are contained in [from, to[ to - * die at [to]. - */ - void loopUpdate(int from, int to) { - for (LiveRange range in ranges) { - if (from <= range.start && range.end < to) { - range.end = to; - } - } - } - - /** - * Add a new range to this interval. - */ - void add(LiveRange interval) { - ranges.add(interval); - } - - /** - * Returns true if one of the ranges of this interval dies at [at]. - */ - bool diesAt(int at) { - for (LiveRange range in ranges) { - if (range.end == at) return true; - } - return false; - } - - String toString() { - List<String> res = new List<String>(); - for (final interval in ranges) res.add(interval.toString()); - return '(${Strings.join(res, ', ')})'; - } -} - -/** - * The [LiveEnvironment] class contains the liveIn set of a basic - * block. A liveIn set of a block contains the instructions that are - * live when entering that block. - */ -class LiveEnvironment { - /** - * The instruction id where the basic block starts. See - * [SsaLiveIntervalBuilder.instructionId]. - */ - int startId; - - /** - * The instruction id where the basic block ends. - */ - final int endId; - - /** - * Loop markers that will be updated once the loop header is - * visited. The liveIn set of the loop header will be merged into this - * environment. [loopMarkers] is a mapping from block header to the - * end instruction id of the loop exit block. - */ - final Map<HBasicBlock, int> loopMarkers; - - /** - * The instructions that are live in this basic block. The values of - * the map contain the instruction ids where the instructions die. - * It will be used when adding a range to the live interval of an - * instruction. - */ - final Map<HInstruction, int> liveInstructions; - - /** - * Map containing the live intervals of instructions. - */ - final Map<HInstruction, LiveInterval> liveIntervals; - - LiveEnvironment(this.liveIntervals, this.endId) - : liveInstructions = new Map<HInstruction, int>(), - loopMarkers = new Map<HBasicBlock, int>(); - - /** - * Remove an instruction from the liveIn set. This method also - * updates the live interval of [instruction] to contain the new - * range: [id, / id contained in [liveInstructions] /]. - */ - void remove(HInstruction instruction, int id) { - // Special case the HCheck instruction to have the same live - // interval as the instruction it is checking. - if (instruction is HCheck) { - var input = instruction.checkedInput; - while (input is HCheck) input = input.checkedInput; - liveIntervals.putIfAbsent(input, () => new LiveInterval()); - // Unconditionally force the live interval of the HCheck to - // be the live interval of the instruction it is checking. - liveIntervals[instruction] = liveIntervals[input]; - } else { - LiveInterval range = liveIntervals.putIfAbsent( - instruction, () => new LiveInterval()); - int lastId = liveInstructions[instruction]; - // If [lastId] is null, then this instruction is not being used. - range.add(new LiveRange(id, lastId == null ? id : lastId)); - // The instruction is defined at [id]. - range.start = id; - } - liveInstructions.remove(instruction); - } - - /** - * Add [instruction] to the liveIn set. If the instruction is not - * already in the set, we save the id where it dies. - */ - void add(HInstruction instruction, int userId) { - // Note that we are visiting the graph in post-dominator order, so - // the first time we see a variable is when it dies. - liveInstructions.putIfAbsent(instruction, () => userId); - if (instruction is HCheck) { - // Special case the HCheck instruction to mark the actual - // checked instruction live. - var input = instruction.checkedInput; - while (input is HCheck) input = input.checkedInput; - liveInstructions.putIfAbsent(input, () => userId); - } - } - - /** - * Merge this environment with [other]. Update the end id of - * instructions in case they are different between this and [other]. - */ - void mergeWith(LiveEnvironment other) { - other.liveInstructions.forEach((HInstruction instruction, int existingId) { - // If both environments have the same instruction id of where - // [instruction] dies, there is no need to update the live - // interval of [instruction]. For example the if block and the - // else block have the same end id for an instruction that is - // being used in the join block and defined before the if/else. - if (existingId == endId) return; - LiveInterval range = liveIntervals.putIfAbsent( - instruction, () => new LiveInterval()); - range.add(new LiveRange(other.startId, existingId)); - liveInstructions[instruction] = endId; - }); - other.loopMarkers.forEach((k, v) { loopMarkers[k] = v; }); - } - - void addLoopMarker(HBasicBlock header, int id) { - assert(!loopMarkers.containsKey(header)); - loopMarkers[header] = id; - } - - void removeLoopMarker(HBasicBlock header) { - assert(loopMarkers.containsKey(header)); - loopMarkers.remove(header); - } - - bool get isEmpty => liveInstructions.isEmpty && loopMarkers.isEmpty; - bool contains(HInstruction instruction) => - liveInstructions.containsKey(instruction); - String toString() => liveInstructions.toString(); -} - -/** - * Builds the live intervals of each instruction. The algorithm visits - * the graph post-dominator tree to find the last uses of an - * instruction, and computes the liveIns of each basic block. - */ -class SsaLiveIntervalBuilder extends HBaseVisitor { - final Compiler compiler; - final Set<HInstruction> generateAtUseSite; - - /** - * A counter to assign start and end ids to live ranges. The initial - * value is not relevant. Note that instructionId goes downward to ease - * reasoning about live ranges (the first instruction of a graph has - * the lowest id). - */ - int instructionId = 0; - - /** - * The liveIns of basic blocks. - */ - final Map<HBasicBlock, LiveEnvironment> liveInstructions; - - /** - * The live intervals of instructions. - */ - final Map<HInstruction, LiveInterval> liveIntervals; - - SsaLiveIntervalBuilder(this.compiler, this.generateAtUseSite) - : liveInstructions = new Map<HBasicBlock, LiveEnvironment>(), - liveIntervals = new Map<HInstruction, LiveInterval>(); - - void visitGraph(HGraph graph) { - visitPostDominatorTree(graph); - if (!liveInstructions[graph.entry].isEmpty) { - compiler.internalError('LiveIntervalBuilder', - node: compiler.currentElement.parseNode(compiler)); - } - } - - void markInputsAsLiveInEnvironment(HInstruction instruction, - LiveEnvironment environment) { - for (int i = 0, len = instruction.inputs.length; i < len; i++) { - markAsLiveInEnvironment(instruction.inputs[i], environment); - } - } - - void markAsLiveInEnvironment(HInstruction instruction, - LiveEnvironment environment) { - if (environment.contains(instruction)) return; - environment.add(instruction, instructionId); - // HPhis are treated specially. - if (generateAtUseSite.contains(instruction) && instruction is !HPhi) { - markInputsAsLiveInEnvironment(instruction, environment); - } - } - - void visitBasicBlock(HBasicBlock block) { - LiveEnvironment environment = - new LiveEnvironment(liveIntervals, instructionId); - - // Add to the environment the liveIn of its successor, as well as - // the inputs of the phis of the successor that flow from this block. - for (int i = 0; i < block.successors.length; i++) { - HBasicBlock successor = block.successors[i]; - LiveEnvironment successorEnv = liveInstructions[successor]; - if (successorEnv != null) { - environment.mergeWith(successorEnv); - } else { - environment.addLoopMarker(successor, instructionId); - } - - int index = successor.predecessors.indexOf(block); - for (HPhi phi = successor.phis.first; phi != null; phi = phi.next) { - markAsLiveInEnvironment(phi.inputs[index], environment); - } - } - - // Iterate over all instructions to remove an instruction from the - // environment and add its inputs. - HInstruction instruction = block.last; - while (instruction != null) { - environment.remove(instruction, instructionId); - markInputsAsLiveInEnvironment(instruction, environment); - instruction = instruction.previous; - instructionId--; - } - - // We just remove the phis from the environment. The inputs of the - // phis will be put in the environment of the predecessors. - for (HPhi phi = block.phis.first; phi != null; phi = phi.next) { - environment.remove(phi, instructionId); - } - - // Save the liveInstructions of that block. - environment.startId = instructionId + 1; - liveInstructions[block] = environment; - - // If the block is a loop header, we can remove the loop marker, - // because it will just recompute the loop phis. - // We also check if this loop header has any back edges. If not, - // we know there is no loop marker for it. - if (block.isLoopHeader() && block.predecessors.length > 1) { - updateLoopMarker(block); - } - } - - void updateLoopMarker(HBasicBlock header) { - LiveEnvironment env = liveInstructions[header]; - int lastId = env.loopMarkers[header]; - // Update all instructions that are liveIns in [header] to have a - // range that covers the loop. - env.liveInstructions.forEach((HInstruction instruction, int id) { - LiveInterval range = env.liveIntervals.putIfAbsent( - instruction, () => new LiveInterval()); - range.loopUpdate(env.startId, lastId); - env.liveInstructions[instruction] = lastId; - }); - - env.removeLoopMarker(header); - - // Update all liveIns set to contain the liveIns of [header]. - liveInstructions.forEach((HBasicBlock block, LiveEnvironment other) { - if (other.loopMarkers.containsKey(header)) { - env.liveInstructions.forEach((HInstruction instruction, int id) { - other.liveInstructions[instruction] = id; - }); - other.removeLoopMarker(header); - env.loopMarkers.forEach((k, v) { other.loopMarkers[k] = v; }); - } - }); - } -} - -/** - * Represents a copy from one instruction to another. The codegen - * also uses this class to represent a copy from one variable to - * another. - */ -class Copy { - final source; - final destination; - Copy(this.source, this.destination); - String toString() => '$destination <- $source'; -} - -/** - * A copy handler contains the copies that a basic block needs to do - * after executing all its instructions. - */ -class CopyHandler { - /** - * The copies from an instruction to a phi of the successor. - */ - final List<Copy> copies; - - /** - * Assignments from an instruction that does not need a name (e.g. a - * constant) to the phi of a successor. - */ - final List<Copy> assignments; - - CopyHandler() - : copies = new List<Copy>(), - assignments = new List<Copy>(); - - void addCopy(HInstruction source, HInstruction destination) { - copies.add(new Copy(source, destination)); - } - - void addAssignment(HInstruction source, HInstruction destination) { - assignments.add(new Copy(source, destination)); - } - - String toString() => 'Copies: $copies, assignments: $assignments'; - bool get isEmpty => copies.isEmpty && assignments.isEmpty; -} - -/** - * Contains the mapping between instructions and their names for code - * generation, as well as the [CopyHandler] for each basic block. - */ -class VariableNames { - final Map<HInstruction, String> ownName; - final Map<HBasicBlock, CopyHandler> copyHandlers; - - // Used to control heuristic that determines how local variables are declared. - final Set<String> allUsedNames; - /** - * Name that is used as a temporary to break cycles in - * parallel copies. We make sure this name is not being used - * anywhere by reserving it when we allocate names for instructions. - */ - final String swapTemp; - /** - * Name that is used in bailout code. We make sure this name is not being used - * anywhere by reserving it when we allocate names for instructions. - */ - final String stateName; - - String getSwapTemp() { - allUsedNames.add(swapTemp); - return swapTemp; - } - - VariableNames() - : ownName = new Map<HInstruction, String>(), - copyHandlers = new Map<HBasicBlock, CopyHandler>(), - allUsedNames = new Set<String>(), - swapTemp = computeFreshWithPrefix("t"), - stateName = computeFreshWithPrefix("state"); - - int get numberOfVariables => allUsedNames.length; - - /** Returns a fresh variable with the given prefix. */ - static String computeFreshWithPrefix(String prefix) { - String name = '${prefix}0'; - int i = 1; - return name; - } - - String getName(HInstruction instruction) { - return ownName[instruction]; - } - - CopyHandler getCopyHandler(HBasicBlock block) { - return copyHandlers[block]; - } - - void addNameUsed(String name) => allUsedNames.add(name); - - bool hasName(HInstruction instruction) => ownName.containsKey(instruction); - - void addCopy(HBasicBlock block, HInstruction source, HPhi destination) { - CopyHandler handler = - copyHandlers.putIfAbsent(block, () => new CopyHandler()); - handler.addCopy(source, destination); - } - - void addAssignment(HBasicBlock block, HInstruction source, HPhi destination) { - CopyHandler handler = - copyHandlers.putIfAbsent(block, () => new CopyHandler()); - handler.addAssignment(source, destination); - } -} - -/** - * Allocates variable names for instructions, making sure they don't collide. - */ -class VariableNamer { - final VariableNames names; - final Compiler compiler; - final Set<String> usedNames; - final List<String> freeTemporaryNames; - int temporaryIndex = 0; - static final RegExp regexp = new RegExp('t[0-9]+'); - - VariableNamer(LiveEnvironment environment, - this.names, - this.compiler) - : usedNames = new Set<String>(), - freeTemporaryNames = new List<String>() { - // [VariableNames.swapTemp] is used when there is a cycle in a copy handler. - // Therefore we make sure no one uses it. - usedNames.add(names.swapTemp); - // [VariableNames.stateName] is being used throughout a bailout function. - // Whenever a bailout-target is reached we set the state-variable to 0. We - // must therefore not have any local variable that could clash with the - // state variable. - // Therefore we make sure no one uses it at any time. - usedNames.add(names.stateName); - - // All liveIns instructions must have a name at this point, so we - // add them to the list of used names. - environment.liveInstructions.forEach((HInstruction instruction, int index) { - String name = names.getName(instruction); - if (name != null) { - usedNames.add(name); - names.addNameUsed(name); - } - }); - } - - String allocateWithHint(String originalName) { - int i = 0; - JavaScriptBackend backend = compiler.backend; - String name = backend.namer.safeVariableName(originalName); - while (usedNames.contains(name)) { - name = backend.namer.safeVariableName('$originalName${i++}'); - } - return name; - } - - String allocateTemporary() { - while (!freeTemporaryNames.isEmpty) { - String name = freeTemporaryNames.removeLast(); - if (!usedNames.contains(name)) return name; - } - String name = 't${temporaryIndex++}'; - while (usedNames.contains(name)) name = 't${temporaryIndex++}'; - return name; - } - - HPhi firstPhiUserWithElement(HInstruction instruction) { - for (HInstruction user in instruction.usedBy) { - if (user is HPhi && user.sourceElement != null) { - return user; - } - } - return null; - } - - String allocateName(HInstruction instruction) { - String name; - if (instruction is HCheck) { - // Special case this instruction to use the name of its - // input if it has one. - var temp = instruction; - do { - temp = temp.checkedInput; - name = names.ownName[temp]; - } while (name == null && temp is HCheck); - if (name != null) return addAllocatedName(instruction, name); - } - - if (instruction.sourceElement != null) { - name = allocateWithHint(instruction.sourceElement.name.slowToString()); - } else { - // We could not find an element for the instruction. If the - // instruction is used by a phi, try to use the name of the phi. - // Otherwise, just allocate a temporary name. - HPhi phi = firstPhiUserWithElement(instruction); - if (phi != null) { - name = allocateWithHint(phi.sourceElement.name.slowToString()); - } else { - name = allocateTemporary(); - } - } - return addAllocatedName(instruction, name); - } - - String addAllocatedName(HInstruction instruction, String name) { - usedNames.add(name); - names.addNameUsed(name); - names.ownName[instruction] = name; - return name; - } - - /** - * Frees [instruction]'s name so it can be used for other instructions. - */ - void freeName(HInstruction instruction) { - String ownName = names.ownName[instruction]; - if (ownName != null) { - // We check if we have already looked for temporary names - // because if we haven't, chances are the temporary we allocate - // in this block can match a phi with the same name in the - // successor block. - if (temporaryIndex != 0 && regexp.hasMatch(ownName)) { - freeTemporaryNames.addLast(ownName); - } - usedNames.remove(ownName); - } - } -} - -/** - * Visits all blocks in the graph, sets names to instructions, and - * creates the [CopyHandler] for each block. This class needs to have - * the liveIns set as well as all the live intervals of instructions. - * It visits the graph in dominator order, so that at each entry of a - * block, the instructions in its liveIns set have names. - * - * When visiting a block, it goes through all instructions. For each - * instruction, it frees the names of the inputs that die at that - * instruction, and allocates a name to the instruction. For each phi, - * it adds a copy to the CopyHandler of the corresponding predecessor. - */ -class SsaVariableAllocator extends HBaseVisitor { - - final Compiler compiler; - final Map<HBasicBlock, LiveEnvironment> liveInstructions; - final Map<HInstruction, LiveInterval> liveIntervals; - final Set<HInstruction> generateAtUseSite; - - final VariableNames names; - - SsaVariableAllocator(this.compiler, - this.liveInstructions, - this.liveIntervals, - this.generateAtUseSite) - : this.names = new VariableNames(); - - void visitGraph(HGraph graph) { - visitDominatorTree(graph); - } - - void visitBasicBlock(HBasicBlock block) { - VariableNamer namer = new VariableNamer( - liveInstructions[block], names, compiler); - - block.forEachPhi((HPhi phi) { - handlePhi(phi, namer); - }); - - block.forEachInstruction((HInstruction instruction) { - handleInstruction(instruction, namer); - }); - } - - /** - * Returns whether [instruction] needs a name. Instructions that - * have no users or that are generated at use site does not need a name. - */ - bool needsName(HInstruction instruction) { - if (instruction is HThis) return false; - if (instruction is HParameterValue) return true; - if (instruction.usedBy.isEmpty) return false; - if (generateAtUseSite.contains(instruction)) return false; - // A [HCheck] instruction that has control flow needs a name only if its - // checked input needs a name (e.g. a check [HConstant] does not - // need a name). - if (instruction is HCheck && instruction.isControlFlow()) { - HCheck check = instruction; - return needsName(instruction.checkedInput); - } - return true; - } - - /** - * Returns whether [instruction] dies at the instruction [at]. - */ - bool diesAt(HInstruction instruction, HInstruction at) { - LiveInterval atInterval = liveIntervals[at]; - LiveInterval instructionInterval = liveIntervals[instruction]; - int start = atInterval.start; - return instructionInterval.diesAt(start); - } - - void handleInstruction(HInstruction instruction, VariableNamer namer) { - // TODO(ager): We cannot perform this check to free names for - // HCheck instructions because they are special cased to have the - // same live intervals as the instruction they are checking. This - // includes sharing the start id with the checked - // input. Therefore, for HCheck(checkedInput, otherInput) we would - // end up checking that otherInput dies not here, but at the - // location of checkedInput. We should preserve the start id for - // the check instruction. - if (instruction is! HCheck) { - for (int i = 0, len = instruction.inputs.length; i < len; i++) { - HInstruction input = instruction.inputs[i]; - // If [input] has a name, and its use here is the last use, free - // its name. - if (needsName(input) && diesAt(input, instruction)) { - namer.freeName(input); - } - } - } - - if (needsName(instruction)) { - namer.allocateName(instruction); - } - } - - void handlePhi(HPhi phi, VariableNamer namer) { - if (!needsName(phi)) return; - - for (int i = 0; i < phi.inputs.length; i++) { - HInstruction input = phi.inputs[i]; - HBasicBlock predecessor = phi.block.predecessors[i]; - if (!needsName(input)) { - names.addAssignment(predecessor, input, phi); - } else { - names.addCopy(predecessor, input, phi); - } - } - - namer.allocateName(phi); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/string_validator.dart b/pkgs/markdown/test/lib/src/compiler/implementation/string_validator.dart deleted file mode 100644 index ef294bd..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/string_validator.dart +++ /dev/null
@@ -1,214 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// Check the validity of string literals. - -library stringvalidator; - -import "dart:collection"; - -import "dart2jslib.dart"; -import "tree/tree.dart"; -import "elements/elements.dart"; -import "util/characters.dart"; -import "scanner/scannerlib.dart" show Token; - -class StringValidator { - final DiagnosticListener listener; - - StringValidator(this.listener); - - DartString validateQuotedString(Token token) { - SourceString source = token.value; - StringQuoting quoting = quotingFromString(source); - int leftQuote = quoting.leftQuoteLength; - int rightQuote = quoting.rightQuoteLength; - SourceString content = source.copyWithoutQuotes(leftQuote, rightQuote); - return validateString(token, - token.charOffset + leftQuote, - content, - quoting); - } - - DartString validateInterpolationPart(Token token, StringQuoting quoting, - {bool isFirst: false, - bool isLast: false}) { - SourceString source = token.value; - int leftQuote = 0; - int rightQuote = 0; - if (isFirst) leftQuote = quoting.leftQuoteLength; - if (isLast) rightQuote = quoting.rightQuoteLength; - SourceString content = source.copyWithoutQuotes(leftQuote, rightQuote); - return validateString(token, - token.charOffset + leftQuote, - content, - quoting); - } - - static StringQuoting quotingFromString(SourceString sourceString) { - Iterator<int> source = sourceString.iterator; - bool raw = false; - int quoteLength = 1; - source.moveNext(); - int quoteChar = source.current; - if (quoteChar == $r) { - raw = true; - source.moveNext(); - quoteChar = source.current; - } - assert(quoteChar == $SQ || quoteChar == $DQ); - // String has at least one quote. Check it if has three. - // If it only have two, the string must be an empty string literal, - // and end after the second quote. - bool multiline = false; - if (source.moveNext() && source.current == quoteChar && source.moveNext()) { - int code = source.current; - assert(code == quoteChar); // If not, there is a bug in the parser. - quoteLength = 3; - // Check if a multiline string starts with a newline (CR, LF or CR+LF). - if (source.moveNext()) { - code = source.current; - if (code == $CR) { - quoteLength += 1; - if (source.moveNext() && source.current == $LF) { - quoteLength += 1; - } - } else if (code == $LF) { - quoteLength += 1; - } - } - } - return StringQuoting.getQuoting(quoteChar, raw, quoteLength); - } - - void stringParseError(String message, Token token, int offset) { - listener.cancel("$message @ $offset", token : token); - } - - /** - * Validates the escape sequences and special characters of a string literal. - * Returns a DartString if valid, and null if not. - */ - DartString validateString(Token token, - int startOffset, - SourceString string, - StringQuoting quoting) { - // We need to check for invalid x and u escapes, for line - // terminators in non-multiline strings, and for invalid Unicode - // scalar values (either directly or as u-escape values). We also check - // for unpaired UTF-16 surrogates. - int length = 0; - int index = startOffset; - bool containsEscape = false; - bool previousWasLeadSurrogate = false; - bool invalidUtf16 = false; - for(HasNextIterator<int> iter = new HasNextIterator(string.iterator); - iter.hasNext; - length++) { - index++; - int code = iter.next(); - if (code == $BACKSLASH) { - if (quoting.raw) continue; - containsEscape = true; - if (!iter.hasNext) { - stringParseError("Incomplete escape sequence",token, index); - return null; - } - index++; - code = iter.next(); - if (code == $x) { - for (int i = 0; i < 2; i++) { - if (!iter.hasNext) { - stringParseError("Incomplete escape sequence", token, index); - return null; - } - index++; - code = iter.next(); - if (!isHexDigit(code)) { - stringParseError("Invalid character in escape sequence", - token, index); - return null; - } - } - // A two-byte hex escape can't generate an invalid value. - continue; - } else if (code == $u) { - int escapeStart = index - 1; - index++; - code = iter.hasNext ? iter.next() : 0; - int value = 0; - if (code == $OPEN_CURLY_BRACKET) { - // expect 1-6 hex digits. - int count = 0; - while (iter.hasNext) { - code = iter.next(); - index++; - if (code == $CLOSE_CURLY_BRACKET) { - break; - } - if (!isHexDigit(code)) { - stringParseError("Invalid character in escape sequence", - token, index); - return null; - } - count++; - value = value * 16 + hexDigitValue(code); - } - if (code != $CLOSE_CURLY_BRACKET || count == 0 || count > 6) { - int errorPosition = index - count; - if (count > 6) errorPosition += 6; - stringParseError("Invalid character in escape sequence", - token, errorPosition); - return null; - } - } else { - // Expect four hex digits, including the one just read. - for (int i = 0; i < 4; i++) { - if (i > 0) { - if (iter.hasNext) { - index++; - code = iter.next(); - } else { - code = 0; - } - } - if (!isHexDigit(code)) { - stringParseError("Invalid character in escape sequence", - token, index); - return null; - } - value = value * 16 + hexDigitValue(code); - } - } - code = value; - } - } - if (code >= 0x10000) length++; - // This handles both unescaped characters and the value of unicode - // escapes. - if (previousWasLeadSurrogate) { - if (!isUtf16TrailSurrogate(code)) { - invalidUtf16 = true; - break; - } - previousWasLeadSurrogate = false; - } else if (isUtf16LeadSurrogate(code)) { - previousWasLeadSurrogate = true; - } else if (!isUnicodeScalarValue(code)) { - invalidUtf16 = true; - break; - } - } - if (previousWasLeadSurrogate || invalidUtf16) { - stringParseError("Invalid Utf16 surrogate", token, index); - return null; - } - // String literal successfully validated. - if (quoting.raw || !containsEscape) { - // A string without escapes could just as well have been raw. - return new DartString.rawString(string, length); - } - return new DartString.escapedString(string, length); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/tools/mini_parser.dart b/pkgs/markdown/test/lib/src/compiler/implementation/tools/mini_parser.dart deleted file mode 100644 index ea56771..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/tools/mini_parser.dart +++ /dev/null
@@ -1,321 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library parser; - -import 'dart:io'; -import 'dart:scalarlist'; - -import 'dart:utf'; - -import '../elements/elements.dart'; -import '../scanner/scanner_implementation.dart'; -import '../scanner/scannerlib.dart'; -import '../tree/tree.dart'; -import '../util/characters.dart'; -import '../source_file.dart'; -import '../ssa/ssa.dart'; - -import '../../compiler.dart' as api; - -part '../diagnostic_listener.dart'; -part '../scanner/byte_array_scanner.dart'; -part '../scanner/byte_strings.dart'; - -int charCount = 0; -Stopwatch stopwatch; - -void main() { - toolMain(new Options().arguments); -} - -void toolMain(List<String> arguments) { - filesWithCrashes = []; - stopwatch = new Stopwatch(); - MyOptions options = new MyOptions(); - - void printStats() { - int kb = (charCount / 1024).round().toInt(); - String stats = - '$classCount classes (${kb}Kb) in ${stopwatch.elapsedMilliseconds}ms'; - if (errorCount != 0) { - stats = '$stats with $errorCount errors'; - } - if (options.diet) { - print('Diet parsed $stats.'); - } else { - print('Parsed $stats.'); - } - if (filesWithCrashes.length != 0) { - print('The following ${filesWithCrashes.length} files caused a crash:'); - for (String file in filesWithCrashes) { - print(file); - } - } - } - - for (String argument in arguments) { - if (argument == "--diet") { - options.diet = true; - continue; - } - if (argument == "--throw") { - options.throwOnError = true; - continue; - } - if (argument == "--scan-only") { - options.scanOnly = true; - continue; - } - if (argument == "--read-only") { - options.readOnly = true; - continue; - } - if (argument == "--ast") { - options.buildAst = true; - continue; - } - if (argument == "-") { - parseFilesFrom(stdin, options, printStats); - return; - } - stopwatch.start(); - parseFile(argument, options); - stopwatch.stop(); - } - - printStats(); -} - -void parseFile(String filename, MyOptions options) { - List<int> bytes = read(filename); - charCount += bytes.length; - if (options.readOnly) return; - MySourceFile file = new MySourceFile(filename, bytes); - final Listener listener = options.buildAst - ? new MyNodeListener(file, options) - : new MyListener(file); - final Parser parser = options.diet - ? new PartialParser(listener) - : new Parser(listener); - try { - Token token = scan(file); - if (!options.scanOnly) parser.parseUnit(token); - } on ParserError catch (ex) { - if (options.throwOnError) { - throw; - } else { - print(ex); - } - } catch (ex) { - print('Error in file: $filename'); - throw; - } - if (options.buildAst) { - MyNodeListener l = listener; - if (!l.nodes.isEmpty) { - String message = 'Stack not empty after parsing'; - print(formatError(message, l.nodes.head.getBeginToken(), - l.nodes.head.getEndToken(), file)); - throw message; - } - } -} - -Token scan(MySourceFile source) { - Scanner scanner = new ByteArrayScanner(source.rawText); - return scanner.tokenize(); -} - -var filesWithCrashes; - -void parseFilesFrom(InputStream input, MyOptions options, Function whenDone) { - void readLine(String line) { - stopwatch.start(); - try { - parseFile(line, options); - } catch (ex, trace) { - filesWithCrashes.add(line); - print(ex); - print(trace); - } - stopwatch.stop(); - } - forEachLine(input, readLine, whenDone); -} - -void forEachLine(InputStream input, - void lineHandler(String line), - void closeHandler()) { - StringInputStream stringStream = new StringInputStream(input); - stringStream.onLine = () { - String line; - while ((line = stringStream.readLine()) != null) { - lineHandler(line); - } - }; - stringStream.onClosed = closeHandler; -} - -List<int> read(String filename) { - RandomAccessFile file = new File(filename).openSync(); - bool threw = true; - try { - int size = file.lengthSync(); - List<int> bytes = new Uint8List(size + 1); - file.readListSync(bytes, 0, size); - bytes[size] = $EOF; - threw = false; - return bytes; - } finally { - try { - file.closeSync(); - } catch (ex) { - if (!threw) throw; - } - } -} - -int classCount = 0; -int errorCount = 0; - -class MyListener extends Listener { - final SourceFile file; - - MyListener(this.file); - - void beginClassDeclaration(Token token) { - classCount++; - } - - void beginInterface(Token token) { - classCount++; - } - - void error(String message, Token token) { - throw new ParserError(formatError(message, token, token, file)); - } -} - -String formatError(String message, Token beginToken, Token endToken, - SourceFile file) { - ++errorCount; - if (beginToken == null) return '${file.filename}: $message'; - String tokenString = endToken.toString(); - int begin = beginToken.charOffset; - int end = endToken.charOffset + tokenString.length; - return file.getLocationMessage(message, begin, end, true, (x) => x); -} - -class MyNodeListener extends NodeListener { - MyNodeListener(SourceFile file, MyOptions options) - : super(new MyCanceller(file, options), null); - - void beginClassDeclaration(Token token) { - classCount++; - } - - void beginInterface(Token token) { - classCount++; - } - - void endClassDeclaration(int interfacesCount, Token beginToken, - Token extendsKeyword, Token implementsKeyword, - Token endToken) { - super.endClassDeclaration(interfacesCount, beginToken, - extendsKeyword, implementsKeyword, - endToken); - ClassNode node = popNode(); // Discard ClassNode and assert the type. - } - - void endInterface(int supertypeCount, Token interfaceKeyword, - Token extendsKeyword, Token endToken) { - super.endInterface(supertypeCount, interfaceKeyword, extendsKeyword, - endToken); - ClassNode node = popNode(); // Discard ClassNode and assert the type. - } - - void endTopLevelFields(int count, Token beginToken, Token endToken) { - super.endTopLevelFields(count, beginToken, endToken); - VariableDefinitions node = popNode(); // Discard node and assert the type. - } - - void endFunctionTypeAlias(Token typedefKeyword, Token endToken) { - super.endFunctionTypeAlias(typedefKeyword, endToken); - Typedef node = popNode(); // Discard Typedef and assert type type. - } - - void endLibraryTag(bool hasPrefix, Token beginToken, Token endToken) { - super.endLibraryTag(hasPrefix, beginToken, endToken); - ScriptTag node = popNode(); // Discard ScriptTag and assert type type. - } - - void log(message) { - print(message); - } -} - -class MyCanceller implements DiagnosticListener { - final SourceFile file; - final MyOptions options; - - MyCanceller(this.file, this.options); - - void log(String message) {} - - void cancel(String reason, {node, token, instruction, element}) { - Token beginToken; - Token endToken; - if (token != null) { - beginToken = token; - endToken = token; - } else if (node != null) { - beginToken = node.getBeginToken(); - endToken = node.getEndToken(); - } - String message = formatError(reason, beginToken, endToken, file); - if (options.throwOnError) throw new ParserError(message); - print(message); - } -} - -class MyOptions { - bool diet = false; - bool throwOnError = false; - bool scanOnly = false; - bool readOnly = false; - bool buildAst = false; -} - -class MySourceFile extends SourceFile { - final rawText; - var stringText; - - MySourceFile(filename, this.rawText) : super(filename, null); - - String get text { - if (rawText is String) { - return rawText; - } else { - if (stringText == null) { - stringText = new String.fromCharCodes(rawText); - if (stringText.endsWith('\u0000')) { - // Strip trailing NUL used by ByteArrayScanner to signal EOF. - stringText = stringText.substring(0, stringText.length - 1); - } - } - return stringText; - } - } - - set text(String newText) { - throw "not supported"; - } -} - -class Mock { - const Mock(); - bool get useColors => true; - internalError(message) { throw message.toString(); } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/tree/dartstring.dart b/pkgs/markdown/test/lib/src/compiler/implementation/tree/dartstring.dart deleted file mode 100644 index 5a3494d..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/tree/dartstring.dart +++ /dev/null
@@ -1,235 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of tree; - -/** - * The [DartString] type represents a Dart string value as a sequence of Unicode - * Scalar Values. - * After parsing, any valid [LiteralString] will contain a [DartString] - * representing its content after removing quotes and resolving escapes in - * its source. - */ -abstract class DartString extends Iterable<int> { - factory DartString.empty() => const LiteralDartString(""); - // This is a convenience constructor. If you need a const literal DartString, - // use [const LiteralDartString(string)] directly. - factory DartString.literal(String string) => new LiteralDartString(string); - factory DartString.rawString(SourceString source, int length) => - new RawSourceDartString(source, length); - factory DartString.escapedString(SourceString source, int length) => - new EscapedSourceDartString(source, length); - factory DartString.concat(DartString first, DartString second) { - if (first.isEmpty) return second; - if (second.isEmpty) return first; - return new ConsDartString(first, second); - } - const DartString(); - int get length; - bool get isEmpty => length == 0; - Iterator<int> get iterator; - String slowToString(); - - bool operator ==(var other) { - if (other is !DartString) return false; - DartString otherString = other; - if (length != otherString.length) return false; - Iterator it1 = iterator; - Iterator it2 = otherString.iterator; - while (it1.moveNext()) { - if (!it2.moveNext()) return false; - if (it1.current != it2.current) return false; - } - return true; - } - String toString() => "DartString#${length}:${slowToString()}"; - SourceString get source; -} - - -/** - * A [DartString] where the content is represented by an actual [String]. - */ -class LiteralDartString extends DartString { - final String string; - const LiteralDartString(this.string); - int get length => string.length; - Iterator<int> get iterator => new StringCodeIterator(string); - String slowToString() => string; - SourceString get source => new StringWrapper(string); -} - -/** - * A [DartString] where the content comes from a slice of the program source. - */ -abstract class SourceBasedDartString extends DartString { - String toStringCache = null; - final SourceString source; - final int length; - SourceBasedDartString(this.source, this.length); - Iterator<int> get iterator; -} - -/** - * Special case of a [SourceBasedDartString] where we know the source doesn't - * contain any escapes. - */ -class RawSourceDartString extends SourceBasedDartString { - RawSourceDartString(source, length) : super(source, length); - Iterator<int> get iterator => source.iterator; - String slowToString() { - if (toStringCache != null) return toStringCache; - toStringCache = source.slowToString(); - return toStringCache; - } -} - -/** - * General case of a [SourceBasedDartString] where the source might contain - * escapes. - */ -class EscapedSourceDartString extends SourceBasedDartString { - EscapedSourceDartString(source, length) : super(source, length); - Iterator<int> get iterator { - if (toStringCache != null) return new StringCodeIterator(toStringCache); - return new StringEscapeIterator(source); - } - String slowToString() { - if (toStringCache != null) return toStringCache; - StringBuffer buffer = new StringBuffer(); - StringEscapeIterator it = new StringEscapeIterator(source); - while (it.moveNext()) { - buffer.addCharCode(it.current); - } - toStringCache = buffer.toString(); - return toStringCache; - } -} - -/** - * The concatenation of two [DartString]s. - */ -class ConsDartString extends DartString { - final DartString left; - final DartString right; - final int length; - String toStringCache; - ConsDartString(DartString left, DartString right) - : this.left = left, - this.right = right, - length = left.length + right.length; - - Iterator<int> get iterator => new ConsDartStringIterator(this); - - String slowToString() { - if (toStringCache != null) return toStringCache; - toStringCache = left.slowToString().concat(right.slowToString()); - return toStringCache; - } - SourceString get source => new StringWrapper(slowToString()); -} - -class ConsDartStringIterator implements Iterator<int> { - HasNextIterator<int> currentIterator; - DartString right; - bool hasNextLookAhead; - int _current = null; - - ConsDartStringIterator(ConsDartString cons) - : currentIterator = new HasNextIterator<int>(cons.left.iterator), - right = cons.right { - hasNextLookAhead = currentIterator.hasNext; - if (!hasNextLookAhead) { - nextPart(); - } - } - - int get current => _current; - - bool moveNext() { - if (!hasNextLookAhead) { - _current = null; - return false; - } - _current = currentIterator.next(); - hasNextLookAhead = currentIterator.hasNext; - if (!hasNextLookAhead) { - nextPart(); - } - return true; - } - void nextPart() { - if (right != null) { - currentIterator = new HasNextIterator<int>(right.iterator); - right = null; - hasNextLookAhead = currentIterator.hasNext; - } - } -} - -/** - *Iterator that returns the actual string contents of a string with escapes. - */ -class StringEscapeIterator implements Iterator<int>{ - final Iterator<int> source; - int _current = null; - - StringEscapeIterator(SourceString source) : this.source = source.iterator; - - int get current => _current; - - bool moveNext() { - if (!source.moveNext()) { - _current = null; - return false; - } - int code = source.current; - if (code != $BACKSLASH) { - _current = code; - return true; - } - source.moveNext(); - code = source.current; - switch (code) { - case $n: _current = $LF; break; - case $r: _current = $CR; break; - case $t: _current = $TAB; break; - case $b: _current = $BS; break; - case $f: _current = $FF; break; - case $v: _current = $VTAB; break; - case $x: - source.moveNext(); - int value = hexDigitValue(source.current); - source.moveNext(); - value = value * 16 + hexDigitValue(source.current); - _current = value; - break; - case $u: - int value = 0; - source.moveNext(); - code = source.current; - if (code == $OPEN_CURLY_BRACKET) { - source.moveNext(); - while (source.current != $CLOSE_CURLY_BRACKET) { - value = value * 16 + hexDigitValue(source.current); - source.moveNext(); - } - _current = value; - break; - } - // Four digit hex value. - value = hexDigitValue(code); - for (int i = 0; i < 3; i++) { - source.moveNext(); - value = value * 16 + hexDigitValue(source.current); - } - _current = value; - break; - default: - _current = code; - } - return true; - } -} -
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/tree/nodes.dart b/pkgs/markdown/test/lib/src/compiler/implementation/tree/nodes.dart deleted file mode 100644 index 1b3b455..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/tree/nodes.dart +++ /dev/null
@@ -1,2086 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of tree; - -abstract class Visitor<R> { - const Visitor(); - - R visitNode(Node node); - - R visitBlock(Block node) => visitStatement(node); - R visitBreakStatement(BreakStatement node) => visitGotoStatement(node); - R visitCascade(Cascade node) => visitExpression(node); - R visitCascadeReceiver(CascadeReceiver node) => visitExpression(node); - R visitCaseMatch(CaseMatch node) => visitNode(node); - R visitCatchBlock(CatchBlock node) => visitNode(node); - R visitClassNode(ClassNode node) => visitNode(node); - R visitCombinator(Combinator node) => visitNode(node); - R visitConditional(Conditional node) => visitExpression(node); - R visitContinueStatement(ContinueStatement node) => visitGotoStatement(node); - R visitDoWhile(DoWhile node) => visitLoop(node); - R visitEmptyStatement(EmptyStatement node) => visitStatement(node); - R visitExport(Export node) => visitLibraryDependency(node); - R visitExpression(Expression node) => visitNode(node); - R visitExpressionStatement(ExpressionStatement node) => visitStatement(node); - R visitFor(For node) => visitLoop(node); - R visitForIn(ForIn node) => visitLoop(node); - R visitFunctionDeclaration(FunctionDeclaration node) => visitStatement(node); - R visitFunctionExpression(FunctionExpression node) => visitExpression(node); - R visitGotoStatement(GotoStatement node) => visitStatement(node); - R visitIdentifier(Identifier node) => visitExpression(node); - R visitIf(If node) => visitStatement(node); - R visitImport(Import node) => visitLibraryDependency(node); - R visitLabel(Label node) => visitNode(node); - R visitLabeledStatement(LabeledStatement node) => visitStatement(node); - R visitLibraryDependency(LibraryDependency node) => visitLibraryTag(node); - R visitLibraryName(LibraryName node) => visitLibraryTag(node); - R visitLibraryTag(LibraryTag node) => visitNode(node); - R visitLiteral(Literal node) => visitExpression(node); - R visitLiteralBool(LiteralBool node) => visitLiteral(node); - R visitLiteralDouble(LiteralDouble node) => visitLiteral(node); - R visitLiteralInt(LiteralInt node) => visitLiteral(node); - R visitLiteralList(LiteralList node) => visitExpression(node); - R visitLiteralMap(LiteralMap node) => visitExpression(node); - R visitLiteralMapEntry(LiteralMapEntry node) => visitNode(node); - R visitLiteralNull(LiteralNull node) => visitLiteral(node); - R visitLiteralString(LiteralString node) => visitStringNode(node); - R visitStringJuxtaposition(StringJuxtaposition node) => visitStringNode(node); - R visitLoop(Loop node) => visitStatement(node); - R visitMixinApplication(MixinApplication node) => visitNode(node); - R visitModifiers(Modifiers node) => visitNode(node); - R visitNamedArgument(NamedArgument node) => visitExpression(node); - R visitNamedMixinApplication(NamedMixinApplication node) { - return visitMixinApplication(node); - } - R visitNewExpression(NewExpression node) => visitExpression(node); - R visitNodeList(NodeList node) => visitNode(node); - R visitOperator(Operator node) => visitIdentifier(node); - R visitParenthesizedExpression(ParenthesizedExpression node) { - return visitExpression(node); - } - R visitPart(Part node) => visitLibraryTag(node); - R visitPartOf(PartOf node) => visitNode(node); - R visitPostfix(Postfix node) => visitNodeList(node); - R visitPrefix(Prefix node) => visitNodeList(node); - R visitReturn(Return node) => visitStatement(node); - R visitScriptTag(ScriptTag node) => visitNode(node); - R visitSend(Send node) => visitExpression(node); - R visitSendSet(SendSet node) => visitSend(node); - R visitStatement(Statement node) => visitNode(node); - R visitStringNode(StringNode node) => visitExpression(node); - R visitStringInterpolation(StringInterpolation node) => visitStringNode(node); - R visitStringInterpolationPart(StringInterpolationPart node) { - return visitNode(node); - } - R visitSwitchCase(SwitchCase node) => visitNode(node); - R visitSwitchStatement(SwitchStatement node) => visitStatement(node); - R visitThrow(Throw node) => visitStatement(node); - R visitTryStatement(TryStatement node) => visitStatement(node); - R visitTypeAnnotation(TypeAnnotation node) => visitNode(node); - R visitTypedef(Typedef node) => visitNode(node); - R visitTypeVariable(TypeVariable node) => visitNode(node); - R visitVariableDefinitions(VariableDefinitions node) => visitStatement(node); - R visitWhile(While node) => visitLoop(node); -} - -Token firstBeginToken(Node first, Node second) { - Token token = null; - if (first != null) { - token = first.getBeginToken(); - } - if (token == null && second != null) { - // [token] might be null even when [first] is not, e.g. for empty Modifiers. - token = second.getBeginToken(); - } - return token; -} - -/** - * A node in a syntax tree. - * - * The abstract part of "abstract syntax tree" is invalidated when - * supporting tools such as code formatting. These tools need concrete - * syntax such as parentheses and no constant folding. - * - * We support these tools by storing additional references back to the - * token stream. These references are stored in fields ending with - * "Token". - */ -abstract class Node extends TreeElementMixin implements Spannable { - final int hashCode; - static int _HASH_COUNTER = 0; - - Node() : hashCode = ++_HASH_COUNTER; - - accept(Visitor visitor); - - visitChildren(Visitor visitor); - - /** - * Returns this node unparsed to Dart source string. - */ - toString() => unparse(this); - - /** - * Returns Xml-like tree representation of this node. - */ - toDebugString() { - return PrettyPrinter.prettyPrint(this); - } - - String getObjectDescription() => super.toString(); - - Token getBeginToken(); - - Token getEndToken(); - - Block asBlock() => null; - BreakStatement asBreakStatement() => null; - Cascade asCascade() => null; - CascadeReceiver asCascadeReceiver() => null; - CaseMatch asCaseMatch() => null; - CatchBlock asCatchBlock() => null; - ClassNode asClassNode() => null; - Combinator asCombinator() => null; - Conditional asConditional() => null; - ContinueStatement asContinueStatement() => null; - DoWhile asDoWhile() => null; - EmptyStatement asEmptyStatement() => null; - Export asExport() => null; - Expression asExpression() => null; - ExpressionStatement asExpressionStatement() => null; - For asFor() => null; - ForIn asForIn() => null; - FunctionDeclaration asFunctionDeclaration() => null; - FunctionExpression asFunctionExpression() => null; - Identifier asIdentifier() => null; - If asIf() => null; - Import asImport() => null; - Label asLabel() => null; - LabeledStatement asLabeledStatement() => null; - LibraryName asLibraryName() => null; - LiteralBool asLiteralBool() => null; - LiteralDouble asLiteralDouble() => null; - LiteralInt asLiteralInt() => null; - LiteralList asLiteralList() => null; - LiteralMap asLiteralMap() => null; - LiteralMapEntry asLiteralMapEntry() => null; - LiteralNull asLiteralNull() => null; - LiteralString asLiteralString() => null; - MixinApplication asMixinApplication() => null; - Modifiers asModifiers() => null; - NamedArgument asNamedArgument() => null; - NamedMixinApplication asNamedMixinApplication() => null; - NodeList asNodeList() => null; - Operator asOperator() => null; - ParenthesizedExpression asParenthesizedExpression() => null; - Part asPart() => null; - PartOf asPartOf() => null; - Return asReturn() => null; - ScriptTag asScriptTag() => null; - Send asSend() => null; - SendSet asSendSet() => null; - Statement asStatement() => null; - StringInterpolation asStringInterpolation() => null; - StringInterpolationPart asStringInterpolationPart() => null; - StringJuxtaposition asStringJuxtaposition() => null; - StringNode asStringNode() => null; - SwitchCase asSwitchCase() => null; - SwitchStatement asSwitchStatement() => null; - Throw asThrow() => null; - TryStatement asTryStatement() => null; - TypeAnnotation asTypeAnnotation() => null; - TypeVariable asTypeVariable() => null; - Typedef asTypedef() => null; - VariableDefinitions asVariableDefinitions() => null; - While asWhile() => null; - - bool isValidBreakTarget() => false; - bool isValidContinueTarget() => false; -} - -class ClassNode extends Node { - final Modifiers modifiers; - final Identifier name; - final Node superclass; - final NodeList interfaces; - final NodeList typeParameters; - final NodeList body; - - // TODO(ahe, karlklose): the default keyword is not recorded. - final TypeAnnotation defaultClause; - - final Token beginToken; - final Token extendsKeyword; - final Token endToken; - - ClassNode(this.modifiers, this.name, this.typeParameters, this.superclass, - this.interfaces, this.defaultClause, this.beginToken, - this.extendsKeyword, this.body, this.endToken); - - ClassNode asClassNode() => this; - - accept(Visitor visitor) => visitor.visitClassNode(this); - - visitChildren(Visitor visitor) { - if (name != null) name.accept(visitor); - if (typeParameters != null) typeParameters.accept(visitor); - if (superclass != null) superclass.accept(visitor); - if (interfaces != null) interfaces.accept(visitor); - if (body != null) body.accept(visitor); - } - - bool get isInterface => identical(beginToken.stringValue, 'interface'); - - bool get isClass => !isInterface; - - Token getBeginToken() => beginToken; - - Token getEndToken() => endToken; -} - -class MixinApplication extends Node { - final TypeAnnotation superclass; - final NodeList mixins; - - MixinApplication(this.superclass, this.mixins); - - MixinApplication asMixinApplication() => this; - - accept(Visitor visitor) => visitor.visitMixinApplication(this); - - visitChildren(Visitor visitor) { - if (superclass != null) superclass.accept(visitor); - if (mixins != null) mixins.accept(visitor); - } - - Token getBeginToken() => superclass.getBeginToken(); - Token getEndToken() => mixins.getEndToken(); -} - -// TODO(kasperl): Let this share some structure with the typedef for function -// type aliases? -class NamedMixinApplication extends Node implements MixinApplication { - final Identifier name; - final NodeList typeParameters; - - final Modifiers modifiers; - final MixinApplication mixinApplication; - final NodeList interfaces; - - final Token typedefKeyword; - final Token endToken; - - NamedMixinApplication(this.name, this.typeParameters, - this.modifiers, this.mixinApplication, this.interfaces, - this.typedefKeyword, this.endToken); - - TypeAnnotation get superclass => mixinApplication.superclass; - NodeList get mixins => mixinApplication.mixins; - - MixinApplication asMixinApplication() => this; - NamedMixinApplication asNamedMixinApplication() => this; - - accept(Visitor visitor) => visitor.visitNamedMixinApplication(this); - - visitChildren(Visitor visitor) { - name.accept(visitor); - if (typeParameters != null) typeParameters.accept(visitor); - if (modifiers != null) modifiers.accept(visitor); - if (interfaces != null) interfaces.accept(visitor); - mixinApplication.accept(visitor); - } - - Token getBeginToken() => typedefKeyword; - Token getEndToken() => endToken; -} - -abstract class Expression extends Node { - Expression(); - - Expression asExpression() => this; - - // TODO(ahe): make class abstract instead of adding an abstract method. - accept(Visitor visitor); -} - -abstract class Statement extends Node { - Statement(); - - Statement asStatement() => this; - - // TODO(ahe): make class abstract instead of adding an abstract method. - accept(Visitor visitor); - - bool isValidBreakTarget() => true; -} - -/** - * A message send aka method invocation. In Dart, most operations can - * (and should) be considered as message sends. Getters and setters - * are just methods with a special syntax. Consequently, we model - * property access, assignment, operators, and method calls with this - * one node. - */ -class Send extends Expression { - final Node receiver; - final Node selector; - final NodeList argumentsNode; - Link<Node> get arguments => argumentsNode.nodes; - - Send([this.receiver, this.selector, this.argumentsNode]); - Send.postfix(this.receiver, this.selector, [Node argument = null]) - : argumentsNode = (argument == null) - ? new Postfix() - : new Postfix.singleton(argument); - Send.prefix(this.receiver, this.selector, [Node argument = null]) - : argumentsNode = (argument == null) - ? new Prefix() - : new Prefix.singleton(argument); - - Send asSend() => this; - - accept(Visitor visitor) => visitor.visitSend(this); - - visitChildren(Visitor visitor) { - if (receiver != null) receiver.accept(visitor); - if (selector != null) selector.accept(visitor); - if (argumentsNode != null) argumentsNode.accept(visitor); - } - - int argumentCount() { - return (argumentsNode == null) ? -1 : argumentsNode.slowLength(); - } - - bool get isSuperCall { - return receiver != null && - receiver.asIdentifier() != null && - receiver.asIdentifier().isSuper(); - } - bool get isOperator => selector is Operator; - bool get isPropertyAccess => argumentsNode == null; - bool get isFunctionObjectInvocation => selector == null; - bool get isPrefix => argumentsNode is Prefix; - bool get isPostfix => argumentsNode is Postfix; - bool get isCall => !isOperator && !isPropertyAccess; - bool get isIndex => - isOperator && identical(selector.asOperator().source.stringValue, '[]'); - bool get isLogicalAnd => - isOperator && identical(selector.asOperator().source.stringValue, '&&'); - bool get isLogicalOr => - isOperator && identical(selector.asOperator().source.stringValue, '||'); - bool get isParameterCheck => - isOperator && identical(selector.asOperator().source.stringValue, '?'); - - Token getBeginToken() { - if (isPrefix && !isIndex) return selector.getBeginToken(); - return firstBeginToken(receiver, selector); - } - - Token getEndToken() { - if (isPrefix) { - if (receiver != null) return receiver.getEndToken(); - if (selector != null) return selector.getEndToken(); - return null; - } - if (!isPostfix && argumentsNode != null) { - return argumentsNode.getEndToken(); - } - if (selector != null) return selector.getEndToken(); - return receiver.getBeginToken(); - } - - Send copyWithReceiver(Node newReceiver) { - assert(receiver == null); - return new Send(newReceiver, selector, argumentsNode); - } -} - -class Postfix extends NodeList { - Postfix() : super(null, const Link<Node>()); - Postfix.singleton(Node argument) : super.singleton(argument); -} - -class Prefix extends NodeList { - Prefix() : super(null, const Link<Node>()); - Prefix.singleton(Node argument) : super.singleton(argument); -} - -class SendSet extends Send { - final Operator assignmentOperator; - SendSet(receiver, selector, this.assignmentOperator, argumentsNode) - : super(receiver, selector, argumentsNode); - SendSet.postfix(receiver, - selector, - this.assignmentOperator, - [Node argument = null]) - : super.postfix(receiver, selector, argument); - SendSet.prefix(receiver, - selector, - this.assignmentOperator, - [Node argument = null]) - : super.prefix(receiver, selector, argument); - - SendSet asSendSet() => this; - - accept(Visitor visitor) => visitor.visitSendSet(this); - - visitChildren(Visitor visitor) { - super.visitChildren(visitor); - if (assignmentOperator != null) assignmentOperator.accept(visitor); - } - - Send copyWithReceiver(Node newReceiver) { - assert(receiver == null); - return new SendSet(newReceiver, selector, assignmentOperator, - argumentsNode); - } - - Token getBeginToken() { - if (isPrefix) return assignmentOperator.getBeginToken(); - return super.getBeginToken(); - } - - Token getEndToken() { - if (isPostfix) return assignmentOperator.getEndToken(); - return super.getEndToken(); - } -} - -class NewExpression extends Expression { - /** The token NEW or CONST */ - final Token newToken; - - // Note: we expect that send.receiver is null. - final Send send; - - NewExpression([this.newToken, this.send]); - - accept(Visitor visitor) => visitor.visitNewExpression(this); - - visitChildren(Visitor visitor) { - if (send != null) send.accept(visitor); - } - - bool isConst() { - return identical(newToken.stringValue, 'const') - || identical(newToken.stringValue, '@'); - } - - Token getBeginToken() => newToken; - - Token getEndToken() => send.getEndToken(); -} - -class NodeList extends Node { - final Link<Node> nodes; - final Token beginToken; - final Token endToken; - final SourceString delimiter; - bool get isEmpty => nodes.isEmpty; - - NodeList([this.beginToken, this.nodes, this.endToken, this.delimiter]); - - Iterator<Node> get iterator => nodes.iterator; - - NodeList.singleton(Node node) : this(null, const Link<Node>().prepend(node)); - NodeList.empty() : this(null, const Link<Node>()); - - NodeList asNodeList() => this; - - int slowLength() { - int result = 0; - for (Link<Node> cursor = nodes; !cursor.isEmpty; cursor = cursor.tail) { - result++; - } - return result; - } - - accept(Visitor visitor) => visitor.visitNodeList(this); - - visitChildren(Visitor visitor) { - if (nodes == null) return; - for (Link<Node> link = nodes; !link.isEmpty; link = link.tail) { - if (link.head != null) link.head.accept(visitor); - } - } - - Token getBeginToken() { - if (beginToken != null) return beginToken; - if (nodes != null) { - for (Link<Node> link = nodes; !link.isEmpty; link = link.tail) { - if (link.head.getBeginToken() != null) { - return link.head.getBeginToken(); - } - if (link.head.getEndToken() != null) { - return link.head.getEndToken(); - } - } - } - return endToken; - } - - Token getEndToken() { - if (endToken != null) return endToken; - if (nodes != null) { - Link<Node> link = nodes; - if (link.isEmpty) return beginToken; - while (!link.tail.isEmpty) link = link.tail; - if (link.head.getEndToken() != null) return link.head.getEndToken(); - if (link.head.getBeginToken() != null) return link.head.getBeginToken(); - } - return beginToken; - } -} - -class Block extends Statement { - final NodeList statements; - - Block(this.statements); - - Block asBlock() => this; - - accept(Visitor visitor) => visitor.visitBlock(this); - - visitChildren(Visitor visitor) { - if (statements != null) statements.accept(visitor); - } - - Token getBeginToken() => statements.getBeginToken(); - - Token getEndToken() => statements.getEndToken(); -} - -class If extends Statement { - final ParenthesizedExpression condition; - final Statement thenPart; - final Statement elsePart; - - final Token ifToken; - final Token elseToken; - - If(this.condition, this.thenPart, this.elsePart, - this.ifToken, this.elseToken); - - If asIf() => this; - - bool get hasElsePart => elsePart != null; - - void validate() { - // TODO(ahe): Check that condition has size one. - } - - accept(Visitor visitor) => visitor.visitIf(this); - - visitChildren(Visitor visitor) { - if (condition != null) condition.accept(visitor); - if (thenPart != null) thenPart.accept(visitor); - if (elsePart != null) elsePart.accept(visitor); - } - - Token getBeginToken() => ifToken; - - Token getEndToken() { - if (elsePart == null) return thenPart.getEndToken(); - return elsePart.getEndToken(); - } -} - -class Conditional extends Expression { - final Expression condition; - final Expression thenExpression; - final Expression elseExpression; - - final Token questionToken; - final Token colonToken; - - Conditional(this.condition, this.thenExpression, - this.elseExpression, this.questionToken, this.colonToken); - - Conditional asConditional() => this; - - accept(Visitor visitor) => visitor.visitConditional(this); - - visitChildren(Visitor visitor) { - condition.accept(visitor); - thenExpression.accept(visitor); - elseExpression.accept(visitor); - } - - Token getBeginToken() => condition.getBeginToken(); - - Token getEndToken() => elseExpression.getEndToken(); -} - -class For extends Loop { - /** Either a variable declaration or an expression. */ - final Node initializer; - /** Either an expression statement or an empty statement. */ - final Statement conditionStatement; - final NodeList update; - - final Token forToken; - - For(this.initializer, this.conditionStatement, this.update, body, - this.forToken) : super(body); - - For asFor() => this; - - Expression get condition { - if (conditionStatement is ExpressionStatement) { - return conditionStatement.asExpressionStatement().expression; - } else { - return null; - } - } - - accept(Visitor visitor) => visitor.visitFor(this); - - visitChildren(Visitor visitor) { - if (initializer != null) initializer.accept(visitor); - if (conditionStatement != null) conditionStatement.accept(visitor); - if (update != null) update.accept(visitor); - if (body != null) body.accept(visitor); - } - - Token getBeginToken() => forToken; - - Token getEndToken() { - return body.getEndToken(); - } -} - -class FunctionDeclaration extends Statement { - final FunctionExpression function; - - FunctionDeclaration(this.function); - - FunctionDeclaration asFunctionDeclaration() => this; - - accept(Visitor visitor) => visitor.visitFunctionDeclaration(this); - - visitChildren(Visitor visitor) => function.accept(visitor); - - Token getBeginToken() => function.getBeginToken(); - Token getEndToken() => function.getEndToken(); -} - -class FunctionExpression extends Expression { - final Node name; - - /** - * List of VariableDefinitions or NodeList. - * - * A NodeList can only occur at the end and holds named parameters. - */ - final NodeList parameters; - - final Statement body; - final TypeAnnotation returnType; - final Modifiers modifiers; - final NodeList initializers; - - final Token getOrSet; - - FunctionExpression(this.name, this.parameters, this.body, this.returnType, - this.modifiers, this.initializers, this.getOrSet) { - assert(modifiers != null); - } - - FunctionExpression asFunctionExpression() => this; - - accept(Visitor visitor) => visitor.visitFunctionExpression(this); - - visitChildren(Visitor visitor) { - if (modifiers != null) modifiers.accept(visitor); - if (returnType != null) returnType.accept(visitor); - if (name != null) name.accept(visitor); - if (parameters != null) parameters.accept(visitor); - if (initializers != null) initializers.accept(visitor); - if (body != null) body.accept(visitor); - } - - bool hasBody() => body.asEmptyStatement() == null; - - bool hasEmptyBody() { - Block block = body.asBlock(); - if (block == null) return false; - return block.statements.isEmpty; - } - - Token getBeginToken() { - Token token = firstBeginToken(modifiers, returnType); - if (token != null) return token; - if (getOrSet != null) return getOrSet; - return firstBeginToken(name, parameters); - } - - Token getEndToken() { - Token token = (body == null) ? null : body.getEndToken(); - token = (token == null) ? parameters.getEndToken() : token; - return (token == null) ? name.getEndToken() : token; - } -} - -typedef void DecodeErrorHandler(Token token, var error); - -abstract class Literal<T> extends Expression { - final Token token; - final DecodeErrorHandler handler; - - Literal(Token this.token, DecodeErrorHandler this.handler); - - T get value; - - visitChildren(Visitor visitor) {} - - Token getBeginToken() => token; - - Token getEndToken() => token; -} - -class LiteralInt extends Literal<int> { - LiteralInt(Token token, DecodeErrorHandler handler) : super(token, handler); - - LiteralInt asLiteralInt() => this; - - int get value { - try { - Token valueToken = token; - if (identical(valueToken.kind, PLUS_TOKEN)) valueToken = valueToken.next; - return int.parse(valueToken.value.slowToString()); - } on FormatException catch (ex) { - (this.handler)(token, ex); - } - } - - accept(Visitor visitor) => visitor.visitLiteralInt(this); -} - -class LiteralDouble extends Literal<double> { - LiteralDouble(Token token, DecodeErrorHandler handler) - : super(token, handler); - - LiteralDouble asLiteralDouble() => this; - - double get value { - try { - Token valueToken = token; - if (identical(valueToken.kind, PLUS_TOKEN)) valueToken = valueToken.next; - return double.parse(valueToken.value.slowToString()); - } on FormatException catch (ex) { - (this.handler)(token, ex); - } - } - - accept(Visitor visitor) => visitor.visitLiteralDouble(this); -} - -class LiteralBool extends Literal<bool> { - LiteralBool(Token token, DecodeErrorHandler handler) : super(token, handler); - - LiteralBool asLiteralBool() => this; - - bool get value { - if (identical(token.stringValue, 'true')) return true; - if (identical(token.stringValue, 'false')) return false; - (this.handler)(token, "not a bool ${token.value}"); - } - - accept(Visitor visitor) => visitor.visitLiteralBool(this); -} - - -class StringQuoting { - static const StringQuoting SINGLELINE_DQ = - const StringQuoting($DQ, raw: false, leftQuoteLength: 1); - static const StringQuoting RAW_SINGLELINE_DQ = - const StringQuoting($DQ, raw: true, leftQuoteLength: 1); - static const StringQuoting MULTILINE_DQ = - const StringQuoting($DQ, raw: false, leftQuoteLength: 3); - static const StringQuoting RAW_MULTILINE_DQ = - const StringQuoting($DQ, raw: true, leftQuoteLength: 3); - static const StringQuoting MULTILINE_NL_DQ = - const StringQuoting($DQ, raw: false, leftQuoteLength: 4); - static const StringQuoting RAW_MULTILINE_NL_DQ = - const StringQuoting($DQ, raw: true, leftQuoteLength: 4); - static const StringQuoting MULTILINE_NL2_DQ = - const StringQuoting($DQ, raw: false, leftQuoteLength: 5); - static const StringQuoting RAW_MULTILINE_NL2_DQ = - const StringQuoting($DQ, raw: true, leftQuoteLength: 5); - static const StringQuoting SINGLELINE_SQ = - const StringQuoting($SQ, raw: false, leftQuoteLength: 1); - static const StringQuoting RAW_SINGLELINE_SQ = - const StringQuoting($SQ, raw: true, leftQuoteLength: 1); - static const StringQuoting MULTILINE_SQ = - const StringQuoting($SQ, raw: false, leftQuoteLength: 3); - static const StringQuoting RAW_MULTILINE_SQ = - const StringQuoting($SQ, raw: true, leftQuoteLength: 3); - static const StringQuoting MULTILINE_NL_SQ = - const StringQuoting($SQ, raw: false, leftQuoteLength: 4); - static const StringQuoting RAW_MULTILINE_NL_SQ = - const StringQuoting($SQ, raw: true, leftQuoteLength: 4); - static const StringQuoting MULTILINE_NL2_SQ = - const StringQuoting($SQ, raw: false, leftQuoteLength: 5); - static const StringQuoting RAW_MULTILINE_NL2_SQ = - const StringQuoting($SQ, raw: true, leftQuoteLength: 5); - - - static const List<StringQuoting> mapping = const <StringQuoting>[ - SINGLELINE_DQ, - RAW_SINGLELINE_DQ, - MULTILINE_DQ, - RAW_MULTILINE_DQ, - MULTILINE_NL_DQ, - RAW_MULTILINE_NL_DQ, - MULTILINE_NL2_DQ, - RAW_MULTILINE_NL2_DQ, - SINGLELINE_SQ, - RAW_SINGLELINE_SQ, - MULTILINE_SQ, - RAW_MULTILINE_SQ, - MULTILINE_NL_SQ, - RAW_MULTILINE_NL_SQ, - MULTILINE_NL2_SQ, - RAW_MULTILINE_NL2_SQ - ]; - final bool raw; - final int leftQuoteCharCount; - final int quote; - const StringQuoting(this.quote, {bool raw, int leftQuoteLength}) - : this.raw = raw, this.leftQuoteCharCount = leftQuoteLength; - String get quoteChar => identical(quote, $DQ) ? '"' : "'"; - - int get leftQuoteLength => (raw ? 1 : 0) + leftQuoteCharCount; - int get rightQuoteLength => (leftQuoteCharCount > 2) ? 3 : 1; - static StringQuoting getQuoting(int quote, bool raw, int quoteLength) { - int index = quoteLength - 1; - if (quoteLength > 2) index -= 1; - return mapping[(raw ? 1 : 0) + index * 2 + (identical(quote, $SQ) ? 8 : 0)]; - } -} - -/** - * Superclass for classes representing string literals. - */ -abstract class StringNode extends Expression { - DartString get dartString; - bool get isInterpolation; - - StringNode asStringNode() => this; -} - -class LiteralString extends StringNode { - final Token token; - /** Non-null on validated string literals. */ - final DartString dartString; - - LiteralString(this.token, this.dartString); - - LiteralString asLiteralString() => this; - - void visitChildren(Visitor visitor) {} - - bool get isInterpolation => false; - bool isValidated() => dartString != null; - - Token getBeginToken() => token; - Token getEndToken() => token; - - accept(Visitor visitor) => visitor.visitLiteralString(this); -} - -class LiteralNull extends Literal<SourceString> { - LiteralNull(Token token) : super(token, null); - - LiteralNull asLiteralNull() => this; - - SourceString get value => null; - - accept(Visitor visitor) => visitor.visitLiteralNull(this); -} - -class LiteralList extends Expression { - final NodeList typeArguments; - final NodeList elements; - - final Token constKeyword; - - LiteralList(this.typeArguments, this.elements, this.constKeyword); - - bool isConst() => constKeyword != null; - - LiteralList asLiteralList() => this; - accept(Visitor visitor) => visitor.visitLiteralList(this); - - visitChildren(Visitor visitor) { - if (typeArguments != null) typeArguments.accept(visitor); - elements.accept(visitor); - } - - Token getBeginToken() { - if (constKeyword != null) return constKeyword; - return firstBeginToken(typeArguments, elements); - } - - Token getEndToken() => elements.getEndToken(); -} - -class Identifier extends Expression { - final Token token; - - SourceString get source => token.value; - - Identifier(Token this.token); - - bool isThis() => identical(source.stringValue, 'this'); - - bool isSuper() => identical(source.stringValue, 'super'); - - Identifier asIdentifier() => this; - - accept(Visitor visitor) => visitor.visitIdentifier(this); - - visitChildren(Visitor visitor) {} - - Token getBeginToken() => token; - - Token getEndToken() => token; -} - -class Operator extends Identifier { - Operator(Token token) : super(token); - - Operator asOperator() => this; - - accept(Visitor visitor) => visitor.visitOperator(this); -} - -class Return extends Statement { - final Node expression; - final Token beginToken; - final Token endToken; - - Return(this.beginToken, this.endToken, this.expression); - - Return asReturn() => this; - - bool get hasExpression => expression != null; - - bool get isRedirectingFactoryBody => beginToken.stringValue == '='; - - accept(Visitor visitor) => visitor.visitReturn(this); - - visitChildren(Visitor visitor) { - if (expression != null) expression.accept(visitor); - } - - Token getBeginToken() => beginToken; - - Token getEndToken() { - if (endToken == null) return expression.getEndToken(); - return endToken; - } -} - -class ExpressionStatement extends Statement { - final Expression expression; - final Token endToken; - - ExpressionStatement(this.expression, this.endToken); - - ExpressionStatement asExpressionStatement() => this; - - accept(Visitor visitor) => visitor.visitExpressionStatement(this); - - visitChildren(Visitor visitor) { - if (expression != null) expression.accept(visitor); - } - - Token getBeginToken() => expression.getBeginToken(); - - Token getEndToken() => endToken; -} - -class Throw extends Statement { - final Expression expression; - - final Token throwToken; - final Token endToken; - - Throw(this.expression, this.throwToken, this.endToken); - - Throw asThrow() => this; - - accept(Visitor visitor) => visitor.visitThrow(this); - - visitChildren(Visitor visitor) { - if (expression != null) expression.accept(visitor); - } - - Token getBeginToken() => throwToken; - - Token getEndToken() => endToken; -} - -class TypeAnnotation extends Node { - final Expression typeName; - final NodeList typeArguments; - - TypeAnnotation(Expression this.typeName, NodeList this.typeArguments); - - TypeAnnotation asTypeAnnotation() => this; - - accept(Visitor visitor) => visitor.visitTypeAnnotation(this); - - visitChildren(Visitor visitor) { - typeName.accept(visitor); - if (typeArguments != null) typeArguments.accept(visitor); - } - - Token getBeginToken() => typeName.getBeginToken(); - - Token getEndToken() => typeName.getEndToken(); -} - -class TypeVariable extends Node { - final Identifier name; - final TypeAnnotation bound; - TypeVariable(Identifier this.name, TypeAnnotation this.bound); - - accept(Visitor visitor) => visitor.visitTypeVariable(this); - - visitChildren(Visitor visitor) { - name.accept(visitor); - if (bound != null) { - bound.accept(visitor); - } - } - - TypeVariable asTypeVariable() => this; - - Token getBeginToken() => name.getBeginToken(); - - Token getEndToken() { - return (bound != null) ? bound.getEndToken() : name.getEndToken(); - } -} - -class VariableDefinitions extends Statement { - final TypeAnnotation type; - final Modifiers modifiers; - final NodeList definitions; - VariableDefinitions(this.type, this.modifiers, this.definitions) { - assert(modifiers != null); - } - - VariableDefinitions asVariableDefinitions() => this; - - accept(Visitor visitor) => visitor.visitVariableDefinitions(this); - - visitChildren(Visitor visitor) { - if (type != null) type.accept(visitor); - if (definitions != null) definitions.accept(visitor); - } - - Token getBeginToken() { - var token = firstBeginToken(modifiers, type); - if (token == null) { - token = definitions.getBeginToken(); - } - return token; - } - - Token getEndToken() => definitions.getEndToken(); -} - -abstract class Loop extends Statement { - Expression get condition; - final Statement body; - - Loop(this.body); - - bool isValidContinueTarget() => true; -} - -class DoWhile extends Loop { - final Token doKeyword; - final Token whileKeyword; - final Token endToken; - - final Expression condition; - - DoWhile(Statement body, Expression this.condition, - Token this.doKeyword, Token this.whileKeyword, Token this.endToken) - : super(body); - - DoWhile asDoWhile() => this; - - accept(Visitor visitor) => visitor.visitDoWhile(this); - - visitChildren(Visitor visitor) { - if (condition != null) condition.accept(visitor); - if (body != null) body.accept(visitor); - } - - Token getBeginToken() => doKeyword; - - Token getEndToken() => endToken; -} - -class While extends Loop { - final Token whileKeyword; - final Expression condition; - - While(Expression this.condition, Statement body, - Token this.whileKeyword) : super(body); - - While asWhile() => this; - - accept(Visitor visitor) => visitor.visitWhile(this); - - visitChildren(Visitor visitor) { - if (condition != null) condition.accept(visitor); - if (body != null) body.accept(visitor); - } - - Token getBeginToken() => whileKeyword; - - Token getEndToken() => body.getEndToken(); -} - -class ParenthesizedExpression extends Expression { - final Expression expression; - final BeginGroupToken beginToken; - - ParenthesizedExpression(Expression this.expression, - BeginGroupToken this.beginToken); - - ParenthesizedExpression asParenthesizedExpression() => this; - - accept(Visitor visitor) => visitor.visitParenthesizedExpression(this); - - visitChildren(Visitor visitor) { - if (expression != null) expression.accept(visitor); - } - - Token getBeginToken() => beginToken; - - Token getEndToken() => beginToken.endGroup; -} - -/** Representation of modifiers such as static, abstract, final, etc. */ -class Modifiers extends Node { - /** - * Pseudo-constant for empty modifiers. - */ - static final Modifiers EMPTY = new Modifiers(new NodeList.empty()); - - /* TODO(ahe): The following should be validated relating to modifiers: - * 1. The nodes must come in a certain order. - * 2. The keywords "var" and "final" may not be used at the same time. - * 3. The keywords "abstract" and "external" may not be used at the same time. - * 4. The type of an element must be null if isVar() is true. - */ - - final NodeList nodes; - /** Bit pattern to easy check what modifiers are present. */ - final int flags; - - static const int FLAG_STATIC = 1; - static const int FLAG_ABSTRACT = FLAG_STATIC << 1; - static const int FLAG_FINAL = FLAG_ABSTRACT << 1; - static const int FLAG_VAR = FLAG_FINAL << 1; - static const int FLAG_CONST = FLAG_VAR << 1; - static const int FLAG_FACTORY = FLAG_CONST << 1; - static const int FLAG_EXTERNAL = FLAG_FACTORY << 1; - - Modifiers(NodeList nodes) : this.withFlags(nodes, computeFlags(nodes.nodes)); - - Modifiers.withFlags(this.nodes, this.flags); - - static int computeFlags(Link<Node> nodes) { - int flags = 0; - for (; !nodes.isEmpty; nodes = nodes.tail) { - String value = nodes.head.asIdentifier().source.stringValue; - if (identical(value, 'static')) flags |= FLAG_STATIC; - else if (identical(value, 'abstract')) flags |= FLAG_ABSTRACT; - else if (identical(value, 'final')) flags |= FLAG_FINAL; - else if (identical(value, 'var')) flags |= FLAG_VAR; - else if (identical(value, 'const')) flags |= FLAG_CONST; - else if (identical(value, 'factory')) flags |= FLAG_FACTORY; - else if (identical(value, 'external')) flags |= FLAG_EXTERNAL; - else throw 'internal error: ${nodes.head}'; - } - return flags; - } - - Node findModifier(String modifier) { - Link<Node> nodeList = nodes.nodes; - for (; !nodeList.isEmpty; nodeList = nodeList.tail) { - String value = nodeList.head.asIdentifier().source.stringValue; - if(identical(value, modifier)) { - return nodeList.head; - } - } - return null; - } - - Modifiers asModifiers() => this; - Token getBeginToken() => nodes.getBeginToken(); - Token getEndToken() => nodes.getEndToken(); - accept(Visitor visitor) => visitor.visitModifiers(this); - visitChildren(Visitor visitor) => nodes.accept(visitor); - - bool isStatic() => (flags & FLAG_STATIC) != 0; - bool isAbstract() => (flags & FLAG_ABSTRACT) != 0; - bool isFinal() => (flags & FLAG_FINAL) != 0; - bool isVar() => (flags & FLAG_VAR) != 0; - bool isConst() => (flags & FLAG_CONST) != 0; - bool isFactory() => (flags & FLAG_FACTORY) != 0; - bool isExternal() => (flags & FLAG_EXTERNAL) != 0; - - Node getStatic() => findModifier('static'); - - /** - * Use this to check if the declaration is either explicitly or implicitly - * final. - */ - bool isFinalOrConst() => isFinal() || isConst(); - - String toString() { - LinkBuilder<String> builder = new LinkBuilder<String>(); - if (isStatic()) builder.addLast('static'); - if (isAbstract()) builder.addLast('abstract'); - if (isFinal()) builder.addLast('final'); - if (isVar()) builder.addLast('var'); - if (isConst()) builder.addLast('const'); - if (isFactory()) builder.addLast('factory'); - if (isExternal()) builder.addLast('external'); - StringBuffer buffer = new StringBuffer(); - builder.toLink().printOn(buffer, ', '); - return buffer.toString(); - } -} - -class StringInterpolation extends StringNode { - final LiteralString string; - final NodeList parts; - - StringInterpolation(this.string, this.parts); - - StringInterpolation asStringInterpolation() => this; - - DartString get dartString => null; - bool get isInterpolation => true; - - accept(Visitor visitor) => visitor.visitStringInterpolation(this); - - visitChildren(Visitor visitor) { - string.accept(visitor); - parts.accept(visitor); - } - - Token getBeginToken() => string.getBeginToken(); - Token getEndToken() => parts.getEndToken(); -} - -class StringInterpolationPart extends Node { - final Expression expression; - final LiteralString string; - - StringInterpolationPart(this.expression, this.string); - - StringInterpolationPart asStringInterpolationPart() => this; - - accept(Visitor visitor) => visitor.visitStringInterpolationPart(this); - - visitChildren(Visitor visitor) { - expression.accept(visitor); - string.accept(visitor); - } - - Token getBeginToken() => expression.getBeginToken(); - - Token getEndToken() => string.getEndToken(); -} - -/** - * A class representing juxtaposed string literals. - * The string literals can be both plain literals and string interpolations. - */ -class StringJuxtaposition extends StringNode { - final Expression first; - final Expression second; - - /** - * Caches the check for whether this juxtaposition contains a string - * interpolation - */ - bool isInterpolationCache = null; - - /** - * Caches a Dart string representation of the entire juxtaposition's - * content. Only juxtapositions that don't (transitively) contains - * interpolations have a static representation. - */ - DartString dartStringCache = null; - - StringJuxtaposition(this.first, this.second); - - StringJuxtaposition asStringJuxtaposition() => this; - - bool get isInterpolation { - if (isInterpolationCache == null) { - isInterpolationCache = (first.accept(const IsInterpolationVisitor()) || - second.accept(const IsInterpolationVisitor())); - } - return isInterpolationCache; - } - - /** - * Retrieve a single DartString that represents this entire juxtaposition - * of string literals. - * Should only be called if [isInterpolation] returns false. - */ - DartString get dartString { - if (isInterpolation) { - throw new SpannableAssertionFailure( - this, "Getting dartString on interpolation;"); - } - if (dartStringCache == null) { - DartString firstString = first.accept(const GetDartStringVisitor()); - DartString secondString = second.accept(const GetDartStringVisitor()); - if (firstString == null || secondString == null) { - return null; - } - dartStringCache = new DartString.concat(firstString, secondString); - } - return dartStringCache; - } - - accept(Visitor visitor) => visitor.visitStringJuxtaposition(this); - - void visitChildren(Visitor visitor) { - first.accept(visitor); - second.accept(visitor); - } - - Token getBeginToken() => first.getBeginToken(); - - Token getEndToken() => second.getEndToken(); -} - -class EmptyStatement extends Statement { - final Token semicolonToken; - - EmptyStatement(this.semicolonToken); - - EmptyStatement asEmptyStatement() => this; - - accept(Visitor visitor) => visitor.visitEmptyStatement(this); - - visitChildren(Visitor visitor) {} - - Token getBeginToken() => semicolonToken; - - Token getEndToken() => semicolonToken; -} - -class LiteralMap extends Expression { - final NodeList typeArguments; - final NodeList entries; - - final Token constKeyword; - - LiteralMap(this.typeArguments, this.entries, this.constKeyword); - - bool isConst() => constKeyword != null; - - LiteralMap asLiteralMap() => this; - - accept(Visitor visitor) => visitor.visitLiteralMap(this); - - visitChildren(Visitor visitor) { - if (typeArguments != null) typeArguments.accept(visitor); - entries.accept(visitor); - } - - Token getBeginToken() { - if (constKeyword != null) return constKeyword; - return firstBeginToken(typeArguments, entries); - } - - Token getEndToken() => entries.getEndToken(); -} - -class LiteralMapEntry extends Node { - final Expression key; - final Expression value; - - final Token colonToken; - - LiteralMapEntry(this.key, this.colonToken, this.value); - - LiteralMapEntry asLiteralMapEntry() => this; - - accept(Visitor visitor) => visitor.visitLiteralMapEntry(this); - - visitChildren(Visitor visitor) { - key.accept(visitor); - value.accept(visitor); - } - - Token getBeginToken() => key.getBeginToken(); - - Token getEndToken() => value.getEndToken(); -} - -class NamedArgument extends Expression { - final Identifier name; - final Expression expression; - - final Token colonToken; - - NamedArgument(this.name, this.colonToken, this.expression); - - NamedArgument asNamedArgument() => this; - - accept(Visitor visitor) => visitor.visitNamedArgument(this); - - visitChildren(Visitor visitor) { - name.accept(visitor); - expression.accept(visitor); - } - - Token getBeginToken() => name.getBeginToken(); - - Token getEndToken() => expression.getEndToken(); -} - -class SwitchStatement extends Statement { - final ParenthesizedExpression parenthesizedExpression; - final NodeList cases; - - final Token switchKeyword; - - SwitchStatement(this.parenthesizedExpression, this.cases, - this.switchKeyword); - - SwitchStatement asSwitchStatement() => this; - - Expression get expression => parenthesizedExpression.expression; - - accept(Visitor visitor) => visitor.visitSwitchStatement(this); - - visitChildren(Visitor visitor) { - parenthesizedExpression.accept(visitor); - cases.accept(visitor); - } - - Token getBeginToken() => switchKeyword; - - Token getEndToken() => cases.getEndToken(); -} - -class CaseMatch extends Node { - final Token caseKeyword; - final Expression expression; - final Token colonToken; - CaseMatch(this.caseKeyword, this.expression, this.colonToken); - - CaseMatch asCaseMatch() => this; - Token getBeginToken() => caseKeyword; - Token getEndToken() => colonToken; - accept(Visitor visitor) => visitor.visitCaseMatch(this); - visitChildren(Visitor visitor) => expression.accept(visitor); -} - -class SwitchCase extends Node { - // The labels and case patterns are collected in [labelsAndCases]. - // The default keyword, if present, is collected in [defaultKeyword]. - // Any actual switch case must have at least one 'case' or 'default' - // clause. - // Notice: The labels and cases can occur interleaved in the source. - // They are separated here, since the order is irrelevant to the meaning - // of the switch. - - /** List of [Label] and [CaseMatch] nodes. */ - final NodeList labelsAndCases; - /** A "default" keyword token, if applicable. */ - final Token defaultKeyword; - /** List of statements, the body of the case. */ - final NodeList statements; - - final Token startToken; - - SwitchCase(this.labelsAndCases, this.defaultKeyword, - this.statements, this.startToken); - - SwitchCase asSwitchCase() => this; - - bool get isDefaultCase => defaultKeyword != null; - - bool isValidContinueTarget() => true; - - accept(Visitor visitor) => visitor.visitSwitchCase(this); - - visitChildren(Visitor visitor) { - labelsAndCases.accept(visitor); - statements.accept(visitor); - } - - Token getBeginToken() { - return startToken; - } - - Token getEndToken() { - if (statements.nodes.isEmpty) { - // All cases must have at least one expression or be the default. - if (defaultKeyword != null) { - // The colon after 'default'. - return defaultKeyword.next; - } - // The colon after the last expression. - return labelsAndCases.getEndToken(); - } else { - return statements.getEndToken(); - } - } -} - -abstract class GotoStatement extends Statement { - final Identifier target; - final Token keywordToken; - final Token semicolonToken; - - GotoStatement(this.target, this.keywordToken, this.semicolonToken); - - visitChildren(Visitor visitor) { - if (target != null) target.accept(visitor); - } - - Token getBeginToken() => keywordToken; - - Token getEndToken() => semicolonToken; - - // TODO(ahe): make class abstract instead of adding an abstract method. - accept(Visitor visitor); -} - -class BreakStatement extends GotoStatement { - BreakStatement(Identifier target, Token keywordToken, Token semicolonToken) - : super(target, keywordToken, semicolonToken); - - BreakStatement asBreakStatement() => this; - - accept(Visitor visitor) => visitor.visitBreakStatement(this); -} - -class ContinueStatement extends GotoStatement { - ContinueStatement(Identifier target, Token keywordToken, Token semicolonToken) - : super(target, keywordToken, semicolonToken); - - ContinueStatement asContinueStatement() => this; - - accept(Visitor visitor) => visitor.visitContinueStatement(this); -} - -class ForIn extends Loop { - final Node declaredIdentifier; - final Expression expression; - - final Token forToken; - final Token inToken; - - ForIn(this.declaredIdentifier, this.expression, - Statement body, this.forToken, this.inToken) : super(body); - - Expression get condition => null; - - ForIn asForIn() => this; - - accept(Visitor visitor) => visitor.visitForIn(this); - - visitChildren(Visitor visitor) { - declaredIdentifier.accept(visitor); - expression.accept(visitor); - body.accept(visitor); - } - - Token getBeginToken() => forToken; - - Token getEndToken() => body.getEndToken(); -} - -class Label extends Node { - final Identifier identifier; - final Token colonToken; - - Label(this.identifier, this.colonToken); - - String slowToString() => identifier.source.slowToString(); - - Label asLabel() => this; - - accept(Visitor visitor) => visitor.visitLabel(this); - - void visitChildren(Visitor visitor) { - identifier.accept(visitor); - } - - Token getBeginToken() => identifier.token; - Token getEndToken() => colonToken; -} - -class LabeledStatement extends Statement { - final NodeList labels; - final Statement statement; - - LabeledStatement(this.labels, this.statement); - - LabeledStatement asLabeledStatement() => this; - - accept(Visitor visitor) => visitor.visitLabeledStatement(this); - - visitChildren(Visitor visitor) { - labels.accept(visitor); - statement.accept(visitor); - } - - Token getBeginToken() => labels.getBeginToken(); - - Token getEndToken() => statement.getEndToken(); - - bool isValidContinueTarget() => statement.isValidContinueTarget(); - - Node getBody() => statement; -} - -class ScriptTag extends Node { - final Identifier tag; - final StringNode argument; - final Identifier prefixIdentifier; - final StringNode prefix; - - final Token beginToken; - final Token endToken; - - ScriptTag(this.tag, this.argument, this.prefixIdentifier, this.prefix, - this.beginToken, this.endToken); - - bool isImport() => tag.source == const SourceString("import"); - bool isSource() => tag.source == const SourceString("source"); - bool isLibrary() => tag.source == const SourceString("library"); - - ScriptTag asScriptTag() => this; - - accept(Visitor visitor) => visitor.visitScriptTag(this); - - visitChildren(Visitor visitor) { - tag.accept(visitor); - argument.accept(visitor); - if (prefixIdentifier != null) prefixIdentifier.accept(visitor); - if (prefix != null) prefix.accept(visitor); - } - - Token getBeginToken() => beginToken; - - Token getEndToken() => endToken; - - LibraryTag toLibraryTag() { - if (isImport()) { - Identifier prefixNode; - if (prefix != null) { - SourceString source = prefix.dartString.source; - Token prefixToken = prefix.getBeginToken(); - Token token = new StringToken.fromSource(IDENTIFIER_INFO, source, - prefixToken.charOffset); - token.next = prefixToken.next; - prefixNode = new Identifier(token); - } - return new Import(tag.token, argument, prefixNode, null, null); - } else if (isLibrary()) { - return new LibraryName(tag.token, argument, null); - } else if (isSource()) { - return new Part(tag.token, argument, null); - } else { - throw 'Unknown script tag ${tag.token.slowToString()}'; - } - } -} - -abstract class LibraryTag extends Node { - final Link<MetadataAnnotation> metadata; - - LibraryTag(this.metadata); - - bool get isLibraryName => false; - bool get isImport => false; - bool get isExport => false; - bool get isPart => false; - bool get isPartOf => false; -} - -class LibraryName extends LibraryTag { - final Expression name; - - final Token libraryKeyword; - - LibraryName(this.libraryKeyword, - this.name, - Link<MetadataAnnotation> metadata) - : super(metadata); - - bool get isLibraryName => true; - - LibraryName asLibraryName() => this; - - accept(Visitor visitor) => visitor.visitLibraryName(this); - - visitChildren(Visitor visitor) => name.accept(visitor); - - Token getBeginToken() => libraryKeyword; - - Token getEndToken() => name.getEndToken().next; -} - -/** - * This tag describes a dependency between one library and the exported - * identifiers of another library. The other library is specified by the [uri]. - * Combinators filter away some identifiers from the other library. - */ -abstract class LibraryDependency extends LibraryTag { - final StringNode uri; - final NodeList combinators; - - LibraryDependency(this.uri, - this.combinators, - Link<MetadataAnnotation> metadata) - : super(metadata); -} - -/** - * An [:import:] library tag. - * - * An import tag is dependency on another library where the exported identifiers - * are put into the import scope of the importing library. The import scope is - * only visible inside the library. - */ -class Import extends LibraryDependency { - final Identifier prefix; - final Token importKeyword; - - Import(this.importKeyword, StringNode uri, - this.prefix, NodeList combinators, - Link<MetadataAnnotation> metadata) - : super(uri, combinators, metadata); - - bool get isImport => true; - - Import asImport() => this; - - Token get asKeyword => prefix == null ? null : uri.getEndToken().next; - - accept(Visitor visitor) => visitor.visitImport(this); - - visitChildren(Visitor visitor) { - uri.accept(visitor); - if (prefix != null) prefix.accept(visitor); - if (combinators != null) combinators.accept(visitor); - } - - Token getBeginToken() => importKeyword; - - Token getEndToken() { - if (combinators != null) return combinators.getEndToken().next; - if (prefix != null) return prefix.getEndToken().next; - return uri.getEndToken().next; - } -} - -/** - * An [:export:] library tag. - * - * An export tag is dependency on another library where the exported identifiers - * are put into the export scope of the exporting library. The export scope is - * not visible inside the library. - */ -class Export extends LibraryDependency { - final Token exportKeyword; - - Export(this.exportKeyword, - StringNode uri, - NodeList combinators, - Link<MetadataAnnotation> metadata) - : super(uri, combinators, metadata); - - bool get isExport => true; - - Export asExport() => this; - - accept(Visitor visitor) => visitor.visitExport(this); - - visitChildren(Visitor visitor) { - uri.accept(visitor); - if (combinators != null) combinators.accept(visitor); - } - - Token getBeginToken() => exportKeyword; - - Token getEndToken() { - if (combinators != null) return combinators.getEndToken().next; - return uri.getEndToken().next; - } -} - -class Part extends LibraryTag { - final StringNode uri; - - final Token partKeyword; - - Part(this.partKeyword, this.uri, Link<MetadataAnnotation> metadata) - : super(metadata); - - bool get isPart => true; - - Part asPart() => this; - - accept(Visitor visitor) => visitor.visitPart(this); - - visitChildren(Visitor visitor) => uri.accept(visitor); - - Token getBeginToken() => partKeyword; - - Token getEndToken() => uri.getEndToken().next; -} - -class PartOf extends Node { - final Expression name; - - final Token partKeyword; - - final Link<MetadataAnnotation> metadata; - - PartOf(this.partKeyword, this.name, this.metadata); - - Token get ofKeyword => partKeyword.next; - - bool get isPartOf => true; - - PartOf asPartOf() => this; - - accept(Visitor visitor) => visitor.visitPartOf(this); - - visitChildren(Visitor visitor) => name.accept(visitor); - - Token getBeginToken() => partKeyword; - - Token getEndToken() => name.getEndToken().next; -} - -class Combinator extends Node { - final NodeList identifiers; - - final Token keywordToken; - - Combinator(this.identifiers, this.keywordToken); - - bool get isShow => identical(keywordToken.stringValue, 'show'); - - bool get isHide => identical(keywordToken.stringValue, 'hide'); - - Combinator asCombinator() => this; - - accept(Visitor visitor) => visitor.visitCombinator(this); - - visitChildren(Visitor visitor) => identifiers.accept(visitor); - - Token getBeginToken() => keywordToken; - - Token getEndToken() => identifiers.getEndToken(); -} - -class Typedef extends Node { - final TypeAnnotation returnType; - final Identifier name; - final NodeList typeParameters; - final NodeList formals; - - final Token typedefKeyword; - final Token endToken; - - Typedef(this.returnType, this.name, this.typeParameters, this.formals, - this.typedefKeyword, this.endToken); - - Typedef asTypedef() => this; - - accept(Visitor visitor) => visitor.visitTypedef(this); - - visitChildren(Visitor visitor) { - if (returnType != null) returnType.accept(visitor); - name.accept(visitor); - if (typeParameters != null) typeParameters.accept(visitor); - formals.accept(visitor); - } - - Token getBeginToken() => typedefKeyword; - - Token getEndToken() => endToken; -} - -class TryStatement extends Statement { - final Block tryBlock; - final NodeList catchBlocks; - final Block finallyBlock; - - final Token tryKeyword; - final Token finallyKeyword; - - TryStatement(this.tryBlock, this.catchBlocks, this.finallyBlock, - this.tryKeyword, this.finallyKeyword); - - TryStatement asTryStatement() => this; - - accept(Visitor visitor) => visitor.visitTryStatement(this); - - visitChildren(Visitor visitor) { - tryBlock.accept(visitor); - catchBlocks.accept(visitor); - if (finallyBlock != null) finallyBlock.accept(visitor); - } - - Token getBeginToken() => tryKeyword; - - Token getEndToken() { - if (finallyBlock != null) return finallyBlock.getEndToken(); - if (!catchBlocks.isEmpty) return catchBlocks.getEndToken(); - return tryBlock.getEndToken(); - } -} - -class Cascade extends Expression { - final Expression expression; - Cascade(this.expression); - - Cascade asCascade() => this; - accept(Visitor visitor) => visitor.visitCascade(this); - - void visitChildren(Visitor visitor) { - expression.accept(visitor); - } - - Token getBeginToken() => expression.getBeginToken(); - - Token getEndToken() => expression.getEndToken(); -} - -class CascadeReceiver extends Expression { - final Expression expression; - final Token cascadeOperator; - CascadeReceiver(this.expression, this.cascadeOperator); - - CascadeReceiver asCascadeReceiver() => this; - accept(Visitor visitor) => visitor.visitCascadeReceiver(this); - - void visitChildren(Visitor visitor) { - expression.accept(visitor); - } - - Token getBeginToken() => expression.getBeginToken(); - - Token getEndToken() => expression.getEndToken(); -} - -class CatchBlock extends Node { - final TypeAnnotation type; - final NodeList formals; - final Block block; - - final Token onKeyword; - final Token catchKeyword; - - CatchBlock(this.type, this.formals, this.block, - this.onKeyword, this.catchKeyword); - - CatchBlock asCatchBlock() => this; - - accept(Visitor visitor) => visitor.visitCatchBlock(this); - - Node get exception { - if (formals == null || formals.nodes.isEmpty) return null; - VariableDefinitions declarations = formals.nodes.head; - return declarations.definitions.nodes.head; - } - - Node get trace { - if (formals == null || formals.nodes.isEmpty) return null; - Link<Node> declarations = formals.nodes.tail; - if (declarations.isEmpty) return null; - VariableDefinitions head = declarations.head; - return head.definitions.nodes.head; - } - - visitChildren(Visitor visitor) { - if (type != null) type.accept(visitor); - if (formals != null) formals.accept(visitor); - block.accept(visitor); - } - - Token getBeginToken() => onKeyword != null ? onKeyword : catchKeyword; - - Token getEndToken() => block.getEndToken(); -} - -class Initializers { - static bool isSuperConstructorCall(Send node) { - return (node.receiver == null && - node.selector.asIdentifier() != null && - node.selector.asIdentifier().isSuper()) || - (node.receiver != null && - node.receiver.asIdentifier() != null && - node.receiver.asIdentifier().isSuper() && - node.selector.asIdentifier() != null); - } - - static bool isConstructorRedirect(Send node) { - return (node.receiver == null && - node.selector.asIdentifier() != null && - node.selector.asIdentifier().isThis()) || - (node.receiver != null && - node.receiver.asIdentifier() != null && - node.receiver.asIdentifier().isThis() && - node.selector.asIdentifier() != null); - } -} - -class GetDartStringVisitor extends Visitor<DartString> { - const GetDartStringVisitor(); - DartString visitNode(Node node) => null; - DartString visitStringJuxtaposition(StringJuxtaposition node) - => node.dartString; - DartString visitLiteralString(LiteralString node) => node.dartString; -} - -class IsInterpolationVisitor extends Visitor<bool> { - const IsInterpolationVisitor(); - bool visitNode(Node node) => false; - bool visitStringInterpolation(StringInterpolation node) => true; - bool visitStringJuxtaposition(StringJuxtaposition node) - => node.isInterpolation; -} - -/** - * If the given node is a send set, it visits its initializer (first - * argument). - * - * TODO(ahe): This method is controversial, the team needs to discuss - * if top-level methods are acceptable and what naming conventions to - * use. - */ -initializerDo(Node node, f(Node node)) { - SendSet send = node.asSendSet(); - if (send != null) return f(send.arguments.head); -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/tree/prettyprint.dart b/pkgs/markdown/test/lib/src/compiler/implementation/tree/prettyprint.dart deleted file mode 100644 index 129c637..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/tree/prettyprint.dart +++ /dev/null
@@ -1,480 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of tree; - -/** - * Pretty-prints Node tree in XML-like format. - * - * TODO(smok): Add main() to run from command-line to print out tree for given - * .dart file. - */ -class PrettyPrinter implements Visitor { - - /** String used to represent one level of indent. */ - static const String INDENT = " "; - - StringBuffer sb; - Link<String> tagStack; - - PrettyPrinter() : - sb = new StringBuffer(), - tagStack = const Link<String>(); - - void pushTag(String tag) { - tagStack = tagStack.prepend(tag); - } - - String popTag() { - assert(!tagStack.isEmpty); - String tag = tagStack.head; - tagStack = tagStack.tail; - return tag; - } - - /** - * Adds given string to result string. - */ - void add(SourceString string) { - string.printOn(sb); - } - - void addBeginAndEndTokensToParams(Node node, Map params) { - params['getBeginToken'] = tokenToStringOrNull(node.getBeginToken()); - params['getEndToken'] = tokenToStringOrNull(node.getEndToken()); - } - - /** - * Adds given node type to result string. - * The method "opens" the node, meaning that all output after calling - * this method and before calling closeNode() will represent contents - * of given node. - */ - void openNode(Node node, String type, [Map params]) { - if (params == null) params = new Map(); - addCurrentIndent(); - sb.add("<"); - addBeginAndEndTokensToParams(node, params); - addTypeWithParams(type, params); - sb.add(">\n"); - pushTag(type); - } - - /** - * Adds given node to result string. - */ - void openAndCloseNode(Node node, String type, [Map params]) { - if (params == null) params = new Map(); - addCurrentIndent(); - sb.add("<"); - addBeginAndEndTokensToParams(node, params); - addTypeWithParams(type, params); - sb.add("/>\n"); - } - - /** - * Closes current node type. - */ - void closeNode() { - String tag = popTag(); - addCurrentIndent(); - sb.add("</"); - addTypeWithParams(tag); - sb.add(">\n"); - } - - void addTypeWithParams(String type, [Map params]) { - if (params == null) params = new Map(); - sb.add("${type}"); - params.forEach((k, v) { - String value; - if (v != null) { - value = v - .replaceAll("<", "<") - .replaceAll(">", ">") - .replaceAll('"', "'"); - } else { - value = "[null]"; - } - sb.add(' $k="$value"'); - }); - } - - void addCurrentIndent() { - tagStack.forEach((_) { sb.add(INDENT); }); - } - - /** - * Pretty-prints given node tree into string. - */ - static String prettyPrint(Node node) { - var p = new PrettyPrinter(); - node.accept(p); - return p.sb.toString(); - } - - visitNodeWithChildren(Node node, String type) { - openNode(node, type); - node.visitChildren(this); - closeNode(); - } - - visitBlock(Block node) { - visitNodeWithChildren(node, "Block"); - } - - visitBreakStatement(BreakStatement node) { - visitNodeWithChildren(node, "BreakStatement"); - } - - visitCascade(Cascade node) { - visitNodeWithChildren(node, "Cascade"); - } - - visitCascadeReceiver(CascadeReceiver node) { - visitNodeWithChildren(node, "CascadeReceiver"); - } - - visitCaseMatch(CaseMatch node) { - visitNodeWithChildren(node, "CaseMatch"); - } - - visitCatchBlock(CatchBlock node) { - visitNodeWithChildren(node, "CatchBlock"); - } - - visitClassNode(ClassNode node) { - openNode(node, "ClassNode", { - "extendsKeyword" : tokenToStringOrNull(node.extendsKeyword) - }); - visitChildNode(node.name, "name"); - visitChildNode(node.superclass, "superclass"); - visitChildNode(node.interfaces, "interfaces"); - visitChildNode(node.typeParameters, "typeParameters"); - visitChildNode(node.defaultClause, "defaultClause"); - closeNode(); - } - - visitConditional(Conditional node) { - visitNodeWithChildren(node, "Conditional"); - } - - visitContinueStatement(ContinueStatement node) { - visitNodeWithChildren(node, "ContinueStatement"); - } - - visitDoWhile(DoWhile node) { - visitNodeWithChildren(node, "DoWhile"); - } - - visitEmptyStatement(EmptyStatement node) { - visitNodeWithChildren(node, "EmptyStatement"); - } - - visitExpressionStatement(ExpressionStatement node) { - visitNodeWithChildren(node, "ExpressionStatement"); - } - - visitFor(For node) { - visitNodeWithChildren(node, "For"); - } - - visitForIn(ForIn node) { - visitNodeWithChildren(node, "ForIn"); - } - - visitFunctionDeclaration(FunctionDeclaration node) { - visitNodeWithChildren(node, "FunctionDeclaration"); - } - - visitFunctionExpression(FunctionExpression node) { - openNode(node, "FunctionExpression", { - "getOrSet" : tokenToStringOrNull(node.getOrSet) - }); - visitChildNode(node.modifiers, "modifiers"); - visitChildNode(node.returnType, "returnType"); - visitChildNode(node.name, "name"); - visitChildNode(node.parameters, "parameters"); - visitChildNode(node.initializers, "initializers"); - visitChildNode(node.body, "body"); - closeNode(); - } - - visitIdentifier(Identifier node) { - openAndCloseNode(node, "Identifier", {"token" : node.token.slowToString()}); - } - - visitIf(If node) { - visitNodeWithChildren(node, "If"); - } - - visitLabel(Label node) { - visitNodeWithChildren(node, "Label"); - } - - visitLabeledStatement(LabeledStatement node) { - visitNodeWithChildren(node, "LabeledStatement"); - } - - // Custom. - printLiteral(Literal node, String type) { - openAndCloseNode(node, type, {"value" : node.value.toString()}); - } - - visitLiteralBool(LiteralBool node) { - printLiteral(node, "LiteralBool"); - } - - visitLiteralDouble(LiteralDouble node) { - printLiteral(node, "LiteralDouble"); - } - - visitLiteralInt(LiteralInt node) { - printLiteral(node, "LiteralInt"); - } - - /** Returns token string value or [null] if token is [null]. */ - tokenToStringOrNull(Token token) => token == null ? null : token.stringValue; - - visitLiteralList(LiteralList node) { - openNode(node, "LiteralList", { - "constKeyword" : tokenToStringOrNull(node.constKeyword) - }); - visitChildNode(node.typeArguments, "typeArguments"); - visitChildNode(node.elements, "elements"); - closeNode(); - } - - visitLiteralMap(LiteralMap node) { - visitNodeWithChildren(node, "LiteralMap"); - } - - visitLiteralMapEntry(LiteralMapEntry node) { - visitNodeWithChildren(node, "LiteralMapEntry"); - } - - visitLiteralNull(LiteralNull node) { - printLiteral(node, "LiteralNull"); - } - - visitLiteralString(LiteralString node) { - openAndCloseNode(node, "LiteralString", - {"value" : node.token.slowToString()}); - } - - visitMixinApplication(MixinApplication node) { - visitNodeWithChildren(node, "MixinApplication"); - } - - visitModifiers(Modifiers node) { - visitNodeWithChildren(node, "Modifiers"); - } - - visitNamedArgument(NamedArgument node) { - visitNodeWithChildren(node, "NamedArgument"); - } - - visitNamedMixinApplication(NamedMixinApplication node) { - visitNodeWithChildren(node, "NamedMixinApplication"); - } - - visitNewExpression(NewExpression node) { - visitNodeWithChildren(node, "NewExpression"); - } - - visitNodeList(NodeList node) { - var params = { - "delimiter" : - node.delimiter != null ? node.delimiter.stringValue : null - }; - if (node.nodes.toList().length == 0) { - openAndCloseNode(node, "NodeList", params); - } else { - openNode(node, "NodeList", params); - node.visitChildren(this); - closeNode(); - } - } - - visitOperator(Operator node) { - openAndCloseNode(node, "Operator", {"value" : node.token.slowToString()}); - } - - visitParenthesizedExpression(ParenthesizedExpression node) { - visitNodeWithChildren(node, "ParenthesizedExpression"); - } - - visitReturn(Return node) { - openNode(node, "Return"); - visitChildNode(node.expression, "expression"); - closeNode(); - } - - visitScriptTag(ScriptTag node) { - visitNodeWithChildren(node, "ScriptTag"); - } - - visitChildNode(Node node, String fieldName) { - if (node == null) return; - addCurrentIndent(); - sb.add("<$fieldName>\n"); - pushTag(fieldName); - node.accept(this); - popTag(); - addCurrentIndent(); - sb.add("</$fieldName>\n"); - } - - openSendNodeWithFields(Send node, String type) { - openNode(node, type, { - "isPrefix" : "${node.isPrefix}", - "isPostfix" : "${node.isPostfix}", - "isIndex" : "${node.isIndex}" - }); - visitChildNode(node.receiver, "receiver"); - visitChildNode(node.selector, "selector"); - visitChildNode(node.argumentsNode, "argumentsNode"); - } - - visitSend(Send node) { - openSendNodeWithFields(node, "Send"); - closeNode(); - } - - visitSendSet(SendSet node) { - openSendNodeWithFields(node, "SendSet"); - visitChildNode(node.assignmentOperator, "assignmentOperator"); - closeNode(); - } - - visitStringInterpolation(StringInterpolation node) { - visitNodeWithChildren(node, "StringInterpolation"); - } - - visitStringInterpolationPart(StringInterpolationPart node) { - visitNodeWithChildren(node, "StringInterpolationPart"); - } - - visitStringJuxtaposition(StringJuxtaposition node) { - visitNodeWithChildren(node, "StringJuxtaposition"); - } - - visitSwitchCase(SwitchCase node) { - visitNodeWithChildren(node, "SwitchCase"); - } - - visitSwitchStatement(SwitchStatement node) { - visitNodeWithChildren(node, "SwitchStatement"); - } - - visitThrow(Throw node) { - visitNodeWithChildren(node, "Throw"); - } - - visitTryStatement(TryStatement node) { - visitNodeWithChildren(node, "TryStatement"); - } - - visitTypeAnnotation(TypeAnnotation node) { - openNode(node, "TypeAnnotation"); - visitChildNode(node.typeName, "typeName"); - visitChildNode(node.typeArguments, "typeArguments"); - closeNode(); - } - - visitTypedef(Typedef node) { - visitNodeWithChildren(node, "Typedef"); - } - - visitTypeVariable(TypeVariable node) { - openNode(node, "TypeVariable"); - visitChildNode(node.name, "name"); - visitChildNode(node.bound, "bound"); - closeNode(); - } - - visitVariableDefinitions(VariableDefinitions node) { - openNode(node, "VariableDefinitions"); - visitChildNode(node.type, "type"); - visitChildNode(node.modifiers, "modifiers"); - visitChildNode(node.definitions, "definitions"); - closeNode(); - } - - visitWhile(While node) { - visitNodeWithChildren(node, "While"); - } - - visitNode(Node node) { - unimplemented('visitNode', node: node); - } - - visitCombinator(Combinator node) { - unimplemented('visitNode', node: node); - } - - visitExport(Export node) { - unimplemented('visitNode', node: node); - } - - visitExpression(Expression node) { - unimplemented('visitNode', node: node); - } - - visitGotoStatement(GotoStatement node) { - unimplemented('visitNode', node: node); - } - - visitImport(Import node) { - unimplemented('visitNode', node: node); - } - - visitLibraryDependency(Node node) { - unimplemented('visitNode', node: node); - } - - visitLibraryName(LibraryName node) { - unimplemented('visitNode', node: node); - } - - visitLibraryTag(LibraryTag node) { - unimplemented('visitNode', node: node); - } - - visitLiteral(Literal node) { - unimplemented('visitNode', node: node); - } - - visitLoop(Loop node) { - unimplemented('visitNode', node: node); - } - - visitPart(Part node) { - unimplemented('visitNode', node: node); - } - - visitPartOf(PartOf node) { - unimplemented('visitNode', node: node); - } - - visitPostfix(Postfix node) { - unimplemented('visitNode', node: node); - } - - visitPrefix(Prefix node) { - unimplemented('visitNode', node: node); - } - - visitStatement(Statement node) { - unimplemented('visitNode', node: node); - } - - visitStringNode(StringNode node) { - unimplemented('visitNode', node: node); - } - - unimplemented(String message, {Node node}) { - throw message; - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/tree/tree.dart b/pkgs/markdown/test/lib/src/compiler/implementation/tree/tree.dart deleted file mode 100644 index 3faa36c..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/tree/tree.dart +++ /dev/null
@@ -1,22 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library tree; - -import 'dart:math'; -import 'dart:collection'; - -import '../scanner/scannerlib.dart'; -import '../util/util.dart'; -import '../util/characters.dart'; - -import '../resolution/secret_tree_element.dart' show TreeElementMixin; - -import '../elements/elements.dart' show MetadataAnnotation; - -part 'dartstring.dart'; -part 'nodes.dart'; -part 'prettyprint.dart'; -part 'unparser.dart'; -part 'visitors.dart';
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/tree/unparser.dart b/pkgs/markdown/test/lib/src/compiler/implementation/tree/unparser.dart deleted file mode 100644 index 9c20f2d..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/tree/unparser.dart +++ /dev/null
@@ -1,627 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of tree; - -String unparse(Node node) { - Unparser unparser = new Unparser(); - unparser.unparse(node); - return unparser.result; -} - -class Unparser implements Visitor { - final StringBuffer sb; - - String get result => sb.toString(); - - Unparser() : sb = new StringBuffer(); - - void add(SourceString string) { - string.printOn(sb); - } - - void addToken(Token token) { - if (token == null) return; - add(token.value); - if (identical(token.kind, KEYWORD_TOKEN) - || identical(token.kind, IDENTIFIER_TOKEN)) { - sb.add(' '); - } - } - - unparse(Node node) { visit(node); } - - visit(Node node) { - if (node != null) node.accept(this); - } - - visitBlock(Block node) { - visit(node.statements); - } - - visitCascade(Cascade node) { - visit(node.expression); - } - - visitCascadeReceiver(CascadeReceiver node) { - visit(node.expression); - } - - unparseClassWithBody(ClassNode node, Iterable<Node> members) { - addToken(node.beginToken); - if (node.beginToken.stringValue == 'abstract') { - addToken(node.beginToken.next); - } - visit(node.name); - if (node.typeParameters != null) { - visit(node.typeParameters); - } - if (node.extendsKeyword != null) { - sb.add(' '); - addToken(node.extendsKeyword); - visit(node.superclass); - } - if (!node.interfaces.isEmpty) { - sb.add(' '); - visit(node.interfaces); - } - if (node.defaultClause != null) { - sb.add(' default '); - visit(node.defaultClause); - } - sb.add('{'); - for (final member in members) { - visit(member); - } - sb.add('}'); - } - - visitClassNode(ClassNode node) { - unparseClassWithBody(node, node.body.nodes); - } - - visitMixinApplication(MixinApplication node) { - visit(node.superclass); - sb.add(' with '); - visit(node.mixins); - } - - visitNamedMixinApplication(NamedMixinApplication node) { - sb.add('typedef '); - visit(node.name); - if (node.typeParameters != null) { - visit(node.typeParameters); - } - sb.add(' = '); - if (!node.modifiers.nodes.isEmpty) { - visit(node.modifiers); - sb.add(' '); - } - visit(node.mixinApplication); - if (node.interfaces != null) { - sb.add(' implements '); - visit(node.interfaces); - } - sb.add(';'); - } - - visitConditional(Conditional node) { - visit(node.condition); - add(node.questionToken.value); - visit(node.thenExpression); - add(node.colonToken.value); - visit(node.elseExpression); - } - - visitExpressionStatement(ExpressionStatement node) { - visit(node.expression); - add(node.endToken.value); - } - - visitFor(For node) { - add(node.forToken.value); - sb.add('('); - visit(node.initializer); - sb.add(';'); - visit(node.conditionStatement); - visit(node.update); - sb.add(')'); - visit(node.body); - } - - visitFunctionDeclaration(FunctionDeclaration node) { - visit(node.function); - } - - void unparseFunctionName(Node name) { - // TODO(antonm): that's a workaround as currently FunctionExpression - // names are modelled with Send and it emits operator[] as only - // operator, without [] which are expected to be emitted with - // arguments. - if (name is Send) { - Send send = name; - assert(send is !SendSet); - if (!send.isOperator) { - // Looks like a factory method. - visit(send.receiver); - sb.add('.'); - } else { - visit(send.receiver); - Identifier identifier = send.selector.asIdentifier(); - if (identical(identifier.token.kind, KEYWORD_TOKEN)) { - sb.add(' '); - } else if (identifier.source == const SourceString('negate')) { - // TODO(ahe): Remove special case for negate. - sb.add(' '); - } - } - visit(send.selector); - } else { - visit(name); - } - } - - visitFunctionExpression(FunctionExpression node) { - if (!node.modifiers.nodes.isEmpty) { - visit(node.modifiers); - sb.add(' '); - } - if (node.returnType != null) { - visit(node.returnType); - sb.add(' '); - } - if (node.getOrSet != null) { - add(node.getOrSet.value); - sb.add(' '); - } - unparseFunctionName(node.name); - visit(node.parameters); - visit(node.initializers); - visit(node.body); - } - - visitIdentifier(Identifier node) { - add(node.token.value); - } - - visitIf(If node) { - add(node.ifToken.value); - visit(node.condition); - visit(node.thenPart); - if (node.hasElsePart) { - add(node.elseToken.value); - if (node.elsePart is !Block) sb.add(' '); - visit(node.elsePart); - } - } - - visitLiteralBool(LiteralBool node) { - add(node.token.value); - } - - visitLiteralDouble(LiteralDouble node) { - add(node.token.value); - // -Lit is represented as a send. - if (node.token.kind == PLUS_TOKEN) add(node.token.next.value); - } - - visitLiteralInt(LiteralInt node) { - add(node.token.value); - // -Lit is represented as a send. - if (node.token.kind == PLUS_TOKEN) add(node.token.next.value); - } - - visitLiteralString(LiteralString node) { - add(node.token.value); - } - - visitStringJuxtaposition(StringJuxtaposition node) { - visit(node.first); - sb.add(" "); - visit(node.second); - } - - visitLiteralNull(LiteralNull node) { - add(node.token.value); - } - - visitNewExpression(NewExpression node) { - addToken(node.newToken); - visit(node.send); - } - - visitLiteralList(LiteralList node) { - if (node.constKeyword != null) add(node.constKeyword.value); - visit(node.typeArguments); - visit(node.elements); - // If list is empty, emit space after [] to disambiguate cases like []==[]. - if (node.elements.isEmpty) sb.add(' '); - } - - visitModifiers(Modifiers node) => node.visitChildren(this); - - /** - * Unparses given NodeList starting from specific node. - */ - unparseNodeListFrom(NodeList node, Link<Node> from) { - if (from.isEmpty) return; - String delimiter = (node.delimiter == null) ? "" : "${node.delimiter}"; - visit(from.head); - for (Link link = from.tail; !link.isEmpty; link = link.tail) { - sb.add(delimiter); - visit(link.head); - } - } - - visitNodeList(NodeList node) { - addToken(node.beginToken); - if (node.nodes != null) { - unparseNodeListFrom(node, node.nodes); - } - if (node.endToken != null) add(node.endToken.value); - } - - visitOperator(Operator node) { - visitIdentifier(node); - } - - visitReturn(Return node) { - if (node.isRedirectingFactoryBody) { - sb.add(' '); - } - add(node.beginToken.value); - if (node.hasExpression && node.beginToken.stringValue != '=>') { - sb.add(' '); - } - visit(node.expression); - if (node.endToken != null) add(node.endToken.value); - } - - unparseSendReceiver(Send node, {bool spacesNeeded: false}) { - if (node.receiver == null) return; - visit(node.receiver); - CascadeReceiver asCascadeReceiver = node.receiver.asCascadeReceiver(); - if (asCascadeReceiver != null) { - add(asCascadeReceiver.cascadeOperator.value); - } else if (node.selector.asOperator() == null) { - sb.add('.'); - } else if (spacesNeeded) { - sb.add(' '); - } - } - - visitSend(Send node) { - Operator op = node.selector.asOperator(); - String opString = op != null ? op.source.stringValue : null; - bool spacesNeeded = identical(opString, 'is') || identical(opString, 'as'); - - if (node.isPrefix) visit(node.selector); - unparseSendReceiver(node, spacesNeeded: spacesNeeded); - if (!node.isPrefix && !node.isIndex) visit(node.selector); - if (spacesNeeded) sb.add(' '); - // Also add a space for sequences like x + +1 and y - -y. - // TODO(ahe): remove case for '+' when we drop the support for it. - if (node.argumentsNode != null && (identical(opString, '-') - || identical(opString, '+'))) { - Token beginToken = node.argumentsNode.getBeginToken(); - if (beginToken != null && identical(beginToken.stringValue, opString)) { - sb.add(' '); - } - } - visit(node.argumentsNode); - } - - visitSendSet(SendSet node) { - if (node.isPrefix) { - sb.add(' '); - visit(node.assignmentOperator); - } - unparseSendReceiver(node); - if (node.isIndex) { - sb.add('['); - visit(node.arguments.head); - sb.add(']'); - if (!node.isPrefix) visit(node.assignmentOperator); - unparseNodeListFrom(node.argumentsNode, node.argumentsNode.nodes.tail); - } else { - visit(node.selector); - if (!node.isPrefix) { - visit(node.assignmentOperator); - if (node.assignmentOperator.source.slowToString() != '=') sb.add(' '); - } - visit(node.argumentsNode); - } - } - - visitThrow(Throw node) { - add(node.throwToken.value); - if (node.expression != null) { - sb.add(' '); - visit(node.expression); - } - node.endToken.value.printOn(sb); - } - - visitTypeAnnotation(TypeAnnotation node) { - visit(node.typeName); - visit(node.typeArguments); - } - - visitTypeVariable(TypeVariable node) { - visit(node.name); - if (node.bound != null) { - sb.add(' extends '); - visit(node.bound); - } - } - - visitVariableDefinitions(VariableDefinitions node) { - visit(node.modifiers); - if (!node.modifiers.nodes.isEmpty) { - sb.add(' '); - } - if (node.type != null) { - visit(node.type); - sb.add(' '); - } - visit(node.definitions); - } - - visitDoWhile(DoWhile node) { - add(node.doKeyword.value); - if (node.body is !Block) sb.add(' '); - visit(node.body); - add(node.whileKeyword.value); - visit(node.condition); - sb.add(node.endToken.value); - } - - visitWhile(While node) { - addToken(node.whileKeyword); - visit(node.condition); - visit(node.body); - } - - visitParenthesizedExpression(ParenthesizedExpression node) { - add(node.getBeginToken().value); - visit(node.expression); - add(node.getEndToken().value); - } - - visitStringInterpolation(StringInterpolation node) { - visit(node.string); - visit(node.parts); - } - - visitStringInterpolationPart(StringInterpolationPart node) { - sb.add('\${'); // TODO(ahe): Preserve the real tokens. - visit(node.expression); - sb.add('}'); - visit(node.string); - } - - visitEmptyStatement(EmptyStatement node) { - add(node.semicolonToken.value); - } - - visitGotoStatement(GotoStatement node) { - add(node.keywordToken.value); - if (node.target != null) { - sb.add(' '); - visit(node.target); - } - add(node.semicolonToken.value); - } - - visitBreakStatement(BreakStatement node) { - visitGotoStatement(node); - } - - visitContinueStatement(ContinueStatement node) { - visitGotoStatement(node); - } - - visitForIn(ForIn node) { - add(node.forToken.value); - sb.add('('); - visit(node.declaredIdentifier); - sb.add(' '); - addToken(node.inToken); - visit(node.expression); - sb.add(')'); - visit(node.body); - } - - visitLabel(Label node) { - visit(node.identifier); - add(node.colonToken.value); - } - - visitLabeledStatement(LabeledStatement node) { - visit(node.labels); - visit(node.statement); - } - - visitLiteralMap(LiteralMap node) { - if (node.constKeyword != null) add(node.constKeyword.value); - if (node.typeArguments != null) visit(node.typeArguments); - visit(node.entries); - } - - visitLiteralMapEntry(LiteralMapEntry node) { - visit(node.key); - add(node.colonToken.value); - visit(node.value); - } - - visitNamedArgument(NamedArgument node) { - visit(node.name); - add(node.colonToken.value); - visit(node.expression); - } - - visitSwitchStatement(SwitchStatement node) { - addToken(node.switchKeyword); - visit(node.parenthesizedExpression); - visit(node.cases); - } - - visitSwitchCase(SwitchCase node) { - visit(node.labelsAndCases); - if (node.isDefaultCase) { - sb.add('default:'); - } - visit(node.statements); - } - - unparseImportTag(String uri, [String prefix]) { - final suffix = prefix == null ? '' : ' as $prefix'; - sb.add('import "$uri"$suffix;'); - } - - visitScriptTag(ScriptTag node) { - add(node.beginToken.value); - visit(node.tag); - sb.add('('); - visit(node.argument); - if (node.prefixIdentifier != null) { - visit(node.prefixIdentifier); - sb.add(':'); - visit(node.prefix); - } - sb.add(')'); - add(node.endToken.value); - } - - visitTryStatement(TryStatement node) { - addToken(node.tryKeyword); - visit(node.tryBlock); - visit(node.catchBlocks); - if (node.finallyKeyword != null) { - addToken(node.finallyKeyword); - visit(node.finallyBlock); - } - } - - visitCaseMatch(CaseMatch node) { - add(node.caseKeyword.value); - sb.add(" "); - visit(node.expression); - add(node.colonToken.value); - } - - visitCatchBlock(CatchBlock node) { - addToken(node.onKeyword); - if (node.type != null) { - visit(node.type); - sb.add(' '); - } - addToken(node.catchKeyword); - visit(node.formals); - visit(node.block); - } - - visitTypedef(Typedef node) { - addToken(node.typedefKeyword); - if (node.returnType != null) { - visit(node.returnType); - sb.add(' '); - } - visit(node.name); - if (node.typeParameters != null) { - visit(node.typeParameters); - } - visit(node.formals); - add(node.endToken.value); - } - - visitLibraryName(LibraryName node) { - addToken(node.libraryKeyword); - node.visitChildren(this); - add(node.getEndToken().value); - } - - visitImport(Import node) { - addToken(node.importKeyword); - visit(node.uri); - if (node.prefix != null) { - sb.add(' '); - addToken(node.asKeyword); - visit(node.prefix); - } - if (node.combinators != null) { - sb.add(' '); - visit(node.combinators); - } - add(node.getEndToken().value); - } - - visitExport(Export node) { - addToken(node.exportKeyword); - visit(node.uri); - if (node.combinators != null) { - sb.add(' '); - visit(node.combinators); - } - add(node.getEndToken().value); - } - - visitPart(Part node) { - addToken(node.partKeyword); - visit(node.uri); - add(node.getEndToken().value); - } - - visitPartOf(PartOf node) { - addToken(node.partKeyword); - addToken(node.ofKeyword); - visit(node.name); - add(node.getEndToken().value); - } - - visitCombinator(Combinator node) { - addToken(node.keywordToken); - visit(node.identifiers); - } - - visitNode(Node node) { - throw 'internal error'; // Should not be called. - } - - visitExpression(Expression node) { - throw 'internal error'; // Should not be called. - } - - visitLibraryTag(LibraryTag node) { - throw 'internal error'; // Should not be called. - } - - visitLibraryDependency(Node node) { - throw 'internal error'; // Should not be called. - } - - visitLiteral(Literal node) { - throw 'internal error'; // Should not be called. - } - - visitLoop(Loop node) { - throw 'internal error'; // Should not be called. - } - - visitPostfix(Postfix node) { - throw 'internal error'; // Should not be called. - } - - visitPrefix(Prefix node) { - throw 'internal error'; // Should not be called. - } - - visitStatement(Statement node) { - throw 'internal error'; // Should not be called. - } - - visitStringNode(StringNode node) { - throw 'internal error'; // Should not be called. - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/tree/visitors.dart b/pkgs/markdown/test/lib/src/compiler/implementation/tree/visitors.dart deleted file mode 100644 index 9096cff..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/tree/visitors.dart +++ /dev/null
@@ -1,21 +0,0 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of tree; - -/** - * This visitor takes another visitor and applies it to every - * node in the tree. There is currently no way to control the - * traversal. - */ -class TraversingVisitor extends Visitor { - final Visitor visitor; - - TraversingVisitor(Visitor this.visitor); - - visitNode(Node node) { - node.accept(visitor); - node.visitChildren(this); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/tree_validator.dart b/pkgs/markdown/test/lib/src/compiler/implementation/tree_validator.dart deleted file mode 100644 index 6a3b93f..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/tree_validator.dart +++ /dev/null
@@ -1,78 +0,0 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of dart2js; - -class TreeValidatorTask extends CompilerTask { - TreeValidatorTask(Compiler compiler) : super(compiler); - - void validate(Node tree) { - assert(check(tree)); - } - - bool check(Node tree) { - List<InvalidNodeError> errors = []; - void report(node, message) { - final error = new InvalidNodeError(node, message); - errors.add(error); - compiler.reportWarning(node, message); - }; - final validator = new ValidatorVisitor(report); - tree.accept(new TraversingVisitor(validator)); - - return errors.isEmpty; - } -} - -class ValidatorVisitor extends Visitor { - final Function reportInvalidNode; - - ValidatorVisitor(Function this.reportInvalidNode); - - expect(Node node, bool test, [message]) { - if (!test) reportInvalidNode(node, message); - } - - visitNode(Node node) {} - - visitSendSet(SendSet node) { - final selector = node.selector; - final name = node.assignmentOperator.source.stringValue; - final arguments = node.arguments; - - expect(node, arguments != null); - expect(node, selector is Identifier, 'selector is not assignable'); - if (identical(name, '++') || identical(name, '--')) { - expect(node, node.assignmentOperator is Operator); - if (node.isIndex) { - expect(node.arguments.tail.head, node.arguments.tail.isEmpty); - } else { - expect(node.arguments.head, node.arguments.isEmpty); - } - } else { - expect(node, !node.arguments.isEmpty); - } - } - - visitReturn(Return node) { - if (!node.isRedirectingFactoryBody && node.hasExpression) { - // We allow non-expression expressions in Return nodes, but only when - // using them to hold redirecting factory constructors. - expect(node, node.expression.asExpression() != null); - } - } -} - -class InvalidNodeError { - final Node node; - final String message; - InvalidNodeError(this.node, [this.message]); - - toString() { - String nodeString = node.toDebugString(); - String result = 'invalid node: $nodeString'; - if (message != null) result = '$result ($message)'; - return result; - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/typechecker.dart b/pkgs/markdown/test/lib/src/compiler/implementation/typechecker.dart deleted file mode 100644 index 01fa607..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/typechecker.dart +++ /dev/null
@@ -1,751 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of dart2js; - -class TypeCheckerTask extends CompilerTask { - TypeCheckerTask(Compiler compiler) : super(compiler); - String get name => "Type checker"; - - static const bool LOG_FAILURES = false; - - void check(Node tree, TreeElements elements) { - measure(() { - Visitor visitor = - new TypeCheckerVisitor(compiler, elements, compiler.types); - try { - tree.accept(visitor); - } on CancelTypeCheckException catch (e) { - if (LOG_FAILURES) { - // Do not warn about unimplemented features; log message instead. - compiler.log("'${e.node}': ${e.reason}"); - } - } - }); - } -} - -class CancelTypeCheckException { - final Node node; - final String reason; - - CancelTypeCheckException(this.node, this.reason); -} - -class TypeCheckerVisitor implements Visitor<DartType> { - final Compiler compiler; - final TreeElements elements; - final Types types; - - Node lastSeenNode; - DartType expectedReturnType; - ClassElement currentClass; - - Link<DartType> cascadeTypes = const Link<DartType>(); - - DartType intType; - DartType doubleType; - DartType boolType; - DartType stringType; - DartType objectType; - DartType listType; - - TypeCheckerVisitor(this.compiler, this.elements, this.types) { - intType = compiler.intClass.computeType(compiler); - doubleType = compiler.doubleClass.computeType(compiler); - boolType = compiler.boolClass.computeType(compiler); - stringType = compiler.stringClass.computeType(compiler); - objectType = compiler.objectClass.computeType(compiler); - listType = compiler.listClass.computeType(compiler); - } - - DartType fail(node, [reason]) { - String message = 'cannot type-check'; - if (reason != null) { - message = '$message: $reason'; - } - throw new CancelTypeCheckException(node, message); - } - - reportTypeWarning(Node node, MessageKind kind, [Map arguments = const {}]) { - compiler.reportWarning(node, new TypeWarning(kind, arguments)); - } - - // TODO(karlklose): remove these functions. - DartType unhandledStatement() => StatementType.NOT_RETURNING; - DartType unhandledExpression() => types.dynamicType; - - DartType analyzeNonVoid(Node node) { - DartType type = analyze(node); - if (type == types.voidType) { - reportTypeWarning(node, MessageKind.VOID_EXPRESSION); - } - return type; - } - - DartType analyzeWithDefault(Node node, DartType defaultValue) { - return node != null ? analyze(node) : defaultValue; - } - - DartType analyze(Node node) { - if (node == null) { - final String error = 'internal error: unexpected node: null'; - if (lastSeenNode != null) { - fail(null, error); - } else { - compiler.cancel(error); - } - } else { - lastSeenNode = node; - } - DartType result = node.accept(this); - // TODO(karlklose): record type? - if (result == null) { - fail(node, 'internal error: type is null'); - } - return result; - } - - /** - * Check if a value of type t can be assigned to a variable, - * parameter or return value of type s. - */ - checkAssignable(Node node, DartType s, DartType t) { - if (!types.isAssignable(s, t)) { - reportTypeWarning(node, MessageKind.NOT_ASSIGNABLE, - {'fromType': s, 'toType': t}); - } - } - - checkCondition(Expression condition) { - checkAssignable(condition, boolType, analyze(condition)); - } - - void pushCascadeType(DartType type) { - cascadeTypes = cascadeTypes.prepend(type); - } - - DartType popCascadeType() { - DartType type = cascadeTypes.head; - cascadeTypes = cascadeTypes.tail; - return type; - } - - DartType visitBlock(Block node) { - return analyze(node.statements); - } - - DartType visitCascade(Cascade node) { - analyze(node.expression); - return popCascadeType(); - } - - DartType visitCascadeReceiver(CascadeReceiver node) { - DartType type = analyze(node.expression); - pushCascadeType(type); - return type; - } - - DartType visitClassNode(ClassNode node) { - fail(node); - } - - DartType visitMixinApplication(MixinApplication node) { - fail(node); - } - - DartType visitNamedMixinApplication(NamedMixinApplication node) { - fail(node); - } - - DartType visitDoWhile(DoWhile node) { - StatementType bodyType = analyze(node.body); - checkCondition(node.condition); - return bodyType.join(StatementType.NOT_RETURNING); - } - - DartType visitExpressionStatement(ExpressionStatement node) { - analyze(node.expression); - return StatementType.NOT_RETURNING; - } - - /** Dart Programming Language Specification: 11.5.1 For Loop */ - DartType visitFor(For node) { - analyzeWithDefault(node.initializer, StatementType.NOT_RETURNING); - checkCondition(node.condition); - analyzeWithDefault(node.update, StatementType.NOT_RETURNING); - StatementType bodyType = analyze(node.body); - return bodyType.join(StatementType.NOT_RETURNING); - } - - DartType visitFunctionDeclaration(FunctionDeclaration node) { - analyze(node.function); - return StatementType.NOT_RETURNING; - } - - DartType visitFunctionExpression(FunctionExpression node) { - DartType type; - DartType returnType; - DartType previousType; - final FunctionElement element = elements[node]; - if (Elements.isUnresolved(element)) return types.dynamicType; - if (identical(element.kind, ElementKind.GENERATIVE_CONSTRUCTOR) || - identical(element.kind, ElementKind.GENERATIVE_CONSTRUCTOR_BODY)) { - type = types.dynamicType; - returnType = types.voidType; - } else { - FunctionType functionType = computeType(element); - returnType = functionType.returnType; - type = functionType; - } - DartType previous = expectedReturnType; - expectedReturnType = returnType; - if (element.isMember()) currentClass = element.getEnclosingClass(); - StatementType bodyType = analyze(node.body); - if (returnType != types.voidType && returnType != types.dynamicType - && bodyType != StatementType.RETURNING) { - MessageKind kind; - if (bodyType == StatementType.MAYBE_RETURNING) { - kind = MessageKind.MAYBE_MISSING_RETURN; - } else { - kind = MessageKind.MISSING_RETURN; - } - reportTypeWarning(node.name, kind); - } - expectedReturnType = previous; - return type; - } - - DartType visitIdentifier(Identifier node) { - if (node.isThis()) { - return currentClass.computeType(compiler); - } else { - // This is an identifier of a formal parameter. - return types.dynamicType; - } - } - - DartType visitIf(If node) { - checkCondition(node.condition); - StatementType thenType = analyze(node.thenPart); - StatementType elseType = node.hasElsePart ? analyze(node.elsePart) - : StatementType.NOT_RETURNING; - return thenType.join(elseType); - } - - DartType visitLoop(Loop node) { - return unhandledStatement(); - } - - DartType lookupMethodType(Node node, ClassElement classElement, - SourceString name) { - Element member = classElement.lookupLocalMember(name); - if (member == null) { - classElement.ensureResolved(compiler); - for (Link<DartType> supertypes = classElement.allSupertypes; - !supertypes.isEmpty && member == null; - supertypes = supertypes.tail) { - ClassElement lookupTarget = supertypes.head.element; - member = lookupTarget.lookupLocalMember(name); - } - } - if (member != null && member.kind == ElementKind.FUNCTION) { - return computeType(member); - } - reportTypeWarning(node, MessageKind.METHOD_NOT_FOUND, - {'className': classElement.name, 'methodName': name}); - return types.dynamicType; - } - - // TODO(johnniwinther): Provide the element from which the type came in order - // to give better error messages. - void analyzeArguments(Send send, DartType type) { - Link<Node> arguments = send.arguments; - if (type == null || identical(type, types.dynamicType)) { - while(!arguments.isEmpty) { - analyze(arguments.head); - arguments = arguments.tail; - } - } else { - FunctionType funType = type; - Link<DartType> parameterTypes = funType.parameterTypes; - Link<DartType> optionalParameterTypes = funType.optionalParameterTypes; - while (!arguments.isEmpty) { - Node argument = arguments.head; - NamedArgument namedArgument = argument.asNamedArgument(); - if (namedArgument != null) { - argument = namedArgument.expression; - SourceString argumentName = namedArgument.name.source; - DartType namedParameterType = - funType.getNamedParameterType(argumentName); - if (namedParameterType == null) { - // TODO(johnniwinther): Provide better information on the called - // function. - reportTypeWarning(argument, MessageKind.NAMED_ARGUMENT_NOT_FOUND, - {'argumentName': argumentName}); - - analyze(argument); - } else { - checkAssignable(argument, namedParameterType, analyze(argument)); - } - } else { - if (parameterTypes.isEmpty) { - if (optionalParameterTypes.isEmpty) { - // TODO(johnniwinther): Provide better information on the - // called function. - reportTypeWarning(argument, MessageKind.ADDITIONAL_ARGUMENT); - - analyze(argument); - } else { - checkAssignable(argument, optionalParameterTypes.head, - analyze(argument)); - optionalParameterTypes = optionalParameterTypes.tail; - } - } else { - checkAssignable(argument, parameterTypes.head, analyze(argument)); - parameterTypes = parameterTypes.tail; - } - } - arguments = arguments.tail; - } - if (!parameterTypes.isEmpty) { - // TODO(johnniwinther): Provide better information on the called - // function. - reportTypeWarning(send, MessageKind.MISSING_ARGUMENT, - {'argumentType': parameterTypes.head}); - } - } - } - - DartType visitSend(Send node) { - Element element = elements[node]; - - if (Elements.isClosureSend(node, element)) { - // TODO(karlklose): Finish implementation. - return types.dynamicType; - } - - Identifier selector = node.selector.asIdentifier(); - String name = selector.source.stringValue; - - if (node.isOperator && identical(name, 'is')) { - analyze(node.receiver); - return boolType; - } else if (node.isOperator) { - final Node firstArgument = node.receiver; - final DartType firstArgumentType = analyze(node.receiver); - final arguments = node.arguments; - final Node secondArgument = arguments.isEmpty ? null : arguments.head; - final DartType secondArgumentType = - analyzeWithDefault(secondArgument, null); - - if (identical(name, '+') || identical(name, '=') || identical(name, '-') - || identical(name, '*') || identical(name, '/') || identical(name, '%') - || identical(name, '~/') || identical(name, '|') || identical(name, '&') - || identical(name, '^') || identical(name, '~')|| identical(name, '<<') - || identical(name, '>>') || identical(name, '[]')) { - return types.dynamicType; - } else if (identical(name, '<') || identical(name, '>') || identical(name, '<=') - || identical(name, '>=') || identical(name, '==') || identical(name, '!=') - || identical(name, '===') || identical(name, '!==')) { - return boolType; - } else if (identical(name, '||') || identical(name, '&&') || identical(name, '!')) { - checkAssignable(firstArgument, boolType, firstArgumentType); - if (!arguments.isEmpty) { - // TODO(karlklose): check number of arguments in validator. - checkAssignable(secondArgument, boolType, secondArgumentType); - } - return boolType; - } - fail(selector, 'unexpected operator ${name}'); - - } else if (node.isPropertyAccess) { - if (node.receiver != null) { - // TODO(karlklose): we cannot handle fields. - return unhandledExpression(); - } - if (element == null) return types.dynamicType; - return computeType(element); - - } else if (node.isFunctionObjectInvocation) { - fail(node.receiver, 'function object invocation unimplemented'); - - } else { - FunctionType computeFunType() { - if (node.receiver != null) { - DartType receiverType = analyze(node.receiver); - if (receiverType.element == compiler.dynamicClass) return null; - if (receiverType == null) { - fail(node.receiver, 'receivertype is null'); - } - if (identical(receiverType.element.kind, ElementKind.GETTER)) { - FunctionType getterType = receiverType; - receiverType = getterType.returnType; - } - ElementKind receiverKind = receiverType.element.kind; - if (identical(receiverKind, ElementKind.TYPEDEF)) { - // TODO(karlklose): handle typedefs. - return null; - } - if (identical(receiverKind, ElementKind.TYPE_VARIABLE)) { - // TODO(karlklose): handle type variables. - return null; - } - if (!identical(receiverKind, ElementKind.CLASS)) { - fail(node.receiver, 'unexpected receiver kind: ${receiverKind}'); - } - ClassElement classElement = receiverType.element; - // TODO(karlklose): substitute type arguments. - DartType memberType = - lookupMethodType(selector, classElement, selector.source); - if (identical(memberType.element, compiler.dynamicClass)) return null; - return memberType; - } else { - if (Elements.isUnresolved(element)) { - fail(node, 'unresolved ${node.selector}'); - } else if (identical(element.kind, ElementKind.FUNCTION)) { - return computeType(element); - } else if (element.isForeign(compiler)) { - return null; - } else if (identical(element.kind, ElementKind.VARIABLE) - || identical(element.kind, ElementKind.FIELD)) { - // TODO(karlklose): handle object invocations. - return null; - } else { - fail(node, 'unexpected element kind ${element.kind}'); - } - } - } - FunctionType funType = computeFunType(); - analyzeArguments(node, funType); - return (funType != null) ? funType.returnType : types.dynamicType; - } - } - - visitSendSet(SendSet node) { - Identifier selector = node.selector; - final name = node.assignmentOperator.source.stringValue; - if (identical(name, '++') || identical(name, '--')) { - final Element element = elements[node.selector]; - final DartType receiverType = computeType(element); - // TODO(karlklose): this should be the return type instead of int. - return node.isPrefix ? intType : receiverType; - } else { - DartType targetType = computeType(elements[node]); - Node value = node.arguments.head; - checkAssignable(value, targetType, analyze(value)); - return targetType; - } - } - - DartType visitLiteralInt(LiteralInt node) { - return intType; - } - - DartType visitLiteralDouble(LiteralDouble node) { - return doubleType; - } - - DartType visitLiteralBool(LiteralBool node) { - return boolType; - } - - DartType visitLiteralString(LiteralString node) { - return stringType; - } - - DartType visitStringJuxtaposition(StringJuxtaposition node) { - analyze(node.first); - analyze(node.second); - return stringType; - } - - DartType visitLiteralNull(LiteralNull node) { - return types.dynamicType; - } - - DartType visitNewExpression(NewExpression node) { - Element element = elements[node.send]; - analyzeArguments(node.send, computeType(element)); - return analyze(node.send.selector); - } - - DartType visitLiteralList(LiteralList node) { - return listType; - } - - DartType visitNodeList(NodeList node) { - DartType type = StatementType.NOT_RETURNING; - bool reportedDeadCode = false; - for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) { - DartType nextType = analyze(link.head); - if (type == StatementType.RETURNING) { - if (!reportedDeadCode) { - reportTypeWarning(link.head, MessageKind.UNREACHABLE_CODE); - reportedDeadCode = true; - } - } else if (type == StatementType.MAYBE_RETURNING){ - if (nextType == StatementType.RETURNING) { - type = nextType; - } - } else { - type = nextType; - } - } - return type; - } - - DartType visitOperator(Operator node) { - fail(node, 'internal error'); - } - - /** Dart Programming Language Specification: 11.10 Return */ - DartType visitReturn(Return node) { - if (identical(node.getBeginToken().stringValue, 'native')) { - return StatementType.RETURNING; - } - if (node.isRedirectingFactoryBody) { - // TODO(lrn): Typecheck the body. It must refer to the constructor - // of a subtype. - return StatementType.RETURNING; - } - - final expression = node.expression; - final isVoidFunction = (identical(expectedReturnType, types.voidType)); - - // Executing a return statement return e; [...] It is a static type warning - // if the type of e may not be assigned to the declared return type of the - // immediately enclosing function. - if (expression != null) { - final expressionType = analyze(expression); - if (isVoidFunction - && !types.isAssignable(expressionType, types.voidType)) { - reportTypeWarning(expression, MessageKind.RETURN_VALUE_IN_VOID); - } else { - checkAssignable(expression, expectedReturnType, expressionType); - } - - // Let f be the function immediately enclosing a return statement of the - // form 'return;' It is a static warning if both of the following conditions - // hold: - // - f is not a generative constructor. - // - The return type of f may not be assigned to void. - } else if (!types.isAssignable(expectedReturnType, types.voidType)) { - reportTypeWarning(node, MessageKind.RETURN_NOTHING, - {'returnType': expectedReturnType}); - } - return StatementType.RETURNING; - } - - DartType visitThrow(Throw node) { - if (node.expression != null) analyze(node.expression); - return StatementType.RETURNING; - } - - DartType computeType(Element element) { - if (Elements.isUnresolved(element)) return types.dynamicType; - DartType result = element.computeType(compiler); - return (result != null) ? result : types.dynamicType; - } - - DartType visitTypeAnnotation(TypeAnnotation node) { - return elements.getType(node); - } - - visitTypeVariable(TypeVariable node) { - return types.dynamicType; - } - - DartType visitVariableDefinitions(VariableDefinitions node) { - DartType type = analyzeWithDefault(node.type, types.dynamicType); - if (type == types.voidType) { - reportTypeWarning(node.type, MessageKind.VOID_VARIABLE); - type = types.dynamicType; - } - for (Link<Node> link = node.definitions.nodes; !link.isEmpty; - link = link.tail) { - Node initialization = link.head; - compiler.ensure(initialization is Identifier - || initialization is Send); - if (initialization is Send) { - DartType initializer = analyzeNonVoid(link.head); - checkAssignable(node, type, initializer); - } - } - return StatementType.NOT_RETURNING; - } - - DartType visitWhile(While node) { - checkCondition(node.condition); - StatementType bodyType = analyze(node.body); - Expression cond = node.condition.asParenthesizedExpression().expression; - if (cond.asLiteralBool() != null && cond.asLiteralBool().value == true) { - // If the condition is a constant boolean expression denoting true, - // control-flow always enters the loop body. - // TODO(karlklose): this should be StatementType.RETURNING unless there - // is a break in the loop body that has the loop or a label outside the - // loop as a target. - return bodyType; - } else { - return bodyType.join(StatementType.NOT_RETURNING); - } - } - - DartType visitParenthesizedExpression(ParenthesizedExpression node) { - return analyze(node.expression); - } - - DartType visitConditional(Conditional node) { - checkCondition(node.condition); - DartType thenType = analyzeNonVoid(node.thenExpression); - DartType elseType = analyzeNonVoid(node.elseExpression); - if (types.isSubtype(thenType, elseType)) { - return thenType; - } else if (types.isSubtype(elseType, thenType)) { - return elseType; - } else { - return objectType; - } - } - - DartType visitModifiers(Modifiers node) {} - - visitStringInterpolation(StringInterpolation node) { - node.visitChildren(this); - return stringType; - } - - visitStringInterpolationPart(StringInterpolationPart node) { - node.visitChildren(this); - return stringType; - } - - visitEmptyStatement(EmptyStatement node) { - return StatementType.NOT_RETURNING; - } - - visitBreakStatement(BreakStatement node) { - return StatementType.NOT_RETURNING; - } - - visitContinueStatement(ContinueStatement node) { - return StatementType.NOT_RETURNING; - } - - visitForIn(ForIn node) { - analyze(node.expression); - StatementType bodyType = analyze(node.body); - return bodyType.join(StatementType.NOT_RETURNING); - } - - visitLabel(Label node) { } - - visitLabeledStatement(LabeledStatement node) { - return node.statement.accept(this); - } - - visitLiteralMap(LiteralMap node) { - return unhandledExpression(); - } - - visitLiteralMapEntry(LiteralMapEntry node) { - return unhandledExpression(); - } - - visitNamedArgument(NamedArgument node) { - return unhandledExpression(); - } - - visitSwitchStatement(SwitchStatement node) { - return unhandledStatement(); - } - - visitSwitchCase(SwitchCase node) { - return unhandledStatement(); - } - - visitCaseMatch(CaseMatch node) { - return unhandledStatement(); - } - - visitTryStatement(TryStatement node) { - return unhandledStatement(); - } - - visitScriptTag(ScriptTag node) { - return unhandledExpression(); - } - - visitCatchBlock(CatchBlock node) { - return unhandledStatement(); - } - - visitTypedef(Typedef node) { - return unhandledStatement(); - } - - DartType visitNode(Node node) { - compiler.unimplemented('visitNode', node: node); - } - - DartType visitCombinator(Combinator node) { - compiler.unimplemented('visitNode', node: node); - } - - DartType visitExport(Export node) { - compiler.unimplemented('visitNode', node: node); - } - - DartType visitExpression(Expression node) { - compiler.unimplemented('visitNode', node: node); - } - - DartType visitGotoStatement(GotoStatement node) { - compiler.unimplemented('visitNode', node: node); - } - - DartType visitImport(Import node) { - compiler.unimplemented('visitNode', node: node); - } - - DartType visitLibraryName(LibraryName node) { - compiler.unimplemented('visitNode', node: node); - } - - DartType visitLibraryTag(LibraryTag node) { - compiler.unimplemented('visitNode', node: node); - } - - DartType visitLiteral(Literal node) { - compiler.unimplemented('visitNode', node: node); - } - - DartType visitPart(Part node) { - compiler.unimplemented('visitNode', node: node); - } - - DartType visitPartOf(PartOf node) { - compiler.unimplemented('visitNode', node: node); - } - - DartType visitPostfix(Postfix node) { - compiler.unimplemented('visitNode', node: node); - } - - DartType visitPrefix(Prefix node) { - compiler.unimplemented('visitNode', node: node); - } - - DartType visitStatement(Statement node) { - compiler.unimplemented('visitNode', node: node); - } - - DartType visitStringNode(StringNode node) { - compiler.unimplemented('visitNode', node: node); - } - - DartType visitLibraryDependency(LibraryDependency node) { - compiler.unimplemented('visitNode', node: node); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/types/concrete_types_inferrer.dart b/pkgs/markdown/test/lib/src/compiler/implementation/types/concrete_types_inferrer.dart deleted file mode 100644 index 6c05203..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/types/concrete_types_inferrer.dart +++ /dev/null
@@ -1,1678 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of types; - -class CancelTypeInferenceException { - final Node node; - final String reason; - - CancelTypeInferenceException(this.node, this.reason); -} - -/** - * A singleton concrete type. More precisely, a [BaseType] is one of the - * following: - * - * - a non-asbtract class like [: int :] or [: Uri :] but not [: List :] - * - the null base type - * - the unknown base type - */ -abstract class BaseType { - bool isClass(); - bool isUnknown(); - bool isNull(); -} - -/** - * A non-asbtract class like [: int :] or [: Uri :] but not [: List :]. - */ -class ClassBaseType implements BaseType { - final ClassElement element; - - ClassBaseType(this.element); - - bool operator ==(BaseType other) { - if (identical(this, other)) return true; - if (other is! ClassBaseType) return false; - return element == other.element; - } - int get hashCode => element.hashCode; - String toString() => element.name.slowToString(); - bool isClass() => true; - bool isUnknown() => false; - bool isNull() => false; -} - -/** - * The unknown base type. - */ -class UnknownBaseType implements BaseType { - const UnknownBaseType(); - bool operator ==(BaseType other) => other is UnknownBaseType; - int get hashCode => 0; - bool isClass() => false; - bool isUnknown() => true; - bool isNull() => false; - toString() => "unknown"; -} - -/** - * The null base type. - */ -class NullBaseType implements BaseType { - const NullBaseType(); - bool operator ==(BaseType other) => other is NullBaseType; - int get hashCode => 1; - bool isClass() => false; - bool isUnknown() => false; - bool isNull() => true; - toString() => "null"; -} - -/** - * An immutable set of base types, like [: {int, bool} :] or the unknown - * concrete type. - */ -abstract class ConcreteType { - factory ConcreteType.empty() { - return new UnionType(new Set<BaseType>()); - } - - /** - * The singleton constituted of the unknown base type is the unknown concrete - * type. - */ - factory ConcreteType.singleton(int maxConcreteTypeSize, BaseType baseType) { - if (baseType.isUnknown() || maxConcreteTypeSize < 1) { - return new UnknownConcreteType(); - } - Set<BaseType> singletonSet = new Set<BaseType>(); - singletonSet.add(baseType); - return new UnionType(singletonSet); - } - - factory ConcreteType.unknown() { - return const UnknownConcreteType(); - } - - ConcreteType union(int maxConcreteTypeSize, ConcreteType other); - bool isUnkown(); - bool isEmpty(); - Set<BaseType> get baseTypes; - - /** - * Returns the unique element of [: this :] if [: this :] is a singleton, - * null otherwise. - */ - ClassElement getUniqueType(); -} - -/** - * The unkown concrete type: it is absorbing for the union. - */ -class UnknownConcreteType implements ConcreteType { - const UnknownConcreteType(); - bool isUnkown() => true; - bool isEmpty() => false; - bool operator ==(ConcreteType other) => identical(this, other); - Set<BaseType> get baseTypes => - new Set<BaseType>.from([const UnknownBaseType()]); - int get hashCode => 0; - ConcreteType union(int maxConcreteTypeSize, ConcreteType other) => this; - ClassElement getUniqueType() => null; - toString() => "unknown"; -} - -/** - * An immutable set of base types, like [: {int, bool} :]. - */ -class UnionType implements ConcreteType { - final Set<BaseType> baseTypes; - - /** - * The argument should NOT be mutated later. Do not call directly, use - * ConcreteType.singleton instead. - */ - UnionType(this.baseTypes); - - bool isUnkown() => false; - bool isEmpty() => baseTypes.isEmpty; - - bool operator ==(ConcreteType other) { - if (other is! UnionType) return false; - if (baseTypes.length != other.baseTypes.length) return false; - return baseTypes.containsAll(other.baseTypes); - } - - int get hashCode { - int result = 1; - for (final baseType in baseTypes) { - result = 31 * result + baseType.hashCode; - } - return result; - } - - // TODO(polux): Collapse {num, int, ...}, {num, double, ...} and - // {int, double,...} into {num, ...} as an optimization. It will require - // UnionType to know about these class elements, which is cumbersome because - // there are no nested classes. We need factory methods instead. - ConcreteType union(int maxConcreteTypeSize, ConcreteType other) { - if (other.isUnkown()) { - return const UnknownConcreteType(); - } - UnionType otherUnion = other; // cast - Set<BaseType> newBaseTypes = new Set<BaseType>.from(baseTypes); - newBaseTypes.addAll(otherUnion.baseTypes); - return newBaseTypes.length > maxConcreteTypeSize - ? const UnknownConcreteType() - : new UnionType(newBaseTypes); - } - - ClassElement getUniqueType() { - if (baseTypes.length == 1) { - var iterator = baseTypes.iterator; - iterator.moveNext(); - BaseType uniqueBaseType = iterator.current; - if (uniqueBaseType.isClass()) { - ClassBaseType uniqueClassType = uniqueBaseType; - return uniqueClassType.element; - } - } - return null; - } - - String toString() => baseTypes.toString(); -} - -/** - * The cartesian product of concrete types: an iterable of [BaseTypeTuple]s. For - * instance, the cartesian product of the concrete types [: {A, B} :] and - * [: {C, D} :] is an itearble whose iterators will yield [: (A, C) :], - * [: (A, D) :], [: (B, C) :] and finally [: (B, D) :]. - */ -class ConcreteTypeCartesianProduct - extends Iterable<ConcreteTypesEnvironment> { - final ConcreteTypesInferrer inferrer; - final ClassElement typeOfThis; - final Map<Element, ConcreteType> concreteTypes; - ConcreteTypeCartesianProduct(this.inferrer, this.typeOfThis, - this.concreteTypes); - Iterator get iterator => concreteTypes.isEmpty - ? [new ConcreteTypesEnvironment(inferrer, new ClassBaseType(typeOfThis))] - .iterator - : new ConcreteTypeCartesianProductIterator(inferrer, - new ClassBaseType(typeOfThis), concreteTypes); - String toString() { - List<ConcreteTypesEnvironment> cartesianProduct = - new List<ConcreteTypesEnvironment>.from(this); - return cartesianProduct.toString(); - } -} - -/** - * An helper class for [ConcreteTypeCartesianProduct]. - */ -class ConcreteTypeCartesianProductIterator - implements Iterator<ConcreteTypesEnvironment> { - final ConcreteTypesInferrer inferrer; - final BaseType baseTypeOfThis; - final Map<Element, ConcreteType> concreteTypes; - final Map<Element, BaseType> nextValues; - final Map<Element, Iterator> state; - int size = 1; - int counter = 0; - ConcreteTypesEnvironment _current; - - ConcreteTypeCartesianProductIterator(this.inferrer, this.baseTypeOfThis, - Map<Element, ConcreteType> concreteTypes) - : this.concreteTypes = concreteTypes, - nextValues = new Map<Element, BaseType>(), - state = new Map<Element, Iterator>() { - if (concreteTypes.isEmpty) { - size = 0; - return; - } - for (final e in concreteTypes.keys) { - final baseTypes = concreteTypes[e].baseTypes; - size *= baseTypes.length; - } - } - - ConcreteTypesEnvironment get current => _current; - - ConcreteTypesEnvironment takeSnapshot() { - Map<Element, ConcreteType> result = new Map<Element, ConcreteType>(); - nextValues.forEach((k, v) { - result[k] = inferrer.singletonConcreteType(v); - }); - return new ConcreteTypesEnvironment.of(inferrer, result, baseTypeOfThis); - } - - bool moveNext() { - if (counter >= size) { - _current = null; - return false; - } - Element keyToIncrement = null; - for (final key in concreteTypes.keys) { - final iterator = state[key]; - if (iterator != null && iterator.moveNext()) { - nextValues[key] = state[key].current; - break; - } - Iterator newIterator = concreteTypes[key].baseTypes.iterator; - state[key] = newIterator; - newIterator.moveNext(); - nextValues[key] = newIterator.current; - } - counter++; - _current = takeSnapshot(); - return true; - } -} - -/** - * [BaseType] Constants. - */ -class BaseTypes { - final ClassBaseType intBaseType; - final ClassBaseType doubleBaseType; - final ClassBaseType numBaseType; - final ClassBaseType boolBaseType; - final ClassBaseType stringBaseType; - final ClassBaseType listBaseType; - final ClassBaseType mapBaseType; - final ClassBaseType objectBaseType; - final ClassBaseType typeBaseType; - - static _getNativeListClass(Compiler compiler) { - // TODO(polux): switch to other implementations on other backends - JavaScriptBackend backend = compiler.backend; - return backend.jsArrayClass; - } - - BaseTypes(Compiler compiler) : - intBaseType = new ClassBaseType(compiler.intClass), - doubleBaseType = new ClassBaseType(compiler.doubleClass), - numBaseType = new ClassBaseType(compiler.numClass), - boolBaseType = new ClassBaseType(compiler.boolClass), - stringBaseType = new ClassBaseType(compiler.stringClass), - // in the Javascript backend, lists are implemented by JsArray - listBaseType = new ClassBaseType(_getNativeListClass(compiler)), - mapBaseType = new ClassBaseType(compiler.mapClass), - objectBaseType = new ClassBaseType(compiler.objectClass), - typeBaseType = new ClassBaseType(compiler.typeClass); -} - -/** - * A method-local immutable mapping from variables to their inferred - * [ConcreteTypes]. Each visitor owns one. - */ -class ConcreteTypesEnvironment { - final ConcreteTypesInferrer inferrer; - final Map<Element, ConcreteType> environment; - final BaseType typeOfThis; - - ConcreteTypesEnvironment(this.inferrer, [this.typeOfThis]) : - this.environment = new Map<Element, ConcreteType>(); - ConcreteTypesEnvironment.of(this.inferrer, this.environment, this.typeOfThis); - - ConcreteType lookupType(Element element) => environment[element]; - ConcreteType lookupTypeOfThis() { - return (typeOfThis == null) - ? null - : inferrer.singletonConcreteType(typeOfThis); - } - - ConcreteTypesEnvironment put(Element element, ConcreteType type) { - Map<Element, ConcreteType> newMap = - new Map<Element, ConcreteType>.from(environment); - newMap[element] = type; - return new ConcreteTypesEnvironment.of(inferrer, newMap, typeOfThis); - } - - ConcreteTypesEnvironment join(ConcreteTypesEnvironment other) { - if (typeOfThis != other.typeOfThis) { - throw "trying to join incompatible environments"; - } - Map<Element, ConcreteType> newMap = - new Map<Element, ConcreteType>.from(environment); - other.environment.forEach((element, type) { - ConcreteType currentType = newMap[element]; - if (element == null) { - newMap[element] = type; - } else { - newMap[element] = inferrer.union(currentType, type); - } - }); - return new ConcreteTypesEnvironment.of(inferrer, newMap, typeOfThis); - } - - bool operator ==(ConcreteTypesEnvironment other) { - if (other is! ConcreteTypesEnvironment) return false; - if (typeOfThis != other.typeOfThis) return false; - if (environment.length != other.environment.length) return false; - for (Element key in environment.keys) { - if (!other.environment.containsKey(key) - || (environment[key] != other.environment[key])) { - return false; - } - } - return true; - } - - int get hashCode { - int result = (typeOfThis != null) ? typeOfThis.hashCode : 1; - environment.forEach((element, concreteType) { - result = 31 * (31 * result + element.hashCode) + - concreteType.hashCode; - }); - return result; - } - - String toString() => "{ this: $typeOfThis, env: ${environment.toString()} }"; -} - -/** - * A work item for the type inference queue. - */ -class InferenceWorkItem { - FunctionElement method; - ConcreteTypesEnvironment environment; - InferenceWorkItem(this.method, this.environment); - - toString() => "{ method = ${method.name.slowToString()}, " - "environment = $environment }"; -} - -/** - * A task which conservatively infers a [ConcreteType] for each sub expression - * of the program. The entry point is [analyzeMain]. - */ -class ConcreteTypesInferrer { - static final bool LOG_FAILURES = true; - - final String name = "Type inferrer"; - - final Compiler compiler; - - /** - * When true, the string literal [:"__dynamic_for_test":] is inferred to - * have the unknown type. - */ - // TODO(polux): get rid of this hack once we have a natural way of inferring - // the unknown type. - bool testMode = false; - - /** - * Constants representing builtin base types. Initialized in [initialize] - * and not in the constructor because the compiler elements are not yet - * populated. - */ - BaseTypes baseTypes; - - /** - * Constant representing [:ConcreteList#[]:] where [:ConcreteList:] is the - * concrete implmentation of lists for the selected backend. - */ - FunctionElement listIndex; - - /** - * Constant representing [:ConcreteList#[]=:] where [:ConcreteList:] is the - * concrete implmentation of lists for the selected backend. - */ - FunctionElement listIndexSet; - - /** - * Constant representing [:List():]. - */ - FunctionElement listConstructor; - - /** - * A cache from (function x argument base types) to concrete types, - * used to memoize [analyzeMonoSend]. Another way of seeing [cache] is as a - * map from [FunctionElement]s to "templates" in the sense of "The Cartesian - * Product Algorithm - Simple and Precise Type Inference of Parametric - * Polymorphism" by Ole Agesen. - */ - final Map<FunctionElement, Map<ConcreteTypesEnvironment, ConcreteType>> cache; - - /** A map from expressions to their inferred concrete types. */ - final Map<Node, ConcreteType> inferredTypes; - - /** A map from fields to their inferred concrete types. */ - final Map<Element, ConcreteType> inferredFieldTypes; - - /** The work queue consumed by [analyzeMain]. */ - final Queue<InferenceWorkItem> workQueue; - - /** [: callers[f] :] is the list of [: f :]'s possible callers. */ - final Map<FunctionElement, Set<FunctionElement>> callers; - - /** [: readers[field] :] is the list of [: field :]'s possible readers. */ - final Map<Element, Set<FunctionElement>> readers; - - /** The inferred type of elements stored in Lists. */ - ConcreteType listElementType; - - /** - * A map from parameters to their inferred concrete types. It plays no role - * in the analysis, it is write only. - */ - final Map<VariableElement, ConcreteType> inferredParameterTypes; - - ConcreteTypesInferrer(Compiler compiler) - : this.compiler = compiler, - cache = new Map<FunctionElement, - Map<ConcreteTypesEnvironment, ConcreteType>>(), - inferredTypes = new Map<Node, ConcreteType>(), - inferredFieldTypes = new Map<Element, ConcreteType>(), - inferredParameterTypes = new Map<VariableElement, ConcreteType>(), - workQueue = new Queue<InferenceWorkItem>(), - callers = new Map<FunctionElement, Set<FunctionElement>>(), - readers = new Map<Element, Set<FunctionElement>>(), - listElementType = new ConcreteType.empty() { - unknownConcreteType = new ConcreteType.unknown(); - emptyConcreteType = new ConcreteType.empty(); - } - - /** - * Populates [cache] with ad hoc rules like: - * - * {int} + {int} -> {int} - * {int} + {double} -> {num} - * {int} + {num} -> {double} - * ... - */ - populateCacheWithBuiltinRules() { - // Builds the environment that would be looked up if we were to analyze - // o.method(arg) where o has concrete type {receiverType} and arg has - // concrete type {argumentType}. - ConcreteTypesEnvironment makeEnvironment(BaseType receiverType, - FunctionElement method, - BaseType argumentType) { - ArgumentsTypes argumentsTypes = new ArgumentsTypes( - [singletonConcreteType(argumentType)], - new Map()); - Map<Element, ConcreteType> argumentMap = - associateArguments(method, argumentsTypes); - return new ConcreteTypesEnvironment.of(this, argumentMap, receiverType); - } - - // Adds the rule {receiverType}.method({argumentType}) -> {returnType} - // to cache. - void rule(ClassBaseType receiverType, String method, - BaseType argumentType, BaseType returnType) { - // The following line shouldn't be needed but the mock compiler doesn't - // resolve num for some reason. - receiverType.element.ensureResolved(compiler); - FunctionElement methodElement = - receiverType.element.lookupMember(new SourceString(method)); - ConcreteTypesEnvironment environment = - makeEnvironment(receiverType, methodElement, argumentType); - Map<ConcreteTypesEnvironment, ConcreteType> map = - cache.containsKey(methodElement) - ? cache[methodElement] - : new Map<ConcreteTypesEnvironment, ConcreteType>(); - map[environment] = singletonConcreteType(returnType); - cache[methodElement] = map; - } - - // The hardcoded typing rules. - final ClassBaseType int = baseTypes.intBaseType; - final ClassBaseType double = baseTypes.doubleBaseType; - final ClassBaseType num = baseTypes.numBaseType; - for (String method in ['+', '*', '-']) { - rule(int, method, int, int); - rule(int, method, double, num); - rule(int, method, num, num); - - rule(double, method, double, double); - rule(double, method, int, num); - rule(double, method, num, num); - - rule(num, method, int, num); - rule(num, method, double, num); - rule(num, method, num, num); - } - } - - // --- utility methods --- - - /** The unknown concrete type */ - ConcreteType unknownConcreteType; - - /** The empty concrete type */ - ConcreteType emptyConcreteType; - - /** Creates a singleton concrete type containing [baseType]. */ - ConcreteType singletonConcreteType(BaseType baseType) { - return new ConcreteType.singleton(compiler.maxConcreteTypeSize, baseType); - } - - /** Returns the union of its two arguments */ - ConcreteType union(ConcreteType concreteType1, ConcreteType concreteType2) { - return concreteType1.union(compiler.maxConcreteTypeSize, concreteType2); - } - - /** - * Returns all the members with name [methodName]. - */ - List<Element> getMembersByName(SourceString methodName) { - // TODO(polux): memoize? - var result = new List<Element>(); - for (ClassElement cls in compiler.enqueuer.resolution.seenClasses) { - Element elem = cls.lookupLocalMember(methodName); - if (elem != null) { - result.add(elem); - } - } - return result; - } - - /** - * Sets the concrete type associated to [node] to the union of the inferred - * concrete type so far and [type]. - */ - void augmentInferredType(Node node, ConcreteType type) { - ConcreteType currentType = inferredTypes[node]; - inferredTypes[node] = (currentType == null) - ? type - : union(currentType, type); - } - - /** - * Returns the current inferred concrete type of [field]. - */ - ConcreteType getFieldType(Element field) { - ConcreteType result = inferredFieldTypes[field]; - return (result == null) ? emptyConcreteType : result; - } - - /** - * Sets the concrete type associated to [field] to the union of the inferred - * concrete type so far and [type]. - */ - void augmentFieldType(Element field, ConcreteType type) { - ConcreteType oldType = inferredFieldTypes[field]; - ConcreteType newType = (oldType != null) - ? union(oldType, type) - : type; - if (oldType != newType) { - inferredFieldTypes[field] = newType; - final fieldReaders = readers[field]; - if (fieldReaders != null) { - for (final reader in fieldReaders) { - final readerInstances = cache[reader]; - if (readerInstances != null) { - readerInstances.forEach((environment, _) { - workQueue.addLast(new InferenceWorkItem(reader, environment)); - }); - } - } - } - } - } - - /// Augment the inferred type of elements stored in Lists. - void augmentListElementType(ConcreteType type) { - ConcreteType newType = union(listElementType, type); - if (newType != listElementType) { - invalidateCallers(listIndex); - listElementType = newType; - } - } - - /** - * Sets the concrete type associated to [parameter] to the union of the - * inferred concrete type so far and [type]. - */ - void augmentParameterType(VariableElement parameter, ConcreteType type) { - ConcreteType oldType = inferredParameterTypes[parameter]; - inferredParameterTypes[parameter] = - (oldType == null) ? type : union(oldType, type); - } - - /** - * Add [caller] to the set of [callee]'s callers. - */ - void addCaller(FunctionElement callee, FunctionElement caller) { - Set<FunctionElement> current = callers[callee]; - if (current != null) { - current.add(caller); - } else { - Set<FunctionElement> newSet = new Set<FunctionElement>(); - newSet.add(caller); - callers[callee] = newSet; - } - } - - /** - * Add [reader] to the set of [field]'s readers. - */ - void addReader(Element field, FunctionElement reader) { - Set<FunctionElement> current = readers[field]; - if (current != null) { - current.add(reader); - } else { - Set<FunctionElement> newSet = new Set<FunctionElement>(); - newSet.add(reader); - readers[field] = newSet; - } - } - - /** - * Add callers of [function] to the workqueue. - */ - void invalidateCallers(FunctionElement function) { - Set<FunctionElement> methodCallers = callers[function]; - if (methodCallers == null) return; - for (FunctionElement caller in methodCallers) { - Map<ConcreteTypesEnvironment, ConcreteType> callerInstances = - cache[caller]; - if (callerInstances != null) { - callerInstances.forEach((environment, _) { - workQueue.addLast( - new InferenceWorkItem(caller, environment)); - }); - } - } - } - - // -- query -- - - /** - * Get the inferred concrete type of [node]. - */ - ConcreteType getConcreteTypeOfNode(Node node) => inferredTypes[node]; - - /** - * Get the inferred concrete type of [parameter]. - */ - ConcreteType getConcreteTypeOfParameter(VariableElement parameter) { - return inferredParameterTypes[parameter]; - } - - // --- analysis --- - - /** - * Returns the concrete type returned by [function] given arguments of - * concrete types [argumentsTypes]. If [function] is static then - * [receiverType] must be null, else [function] must be a member of the class - * of [receiverType]. - */ - ConcreteType getSendReturnType(FunctionElement function, - ClassElement receiverType, - ArgumentsTypes argumentsTypes) { - ConcreteType result = emptyConcreteType; - Map<Element, ConcreteType> argumentMap = - associateArguments(function, argumentsTypes); - // if the association failed, this send will never occur or will fail - if (argumentMap == null) { - return emptyConcreteType; - } - - argumentMap.forEach(augmentParameterType); - ConcreteTypeCartesianProduct product = - new ConcreteTypeCartesianProduct(this, receiverType, argumentMap); - for (ConcreteTypesEnvironment environment in product) { - result = union(result, - getMonomorphicSendReturnType(function, environment)); - } - return result; - } - - /** - * Given a method signature and a list of concrete types, builds a map from - * formals to their corresponding concrete types. Returns null if the - * association is impossible (for instance: too many arguments). - */ - Map<Element, ConcreteType> associateArguments(FunctionElement function, - ArgumentsTypes argumentsTypes) { - final Map<Element, ConcreteType> result = new Map<Element, ConcreteType>(); - final FunctionSignature signature = function.computeSignature(compiler); - - // guard 1: too many arguments - if (argumentsTypes.length > signature.parameterCount) { - return null; - } - // guard 2: not enough arguments - if (argumentsTypes.positional.length < signature.requiredParameterCount) { - return null; - } - // guard 3: too many positional arguments - if (signature.optionalParametersAreNamed && - argumentsTypes.positional.length > signature.requiredParameterCount) { - return null; - } - - handleLeftoverOptionalParameter(Element parameter) { - // TODO(polux): use default value whenever available - // TODO(polux): add a marker to indicate whether an argument was provided - // in order to handle "?parameter" tests - result[parameter] = singletonConcreteType(const NullBaseType()); - } - - final Iterator<ConcreteType> remainingPositionalArguments = - argumentsTypes.positional.iterator; - // we attach each positional parameter to its corresponding positional - // argument - for (Link<Element> requiredParameters = signature.requiredParameters; - !requiredParameters.isEmpty; - requiredParameters = requiredParameters.tail) { - final Element requiredParameter = requiredParameters.head; - // we know moveNext() succeeds because of guard 2 - remainingPositionalArguments.moveNext(); - result[requiredParameter] = remainingPositionalArguments.current; - } - if (signature.optionalParametersAreNamed) { - // we build a map out of the remaining named parameters - Link<Element> remainingOptionalParameters = signature.optionalParameters; - final Map<SourceString, Element> leftOverNamedParameters = - new Map<SourceString, Element>(); - for (; - !remainingOptionalParameters.isEmpty; - remainingOptionalParameters = remainingOptionalParameters.tail) { - final Element namedParameter = remainingOptionalParameters.head; - leftOverNamedParameters[namedParameter.name] = namedParameter; - } - // we attach the named arguments to their corresponding optional - // parameters - for (Identifier identifier in argumentsTypes.named.keys) { - final ConcreteType concreteType = argumentsTypes.named[identifier]; - SourceString source = identifier.source; - final Element namedParameter = leftOverNamedParameters[source]; - // unexisting or already used named parameter - if (namedParameter == null) return null; - result[namedParameter] = concreteType; - leftOverNamedParameters.remove(source); - } - leftOverNamedParameters.forEach((_, Element parameter) { - handleLeftoverOptionalParameter(parameter); - }); - } else { // optional parameters are positional - // we attach the remaining positional arguments to their corresponding - // optional parameters - Link<Element> remainingOptionalParameters = signature.optionalParameters; - while (remainingPositionalArguments.moveNext()) { - final Element optionalParameter = remainingOptionalParameters.head; - result[optionalParameter] = remainingPositionalArguments.current; - // we know tail is defined because of guard 1 - remainingOptionalParameters = remainingOptionalParameters.tail; - } - for (; - !remainingOptionalParameters.isEmpty; - remainingOptionalParameters = remainingOptionalParameters.tail) { - handleLeftoverOptionalParameter(remainingOptionalParameters.head); - } - } - return result; - } - - ConcreteType getMonomorphicSendReturnType( - FunctionElement function, - ConcreteTypesEnvironment environment) { - ConcreteType specialType = getSpecialCaseReturnType(function, environment); - if (specialType != null) return specialType; - - Map<ConcreteTypesEnvironment, ConcreteType> template = cache[function]; - if (template == null) { - template = new Map<ConcreteTypesEnvironment, ConcreteType>(); - cache[function] = template; - } - ConcreteType type = template[environment]; - if (type != null) { - return type; - } else { - workQueue.addLast( - new InferenceWorkItem(function, environment)); - // in case of a constructor, optimize by returning the class - return emptyConcreteType; - } - } - - /** - * Handles external methods that cannot be cached because they depend on some - * other state of [ConcreteTypesInferrer] like [:List#[]:] and - * [:List#[]=:]. Returns null if [function] and [environment] don't form a - * special case - */ - ConcreteType getSpecialCaseReturnType(FunctionElement function, - ConcreteTypesEnvironment environment) { - if (function == listIndex) { - ConcreteType indexType = environment.lookupType( - listIndex.functionSignature.requiredParameters.head); - if (!indexType.baseTypes.contains(baseTypes.intBaseType)) { - return new ConcreteType.empty(); - } - return listElementType; - } else if (function == listIndexSet) { - Link<Element> parameters = - listIndexSet.functionSignature.requiredParameters; - ConcreteType indexType = environment.lookupType(parameters.head); - if (!indexType.baseTypes.contains(baseTypes.intBaseType)) { - return new ConcreteType.empty(); - } - ConcreteType elementType = environment.lookupType(parameters.tail.head); - augmentListElementType(elementType); - return new ConcreteType.empty(); - } - return null; - } - - ConcreteType analyze(FunctionElement element, - ConcreteTypesEnvironment environment) { - return element.isGenerativeConstructor() - ? analyzeConstructor(element, environment) - : analyzeMethod(element, environment); - } - - ConcreteType analyzeMethod(FunctionElement element, - ConcreteTypesEnvironment environment) { - TreeElements elements = - compiler.enqueuer.resolution.resolvedElements[element]; - ConcreteType specialResult = handleSpecialMethod(element, environment); - if (specialResult != null) return specialResult; - FunctionExpression tree = element.parseNode(compiler); - if (tree.hasBody()) { - Visitor visitor = - new TypeInferrerVisitor(elements, element, this, environment); - return tree.accept(visitor); - } else { - // TODO(polux): implement visitForeingCall and always use the - // implementation element instead of this hack - return new ConcreteType.unknown(); - } - } - - ConcreteType analyzeConstructor(FunctionElement element, - ConcreteTypesEnvironment environment) { - ClassElement enclosingClass = element.enclosingElement; - FunctionExpression tree = compiler.parser.parse(element); - TreeElements elements = - compiler.enqueuer.resolution.resolvedElements[element]; - Visitor visitor = - new TypeInferrerVisitor(elements, element, this, environment); - - // handle initializing formals - element.functionSignature.forEachParameter((param) { - if (param.kind == ElementKind.FIELD_PARAMETER) { - FieldParameterElement fieldParam = param; - augmentFieldType(fieldParam.fieldElement, - environment.lookupType(param)); - } - }); - - // analyze initializers, including a possible call to super or a redirect - bool foundSuperOrRedirect = false; - if (tree.initializers != null) { - // we look for a possible call to super in the initializer list - for (final init in tree.initializers) { - init.accept(visitor); - if (init.asSendSet() == null) { - foundSuperOrRedirect = true; - } - } - } - - // if no call to super or redirect has been found, call the default - // constructor (if the current class is not Object). - if (!foundSuperOrRedirect) { - ClassElement superClass = enclosingClass.superclass; - if (enclosingClass != compiler.objectClass) { - FunctionElement target = superClass.lookupConstructor( - new Selector.callDefaultConstructor(enclosingClass.getLibrary())); - final superClassConcreteType = singletonConcreteType( - new ClassBaseType(enclosingClass)); - getSendReturnType(target, enclosingClass, - new ArgumentsTypes(new List(), new Map())); - } - } - - tree.accept(visitor); - return singletonConcreteType(new ClassBaseType(enclosingClass)); - } - - /** - * Hook that performs side effects on some special method calls (like - * [:List(length):]) and possibly returns a concrete type - * (like [:{JsArray}:]). - */ - ConcreteType handleSpecialMethod(FunctionElement element, - ConcreteTypesEnvironment environment) { - // When List([length]) is called with some length, we must augment - // listElementType with {null}. - if (element == listConstructor) { - Link<Element> parameters = - listConstructor.functionSignature.optionalParameters; - ConcreteType lengthType = environment.lookupType(parameters.head); - if (lengthType.baseTypes.contains(baseTypes.intBaseType)) { - augmentListElementType(singletonConcreteType(new NullBaseType())); - } - return singletonConcreteType(baseTypes.listBaseType); - } - } - - /* Initialization code that cannot be run in the constructor because it - * requires the compiler's elements to be populated. - */ - void initialize() { - baseTypes = new BaseTypes(compiler); - ClassElement jsArrayClass = baseTypes.listBaseType.element; - listIndex = jsArrayClass.lookupMember(const SourceString('[]')); - listIndexSet = - jsArrayClass.lookupMember(const SourceString('[]=')); - listConstructor = - compiler.listClass.lookupConstructor( - new Selector.callConstructor(const SourceString(''), - compiler.listClass.getLibrary())); - } - - /** - * Performs concrete type inference of the code reachable from [element]. - * Returns [:true:] if and only if analysis succeeded. - */ - bool analyzeMain(Element element) { - initialize(); - cache[element] = new Map<ConcreteTypesEnvironment, ConcreteType>(); - populateCacheWithBuiltinRules(); - try { - workQueue.addLast( - new InferenceWorkItem(element, new ConcreteTypesEnvironment(this))); - while (!workQueue.isEmpty) { - InferenceWorkItem item = workQueue.removeFirst(); - ConcreteType concreteType = analyze(item.method, item.environment); - var template = cache[item.method]; - if (template[item.environment] == concreteType) continue; - template[item.environment] = concreteType; - invalidateCallers(item.method); - } - return true; - } on CancelTypeInferenceException catch(e) { - if (LOG_FAILURES) { - compiler.log(e.reason); - } - return false; - } - } - - /** - * Dumps debugging information on the standard output. - */ - void debug() { - print("callers :"); - callers.forEach((k,v) { - print(" $k: $v"); - }); - print("readers :"); - readers.forEach((k,v) { - print(" $k: $v"); - }); - print("inferredFieldTypes:"); - inferredFieldTypes.forEach((k,v) { - print(" $k: $v"); - }); - print("inferredParameterTypes:"); - inferredParameterTypes.forEach((k,v) { - print(" $k: $v"); - }); - print("cache:"); - cache.forEach((k,v) { - print(" $k: $v"); - }); - print("inferred expression types: "); - inferredTypes.forEach((k,v) { - print(" $k: $v"); - }); - } - - /** - * Fail with a message and abort. - */ - void fail(node, [reason]) { - String message = 'cannot infer types'; - if (reason != null) { - message = '$message: $reason'; - } - throw new CancelTypeInferenceException(node, message); - } -} - -/** - * Represents the concrete types of the arguments of a send, indexed by - * position or name. - */ -class ArgumentsTypes { - final List<ConcreteType> positional; - final Map<Identifier, ConcreteType> named; - ArgumentsTypes(this.positional, this.named); - int get length => positional.length + named.length; - toString() => "{ positional = $positional, named = $named }"; -} - -/** - * The core logic of the type inference algorithm. - */ -class TypeInferrerVisitor extends ResolvedVisitor<ConcreteType> { - final ConcreteTypesInferrer inferrer; - - final FunctionElement currentMethod; - ConcreteTypesEnvironment environment; - Node lastSeenNode; - - TypeInferrerVisitor(TreeElements elements, this.currentMethod, this.inferrer, - this.environment) - : super(elements); - - ArgumentsTypes analyzeArguments(Link<Node> arguments) { - final positional = new List<ConcreteType>(); - final named = new Map<Identifier, ConcreteType>(); - for(Link<Node> iterator = arguments; - !iterator.isEmpty; - iterator = iterator.tail) { - Node node = iterator.head; - NamedArgument namedArgument = node.asNamedArgument(); - if (namedArgument != null) { - named[namedArgument.name] = analyze(namedArgument.expression); - } else { - positional.add(analyze(node)); - } - } - return new ArgumentsTypes(positional, named); - } - - /** - * A proxy to accept which does book keeping and error reporting. Returns null - * if [node] is a non-returning statement, its inferred concrete type - * otherwise. - */ - ConcreteType analyze(Node node) { - if (node == null) { - final String error = 'internal error: unexpected node: null'; - inferrer.fail(lastSeenNode, error); - } else { - lastSeenNode = node; - } - ConcreteType result = node.accept(this); - if (result == null) { - inferrer.fail(node, 'internal error: inferred type is null'); - } - inferrer.augmentInferredType(node, result); - return result; - } - - ConcreteType visitBlock(Block node) { - return analyze(node.statements); - } - - ConcreteType visitCascade(Cascade node) { - inferrer.fail(node, 'not yet implemented'); - } - - ConcreteType visitCascadeReceiver(CascadeReceiver node) { - inferrer.fail(node, 'not yet implemented'); - } - - ConcreteType visitClassNode(ClassNode node) { - inferrer.fail(node, 'not implemented'); - } - - ConcreteType visitDoWhile(DoWhile node) { - inferrer.fail(node, 'not yet implemented'); - } - - ConcreteType visitExpressionStatement(ExpressionStatement node) { - analyze(node.expression); - return inferrer.emptyConcreteType; - } - - ConcreteType visitFor(For node) { - if (node.initializer != null) { - analyze(node.initializer); - } - analyze(node.conditionStatement); - ConcreteType result = inferrer.emptyConcreteType; - ConcreteTypesEnvironment oldEnvironment; - do { - oldEnvironment = environment; - analyze(node.conditionStatement); - analyze(node.body); - analyze(node.update); - environment = oldEnvironment.join(environment); - // TODO(polux): Maybe have a destructive join-method that returns a boolean - // value indicating whether something changed to avoid performing this - // comparison twice. - } while (oldEnvironment != environment); - return result; - } - - ConcreteType visitFunctionDeclaration(FunctionDeclaration node) { - inferrer.fail(node, 'not yet implemented'); - } - - ConcreteType visitFunctionExpression(FunctionExpression node) { - return analyze(node.body); - } - - ConcreteType visitIdentifier(Identifier node) { - if (node.isThis()) { - ConcreteType result = environment.lookupTypeOfThis(); - if (result == null) { - inferrer.fail(node, '"this" has no type'); - } - return result; - } - inferrer.fail(node, 'not yet implemented'); - } - - ConcreteType visitIf(If node) { - analyze(node.condition); - ConcreteType thenType = analyze(node.thenPart); - ConcreteTypesEnvironment snapshot = environment; - ConcreteType elseType = node.hasElsePart ? analyze(node.elsePart) - : inferrer.emptyConcreteType; - environment = environment.join(snapshot); - return inferrer.union(thenType, elseType); - } - - ConcreteType visitLoop(Loop node) { - inferrer.fail(node, 'not yet implemented'); - } - - ConcreteType analyzeSetElement(Element receiver, ConcreteType argumentType) { - environment = environment.put(receiver, argumentType); - if (receiver.isField()) { - inferrer.augmentFieldType(receiver, argumentType); - } else if (receiver.isSetter()){ - FunctionElement setter = receiver; - // TODO(polux): A setter always returns void so there's no need to - // invalidate its callers even if it is called with new arguments. - // However, if we start to record more than returned types, like - // exceptions for instance, we need to do it by uncommenting the following - // line. - // inferrer.addCaller(setter, currentMethod); - inferrer.getSendReturnType(setter, receiver.enclosingElement, - new ArgumentsTypes([argumentType], new Map())); - } - return argumentType; - } - - ConcreteType analyzeSetNode(Node receiver, ConcreteType argumentType, - SourceString name) { - ConcreteType receiverType = analyze(receiver); - - void augmentField(ClassElement receiverType, Element member) { - if (member.isField()) { - inferrer.augmentFieldType(member, argumentType); - } else if (member.isAbstractField()){ - AbstractFieldElement abstractField = member; - FunctionElement setter = abstractField.setter; - // TODO(polux): A setter always returns void so there's no need to - // invalidate its callers even if it is called with new arguments. - // However, if we start to record more than returned types, like - // exceptions for instance, we need to do it by uncommenting the - // following line. - // inferrer.addCaller(setter, currentMethod); - inferrer.getSendReturnType(setter, receiverType, - new ArgumentsTypes([argumentType], new Map())); - } - // since this is a sendSet we ignore non-fields - } - - if (receiverType.isUnkown()) { - for (Element member in inferrer.getMembersByName(name)) { - if (!(member.isField() || member.isAbstractField())) continue; - Element cls = member.getEnclosingClass(); - augmentField(cls, member); - } - } else { - for (BaseType baseReceiverType in receiverType.baseTypes) { - if (!baseReceiverType.isClass()) continue; - ClassBaseType baseReceiverClassType = baseReceiverType; - Element member = baseReceiverClassType.element.lookupMember(name); - if (member != null) { - augmentField(baseReceiverClassType.element, member); - } - } - } - return argumentType; - } - - SourceString canonicalizeCompoundOperator(SourceString op) { - // TODO(ahe): This class should work on elements or selectors, not - // names. Otherwise, it is repeating work the resolver has - // already done (or should have done). In this case, the problem - // is that the resolver is not recording the selectors it is - // registering in registerBinaryOperator in - // ResolverVisitor.visitSendSet. - String stringValue = op.stringValue; - if (stringValue == '++') return const SourceString(r'+'); - else if (stringValue == '--') return const SourceString(r'-'); - else return Elements.mapToUserOperatorOrNull(op); - } - - ConcreteType visitSendSet(SendSet node) { - // Operator []= has a different behaviour than other send sets: it is - // actually a send whose return type is that of its second argument. - if (node.selector.asIdentifier().source.stringValue == '[]') { - ConcreteType receiverType = analyze(node.receiver); - ArgumentsTypes argumentsTypes = analyzeArguments(node.arguments); - analyzeDynamicSend(receiverType, const SourceString('[]='), - argumentsTypes); - return argumentsTypes.positional[1]; - } - - // All other operators have a single argument (++ and -- have an implicit - // argument: 1). We will store its type in argumentType. - ConcreteType argumentType; - SourceString operatorName = node.assignmentOperator.source; - SourceString compoundOperatorName = - canonicalizeCompoundOperator(node.assignmentOperator.source); - // ++, --, +=, -=, ... - if (compoundOperatorName != null) { - ConcreteType receiverType = visitGetterSend(node); - // argumentsTypes is either computed from the actual arguments or [{int}] - // in case of ++ or --. - ArgumentsTypes argumentsTypes; - if (operatorName.stringValue == '++' - || operatorName.stringValue == '--') { - List<ConcreteType> positionalArguments = <ConcreteType>[ - inferrer.singletonConcreteType(inferrer.baseTypes.intBaseType)]; - argumentsTypes = new ArgumentsTypes(positionalArguments, new Map()); - } else { - argumentsTypes = analyzeArguments(node.arguments); - } - argumentType = analyzeDynamicSend(receiverType, compoundOperatorName, - argumentsTypes); - // The simple assignment case: receiver = argument. - } else { - argumentType = analyze(node.argumentsNode); - } - - Element element = elements[node]; - if (element != null) { - return analyzeSetElement(element, argumentType); - } else { - return analyzeSetNode(node.receiver, argumentType, - node.selector.asIdentifier().source); - } - } - - ConcreteType visitLiteralInt(LiteralInt node) { - return inferrer.singletonConcreteType(inferrer.baseTypes.intBaseType); - } - - ConcreteType visitLiteralDouble(LiteralDouble node) { - return inferrer.singletonConcreteType(inferrer.baseTypes.doubleBaseType); - } - - ConcreteType visitLiteralBool(LiteralBool node) { - return inferrer.singletonConcreteType(inferrer.baseTypes.boolBaseType); - } - - ConcreteType visitLiteralString(LiteralString node) { - // TODO(polux): get rid of this hack once we have a natural way of inferring - // the unknown type. - if (inferrer.testMode - && node.dartString.slowToString() == "__dynamic_for_test") { - return inferrer.unknownConcreteType; - } - return inferrer.singletonConcreteType(inferrer.baseTypes.stringBaseType); - } - - ConcreteType visitStringJuxtaposition(StringJuxtaposition node) { - analyze(node.first); - analyze(node.second); - return inferrer.singletonConcreteType(inferrer.baseTypes.stringBaseType); - } - - ConcreteType visitLiteralNull(LiteralNull node) { - return inferrer.singletonConcreteType(const NullBaseType()); - } - - ConcreteType visitNewExpression(NewExpression node) { - Element constructor = elements[node.send]; - inferrer.addCaller(constructor, currentMethod); - ClassElement cls = constructor.enclosingElement; - return inferrer.getSendReturnType(constructor, cls, - analyzeArguments(node.send.arguments)); - } - - ConcreteType visitLiteralList(LiteralList node) { - ConcreteType elementsType = new ConcreteType.empty(); - // We compute the union of the types of the list literal's elements. - for (Link<Node> link = node.elements.nodes; - !link.isEmpty; - link = link.tail) { - elementsType = inferrer.union(elementsType, analyze(link.head)); - } - inferrer.augmentListElementType(elementsType); - return inferrer.singletonConcreteType(inferrer.baseTypes.listBaseType); - } - - ConcreteType visitNodeList(NodeList node) { - ConcreteType type = inferrer.emptyConcreteType; - // The concrete type of a sequence of statements is the union of the - // statement's types. - for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) { - type = inferrer.union(type, analyze(link.head)); - } - return type; - } - - ConcreteType visitOperator(Operator node) { - inferrer.fail(node, 'not yet implemented'); - } - - ConcreteType visitReturn(Return node) { - final expression = node.expression; - return (expression == null) - ? inferrer.singletonConcreteType(const NullBaseType()) - : analyze(expression); - } - - ConcreteType visitThrow(Throw node) { - if (node.expression != null) analyze(node.expression); - return inferrer.emptyConcreteType; - } - - ConcreteType visitTypeAnnotation(TypeAnnotation node) { - inferrer.fail(node, 'not yet implemented'); - } - - ConcreteType visitTypeVariable(TypeVariable node) { - inferrer.fail(node, 'not yet implemented'); - } - - ConcreteType visitVariableDefinitions(VariableDefinitions node) { - for (Link<Node> link = node.definitions.nodes; !link.isEmpty; - link = link.tail) { - analyze(link.head); - } - return inferrer.emptyConcreteType; - } - - ConcreteType visitWhile(While node) { - analyze(node.condition); - ConcreteType result = inferrer.emptyConcreteType; - ConcreteTypesEnvironment oldEnvironment; - do { - oldEnvironment = environment; - analyze(node.condition); - analyze(node.body); - environment = oldEnvironment.join(environment); - } while (oldEnvironment != environment); - return result; - } - - ConcreteType visitParenthesizedExpression(ParenthesizedExpression node) { - return analyze(node.expression); - } - - ConcreteType visitConditional(Conditional node) { - analyze(node.condition); - ConcreteType thenType = analyze(node.thenExpression); - ConcreteType elseType = analyze(node.elseExpression); - return inferrer.union(thenType, elseType); - } - - ConcreteType visitModifiers(Modifiers node) { - inferrer.fail(node, 'not yet implemented'); - } - - ConcreteType visitStringInterpolation(StringInterpolation node) { - node.visitChildren(this); - return inferrer.singletonConcreteType(inferrer.baseTypes.stringBaseType); - } - - ConcreteType visitStringInterpolationPart(StringInterpolationPart node) { - node.visitChildren(this); - return inferrer.singletonConcreteType(inferrer.baseTypes.stringBaseType); - } - - ConcreteType visitEmptyStatement(EmptyStatement node) { - return inferrer.emptyConcreteType; - } - - ConcreteType visitBreakStatement(BreakStatement node) { - return inferrer.emptyConcreteType; - } - - ConcreteType visitContinueStatement(ContinueStatement node) { - // TODO(polux): we can be more precise - return inferrer.emptyConcreteType; - } - - ConcreteType visitForIn(ForIn node) { - inferrer.fail(node, 'not yet implemented'); - } - - ConcreteType visitLabel(Label node) { - inferrer.fail(node, 'not yet implemented'); - } - - ConcreteType visitLabeledStatement(LabeledStatement node) { - return analyze(node.statement); - } - - ConcreteType visitLiteralMap(LiteralMap node) { - visitNodeList(node.entries); - return inferrer.singletonConcreteType(inferrer.baseTypes.mapBaseType); - } - - ConcreteType visitLiteralMapEntry(LiteralMapEntry node) { - // We don't need to visit the key, it's always a string. - return analyze(node.value); - } - - ConcreteType visitNamedArgument(NamedArgument node) { - inferrer.fail(node, 'not yet implemented'); - } - - ConcreteType visitSwitchStatement(SwitchStatement node) { - inferrer.fail(node, 'not yet implemented'); - } - - ConcreteType visitSwitchCase(SwitchCase node) { - inferrer.fail(node, 'not yet implemented'); - } - - ConcreteType visitCaseMatch(CaseMatch node) { - inferrer.fail(node, 'not yet implemented'); - } - - ConcreteType visitTryStatement(TryStatement node) { - inferrer.fail(node, 'not yet implemented'); - } - - ConcreteType visitScriptTag(ScriptTag node) { - inferrer.fail(node, 'not yet implemented'); - } - - ConcreteType visitCatchBlock(CatchBlock node) { - inferrer.fail(node, 'not yet implemented'); - } - - ConcreteType visitTypedef(Typedef node) { - inferrer.fail(node, 'not implemented'); - } - - ConcreteType visitSuperSend(Send node) { - inferrer.fail(node, 'not implemented'); - } - - ConcreteType visitOperatorSend(Send node) { - SourceString name = - canonicalizeMethodName(node.selector.asIdentifier().source); - if (name == const SourceString('is')) { - return inferrer.singletonConcreteType(inferrer.baseTypes.boolBaseType); - } - return visitDynamicSend(node); - } - - ConcreteType analyzeFieldRead(Element field) { - inferrer.addReader(field, currentMethod); - return inferrer.getFieldType(field); - } - - ConcreteType analyzeGetterSend(ClassElement receiverType, - FunctionElement getter) { - inferrer.addCaller(getter, currentMethod); - return inferrer.getSendReturnType(getter, - receiverType, - new ArgumentsTypes([], new Map())); - } - - ConcreteType visitGetterSend(Send node) { - Element element = elements[node]; - if (element != null) { - // node is a local variable or a field of this - ConcreteType result = environment.lookupType(element); - if (result != null) { - // node is a local variable - return result; - } else { - // node is a field or a getter of this - if (element.isField()) { - return analyzeFieldRead(element); - } else { - assert(element.isGetter()); - ClassElement receiverType = element.enclosingElement; - return analyzeGetterSend(receiverType, element); - } - } - } else { - // node is a field of not(this) - assert(node.receiver != null); - - ConcreteType result = inferrer.emptyConcreteType; - void augmentResult(ClassElement baseReceiverType, Element member) { - if (member.isField()) { - result = inferrer.union(result, analyzeFieldRead(member)); - } else if (member.isAbstractField()){ - // call to a getter - AbstractFieldElement abstractField = member; - result = inferrer.union( - result, - analyzeGetterSend(baseReceiverType, abstractField.getter)); - } - // since this is a get we ignore non-fields - } - - ConcreteType receiverType = analyze(node.receiver); - if (receiverType.isUnkown()) { - List<Element> members = - inferrer.getMembersByName(node.selector.asIdentifier().source); - for (Element member in members) { - if (!(member.isField() || member.isAbstractField())) continue; - Element cls = member.getEnclosingClass(); - augmentResult(cls, member); - } - } else { - for (BaseType baseReceiverType in receiverType.baseTypes) { - if (!baseReceiverType.isNull()) { - ClassBaseType classBaseType = baseReceiverType; - ClassElement cls = classBaseType.element; - Element getterOrField = - cls.lookupMember(node.selector.asIdentifier().source); - if (getterOrField != null) { - augmentResult(cls, getterOrField); - } - } - } - } - return result; - } - } - - ConcreteType visitClosureSend(Send node) { - inferrer.fail(node, 'not implemented'); - } - - ConcreteType analyzeDynamicSend(ConcreteType receiverType, - SourceString canonicalizedMethodName, - ArgumentsTypes argumentsTypes) { - ConcreteType result = inferrer.emptyConcreteType; - - if (receiverType.isUnkown()) { - List<Element> methods = - inferrer.getMembersByName(canonicalizedMethodName); - for (Element element in methods) { - // TODO(polux): when we handle closures, we must handle sends to fields - // that are closures. - if (!element.isFunction()) continue; - FunctionElement method = element; - inferrer.addCaller(method, currentMethod); - Element cls = method.enclosingElement; - result = inferrer.union( - result, - inferrer.getSendReturnType(method, cls, argumentsTypes)); - } - - } else { - for (BaseType baseReceiverType in receiverType.baseTypes) { - if (!baseReceiverType.isNull()) { - ClassBaseType classBaseReceiverType = baseReceiverType; - ClassElement cls = classBaseReceiverType.element; - FunctionElement method = cls.lookupMember(canonicalizedMethodName); - if (method != null) { - inferrer.addCaller(method, currentMethod); - result = inferrer.union( - result, - inferrer.getSendReturnType(method, cls, argumentsTypes)); - } - } - } - } - return result; - } - - SourceString canonicalizeMethodName(SourceString name) { - // TODO(polux): handle unary- - SourceString operatorName = - Elements.constructOperatorNameOrNull(name, false); - if (operatorName != null) return operatorName; - return name; - } - - ConcreteType visitDynamicSend(Send node) { - ConcreteType receiverType = (node.receiver != null) - ? analyze(node.receiver) - : inferrer.singletonConcreteType( - new ClassBaseType(currentMethod.getEnclosingClass())); - SourceString name = - canonicalizeMethodName(node.selector.asIdentifier().source); - ArgumentsTypes argumentsTypes = analyzeArguments(node.arguments); - if (name.stringValue == '!=') { - ConcreteType returnType = analyzeDynamicSend(receiverType, - const SourceString('=='), - argumentsTypes); - return returnType.isEmpty() - ? returnType - : inferrer.singletonConcreteType(inferrer.baseTypes.boolBaseType); - } else { - return analyzeDynamicSend(receiverType, name, argumentsTypes); - } - } - - ConcreteType visitForeignSend(Send node) { - inferrer.fail(node, 'not implemented'); - } - - ConcreteType visitStaticSend(Send node) { - Element element = elements[node]; - inferrer.addCaller(element, currentMethod); - return inferrer.getSendReturnType(element, null, - analyzeArguments(node.arguments)); - } - - void internalError(String reason, {Node node}) { - inferrer.fail(node, reason); - } - - ConcreteType visitTypeReferenceSend(Send) { - return inferrer.singletonConcreteType(inferrer.baseTypes.typeBaseType); - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/types/types.dart b/pkgs/markdown/test/lib/src/compiler/implementation/types/types.dart deleted file mode 100644 index fdce427..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/types/types.dart +++ /dev/null
@@ -1,260 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library types; - -import 'dart:collection' show Queue; - -import '../dart2jslib.dart' hide Selector; -import '../js_backend/js_backend.dart' show JavaScriptBackend; -import '../tree/tree.dart'; -import '../elements/elements.dart'; -import '../util/util.dart'; -import '../universe/universe.dart'; - -part 'concrete_types_inferrer.dart'; - -/** - * The types task infers guaranteed types globally. - */ -class TypesTask extends CompilerTask { - final String name = 'Type inference'; - final Set<Element> untypedElements; - final Map<Element, Link<Element>> typedSends; - ConcreteTypesInferrer concreteTypesInferrer; - - TypesTask(Compiler compiler) - : untypedElements = new Set<Element>(), - typedSends = new Map<Element, Link<Element>>(), - concreteTypesInferrer = compiler.enableConcreteTypeInference - ? new ConcreteTypesInferrer(compiler) : null, - super(compiler); - - /** - * Called once for each method during the resolution phase of the - * compiler. - */ - void analyze(Node node, TreeElements elements) { - measure(() { - node.accept(new ConcreteTypeInferencer(this, elements)); - }); - } - - /** - * Called when resolution is complete. - */ - void onResolutionComplete(Element mainElement) { - measure(() { - if (concreteTypesInferrer != null) { - bool success = concreteTypesInferrer.analyzeMain(mainElement); - if (!success) { - // If the concrete type inference bailed out, we pretend it didn't - // happen. In the future we might want to record that it failed but - // use the partial results as hints. - concreteTypesInferrer = null; - } - } - }); - } - - /** - * Return the (inferred) guaranteed concrete type of [element] or null. - */ - ConcreteType getGuaranteedTypeOfElement(Element element) { - return measure(() { - if (!element.isParameter()) return null; - if (concreteTypesInferrer != null) { - ConcreteType guaranteedType = concreteTypesInferrer - .getConcreteTypeOfParameter(element); - if (guaranteedType != null) return guaranteedType; - } - Element holder = element.enclosingElement; - Link<Element> types = typedSends[holder]; - if (types == null) return null; - if (!holder.isFunction()) return null; - if (untypedElements.contains(holder)) return null; - FunctionElement function = holder; - FunctionSignature signature = function.computeSignature(compiler); - for (Element parameter in signature.requiredParameters) { - if (types.isEmpty) return null; - if (element == parameter) { - return new ConcreteType.singleton(compiler.maxConcreteTypeSize, - new ClassBaseType(types.head)); - } - types = types.tail; - } - return null; - }); - } - - /** - * Return the (inferred) guaranteed concrete type of [node] or null. - * [node] must be an AST node of [owner]. - */ - ConcreteType getGuaranteedTypeOfNode(Node node, Element owner) { - return measure(() { - if (concreteTypesInferrer != null) { - return concreteTypesInferrer.getConcreteTypeOfNode(node); - } - return null; - }); - } -} - -/** - * Infers concrete types for a single method or expression. - */ -class ConcreteTypeInferencer extends Visitor { - final TypesTask task; - final TreeElements elements; - final ClassElement boolClass; - final ClassElement doubleClass; - final ClassElement intClass; - final ClassElement listClass; - final ClassElement nullClass; - final ClassElement stringClass; - - final Map<Node, ClassElement> concreteTypes; - - ConcreteTypeInferencer(TypesTask task, this.elements) - : this.task = task, - this.boolClass = task.compiler.boolClass, - this.doubleClass = task.compiler.doubleClass, - this.intClass = task.compiler.intClass, - this.listClass = task.compiler.listClass, - this.nullClass = task.compiler.nullClass, - this.stringClass = task.compiler.stringClass, - this.concreteTypes = new Map<Node, ClassElement>(); - - visitNode(Node node) => node.visitChildren(this); - - visitLiteralString(LiteralString node) { - recordConcreteType(node, stringClass); - } - - visitStringInterpolation(StringInterpolation node) { - node.visitChildren(this); - recordConcreteType(node, stringClass); - } - - visitStringJuxtaposition(StringJuxtaposition node) { - node.visitChildren(this); - recordConcreteType(node, stringClass); - } - - recordConcreteType(Node node, ClassElement cls) { - concreteTypes[node] = cls; - } - - visitLiteralBool(LiteralBool node) { - recordConcreteType(node, boolClass); - } - - visitLiteralDouble(LiteralDouble node) { - recordConcreteType(node, doubleClass); - } - - visitLiteralInt(LiteralInt node) { - recordConcreteType(node, intClass); - } - - visitLiteralList(LiteralList node) { - node.visitChildren(this); - recordConcreteType(node, listClass); - } - - visitLiteralMap(LiteralMap node) { - node.visitChildren(this); - // TODO(ahe): map class? - } - - visitLiteralNull(LiteralNull node) { - recordConcreteType(node, nullClass); - } - - Link<Element> computeConcreteSendArguments(Send node) { - if (node.argumentsNode == null) return null; - if (node.arguments.isEmpty) return const Link<Element>(); - if (node.receiver != null && concreteTypes[node.receiver] == null) { - return null; - } - LinkBuilder<Element> types = new LinkBuilder<Element>(); - for (Node argument in node.arguments) { - Element type = concreteTypes[argument]; - if (type == null) return null; - types.addLast(type); - } - return types.toLink(); - } - - visitSend(Send node) { - node.visitChildren(this); - Element element = elements[node.selector]; - if (element == null) return; - if (!Elements.isStaticOrTopLevelFunction(element)) return; - if (node.argumentsNode == null) { - // interest(node, 'closurized method'); - task.untypedElements.add(element); - return; - } - Link<Element> types = computeConcreteSendArguments(node); - if (types != null) { - Link<Element> existing = task.typedSends[element]; - if (existing == null) { - task.typedSends[element] = types; - } else { - // interest(node, 'multiple invocations'); - Link<Element> lub = computeLubs(existing, types); - if (lub == null) { - task.untypedElements.add(element); - } else { - task.typedSends[element] = lub; - } - } - } else { - // interest(node, 'dynamically typed invocation'); - task.untypedElements.add(element); - } - } - - visitSendSet(SendSet node) { - // TODO(ahe): Implement this. For now, overridden to avoid calling - // visitSend through super. - node.visitChildren(this); - } - - void interest(Node node, String note) { - var message = MessageKind.GENERIC.message({'text': note}); - task.compiler.reportWarning(node, message); - } - - /** - * Computes the pairwise Least Upper Bound (LUB) of the elements of - * [a] and [b]. Returns [:null:] if it gives up, or if the lists - * aren't the same length. - */ - Link<Element> computeLubs(Link<Element> a, Link<Element> b) { - LinkBuilder<Element> lubs = new LinkBuilder<Element>(); - while (!a.isEmpty && !b.isEmpty) { - Element lub = computeLub(a.head, b.head); - if (lub == null) return null; - lubs.addLast(lub); - a = a.tail; - b = b.tail; - } - return (a.isEmpty && b.isEmpty) ? lubs.toLink() : null; - } - - /** - * Computes the Least Upper Bound (LUB) of [a] and [b]. Returns - * [:null:] if it gives up. - */ - Element computeLub(Element a, Element b) { - // Fast common case, but also simple initial implementation. - if (identical(a, b)) return a; - - // TODO(ahe): Improve the following "computation"... - return null; - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/universe/function_set.dart b/pkgs/markdown/test/lib/src/compiler/implementation/universe/function_set.dart deleted file mode 100644 index 23bc782..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/universe/function_set.dart +++ /dev/null
@@ -1,140 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of universe; - -// TODO(kasperl): This actually holds getters and setters just fine -// too and stricly they aren't functions. Maybe this needs a better -// name -- something like ElementSet seems a bit too generic. -class FunctionSet extends PartialTypeTree { - - FunctionSet(Compiler compiler) : super(compiler); - - FunctionSetNode newSpecializedNode(ClassElement type) - => new FunctionSetNode(type); - - // TODO(kasperl): Allow static members too? - void add(Element element) { - assert(element.isMember()); - FunctionSetNode node = findNode(element.getEnclosingClass(), true); - node.membersByName[element.name] = element; - } - - // TODO(kasperl): Allow static members too? - void remove(Element element) { - assert(element.isMember()); - FunctionSetNode node = findNode(element.getEnclosingClass(), false); - if (node != null) node.membersByName.remove(element.name); - } - - // TODO(kasperl): Allow static members too? - bool contains(Element element) { - assert(element.isMember()); - FunctionSetNode node = findNode(element.getEnclosingClass(), false); - return (node != null) - ? node.membersByName.containsKey(element.name) - : false; - } - - /** - * Returns all elements that may be invoked with the given [selector]. - */ - Set<Element> filterBySelector(Selector selector) { - // TODO(kasperl): For now, we use a different implementation for - // filtering if the tree contains interface subtypes. - return containsInterfaceSubtypes - ? filterAllBySelector(selector) - : filterHierarchyBySelector(selector); - } - - /** - * Returns whether the set has any element matching the given - * [selector]. - */ - bool hasAnyElementMatchingSelector(Selector selector) { - // TODO(kasperl): For now, we use a different implementation for - // filtering if the tree contains interface subtypes. - return containsInterfaceSubtypes - ? hasAnyInAll(selector) - : hasAnyInHierarchy(selector); - } - - Set<Element> filterAllBySelector(Selector selector) { - Set<Element> result = new Set<Element>(); - if (root == null) return result; - root.visitRecursively((FunctionSetNode node) { - Element member = node.membersByName[selector.name]; - // Since we're running through the entire tree we have to use - // the applies method that takes types into account. - if (member != null && selector.appliesUnnamed(member, compiler)) { - result.add(member); - } - return true; - }); - return result; - } - - Set<Element> filterHierarchyBySelector(Selector selector) { - Set<Element> result = new Set<Element>(); - if (root == null) return result; - visitHierarchy(selectorType(selector), (FunctionSetNode node) { - Element member = node.membersByName[selector.name]; - if (member != null && selector.appliesUntyped(member, compiler)) { - result.add(member); - } - return true; - }); - return result; - } - - bool hasAnyInAll(Selector selector) { - bool result = false; - if (root == null) return result; - root.visitRecursively((FunctionSetNode node) { - Element member = node.membersByName[selector.name]; - // Since we're running through the entire tree we have to use - // the applies method that takes types into account. - if (member != null && selector.appliesUnnamed(member, compiler)) { - result = true; - // End the traversal. - return false; - } - return true; - }); - return result; - } - - bool hasAnyInHierarchy(Selector selector) { - bool result = false; - if (root == null) return result; - visitHierarchy(selectorType(selector), (FunctionSetNode node) { - Element member = node.membersByName[selector.name]; - if (member != null && selector.appliesUntyped(member, compiler)) { - result = true; - // End the traversal. - return false; - } - return true; - }); - return result; - } - - void forEach(Function f) { - if (root == null) return; - root.visitRecursively((FunctionSetNode node) { - node.membersByName.forEach( - (SourceString _, Element element) => f(element)); - return true; - }); - } -} - -class FunctionSetNode extends PartialTypeTreeNode { - - final Map<SourceString, Element> membersByName; - - FunctionSetNode(ClassElement type) : super(type), - membersByName = new Map<SourceString, Element>(); - -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/universe/partial_type_tree.dart b/pkgs/markdown/test/lib/src/compiler/implementation/universe/partial_type_tree.dart deleted file mode 100644 index f310174..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/universe/partial_type_tree.dart +++ /dev/null
@@ -1,190 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of universe; - -abstract class PartialTypeTree { - - final Compiler compiler; - PartialTypeTreeNode root; - - // TODO(kasperl): This should be final but the VM will not allow - // that without making the map a compile-time constant. - Map<ClassElement, PartialTypeTreeNode> nodes = - new Map<ClassElement, PartialTypeTreeNode>(); - - // TODO(kasperl): For now, we keep track of whether or not the tree - // contains two classes with a subtype relationship that isn't a - // subclass relationship. - bool containsInterfaceSubtypes = false; - - // TODO(kasperl): This should be final but the VM will not allow - // that without making the set a compile-time constant. - Set<ClassElement> unseenInterfaceSubtypes = - new Set<ClassElement>(); - - PartialTypeTree(this.compiler); - - PartialTypeTreeNode newSpecializedNode(ClassElement type); - - PartialTypeTreeNode newNode(ClassElement type) { - PartialTypeTreeNode node = newSpecializedNode(type); - nodes[type] = node; - if (containsInterfaceSubtypes) return node; - - // Check if the implied interface of the new class is implemented - // by another class that is already in the tree. - if (unseenInterfaceSubtypes.contains(type)) { - containsInterfaceSubtypes = true; - unseenInterfaceSubtypes.clear(); - return node; - } - - // Run through all the implied interfaces the class that we're - // adding implements and see if any of them are already in the - // tree. If so, we have a tree with interface subtypes. If not, - // keep track of them so we can deal with it if the interface is - // added to the tree later. - for (Link link = type.interfaces; !link.isEmpty; link = link.tail) { - InterfaceType superType = link.head; - ClassElement superTypeElement = superType.element; - if (nodes.containsKey(superTypeElement)) { - containsInterfaceSubtypes = true; - unseenInterfaceSubtypes.clear(); - break; - } else { - unseenInterfaceSubtypes.add(superTypeElement); - } - } - return node; - } - - // TODO(kasperl): Move this to the Selector class? - /** - * Returns a [ClassElement] that is an upper bound of the receiver type on - * [selector]. - */ - ClassElement selectorType(Selector selector) { - // TODO(ngeoffray): Should the tree be specialized with DartType? - DartType type = selector.receiverType; - if (type == null) return compiler.objectClass; - // TODO(kasperl): Should [dynamic] return Object? - if (identical(type.kind, TypeKind.MALFORMED_TYPE)) - return compiler.objectClass; - // TODO(johnniwinther): Change to use [DartType.unalias]. - if (type.element.isTypedef()) return compiler.functionClass; - return type.element; - } - - /** - * Finds the tree node corresponding to the given [type]. If [insert] - * is true, we always return a node that matches the type by - * inserting a new node if necessary. If [insert] is false, we - * return null if we cannot find a node that matches the [type]. - */ - PartialTypeTreeNode findNode(ClassElement type, bool insert) { - if (root == null) { - if (!insert) return null; - root = newNode(compiler.objectClass); - } - - PartialTypeTreeNode current = root; - L: while (!identical(current.type, type)) { - assert(type.isSubclassOf(current.type)); - - // Run through the children. If we find a subtype of the type - // we are looking for we go that way. If not, we keep track of - // the subtypes so we can move them from being children of the - // current node to being children of a new node if we need - // to insert that. - Link<PartialTypeTreeNode> subtypes = const Link(); - for (Link link = current.children; !link.isEmpty; link = link.tail) { - PartialTypeTreeNode child = link.head; - ClassElement childType = child.type; - if (type.isSubclassOf(childType)) { - assert(subtypes.isEmpty); - current = child; - continue L; - } else if (childType.isSubclassOf(type)) { - if (insert) subtypes = subtypes.prepend(child); - } - } - - // If we are not inserting any nodes, we are done. - if (!insert) return null; - - // Create a new node and move the children of the current node - // that are subtypes of the type of the new node below the new - // node in the hierarchy. - PartialTypeTreeNode node = newNode(type); - if (!subtypes.isEmpty) { - node.children = subtypes; - Link<PartialTypeTreeNode> remaining = const Link(); - for (Link link = current.children; !link.isEmpty; link = link.tail) { - PartialTypeTreeNode child = link.head; - if (!child.type.isSubclassOf(type)) { - remaining = remaining.prepend(child); - } - } - current.children = remaining; - } - - // Add the new node as a child node of the current node and return it. - current.children = current.children.prepend(node); - return node; - } - - // We found an exact match. No need to insert new nodes. - assert(identical(current.type, type)); - return current; - } - - /** - * Visits all superclass and subclass nodes for the given [type]. If - * the [visit] function ever returns false, we abort the traversal. - */ - void visitHierarchy(ClassElement type, bool visit(PartialTypeTreeNode node)) { - assert(!containsInterfaceSubtypes); - PartialTypeTreeNode current = root; - L: while (!identical(current.type, type)) { - assert(type.isSubclassOf(current.type)); - if (!visit(current)) return; - for (Link link = current.children; !link.isEmpty; link = link.tail) { - PartialTypeTreeNode child = link.head; - ClassElement childType = child.type; - if (type.isSubclassOf(childType)) { - current = child; - continue L; - } else if (childType.isSubclassOf(type)) { - if (!child.visitRecursively(visit)) return; - } - } - return; - } - current.visitRecursively(visit); - } - -} - -class PartialTypeTreeNode { - - final ClassElement type; - Link<PartialTypeTreeNode> children; - - PartialTypeTreeNode(this.type) : children = const Link(); - - /** - * Visits this node and its children recursively. If the visit - * callback ever returns false, the visiting stops early. - */ - bool visitRecursively(bool visit(PartialTypeTreeNode node)) { - if (!visit(this)) return false; - for (Link link = children; !link.isEmpty; link = link.tail) { - PartialTypeTreeNode child = link.head; - if (!child.visitRecursively(visit)) return false; - } - return true; - } - -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/universe/selector_map.dart b/pkgs/markdown/test/lib/src/compiler/implementation/universe/selector_map.dart deleted file mode 100644 index cf98a10..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/universe/selector_map.dart +++ /dev/null
@@ -1,132 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of universe; - -class SelectorMap<T> extends PartialTypeTree { - - SelectorMap(Compiler compiler) : super(compiler); - - SelectorMapNode<T> newSpecializedNode(ClassElement type) - => new SelectorMapNode<T>(type); - - T operator [](Selector selector) { - SelectorMapNode<T> node = findNode(selectorType(selector), false); - if (node == null) return null; - Link<SelectorValue<T>> selectors = node.selectorsByName[selector.name]; - if (selectors == null) return null; - for (Link link = selectors; !link.isEmpty; link = link.tail) { - SelectorValue<T> existing = link.head; - if (existing.selector.equalsUntyped(selector)) return existing.value; - } - return null; - } - - void operator []=(Selector selector, T value) { - SelectorMapNode<T> node = findNode(selectorType(selector), true); - Link<SelectorValue<T>> selectors = node.selectorsByName[selector.name]; - if (selectors == null) { - // No existing selectors with the given name. Create a new - // linked list. - SelectorValue<T> head = new SelectorValue<T>(selector, value); - node.selectorsByName[selector.name] = - new Link<SelectorValue<T>>().prepend(head); - } else { - // Run through the linked list of selectors with the same name. If - // we find one that matches, we update the value in the mapping. - for (Link link = selectors; !link.isEmpty; link = link.tail) { - SelectorValue<T> existing = link.head; - // It is safe to ignore the type here, because all selector - // mappings that are stored in a single node have the same type. - if (existing.selector.equalsUntyped(selector)) { - existing.value = value; - return; - } - } - // We could not find an existing mapping for the selector, so - // we add a new one to the existing linked list. - SelectorValue<T> head = new SelectorValue<T>(selector, value); - node.selectorsByName[selector.name] = selectors.prepend(head); - } - } - - // TODO(kasperl): Share code with the [] operator? - bool containsKey(Selector selector) { - SelectorMapNode<T> node = findNode(selectorType(selector), false); - if (node == null) return false; - Link<SelectorValue<T>> selectors = node.selectorsByName[selector.name]; - if (selectors == null) return false; - for (Link link = selectors; !link.isEmpty; link = link.tail) { - SelectorValue<T> existing = link.head; - if (existing.selector.equalsUntyped(selector)) return true; - } - return false; - } - - /** - * Visits all mappings for selectors that may be used to invoke the - * given [member] element. If the [visit] function ever returns false, - * we abort the traversal early. - */ - void visitMatching(Element member, bool visit(Selector selector, T value)) { - assert(member.isMember()); - if (root == null) return; - // TODO(kasperl): For now, we use a different implementation for - // visiting if the tree contains interface subtypes. - if (containsInterfaceSubtypes) { - visitAllMatching(member, visit); - } else { - visitHierarchyMatching(member, visit); - } - } - - void visitAllMatching(Element member, bool visit(selector, value)) { - root.visitRecursively((SelectorMapNode<T> node) { - Link<SelectorValue<T>> selectors = node.selectorsByName[member.name]; - if (selectors == null) return true; - for (Link link = selectors; !link.isEmpty; link = link.tail) { - SelectorValue<T> existing = link.head; - Selector selector = existing.selector; - // Since we're running through the entire tree we have to use - // the applies method that takes types into account. - if (selector.appliesUnnamed(member, compiler)) { - if (!visit(selector, existing.value)) return false; - } - } - return true; - }); - } - - void visitHierarchyMatching(Element member, bool visit(selector, value)) { - visitHierarchy(member.getEnclosingClass(), (SelectorMapNode<T> node) { - Link<SelectorValue<T>> selectors = node.selectorsByName[member.name]; - if (selectors == null) return true; - for (Link link = selectors; !link.isEmpty; link = link.tail) { - SelectorValue<T> existing = link.head; - Selector selector = existing.selector; - if (selector.appliesUntyped(member, compiler)) { - if (!visit(selector, existing.value)) return false; - } - } - return true; - }); - } - -} - -class SelectorMapNode<T> extends PartialTypeTreeNode { - - final Map<SourceString, Link<SelectorValue<T>>> selectorsByName; - - SelectorMapNode(ClassElement type) : super(type), - selectorsByName = new Map<SourceString, Link<SelectorValue<T>>>(); - -} - -class SelectorValue<T> { - final Selector selector; - T value; - SelectorValue(this.selector, this.value); - toString() => "$selector -> $value"; -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/universe/universe.dart b/pkgs/markdown/test/lib/src/compiler/implementation/universe/universe.dart deleted file mode 100644 index 6b64382..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/universe/universe.dart +++ /dev/null
@@ -1,495 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library universe; - -import '../closure.dart'; -import '../elements/elements.dart'; -import '../dart2jslib.dart'; -import '../dart_types.dart'; -import '../tree/tree.dart'; -import '../util/util.dart'; -import '../js/js.dart' as js; - -part 'function_set.dart'; -part 'partial_type_tree.dart'; -part 'selector_map.dart'; - -class Universe { - /** - * Documentation wanted -- johnniwinther - * - * Invariant: Elements are declaration elements. - */ - // TODO(karlklose): these sets should be merged. - final Set<ClassElement> instantiatedClasses; - final Set<DartType> instantiatedTypes; - - /** - * Documentation wanted -- johnniwinther - * - * Invariant: Elements are declaration elements. - */ - final Set<FunctionElement> staticFunctionsNeedingGetter; - final Map<SourceString, Set<Selector>> invokedNames; - final Map<SourceString, Set<Selector>> invokedGetters; - final Map<SourceString, Set<Selector>> invokedSetters; - - /** - * Fields accessed. Currently only the codegen knows this - * information. The resolver is too conservative when seeing a - * getter and only registers an invoked getter. - */ - final Map<SourceString, Set<Selector>> fieldGetters; - - /** - * Fields set. See comment in [fieldGetters]. - */ - final Map<SourceString, Set<Selector>> fieldSetters; - final Set<DartType> isChecks; - - Universe() : instantiatedClasses = new Set<ClassElement>(), - instantiatedTypes = new Set<DartType>(), - staticFunctionsNeedingGetter = new Set<FunctionElement>(), - invokedNames = new Map<SourceString, Set<Selector>>(), - invokedGetters = new Map<SourceString, Set<Selector>>(), - fieldGetters = new Map<SourceString, Set<Selector>>(), - fieldSetters = new Map<SourceString, Set<Selector>>(), - invokedSetters = new Map<SourceString, Set<Selector>>(), - isChecks = new Set<DartType>(); - - bool hasMatchingSelector(Set<Selector> selectors, - Element member, - Compiler compiler) { - if (selectors == null) return false; - for (Selector selector in selectors) { - if (selector.appliesUnnamed(member, compiler)) return true; - } - return false; - } - - bool hasInvocation(Element member, Compiler compiler) { - return hasMatchingSelector(invokedNames[member.name], member, compiler); - } - - bool hasInvokedGetter(Element member, Compiler compiler) { - return hasMatchingSelector(invokedGetters[member.name], member, compiler); - } - - bool hasInvokedSetter(Element member, Compiler compiler) { - return hasMatchingSelector(invokedSetters[member.name], member, compiler); - } - - bool hasFieldGetter(Element member, Compiler compiler) { - return hasMatchingSelector(fieldGetters[member.name], member, compiler); - } - - bool hasFieldSetter(Element member, Compiler compiler) { - return hasMatchingSelector(fieldSetters[member.name], member, compiler); - } -} - -class SelectorKind { - final String name; - const SelectorKind(this.name); - - static const SelectorKind GETTER = const SelectorKind('getter'); - static const SelectorKind SETTER = const SelectorKind('setter'); - static const SelectorKind CALL = const SelectorKind('call'); - static const SelectorKind OPERATOR = const SelectorKind('operator'); - static const SelectorKind INDEX = const SelectorKind('index'); - - toString() => name; -} - -class Selector { - final SelectorKind kind; - final SourceString name; - final LibraryElement library; // Library is null for non-private selectors. - - // The numbers of arguments of the selector. Includes named arguments. - final int argumentCount; - final List<SourceString> namedArguments; - final List<SourceString> orderedNamedArguments; - - Selector( - this.kind, - SourceString name, - LibraryElement library, - this.argumentCount, - [List<SourceString> namedArguments = const <SourceString>[]]) - : this.name = name, - this.library = name.isPrivate() ? library : null, - this.namedArguments = namedArguments, - this.orderedNamedArguments = namedArguments.isEmpty - ? namedArguments - : <SourceString>[] { - assert(!name.isPrivate() || library != null); - } - - Selector.getter(SourceString name, LibraryElement library) - : this(SelectorKind.GETTER, name, library, 0); - - Selector.getterFrom(Selector selector) - : this(SelectorKind.GETTER, selector.name, selector.library, 0); - - Selector.setter(SourceString name, LibraryElement library) - : this(SelectorKind.SETTER, name, library, 1); - - Selector.unaryOperator(SourceString name) - : this(SelectorKind.OPERATOR, - Elements.constructOperatorName(name, true), - null, 0); - - Selector.binaryOperator(SourceString name) - : this(SelectorKind.OPERATOR, - Elements.constructOperatorName(name, false), - null, 1); - - Selector.index() - : this(SelectorKind.INDEX, - Elements.constructOperatorName(const SourceString("[]"), false), - null, 1); - - Selector.indexSet() - : this(SelectorKind.INDEX, - Elements.constructOperatorName(const SourceString("[]="), false), - null, 2); - - Selector.call(SourceString name, - LibraryElement library, - int arity, - [List<SourceString> named = const []]) - : this(SelectorKind.CALL, name, library, arity, named); - - Selector.callClosure(int arity, [List<SourceString> named = const []]) - : this(SelectorKind.CALL, Compiler.CALL_OPERATOR_NAME, null, - arity, named); - - Selector.callClosureFrom(Selector selector) - : this(SelectorKind.CALL, Compiler.CALL_OPERATOR_NAME, null, - selector.argumentCount, selector.namedArguments); - - Selector.callConstructor(SourceString constructorName, - LibraryElement library) - : this(SelectorKind.CALL, - constructorName, - library, - 0, - const []); - - Selector.callDefaultConstructor(LibraryElement library) - : this(SelectorKind.CALL, const SourceString(""), library, 0, const []); - - // TODO(kasperl): This belongs somewhere else. - Selector.noSuchMethod() - : this(SelectorKind.CALL, Compiler.NO_SUCH_METHOD, null, - Compiler.NO_SUCH_METHOD_ARG_COUNT); - - bool isGetter() => identical(kind, SelectorKind.GETTER); - bool isSetter() => identical(kind, SelectorKind.SETTER); - bool isCall() => identical(kind, SelectorKind.CALL); - bool isClosureCall() { - SourceString callName = Compiler.CALL_OPERATOR_NAME; - return isCall() && name == callName; - } - - bool isIndex() => identical(kind, SelectorKind.INDEX) && argumentCount == 1; - bool isIndexSet() => identical(kind, SelectorKind.INDEX) && argumentCount == 2; - - bool isOperator() => identical(kind, SelectorKind.OPERATOR); - bool isUnaryOperator() => isOperator() && argumentCount == 0; - bool isBinaryOperator() => isOperator() && argumentCount == 1; - - /** Check whether this is a call to 'assert'. */ - bool isAssert() => isCall() && identical(name.stringValue, "assert"); - - int get hashCode => argumentCount + 1000 * namedArguments.length; - int get namedArgumentCount => namedArguments.length; - int get positionalArgumentCount => argumentCount - namedArgumentCount; - DartType get receiverType => null; - - Selector get asUntyped => this; - - /** - * The member name for invocation mirrors created from this selector. - */ - String get invocationMirrorMemberName => - isSetter() ? '${name.slowToString()}=' : name.slowToString(); - - int get invocationMirrorKind { - const int METHOD = 0; - const int GETTER = 1; - const int SETTER = 2; - int kind = METHOD; - if (isGetter()) { - kind = GETTER; - } else if (isSetter()) { - kind = SETTER; - } - return kind; - } - - bool appliesUnnamed(Element element, Compiler compiler) { - assert(sameNameHack(element, compiler)); - return appliesUntyped(element, compiler); - } - - bool appliesUntyped(Element element, Compiler compiler) { - assert(sameNameHack(element, compiler)); - if (Elements.isUnresolved(element)) return false; - if (name.isPrivate() && library != element.getLibrary()) return false; - if (element.isForeign(compiler)) return true; - if (element.isSetter()) return isSetter(); - if (element.isGetter()) return isGetter() || isCall(); - if (element.isField()) return isGetter() || isSetter() || isCall(); - if (isGetter()) return true; - if (isSetter()) return false; - - FunctionElement function = element; - FunctionSignature parameters = function.computeSignature(compiler); - if (argumentCount > parameters.parameterCount) return false; - int requiredParameterCount = parameters.requiredParameterCount; - int optionalParameterCount = parameters.optionalParameterCount; - if (positionalArgumentCount < requiredParameterCount) return false; - - if (!parameters.optionalParametersAreNamed) { - // We have already checked that the number of arguments are - // not greater than the number of parameters. Therefore the - // number of positional arguments are not greater than the - // number of parameters. - assert(positionalArgumentCount <= parameters.parameterCount); - return namedArguments.isEmpty; - } else { - if (positionalArgumentCount > requiredParameterCount) return false; - assert(positionalArgumentCount == requiredParameterCount); - if (namedArgumentCount > optionalParameterCount) return false; - Set<SourceString> nameSet = new Set<SourceString>(); - parameters.optionalParameters.forEach((Element element) { - nameSet.add(element.name); - }); - for (SourceString name in namedArguments) { - if (!nameSet.contains(name)) return false; - // TODO(5213): By removing from the set we are checking - // that we are not passing the name twice. We should have this - // check in the resolver also. - nameSet.remove(name); - } - return true; - } - } - - bool sameNameHack(Element element, Compiler compiler) { - // TODO(ngeoffray): Remove workaround checks. - return element == compiler.assertMethod - || element.isConstructor() - || name == element.name; - } - - bool applies(Element element, Compiler compiler) { - if (!sameNameHack(element, compiler)) return false; - return appliesUnnamed(element, compiler); - } - - /** - * Fills [list] with the arguments in a defined order. - * - * [compileArgument] is a function that returns a compiled version - * of an argument located in [arguments]. - * - * [compileConstant] is a function that returns a compiled constant - * of an optional argument that is not in [arguments. - * - * Returns [:true:] if the selector and the [element] match; [:false:] - * otherwise. - * - * Invariant: [element] must be the implementation element. - */ - bool addArgumentsToList(Link<Node> arguments, - List list, - FunctionElement element, - compileArgument(Node argument), - compileConstant(Element element), - Compiler compiler) { - assert(invariant(element, element.isImplementation)); - if (!this.applies(element, compiler)) return false; - - FunctionSignature parameters = element.computeSignature(compiler); - parameters.forEachRequiredParameter((element) { - list.add(compileArgument(arguments.head)); - arguments = arguments.tail; - }); - - if (!parameters.optionalParametersAreNamed) { - parameters.forEachOptionalParameter((element) { - if (!arguments.isEmpty) { - list.add(compileArgument(arguments.head)); - arguments = arguments.tail; - } else { - list.add(compileConstant(element)); - } - }); - } else { - // Visit named arguments and add them into a temporary list. - List compiledNamedArguments = []; - for (; !arguments.isEmpty; arguments = arguments.tail) { - NamedArgument namedArgument = arguments.head; - compiledNamedArguments.add(compileArgument(namedArgument.expression)); - } - // Iterate over the optional parameters of the signature, and try to - // find them in [compiledNamedArguments]. If found, we use the - // value in the temporary list, otherwise the default value. - parameters.orderedOptionalParameters.forEach((element) { - int foundIndex = namedArguments.indexOf(element.name); - if (foundIndex != -1) { - list.add(compiledNamedArguments[foundIndex]); - } else { - list.add(compileConstant(element)); - } - }); - } - return true; - } - - static bool sameNames(List<SourceString> first, List<SourceString> second) { - for (int i = 0; i < first.length; i++) { - if (first[i] != second[i]) return false; - } - return true; - } - - bool operator ==(other) { - if (other is !Selector) return false; - return identical(receiverType, other.receiverType) - && equalsUntyped(other); - } - - bool equalsUntyped(Selector other) { - return name == other.name - && kind == other.kind - && identical(library, other.library) - && argumentCount == other.argumentCount - && namedArguments.length == other.namedArguments.length - && sameNames(namedArguments, other.namedArguments); - } - - List<SourceString> getOrderedNamedArguments() { - if (namedArguments.isEmpty) return namedArguments; - if (!orderedNamedArguments.isEmpty) return orderedNamedArguments; - - orderedNamedArguments.addAll(namedArguments); - orderedNamedArguments.sort((SourceString first, SourceString second) { - return first.slowToString().compareTo(second.slowToString()); - }); - return orderedNamedArguments; - } - - String namedArgumentsToString() { - if (namedArgumentCount > 0) { - StringBuffer result = new StringBuffer(); - for (int i = 0; i < namedArgumentCount; i++) { - if (i != 0) result.add(', '); - result.add(namedArguments[i].slowToString()); - } - return "[$result]"; - } - return ''; - } - - String toString() { - String named = ''; - String type = ''; - if (namedArgumentCount > 0) named = ', named=${namedArgumentsToString()}'; - if (receiverType != null) type = ', type=$receiverType'; - return 'Selector($kind, ${name.slowToString()}, ' - 'arity=$argumentCount$named$type)'; - } -} - -class TypedSelector extends Selector { - /** - * The type of the receiver. Any subtype of that type can be the - * target of the invocation. - */ - final DartType receiverType; - - final Selector asUntyped; - - TypedSelector(DartType this.receiverType, Selector selector) - : asUntyped = selector.asUntyped, - super(selector.kind, - selector.name, - selector.library, - selector.argumentCount, - selector.namedArguments) { - // Invariant: Typed selector can not be based on a malformed type. - assert(!identical(receiverType.kind, TypeKind.MALFORMED_TYPE)); - assert(asUntyped.receiverType == null); - } - - /** - * Check if [element] will be the one used at runtime when being - * invoked on an instance of [cls]. - */ - bool hasElementIn(ClassElement cls, Element element) { - // Use the selector for the lookup instead of [:element.name:] - // because the selector has the right privacy information. - Element resolved = cls.lookupSelector(this); - if (resolved == element) return true; - if (resolved == null) return false; - if (resolved.isAbstractField()) { - AbstractFieldElement field = resolved; - if (element == field.getter || element == field.setter) { - return true; - } else { - ClassElement otherCls = field.getEnclosingClass(); - // We have not found a match, but another class higher in the - // hierarchy may define the getter or the setter. - return hasElementIn(otherCls.superclass, element); - } - } - return false; - } - - bool appliesUnnamed(Element element, Compiler compiler) { - assert(sameNameHack(element, compiler)); - // [TypedSelector] are only used when compiling. - assert(compiler.phase == Compiler.PHASE_COMPILING); - if (!element.isMember()) return false; - - // A closure can be called through any typed selector: - // class A { - // get foo => () => 42; - // bar() => foo(); // The call to 'foo' is a typed selector. - // } - ClassElement other = element.getEnclosingClass(); - if (identical(other.superclass, compiler.closureClass)) { - return appliesUntyped(element, compiler); - } - - Element self = receiverType.element; - if (self.isTypedef()) { - // A typedef is a function type that doesn't have any - // user-defined members. - return false; - } - - if (other.implementsInterface(self) - || other.isSubclassOf(self) - || compiler.world.hasAnySubclassThatImplements(other, receiverType)) { - return appliesUntyped(element, compiler); - } - - // If [self] is a subclass of [other], it inherits the - // implementation of [element]. - ClassElement cls = self; - if (cls.isSubclassOf(other)) { - // Resolve an invocation of [element.name] on [self]. If it - // is found, this selector is a candidate. - return hasElementIn(self, element) && appliesUntyped(element, compiler); - } - - return false; - } -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/util/characters.dart b/pkgs/markdown/test/lib/src/compiler/implementation/util/characters.dart deleted file mode 100644 index 5961d07..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/util/characters.dart +++ /dev/null
@@ -1,143 +0,0 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library characters; - -const int $EOF = 0; -const int $STX = 2; -const int $BS = 8; -const int $TAB = 9; -const int $LF = 10; -const int $VTAB = 11; -const int $FF = 12; -const int $CR = 13; -const int $SPACE = 32; -const int $BANG = 33; -const int $DQ = 34; -const int $HASH = 35; -const int $$ = 36; -const int $PERCENT = 37; -const int $AMPERSAND = 38; -const int $SQ = 39; -const int $OPEN_PAREN = 40; -const int $CLOSE_PAREN = 41; -const int $STAR = 42; -const int $PLUS = 43; -const int $COMMA = 44; -const int $MINUS = 45; -const int $PERIOD = 46; -const int $SLASH = 47; -const int $0 = 48; -const int $1 = 49; -const int $2 = 50; -const int $3 = 51; -const int $4 = 52; -const int $5 = 53; -const int $6 = 54; -const int $7 = 55; -const int $8 = 56; -const int $9 = 57; -const int $COLON = 58; -const int $SEMICOLON = 59; -const int $LT = 60; -const int $EQ = 61; -const int $GT = 62; -const int $QUESTION = 63; -const int $AT = 64; -const int $A = 65; -const int $B = 66; -const int $C = 67; -const int $D = 68; -const int $E = 69; -const int $F = 70; -const int $G = 71; -const int $H = 72; -const int $I = 73; -const int $J = 74; -const int $K = 75; -const int $L = 76; -const int $M = 77; -const int $N = 78; -const int $O = 79; -const int $P = 80; -const int $Q = 81; -const int $R = 82; -const int $S = 83; -const int $T = 84; -const int $U = 85; -const int $V = 86; -const int $W = 87; -const int $X = 88; -const int $Y = 89; -const int $Z = 90; -const int $OPEN_SQUARE_BRACKET = 91; -const int $BACKSLASH = 92; -const int $CLOSE_SQUARE_BRACKET = 93; -const int $CARET = 94; -const int $_ = 95; -const int $BACKPING = 96; -const int $a = 97; -const int $b = 98; -const int $c = 99; -const int $d = 100; -const int $e = 101; -const int $f = 102; -const int $g = 103; -const int $h = 104; -const int $i = 105; -const int $j = 106; -const int $k = 107; -const int $l = 108; -const int $m = 109; -const int $n = 110; -const int $o = 111; -const int $p = 112; -const int $q = 113; -const int $r = 114; -const int $s = 115; -const int $t = 116; -const int $u = 117; -const int $v = 118; -const int $w = 119; -const int $x = 120; -const int $y = 121; -const int $z = 122; -const int $OPEN_CURLY_BRACKET = 123; -const int $BAR = 124; -const int $CLOSE_CURLY_BRACKET = 125; -const int $TILDE = 126; -const int $DEL = 127; -const int $NBSP = 160; -const int $LS = 0x2028; -const int $PS = 0x2029; - -const int $FIRST_SURROGATE = 0xd800; -const int $LAST_SURROGATE = 0xdfff; -const int $LAST_CODE_POINT = 0x10ffff; - -bool isHexDigit(int characterCode) { - if (characterCode <= $9) return $0 <= characterCode; - characterCode |= $a ^ $A; - return ($a <= characterCode && characterCode <= $f); -} - -int hexDigitValue(int hexDigit) { - assert(isHexDigit(hexDigit)); - // hexDigit is one of '0'..'9', 'A'..'F' and 'a'..'f'. - if (hexDigit <= $9) return hexDigit - $0; - return (hexDigit | ($a ^ $A)) - ($a - 10); -} - -bool isUnicodeScalarValue(int value) { - return value < $FIRST_SURROGATE || - (value > $LAST_SURROGATE && value <= $LAST_CODE_POINT); -} - -bool isUtf16LeadSurrogate(int value) { - return value >= 0xd800 && value <= 0xdbff; -} - -bool isUtf16TrailSurrogate(int value) { - return value >= 0xdc00 && value <= 0xdfff; -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/util/link.dart b/pkgs/markdown/test/lib/src/compiler/implementation/util/link.dart deleted file mode 100644 index 9cc81cc..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/util/link.dart +++ /dev/null
@@ -1,81 +0,0 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of org_dartlang_compiler_util; - -class Link<T> extends Iterable<T> { - T get head => null; - Link<T> get tail => null; - - factory Link.fromList(List<T> list) { - switch (list.length) { - case 0: - return new Link<T>(); - case 1: - return new LinkEntry<T>(list[0]); - case 2: - return new LinkEntry<T>(list[0], new LinkEntry<T>(list[1])); - case 3: - return new LinkEntry<T>( - list[0], new LinkEntry<T>(list[1], new LinkEntry<T>(list[2]))); - } - Link link = new Link<T>(); - for (int i = list.length ; i > 0; i--) { - link = link.prepend(list[i - 1]); - } - return link; - } - - const Link(); - - Link<T> prepend(T element) { - return new LinkEntry<T>(element, this); - } - - Iterator<T> get iterator => new LinkIterator<T>(this); - - void printOn(StringBuffer buffer, [separatedBy]) { - } - - List toList() => new List<T>.fixedLength(0); - - bool get isEmpty => true; - - Link<T> reverse() => this; - - Link<T> reversePrependAll(Link<T> from) { - if (from.isEmpty) return this; - return this.prepend(from.head).reversePrependAll(from.tail); - } - - Link<T> skip(int n) { - if (n == 0) return this; - throw new RangeError('Index $n out of range'); - } - - void forEach(void f(T element)) {} - - bool operator ==(other) { - if (other is !Link<T>) return false; - return other.isEmpty; - } - - String toString() => "[]"; - - get length { - throw new UnsupportedError('get:length'); - } - - int slowLength() => 0; -} - -abstract class LinkBuilder<T> { - factory LinkBuilder() = LinkBuilderImplementation; - - Link<T> toLink(); - void addLast(T t); - - final int length; - final bool isEmpty; -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/util/link_implementation.dart b/pkgs/markdown/test/lib/src/compiler/implementation/util/link_implementation.dart deleted file mode 100644 index d00ec86..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/util/link_implementation.dart +++ /dev/null
@@ -1,142 +0,0 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of util_implementation; - -class LinkIterator<T> implements Iterator<T> { - T _current; - Link<T> _link; - - LinkIterator(Link<T> this._link); - - T get current => _current; - - bool moveNext() { - if (_link.isEmpty) { - _current = null; - return false; - } - _current = _link.head; - _link = _link.tail; - return true; - } -} - -class LinkEntry<T> extends Link<T> { - final T head; - Link<T> tail; - - LinkEntry(T this.head, [Link<T> tail]) - : this.tail = ((tail == null) ? new Link<T>() : tail); - - Link<T> prepend(T element) { - // TODO(ahe): Use new Link<T>, but this cost 8% performance on VM. - return new LinkEntry<T>(element, this); - } - - void printOn(StringBuffer buffer, [separatedBy]) { - buffer.add(head); - if (separatedBy == null) separatedBy = ''; - for (Link link = tail; !link.isEmpty; link = link.tail) { - buffer.add(separatedBy); - buffer.add(link.head); - } - } - - String toString() { - StringBuffer buffer = new StringBuffer(); - buffer.add('[ '); - printOn(buffer, ', '); - buffer.add(' ]'); - return buffer.toString(); - } - - Link<T> reverse() { - Link<T> result = const Link(); - for (Link<T> link = this; !link.isEmpty; link = link.tail) { - result = result.prepend(link.head); - } - return result; - } - - Link<T> reversePrependAll(Link<T> from) { - Link<T> result; - for (result = this; !from.isEmpty; from = from.tail) { - result = result.prepend(from.head); - } - return result; - } - - Link<T> skip(int n) { - Link<T> link = this; - for (int i = 0 ; i < n ; i++) { - if (link.isEmpty) { - throw new RangeError('Index $n out of range'); - } - link = link.tail; - } - return link; - } - - bool get isEmpty => false; - - List<T> toList() { - List<T> list = new List<T>(); - for (Link<T> link = this; !link.isEmpty; link = link.tail) { - list.addLast(link.head); - } - return list; - } - - void forEach(void f(T element)) { - for (Link<T> link = this; !link.isEmpty; link = link.tail) { - f(link.head); - } - } - - bool operator ==(other) { - if (other is !Link<T>) return false; - Link<T> myElements = this; - while (!myElements.isEmpty && !other.isEmpty) { - if (myElements.head != other.head) { - return false; - } - myElements = myElements.tail; - other = other.tail; - } - return myElements.isEmpty && other.isEmpty; - } - - int slowLength() => 1 + tail.slowLength(); -} - -class LinkBuilderImplementation<T> implements LinkBuilder<T> { - LinkEntry<T> head = null; - LinkEntry<T> lastLink = null; - int length = 0; - - LinkBuilderImplementation(); - - Link<T> toLink() { - if (head == null) return const Link(); - lastLink.tail = const Link(); - Link<T> link = head; - lastLink = null; - head = null; - return link; - } - - void addLast(T t) { - length++; - LinkEntry<T> entry = new LinkEntry<T>(t, null); - if (head == null) { - head = entry; - } else { - lastLink.tail = entry; - } - lastLink = entry; - } - - bool get isEmpty => length == 0; -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/util/uri_extras.dart b/pkgs/markdown/test/lib/src/compiler/implementation/util/uri_extras.dart deleted file mode 100644 index fed5f15..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/util/uri_extras.dart +++ /dev/null
@@ -1,65 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library uri_extras; - -import 'dart:math'; -import 'dart:uri'; - -String relativize(Uri base, Uri uri, bool isWindows) { - if (!base.path.startsWith('/')) { - // Also throw an exception if [base] or base.path is null. - throw new ArgumentError('Expected absolute path: ${base.path}'); - } - if (!uri.path.startsWith('/')) { - // Also throw an exception if [uri] or uri.path is null. - throw new ArgumentError('Expected absolute path: ${uri.path}'); - } - bool equalsNCS(String a, String b) { - return a.toLowerCase() == b.toLowerCase(); - } - - String normalize(String path) { - if (isWindows) { - return path.toLowerCase(); - } else { - return path; - } - } - - if (equalsNCS(base.scheme, 'file') && - equalsNCS(base.scheme, uri.scheme) && - base.userInfo == uri.userInfo && - equalsNCS(base.domain, uri.domain) && - base.port == uri.port && - uri.query == "" && uri.fragment == "") { - if (normalize(uri.path).startsWith(normalize(base.path))) { - return uri.path.substring(base.path.length); - } - List<String> uriParts = uri.path.split('/'); - List<String> baseParts = base.path.split('/'); - int common = 0; - int length = min(uriParts.length, baseParts.length); - while (common < length && - normalize(uriParts[common]) == normalize(baseParts[common])) { - common++; - } - if (common == 1 || (isWindows && common == 2)) { - // The first part will always be an empty string because the - // paths are absolute. On Windows, we must also consider drive - // letters or hostnames. - return uri.path; - } - StringBuffer sb = new StringBuffer(); - for (int i = common + 1; i < baseParts.length; i++) { - sb.add('../'); - } - for (int i = common; i < uriParts.length - 1; i++) { - sb.add('${uriParts[i]}/'); - } - sb.add('${uriParts.last}'); - return sb.toString(); - } - return uri.toString(); -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/util/util.dart b/pkgs/markdown/test/lib/src/compiler/implementation/util/util.dart deleted file mode 100644 index 8a07687..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/util/util.dart +++ /dev/null
@@ -1,109 +0,0 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library org_dartlang_compiler_util; - -import 'util_implementation.dart'; -import 'characters.dart'; - -part 'link.dart'; - -/** - * Tagging interface for classes from which source spans can be generated. - */ -// TODO(johnniwinther): Find a better name. -// TODO(ahe): How about "Bolt"? -abstract class Spannable {} - -class _SpannableSentinel implements Spannable { - final String name; - - const _SpannableSentinel(this.name); - - String toString() => name; -} - -const Spannable CURRENT_ELEMENT_SPANNABLE = - const _SpannableSentinel("Current element"); - -class SpannableAssertionFailure { - final Spannable node; - final String message; - SpannableAssertionFailure(this.node, this.message); - - String toString() => 'Compiler crashed: $message.'; -} - -/// Writes the characters of [string] on [buffer]. The characters -/// are escaped as suitable for JavaScript and JSON. [buffer] is -/// anything which supports [:add:] and [:addCharCode:], for example, -/// [StringBuffer]. Note that JS supports \xnn and \unnnn whereas JSON only -/// supports the \unnnn notation. Therefore we use the \unnnn notation. -void writeJsonEscapedCharsOn(String string, buffer) { - void addCodeUnitEscaped(var buffer, int code) { - assert(code < 0x10000); - buffer.add(r'\u'); - if (code < 0x1000) { - buffer.add('0'); - if (code < 0x100) { - buffer.add('0'); - if (code < 0x10) { - buffer.add('0'); - } - } - } - buffer.add(code.toRadixString(16)); - } - - void writeEscapedOn(String string, var buffer) { - for (int i = 0; i < string.length; i++) { - int code = string.charCodeAt(i); - if (code == $DQ) { - buffer.add(r'\"'); - } else if (code == $TAB) { - buffer.add(r'\t'); - } else if (code == $LF) { - buffer.add(r'\n'); - } else if (code == $CR) { - buffer.add(r'\r'); - } else if (code == $DEL) { - addCodeUnitEscaped(buffer, $DEL); - } else if (code == $LS) { - // This Unicode line terminator and $PS are invalid in JS string - // literals. - addCodeUnitEscaped(buffer, $LS); // 0x2028. - } else if (code == $PS) { - addCodeUnitEscaped(buffer, $PS); // 0x2029. - } else if (code == $BACKSLASH) { - buffer.add(r'\\'); - } else { - if (code < 0x20) { - addCodeUnitEscaped(buffer, code); - // We emit DEL (ASCII 0x7f) as an escape because it would be confusing - // to have it unescaped in a string literal. We also escape - // everything above 0x7f because that means we don't have to worry - // about whether the web server serves it up as Latin1 or UTF-8. - } else if (code < 0x7f) { - buffer.addCharCode(code); - } else { - // This will output surrogate pairs in the form \udxxx\udyyy, rather - // than the more logical \u{zzzzzz}. This should work in JavaScript - // (especially old UCS-2 based implementations) and is the only - // format that is allowed in JSON. - addCodeUnitEscaped(buffer, code); - } - } - } - } - - for (int i = 0; i < string.length; i++) { - int code = string.charCodeAt(i); - if (code < 0x20 || code == $DEL || code == $DQ || code == $LS || - code == $PS || code == $BACKSLASH || code >= 0x80) { - writeEscapedOn(string, buffer); - return; - } - } - buffer.add(string); -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/util/util_implementation.dart b/pkgs/markdown/test/lib/src/compiler/implementation/util/util_implementation.dart deleted file mode 100644 index bbb852a..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/util/util_implementation.dart +++ /dev/null
@@ -1,9 +0,0 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library util_implementation; - -import 'util.dart'; - -part 'link_implementation.dart';
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/warnings.dart b/pkgs/markdown/test/lib/src/compiler/implementation/warnings.dart deleted file mode 100644 index 56f3698..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/warnings.dart +++ /dev/null
@@ -1,568 +0,0 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of dart2js; - -class MessageKind { - final String template; - const MessageKind(this.template); - - static const GENERIC = const MessageKind('#{text}'); - - static const NOT_ASSIGNABLE = const MessageKind( - '#{fromType} is not assignable to #{toType}'); - static const VOID_EXPRESSION = const MessageKind( - 'expression does not yield a value'); - static const VOID_VARIABLE = const MessageKind( - 'variable cannot be of type void'); - static const RETURN_VALUE_IN_VOID = const MessageKind( - 'cannot return value from void function'); - static const RETURN_NOTHING = const MessageKind( - 'value of type #{returnType} expected'); - static const MISSING_ARGUMENT = const MessageKind( - 'missing argument of type #{argumentType}'); - static const ADDITIONAL_ARGUMENT = const MessageKind( - 'additional argument'); - static const NAMED_ARGUMENT_NOT_FOUND = const MessageKind( - "no named argument '#{argumentName}' found on method"); - static const METHOD_NOT_FOUND = const MessageKind( - 'no method named #{methodName} in class #{className}'); - static const MEMBER_NOT_STATIC = const MessageKind( - '#{className}.#{memberName} is not static'); - static const NO_INSTANCE_AVAILABLE = const MessageKind( - '#{name} is only available in instance methods'); - - static const UNREACHABLE_CODE = const MessageKind( - 'unreachable code'); - static const MISSING_RETURN = const MessageKind( - 'missing return'); - static const MAYBE_MISSING_RETURN = const MessageKind( - 'not all paths lead to a return or throw statement'); - - static const CANNOT_RESOLVE = const MessageKind( - 'cannot resolve #{name}'); - static const CANNOT_RESOLVE_CONSTRUCTOR = const MessageKind( - 'cannot resolve constructor #{constructorName}'); - static const CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT = const MessageKind( - 'cannot resolve constructor #{constructorName} for implicit super call'); - static const CANNOT_RESOLVE_TYPE = const MessageKind( - 'cannot resolve type #{typeName}'); - static const DUPLICATE_DEFINITION = const MessageKind( - 'duplicate definition of #{name}'); - static const DUPLICATE_IMPORT = const MessageKind( - 'duplicate import of #{name}'); - static const DUPLICATE_EXPORT = const MessageKind( - 'duplicate export of #{name}'); - static const NOT_A_TYPE = const MessageKind( - '#{node} is not a type'); - static const NOT_A_PREFIX = const MessageKind( - '#{node} is not a prefix'); - static const NO_SUPER_IN_OBJECT = const MessageKind( - "'Object' does not have a superclass"); - static const CANNOT_FIND_CONSTRUCTOR = const MessageKind( - 'cannot find constructor #{constructorName}'); - static const CANNOT_FIND_CONSTRUCTOR2 = const MessageKind( - 'cannot find constructor #{constructorName} in #{className}'); - static const CYCLIC_CLASS_HIERARCHY = const MessageKind( - '#{className} creates a cycle in the class hierarchy'); - static const INVALID_RECEIVER_IN_INITIALIZER = const MessageKind( - 'field initializer expected'); - static const NO_SUPER_IN_STATIC = const MessageKind( - "'super' is only available in instance methods"); - static const DUPLICATE_INITIALIZER = const MessageKind( - 'field #{fieldName} is initialized more than once'); - static const ALREADY_INITIALIZED = const MessageKind( - '#{fieldName} was already initialized here'); - static const INIT_STATIC_FIELD = const MessageKind( - 'cannot initialize static field #{fieldName}'); - static const NOT_A_FIELD = const MessageKind( - '#{fieldName} is not a field'); - static const CONSTRUCTOR_CALL_EXPECTED = const MessageKind( - "only call to 'this' or 'super' constructor allowed"); - static const INVALID_FOR_IN = const MessageKind( - 'invalid for-in variable declaration.'); - static const INVALID_INITIALIZER = const MessageKind( - 'invalid initializer'); - static const FUNCTION_WITH_INITIALIZER = const MessageKind( - 'only constructors can have initializers'); - static const REDIRECTING_CONSTRUCTOR_CYCLE = const MessageKind( - 'cyclic constructor redirection'); - static const REDIRECTING_CONSTRUCTOR_HAS_BODY = const MessageKind( - 'redirecting constructor cannot have a body'); - static const REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER = const MessageKind( - 'redirecting constructor cannot have other initializers'); - static const SUPER_INITIALIZER_IN_OBJECT = const MessageKind( - "'Object' cannot have a super initializer"); - static const DUPLICATE_SUPER_INITIALIZER = const MessageKind( - 'cannot have more than one super initializer'); - static const INVALID_ARGUMENTS = const MessageKind( - "arguments do not match the expected parameters of #{methodName}"); - static const NO_MATCHING_CONSTRUCTOR = const MessageKind( - "super call arguments and constructor parameters don't match"); - static const NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT = const MessageKind( - "implicit super call arguments and constructor parameters don't match"); - static const FIELD_PARAMETER_NOT_ALLOWED = const MessageKind( - 'a field parameter is only allowed in generative constructors'); - static const INVALID_PARAMETER = const MessageKind( - "cannot resolve parameter"); - static const NOT_INSTANCE_FIELD = const MessageKind( - '#{fieldName} is not an instance field'); - static const NO_CATCH_NOR_FINALLY = const MessageKind( - "expected 'catch' or 'finally'"); - static const EMPTY_CATCH_DECLARATION = const MessageKind( - 'expected an identifier in catch declaration'); - static const EXTRA_CATCH_DECLARATION = const MessageKind( - 'extra parameter in catch declaration'); - static const PARAMETER_WITH_TYPE_IN_CATCH = const MessageKind( - 'cannot use type annotations in catch'); - static const PARAMETER_WITH_MODIFIER_IN_CATCH = const MessageKind( - 'cannot use modifiers in catch'); - static const OPTIONAL_PARAMETER_IN_CATCH = const MessageKind( - 'cannot use optional parameters in catch'); - static const THROW_WITHOUT_EXPRESSION = const MessageKind( - 'cannot use re-throw outside of catch block (expression expected after ' - '"throw")'); - static const UNBOUND_LABEL = const MessageKind( - 'cannot resolve label #{labelName}'); - static const NO_BREAK_TARGET = const MessageKind( - 'break statement not inside switch or loop'); - static const NO_CONTINUE_TARGET = const MessageKind( - 'continue statement not inside loop'); - static const EXISTING_LABEL = const MessageKind( - 'original declaration of duplicate label #{labelName}'); - static const DUPLICATE_LABEL = const MessageKind( - 'duplicate declaration of label #{labelName}'); - static const UNUSED_LABEL = const MessageKind( - 'unused label #{labelName}'); - static const INVALID_CONTINUE = const MessageKind( - 'target of continue is not a loop or switch case'); - static const INVALID_BREAK = const MessageKind( - 'target of break is not a statement'); - - static const TYPE_VARIABLE_AS_CONSTRUCTOR = const MessageKind( - 'cannot use type variable as constructor'); - static const DUPLICATE_TYPE_VARIABLE_NAME = const MessageKind( - 'type variable #{typeVariableName} already declared'); - static const TYPE_VARIABLE_WITHIN_STATIC_MEMBER = const MessageKind( - 'cannot refer to type variable #{typeVariableName} ' - 'within a static member'); - - static const INVALID_USE_OF_SUPER = const MessageKind( - 'super not allowed here'); - static const INVALID_CASE_DEFAULT = const MessageKind( - 'default only allowed on last case of a switch'); - - static const SWITCH_CASE_TYPES_NOT_EQUAL = const MessageKind( - "case expressions don't all have the same type."); - static const SWITCH_CASE_VALUE_OVERRIDES_EQUALS = const MessageKind( - "case expression value overrides 'operator=='."); - static const SWITCH_INVALID = const MessageKind( - "switch cases contain invalid expressions."); - - static const INVALID_ARGUMENT_AFTER_NAMED = const MessageKind( - 'non-named argument after named argument'); - - static const NOT_A_COMPILE_TIME_CONSTANT = const MessageKind( - 'not a compile-time constant'); - static const CYCLIC_COMPILE_TIME_CONSTANTS = const MessageKind( - 'cycle in the compile-time constant computation'); - static const CONSTRUCTOR_IS_NOT_CONST = const MessageKind( - 'constructor is not a const constructor'); - - static const KEY_NOT_A_STRING_LITERAL = const MessageKind( - 'map-literal key not a string literal'); - - static const NO_SUCH_LIBRARY_MEMBER = const MessageKind( - '#{libraryName} has no member named #{memberName}'); - - static const CANNOT_INSTANTIATE_INTERFACE = const MessageKind( - "cannot instantiate interface '#{interfaceName}'"); - - static const CANNOT_INSTANTIATE_TYPEDEF = const MessageKind( - "cannot instantiate typedef '#{typedefName}'"); - - static const CANNOT_INSTANTIATE_TYPE_VARIABLE = const MessageKind( - "cannot instantiate type variable '#{typeVariableName}'"); - - static const NO_DEFAULT_CLASS = const MessageKind( - "no default class on enclosing interface '#{interfaceName}'"); - - static const CYCLIC_TYPE_VARIABLE = const MessageKind( - "cyclic reference to type variable #{typeVariableName}"); - - static const CLASS_NAME_EXPECTED = const MessageKind( - "class name expected"); - - static const INTERFACE_TYPE_EXPECTED = const MessageKind( - "interface type expected"); - - static const CANNOT_EXTEND = const MessageKind( - "#{type} cannot be extended"); - - static const CANNOT_IMPLEMENT = const MessageKind( - "#{type} cannot be implemented"); - - static const DUPLICATE_EXTENDS_IMPLEMENTS = const MessageKind( - "Error: #{type} can not be both extended and implemented."); - - static const DUPLICATE_IMPLEMENTS = const MessageKind( - "Error: #{type} must not occur more than once " - "in the implements clause."); - - static const ILLEGAL_SUPER_SEND = const MessageKind( - "#{name} cannot be called on super"); - - static const ADDITIONAL_TYPE_ARGUMENT = const MessageKind( - "additional type argument"); - - static const MISSING_TYPE_ARGUMENT = const MessageKind( - "missing type argument"); - - // TODO(johnniwinther): Use ADDITIONAL_TYPE_ARGUMENT or MISSING_TYPE_ARGUMENT - // instead. - static const TYPE_ARGUMENT_COUNT_MISMATCH = const MessageKind( - "incorrect number of type arguments on #{type}"); - - static const MISSING_ARGUMENTS_TO_ASSERT = const MessageKind( - "missing arguments to assert"); - - static const GETTER_MISMATCH = const MessageKind( - "Error: setter disagrees on: #{modifiers}."); - - static const SETTER_MISMATCH = const MessageKind( - "Error: getter disagrees on: #{modifiers}."); - - static const ILLEGAL_SETTER_FORMALS = const MessageKind( - "Error: a setter must have exactly one argument."); - - static const NO_STATIC_OVERRIDE = const MessageKind( - "Error: static member cannot override instance member '#{memberName}' of " - "'#{className}'."); - - static const NO_STATIC_OVERRIDE_CONT = const MessageKind( - "Info: this is the instance member that cannot be overridden " - "by a static member."); - - static const CANNOT_OVERRIDE_FIELD_WITH_METHOD = const MessageKind( - "Error: method cannot override field '#{memberName}' of '#{className}'."); - - static const CANNOT_OVERRIDE_FIELD_WITH_METHOD_CONT = const MessageKind( - "Info: this is the field that cannot be overridden by a method."); - - static const CANNOT_OVERRIDE_METHOD_WITH_FIELD = const MessageKind( - "Error: field cannot override method '#{memberName}' of '#{className}'."); - - static const CANNOT_OVERRIDE_METHOD_WITH_FIELD_CONT = const MessageKind( - "Info: this is the method that cannot be overridden by a field."); - - static const BAD_ARITY_OVERRIDE = const MessageKind( - "Error: cannot override method '#{memberName}' in '#{className}'; " - "the parameters do not match."); - - static const BAD_ARITY_OVERRIDE_CONT = const MessageKind( - "Info: this is the method whose parameters do not match."); - - static const MISSING_FORMALS = const MessageKind( - "Error: Formal parameters are missing."); - - static const EXTRA_FORMALS = const MessageKind( - "Error: Formal parameters are not allowed here."); - - static const UNARY_OPERATOR_BAD_ARITY = const MessageKind( - "Error: Operator #{operatorName} must have no parameters."); - - static const MINUS_OPERATOR_BAD_ARITY = const MessageKind( - "Error: Operator - must have 0 or 1 parameters."); - - static const BINARY_OPERATOR_BAD_ARITY = const MessageKind( - "Error: Operator #{operatorName} must have exactly 1 parameter."); - - static const TERNARY_OPERATOR_BAD_ARITY = const MessageKind( - "Error: Operator #{operatorName} must have exactly 2 parameters."); - - static const OPERATOR_OPTIONAL_PARAMETERS = const MessageKind( - "Error: Operator #{operatorName} cannot have optional parameters."); - - static const OPERATOR_NAMED_PARAMETERS = const MessageKind( - "Error: Operator #{operatorName} cannot have named parameters."); - - // TODO(ahe): This message is hard to localize. This is acceptable, - // as it will be removed when we ship Dart version 1.0. - static const DEPRECATED_FEATURE_WARNING = const MessageKind( - "Warning: deprecated language feature, #{featureName}, " - "will be removed in a future Dart milestone."); - - // TODO(ahe): This message is hard to localize. This is acceptable, - // as it will be removed when we ship Dart version 1.0. - static const DEPRECATED_FEATURE_ERROR = const MessageKind( - "Error: #{featureName} are not legal " - "due to option --reject-deprecated-language-features."); - - static const CONSTRUCTOR_WITH_RETURN_TYPE = const MessageKind( - "Error: cannot have return type for constructor."); - - static const ILLEGAL_FINAL_METHOD_MODIFIER = const MessageKind( - "Error: cannot have final modifier on method."); - - static const ILLEGAL_CONSTRUCTOR_MODIFIERS = const MessageKind( - "Error: illegal constructor modifiers: #{modifiers}."); - - static const ILLEGAL_MIXIN_APPLICATION_MODIFIERS = const MessageKind( - "Error: illegal mixin application modifiers: #{modifiers}."); - - static const ILLEGAL_MIXIN_SUPERCLASS = const MessageKind( - "Error: class used as mixin must have Object as superclass."); - - static const ILLEGAL_MIXIN_CONSTRUCTOR = const MessageKind( - "Error: class used as mixin cannot have non-factory constructor."); - - static const ILLEGAL_MIXIN_CYCLE = const MessageKind( - "Error: class used as mixin introduces mixin cycle: " - "#{mixinName1} <-> #{mixinName2}."); - - static const ILLEGAL_MIXIN_WITH_SUPER = const MessageKind( - "Error: cannot use class #{className} as a mixin because it uses super."); - - static const ILLEGAL_MIXIN_SUPER_USE = const MessageKind( - "Use of super in class used as mixin."); - - static const PARAMETER_NAME_EXPECTED = const MessageKind( - "Error: parameter name expected."); - - static const CANNOT_RESOLVE_GETTER = const MessageKind( - 'cannot resolve getter.'); - - static const CANNOT_RESOLVE_SETTER = const MessageKind( - 'cannot resolve setter.'); - - static const VOID_NOT_ALLOWED = const MessageKind( - 'type void is only allowed in a return type.'); - - static const BEFORE_TOP_LEVEL = const MessageKind( - 'Error: part header must come before top-level definitions.'); - - static const LIBRARY_NAME_MISMATCH = const MessageKind( - 'Warning: expected part of library name "#{libraryName}".'); - - static const MISSING_PART_OF_TAG = const MessageKind( - 'Note: This file has no part-of tag, but it is being used as a part.'); - - static const DUPLICATED_PART_OF = const MessageKind( - 'Error: duplicated part-of directive.'); - - static const ILLEGAL_DIRECTIVE = const MessageKind( - 'Error: directive not allowed here.'); - - static const DUPLICATED_LIBRARY_NAME = const MessageKind( - 'Warning: duplicated library name "#{libraryName}".'); - - static const INVALID_SOURCE_FILE_LOCATION = const MessageKind(''' -Invalid offset (#{offset}) in source map. -File: #{fileName} -Length: #{length}'''); - - static const TOP_LEVEL_VARIABLE_DECLARED_STATIC = const MessageKind( - "Top-level variable cannot be declared static."); - - static const WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT = const MessageKind( - "Wrong number of arguments to assert. Should be 1, but given " - "#{argumentCount}."); - - static const ASSERT_IS_GIVEN_NAMED_ARGUMENTS = const MessageKind( - "assert takes no named arguments, but given #{argumentCount}."); - - static const FACTORY_REDIRECTION_IN_NON_FACTORY = const MessageKind( - "Error: Factory redirection only allowed in factories."); - - static const MISSING_FACTORY_KEYWORD = const MessageKind( - "Did you forget a factory keyword here?"); - - static const COMPILER_CRASHED = const MessageKind( - "Error: The compiler crashed when compiling this element."); - - static const PLEASE_REPORT_THE_CRASH = const MessageKind(''' -The compiler is broken. - -When compiling the above element, the compiler crashed. It is not -possible to tell if this is caused by a problem in your program or -not. Regardless, the compiler should not crash. - -The Dart team would greatly appreciate if you would take a moment to -report this problem at http://dartbug.com/new. - -Please include the following information: - -* the name and version of your operating system, - -* the Dart SDK build number (#{buildId}), and - -* the entire message you see here (including the full stack trace - below as well as the source location above). -'''); - - - ////////////////////////////////////////////////////////////////////////////// - // Patch errors start. - ////////////////////////////////////////////////////////////////////////////// - - static const PATCH_RETURN_TYPE_MISMATCH = const MessageKind( - "Patch return type '#{patchReturnType}' doesn't match " - "'#{originReturnType}' on origin method '#{methodName}'."); - - static const PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH = const MessageKind( - "Required parameter count of patch method (#{patchParameterCount}) " - "doesn't match parameter count on origin method '#{methodName}' " - "(#{originParameterCount})."); - - static const PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH = const MessageKind( - "Optional parameter count of patch method (#{patchParameterCount}) " - "doesn't match parameter count on origin method '#{methodName}' " - "(#{originParameterCount})."); - - static const PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH = const MessageKind( - "Optional parameters of origin and patch method '#{methodName}' must " - "both be either named or positional."); - - static const PATCH_PARAMETER_MISMATCH = const MessageKind( - "Patch method parameter '#{patchParameter}' doesn't match " - "'#{originParameter}' on origin method #{methodName}."); - - static const PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION = const MessageKind( - "External method without an implementation."); - - static const PATCH_POINT_TO_FUNCTION = const MessageKind( - "Info: This is the function patch '#{functionName}'."); - - static const PATCH_POINT_TO_CLASS = const MessageKind( - "Info: This is the class patch '#{className}'."); - - static const PATCH_POINT_TO_GETTER = const MessageKind( - "Info: This is the getter patch '#{getterName}'."); - - static const PATCH_POINT_TO_SETTER = const MessageKind( - "Info: This is the setter patch '#{setterName}'."); - - static const PATCH_POINT_TO_CONSTRUCTOR = const MessageKind( - "Info: This is the constructor patch '#{constructorName}'."); - - static const PATCH_NON_EXISTING = const MessageKind( - "Error: Origin does not exist for patch '#{name}'."); - - static const PATCH_NONPATCHABLE = const MessageKind( - "Error: Only classes and functions can be patched."); - - static const PATCH_NON_EXTERNAL = const MessageKind( - "Error: Only external functions can be patched."); - - static const PATCH_NON_CLASS = const MessageKind( - "Error: Patching non-class with class patch '#{className}'."); - - static const PATCH_NON_GETTER = const MessageKind( - "Error: Cannot patch non-getter '#{name}' with getter patch."); - - static const PATCH_NO_GETTER = const MessageKind( - "Error: No getter found for getter patch '#{getterName}'."); - - static const PATCH_NON_SETTER = const MessageKind( - "Error: Cannot patch non-setter '#{name}' with setter patch."); - - static const PATCH_NO_SETTER = const MessageKind( - "Error: No setter found for setter patch '#{setterName}'."); - - static const PATCH_NON_CONSTRUCTOR = const MessageKind( - "Error: Cannot patch non-constructor with constructor patch " - "'#{constructorName}'."); - - static const PATCH_NON_FUNCTION = const MessageKind( - "Error: Cannot patch non-function with function patch " - "'#{functionName}'."); - - ////////////////////////////////////////////////////////////////////////////// - // Patch errors end. - ////////////////////////////////////////////////////////////////////////////// - - toString() => template; - - Message message([Map arguments = const {}]) { - return new Message(this, arguments); - } - - CompilationError error([Map arguments = const {}]) { - return new CompilationError(this, arguments); - } -} - -class Message { - final kind; - final Map arguments; - String message; - - Message(this.kind, this.arguments) { - assert(() { computeMessage(); return true; }); - } - - String computeMessage() { - if (message == null) { - message = kind.template; - arguments.forEach((key, value) { - String string = slowToString(value); - message = message.replaceAll('#{${key}}', string); - }); - assert(invariant( - CURRENT_ELEMENT_SPANNABLE, - !message.contains(new RegExp(r"#\{.+\}")), - message: 'Missing arguments in error message: "$message"')); - } - return message; - } - - String toString() { - return computeMessage(); - } - - bool operator==(other) { - if (other is !Message) return false; - return (kind == other.kind) && (toString() == other.toString()); - } - - String slowToString(object) { - if (object is SourceString) { - return object.slowToString(); - } else { - return object.toString(); - } - } -} - -class Diagnostic { - final Message message; - Diagnostic(MessageKind kind, [Map arguments = const {}]) - : message = new Message(kind, arguments); - String toString() => message.toString(); -} - -class TypeWarning extends Diagnostic { - TypeWarning(MessageKind kind, [Map arguments = const {}]) - : super(kind, arguments); -} - -class ResolutionError extends Diagnostic { - ResolutionError(MessageKind kind, [Map arguments = const {}]) - : super(kind, arguments); -} - -class ResolutionWarning extends Diagnostic { - ResolutionWarning(MessageKind kind, [Map arguments = const {}]) - : super(kind, arguments); -} - -class CompileTimeConstantError extends Diagnostic { - CompileTimeConstantError(MessageKind kind, [Map arguments = const {}]) - : super(kind, arguments); -} - -class CompilationError extends Diagnostic { - CompilationError(MessageKind kind, [Map arguments = const {}]) - : super(kind, arguments); -}
diff --git a/pkgs/markdown/test/lib/src/compiler/implementation/world.dart b/pkgs/markdown/test/lib/src/compiler/implementation/world.dart deleted file mode 100644 index a40050e..0000000 --- a/pkgs/markdown/test/lib/src/compiler/implementation/world.dart +++ /dev/null
@@ -1,232 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of dart2js; - -class World { - final Compiler compiler; - final Map<ClassElement, Set<ClassElement>> subtypes; - final Map<ClassElement, Set<MixinApplicationElement>> mixinUses; - final Map<ClassElement, Set<ClassElement>> typesImplementedBySubclasses; - final Set<ClassElement> classesNeedingRti; - final Map<ClassElement, Set<ClassElement>> rtiDependencies; - final FunctionSet userDefinedGetters; - final FunctionSet userDefinedSetters; - - World(Compiler compiler) - : subtypes = new Map<ClassElement, Set<ClassElement>>(), - mixinUses = new Map<ClassElement, Set<MixinApplicationElement>>(), - typesImplementedBySubclasses = - new Map<ClassElement, Set<ClassElement>>(), - userDefinedGetters = new FunctionSet(compiler), - userDefinedSetters = new FunctionSet(compiler), - classesNeedingRti = new Set<ClassElement>(), - rtiDependencies = new Map<ClassElement, Set<ClassElement>>(), - this.compiler = compiler; - - void populate() { - void addSubtypes(ClassElement cls) { - if (cls.resolutionState != STATE_DONE) { - compiler.internalErrorOnElement( - cls, 'Class "${cls.name.slowToString()}" is not resolved.'); - } - - for (DartType type in cls.allSupertypes) { - Set<Element> subtypesOfCls = - subtypes.putIfAbsent(type.element, () => new Set<ClassElement>()); - subtypesOfCls.add(cls); - } - - // Walk through the superclasses, and record the types - // implemented by that type on the superclasses. - DartType type = cls.supertype; - while (type != null) { - Set<Element> typesImplementedBySubclassesOfCls = - typesImplementedBySubclasses.putIfAbsent( - type.element, () => new Set<ClassElement>()); - for (DartType current in cls.allSupertypes) { - typesImplementedBySubclassesOfCls.add(current.element); - } - ClassElement classElement = type.element; - type = classElement.supertype; - } - } - - compiler.resolverWorld.instantiatedClasses.forEach(addSubtypes); - - // Find the classes that need runtime type information. Such - // classes are: - // (1) used in a is check with type variables, - // (2) dependencies of classes in (1), - // (3) subclasses of (2) and (3). - - void potentiallyAddForRti(ClassElement cls) { - if (cls.typeVariables.isEmpty) return; - if (classesNeedingRti.contains(cls)) return; - classesNeedingRti.add(cls); - - Set<ClassElement> classes = subtypes[cls]; - if (classes != null) { - classes.forEach((ClassElement sub) { - potentiallyAddForRti(sub); - }); - } - - Set<ClassElement> dependencies = rtiDependencies[cls]; - if (dependencies != null) { - dependencies.forEach((ClassElement other) { - potentiallyAddForRti(other); - }); - } - } - - compiler.resolverWorld.isChecks.forEach((DartType type) { - if (type is InterfaceType) { - InterfaceType itf = type; - if (!itf.isRaw) { - potentiallyAddForRti(itf.element); - } - } - }); - } - - bool needsRti(ClassElement cls) { - return classesNeedingRti.contains(cls) || compiler.enabledRuntimeType; - } - - void registerMixinUse(MixinApplicationElement mixinApplication, - ClassElement mixin) { - Set<MixinApplicationElement> users = - mixinUses.putIfAbsent(mixin, () => - new Set<MixinApplicationElement>()); - users.add(mixinApplication); - } - - void registerRtiDependency(Element element, Element dependency) { - // We're not dealing with typedef for now. - if (!element.isClass() || !dependency.isClass()) return; - Set<ClassElement> classes = - rtiDependencies.putIfAbsent(element, () => new Set<ClassElement>()); - classes.add(dependency); - } - - void recordUserDefinedGetter(Element element) { - assert(element.isGetter()); - userDefinedGetters.add(element); - } - - void recordUserDefinedSetter(Element element) { - assert(element.isSetter()); - userDefinedSetters.add(element); - } - - bool hasAnyUserDefinedGetter(Selector selector) { - return userDefinedGetters.hasAnyElementMatchingSelector(selector); - } - - bool hasAnyUserDefinedSetter(Selector selector) { - return userDefinedSetters.hasAnyElementMatchingSelector(selector); - } - - // Returns whether a subclass of [superclass] implements [type]. - bool hasAnySubclassThatImplements(ClassElement superclass, DartType type) { - Set<ClassElement> subclasses= typesImplementedBySubclasses[superclass]; - if (subclasses == null) return false; - return subclasses.contains(type.element); - } - - bool hasNoOverridingMember(Element element) { - ClassElement cls = element.getEnclosingClass(); - Set<ClassElement> subclasses = compiler.world.subtypes[cls]; - // TODO(ngeoffray): Implement the full thing. - return subclasses == null || subclasses.isEmpty; - } - - void registerUsedElement(Element element) { - if (element.isMember()) { - if (element.isGetter()) { - // We're collecting user-defined getters to let the codegen know which - // field accesses might have side effects. - recordUserDefinedGetter(element); - } else if (element.isSetter()) { - recordUserDefinedSetter(element); - } - } - } - - /** - * Returns a [MemberSet] that contains the possible targets of the given - * [selector] on a receiver with the given [type]. This includes all sub - * types. - */ - MemberSet _memberSetFor(DartType type, Selector selector) { - assert(compiler != null); - ClassElement cls = type.element; - SourceString name = selector.name; - LibraryElement library = selector.library; - MemberSet result = new MemberSet(name); - Element element = cls.implementation.lookupSelector(selector); - if (element != null) result.add(element); - - bool isPrivate = name.isPrivate(); - Set<ClassElement> subtypesOfCls = subtypes[cls]; - if (subtypesOfCls != null) { - for (ClassElement sub in subtypesOfCls) { - // Private members from a different library are not visible. - if (isPrivate && sub.getLibrary() != library) continue; - element = sub.implementation.lookupLocalMember(name); - if (element != null) result.add(element); - } - } - return result; - } - - /** - * Returns the field in [type] described by the given [selector]. - * If no such field exists, or a subclass overrides the field - * returns [:null:]. - */ - VariableElement locateSingleField(DartType type, Selector selector) { - MemberSet memberSet = _memberSetFor(type, selector); - ClassElement cls = type.element; - Element result = cls.implementation.lookupSelector(selector); - if (result == null) return null; - if (!result.isField()) return null; - - // Verify that no subclass overrides the field. - if (memberSet.elements.length != 1) return null; - assert(memberSet.elements.contains(result)); - return result; - } - - Set<ClassElement> findNoSuchMethodHolders(DartType type) { - Set<ClassElement> result = new Set<ClassElement>(); - Selector noSuchMethodSelector = new Selector.noSuchMethod(); - MemberSet memberSet = _memberSetFor(type, noSuchMethodSelector); - for (Element element in memberSet.elements) { - ClassElement holder = element.getEnclosingClass(); - if (!identical(holder, compiler.objectClass) && - noSuchMethodSelector.applies(element, compiler)) { - result.add(holder); - } - } - return result; - } -} - -/** - * A [MemberSet] contains all the possible targets for a selector. - */ -class MemberSet { - final Set<Element> elements; - final SourceString name; - - MemberSet(SourceString this.name) : elements = new Set<Element>(); - - void add(Element element) { - elements.add(element); - } - - bool get isEmpty => elements.isEmpty; -}
diff --git a/pkgs/markdown/test/lib/src/libraries.dart b/pkgs/markdown/test/lib/src/libraries.dart deleted file mode 100644 index 5c35483..0000000 --- a/pkgs/markdown/test/lib/src/libraries.dart +++ /dev/null
@@ -1,200 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library libraries; - -/** - * A bit flag used by [LibraryInfo] indicating that a library is used by dart2js - */ -const int DART2JS_PLATFORM = 1; - -/** - * A bit flag used by [LibraryInfo] indicating that a library is used by the VM - */ -const int VM_PLATFORM = 2; - -/** - * Mapping of "dart:" library name (e.g. "core") to information about that library. - * This information is structured such that Dart Editor can parse this file - * and extract the necessary information without executing it - * while other tools can access via execution. - */ -const Map<String, LibraryInfo> LIBRARIES = const { - - "async": const LibraryInfo( - "async/async.dart", - dart2jsPatchPath: "_internal/compiler/implementation/lib/async_patch.dart"), - - "chrome": const LibraryInfo( - "chrome/dartium/chrome_dartium.dart", - category: "Client", - dart2jsPath: "chrome/dart2js/chrome_dart2js.dart", - documented: false, - implementation: true), // Not really, just hiding it for now. - - "collection": const LibraryInfo("collection/collection.dart"), - - "core": const LibraryInfo( - "core/core.dart", - dart2jsPatchPath: "_internal/compiler/implementation/lib/core_patch.dart"), - - "crypto": const LibraryInfo( - "crypto/crypto.dart"), - - "html": const LibraryInfo( - "html/dartium/html_dartium.dart", - category: "Client", - dart2jsPath: "html/dart2js/html_dart2js.dart"), - - "html_common": const LibraryInfo( - "html/html_common/html_common.dart", - category: "Client", - dart2jsPath: "html/html_common/html_common_dart2js.dart", - documented: false, - implementation: true), - - "indexed_db": const LibraryInfo( - "indexed_db/dartium/indexed_db_dartium.dart", - category: "Client", - dart2jsPath: "indexed_db/dart2js/indexed_db_dart2js.dart"), - - "io": const LibraryInfo( - "io/io.dart", - category: "Server", - dart2jsPatchPath: "_internal/compiler/implementation/lib/io_patch.dart"), - - "isolate": const LibraryInfo( - "isolate/isolate.dart", - dart2jsPatchPath: "_internal/compiler/implementation/lib/isolate_patch.dart"), - - "json": const LibraryInfo( - "json/json.dart"), - - "math": const LibraryInfo( - "math/math.dart", - dart2jsPatchPath: "_internal/compiler/implementation/lib/math_patch.dart"), - - "mirrors": const LibraryInfo( - "mirrors/mirrors.dart", - dart2jsPatchPath: "_internal/compiler/implementation/lib/mirrors_patch.dart"), - - "nativewrappers": const LibraryInfo( - "html/dartium/nativewrappers.dart", - category: "Client", - implementation: true, - documented: false, - platforms: VM_PLATFORM), - - "scalarlist": const LibraryInfo( - "scalarlist/scalarlist.dart", - category: "Server", - dart2jsPatchPath: "_internal/compiler/implementation/lib/scalarlist_patch.dart"), - - "svg": const LibraryInfo( - "svg/dartium/svg_dartium.dart", - category: "Client", - dart2jsPath: "svg/dart2js/svg_dart2js.dart"), - - "uri": const LibraryInfo( - "uri/uri.dart"), - - "utf": const LibraryInfo( - "utf/utf.dart"), - - "web_audio": const LibraryInfo( - "web_audio/dartium/web_audio_dartium.dart", - category: "Client", - dart2jsPath: "web_audio/dart2js/web_audio_dart2js.dart"), - - "_collection-dev": const LibraryInfo( - "_collection_dev/collection_dev.dart", - category: "Internal", - documented: false), - - "_js_helper": const LibraryInfo( - "_internal/compiler/implementation/lib/js_helper.dart", - category: "Internal", - documented: false, - platforms: DART2JS_PLATFORM), - - "_interceptors": const LibraryInfo( - "_internal/compiler/implementation/lib/interceptors.dart", - category: "Internal", - documented: false, - platforms: DART2JS_PLATFORM), - - "_foreign_helper": const LibraryInfo( - "_internal/compiler/implementation/lib/foreign_helper.dart", - category: "Internal", - documented: false, - platforms: DART2JS_PLATFORM), - - "_isolate_helper": const LibraryInfo( - "_internal/compiler/implementation/lib/isolate_helper.dart", - category: "Internal", - documented: false, - platforms: DART2JS_PLATFORM), -}; - -/** - * Information about a "dart:" library. - */ -class LibraryInfo { - - /** - * Path to the library's *.dart file relative to this file. - */ - final String path; - - /** - * The category in which the library should appear in the editor - * (e.g. "Common", "Client", "Server", ...). - */ - final String category; - - /** - * Path to the dart2js library's *.dart file relative to this file - * or null if dart2js uses the common library path defined above. - * Access using the [#getDart2JsPath()] method. - */ - final String dart2jsPath; - - /** - * Path to the dart2js library's patch file relative to this file - * or null if no dart2js patch file associated with this library. - * Access using the [#getDart2JsPatchPath()] method. - */ - final String dart2jsPatchPath; - - /** - * True if this library is documented and should be shown to the user. - */ - final bool documented; - - /** - * Bit flags indicating which platforms consume this library. - * See [DART2JS_LIBRARY] and [VM_LIBRARY]. - */ - final int platforms; - - /** - * True if the library contains implementation details for another library. - * The implication is that these libraries are less commonly used - * and that tools like Dart Editor should not show these libraries - * in a list of all libraries unless the user specifically asks the tool to - * do so. - */ - final bool implementation; - - const LibraryInfo(this.path, { - this.category: "Shared", - this.dart2jsPath, - this.dart2jsPatchPath, - this.implementation: false, - this.documented: true, - this.platforms: DART2JS_PLATFORM | VM_PLATFORM}); - - bool get isDart2jsLibrary => (platforms & DART2JS_PLATFORM) != 0; - bool get isVmLibrary => (platforms & VM_PLATFORM) != 0; -}
diff --git a/pkgs/markdown/test/lib/src/markdown/ast.dart b/pkgs/markdown/test/lib/src/markdown/ast.dart deleted file mode 100644 index c966cea..0000000 --- a/pkgs/markdown/test/lib/src/markdown/ast.dart +++ /dev/null
@@ -1,65 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of markdown; - -/// Base class for any AST item. Roughly corresponds to Node in the DOM. Will -/// be either an Element or Text. -abstract class Node { - void accept(NodeVisitor visitor); -} - -/// A named tag that can contain other nodes. -class Element implements Node { - final String tag; - final List<Node> children; - final Map<String, String> attributes; - - Element(this.tag, this.children) - : attributes = <String, String>{}; - - Element.empty(this.tag) - : children = null, - attributes = <String, String>{}; - - Element.withTag(this.tag) - : children = [], - attributes = <String, String>{}; - - Element.text(this.tag, String text) - : children = [new Text(text)], - attributes = <String, String>{}; - - bool get isEmpty => children == null; - - void accept(NodeVisitor visitor) { - if (visitor.visitElementBefore(this)) { - for (final child in children) child.accept(visitor); - visitor.visitElementAfter(this); - } - } -} - -/// A plain text element. -class Text implements Node { - final String text; - Text(this.text); - - void accept(NodeVisitor visitor) => visitor.visitText(this); -} - -/// Visitor pattern for the AST. Renderers or other AST transformers should -/// implement this. -abstract class NodeVisitor { - /// Called when a Text node has been reached. - void visitText(Text text); - - /// Called when an Element has been reached, before its children have been - /// visited. Return `false` to skip its children. - bool visitElementBefore(Element element); - - /// Called when an Element has been reached, after its children have been - /// visited. Will not be called if [visitElementBefore] returns `false`. - void visitElementAfter(Element element); -}
diff --git a/pkgs/markdown/test/lib/src/markdown/block_parser.dart b/pkgs/markdown/test/lib/src/markdown/block_parser.dart deleted file mode 100644 index 67109a4..0000000 --- a/pkgs/markdown/test/lib/src/markdown/block_parser.dart +++ /dev/null
@@ -1,464 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of markdown; - -/// The line contains only whitespace or is empty. -final _RE_EMPTY = new RegExp(r'^([ \t]*)$'); - -/// A series of `=` or `-` (on the next line) define setext-style headers. -final _RE_SETEXT = new RegExp(r'^((=+)|(-+))$'); - -/// Leading (and trailing) `#` define atx-style headers. -final _RE_HEADER = new RegExp(r'^(#{1,6})(.*?)#*$'); - -/// The line starts with `>` with one optional space after. -final _RE_BLOCKQUOTE = new RegExp(r'^[ ]{0,3}>[ ]?(.*)$'); - -/// A line indented four spaces. Used for code blocks and lists. -final _RE_INDENT = new RegExp(r'^(?: |\t)(.*)$'); - -/// Three or more hyphens, asterisks or underscores by themselves. Note that -/// a line like `----` is valid as both HR and SETEXT. In case of a tie, -/// SETEXT should win. -final _RE_HR = new RegExp(r'^[ ]{0,3}((-+[ ]{0,2}){3,}|' - r'(_+[ ]{0,2}){3,}|' - r'(\*+[ ]{0,2}){3,})$'); - -/// Really hacky way to detect block-level embedded HTML. Just looks for -/// "<somename". -final _RE_HTML = new RegExp(r'^<[ ]*\w+[ >]'); - -/// A line starting with one of these markers: `-`, `*`, `+`. May have up to -/// three leading spaces before the marker and any number of spaces or tabs -/// after. -final _RE_UL = new RegExp(r'^[ ]{0,3}[*+-][ \t]+(.*)$'); - -/// A line starting with a number like `123.`. May have up to three leading -/// spaces before the marker and any number of spaces or tabs after. -final _RE_OL = new RegExp(r'^[ ]{0,3}\d+\.[ \t]+(.*)$'); - -/// Maintains the internal state needed to parse a series of lines into blocks -/// of markdown suitable for further inline parsing. -class BlockParser { - final List<String> lines; - - /// The markdown document this parser is parsing. - final Document document; - - /// Index of the current line. - int pos; - - BlockParser(this.lines, this.document) - : pos = 0; - - /// Gets the current line. - String get current => lines[pos]; - - /// Gets the line after the current one or `null` if there is none. - String get next { - // Don't read past the end. - if (pos >= lines.length - 1) return null; - return lines[pos + 1]; - } - - void advance() { - pos++; - } - - bool get isDone => pos >= lines.length; - - /// Gets whether or not the current line matches the given pattern. - bool matches(RegExp regex) { - if (isDone) return false; - return regex.firstMatch(current) != null; - } - - /// Gets whether or not the current line matches the given pattern. - bool matchesNext(RegExp regex) { - if (next == null) return false; - return regex.firstMatch(next) != null; - } -} - -abstract class BlockSyntax { - /// Gets the collection of built-in block parsers. To turn a series of lines - /// into blocks, each of these will be tried in turn. Order matters here. - static List<BlockSyntax> get syntaxes { - // Lazy initialize. - if (_syntaxes == null) { - _syntaxes = [ - new EmptyBlockSyntax(), - new BlockHtmlSyntax(), - new SetextHeaderSyntax(), - new HeaderSyntax(), - new CodeBlockSyntax(), - new BlockquoteSyntax(), - new HorizontalRuleSyntax(), - new UnorderedListSyntax(), - new OrderedListSyntax(), - new ParagraphSyntax() - ]; - } - - return _syntaxes; - } - - static List<BlockSyntax> _syntaxes; - - /// Gets the regex used to identify the beginning of this block, if any. - RegExp get pattern => null; - - bool get canEndBlock => true; - - bool canParse(BlockParser parser) { - return pattern.firstMatch(parser.current) != null; - } - - Node parse(BlockParser parser); - - List<String> parseChildLines(BlockParser parser) { - // Grab all of the lines that form the blockquote, stripping off the ">". - final childLines = <String>[]; - - while (!parser.isDone) { - final match = pattern.firstMatch(parser.current); - if (match == null) break; - childLines.add(match[1]); - parser.advance(); - } - - return childLines; - } - - /// Gets whether or not [parser]'s current line should end the previous block. - static bool isAtBlockEnd(BlockParser parser) { - if (parser.isDone) return true; - return syntaxes.any((s) => s.canParse(parser) && s.canEndBlock); - } -} - -class EmptyBlockSyntax extends BlockSyntax { - RegExp get pattern => _RE_EMPTY; - - Node parse(BlockParser parser) { - parser.advance(); - - // Don't actually emit anything. - return null; - } -} - -/// Parses setext-style headers. -class SetextHeaderSyntax extends BlockSyntax { - bool canParse(BlockParser parser) { - // Note: matches *next* line, not the current one. We're looking for the - // underlining after this line. - return parser.matchesNext(_RE_SETEXT); - } - - Node parse(BlockParser parser) { - final match = _RE_SETEXT.firstMatch(parser.next); - - final tag = (match[1][0] == '=') ? 'h1' : 'h2'; - final contents = parser.document.parseInline(parser.current); - parser.advance(); - parser.advance(); - - return new Element(tag, contents); - } -} - -/// Parses atx-style headers: `## Header ##`. -class HeaderSyntax extends BlockSyntax { - RegExp get pattern => _RE_HEADER; - - Node parse(BlockParser parser) { - final match = pattern.firstMatch(parser.current); - parser.advance(); - final level = match[1].length; - final contents = parser.document.parseInline(match[2].trim()); - return new Element('h$level', contents); - } -} - -/// Parses email-style blockquotes: `> quote`. -class BlockquoteSyntax extends BlockSyntax { - RegExp get pattern => _RE_BLOCKQUOTE; - - Node parse(BlockParser parser) { - final childLines = parseChildLines(parser); - - // Recursively parse the contents of the blockquote. - final children = parser.document.parseLines(childLines); - - return new Element('blockquote', children); - } -} - -/// Parses preformatted code blocks that are indented four spaces. -class CodeBlockSyntax extends BlockSyntax { - RegExp get pattern => _RE_INDENT; - - List<String> parseChildLines(BlockParser parser) { - final childLines = <String>[]; - - while (!parser.isDone) { - var match = pattern.firstMatch(parser.current); - if (match != null) { - childLines.add(match[1]); - parser.advance(); - } else { - // If there's a codeblock, then a newline, then a codeblock, keep the - // code blocks together. - var nextMatch = parser.next != null ? - pattern.firstMatch(parser.next) : null; - if (parser.current.trim() == '' && nextMatch != null) { - childLines.add(''); - childLines.add(nextMatch[1]); - parser.advance(); - parser.advance(); - } else { - break; - } - } - } - return childLines; - } - - Node parse(BlockParser parser) { - final childLines = parseChildLines(parser); - - // The Markdown tests expect a trailing newline. - childLines.add(''); - - // Escape the code. - final escaped = classifySource(Strings.join(childLines, '\n')); - - return new Element.text('pre', escaped); - } -} - -/// Parses horizontal rules like `---`, `_ _ _`, `* * *`, etc. -class HorizontalRuleSyntax extends BlockSyntax { - RegExp get pattern => _RE_HR; - - Node parse(BlockParser parser) { - final match = pattern.firstMatch(parser.current); - parser.advance(); - return new Element.empty('hr'); - } -} - -/// Parses inline HTML at the block level. This differs from other markdown -/// implementations in several ways: -/// -/// 1. This one is way way WAY simpler. -/// 2. All HTML tags at the block level will be treated as blocks. If you -/// start a paragraph with `<em>`, it will not wrap it in a `<p>` for you. -/// As soon as it sees something like HTML, it stops mucking with it until -/// it hits the next block. -/// 3. Absolutely no HTML parsing or validation is done. We're a markdown -/// parser not an HTML parser! -class BlockHtmlSyntax extends BlockSyntax { - RegExp get pattern => _RE_HTML; - - bool get canEndBlock => false; - - Node parse(BlockParser parser) { - final childLines = []; - - // Eat until we hit a blank line. - while (!parser.isDone && !parser.matches(_RE_EMPTY)) { - childLines.add(parser.current); - parser.advance(); - } - - return new Text(Strings.join(childLines, '\n')); - } -} - -class ListItem { - bool forceBlock = false; - final List<String> lines; - - ListItem(this.lines); -} - -/// Base class for both ordered and unordered lists. -abstract class ListSyntax extends BlockSyntax { - bool get canEndBlock => false; - - String get listTag; - - Node parse(BlockParser parser) { - final items = <ListItem>[]; - var childLines = <String>[]; - - endItem() { - if (childLines.length > 0) { - items.add(new ListItem(childLines)); - childLines = <String>[]; - } - } - - var match; - tryMatch(RegExp pattern) { - match = pattern.firstMatch(parser.current); - return match != null; - } - - bool afterEmpty = false; - while (!parser.isDone) { - if (tryMatch(_RE_EMPTY)) { - // Add a blank line to the current list item. - childLines.add(''); - } else if (tryMatch(_RE_UL) || tryMatch(_RE_OL)) { - // End the current list item and start a new one. - endItem(); - childLines.add(match[1]); - } else if (tryMatch(_RE_INDENT)) { - // Strip off indent and add to current item. - childLines.add(match[1]); - } else if (BlockSyntax.isAtBlockEnd(parser)) { - // Done with the list. - break; - } else { - // Anything else is paragraph text or other stuff that can be in a list - // item. However, if the previous item is a blank line, this means we're - // done with the list and are starting a new top-level paragraph. - if ((childLines.length > 0) && (childLines.last == '')) break; - childLines.add(parser.current); - } - parser.advance(); - } - - endItem(); - - // Markdown, because it hates us, specifies two kinds of list items. If you - // have a list like: - // - // * one - // * two - // - // Then it will insert the conents of the lines directly in the <li>, like: - // <ul> - // <li>one</li> - // <li>two</li> - // <ul> - // - // If, however, there are blank lines between the items, each is wrapped in - // paragraphs: - // - // * one - // - // * two - // - // <ul> - // <li><p>one</p></li> - // <li><p>two</p></li> - // <ul> - // - // In other words, sometimes we parse the contents of a list item like a - // block, and sometimes line an inline. The rules our parser implements are: - // - // - If it has more than one line, it's a block. - // - If the line matches any block parser (BLOCKQUOTE, HEADER, HR, INDENT, - // UL, OL) it's a block. (This is for cases like "* > quote".) - // - If there was a blank line between this item and the previous one, it's - // a block. - // - If there was a blank line between this item and the next one, it's a - // block. - // - Otherwise, parse it as an inline. - - // Remove any trailing empty lines and note which items are separated by - // empty lines. Do this before seeing which items are single-line so that - // trailing empty lines on the last item don't force it into being a block. - for (int i = 0; i < items.length; i++) { - for (int j = items[i].lines.length - 1; j > 0; j--) { - if (_RE_EMPTY.firstMatch(items[i].lines[j]) != null) { - // Found an empty line. Item and one after it are blocks. - if (i < items.length - 1) { - items[i].forceBlock = true; - items[i + 1].forceBlock = true; - } - items[i].lines.removeLast(); - } else { - break; - } - } - } - - // Convert the list items to Nodes. - final itemNodes = <Node>[]; - for (final item in items) { - bool blockItem = item.forceBlock || (item.lines.length > 1); - - // See if it matches some block parser. - final blocksInList = [ - _RE_BLOCKQUOTE, - _RE_HEADER, - _RE_HR, - _RE_INDENT, - _RE_UL, - _RE_OL - ]; - - if (!blockItem) { - for (final pattern in blocksInList) { - if (pattern.firstMatch(item.lines[0]) != null) { - blockItem = true; - break; - } - } - } - - // Parse the item as a block or inline. - if (blockItem) { - // Block list item. - final children = parser.document.parseLines(item.lines); - itemNodes.add(new Element('li', children)); - } else { - // Raw list item. - final contents = parser.document.parseInline(item.lines[0]); - itemNodes.add(new Element('li', contents)); - } - } - - return new Element(listTag, itemNodes); - } -} - -/// Parses unordered lists. -class UnorderedListSyntax extends ListSyntax { - RegExp get pattern => _RE_UL; - String get listTag => 'ul'; -} - -/// Parses ordered lists. -class OrderedListSyntax extends ListSyntax { - RegExp get pattern => _RE_OL; - String get listTag => 'ol'; -} - -/// Parses paragraphs of regular text. -class ParagraphSyntax extends BlockSyntax { - bool get canEndBlock => false; - - bool canParse(BlockParser parser) => true; - - Node parse(BlockParser parser) { - final childLines = []; - - // Eat until we hit something that ends a paragraph. - while (!BlockSyntax.isAtBlockEnd(parser)) { - childLines.add(parser.current); - parser.advance(); - } - - final contents = parser.document.parseInline( - Strings.join(childLines, '\n')); - return new Element('p', contents); - } -}
diff --git a/pkgs/markdown/test/lib/src/markdown/html_renderer.dart b/pkgs/markdown/test/lib/src/markdown/html_renderer.dart deleted file mode 100644 index 1695e96..0000000 --- a/pkgs/markdown/test/lib/src/markdown/html_renderer.dart +++ /dev/null
@@ -1,61 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of markdown; - -String renderToHtml(List<Node> nodes) => new HtmlRenderer().render(nodes); - -/// Translates a parsed AST to HTML. -class HtmlRenderer implements NodeVisitor { - static final _BLOCK_TAGS = new RegExp( - 'blockquote|h1|h2|h3|h4|h5|h6|hr|p|pre'); - - StringBuffer buffer; - - HtmlRenderer(); - - String render(List<Node> nodes) { - buffer = new StringBuffer(); - - for (final node in nodes) node.accept(this); - - return buffer.toString(); - } - - void visitText(Text text) { - buffer.add(text.text); - } - - bool visitElementBefore(Element element) { - // Hackish. Separate block-level elements with newlines. - if (!buffer.isEmpty && - _BLOCK_TAGS.firstMatch(element.tag) != null) { - buffer.add('\n'); - } - - buffer.add('<${element.tag}'); - - // Sort the keys so that we generate stable output. - // TODO(rnystrom): This assumes keys returns a fresh mutable - // collection. - final attributeNames = element.attributes.keys.toList(); - attributeNames.sort((a, b) => a.compareTo(b)); - for (final name in attributeNames) { - buffer.add(' $name="${element.attributes[name]}"'); - } - - if (element.isEmpty) { - // Empty element like <hr/>. - buffer.add(' />'); - return false; - } else { - buffer.add('>'); - return true; - } - } - - void visitElementAfter(Element element) { - buffer.add('</${element.tag}>'); - } -}
diff --git a/pkgs/markdown/test/lib/src/markdown/inline_parser.dart b/pkgs/markdown/test/lib/src/markdown/inline_parser.dart deleted file mode 100644 index af42e3e..0000000 --- a/pkgs/markdown/test/lib/src/markdown/inline_parser.dart +++ /dev/null
@@ -1,410 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of markdown; - -/// Maintains the internal state needed to parse inline span elements in -/// markdown. -class InlineParser { - static List<InlineSyntax> get syntaxes { - // Lazy initialize. - if (_syntaxes == null) { - _syntaxes = <InlineSyntax>[ - // This first regexp matches plain text to accelerate parsing. It must - // be written so that it does not match any prefix of any following - // syntax. Most markdown is plain text, so it is faster to match one - // regexp per 'word' rather than fail to match all the following regexps - // at each non-syntax character position. It is much more important - // that the regexp is fast than complete (for example, adding grouping - // is likely to slow the regexp down enough to negate its benefit). - // Since it is purely for optimization, it can be removed for debugging. - new TextSyntax(r'\s*[A-Za-z0-9]+'), - - // The real syntaxes. - - new AutolinkSyntax(), - new LinkSyntax(), - // "*" surrounded by spaces is left alone. - new TextSyntax(r' \* '), - // "_" surrounded by spaces is left alone. - new TextSyntax(r' _ '), - // Leave already-encoded HTML entities alone. Ensures we don't turn - // "&" into "&amp;" - new TextSyntax(r'&[#a-zA-Z0-9]*;'), - // Encode "&". - new TextSyntax(r'&', sub: '&'), - // Encode "<". (Why not encode ">" too? Gruber is toying with us.) - new TextSyntax(r'<', sub: '<'), - // Parse "**strong**" tags. - new TagSyntax(r'\*\*', tag: 'strong'), - // Parse "__strong__" tags. - new TagSyntax(r'__', tag: 'strong'), - // Parse "*emphasis*" tags. - new TagSyntax(r'\*', tag: 'em'), - // Parse "_emphasis_" tags. - // TODO(rnystrom): Underscores in the middle of a word should not be - // parsed as emphasis like_in_this. - new TagSyntax(r'_', tag: 'em'), - // Parse inline code within double backticks: "``code``". - new CodeSyntax(r'``\s?((?:.|\n)*?)\s?``'), - // Parse inline code within backticks: "`code`". - new CodeSyntax(r'`([^`]*)`') - ]; - } - - return _syntaxes; - } - - static List<InlineSyntax> _syntaxes; - - /// The string of markdown being parsed. - final String source; - - /// The markdown document this parser is parsing. - final Document document; - - /// The current read position. - int pos = 0; - - /// Starting position of the last unconsumed text. - int start = 0; - - final List<TagState> _stack; - - InlineParser(this.source, this.document) - : _stack = <TagState>[]; - - List<Node> parse() { - // Make a fake top tag to hold the results. - _stack.add(new TagState(0, 0, null)); - - while (!isDone) { - bool matched = false; - - // See if any of the current tags on the stack match. We don't allow tags - // of the same kind to nest, so this takes priority over other possible // matches. - for (int i = _stack.length - 1; i > 0; i--) { - if (_stack[i].tryMatch(this)) { - matched = true; - break; - } - } - if (matched) continue; - - // See if the current text matches any defined markdown syntax. - for (final syntax in syntaxes) { - if (syntax.tryMatch(this)) { - matched = true; - break; - } - } - if (matched) continue; - - // If we got here, it's just text. - advanceBy(1); - } - - // Unwind any unmatched tags and get the results. - return _stack[0].close(this, null); - } - - writeText() { - writeTextRange(start, pos); - start = pos; - } - - writeTextRange(int start, int end) { - if (end > start) { - final text = source.substring(start, end); - final nodes = _stack.last.children; - - // If the previous node is text too, just append. - if ((nodes.length > 0) && (nodes.last is Text)) { - final newNode = new Text('${nodes.last.text}$text'); - nodes[nodes.length - 1] = newNode; - } else { - nodes.add(new Text(text)); - } - } - } - - addNode(Node node) { - _stack.last.children.add(node); - } - - // TODO(rnystrom): Only need this because RegExp doesn't let you start - // searching from a given offset. - String get currentSource => source.substring(pos, source.length); - - bool get isDone => pos == source.length; - - void advanceBy(int length) { - pos += length; - } - - void consume(int length) { - pos += length; - start = pos; - } -} - -/// Represents one kind of markdown tag that can be parsed. -abstract class InlineSyntax { - final RegExp pattern; - - InlineSyntax(String pattern) - : pattern = new RegExp(pattern, multiLine: true); - - bool tryMatch(InlineParser parser) { - final startMatch = pattern.firstMatch(parser.currentSource); - if ((startMatch != null) && (startMatch.start == 0)) { - // Write any existing plain text up to this point. - parser.writeText(); - - if (onMatch(parser, startMatch)) { - parser.consume(startMatch[0].length); - } - return true; - } - return false; - } - - bool onMatch(InlineParser parser, Match match); -} - -/// Matches stuff that should just be passed through as straight text. -class TextSyntax extends InlineSyntax { - String substitute; - TextSyntax(String pattern, {String sub}) - : super(pattern), - substitute = sub; - - bool onMatch(InlineParser parser, Match match) { - if (substitute == null) { - // Just use the original matched text. - parser.advanceBy(match[0].length); - return false; - } - - // Insert the substitution. - parser.addNode(new Text(substitute)); - return true; - } -} - -/// Matches autolinks like `<http://foo.com>`. -class AutolinkSyntax extends InlineSyntax { - AutolinkSyntax() - : super(r'<((http|https|ftp)://[^>]*)>'); - // TODO(rnystrom): Make case insensitive. - - bool onMatch(InlineParser parser, Match match) { - final url = match[1]; - - final anchor = new Element.text('a', escapeHtml(url)); - anchor.attributes['href'] = url; - parser.addNode(anchor); - - return true; - } -} - -/// Matches syntax that has a pair of tags and becomes an element, like `*` for -/// `<em>`. Allows nested tags. -class TagSyntax extends InlineSyntax { - final RegExp endPattern; - final String tag; - - TagSyntax(String pattern, {String tag, String end}) - : super(pattern), - endPattern = new RegExp((end != null) ? end : pattern, multiLine: true), - tag = tag; - // TODO(rnystrom): Doing this.field doesn't seem to work with named args. - - bool onMatch(InlineParser parser, Match match) { - parser._stack.add(new TagState(parser.pos, - parser.pos + match[0].length, this)); - return true; - } - - bool onMatchEnd(InlineParser parser, Match match, TagState state) { - parser.addNode(new Element(tag, state.children)); - return true; - } -} - -/// Matches inline links like `[blah] [id]` and `[blah] (url)`. -class LinkSyntax extends TagSyntax { - /// The regex for the end of a link needs to handle both reference style and - /// inline styles as well as optional titles for inline links. To make that - /// a bit more palatable, this breaks it into pieces. - static get linkPattern { - final refLink = r'\s?\[([^\]]*)\]'; // "[id]" reflink id. - final title = r'(?:[ ]*"([^"]+)"|)'; // Optional title in quotes. - final inlineLink = '\\s?\\(([^ )]+)$title\\)'; // "(url "title")" link. - return '\](?:($refLink|$inlineLink)|)'; - - // The groups matched by this are: - // 1: Will be non-empty if it's either a ref or inline link. Will be empty - // if it's just a bare pair of square brackets with nothing after them. - // 2: Contains the id inside [] for a reference-style link. - // 3: Contains the URL for an inline link. - // 4: Contains the title, if present, for an inline link. - } - - LinkSyntax() - : super(r'\[', end: linkPattern); - - bool onMatchEnd(InlineParser parser, Match match, TagState state) { - var url; - var title; - - // If we didn't match refLink or inlineLink, then it means there was - // nothing after the first square bracket, so it isn't a normal markdown - // link at all. Instead, we allow users of the library to specify a special - // resolver function ([setImplicitLinkResolver]) that may choose to handle - // this. Otherwise, it's just treated as plain text. - if ((match[1] == null) || (match[1] == '')) { - if (_implicitLinkResolver == null) return false; - - // Only allow implicit links if the content is just text. - // TODO(rnystrom): Do we want to relax this? - if (state.children.length != 1) return false; - if (state.children[0] is! Text) return false; - - Text link = state.children[0]; - - // See if we have a resolver that will generate a link for us. - final node = _implicitLinkResolver(link.text); - if (node == null) return false; - - parser.addNode(node); - return true; - } - - if ((match[3] != null) && (match[3] != '')) { - // Inline link like [foo](url). - url = match[3]; - title = match[4]; - - // For whatever reason, markdown allows angle-bracketed URLs here. - if (url.startsWith('<') && url.endsWith('>')) { - url = url.substring(1, url.length - 1); - } - } else { - // Reference link like [foo] [bar]. - var id = match[2]; - if (id == '') { - // The id is empty ("[]") so infer it from the contents. - id = parser.source.substring(state.startPos + 1, parser.pos); - } - - // References are case-insensitive. - id = id.toLowerCase(); - - // Look up the link. - final link = parser.document.refLinks[id]; - // If it's an unknown link just emit plaintext. - if (link == null) return false; - - url = link.url; - title = link.title; - } - - final anchor = new Element('a', state.children); - anchor.attributes['href'] = escapeHtml(url); - if ((title != null) && (title != '')) { - anchor.attributes['title'] = escapeHtml(title); - } - - parser.addNode(anchor); - return true; - } -} - -/// Matches backtick-enclosed inline code blocks. -class CodeSyntax extends InlineSyntax { - CodeSyntax(String pattern) - : super(pattern); - - bool onMatch(InlineParser parser, Match match) { - parser.addNode(new Element.text('code', escapeHtml(match[1]))); - return true; - } -} - -/// Keeps track of a currently open tag while it is being parsed. The parser -/// maintains a stack of these so it can handle nested tags. -class TagState { - /// The point in the original source where this tag started. - int startPos; - - /// The point in the original source where open tag ended. - int endPos; - - /// The syntax that created this node. - final TagSyntax syntax; - - /// The children of this node. Will be `null` for text nodes. - final List<Node> children; - - TagState(this.startPos, this.endPos, this.syntax) - : children = <Node>[]; - - /// Attempts to close this tag by matching the current text against its end - /// pattern. - bool tryMatch(InlineParser parser) { - Match endMatch = syntax.endPattern.firstMatch(parser.currentSource); - if ((endMatch != null) && (endMatch.start == 0)) { - // Close the tag. - close(parser, endMatch); - return true; - } - - return false; - } - - /// Pops this tag off the stack, completes it, and adds it to the output. - /// Will discard any unmatched tags that happen to be above it on the stack. - /// If this is the last node in the stack, returns its children. - List<Node> close(InlineParser parser, Match endMatch) { - // If there are unclosed tags on top of this one when it's closed, that - // means they are mismatched. Mismatched tags are treated as plain text in - // markdown. So for each tag above this one, we write its start tag as text - // and then adds its children to this one's children. - int index = parser._stack.indexOf(this); - - // Remove the unmatched children. - final unmatchedTags = parser._stack.getRange(index + 1, - parser._stack.length - index - 1); - parser._stack.removeRange(index + 1, parser._stack.length - index - 1); - - // Flatten them out onto this tag. - for (final unmatched in unmatchedTags) { - // Write the start tag as text. - parser.writeTextRange(unmatched.startPos, unmatched.endPos); - - // Bequeath its children unto this tag. - children.addAll(unmatched.children); - } - - // Pop this off the stack. - parser.writeText(); - parser._stack.removeLast(); - - // If the stack is empty now, this is the special "results" node. - if (parser._stack.length == 0) return children; - - // We are still parsing, so add this to its parent's children. - if (syntax.onMatchEnd(parser, endMatch, this)) { - parser.consume(endMatch[0].length); - } else { - // Didn't close correctly so revert to text. - parser.start = startPos; - parser.advanceBy(endMatch[0].length); - } - - return null; - } -}
diff --git a/pkgs/markdown/test/pubspec.yaml b/pkgs/markdown/test/pubspec.yaml deleted file mode 100644 index f45db3a..0000000 --- a/pkgs/markdown/test/pubspec.yaml +++ /dev/null
@@ -1,7 +0,0 @@ -name: markdown -author: "Dart Team <misc@dartlang.org>" -# homepage: https://github.com/dart-lang/csslib -description: A library for converting markdown to HTML. -version: 0.3.4 -dependencies: - unittest: any \ No newline at end of file