Skip to content

Instantly share code, notes, and snippets.

@worldOneo
Created April 6, 2021 15:02
Show Gist options
  • Save worldOneo/7e22215f138e9cfa76fd78e071822a60 to your computer and use it in GitHub Desktop.
Save worldOneo/7e22215f138e9cfa76fd78e071822a60 to your computer and use it in GitHub Desktop.
xml to golang cross compiler
<program>
<import>
<lib>fmt</lib>
</import>
<function name="main">
<define name="i">0</define>
<while condition="i &lt; 100">
<call function="fmt.Printf"><arg>"Hello, %d \n"</arg><arg>i</arg></call>
<set name="i">i + 1</set>
</while>
</function>
</program>
package main
import (
"bytes"
"encoding/xml"
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"strings"
)
type CmdArgs struct {
InputFile string
OutputFile string
}
func main() {
log.Printf("Starting...")
args := CmdArgs{}
flag.StringVar(&args.InputFile, "input", "index.xml", "Specify the input file to compile")
flag.StringVar(&args.OutputFile, "output", "index.go", "Specify the go output file")
flag.Parse()
file, err := os.Open(args.InputFile)
if err != nil {
log.Fatalf("Unable to open file %s, '%v'", args.InputFile, err)
}
data, err := ioutil.ReadAll(file)
if err != nil {
log.Fatalf("Unable to read file %s, '%v'", args.InputFile, err)
}
file.Close()
parsed := parse(data)
file, err = os.OpenFile(args.OutputFile, os.O_CREATE|os.O_TRUNC, 0o600)
if err != nil {
log.Fatalf("Unable to open file %s, '%v'", args.InputFile, err)
}
file.Write([]byte("package main\n\n"))
if _, err = file.Write(parsed); err != nil {
file.Close()
panic(err)
}
file.Close()
}
func parse(str []byte) []byte {
data := bytes.NewBuffer([]byte(str))
dec := xml.NewDecoder(data)
var n Node
err := dec.Decode(&n)
if err != nil {
panic(err)
}
if len(n.Nodes) == 0 {
return parseNode(n)
}
buff := bytes.Buffer{}
buff.Write(parseNodes(n.Nodes))
return buff.Bytes()
}
func parseNodes(nodes []Node) []byte {
buff := bytes.Buffer{}
for i := 0; i < len(nodes); i++ {
curr := nodes[i]
buff.Write(parseNode(curr))
buff.WriteByte('\n')
}
return buff.Bytes()
}
func parseNode(curr Node) []byte {
x := strings.ToLower(string(curr.XMLName.Local))
buff := bytes.Buffer{}
switch x {
case "call":
f := expectAttribute(curr, "function")
buff.Write([]byte(fmt.Sprintf("%s(", f.Value)))
sep := false
for _, arg := range curr.Nodes {
if sep {
buff.Write([]byte{','})
}
sep = true
if arg.XMLName.Local != "arg" {
log.Fatalf("Expected arg ")
}
buff.Write(parseNode(arg))
}
buff.Write([]byte{')'})
case "import":
buff.Write([]byte("import (\n"))
for _, arg := range curr.Nodes {
if arg.XMLName.Local != "lib" {
log.Fatalf("Expected lib")
}
buff.Write([]byte(fmt.Sprintf("\"%s\"\n", arg.Content)))
}
buff.Write([]byte(")"))
case "define":
n := expectAttribute(curr, "name")
if len(curr.Nodes) == 0 {
buff.Write([]byte(fmt.Sprintf("%s := %s", n.Value, string(curr.Content))))
} else {
buff.Write([]byte(fmt.Sprintf("%s := %s", n.Value, string(parseNodes(curr.Nodes)))))
}
case "function":
n := expectAttribute(curr, "name")
buff.Write([]byte(fmt.Sprintf("func %s() {\n", n.Value)))
buff.Write(parseNodes(curr.Nodes))
buff.Write([]byte{'}'})
case "while":
c := expectAttribute(curr, "condition")
buff.Write([]byte(fmt.Sprintf("for %s {\n", c.Value)))
buff.Write(parseNodes(curr.Nodes))
buff.Write([]byte{'}'})
case "set":
n := expectAttribute(curr, "name")
if len(curr.Nodes) == 0 {
buff.Write([]byte(fmt.Sprintf("%s = %s", n.Value, string(curr.Content))))
} else {
buff.Write([]byte(fmt.Sprintf("%s = %s", n.Value, string(parseNodes(curr.Nodes)))))
}
default:
if len(curr.Nodes) == 0 {
log.Printf("Unknown : %s Returning : %s\n", curr.XMLName.Local, curr.Content)
buff.Write([]byte(string(curr.Content)))
} else {
buff.Write([]byte(string(parseNodes(curr.Nodes))))
}
}
return buff.Bytes()
}
func expectAttribute(n Node, attr string) xml.Attr {
for i := 0; i < len(n.Attrs); i++ {
if n.Attrs[i].Name.Local == attr {
return n.Attrs[i]
}
}
panic(fmt.Errorf("expected %s attribute", attr))
}
type Node struct {
XMLName xml.Name
Attrs []xml.Attr `xml:"-"`
Content []byte `xml:",innerxml"`
Nodes []Node `xml:",any"`
}
func (n *Node) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
n.Attrs = start.Attr
type node Node
return d.DecodeElement((*node)(n), &start)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment