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