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 5package mof 6 7import ( 8 "bytes" 9 "encoding/binary" 10 "fmt" 11 "runtime" 12 "strconv" 13 "strings" 14 "unicode/utf8" 15) 16 17// Tree is the representation of a single parsed configuration. 18type tree struct { 19 Root *classNode // top-level root of the tree. 20 text []byte // text parsed to create the template (or its parent) 21 // Parsing only; cleared after parse. 22 lex *lexer 23 token [1]item // one-token lookahead for parser. 24 peekCount int 25} 26 27// Parse returns a Tree, created by parsing the configuration described in the 28// argument string. If an error is encountered, parsing stops and an empty Tree 29// is returned with the error. 30func parse(text []byte) (t *tree, err error) { 31 t = &tree{ 32 text: text, 33 } 34 err = t.Parse(text) 35 return 36} 37 38// next returns the next token. 39func (t *tree) next() item { 40 if t.peekCount > 0 { 41 t.peekCount-- 42 } else { 43 t.token[0] = t.lex.nextItem() 44 } 45 return t.token[t.peekCount] 46} 47 48// backup backs the input stream up one token. 49func (t *tree) backup() { 50 t.peekCount++ 51} 52 53// peek returns but does not consume the next token. 54func (t *tree) peek() item { 55 if t.peekCount > 0 { 56 return t.token[t.peekCount-1] 57 } 58 t.peekCount = 1 59 t.token[0] = t.lex.nextItem() 60 return t.token[0] 61} 62 63// Parsing. 64 65// errorf formats the error and terminates processing. 66func (t *tree) errorf(format string, args ...interface{}) { 67 t.Root = nil 68 format = fmt.Sprintf("parse: %d: %s", t.lex.lineNumber(), format) 69 panic(fmt.Errorf(format, args...)) 70} 71 72// error terminates processing. 73func (t *tree) error(err error) { 74 t.errorf("%s", err) 75} 76 77// expect consumes the next token and guarantees it has the required type. 78func (t *tree) expect(expected itemType, context string) item { 79 token := t.next() 80 if token.typ != expected { 81 t.unexpected(token, context) 82 } 83 return token 84} 85 86// expectOneOf consumes the next token and guarantees it has one of the required types. 87func (t *tree) expectOneOf(expected1, expected2 itemType, context string) item { 88 token := t.next() 89 if token.typ != expected1 && token.typ != expected2 { 90 t.unexpected(token, context) 91 } 92 return token 93} 94 95// until ignores tokens until a specified type is found. 96func (t *tree) until(until itemType, context string) item { 97 for { 98 token := t.next() 99 switch token.typ { 100 case until: 101 return token 102 case itemEOF: 103 t.errorf("did not find %s in %s", until, context) 104 } 105 } 106} 107 108func (t *tree) expectWord(val string, context string) item { 109 token := t.next() 110 if token.typ != itemWord { 111 t.unexpected(token, context) 112 } 113 if token.val != val { 114 t.errorf("expected word %s in %s", val, context) 115 } 116 return token 117} 118 119// unexpected complains about the token and terminates processing. 120func (t *tree) unexpected(token item, context string) { 121 t.errorf("unexpected %s in %s", token, context) 122} 123 124// recover is the handler that turns panics into returns from the top level of Parse. 125func (t *tree) recover(errp *error) { 126 e := recover() 127 if e != nil { 128 if _, ok := e.(runtime.Error); ok { 129 panic(e) 130 } 131 if t != nil { 132 t.stopParse() 133 } 134 *errp = e.(error) 135 } 136 return 137} 138 139// startParse initializes the parser, using the lexer. 140func (t *tree) startParse(lex *lexer) { 141 t.Root = nil 142 t.lex = lex 143} 144 145// stopParse terminates parsing. 146func (t *tree) stopParse() { 147 t.lex = nil 148} 149 150// Parse parses the template definition string to construct a representation of 151// the template for execution. If either action delimiter string is empty, the 152// default ("{{" or "}}") is used. Embedded template definitions are added to 153// the treeSet map. 154func (t *tree) Parse(text []byte) (err error) { 155 defer t.recover(&err) 156 runes, err := toRunes(text) 157 if err != nil { 158 return err 159 } 160 t.startParse(lex(runes)) 161 t.text = text 162 t.Root = newClass(t.peek().pos) 163 t.parse(t.Root) 164 t.stopParse() 165 return nil 166} 167 168func toRunes(text []byte) ([]rune, error) { 169 var runes []rune 170 if bytes.HasPrefix(text, []byte{0, 0, 0xFE, 0xFF}) { 171 return nil, fmt.Errorf("mof: unsupported encoding: UTF-32, big-endian") 172 } else if bytes.HasPrefix(text, []byte{0xFF, 0xFE, 0, 0}) { 173 return nil, fmt.Errorf("mof: unsupported encoding: UTF-32, little-endian") 174 } else if bytes.HasPrefix(text, []byte{0xFE, 0xFF}) { 175 return nil, fmt.Errorf("mof: unsupported encoding: UTF-16, big-endian") 176 } else if bytes.HasPrefix(text, []byte{0xFF, 0xFE}) { 177 // UTF-16, little-endian 178 for len(text) > 0 { 179 u := binary.LittleEndian.Uint16(text) 180 runes = append(runes, rune(u)) 181 text = text[2:] 182 } 183 return runes, nil 184 } 185 // Assume UTF-8. 186 for len(text) > 0 { 187 r, s := utf8.DecodeRune(text) 188 if r == utf8.RuneError { 189 return nil, fmt.Errorf("mof: unrecognized encoding") 190 } 191 runes = append(runes, r) 192 text = text[s:] 193 } 194 return runes, nil 195} 196 197// parse is the top-level parser for a conf. 198// It runs to EOF. 199func (t *tree) parse(n *classNode) { 200 foundClass := false 201 for { 202 token := t.next() 203 switch token.typ { 204 case itemWord: 205 if token.val == "class" { 206 if foundClass { 207 t.unexpected(token, "input") 208 } 209 foundClass = true 210 t.parseClass(n) 211 t.expect(itemSemi, "input") 212 } 213 case itemEOF: 214 if foundClass { 215 return 216 } 217 t.unexpected(token, "input") 218 default: 219 // ignore 220 } 221 } 222} 223 224func (t *tree) parseClass(n *classNode) { 225 const context = "class" 226 token := t.expect(itemWord, context) 227 if token.val != "__PARAMETERS" { 228 t.errorf("expected __PARAMETERS") 229 } 230 t.expect(itemLeftBrace, context) 231 var brackets int 232 var btwn []string 233 for { 234 token := t.next() 235 // Ignore everything between braces. 236 if brackets > 0 && token.typ != itemLeftBracket && token.typ != itemRightBracket { 237 btwn = append(btwn, token.val) 238 continue 239 } 240 switch token.typ { 241 case itemLeftBracket: 242 if brackets == 0 { 243 btwn = nil 244 } 245 brackets++ 246 case itemRightBracket: 247 brackets-- 248 case itemWord: 249 // If [out] was just parsed, then the type is next, not the name. 250 if strings.Join(btwn, " ") == "out" { 251 token = t.expect(itemWord, context) 252 } 253 btwn = nil 254 member := token.val 255 t.until(itemEq, context) 256 n.Members[member] = t.parseValue() 257 t.expect(itemSemi, context) 258 case itemRightBrace: 259 return 260 default: 261 t.unexpected(token, context) 262 } 263 } 264} 265 266func (t *tree) parseValue() node { 267 const context = "value" 268 token := t.next() 269 var n node 270 switch token.typ { 271 case itemLeftBrace: 272 t.backup() 273 n = t.parseArray() 274 case itemString: 275 s, err := strconv.Unquote(token.val) 276 if err != nil { 277 t.error(err) 278 } 279 n = newString(token.pos, token.val, s) 280 case itemNumber: 281 var err error 282 n, err = newNumber(token.pos, token.val) 283 if err != nil { 284 t.error(err) 285 } 286 case itemWord: 287 switch token.val { 288 case "TRUE": 289 n = newBool(token.pos, true) 290 case "FALSE": 291 n = newBool(token.pos, false) 292 case "instance": 293 t.backup() 294 n = t.parseInstance() 295 case "NULL": 296 n = newNil(token.pos) 297 default: 298 t.unexpected(token, context) 299 } 300 default: 301 t.unexpected(token, context) 302 } 303 return n 304} 305 306func (t *tree) parseInstance() *instanceNode { 307 const context = "instance" 308 token := t.expectWord("instance", context) 309 t.expectWord("of", context) 310 t.expect(itemWord, context) 311 t.expect(itemLeftBrace, context) 312 i := newInstance(token.pos) 313 for { 314 token := t.next() 315 switch token.typ { 316 case itemWord: 317 member := token.val 318 t.until(itemEq, context) 319 i.Members[member] = t.parseValue() 320 t.expect(itemSemi, context) 321 case itemRightBrace: 322 return i 323 default: 324 t.unexpected(token, context) 325 } 326 } 327} 328 329func (t *tree) parseArray() *arrayNode { 330 const context = "array" 331 token := t.expect(itemLeftBrace, context) 332 a := newArray(token.pos) 333Loop: 334 for { 335 token = t.next() 336 switch token.typ { 337 case itemRightBrace: 338 break Loop 339 default: 340 t.backup() 341 } 342 a.Array = append(a.Array, t.parseValue()) 343 if a.Array[0].Type() != a.Array[len(a.Array)-1].Type() { 344 t.errorf("unmatching types in array") 345 } 346 token = t.next() 347 switch token.typ { 348 case itemComma: 349 // continue 350 case itemRightBrace: 351 break Loop 352 default: 353 t.unexpected(token, context) 354 } 355 } 356 return a 357} 358