Skip to content
This repository was archived by the owner on Apr 8, 2025. It is now read-only.

Commit 84366d0

Browse files
authored
Add a simple identifier Scope class and a test. (#9)
* Add a simple identifier Scope class and a test. * Address comments.
1 parent fdfb629 commit 84366d0

File tree

3 files changed

+121
-0
lines changed

3 files changed

+121
-0
lines changed

lib/code_builder.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ part 'src/builders/statement_builder.dart';
4646
part 'src/builders/type_builder.dart';
4747

4848
part 'src/pretty_printer.dart';
49+
part 'src/scope.dart';
4950

5051
/// Base class for building and emitting a Dart language [AstNode].
5152
abstract class CodeBuilder<A extends AstNode> {

lib/src/scope.dart

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
part of code_builder;
2+
3+
/// Determines an [Identifier] deppending on where it appears.
4+
///
5+
/// __Example use__:
6+
/// void useContext(Scope scope) {
7+
/// // Prints Identifier "i1.Foo"
8+
/// print(scope.getIdentifier('Foo', 'package:foo/foo.dart');
9+
///
10+
/// // Prints Identifier "i1.Bar"
11+
/// print(scope.getIdentifier('Bar', 'package:foo/foo.dart');
12+
///
13+
/// // Prints Identifier "i2.Baz"
14+
/// print(scope.getIdentifier('Baz', 'package:bar/bar.dart');
15+
/// }
16+
abstract class Scope {
17+
/// Create a default scope context.
18+
///
19+
/// Actual implementation is _not_ guaranteed, only that all import prefixes
20+
/// will be unique in a given scope (actual implementation may be naive).
21+
factory Scope() = _IncrementingScope;
22+
23+
/// Create a context that does _not_ apply any scoping.
24+
factory Scope.identity() = _IdentityScope;
25+
26+
/// Given a [symbol] and its known [importUri], return an [Identifier].
27+
Identifier getIdentifier(String symbol, String importUri);
28+
29+
/// Returns a list of all imports needed to resolve identifiers.
30+
Iterable<ImportBuilder> getImports();
31+
}
32+
33+
class _IdentityScope implements Scope {
34+
final Set<String> _imports = new Set<String>();
35+
36+
@override
37+
Identifier getIdentifier(String symbol, String import) {
38+
_imports.add(import);
39+
return _stringId(symbol);
40+
}
41+
42+
@override
43+
Iterable<ImportBuilder> getImports() {
44+
return _imports.map/*<ImportBuilder*/((i) => new ImportBuilder(i));
45+
}
46+
}
47+
48+
class _IncrementingScope implements Scope {
49+
final Map<String, int> _imports = <String, int>{};
50+
51+
int _counter = 0;
52+
53+
@override
54+
Identifier getIdentifier(String symbol, String import) {
55+
var newId = _imports.putIfAbsent(import, () => ++_counter);
56+
return new PrefixedIdentifier(_stringId('_i$newId'),
57+
new Token(TokenType.PERIOD, 0), _stringId(symbol));
58+
}
59+
60+
@override
61+
Iterable<ImportBuilder> getImports() {
62+
return _imports.keys.map/*<ImportBuilder*/(
63+
(i) => new ImportBuilder(i, as: '_i${_imports[i]}'));
64+
}
65+
}

test/scope_test.dart

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import 'package:analyzer/analyzer.dart';
2+
import 'package:code_builder/code_builder.dart';
3+
import 'package:test/test.dart';
4+
5+
void main() {
6+
group('Identity scope', () {
7+
Scope scope;
8+
9+
setUp(() => scope = new Scope.identity());
10+
11+
test('should just output non-prefixed and de-duplicate imports', () {
12+
var identifiers = <Identifier> [
13+
scope.getIdentifier('Foo', 'package:foo/foo.dart'),
14+
scope.getIdentifier('Bar', 'package:foo/foo.dart'),
15+
scope.getIdentifier('Baz', 'package:baz/baz.dart'),
16+
].map/*<String>*/((i) => i.toSource());
17+
18+
expect(identifiers, [
19+
'Foo',
20+
'Bar',
21+
'Baz',
22+
],);
23+
24+
expect(scope.getImports().map/*<String>*/((i) => i.toAst().toSource()), [
25+
r"import 'package:foo/foo.dart';",
26+
r"import 'package:baz/baz.dart';",
27+
],);
28+
});
29+
});
30+
31+
group('Incrementing scope', () {
32+
Scope scope;
33+
34+
setUp(() => scope = new Scope());
35+
36+
test('should out prefixed with a counter', () {
37+
var identifiers = <Identifier> [
38+
scope.getIdentifier('Foo', 'package:foo/foo.dart'),
39+
scope.getIdentifier('Bar', 'package:foo/foo.dart'),
40+
scope.getIdentifier('Baz', 'package:baz/baz.dart'),
41+
].map/*<String>*/((i) => i.toSource());
42+
43+
expect(identifiers, [
44+
'_i1.Foo',
45+
'_i1.Bar',
46+
'_i2.Baz',
47+
],);
48+
49+
expect(scope.getImports().map/*<String>*/((i) => i.toAst().toSource()), [
50+
r"import 'package:foo/foo.dart' as _i1;",
51+
r"import 'package:baz/baz.dart' as _i2;",
52+
],);
53+
});
54+
});
55+
}

0 commit comments

Comments
 (0)