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 ¤tEntity.tokens_[$-1] < &tokens_[0]; 35 } 36 37 private bool isNestedEntity() { 38 return &nextEntity.tokens_[0] <= ¤tEntity.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 }