separate build phase for boot
This commit is contained in:
parent
1e7c0e8c28
commit
73585dd07d
92
boot_test.go
92
boot_test.go
@ -13,7 +13,7 @@ func TestBoot(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
f, err := os.Open("mml.parser")
|
||||
f, err := os.Open("syntax.parser")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
@ -23,6 +23,7 @@ func TestBoot(t *testing.T) {
|
||||
|
||||
var d time.Duration
|
||||
const n = 120
|
||||
var n0 *Node
|
||||
for i := 0; i < n; i++ {
|
||||
if _, err := f.Seek(0, 0); err != nil {
|
||||
t.Error(err)
|
||||
@ -30,10 +31,10 @@ func TestBoot(t *testing.T) {
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
_, err = b.Parse(f)
|
||||
n0, err = b.Parse(f)
|
||||
d += time.Now().Sub(start)
|
||||
|
||||
if err != ErrNotImplemented {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
@ -41,57 +42,52 @@ func TestBoot(t *testing.T) {
|
||||
|
||||
t.Log("duration:", d/n)
|
||||
|
||||
// if err != nil {
|
||||
// t.Error(err)
|
||||
// return
|
||||
// }
|
||||
s0 := NewSyntax()
|
||||
if err := define(s0, n0); err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
// s0 := NewSyntax()
|
||||
// if err := define(s0, n0); err != nil {
|
||||
// t.Error(err)
|
||||
// return
|
||||
// }
|
||||
_, err = f.Seek(0, 0)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
// _, err = f.Seek(0, 0)
|
||||
// if err != nil {
|
||||
// t.Error(err)
|
||||
// return
|
||||
// }
|
||||
err = s0.Init()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
// err = s0.Init()
|
||||
// if err != nil {
|
||||
// t.Error(err)
|
||||
// return
|
||||
// }
|
||||
n1, err := s0.Parse(f)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
// n1, err := s0.Parse(f)
|
||||
// if err != nil {
|
||||
// t.Error(err)
|
||||
// return
|
||||
// }
|
||||
checkNode(t, n1, n0)
|
||||
if t.Failed() {
|
||||
return
|
||||
}
|
||||
|
||||
// checkNode(t, n1, n0)
|
||||
// if t.Failed() {
|
||||
// return
|
||||
// }
|
||||
s1 := NewSyntax()
|
||||
if err := define(s1, n1); err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
// s1 := NewSyntax()
|
||||
// if err := define(s1, n1); err != nil {
|
||||
// t.Error(err)
|
||||
// return
|
||||
// }
|
||||
_, err = f.Seek(0, 0)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
// _, err = f.Seek(0, 0)
|
||||
// if err != nil {
|
||||
// t.Error(err)
|
||||
// return
|
||||
// }
|
||||
n2, err := s1.Parse(f)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
// n2, err := s1.Parse(f)
|
||||
// if err != nil {
|
||||
// t.Error(err)
|
||||
// return
|
||||
// }
|
||||
|
||||
// checkNode(t, n2, n1)
|
||||
checkNode(t, n2, n1)
|
||||
}
|
||||
|
66
choice.go
66
choice.go
@ -6,6 +6,7 @@ type choiceDefinition struct {
|
||||
commit CommitType
|
||||
elements []string
|
||||
includedBy []int
|
||||
cbuilder *choiceBuilder
|
||||
}
|
||||
|
||||
type choiceParser struct {
|
||||
@ -20,6 +21,7 @@ type choiceBuilder struct {
|
||||
name string
|
||||
id int
|
||||
commit CommitType
|
||||
elements []builder
|
||||
}
|
||||
|
||||
func newChoice(name string, ct CommitType, elements []string) *choiceDefinition {
|
||||
@ -36,6 +38,23 @@ func (d *choiceDefinition) setID(id int) { d.id = id }
|
||||
func (d *choiceDefinition) commitType() CommitType { return d.commit }
|
||||
|
||||
func (d *choiceDefinition) init(r *registry) error {
|
||||
if d.cbuilder == nil {
|
||||
d.cbuilder = &choiceBuilder{
|
||||
name: d.name,
|
||||
id: d.id,
|
||||
commit: d.commit,
|
||||
}
|
||||
}
|
||||
|
||||
for _, e := range d.elements {
|
||||
def, ok := r.definition(e)
|
||||
if !ok {
|
||||
return parserNotFound(e)
|
||||
}
|
||||
|
||||
d.cbuilder.elements = append(d.cbuilder.elements, def.builder())
|
||||
}
|
||||
|
||||
parsers := &idSet{}
|
||||
parsers.set(d.id)
|
||||
return setItemsIncludedBy(r, d.elements, d.id, parsers)
|
||||
@ -98,7 +117,15 @@ func (d *choiceDefinition) parser(r *registry, parsers *idSet) (parser, error) {
|
||||
}
|
||||
|
||||
func (d *choiceDefinition) builder() builder {
|
||||
return &choiceBuilder{}
|
||||
if d.cbuilder == nil {
|
||||
d.cbuilder = &choiceBuilder{
|
||||
name: d.name,
|
||||
id: d.id,
|
||||
commit: d.commit,
|
||||
}
|
||||
}
|
||||
|
||||
return d.cbuilder
|
||||
}
|
||||
|
||||
func (p *choiceParser) nodeName() string { return p.name }
|
||||
@ -170,6 +197,41 @@ func (p *choiceParser) parse(t Trace, c *context) {
|
||||
func (b *choiceBuilder) nodeName() string { return b.name }
|
||||
func (b *choiceBuilder) nodeID() int { return b.id }
|
||||
|
||||
func (b *choiceBuilder) build(*context) ([]*Node, bool) {
|
||||
func (b *choiceBuilder) build(c *context) ([]*Node, bool) {
|
||||
to, ok := c.store.takeMatch(c.offset, b.id)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
var element builder
|
||||
for _, e := range b.elements {
|
||||
elementTo, match, _ := c.store.getMatch(c.offset, e.nodeID())
|
||||
if match && elementTo == to {
|
||||
element = e
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if element == nil {
|
||||
panic("damaged parse result")
|
||||
}
|
||||
|
||||
from := c.offset
|
||||
|
||||
n, ok := element.build(c)
|
||||
if !ok {
|
||||
panic("damaged parse result")
|
||||
}
|
||||
|
||||
if b.commit&Alias != 0 {
|
||||
return n, true
|
||||
}
|
||||
|
||||
return []*Node{{
|
||||
Name: b.name,
|
||||
From: from,
|
||||
To: to,
|
||||
Nodes: n,
|
||||
tokens: c.tokens,
|
||||
}}, true
|
||||
}
|
||||
|
@ -145,8 +145,5 @@ func (c *context) finalize(root parser) error {
|
||||
}
|
||||
}
|
||||
|
||||
return ErrNotImplemented
|
||||
|
||||
c.node.commit(c.tokens)
|
||||
return nil
|
||||
}
|
||||
|
20
parse.go
20
parse.go
@ -73,19 +73,29 @@ func sequenceItemNames(items []SequenceItem) []string {
|
||||
return names
|
||||
}
|
||||
|
||||
func parse(t Trace, p parser, c *context) (*Node, error) {
|
||||
func parse(t Trace, p parser, c *context) error {
|
||||
p.parse(t, c)
|
||||
if c.readErr != nil {
|
||||
return nil, c.readErr
|
||||
return c.readErr
|
||||
}
|
||||
|
||||
if !c.match {
|
||||
return nil, ErrInvalidInput
|
||||
return ErrInvalidInput
|
||||
}
|
||||
|
||||
if err := c.finalize(p); err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
return c.node, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func build(b builder, c *context) *Node {
|
||||
c.offset = 0
|
||||
n, ok := b.build(c)
|
||||
if !ok || len(n) != 1 {
|
||||
panic("damaged parse result")
|
||||
}
|
||||
|
||||
return n[0]
|
||||
}
|
||||
|
99
sequence.go
99
sequence.go
@ -6,6 +6,8 @@ type sequenceDefinition struct {
|
||||
commit CommitType
|
||||
items []SequenceItem
|
||||
includedBy []int
|
||||
ranges [][]int
|
||||
sbuilder *sequenceBuilder
|
||||
}
|
||||
|
||||
type sequenceParser struct {
|
||||
@ -21,6 +23,8 @@ type sequenceBuilder struct {
|
||||
name string
|
||||
id int
|
||||
commit CommitType
|
||||
items []builder
|
||||
ranges [][]int
|
||||
}
|
||||
|
||||
func newSequence(name string, ct CommitType, items []SequenceItem) *sequenceDefinition {
|
||||
@ -41,14 +45,33 @@ func (d *sequenceDefinition) includeItems() bool {
|
||||
}
|
||||
|
||||
func (d *sequenceDefinition) init(r *registry) error {
|
||||
if d.sbuilder == nil {
|
||||
d.sbuilder = &sequenceBuilder{
|
||||
name: d.name,
|
||||
id: d.id,
|
||||
commit: d.commit,
|
||||
}
|
||||
}
|
||||
|
||||
for _, item := range d.items {
|
||||
if item.Min == 0 && item.Max == 0 {
|
||||
item.Min, item.Max = 1, 1
|
||||
} else if item.Max == 0 {
|
||||
item.Max = -1
|
||||
}
|
||||
|
||||
d.ranges = append(d.ranges, []int{item.Min, item.Max})
|
||||
|
||||
def, ok := r.definition(item.Name)
|
||||
if !ok {
|
||||
return parserNotFound(item.Name)
|
||||
}
|
||||
|
||||
d.sbuilder.items = append(d.sbuilder.items, def.builder())
|
||||
}
|
||||
|
||||
d.sbuilder.ranges = d.ranges
|
||||
|
||||
if !d.includeItems() {
|
||||
return nil
|
||||
}
|
||||
@ -92,24 +115,13 @@ func (d *sequenceDefinition) parser(r *registry, parsers *idSet) (parser, error)
|
||||
|
||||
r.setParser(sp)
|
||||
|
||||
var (
|
||||
items []parser
|
||||
ranges [][]int
|
||||
)
|
||||
|
||||
var items []parser
|
||||
parsers.set(d.id)
|
||||
defer parsers.unset(d.id)
|
||||
for _, item := range d.items {
|
||||
if item.Min == 0 && item.Max == 0 {
|
||||
item.Min, item.Max = 1, 1
|
||||
} else if item.Max == 0 {
|
||||
item.Max = -1
|
||||
}
|
||||
|
||||
pi, ok := r.parser(item.Name)
|
||||
if ok {
|
||||
items = append(items, pi)
|
||||
ranges = append(ranges, []int{item.Min, item.Max})
|
||||
continue
|
||||
}
|
||||
|
||||
@ -124,16 +136,23 @@ func (d *sequenceDefinition) parser(r *registry, parsers *idSet) (parser, error)
|
||||
}
|
||||
|
||||
items = append(items, pi)
|
||||
ranges = append(ranges, []int{item.Min, item.Max})
|
||||
}
|
||||
|
||||
sp.items = items
|
||||
sp.ranges = ranges
|
||||
sp.ranges = d.ranges
|
||||
return sp, nil
|
||||
}
|
||||
|
||||
func (d *sequenceDefinition) builder() builder {
|
||||
return &sequenceBuilder{}
|
||||
if d.sbuilder == nil {
|
||||
d.sbuilder = &sequenceBuilder{
|
||||
name: d.name,
|
||||
id: d.id,
|
||||
commit: d.commit,
|
||||
}
|
||||
}
|
||||
|
||||
return d.sbuilder
|
||||
}
|
||||
|
||||
func (p *sequenceParser) nodeName() string { return p.name }
|
||||
@ -162,6 +181,7 @@ func (p *sequenceParser) parse(t Trace, c *context) {
|
||||
to := c.offset
|
||||
|
||||
for itemIndex < len(p.items) {
|
||||
// TODO: is it ok to parse before max range check? what if max=0
|
||||
p.items[itemIndex].parse(t, c)
|
||||
if !c.match {
|
||||
if currentCount < p.ranges[itemIndex][0] {
|
||||
@ -201,6 +221,53 @@ func (p *sequenceParser) parse(t Trace, c *context) {
|
||||
func (b *sequenceBuilder) nodeName() string { return b.name }
|
||||
func (b *sequenceBuilder) nodeID() int { return b.id }
|
||||
|
||||
func (b *sequenceBuilder) build(*context) ([]*Node, bool) {
|
||||
func (b *sequenceBuilder) build(c *context) ([]*Node, bool) {
|
||||
to, ok := c.store.takeMatch(c.offset, b.id)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
from := c.offset
|
||||
var (
|
||||
itemIndex int
|
||||
currentCount int
|
||||
nodes []*Node
|
||||
)
|
||||
|
||||
for itemIndex < len(b.items) {
|
||||
itemFrom := c.offset
|
||||
n, ok := b.items[itemIndex].build(c)
|
||||
if !ok {
|
||||
if currentCount < b.ranges[itemIndex][0] {
|
||||
panic("damaged parse result")
|
||||
}
|
||||
|
||||
itemIndex++
|
||||
currentCount = 0
|
||||
continue
|
||||
}
|
||||
|
||||
parsed := c.offset > itemFrom
|
||||
if parsed {
|
||||
nodes = append(nodes, n...)
|
||||
currentCount++
|
||||
}
|
||||
|
||||
if !parsed || b.ranges[itemIndex][1] >= 0 && currentCount == b.ranges[itemIndex][1] {
|
||||
itemIndex++
|
||||
currentCount = 0
|
||||
}
|
||||
}
|
||||
|
||||
if b.commit&Alias != 0 {
|
||||
return nodes, true
|
||||
}
|
||||
|
||||
return []*Node{{
|
||||
Name: b.name,
|
||||
From: from,
|
||||
To: to,
|
||||
Nodes: nodes,
|
||||
tokens: c.tokens,
|
||||
}}, true
|
||||
}
|
||||
|
42
store.go
42
store.go
@ -24,7 +24,7 @@ func (s *store) getMatch(offset, id int) (int, bool, bool) {
|
||||
|
||||
var (
|
||||
found bool
|
||||
length int
|
||||
to int
|
||||
)
|
||||
|
||||
for i := 0; i < len(s.match[offset]); i += 2 {
|
||||
@ -33,12 +33,46 @@ func (s *store) getMatch(offset, id int) (int, bool, bool) {
|
||||
}
|
||||
|
||||
found = true
|
||||
if s.match[offset][i+1] > length {
|
||||
length = s.match[offset][i+1]
|
||||
if s.match[offset][i+1] > to {
|
||||
to = s.match[offset][i+1]
|
||||
}
|
||||
}
|
||||
|
||||
return length, found, found
|
||||
return to, found, found
|
||||
}
|
||||
|
||||
func (s *store) takeMatch(offset, id int) (int, bool) {
|
||||
if s.hasNoMatch(offset, id) {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
if len(s.match) <= offset {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
var (
|
||||
found bool
|
||||
to int
|
||||
index int
|
||||
)
|
||||
|
||||
for i := 0; i < len(s.match[offset]); i += 2 {
|
||||
if s.match[offset][i] != id {
|
||||
continue
|
||||
}
|
||||
|
||||
found = true
|
||||
if s.match[offset][i+1] > to {
|
||||
to = s.match[offset][i+1]
|
||||
index = i
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
s.match[offset][index] = -1
|
||||
}
|
||||
|
||||
return to, found
|
||||
}
|
||||
|
||||
func (s *store) ensureOffset(offset int) {
|
||||
|
@ -29,6 +29,7 @@ type Syntax struct {
|
||||
explicitRoot bool
|
||||
root definition
|
||||
parser parser
|
||||
builder builder
|
||||
}
|
||||
|
||||
var (
|
||||
@ -154,6 +155,7 @@ func (s *Syntax) Init() error {
|
||||
return err
|
||||
}
|
||||
|
||||
s.builder = s.root.builder()
|
||||
s.initialized = true
|
||||
return nil
|
||||
}
|
||||
@ -174,5 +176,9 @@ func (s *Syntax) Parse(r io.Reader) (*Node, error) {
|
||||
}
|
||||
|
||||
c := newContext(bufio.NewReader(r))
|
||||
return parse(s.trace, s.parser, c)
|
||||
if err := parse(s.trace, s.parser, c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return build(s.builder, c), nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user