OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2017, 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 'dart:typed_data'; | |
6 | |
7 import 'package:front_end/src/base/api_signature.dart'; | |
8 import 'package:front_end/src/fasta/parser/listener.dart' show Listener; | |
9 import 'package:front_end/src/fasta/parser/parser.dart' show Parser, optional; | |
10 import 'package:front_end/src/fasta/parser/top_level_parser.dart'; | |
11 import 'package:front_end/src/fasta/scanner.dart'; | |
12 import 'package:front_end/src/fasta/scanner/token_constants.dart' | |
13 show STRING_TOKEN; | |
14 import 'package:front_end/src/fasta/source/directive_listener.dart'; | |
15 import 'package:front_end/src/incremental/format.dart'; | |
16 | |
17 /// Compute the [UnlinkedUnitBuilder] for the [content]. | |
18 UnlinkedUnitBuilder computeUnlinkedUnit(List<int> salt, List<int> content) { | |
19 // Scan the content. | |
20 ScannerResult scanResult = _scan(content); | |
21 Token token = scanResult.tokens; | |
22 | |
23 // Parse directives. | |
24 var listener = new DirectiveListener(); | |
25 new TopLevelParser(listener).parseUnit(token); | |
Paul Berry
2017/06/13 21:49:46
It seems wasteful that we call `parseUnit` here an
scheglov
2017/06/13 22:03:21
Well, yes, we waste something. But in general TopL
| |
26 | |
27 // Parse to record function bodies. | |
28 var parser = new _BodySkippingParser(); | |
29 parser.parseUnit(token); | |
30 | |
31 ApiSignature apiSignature = new ApiSignature(); | |
32 apiSignature.addBytes(salt); | |
33 | |
34 // Iterate over tokens and skip bodies. | |
35 Iterator<_BodyRange> bodyIterator = parser.bodyRanges.iterator; | |
36 bodyIterator.moveNext(); | |
37 for (; token.kind != EOF_TOKEN; token = token.next) { | |
38 // Move to the body range that ends after the token. | |
39 while (bodyIterator.current != null && | |
40 bodyIterator.current.last < token.charOffset) { | |
41 bodyIterator.moveNext(); | |
42 } | |
43 // If the current body range starts before or at the token, skip it. | |
44 if (bodyIterator.current != null && | |
45 bodyIterator.current.first <= token.charOffset) { | |
46 continue; | |
47 } | |
48 // The token is outside of a function body, add it. | |
49 apiSignature.addString(token.lexeme); | |
50 } | |
51 | |
52 return new UnlinkedUnitBuilder( | |
53 apiSignature: apiSignature.toByteList(), | |
54 imports: listener.imports.map(_toUnlinkedNamespaceDirective).toList(), | |
55 exports: listener.exports.map(_toUnlinkedNamespaceDirective).toList(), | |
56 parts: listener.parts.toList(), | |
57 hasMixinApplication: parser.hasMixin); | |
58 } | |
59 | |
60 /// Exclude all `native 'xyz';` token sequences. | |
61 void _excludeNativeClauses(Token token) { | |
Paul Berry
2017/06/13 21:49:46
This seems like an unnecessarily fragile hack. Ca
scheglov
2017/06/13 22:03:21
Unfortunately my understanding is that position of
Paul Berry
2017/06/14 12:20:52
Ok, I will have a discussion with Peter about this
Siggi Cherem (dart-lang)
2017/06/14 22:37:38
FWIW - in our perf scripts we take the other appro
scheglov
2017/06/14 23:20:34
OK, I see how this is done for parsing directives.
| |
62 for (; token.kind != EOF_TOKEN; token = token.next) { | |
63 if (optional('native', token) && | |
64 token.next.kind == STRING_TOKEN && | |
65 optional(';', token.next.next)) { | |
66 token.previous.next = token.next.next; | |
67 } | |
68 } | |
69 } | |
70 | |
71 /// Scan the content of the file. | |
72 ScannerResult _scan(List<int> content) { | |
73 var zeroTerminatedBytes = new Uint8List(content.length + 1); | |
74 zeroTerminatedBytes.setRange(0, content.length, content); | |
75 ScannerResult result = scan(zeroTerminatedBytes); | |
76 _excludeNativeClauses(result.tokens); | |
77 return result; | |
78 } | |
79 | |
80 /// Convert [NamespaceCombinator] into [UnlinkedCombinatorBuilder]. | |
81 UnlinkedCombinatorBuilder _toUnlinkedCombinator(NamespaceCombinator c) => | |
82 new UnlinkedCombinatorBuilder(isShow: c.isShow, names: c.names.toList()); | |
83 | |
84 /// Convert [NamespaceDirective] into [UnlinkedNamespaceDirectiveBuilder]. | |
85 UnlinkedNamespaceDirectiveBuilder _toUnlinkedNamespaceDirective( | |
86 NamespaceDirective directive) => | |
87 new UnlinkedNamespaceDirectiveBuilder( | |
88 uri: directive.uri, | |
89 combinators: directive.combinators.map(_toUnlinkedCombinator).toList()); | |
90 | |
91 /// The char range of a function body. | |
92 class _BodyRange { | |
93 /// The char offset of the first token in the range. | |
94 final int first; | |
95 | |
96 /// The char offset of the last token in the range. | |
97 final int last; | |
98 | |
99 _BodyRange(this.first, this.last); | |
100 | |
101 @override | |
102 String toString() => '[$first, $last]'; | |
103 } | |
104 | |
105 /// The [Parser] that skips function bodies and remembers their token ranges. | |
106 class _BodySkippingParser extends Parser { | |
107 bool hasMixin = false; | |
108 final List<_BodyRange> bodyRanges = []; | |
109 | |
110 _BodySkippingParser() : super(new Listener()); | |
111 | |
112 @override | |
113 Token parseFunctionBody(Token token, bool isExpression, bool allowAbstract) { | |
ahe
2017/08/07 14:05:13
This feature is already provided by ClassMemberPar
| |
114 if (identical('{', token.lexeme)) { | |
115 Token close = skipBlock(token); | |
116 bodyRanges.add(new _BodyRange(token.charOffset, close.charOffset)); | |
117 return close; | |
118 } | |
119 return super.parseFunctionBody(token, isExpression, allowAbstract); | |
120 } | |
121 | |
122 Token parseMixinApplication(Token token) { | |
ahe
2017/08/07 14:05:13
You should be able to collect this information via
| |
123 hasMixin = true; | |
124 return super.parseMixinApplication(token); | |
125 } | |
126 } | |
OLD | NEW |