aboutsummaryrefslogtreecommitdiff
path: root/src/urubu/grammar/lexical/parser/fragment.go
blob: 196c00b1f6dec9f74d90d420996e5a89d13afbea (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package parser

import (
	"fmt"

	spec "urubu/spec/grammar"
)

type incompleteFragment struct {
	kind spec.LexKindName
	root *rootNode
}

func CompleteFragments(fragments map[spec.LexKindName]CPTree) error {
	if len(fragments) == 0 {
		return nil
	}

	completeFragments := map[spec.LexKindName]CPTree{}
	incompleteFragments := []*incompleteFragment{}
	for kind, tree := range fragments {
		root, ok := tree.(*rootNode)
		if !ok {
			return fmt.Errorf("CompleteFragments can take only *rootNode: %T", tree)
		}
		if root.incomplete() {
			incompleteFragments = append(incompleteFragments, &incompleteFragment{
				kind: kind,
				root: root,
			})
		} else {
			completeFragments[kind] = root
		}
	}
	for len(incompleteFragments) > 0 {
		lastIncompCount := len(incompleteFragments)
		remainingFragments := []*incompleteFragment{}
		for _, e := range incompleteFragments {
			complete, err := ApplyFragments(e.root, completeFragments)
			if err != nil {
				return err
			}
			if !complete {
				remainingFragments = append(remainingFragments, e)
			} else {
				completeFragments[e.kind] = e.root
			}
		}
		incompleteFragments = remainingFragments
		if len(incompleteFragments) == lastIncompCount {
			return ParseErr
		}
	}

	return nil
}

func ApplyFragments(t CPTree, fragments map[spec.LexKindName]CPTree) (bool, error) {
	root, ok := t.(*rootNode)
	if !ok {
		return false, fmt.Errorf("ApplyFragments can take only *rootNode type: %T", t)
	}

	for name, frag := range fragments {
		err := root.applyFragment(name, frag)
		if err != nil {
			return false, err
		}
	}

	return !root.incomplete(), nil
}