1 module tooling.TokenRange;
2 
3 import std.algorithm, std.array, std.file, std.stdio, std.exception, std.conv;
4 
5 import tooling.Scanner;
6 import tooling.TreeRange;
7 import tooling.Tokenizer;
8 
9 alias EntityToken = Tuple!(Token, "token_", Entity, "entity_");
10 
11 struct TokenRangeResult
12 {
13   this(Entity[][] entries, Token[] tokens)
14   {
15 	entries_ = entries;
16 	tokens_ = tokens;
17 
18 	if (isEntityStart())
19 	  consumeEntity();
20   }
21 
22   private Entity currentEntity() { return entityStack_.back; }
23   private Entity nextEntity() { return entries_.front.back; }
24 
25   private bool hasCurrentEntity() { return !entityStack_.empty; }
26   private bool hasNextEntity() { return !entries_.empty; }
27 
28   private bool isEntityStart() {
29 	return hasNextEntity &&
30 	  &nextEntity.tokens_[0] == &tokens_[0];
31   }
32 
33   private bool isEntityDone() {
34 	return &currentEntity.tokens_[$-1] < &tokens_[0];
35   }
36 
37   private bool isNestedEntity() {
38 	return &nextEntity.tokens_[0] <= &currentEntity.tokens_[$-1];
39   }
40 
41   private void consumeEntity()
42   {
43 	entityStack_ = entries_.front;
44 	entries_.popFront;
45   }
46 
47   bool empty() { return tokens_.empty; }
48   EntityToken front() { return EntityToken(tokens_.front, !hasCurrentEntity() ? null : currentEntity); }
49   TokenRangeResult save() { return this; }
50   void popFront()
51   {
52 	tokens_ = tokens_[1 .. $];
53 	if (!tokens_.empty)
54 	{
55 	  if (!hasCurrentEntity())
56 	  {
57 		if (isEntityStart())
58 		  consumeEntity();
59 	  }
60 	  else if (isEntityDone())
61 	  {
62 		if (isEntityStart())
63 		  consumeEntity();
64 		else
65 		  entityStack_.popBack;
66 	  }
67 	  else if (isEntityStart() && isNestedEntity())
68 	  {
69 		consumeEntity();
70 	  }
71 	}
72   }
73 
74 private:
75   Entity[][] entries_;
76   Token[] tokens_;
77   Entity[] entityStack_;
78 }
79 
80 auto namespaceTokenRange(Token[] tokens, Entity[] content)
81 {
82   return TokenRangeResult(treeRange!(t => t.type_ == "namespace",
83 									 t => t.content_)(content)
84 						  .array,
85 						  tokens);
86 }
87 
88 auto namespaceTokenRange(Token[] tokens)
89 {
90   auto content = scanTokens(tokens);
91   return namespaceTokenRange(tokens, content);
92 }
93 
94 auto namespaceTokenRange(SourceFile sourceFile)
95 {
96   return namespaceTokenRange(sourceFile.tokens_, sourceFile.content_);
97 }
98 
99 auto classTokenRange(Token[] tokens, Entity[] content)
100 {
101   return TokenRangeResult(treeRange!(t => t.type_ == "namespace" || t.type_ == "class",
102 									 t => t.content_)(content)
103 						  .array,
104 						  tokens);
105 }
106 
107 auto classTokenRange(Token[] tokens)
108 {
109   auto content = scanTokens(tokens);
110   return classTokenRange(tokens, content);
111 }
112 
113 auto classTokenRange(SourceFile sourceFile)
114 {
115   return classTokenRange(sourceFile.tokens_, sourceFile.content_);
116 }