Created
April 6, 2021 15:02
-
-
Save worldOneo/7e22215f138e9cfa76fd78e071822a60 to your computer and use it in GitHub Desktop.
xml to golang cross compiler
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<program> | |
<import> | |
<lib>fmt</lib> | |
</import> | |
<function name="main"> | |
<define name="i">0</define> | |
<while condition="i < 100"> | |
<call function="fmt.Printf"><arg>"Hello, %d \n"</arg><arg>i</arg></call> | |
<set name="i">i + 1</set> | |
</while> | |
</function> | |
</program> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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