| // Copyright (c) 2014, 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.sexpr_test; |
| |
| import 'dart:async'; |
| |
| import 'package:async_helper/async_helper.dart'; |
| import 'package:compiler/src/compiler.dart'; |
| import 'package:compiler/src/cps_ir/cps_ir_nodes.dart'; |
| import 'package:compiler/src/cps_ir/cps_ir_nodes_sexpr.dart'; |
| import 'package:expect/expect.dart'; |
| |
| import '../compiler_helper.dart' hide compilerFor; |
| import 'sexpr_unstringifier.dart'; |
| import 'test_helper.dart'; |
| |
| const String CODE = """ |
| class Foo { |
| static int x = 1; |
| foo() => 42; |
| } |
| |
| class Bar extends Foo { |
| int y = 2; |
| Bar() { |
| Foo.x = 2; |
| } |
| foo() => this.y + super.foo(); |
| } |
| |
| class FooBar<T> { |
| bool foobar() => T is int; |
| } |
| |
| main() { |
| Foo foo; |
| if (foo is Foo) { |
| print("Surprise"); |
| } |
| |
| String inner() => "Inner function"; |
| print(inner()); |
| |
| int j = 42; |
| for (int i = 0; i < 2; i++) { |
| print(i.toString()); |
| } |
| |
| print(Foo.x); |
| |
| String recursive(int h) { |
| if (h < 1) { |
| return j.toString(); |
| } |
| j++; |
| return "h\$\{recursive(h - 1)\}"; |
| } |
| print(recursive(5)); |
| |
| Bar bar = new Bar(); |
| print(bar.foo().toString()); |
| |
| bar = foo as Bar; |
| if (bar == null) { |
| var list = [1, 2, 3, 4]; |
| var map = { 1: "one" |
| , 2: "two" |
| , 3: "three" |
| }; |
| var double = 3.14; |
| list.forEach((i) => print(i.toString())); |
| print("\$list \$map \$double"); |
| } |
| |
| print(new FooBar<int>().foobar()); |
| } |
| |
| """; |
| |
| bool shouldOutput(Element element) { |
| return (!element.library.isPlatformLibrary && |
| !element.isSynthesized && |
| element.kind == ElementKind.FUNCTION); |
| } |
| |
| /// Compiles the given dart code (which must include a 'main' function) and |
| /// returns a list of all generated CPS IR definitions. |
| Future<List<FunctionDefinition>> compile(String code) { |
| return compilerFor(code).then((Compiler compiler) { |
| return compiler.enqueuer.resolution.resolvedElements |
| .where(shouldOutput) |
| .map(compiler.irBuilder.getIr) |
| .toList(); |
| }); |
| } |
| |
| /// Returns an S-expression string for each compiled function. |
| List<String> stringifyAll(Iterable<FunctionDefinition> functions) { |
| final stringifier = new SExpressionStringifier(); |
| return functions.map((f) => stringifier.visitFunctionDefinition(f)).toList(); |
| } |
| |
| Future<List<String>> testStringifier(String code, |
| Iterable<String> expectedTokens) { |
| return compile(code) |
| .then((List<FunctionDefinition> functions) { |
| List<String> sexprs = stringifyAll(functions); |
| String combined = sexprs.join(); |
| String withoutNullConstants = combined.replaceAll("Constant null", ""); |
| Expect.isFalse(withoutNullConstants.contains("null")); |
| for (String token in expectedTokens) { |
| Expect.isTrue(combined.contains(token), |
| "'$combined' doesn't contain '$token' in test:\n$code"); |
| } |
| |
| return sexprs; |
| }); |
| } |
| |
| /// Checks if the generated S-expressions can be processed by the unstringifier, |
| /// returns the resulting definitions. |
| List<FunctionDefinition> testUnstringifier(List<String> sexprs) { |
| return sexprs.map((String sexpr) { |
| try { |
| final function = new SExpressionUnstringifier().unstringify(sexpr); |
| Expect.isNotNull(function, "Unstringification failed:\n\n$sexpr"); |
| return function; |
| } catch (e, s) { |
| print('$e\n$s'); |
| Expect.fail('Error unstringifying "$sexpr": $e'); |
| } |
| }).toList(); |
| } |
| |
| void main() { |
| final tokens = |
| [ "FunctionDefinition" |
| , "IsTrue" |
| |
| // Expressions |
| , "Branch" |
| , "ConcatenateStrings" |
| , "DeclareFunction" |
| , "InvokeConstructor" |
| , "InvokeContinuation" |
| , "InvokeMethod" |
| , "InvokeStatic" |
| , "InvokeMethodDirectly" |
| , "LetCont" |
| , "LetPrim" |
| , "SetMutableVariable" |
| , "TypeOperator" |
| |
| // Primitives |
| , "Constant" |
| , "CreateFunction" |
| , "GetMutableVariable" |
| , "LiteralList" |
| , "LiteralMap" |
| // Parameters are encoded by name only and hence are not in this list. |
| , "ReifyTypeVar" |
| |
| , "(this)" // 'this' Parameter declarations |
| , "this" // 'this' Parameter uses |
| |
| ]; |
| |
| asyncTest(() => testStringifier(CODE, tokens).then((List<String> sexprs) { |
| final functions = testUnstringifier(sexprs); |
| |
| // Ensure that |
| // stringified(CODE) == stringified(unstringified(stringified(CODE))) |
| Expect.listEquals(sexprs, stringifyAll(functions)); |
| })); |
| } |