2
2
#include < rime/common.h>
3
3
#include < rime/resource.h>
4
4
#include < rime/config/config_compiler.h>
5
+ #include < rime/config/config_compiler_impl.h>
5
6
#include < rime/config/config_data.h>
6
7
#include < rime/config/config_types.h>
8
+ #include < rime/config/plugins.h>
7
9
8
10
namespace rime {
9
11
10
- enum DependencyPriority {
11
- kPendingChild = 0 ,
12
- kInclude = 1 ,
13
- kPatch = 2 ,
14
- };
15
-
16
- struct Dependency {
17
- an<ConfigItemRef> target;
18
-
19
- virtual DependencyPriority priority () const = 0;
20
- bool blocking () const {
21
- return priority () > kPendingChild ;
22
- }
23
- virtual string repr () const = 0;
24
- virtual bool Resolve (ConfigCompiler* compiler) = 0;
25
- };
26
-
27
- template <class StreamT >
28
- StreamT& operator << (StreamT& stream, const Dependency& dep) {
29
- return stream << dep.repr ();
30
- }
31
-
32
- struct PendingChild : Dependency {
33
- string child_path;
34
- an<ConfigItemRef> child_ref;
35
-
36
- PendingChild (const string& path, const an<ConfigItemRef>& ref)
37
- : child_path(path), child_ref(ref) {
38
- }
39
- DependencyPriority priority () const override {
40
- return kPendingChild ;
41
- }
42
- string repr () const override {
43
- return " PendingChild(" + child_path + " )" ;
44
- }
45
- bool Resolve (ConfigCompiler* compiler) override ;
46
- };
47
-
48
- string Reference::repr () const {
49
- return resource_id + " :" + local_path + (optional ? " <optional>" : " " );
50
- }
51
-
52
- template <class StreamT >
53
- StreamT& operator << (StreamT& stream, const Reference& reference) {
54
- return stream << reference.repr ();
55
- }
56
-
57
- struct IncludeReference : Dependency {
58
- IncludeReference (const Reference& r) : reference(r) {
59
- }
60
- DependencyPriority priority () const override {
61
- return kInclude ;
62
- }
63
- string repr () const override {
64
- return " Include(" + reference.repr () + " )" ;
65
- }
66
- bool Resolve (ConfigCompiler* compiler) override ;
67
-
68
- Reference reference;
69
- };
70
-
71
- struct PatchReference : Dependency {
72
- PatchReference (const Reference& r) : reference(r) {
73
- }
74
- DependencyPriority priority () const override {
75
- return kPatch ;
76
- }
77
- string repr () const override {
78
- return " Patch(" + reference.repr () + " )" ;
79
- }
80
- bool Resolve (ConfigCompiler* compiler) override ;
81
-
82
- Reference reference;
83
- };
84
-
85
- struct PatchLiteral : Dependency {
86
- an<ConfigMap> patch;
87
-
88
- PatchLiteral (an<ConfigMap> map) : patch(map) {
89
- }
90
- DependencyPriority priority () const override {
91
- return kPatch ;
92
- }
93
- string repr () const override {
94
- return " Patch(<literal>)" ;
95
- }
96
- bool Resolve (ConfigCompiler* compiler) override ;
97
- };
98
-
99
12
struct ConfigDependencyGraph {
100
13
map<string, of<ConfigResource>> resources;
101
14
vector<of<ConfigItemRef>> node_stack;
@@ -114,12 +27,18 @@ struct ConfigDependencyGraph {
114
27
key_stack.pop_back ();
115
28
}
116
29
117
- string current_resource_id () const {
118
- return key_stack.empty () ? string ()
119
- : boost::trim_right_copy_if (key_stack.front (), boost::is_any_of (" :" ));
120
- }
30
+ string current_resource_id () const ;
121
31
};
122
32
33
+ string ConfigDependencyGraph::current_resource_id () const {
34
+ return key_stack.empty () ? string ()
35
+ : boost::trim_right_copy_if (key_stack.front (), boost::is_any_of (" :" ));
36
+ }
37
+
38
+ string Reference::repr () const {
39
+ return resource_id + " :" + local_path + (optional ? " <optional>" : " " );
40
+ }
41
+
123
42
bool PendingChild::Resolve (ConfigCompiler* compiler) {
124
43
return compiler->ResolveDependencies (child_path);
125
44
}
@@ -156,8 +75,7 @@ bool PatchReference::Resolve(ConfigCompiler* compiler) {
156
75
return false ;
157
76
}
158
77
PatchLiteral patch{As<ConfigMap>(item)};
159
- patch.target = target;
160
- return patch.Resolve (compiler);
78
+ return patch.TargetedAt (target).Resolve (compiler);
161
79
}
162
80
163
81
static bool AppendToString (an<ConfigItemRef> target, an<ConfigValue> value) {
@@ -223,7 +141,7 @@ inline static bool IsMerging(const string& key,
223
141
bool merge_tree) {
224
142
return key == ConfigCompiler::MERGE_DIRECTIVE ||
225
143
boost::ends_with (key, ADD_SUFFIX_OPERATOR) ||
226
- (merge_tree && Is<ConfigMap>(value) &&
144
+ (merge_tree && (!value || Is<ConfigMap>(value) ) &&
227
145
!boost::ends_with (key, EQU_SUFFIX_OPERATOR));
228
146
}
229
147
@@ -294,7 +212,7 @@ void ConfigDependencyGraph::Add(an<Dependency> dependency) {
294
212
<< node_stack.size ();
295
213
if (node_stack.empty ()) return ;
296
214
const auto & target = node_stack.back ();
297
- dependency->target = target ;
215
+ dependency->TargetedAt ( target) ;
298
216
auto target_path = ConfigData::JoinPath (key_stack);
299
217
auto & target_deps = deps[target_path];
300
218
bool target_was_pending = !target_deps.empty ();
@@ -326,8 +244,10 @@ void ConfigDependencyGraph::Add(an<Dependency> dependency) {
326
244
}
327
245
}
328
246
329
- ConfigCompiler::ConfigCompiler (ResourceResolver* resource_resolver)
247
+ ConfigCompiler::ConfigCompiler (ResourceResolver* resource_resolver,
248
+ ConfigCompilerPlugin* plugin)
330
249
: resource_resolver_(resource_resolver),
250
+ plugin_ (plugin),
331
251
graph_(new ConfigDependencyGraph) {
332
252
}
333
253
@@ -353,6 +273,10 @@ void ConfigCompiler::AddDependency(an<Dependency> dependency) {
353
273
graph_->Add (dependency);
354
274
}
355
275
276
+ void ConfigCompiler::Push (an<ConfigResource> resource) {
277
+ graph_->Push (resource, resource->resource_id + " :" );
278
+ }
279
+
356
280
void ConfigCompiler::Push (an<ConfigList> config_list, size_t index) {
357
281
graph_->Push (
358
282
New<ConfigListEntryRef>(nullptr , config_list, index ),
@@ -378,10 +302,12 @@ an<ConfigResource> ConfigCompiler::Compile(const string& file_name) {
378
302
auto resource_id = resource_resolver_->ToResourceId (file_name);
379
303
auto resource = New<ConfigResource>(resource_id, New<ConfigData>());
380
304
graph_->resources [resource_id] = resource;
381
- graph_-> Push (resource, resource_id + " : " );
305
+ Push (resource);
382
306
resource->loaded = resource->data ->LoadFromFile (
383
307
resource_resolver_->ResolvePath (resource_id).string (), this );
384
- graph_->Pop ();
308
+ Pop ();
309
+ if (plugin_)
310
+ plugin_->ReviewCompileOutput (this , resource);
385
311
return resource;
386
312
}
387
313
@@ -462,12 +388,22 @@ bool ConfigCompiler::resolved(const string& full_path) const {
462
388
return found == graph_->deps .end () || found->second .empty ();
463
389
}
464
390
391
+ vector<of<Dependency>> ConfigCompiler::GetDependencies (const string& path) {
392
+ auto found = graph_->deps .find (path);
393
+ return found == graph_->deps .end () ? vector<of<Dependency>>() : found->second ;
394
+ }
395
+
465
396
static an<ConfigItem> ResolveReference (ConfigCompiler* compiler,
466
397
const Reference& reference) {
467
398
auto resource = compiler->GetCompiledResource (reference.resource_id );
468
399
if (!resource) {
469
400
DLOG (INFO) << " resource not loaded, compiling: " << reference.resource_id ;
470
401
resource = compiler->Compile (reference.resource_id );
402
+ // dependency doesn't require full resolution, this allows non conflicting
403
+ // mutual references between config files.
404
+ // this call is made even if resource is not loaded because plugins can
405
+ // edit the empty config data, adding new dependencies.
406
+ ResolveBlockingDependencies (compiler, reference.resource_id + " :" );
471
407
if (!resource->loaded ) {
472
408
if (reference.optional ) {
473
409
LOG (INFO) << " optional resource not loaded: " << reference.resource_id ;
@@ -552,15 +488,17 @@ bool ConfigCompiler::Link(an<ConfigResource> target) {
552
488
LOG (ERROR) << " resource not found: " << target->resource_id ;
553
489
return false ;
554
490
}
555
- return ResolveDependencies (found->first + " :" );
491
+ return ResolveDependencies (found->first + " :" ) &&
492
+ (plugin_ ? plugin_->ReviewLinkOutput (this , target) : true );
556
493
}
557
494
558
495
bool ConfigCompiler::ResolveDependencies (const string& path) {
559
496
DLOG (INFO) << " ResolveDependencies(" << path << " )" ;
560
- if (!graph_->deps .count (path)) {
497
+ auto found = graph_->deps .find (path);
498
+ if (found == graph_->deps .end ()) {
561
499
return true ;
562
500
}
563
- auto & deps = graph_-> deps [path] ;
501
+ auto & deps = found-> second ;
564
502
for (auto iter = deps.begin (); iter != deps.end (); ) {
565
503
if (!(*iter)->Resolve (this )) {
566
504
LOG (ERROR) << " unresolved dependency: " << **iter;
0 commit comments