1 module dlex.DLex; 2 3 import std.conv; 4 import std.array; 5 import std.typecons; 6 import std.algorithm; 7 8 import dlex.Position; 9 import dlex.MatchResult; 10 import dlex.Rule; 11 12 template DLex(Type) { 13 class DLex { 14 class LexResult { 15 public: 16 Type type; 17 dstring str; 18 Position pos; 19 20 this (Type type, dstring str, Position pos) { 21 this.type = type; 22 this.str = str; 23 this.pos = pos; 24 } 25 } 26 public: 27 struct RuleT { 28 Type type; 29 Rule rule; 30 } 31 32 RuleT[] rules; 33 34 void Rules(RuleT[] rules) { 35 this.rules = rules; 36 } 37 38 auto Lex(dstring source) { 39 Position pos; 40 LexResult[] results = []; 41 42 struct Matched { 43 MatchResult result; 44 Position pos; 45 Type type; 46 bool skip; 47 } 48 while (!pos.end(source)) { 49 Matched[] rs = []; 50 foreach (rule; rules) { 51 auto savePos = pos; 52 MatchResult r = rule.rule.matched(source, savePos); 53 if (r && r.str.length > 0) { // 0文字でマッチし得る 54 rs ~= Matched(r, savePos, rule.type, rule.rule.skip); 55 } 56 } 57 if (rs.length == 0) { 58 break; 59 } 60 61 62 // 最長一致なので最長のMatchResultを採用する 63 // 同じ長さならより早く見つけた(先に登録した)方を優先する 64 auto result = rs.reduce!((a,b) => ( 65 (a.result.str.length >= b.result.str.length) ? a : b 66 )); 67 68 if (!result.skip) { 69 results ~= new LexResult(result.type, result.result.str, pos); 70 } 71 pos = result.pos; 72 } 73 if (!pos.end(source)) { 74 throw new Exception("Lex rules did not fully matched input string"); 75 } 76 77 return results; 78 } 79 } 80 } 81