github.com/ronaksoft/rony@v0.16.26-0.20230807065236-1743dbfe6959/internal/parser/parse.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package parse builds parse trees for templates as defined by text/template 6 // and html/template. Clients should use those packages to construct templates 7 // rather than this one, which provides shared internal data structures not 8 // intended for general use. 9 package parse 10 11 import ( 12 "fmt" 13 "runtime" 14 ) 15 16 // Tree is the representation of a single parsed template. 17 type Tree struct { 18 Name string // name of the template represented by the tree. 19 ParseName string // name of the top-level template during parsing, for error messages. 20 Root *ListNode // top-level root of the tree. 21 text string // text parsed to create the template (or its parent) 22 // Parsing only; cleared after parse. 23 lex *lexer 24 token [3]tokenItem // three-token lookahead for parser. 25 peekCount int 26 } 27 28 // Copy returns a copy of the Tree. Any parsing state is discarded. 29 func (t *Tree) Copy() *Tree { 30 if t == nil { 31 return nil 32 } 33 34 return &Tree{ 35 Name: t.Name, 36 ParseName: t.ParseName, 37 Root: t.Root.CopyList(), 38 text: t.text, 39 } 40 } 41 42 // Parse returns a map from template name to parse.Tree, created by parsing the 43 // templates described in the argument string. The top-level template will be 44 // given the specified name. If an error is encountered, parsing stops and an 45 // empty map is returned with the error. 46 func Parse(name, text string) (*Tree, error) { 47 t := New(name) 48 t.text = text 49 _, err := t.Parse(text) 50 51 return t, err 52 } 53 54 // next returns the next token. 55 func (t *Tree) next() tokenItem { 56 if t.peekCount > 0 { 57 t.peekCount-- 58 } else { 59 t.token[0] = t.lex.nextItem() 60 } 61 62 return t.token[t.peekCount] 63 } 64 65 // backup backs the input stream up one token. 66 func (t *Tree) backup() { 67 t.peekCount++ 68 } 69 70 // peek returns but does not consume the next token. 71 func (t *Tree) peek() tokenItem { 72 if t.peekCount > 0 { 73 return t.token[t.peekCount-1] 74 } 75 t.peekCount = 1 76 t.token[0] = t.lex.nextItem() 77 78 return t.token[0] 79 } 80 81 // nextNonSpace returns the next non-space token. 82 func (t *Tree) nextNonSpace() (token tokenItem) { 83 for { 84 token = t.next() 85 if token.tok != SPACE { 86 break 87 } 88 } 89 90 return token 91 } 92 93 // New allocates a new parse tree with the given name. 94 func New(name string) *Tree { 95 return &Tree{ 96 Name: name, 97 } 98 } 99 100 // errorf formats the error and terminates processing. 101 func (t *Tree) errorf(format string, args ...interface{}) { 102 t.Root = nil 103 format = fmt.Sprintf("template: %s:%d: %s", t.ParseName, t.token[0].line, format) 104 panic(fmt.Errorf(format, args...)) 105 } 106 107 // unexpected complains about the token and terminates processing. 108 func (t *Tree) unexpected(token tokenItem, context string) { 109 t.errorf("unexpected %s in %s", token, context) 110 } 111 112 // recover is the handler that turns panics into returns from the top level of Parse. 113 func (t *Tree) recover(errp *error) { 114 e := recover() 115 if e != nil { 116 if _, ok := e.(runtime.Error); ok { 117 panic(e) 118 } 119 if t != nil { 120 t.lex.drain() 121 t.stopParse() 122 } 123 *errp = e.(error) 124 } 125 } 126 127 // startParse initializes the parser, using the lexer. 128 func (t *Tree) startParse(lex *lexer) { 129 t.Root = nil 130 t.lex = lex 131 } 132 133 // stopParse terminates parsing. 134 func (t *Tree) stopParse() { 135 t.lex = nil 136 } 137 138 // Parse parses the template definition string to construct a representation of 139 // the template for execution. If either action delimiter string is empty, the 140 // default ("{{" or "}}") is used. Embedded template definitions are added to 141 // the treeSet map. 142 func (t *Tree) Parse(text string) (tree *Tree, err error) { 143 defer t.recover(&err) 144 t.ParseName = t.Name 145 t.startParse(lex(t.Name, text)) 146 t.text = text 147 t.parse() 148 t.stopParse() 149 150 return t, nil 151 } 152 153 // parse is the top-level parser for a template, essentially the same 154 // as itemList except it also parses {{define}} actions. 155 // It runs to EOF. 156 func (t *Tree) parse() { 157 t.Root = t.newList(t.peek().pos) 158 for t.peek().tok != EOF { 159 switch item := t.nextNonSpace(); item.tok { 160 case TEXT: 161 t.Root.append(t.newText(item.pos, item.val)) 162 case L_DELIM: 163 item = t.nextNonSpace() 164 t.Root.append(t.action()) 165 default: 166 t.unexpected(item, "input") 167 } 168 } 169 } 170 171 // Action: 172 // model, table, view, counter , ... 173 // Left delim is past. Now get actions. 174 func (t *Tree) action() (n Node) { 175 switch item := t.nextNonSpace(); item.tok { 176 case MODEL: 177 n = t.model(item.pos) 178 case TABLE: 179 n = t.table(item.pos) 180 case VIEW: 181 n = t.view(item.pos) 182 case COUNTER: 183 n = t.counter(item.pos) 184 default: 185 t.unexpected(item, "action") 186 } 187 if item := t.nextNonSpace(); item.tok != R_DELIM { 188 t.unexpected(item, "action right delmic") 189 } 190 191 return 192 } 193 194 func (t *Tree) model(pos Pos) (n Node) { 195 switch item := t.nextNonSpace(); item.tok { 196 case IDENT: 197 return t.newModel(pos, item.val) 198 default: 199 t.unexpected(item, "model") 200 } 201 202 panic("unreachable code") 203 } 204 205 func (t *Tree) idents() []string { 206 var args []string 207 Loop: 208 for { 209 item := t.nextNonSpace() 210 switch item.tok { 211 case IDENT: 212 args = append(args, item.val) 213 case COMMA: 214 case R_PAREN: 215 break Loop 216 default: 217 t.unexpected(item, "idents") 218 } 219 } 220 221 return args 222 } 223 224 func (t *Tree) table(pos Pos) (n Node) { 225 var ( 226 pks, cks []string 227 ) 228 // we must see at least one '(' 229 if item := t.nextNonSpace(); item.tok != L_PAREN { 230 t.unexpected(item, "table") 231 } 232 233 // if we see second '(' then we have composed partition keys 234 switch item := t.nextNonSpace(); item.tok { 235 case L_PAREN: 236 pks = t.idents() 237 cks = t.idents() 238 default: 239 // put back to buffer, since we did not pick '(' 240 t.backup() 241 242 ks := t.idents() 243 switch len(ks) { 244 case 0: 245 t.errorf("no primary key for table: (%d:%d)", item.line, item.pos) 246 case 1: 247 pks = append(pks, ks[0]) 248 default: 249 pks = append(pks, ks[0]) 250 cks = append(cks, ks[1:]...) 251 } 252 } 253 254 return t.newTable(pos, pks, cks) 255 } 256 257 func (t *Tree) view(pos Pos) (n Node) { 258 var ( 259 pks, cks []string 260 ) 261 // we must see at least one '(' 262 if item := t.nextNonSpace(); item.tok != L_PAREN { 263 t.unexpected(item, "table") 264 } 265 266 // if we see second '(' then we have composed partition keys 267 switch item := t.nextNonSpace(); item.tok { 268 case L_PAREN: 269 pks = t.idents() 270 cks = t.idents() 271 default: 272 // put back to buffer, since we did not pick '(' 273 t.backup() 274 275 ks := t.idents() 276 switch len(ks) { 277 case 0: 278 t.errorf("no primary key for view: (%d:%d)", item.line, item.pos) 279 case 1: 280 pks = append(pks, ks[0]) 281 default: 282 pks = append(pks, ks[0]) 283 cks = append(cks, ks[1:]...) 284 } 285 } 286 287 return t.newView(pos, pks, cks) 288 } 289 290 func (t *Tree) counter(pos Pos) (n Node) { 291 switch item := t.nextNonSpace(); item.tok { 292 case IDENT: 293 return t.newCounter(pos, item.val) 294 default: 295 t.unexpected(item, "counter") 296 } 297 298 panic("unreachable code") 299 }