vendor/moustachupkg/tokenizer.nim
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
import sequtils import strutils type TokenType* {.pure.} = enum rawtext, escapedvariable, unescapedvariable, section, invertedsection, comment, partial, ender, indenter Token* = tuple[tokentype: TokenType, value: string] proc left_side_empty(tmplate: string, pivotindex: int): tuple[empty: bool, newlineindex: int] = var ls_i = 0 var ls_empty = false var i = pivotindex - 1 while i > -1 and tmplate[i] in {' ', '\t'}: dec(i) if (i == -1) or (tmplate[i] == '\l'): ls_i = i ls_empty = true return (empty: ls_empty, newlineindex: ls_i) iterator tokenize*(tmplate: string): Token = let opening = "{{" var pos = 0 while pos < tmplate.len: let originalpos = pos var closing = "}}" # find start of tag var opening_index = tmplate.find(opening, start=pos) if opening_index == -1: yield (tokentype: TokenType.rawtext, value: tmplate[pos..high(tmplate)]) break #Check if the left side is empty var left_side = left_side_empty(tmplate, opening_index) var ls_empty = left_side.empty var ls_i = left_side.newlineindex #Deal with text before tag var beforetoken = (tokentype: TokenType.rawtext, value: "") if opening_index > pos: #safe bet for now beforetoken.value = tmplate[pos..opening_index-1] pos = opening_index + opening.len if not (pos < tmplate.len): yield (tokentype: TokenType.rawtext, value: tmplate[opening_index..high(tmplate)]) break #Determine TokenType var tt = TokenType.escapedvariable case tmplate[pos] of '!': tt = TokenType.comment pos += 1 of '&': tt = TokenType.unescapedvariable pos += 1 of '{': tt = TokenType.unescapedvariable pos += 1 closing &= "}" of '#': tt = TokenType.section pos += 1 of '^': tt = TokenType.invertedsection pos += 1 of '/': tt = TokenType.ender pos += 1 of '>': tt = TokenType.partial pos += 1 else: tt = TokenType.escapedvariable #find end of tag var closingindex = tmplate.find(closing, start=pos) if closingindex == -1: if beforetoken.value != "": yield beforetoken yield (tokentype: TokenType.rawtext, value: tmplate[opening_index..pos-1]) continue #Check if the right side is empty var rs_i = 0 var rs_empty = false var i = 0 if ls_empty: i = closingindex + closing.len while i < tmplate.len and tmplate[i] in {' ', '\t'}: inc(i) if i == tmplate.len: rs_i = i - 1 rs_empty = true elif tmplate[i] == '\c' and (i+1 < tmplate.len) and (tmplate[i+1] == '\l'): rs_i = i + 1 rs_empty = true elif tmplate[i] == '\l': rs_i = i rs_empty = true else: discard if tt in [TokenType.comment, TokenType.section, TokenType.invertedsection, TokenType.ender, TokenType.partial]: # Standalone tokens if rs_empty: if beforetoken.value != "": beforetoken.value = tmplate[originalpos..ls_i] yield beforetoken if tt == TokenType.partial: if ls_i+1 <= opening_index-1: yield (tokentype: TokenType.indenter, value: tmplate[ls_i+1..opening_index-1]) yield (tokentype: tt, value: tmplate[pos..closingindex-1].strip) pos = rs_i + 1 # remove new line of this line else: if beforetoken.value != "": yield beforetoken yield (tokentype: tt, value: tmplate[pos..closingindex-1].strip) pos = closingindex + closing.len else: if beforetoken.value != "": yield beforetoken yield (tokentype: tt, value: tmplate[pos..closingindex-1].strip) pos = closingindex + closing.len |