|  | // Copyright (c) 2016, 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. | 
|  |  | 
|  | /// Dart test verifying that the parser can handle type parameterization of | 
|  | /// method declarations and method invocations. Slightly adjusted version of | 
|  | /// code from DEP #22. | 
|  |  | 
|  | library generic_methods_test; | 
|  |  | 
|  | import "package:expect/expect.dart"; | 
|  |  | 
|  | class BinaryTreeNode<K extends Comparable<K>, V> { | 
|  | final K _key; | 
|  | final V _value; | 
|  | final BinaryTreeNode<K, V> _left; | 
|  | final BinaryTreeNode<K, V> _right; | 
|  |  | 
|  | BinaryTreeNode(this._key, this._value, | 
|  | {BinaryTreeNode<K, V> left: null, BinaryTreeNode<K, V> right: null}) | 
|  | : _left = left, | 
|  | _right = right; | 
|  |  | 
|  | // Use fresh type variables. | 
|  | static BinaryTreeNode<K2, V2> insertOpt<K2 extends Comparable<K2>, V2>( | 
|  | BinaryTreeNode<K2, V2> t, K2 key, V2 value) { | 
|  | return (t == null) ? new BinaryTreeNode(key, value) : t.insert(key, value); | 
|  | } | 
|  |  | 
|  | BinaryTreeNode<K, V> insert(K key, V value) { | 
|  | int c = key.compareTo(_key); | 
|  | if (c == 0) return this; | 
|  | var _insert = (BinaryTreeNode<K, V> node, K key, V value) => | 
|  | insertOpt<K, V>(node, key, value); | 
|  | BinaryTreeNode<K, V> left = _left; | 
|  | BinaryTreeNode<K, V> right = _right; | 
|  | if (c < 0) { | 
|  | left = _insert(_left, key, value); | 
|  | } else { | 
|  | right = _insert(_right, key, value); | 
|  | } | 
|  | return new BinaryTreeNode<K, V>(_key, _value, left: left, right: right); | 
|  | } | 
|  |  | 
|  | // Reuse type variables [K], [V] to test shadowing. | 
|  | static BinaryTreeNode<K, U> mapOpt<K extends Comparable<K>, V, U>( | 
|  | BinaryTreeNode<K, V> t, U f(V x)) { | 
|  | return (t == null) ? null : t.map<U>(f); | 
|  | } | 
|  |  | 
|  | BinaryTreeNode<K, U> map<U>(U f(V x)) { | 
|  | var _map = (BinaryTreeNode<K, V> t, U f(V x)) => mapOpt<K, V, U>(t, f); | 
|  | return new BinaryTreeNode<K, U>(_key, f(_value), | 
|  | left: _map(_left, f), right: _map(_right, f)); | 
|  | } | 
|  |  | 
|  | // Use fresh [K2], shadowing [V]. | 
|  | static S foldPreOpt<K2 extends Comparable<K2>, V, S>( | 
|  | BinaryTreeNode<K2, V> t, S init, S f(V t, S s)) { | 
|  | return (t == null) ? init : t.foldPre<S>(init, f); | 
|  | } | 
|  |  | 
|  | S foldPre<S>(S init, S f(V t, S s)) { | 
|  | var _fold = (BinaryTreeNode<K, V> t, S s, S f(V t, S s)) => | 
|  | foldPreOpt<K, V, S>(t, s, f); | 
|  | S s = init; | 
|  | s = f(_value, s); | 
|  | s = _fold(_left, s, f); | 
|  | s = _fold(_right, s, f); | 
|  | return s; | 
|  | } | 
|  | } | 
|  |  | 
|  | class BinaryTree<K extends Comparable<K>, V> { | 
|  | final BinaryTreeNode<K, V> _root; | 
|  |  | 
|  | BinaryTree._internal(this._root); | 
|  | BinaryTree.empty() : this._internal(null); | 
|  |  | 
|  | BinaryTree<K, V> insert(K key, V value) { | 
|  | BinaryTreeNode<K, V> root = | 
|  | BinaryTreeNode.insertOpt<K, V>(_root, key, value); | 
|  | return new BinaryTree<K, V>._internal(root); | 
|  | } | 
|  |  | 
|  | BinaryTree<K, U> map<U>(U f(V x)) { | 
|  | BinaryTreeNode<K, U> root = BinaryTreeNode.mapOpt<K, V, U>(_root, f); | 
|  | return new BinaryTree<K, U>._internal(root); | 
|  | } | 
|  |  | 
|  | S foldPre<S>(S init, S f(V t, S s)) { | 
|  | return BinaryTreeNode.foldPreOpt<K, V, S>(_root, init, f); | 
|  | } | 
|  | } | 
|  |  | 
|  | main() { | 
|  | BinaryTree<num, String> sT = new BinaryTree<num, String>.empty(); | 
|  |  | 
|  | sT = sT.insert(0, ""); | 
|  | sT = sT.insert(1, " "); | 
|  | sT = sT.insert(2, "  "); | 
|  | sT = sT.insert(3, "   "); | 
|  |  | 
|  | BinaryTree<num, num> iT = sT.map<num>((String s) => s.length); | 
|  |  | 
|  | Expect.equals(iT.foldPre<num>(0, (num i, num s) => i + s), 6); | 
|  | } |