123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- // Abstract Syntax Tree
- package ast
- import (
- "fmt"
- "strings"
- )
- import . "src.eruta.nl/beoran/ll1/common"
- // Species is the kind of Ast node it is. It also has some methods on it.
- type Species interface {
- Self() Species
- String() string
- }
- // BasicSpecies is a basic implementation of a species.
- type BasicSpecies struct {
- Name string
- }
- func (bs BasicSpecies) Self() Species {
- return bs
- }
- func (bs BasicSpecies) String() string {
- return bs.Name
- }
- func MakeSpecies(name string) Species {
- return BasicSpecies{Name: name}
- }
- // Astro is an abstract syntax tree that is read only
- type Astro interface {
- Value
- Species
- Parent() Ast
- Children() []Ast
- Token() Token
- }
- // Ast is an abstract syntax tree with read/write capabilities
- type Ast interface {
- Astro
- SetParent(Ast)
- AppendChild(child Ast) Ast
- }
- // BasicAst is a basic implementation of an AST.
- type BasicAst struct {
- Species
- parent Ast
- children []Ast
- token Token
- }
- func (ast BasicAst) Value() Value {
- return ast.token.Value()
- }
- func AppendChild(parent Ast, child Ast) Ast {
- basicParent := parent.(*BasicAst)
- return basicParent.AppendChild(child)
- }
- func New(kind Species, parent Ast, children []Ast, token Token) *BasicAst {
- ast := &BasicAst{Species: kind, parent: parent, token: token}
- return ast.AppendChildren(children...)
- }
- func (ast *BasicAst) AppendChildren(children ...Ast) *BasicAst {
- for _, child := range children {
- ast.AppendChild(child)
- }
- return ast
- }
- func (ast *BasicAst) AppendChild(child Ast) Ast {
- child.SetParent(ast)
- ast.children = append(ast.children, child)
- return ast
- }
- func NewChild(ast Ast, spec Species, token Token) Ast {
- child := New(spec, ast, make([]Ast, 0), token)
- ast.AppendChild(child)
- return child
- }
- func (ast BasicAst) IsKind(Species Species) bool {
- return ast.Species == Species
- }
- func (ast BasicAst) IsError() bool {
- return ast.token.Kind() == ErrorKind
- }
- func (ast BasicAst) IsNone() bool {
- return ast.Species == nil
- }
- func (ast BasicAst) Token() Token {
- return ast.token
- }
- func (ast BasicAst) Parent() Ast {
- return ast.parent
- }
- func (ast BasicAst) Children() []Ast {
- return ast.children
- }
- func (ast BasicAst) Self() Species {
- return ast.Species
- }
- func (ast *BasicAst) SetParent(parent Ast) {
- ast.parent = parent
- }
- func (ast BasicAst) Child(index int) Ast {
- count := len(ast.children)
- if index < 0 || index > count {
- return nil
- }
- return ast.children[index]
- }
- func Walk(ast Astro, walker func(node Astro) Astro) Astro {
- if found := walker(ast); found != nil {
- return found
- }
- for _, child := range ast.Children() {
- if found := Walk(child, walker); found != nil {
- return found
- }
- }
- return nil
- }
- func (ast BasicAst) String() string {
- specname := "<no spec>"
- if ast.Species != nil {
- specname = ast.Species.String()
- }
- tokval := "<no token>"
- if ast.token != nil {
- tokval = ast.token.Text()
- /* if ast.token.Value() != nil {
- tokval = ast.token.Value().String()
- } */
- }
- return fmt.Sprintf("Ast %s: %s", specname, tokval)
- }
- func Display(ast Astro) {
- Walk(ast, func(node Astro) Astro {
- depth := Depth(node)
- fmt.Printf("%s", strings.Repeat("--", depth))
- if node != nil {
- fmt.Printf("Ast: %s\n", node.String())
- } else {
- fmt.Printf("Ast: nil node\n")
- }
- return nil
- })
- }
- func Dump(ast Astro) string {
- result := ""
- Walk(ast, func(node Astro) Astro {
- depth := Depth(node)
- result += fmt.Sprintf("%s", strings.Repeat("--", depth))
- if node != nil {
- result += fmt.Sprintf("Ast: %s\n", node.String())
- } else {
- result += fmt.Sprintf("Ast: nil node\n")
- }
- return nil
- })
- return result
- }
- func Depth(ast Astro) int {
- var depth int = 0
- parent := ast.Parent()
- for parent != nil {
- depth++
- parent = parent.Parent()
- }
- return depth
- }
- func CountChildren(ast Astro) int {
- return len(ast.Children())
- }
- func IsError(ast Astro) bool {
- return ast.Token().Kind() == ErrorKind
- }
- func Errors(ast Astro) []Astro {
- res := make([]Astro, 0)
- Walk(ast, func(node Astro) Astro {
- if node != nil && IsError(ast) {
- res = append(res, node)
- }
- return nil
- })
- return res
- }
- func EmptyAstArray() []Ast {
- return make([]Ast, 0)
- }
- func NewEmptyAst(species Species) *BasicAst {
- return NewAstWithToken(species, nil)
- }
- func NewAstNone() *BasicAst {
- return NewEmptyAst(nil)
- }
- func NewAstWithToken(Species Species, token Token) *BasicAst {
- return New(Species, nil, EmptyAstArray(), token)
- }
- // If AST has errors, return it as a merged error, otherwise returns nil
- func MergeErrors(ast Ast) error {
- errlist := Errors(ast)
- if len(errlist) < 1 {
- return nil
- }
- sep := ""
- res := ""
- for _, err := range errlist {
- res = fmt.Sprintf("%s%s%s", res, sep, err)
- sep = "\n"
- }
- return fmt.Errorf("%s", res)
- }
|