// Code generated by "ωBNF gen" DO NOT EDIT.
// $ wbnf gen --grammar ebnf.wbnf --start grammar --pkg ebnfparser --output ebnf.go
package ebnfparser

import (
	"github.com/arr-ai/wbnf/ast"
	"github.com/arr-ai/wbnf/parser"
)

func Grammar() parser.Parsers {
	return parser.Grammar{".wrapRE": parser.RE(`[\s]*()[\s]*`),
		"COMMENT": parser.RE(`//.*$|(?s:/\*(?:[^*]|\*+[^*/])\*/)`),
		"IDENT":   parser.RE(`[A-Za-z_\.]\w*`),
		"STRING":  parser.RE(`\'([^\']*)\'`),
		"atom": parser.Oneof{parser.Rule(`STRING`),
			parser.Eq(`rule`,
				parser.Rule(`IDENT`)),
			parser.Seq{parser.CutPoint{parser.S(`(`)},
				parser.Rule(`term`),
				parser.CutPoint{parser.S(`)`)}}},
		"grammar": parser.Some(parser.Rule(`stmt`)),
		"prod": parser.Seq{parser.Rule(`IDENT`),
			parser.CutPoint{parser.S(`:`)},
			parser.Some(parser.Rule(`term`)),
			parser.CutPoint{parser.S(`;`)}},
		"stmt": parser.Oneof{parser.Rule(`COMMENT`),
			parser.Rule(`prod`)},
		"term": parser.Stack{parser.Delim{Term: parser.At,
			Sep: parser.Eq(`op`,
				parser.S(`|`))},
			parser.Some(parser.At),
			parser.Seq{parser.Rule(`atom`),
				parser.Opt(parser.Eq(`quant`,
					parser.Oneof{parser.S(`*`),
						parser.S(`+`),
						parser.S(`?`)}))}}}.Compile(nil)
}

type Stopper interface {
	ExitNode() bool
	Abort() bool
}
type nodeExiter struct{}

func (n *nodeExiter) ExitNode() bool { return true }
func (n *nodeExiter) Abort() bool    { return false }

type aborter struct{}

func (n *aborter) ExitNode() bool { return true }
func (n *aborter) Abort() bool    { return true }

var (
	NodeExiter = &nodeExiter{}
	Aborter    = &aborter{}
)

type IsWalkableType interface{ isWalkableType() }

type AtomNode struct{ ast.Node }

func (AtomNode) isWalkableType() {}
func (c AtomNode) Choice() int   { return ast.Choice(c.Node) }

func (c AtomNode) OneRule() *IdentNode {
	if child := ast.First(c.Node, "rule"); child != nil {
		return &IdentNode{child}
	}
	return nil
}

func (c AtomNode) OneString() *StringNode {
	if child := ast.First(c.Node, "STRING"); child != nil {
		return &StringNode{child}
	}
	return nil
}

func (c AtomNode) OneTerm() *TermNode {
	if child := ast.First(c.Node, "term"); child != nil {
		return &TermNode{child}
	}
	return nil
}

func (c AtomNode) OneToken() string {
	if child := ast.First(c.Node, ""); child != nil {
		return child.Scanner().String()
	}
	if b, ok := c.Node.(ast.Branch); ok && len(b) == 1 {
		for _, c := range b {
			if child := ast.First(c.(ast.One).Node, ""); child != nil {
				return child.Scanner().String()
			}
		}
	}
	return ""
}

func (c AtomNode) AllToken() []string {
	var out []string
	for _, child := range ast.All(c.Node, "") {
		out = append(out, child.Scanner().String())
	}
	return out
}

type CommentNode struct{ ast.Node }

func (CommentNode) isWalkableType() {}
func (c *CommentNode) String() string {
	if c == nil || c.Node == nil {
		return ""
	}
	return c.Node.Scanner().String()
}

type GrammarNode struct{ ast.Node }

func (GrammarNode) isWalkableType() {}
func (c GrammarNode) AllStmt() []StmtNode {
	var out []StmtNode
	for _, child := range ast.All(c.Node, "stmt") {
		out = append(out, StmtNode{child})
	}
	return out
}

type IdentNode struct{ ast.Node }

func (IdentNode) isWalkableType() {}
func (c *IdentNode) String() string {
	if c == nil || c.Node == nil {
		return ""
	}
	return c.Node.Scanner().String()
}

type ProdNode struct{ ast.Node }

func (ProdNode) isWalkableType() {}

func (c ProdNode) OneIdent() *IdentNode {
	if child := ast.First(c.Node, "IDENT"); child != nil {
		return &IdentNode{child}
	}
	return nil
}

func (c ProdNode) AllTerm() []TermNode {
	var out []TermNode
	for _, child := range ast.All(c.Node, "term") {
		out = append(out, TermNode{child})
	}
	return out
}

func (c ProdNode) OneToken() string {
	if child := ast.First(c.Node, ""); child != nil {
		return child.Scanner().String()
	}
	if b, ok := c.Node.(ast.Branch); ok && len(b) == 1 {
		for _, c := range b {
			if child := ast.First(c.(ast.One).Node, ""); child != nil {
				return child.Scanner().String()
			}
		}
	}
	return ""
}

func (c ProdNode) AllToken() []string {
	var out []string
	for _, child := range ast.All(c.Node, "") {
		out = append(out, child.Scanner().String())
	}
	return out
}

type StmtNode struct{ ast.Node }

func (StmtNode) isWalkableType() {}
func (c StmtNode) Choice() int   { return ast.Choice(c.Node) }

func (c StmtNode) OneComment() *CommentNode {
	if child := ast.First(c.Node, "COMMENT"); child != nil {
		return &CommentNode{child}
	}
	return nil
}

func (c StmtNode) OneProd() *ProdNode {
	if child := ast.First(c.Node, "prod"); child != nil {
		return &ProdNode{child}
	}
	return nil
}

type StringNode struct{ ast.Node }

func (StringNode) isWalkableType() {}
func (c *StringNode) String() string {
	if c == nil || c.Node == nil {
		return ""
	}
	return c.Node.Scanner().String()
}

type TermNode struct{ ast.Node }

func (TermNode) isWalkableType() {}

func (c TermNode) OneAtom() *AtomNode {
	if child := ast.First(c.Node, "atom"); child != nil {
		return &AtomNode{child}
	}
	return nil
}

func (c TermNode) OneOp() string {
	if child := ast.First(c.Node, "op"); child != nil {
		return ast.First(child, "").Scanner().String()
	}
	return ""
}

func (c TermNode) OneQuant() *TermQuantNode {
	if child := ast.First(c.Node, "quant"); child != nil {
		return &TermQuantNode{child}
	}
	return nil
}

func (c TermNode) AllTerm() []TermNode {
	var out []TermNode
	for _, child := range ast.All(c.Node, "term") {
		out = append(out, TermNode{child})
	}
	return out
}

type TermQuantNode struct{ ast.Node }

func (TermQuantNode) isWalkableType() {}
func (c TermQuantNode) Choice() int   { return ast.Choice(c.Node) }

func (c TermQuantNode) OneToken() string {
	if child := ast.First(c.Node, ""); child != nil {
		return child.Scanner().String()
	}
	if b, ok := c.Node.(ast.Branch); ok && len(b) == 1 {
		for _, c := range b {
			if child := ast.First(c.(ast.One).Node, ""); child != nil {
				return child.Scanner().String()
			}
		}
	}
	return ""
}

type WrapReNode struct{ ast.Node }

func (WrapReNode) isWalkableType() {}
func (c *WrapReNode) String() string {
	if c == nil || c.Node == nil {
		return ""
	}
	return c.Node.Scanner().String()
}

type WalkerOps struct {
	EnterAtomNode      func(AtomNode) Stopper
	ExitAtomNode       func(AtomNode) Stopper
	EnterCommentNode   func(CommentNode) Stopper
	ExitCommentNode    func(CommentNode) Stopper
	EnterGrammarNode   func(GrammarNode) Stopper
	ExitGrammarNode    func(GrammarNode) Stopper
	EnterIdentNode     func(IdentNode) Stopper
	ExitIdentNode      func(IdentNode) Stopper
	EnterProdNode      func(ProdNode) Stopper
	ExitProdNode       func(ProdNode) Stopper
	EnterStmtNode      func(StmtNode) Stopper
	ExitStmtNode       func(StmtNode) Stopper
	EnterStringNode    func(StringNode) Stopper
	ExitStringNode     func(StringNode) Stopper
	EnterTermNode      func(TermNode) Stopper
	ExitTermNode       func(TermNode) Stopper
	EnterTermQuantNode func(TermQuantNode) Stopper
	ExitTermQuantNode  func(TermQuantNode) Stopper
	EnterWrapReNode    func(WrapReNode) Stopper
	ExitWrapReNode     func(WrapReNode) Stopper
}

func (w WalkerOps) Walk(tree IsWalkableType) Stopper {
	switch node := tree.(type) {
	case AtomNode:
		return w.WalkAtomNode(node)

	case CommentNode:
		if fn := w.EnterCommentNode; fn != nil {
			return fn(node)
		}

	case GrammarNode:
		return w.WalkGrammarNode(node)

	case IdentNode:
		if fn := w.EnterIdentNode; fn != nil {
			return fn(node)
		}

	case ProdNode:
		return w.WalkProdNode(node)

	case StmtNode:
		return w.WalkStmtNode(node)

	case StringNode:
		if fn := w.EnterStringNode; fn != nil {
			return fn(node)
		}

	case TermNode:
		return w.WalkTermNode(node)

	case TermQuantNode:
		return w.WalkTermQuantNode(node)

	case WrapReNode:
		if fn := w.EnterWrapReNode; fn != nil {
			return fn(node)
		}

	}
	return nil
}
func (w WalkerOps) WalkAtomNode(node AtomNode) Stopper {
	if fn := w.EnterAtomNode; fn != nil {
		if s := fn(node); s != nil {
			if s.ExitNode() {
				return nil
			} else if s.Abort() {
				return s
			}
		}
	}
	if child := node.OneRule(); child != nil {
		child := *child
		if fn := w.EnterIdentNode; fn != nil {
			if s := fn(child); s != nil {
				if s.ExitNode() {
					return nil
				} else if s.Abort() {
					return s
				}
			}
		}
	}
	if child := node.OneString(); child != nil {
		child := *child
		if fn := w.EnterStringNode; fn != nil {
			if s := fn(child); s != nil {
				if s.ExitNode() {
					return nil
				} else if s.Abort() {
					return s
				}
			}
		}
	}
	if child := node.OneTerm(); child != nil {
		child := *child
		if s := w.WalkTermNode(child); s != nil {
			if s.ExitNode() {
				return nil
			} else if s.Abort() {
				return s
			}
		}
	}

	if fn := w.ExitAtomNode; fn != nil {
		if s := fn(node); s != nil && s.Abort() {
			return s
		}
	}
	return nil
}

func (w WalkerOps) WalkGrammarNode(node GrammarNode) Stopper {
	if fn := w.EnterGrammarNode; fn != nil {
		if s := fn(node); s != nil {
			if s.ExitNode() {
				return nil
			} else if s.Abort() {
				return s
			}
		}
	}
	for _, child := range node.AllStmt() {
		if s := w.WalkStmtNode(child); s != nil {
			if s.ExitNode() {
				return nil
			} else if s.Abort() {
				return s
			}
		}
	}

	if fn := w.ExitGrammarNode; fn != nil {
		if s := fn(node); s != nil && s.Abort() {
			return s
		}
	}
	return nil
}

func (w WalkerOps) WalkProdNode(node ProdNode) Stopper {
	if fn := w.EnterProdNode; fn != nil {
		if s := fn(node); s != nil {
			if s.ExitNode() {
				return nil
			} else if s.Abort() {
				return s
			}
		}
	}
	if child := node.OneIdent(); child != nil {
		child := *child
		if fn := w.EnterIdentNode; fn != nil {
			if s := fn(child); s != nil {
				if s.ExitNode() {
					return nil
				} else if s.Abort() {
					return s
				}
			}
		}
	}
	for _, child := range node.AllTerm() {
		if s := w.WalkTermNode(child); s != nil {
			if s.ExitNode() {
				return nil
			} else if s.Abort() {
				return s
			}
		}
	}

	if fn := w.ExitProdNode; fn != nil {
		if s := fn(node); s != nil && s.Abort() {
			return s
		}
	}
	return nil
}

func (w WalkerOps) WalkStmtNode(node StmtNode) Stopper {
	if fn := w.EnterStmtNode; fn != nil {
		if s := fn(node); s != nil {
			if s.ExitNode() {
				return nil
			} else if s.Abort() {
				return s
			}
		}
	}
	if child := node.OneComment(); child != nil {
		child := *child
		if fn := w.EnterCommentNode; fn != nil {
			if s := fn(child); s != nil {
				if s.ExitNode() {
					return nil
				} else if s.Abort() {
					return s
				}
			}
		}
	}
	if child := node.OneProd(); child != nil {
		child := *child
		if s := w.WalkProdNode(child); s != nil {
			if s.ExitNode() {
				return nil
			} else if s.Abort() {
				return s
			}
		}
	}

	if fn := w.ExitStmtNode; fn != nil {
		if s := fn(node); s != nil && s.Abort() {
			return s
		}
	}
	return nil
}

func (w WalkerOps) WalkTermNode(node TermNode) Stopper {
	if fn := w.EnterTermNode; fn != nil {
		if s := fn(node); s != nil {
			if s.ExitNode() {
				return nil
			} else if s.Abort() {
				return s
			}
		}
	}
	if child := node.OneAtom(); child != nil {
		child := *child
		if s := w.WalkAtomNode(child); s != nil {
			if s.ExitNode() {
				return nil
			} else if s.Abort() {
				return s
			}
		}
	}
	if child := node.OneQuant(); child != nil {
		child := *child
		if s := w.WalkTermQuantNode(child); s != nil {
			if s.ExitNode() {
				return nil
			} else if s.Abort() {
				return s
			}
		}
	}
	for _, child := range node.AllTerm() {
		if s := w.WalkTermNode(child); s != nil {
			if s.ExitNode() {
				return nil
			} else if s.Abort() {
				return s
			}
		}
	}

	if fn := w.ExitTermNode; fn != nil {
		if s := fn(node); s != nil && s.Abort() {
			return s
		}
	}
	return nil
}

func (w WalkerOps) WalkTermQuantNode(node TermQuantNode) Stopper {
	if fn := w.EnterTermQuantNode; fn != nil {
		if s := fn(node); s != nil {
			if s.ExitNode() {
				return nil
			} else if s.Abort() {
				return s
			}
		}
	}

	if fn := w.ExitTermQuantNode; fn != nil {
		if s := fn(node); s != nil && s.Abort() {
			return s
		}
	}
	return nil
}

func (c GrammarNode) GetAstNode() ast.Node { return c.Node }

func NewGrammarNode(from ast.Node) GrammarNode { return GrammarNode{from} }

func Parse(input *parser.Scanner) (GrammarNode, error) {
	p := Grammar()
	tree, err := p.Parse("grammar", input)
	if err != nil {
		return GrammarNode{nil}, err
	}
	return GrammarNode{ast.FromParserNode(p.Grammar(), tree)}, nil
}

func ParseString(input string) (GrammarNode, error) {
	return Parse(parser.NewScanner(input))
}
