Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
95 lines
1.9 KiB
95 lines
1.9 KiB
// Copyright 2018 Frank Schroeder. All rights reserved. |
|
// Use of this source code is governed by a BSD-style |
|
// license that can be found in the LICENSE file. |
|
|
|
package properties |
|
|
|
import ( |
|
"fmt" |
|
"runtime" |
|
) |
|
|
|
type parser struct { |
|
lex *lexer |
|
} |
|
|
|
func parse(input string) (properties *Properties, err error) { |
|
p := &parser{lex: lex(input)} |
|
defer p.recover(&err) |
|
|
|
properties = NewProperties() |
|
key := "" |
|
comments := []string{} |
|
|
|
for { |
|
token := p.expectOneOf(itemComment, itemKey, itemEOF) |
|
switch token.typ { |
|
case itemEOF: |
|
goto done |
|
case itemComment: |
|
comments = append(comments, token.val) |
|
continue |
|
case itemKey: |
|
key = token.val |
|
if _, ok := properties.m[key]; !ok { |
|
properties.k = append(properties.k, key) |
|
} |
|
} |
|
|
|
token = p.expectOneOf(itemValue, itemEOF) |
|
if len(comments) > 0 { |
|
properties.c[key] = comments |
|
comments = []string{} |
|
} |
|
switch token.typ { |
|
case itemEOF: |
|
properties.m[key] = "" |
|
goto done |
|
case itemValue: |
|
properties.m[key] = token.val |
|
} |
|
} |
|
|
|
done: |
|
return properties, nil |
|
} |
|
|
|
func (p *parser) errorf(format string, args ...interface{}) { |
|
format = fmt.Sprintf("properties: Line %d: %s", p.lex.lineNumber(), format) |
|
panic(fmt.Errorf(format, args...)) |
|
} |
|
|
|
func (p *parser) expect(expected itemType) (token item) { |
|
token = p.lex.nextItem() |
|
if token.typ != expected { |
|
p.unexpected(token) |
|
} |
|
return token |
|
} |
|
|
|
func (p *parser) expectOneOf(expected ...itemType) (token item) { |
|
token = p.lex.nextItem() |
|
for _, v := range expected { |
|
if token.typ == v { |
|
return token |
|
} |
|
} |
|
p.unexpected(token) |
|
panic("unexpected token") |
|
} |
|
|
|
func (p *parser) unexpected(token item) { |
|
p.errorf(token.String()) |
|
} |
|
|
|
// recover is the handler that turns panics into returns from the top level of Parse. |
|
func (p *parser) recover(errp *error) { |
|
e := recover() |
|
if e != nil { |
|
if _, ok := e.(runtime.Error); ok { |
|
panic(e) |
|
} |
|
*errp = e.(error) |
|
} |
|
return |
|
}
|
|
|