// Package renderer renders the given AST to certain formats.
package renderer import ( ) // A Config struct is a data structure that holds configuration of the Renderer. type Config struct { Options map[OptionName]interface{} NodeRenderers util.PrioritizedSlice } // NewConfig returns a new Config. func () *Config { return &Config{ Options: map[OptionName]interface{}{}, NodeRenderers: util.PrioritizedSlice{}, } } // An OptionName is a name of the option. type OptionName string // An Option interface is a functional option type for the Renderer. type Option interface { SetConfig(*Config) } type withNodeRenderers struct { value []util.PrioritizedValue } func ( *withNodeRenderers) ( *Config) { .NodeRenderers = append(.NodeRenderers, .value...) } // WithNodeRenderers is a functional option that allow you to add // NodeRenderers to the renderer. func ( ...util.PrioritizedValue) Option { return &withNodeRenderers{} } type withOption struct { name OptionName value interface{} } func ( *withOption) ( *Config) { .Options[.name] = .value } // WithOption is a functional option that allow you to set // an arbitrary option to the parser. func ( OptionName, interface{}) Option { return &withOption{, } } // A SetOptioner interface sets given option to the object. type SetOptioner interface { // SetOption sets given option to the object. // Unacceptable options may be passed. // Thus implementations must ignore unacceptable options. SetOption(name OptionName, value interface{}) } // NodeRendererFunc is a function that renders a given node. type NodeRendererFunc func(writer util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) // A NodeRenderer interface offers NodeRendererFuncs. type NodeRenderer interface { // RendererFuncs registers NodeRendererFuncs to given NodeRendererFuncRegisterer. RegisterFuncs(NodeRendererFuncRegisterer) } // A NodeRendererFuncRegisterer registers given NodeRendererFunc to this object. type NodeRendererFuncRegisterer interface { // Register registers given NodeRendererFunc to this object. Register(ast.NodeKind, NodeRendererFunc) } // A Renderer interface renders given AST node to given // writer with given Renderer. type Renderer interface { Render(w io.Writer, source []byte, n ast.Node) error // AddOptions adds given option to this renderer. AddOptions(...Option) } type renderer struct { config *Config options map[OptionName]interface{} nodeRendererFuncsTmp map[ast.NodeKind]NodeRendererFunc maxKind int nodeRendererFuncs []NodeRendererFunc initSync sync.Once } // NewRenderer returns a new Renderer with given options. func ( ...Option) Renderer { := NewConfig() for , := range { .SetConfig() } := &renderer{ options: map[OptionName]interface{}{}, config: , nodeRendererFuncsTmp: map[ast.NodeKind]NodeRendererFunc{}, } return } func ( *renderer) ( ...Option) { for , := range { .SetConfig(.config) } } func ( *renderer) ( ast.NodeKind, NodeRendererFunc) { .nodeRendererFuncsTmp[] = if int() > .maxKind { .maxKind = int() } } // Render renders the given AST node to the given writer with the given Renderer. func ( *renderer) ( io.Writer, []byte, ast.Node) error { .initSync.Do(func() { .options = .config.Options .config.NodeRenderers.Sort() := len(.config.NodeRenderers) for := - 1; >= 0; -- { := .config.NodeRenderers[] , := .Value.(NodeRenderer) if , := .Value.(SetOptioner); { for , := range .options { .SetOption(, ) } } .RegisterFuncs() } .nodeRendererFuncs = make([]NodeRendererFunc, .maxKind+1) for , := range .nodeRendererFuncsTmp { .nodeRendererFuncs[] = } .config = nil .nodeRendererFuncsTmp = nil }) , := .(util.BufWriter) if ! { = bufio.NewWriter() } := ast.Walk(, func( ast.Node, bool) (ast.WalkStatus, error) { := ast.WalkStatus(ast.WalkContinue) var error := .nodeRendererFuncs[.Kind()] if != nil { , = (, , , ) } return , }) if != nil { return } return .Flush() }