Line data Source code
1 : // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 2 : // for details. All rights reserved. Use of this source code is governed by a 3 : // BSD-style license that can be found in the LICENSE file. 4 : 5 : import 'core_matchers.dart'; 6 : import 'equals_matcher.dart'; 7 : import 'interfaces.dart'; 8 : 9 : /// A [Map] between whitespace characters and their escape sequences. 10 : const _escapeMap = { 11 : '\n': r'\n', 12 : '\r': r'\r', 13 : '\f': r'\f', 14 : '\b': r'\b', 15 : '\t': r'\t', 16 : '\v': r'\v', 17 : '\x7F': r'\x7F', // delete 18 : }; 19 : 20 : /// A [RegExp] that matches whitespace characters that should be escaped. 21 0 : final _escapeRegExp = RegExp( 22 : '[\\x00-\\x07\\x0E-\\x1F${_escapeMap.keys.map(_getHexLiteral).join()}]'); 23 : 24 : /// Useful utility for nesting match states. 25 5 : void addStateInfo(Map matchState, Map values) { 26 5 : var innerState = Map.from(matchState); 27 5 : matchState.clear(); 28 5 : matchState['state'] = innerState; 29 5 : matchState.addAll(values); 30 : } 31 : 32 : /// Takes an argument and returns an equivalent [Matcher]. 33 : /// 34 : /// If the argument is already a matcher this does nothing, 35 : /// else if the argument is a function, it generates a predicate 36 : /// function matcher, else it generates an equals matcher. 37 11 : Matcher wrapMatcher(Object? valueOrMatcher) { 38 11 : if (valueOrMatcher is Matcher) { 39 : return valueOrMatcher; 40 8 : } else if (valueOrMatcher is bool Function(Object?)) { 41 : // already a predicate that can handle anything 42 0 : return predicate(valueOrMatcher); 43 8 : } else if (valueOrMatcher is bool Function(Never)) { 44 : // unary predicate, but expects a specific type 45 : // so wrap it. 46 : // ignore: unnecessary_lambdas 47 0 : return predicate((a) => (valueOrMatcher as dynamic)(a)); 48 : } else { 49 8 : return equals(valueOrMatcher); 50 : } 51 : } 52 : 53 : /// Returns [str] with all whitespace characters represented as their escape 54 : /// sequences. 55 : /// 56 : /// Backslash characters are escaped as `\\` 57 0 : String escape(String str) { 58 0 : str = str.replaceAll('\\', r'\\'); 59 0 : return str.replaceAllMapped(_escapeRegExp, (match) { 60 0 : var mapped = _escapeMap[match[0]]; 61 : if (mapped != null) return mapped; 62 0 : return _getHexLiteral(match[0]!); 63 : }); 64 : } 65 : 66 : /// Given single-character string, return the hex-escaped equivalent. 67 0 : String _getHexLiteral(String input) { 68 0 : var rune = input.runes.single; 69 0 : return r'\x' + rune.toRadixString(16).toUpperCase().padLeft(2, '0'); 70 : }