separate build phase for boot

This commit is contained in:
Arpad Ryszka 2017-07-29 18:40:22 +02:00
parent 1e7c0e8c28
commit 73585dd07d
8 changed files with 268 additions and 96 deletions

View File

@ -13,7 +13,7 @@ func TestBoot(t *testing.T) {
return return
} }
f, err := os.Open("mml.parser") f, err := os.Open("syntax.parser")
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return
@ -23,6 +23,7 @@ func TestBoot(t *testing.T) {
var d time.Duration var d time.Duration
const n = 120 const n = 120
var n0 *Node
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
if _, err := f.Seek(0, 0); err != nil { if _, err := f.Seek(0, 0); err != nil {
t.Error(err) t.Error(err)
@ -30,10 +31,10 @@ func TestBoot(t *testing.T) {
} }
start := time.Now() start := time.Now()
_, err = b.Parse(f) n0, err = b.Parse(f)
d += time.Now().Sub(start) d += time.Now().Sub(start)
if err != ErrNotImplemented { if err != nil {
t.Error(err) t.Error(err)
return return
} }
@ -41,57 +42,52 @@ func TestBoot(t *testing.T) {
t.Log("duration:", d/n) t.Log("duration:", d/n)
// if err != nil { s0 := NewSyntax()
// t.Error(err) if err := define(s0, n0); err != nil {
// return t.Error(err)
// } return
}
// s0 := NewSyntax() _, err = f.Seek(0, 0)
// if err := define(s0, n0); err != nil { if err != nil {
// t.Error(err) t.Error(err)
// return return
// } }
// _, err = f.Seek(0, 0) err = s0.Init()
// if err != nil { if err != nil {
// t.Error(err) t.Error(err)
// return return
// } }
// err = s0.Init() n1, err := s0.Parse(f)
// if err != nil { if err != nil {
// t.Error(err) t.Error(err)
// return return
// } }
// n1, err := s0.Parse(f) checkNode(t, n1, n0)
// if err != nil { if t.Failed() {
// t.Error(err) return
// return }
// }
// checkNode(t, n1, n0) s1 := NewSyntax()
// if t.Failed() { if err := define(s1, n1); err != nil {
// return t.Error(err)
// } return
}
// s1 := NewSyntax() _, err = f.Seek(0, 0)
// if err := define(s1, n1); err != nil { if err != nil {
// t.Error(err) t.Error(err)
// return return
// } }
// _, err = f.Seek(0, 0) n2, err := s1.Parse(f)
// if err != nil { if err != nil {
// t.Error(err) t.Error(err)
// return return
// } }
// n2, err := s1.Parse(f) checkNode(t, n2, n1)
// if err != nil {
// t.Error(err)
// return
// }
// checkNode(t, n2, n1)
} }

View File

@ -23,9 +23,9 @@ func newChar(
} }
} }
func (p *charParser) nodeName() string { return p.name } func (p *charParser) nodeName() string { return p.name }
func (p *charParser) nodeID() int { return p.id } func (p *charParser) nodeID() int { return p.id }
func (p *charParser) setID(id int) { p.id = id } func (p *charParser) setID(id int) { p.id = id }
func (p *charParser) commitType() CommitType { return Alias } func (p *charParser) commitType() CommitType { return Alias }
func (p *charParser) init(r *registry) error { return nil } func (p *charParser) init(r *registry) error { return nil }

View File

@ -6,6 +6,7 @@ type choiceDefinition struct {
commit CommitType commit CommitType
elements []string elements []string
includedBy []int includedBy []int
cbuilder *choiceBuilder
} }
type choiceParser struct { type choiceParser struct {
@ -17,9 +18,10 @@ type choiceParser struct {
} }
type choiceBuilder struct { type choiceBuilder struct {
name string name string
id int id int
commit CommitType commit CommitType
elements []builder
} }
func newChoice(name string, ct CommitType, elements []string) *choiceDefinition { func newChoice(name string, ct CommitType, elements []string) *choiceDefinition {
@ -30,12 +32,29 @@ func newChoice(name string, ct CommitType, elements []string) *choiceDefinition
} }
} }
func (d *choiceDefinition) nodeName() string { return d.name } func (d *choiceDefinition) nodeName() string { return d.name }
func (d *choiceDefinition) nodeID() int { return d.id } func (d *choiceDefinition) nodeID() int { return d.id }
func (d *choiceDefinition) setID(id int) { d.id = id } func (d *choiceDefinition) setID(id int) { d.id = id }
func (d *choiceDefinition) commitType() CommitType { return d.commit } func (d *choiceDefinition) commitType() CommitType { return d.commit }
func (d *choiceDefinition) init(r *registry) error { 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 := &idSet{}
parsers.set(d.id) parsers.set(d.id)
return setItemsIncludedBy(r, d.elements, d.id, parsers) 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 { 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 } 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) nodeName() string { return b.name }
func (b *choiceBuilder) nodeID() int { return b.id } func (b *choiceBuilder) nodeID() int { return b.id }
func (b *choiceBuilder) build(*context) ([]*Node, bool) { func (b *choiceBuilder) build(c *context) ([]*Node, bool) {
return nil, false 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
} }

View File

@ -145,8 +145,5 @@ func (c *context) finalize(root parser) error {
} }
} }
return ErrNotImplemented
c.node.commit(c.tokens)
return nil return nil
} }

View File

@ -73,19 +73,29 @@ func sequenceItemNames(items []SequenceItem) []string {
return names 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) p.parse(t, c)
if c.readErr != nil { if c.readErr != nil {
return nil, c.readErr return c.readErr
} }
if !c.match { if !c.match {
return nil, ErrInvalidInput return ErrInvalidInput
} }
if err := c.finalize(p); err != nil { 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]
} }

View File

@ -6,6 +6,8 @@ type sequenceDefinition struct {
commit CommitType commit CommitType
items []SequenceItem items []SequenceItem
includedBy []int includedBy []int
ranges [][]int
sbuilder *sequenceBuilder
} }
type sequenceParser struct { type sequenceParser struct {
@ -18,9 +20,11 @@ type sequenceParser struct {
} }
type sequenceBuilder struct { type sequenceBuilder struct {
name string name string
id int id int
commit CommitType commit CommitType
items []builder
ranges [][]int
} }
func newSequence(name string, ct CommitType, items []SequenceItem) *sequenceDefinition { func newSequence(name string, ct CommitType, items []SequenceItem) *sequenceDefinition {
@ -31,9 +35,9 @@ func newSequence(name string, ct CommitType, items []SequenceItem) *sequenceDefi
} }
} }
func (d *sequenceDefinition) nodeName() string { return d.name } func (d *sequenceDefinition) nodeName() string { return d.name }
func (d *sequenceDefinition) nodeID() int { return d.id } func (d *sequenceDefinition) nodeID() int { return d.id }
func (d *sequenceDefinition) setID(id int) { d.id = id } func (d *sequenceDefinition) setID(id int) { d.id = id }
func (d *sequenceDefinition) commitType() CommitType { return d.commit } func (d *sequenceDefinition) commitType() CommitType { return d.commit }
func (d *sequenceDefinition) includeItems() bool { func (d *sequenceDefinition) includeItems() bool {
@ -41,14 +45,33 @@ func (d *sequenceDefinition) includeItems() bool {
} }
func (d *sequenceDefinition) init(r *registry) error { 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 { for _, item := range d.items {
if item.Min == 0 && item.Max == 0 { if item.Min == 0 && item.Max == 0 {
item.Min, item.Max = 1, 1 item.Min, item.Max = 1, 1
} else if item.Max == 0 { } else if item.Max == 0 {
item.Max = -1 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() { if !d.includeItems() {
return nil return nil
} }
@ -92,24 +115,13 @@ func (d *sequenceDefinition) parser(r *registry, parsers *idSet) (parser, error)
r.setParser(sp) r.setParser(sp)
var ( var items []parser
items []parser
ranges [][]int
)
parsers.set(d.id) parsers.set(d.id)
defer parsers.unset(d.id) defer parsers.unset(d.id)
for _, item := range d.items { 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) pi, ok := r.parser(item.Name)
if ok { if ok {
items = append(items, pi) items = append(items, pi)
ranges = append(ranges, []int{item.Min, item.Max})
continue continue
} }
@ -124,16 +136,23 @@ func (d *sequenceDefinition) parser(r *registry, parsers *idSet) (parser, error)
} }
items = append(items, pi) items = append(items, pi)
ranges = append(ranges, []int{item.Min, item.Max})
} }
sp.items = items sp.items = items
sp.ranges = ranges sp.ranges = d.ranges
return sp, nil return sp, nil
} }
func (d *sequenceDefinition) builder() builder { 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 } func (p *sequenceParser) nodeName() string { return p.name }
@ -162,6 +181,7 @@ func (p *sequenceParser) parse(t Trace, c *context) {
to := c.offset to := c.offset
for itemIndex < len(p.items) { 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) p.items[itemIndex].parse(t, c)
if !c.match { if !c.match {
if currentCount < p.ranges[itemIndex][0] { 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) nodeName() string { return b.name }
func (b *sequenceBuilder) nodeID() int { return b.id } func (b *sequenceBuilder) nodeID() int { return b.id }
func (b *sequenceBuilder) build(*context) ([]*Node, bool) { func (b *sequenceBuilder) build(c *context) ([]*Node, bool) {
return nil, false 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
} }

View File

@ -23,8 +23,8 @@ func (s *store) getMatch(offset, id int) (int, bool, bool) {
} }
var ( var (
found bool found bool
length int to int
) )
for i := 0; i < len(s.match[offset]); i += 2 { 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 found = true
if s.match[offset][i+1] > length { if s.match[offset][i+1] > to {
length = s.match[offset][i+1] 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) { func (s *store) ensureOffset(offset int) {

View File

@ -29,6 +29,7 @@ type Syntax struct {
explicitRoot bool explicitRoot bool
root definition root definition
parser parser parser parser
builder builder
} }
var ( var (
@ -154,6 +155,7 @@ func (s *Syntax) Init() error {
return err return err
} }
s.builder = s.root.builder()
s.initialized = true s.initialized = true
return nil return nil
} }
@ -174,5 +176,9 @@ func (s *Syntax) Parse(r io.Reader) (*Node, error) {
} }
c := newContext(bufio.NewReader(r)) 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
} }