/* 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 }