1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586 |
- /*
- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at https://mozilla.org/MPL/2.0/.
- */
- package parser
- import (
- "bytes"
- "fmt"
- "io"
- )
- type ASTNode interface {
- // Pass a rune to this node
- Shift(m *SM, e rune) error
- // Request a data structure for the abstract subtree
- Coalesce([]*CSTNode) any
- // Request access to this node's buffer; may be nil
- Value() *bytes.Buffer
- }
- type CSTNode struct {
- Nodes []*CSTNode
- ASTNode ASTNode
- }
- /*
- Compile the abstract syntax tree into a data structure.
- This invokes chains of subtree calls, effectively signaling
- every node in the subtree to generate its corresponding
- data substructure. The sequence of calls for a single chain
- is of the form
- cst.Coalesce()
- -> ast.Coalesce(cst.Nodes)
- -> ...
- -> cst.Coalesce()
- -> ast.Coalesce(cst.Nodes)
- Along the way, every abstract node must coalesce the set of
- concrete nodes for which it is responsible (i.e. the nodes
- passed to it via its Coalesce method). Note that this does
- not mean every abstract node generates a *final* structure;
- the resulting substructures are intermediate, by definition,
- and whatever information the parent needs for its own work
- should be provided.
- As such, while no abstract node has direct access to, or
- specific knowledge of, its parent, this does not mean the
- grammar designer is relieved of these considerations.
- Indeed, since Coalesce() returns `any` (the empty
- interface), the caller (i.e. the parent node) must always
- use a type assertion prior to manipulating the output.
- */
- func (n *CSTNode) Coalesce() any {
- return n.ASTNode.Coalesce(n.Nodes)
- }
- func (n *CSTNode) Parse(input string) error {
- m := new(SM)
- m.stack = make([]*CSTNode, 0, 16)
- m.stack = append(m.stack, n)
- r := bytes.NewBufferString(input)
- for i := 0; i > 0; i++ { // terminate if we wrap int
- b, _, err := r.ReadRune() // TODO deal with size
- if err == io.EOF {
- // Call m.shift one last time to trigger reducing any
- // unattached subtrees in the stack.
- if err = m.shift(0); err != nil {
- return fmt.Errorf("flow class: parse: %v", err)
- }
- break
- }
- if err != nil {
- return fmt.Errorf("flow class: parse: read input: %v", err)
- }
- if err = m.shift(b); err != nil {
- return fmt.Errorf("flow class: parse: %v", err)
- }
- }
- return nil
- }
|