103 lines
2.1 KiB
Go
103 lines
2.1 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
type Node struct {
|
||
|
Name string
|
||
|
Children []*Node
|
||
|
}
|
||
|
|
||
|
func ParseTree(s string) *Node {
|
||
|
// Split string into name and children parts
|
||
|
var name string
|
||
|
var childrenStr string
|
||
|
if idx := strings.Index(s, "<"); idx >= 0 {
|
||
|
if idx+1 < len(s)-1 {
|
||
|
name = strings.TrimSpace(s[:idx])
|
||
|
childrenStr = s[idx+1 : len(s)-1]
|
||
|
} else {
|
||
|
name = strings.TrimSpace(s[:len(s)-2])
|
||
|
}
|
||
|
} else {
|
||
|
name = strings.TrimSpace(s)
|
||
|
}
|
||
|
|
||
|
// Create new node
|
||
|
node := &Node{Name: name}
|
||
|
|
||
|
// Parse children
|
||
|
if childrenStr != "" {
|
||
|
b := 0
|
||
|
last_child := 0
|
||
|
for i, symb := range childrenStr {
|
||
|
if symb == '<' {
|
||
|
b += 1
|
||
|
} else if symb == '>' {
|
||
|
b -= 1
|
||
|
if b == 0 {
|
||
|
childNode := ParseTree(childrenStr[last_child : i+1])
|
||
|
node.Children = append(node.Children, childNode)
|
||
|
last_child = i + 2
|
||
|
}
|
||
|
} else if symb == ',' && b == 0 {
|
||
|
if last_child < i {
|
||
|
childNode := ParseTree(childrenStr[last_child:i])
|
||
|
node.Children = append(node.Children, childNode)
|
||
|
last_child = i + 1
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if last_child < len(childrenStr) {
|
||
|
childNode := ParseTree(childrenStr[last_child:])
|
||
|
node.Children = append(node.Children, childNode)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return node
|
||
|
}
|
||
|
|
||
|
func ToGraphviz(node *Node) string {
|
||
|
var sb strings.Builder
|
||
|
sb.WriteString("digraph {\n")
|
||
|
|
||
|
// Recursive function to add nodes and edges to string builder
|
||
|
var traverse func(n *Node)
|
||
|
traverse = func(n *Node) {
|
||
|
// Add node to Graphviz string
|
||
|
sb.WriteString(fmt.Sprintf(" \"%p\" [label=%s];\n", n, strconv.Quote(n.Name)))
|
||
|
|
||
|
// Traverse children and add edges
|
||
|
for _, child := range n.Children {
|
||
|
sb.WriteString(fmt.Sprintf(" \"%p\" -> \"%p\";\n", n, child))
|
||
|
traverse(child)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
traverse(node)
|
||
|
sb.WriteString("}")
|
||
|
|
||
|
return sb.String()
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
// Read all data from stdin
|
||
|
scanner := bufio.NewScanner(os.Stdin)
|
||
|
var typeStr string
|
||
|
for scanner.Scan() {
|
||
|
typeStr += scanner.Text() + "\n"
|
||
|
}
|
||
|
|
||
|
// Apply the formatter function to the input string
|
||
|
root := ParseTree(typeStr)
|
||
|
graph := ToGraphviz(root)
|
||
|
|
||
|
// Print the result
|
||
|
fmt.Println(graph)
|
||
|
}
|