You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
joy4/format/mp4/mp4io/gen/gen.go

1056 lines
27 KiB
Go

package main
import (
"fmt"
"go/ast"
"go/parser"
"go/printer"
"go/token"
"os"
"strings"
)
func getexprs(e ast.Expr) string {
if lit, ok := e.(*ast.BasicLit); ok {
return lit.Value
}
if ident, ok := e.(*ast.Ident); ok {
return ident.Name
}
return ""
}
func genatomdecl(origfn *ast.FuncDecl, origname, origtag string) (decls []ast.Decl) {
fieldslist := &ast.FieldList{}
typespec := &ast.TypeSpec{
Name: ast.NewIdent(origname),
Type: &ast.StructType{Fields: fieldslist},
}
for _, _stmt := range origfn.Body.List {
stmt := _stmt.(*ast.ExprStmt)
callexpr := stmt.X.(*ast.CallExpr)
typ := callexpr.Fun.(*ast.Ident).Name
if strings.HasPrefix(typ, "_") {
if typ == "_unknowns" {
fieldslist.List = append(fieldslist.List, &ast.Field{
Names: []*ast.Ident{ast.NewIdent("Unknowns")},
Type: ast.NewIdent("[]Atom"),
})
}
continue
}
name := getexprs(callexpr.Args[0])
name2 := ""
if len(callexpr.Args) > 1 {
name2 = getexprs(callexpr.Args[1])
}
len3 := ""
if len(callexpr.Args) > 2 {
len3 = getexprs(callexpr.Args[2])
}
if strings.HasPrefix(name, "_") {
continue
}
switch typ {
case "fixed16":
typ = "float64"
case "fixed32":
typ = "float64"
case "bytesleft":
typ = "[]byte"
case "bytes":
typ = "[" + name2 + "]byte"
case "uint24":
typ = "uint32"
case "time64", "time32":
typ = "time.Time"
case "atom":
typ = "*" + name2
case "atoms":
typ = "[]*" + name2
case "slice":
typ = "[]" + name2
case "array":
typ = "[" + len3 + "]" + name2
}
fieldslist.List = append(fieldslist.List, &ast.Field{
Names: []*ast.Ident{ast.NewIdent(name)},
Type: ast.NewIdent(typ),
})
}
if origtag != "" {
fieldslist.List = append(fieldslist.List, &ast.Field{
Type: ast.NewIdent("AtomPos"),
})
}
gendecl := &ast.GenDecl{
Tok: token.TYPE,
Specs: []ast.Spec{
typespec,
},
}
decls = append(decls, gendecl)
return
}
func typegetlen(typ string) (n int) {
switch typ {
case "uint8":
n = 1
case "uint16":
n = 2
case "uint24":
n = 3
case "uint32":
n = 4
case "int16":
n = 2
case "int32":
n = 4
case "uint64":
n = 8
case "time32":
n = 4
case "time64":
n = 8
case "fixed32":
n = 4
case "fixed16":
n = 2
}
return
}
func typegetlens(typ string) string {
n := typegetlen(typ)
if n == 0 {
return "Len" + typ
} else {
return fmt.Sprint(n)
}
}
func typegetvartype(typ string) string {
switch typ {
case "uint8":
return "uint8"
case "uint16":
return "uint16"
case "uint24":
return "uint32"
case "uint32":
return "uint32"
case "uint64":
return "uint64"
case "int16":
return "int16"
case "int32":
return "int32"
}
return ""
}
func typegetputfn(typ string) (fn string) {
fn = typ
switch typ {
case "uint8":
fn = "pio.PutU8"
case "uint16":
fn = "pio.PutU16BE"
case "uint24":
fn = "pio.PutU24BE"
case "uint32":
fn = "pio.PutU32BE"
case "int16":
fn = "pio.PutI16BE"
case "int32":
fn = "pio.PutI32BE"
case "uint64":
fn = "pio.PutU64BE"
case "time32":
fn = "PutTime32"
case "time64":
fn = "PutTime64"
case "fixed32":
fn = "PutFixed32"
case "fixed16":
fn = "PutFixed16"
default:
fn = "Put" + typ
}
return
}
func typegetgetfn(typ string) (fn string) {
fn = typ
switch typ {
case "uint8":
fn = "pio.U8"
case "uint16":
fn = "pio.U16BE"
case "uint24":
fn = "pio.U24BE"
case "uint32":
fn = "pio.U32BE"
case "int16":
fn = "pio.I16BE"
case "int32":
fn = "pio.I32BE"
case "uint64":
fn = "pio.U64BE"
case "time32":
fn = "GetTime32"
case "time64":
fn = "GetTime64"
case "fixed32":
fn = "GetFixed32"
case "fixed16":
fn = "GetFixed16"
default:
fn = "Get" + typ
}
return
}
func addns(n string) (stmts []ast.Stmt) {
assign := &ast.AssignStmt{
Tok: token.ADD_ASSIGN,
Lhs: []ast.Expr{ast.NewIdent("n")},
Rhs: []ast.Expr{&ast.BasicLit{Kind: token.INT, Value: n}},
}
stmts = append(stmts, assign)
return
}
func addn(n int) (stmts []ast.Stmt) {
return addns(fmt.Sprint(n))
}
func simplecall(fun string, args ...string) *ast.ExprStmt {
_args := []ast.Expr{}
for _, s := range args {
_args = append(_args, ast.NewIdent(s))
}
return &ast.ExprStmt{
X: &ast.CallExpr{
Fun: ast.NewIdent(fun),
Args: _args,
},
}
}
func getxx(typ string, pos, name string, conv bool) (stmts []ast.Stmt) {
fn := typegetgetfn(typ)
assign := &ast.AssignStmt{
Tok: token.ASSIGN,
Lhs: []ast.Expr{ast.NewIdent(name)},
Rhs: []ast.Expr{simplecall(fn, "b["+pos+":]").X},
}
stmts = append(stmts, assign)
return
}
func putxx(typ string, pos, name string, conv bool) (stmts []ast.Stmt) {
if conv {
name = fmt.Sprintf("%s(%s)", typ, name)
}
fn := typegetputfn(typ)
stmts = append(stmts, simplecall(fn, "b["+pos+":]", name))
return
}
func putxxadd(fn string, name string, conv bool) (stmts []ast.Stmt) {
n := typegetlen(fn)
stmts = append(stmts, putxx(fn, "n", name, conv)...)
stmts = append(stmts, addn(n)...)
return
}
func newdecl(origname, name string, params, res []*ast.Field, stmts []ast.Stmt) *ast.FuncDecl {
return &ast.FuncDecl{
Recv: &ast.FieldList{
List: []*ast.Field{
&ast.Field{
Names: []*ast.Ident{ast.NewIdent("self")},
Type: ast.NewIdent(origname),
},
},
},
Name: ast.NewIdent(name),
Type: &ast.FuncType{
Params: &ast.FieldList{
List: params,
},
Results: &ast.FieldList{
List: res,
},
},
Body: &ast.BlockStmt{List: stmts},
}
}
func getstructputgetlenfn(origfn *ast.FuncDecl, origname string) (decls []ast.Decl) {
getstmts := []ast.Stmt{}
putstmts := []ast.Stmt{}
totlen := 0
for _, _stmt := range origfn.Body.List {
stmt := _stmt.(*ast.ExprStmt)
callexpr := stmt.X.(*ast.CallExpr)
typ := callexpr.Fun.(*ast.Ident).Name
name := getexprs(callexpr.Args[0])
getstmts = append(getstmts, getxx(typ, fmt.Sprint(totlen), "self."+name, false)...)
putstmts = append(putstmts, putxx(typ, fmt.Sprint(totlen), "self."+name, false)...)
totlen += typegetlen(typ)
}
getstmts = append(getstmts, &ast.ReturnStmt{})
decls = append(decls, &ast.FuncDecl{
Name: ast.NewIdent("Get" + origname),
Type: &ast.FuncType{
Params: &ast.FieldList{
List: []*ast.Field{
&ast.Field{Names: []*ast.Ident{ast.NewIdent("b")}, Type: ast.NewIdent("[]byte")},
},
},
Results: &ast.FieldList{
List: []*ast.Field{
&ast.Field{Names: []*ast.Ident{ast.NewIdent("self")}, Type: ast.NewIdent(origname)},
},
},
},
Body: &ast.BlockStmt{List: getstmts},
})
decls = append(decls, &ast.FuncDecl{
Name: ast.NewIdent("Put" + origname),
Type: &ast.FuncType{
Params: &ast.FieldList{
List: []*ast.Field{
&ast.Field{Names: []*ast.Ident{ast.NewIdent("b")}, Type: ast.NewIdent("[]byte")},
&ast.Field{Names: []*ast.Ident{ast.NewIdent("self")}, Type: ast.NewIdent(origname)},
},
},
},
Body: &ast.BlockStmt{List: putstmts},
})
decls = append(decls, &ast.GenDecl{
Tok: token.CONST,
Specs: []ast.Spec{
&ast.ValueSpec{
Names: []*ast.Ident{ast.NewIdent("Len" + origname)},
Values: []ast.Expr{ast.NewIdent(fmt.Sprint(totlen))},
},
},
})
return
}
func cc4decls(name string) (decls []ast.Decl) {
constdecl := &ast.GenDecl{
Tok: token.CONST,
Specs: []ast.Spec{
&ast.ValueSpec{
Names: []*ast.Ident{
ast.NewIdent(strings.ToUpper(name)),
},
Values: []ast.Expr{
&ast.CallExpr{
Fun: ast.NewIdent("Tag"),
Args: []ast.Expr{&ast.BasicLit{Kind: token.INT, Value: fmt.Sprintf("0x%x", []byte(name))}},
},
},
},
},
}
decls = append(decls, constdecl)
return
}
func codeclonereplace(stmts []ast.Stmt, doit []ast.Stmt) (out []ast.Stmt) {
out = append([]ast.Stmt(nil), stmts...)
for i := range out {
if ifstmt, ok := out[i].(*ast.IfStmt); ok {
newifstmt := &ast.IfStmt{
Cond: ifstmt.Cond,
Body: &ast.BlockStmt{
List: codeclonereplace(ifstmt.Body.List, doit),
},
}
if ifstmt.Else != nil {
newifstmt.Else = &ast.BlockStmt{
List: codeclonereplace(ifstmt.Else.(*ast.BlockStmt).List, doit),
}
}
out[i] = newifstmt
} else if exprstmt, ok := out[i].(*ast.ExprStmt); ok {
if callexpr, ok := exprstmt.X.(*ast.CallExpr); ok {
if getexprs(callexpr.Fun) == "doit" {
out[i] = &ast.BlockStmt{List: doit}
}
}
}
}
return
}
func getatommarshalfn(origfn *ast.FuncDecl,
origname, origtag string,
tagnamemap map[string]string,
) (decls []ast.Decl) {
marstmts := []ast.Stmt{}
unmarstmts := []ast.Stmt{}
lenstmts := []ast.Stmt{}
childrenstmts := []ast.Stmt{}
parseerrreturn := func(debug string) (stmts []ast.Stmt) {
return []ast.Stmt{
&ast.AssignStmt{
Tok: token.ASSIGN,
Lhs: []ast.Expr{ast.NewIdent("err")},
Rhs: []ast.Expr{ast.NewIdent(fmt.Sprintf(`parseErr("%s", n+offset, err)`, debug))},
},
&ast.ReturnStmt{},
}
}
callmarshal := func(name string) (stmts []ast.Stmt) {
callexpr := &ast.CallExpr{
Fun: ast.NewIdent(name + ".Marshal"),
Args: []ast.Expr{ast.NewIdent("b[n:]")},
}
assign := &ast.AssignStmt{
Tok: token.ADD_ASSIGN,
Lhs: []ast.Expr{ast.NewIdent("n")},
Rhs: []ast.Expr{callexpr},
}
stmts = append(stmts, assign)
return
}
callputstruct := func(typ, name string) (stmts []ast.Stmt) {
stmts = append(stmts, &ast.ExprStmt{
X: &ast.CallExpr{
Fun: ast.NewIdent(typegetputfn(typ)),
Args: []ast.Expr{ast.NewIdent("b[n:]"), ast.NewIdent(name)},
},
})
stmts = append(stmts, &ast.AssignStmt{
Tok: token.ADD_ASSIGN,
Lhs: []ast.Expr{ast.NewIdent("n")},
Rhs: []ast.Expr{ast.NewIdent(typegetlens(typ))},
})
return
}
calllenstruct := func(typ, name string) (stmts []ast.Stmt) {
inc := typegetlens(typ) + "*len(" + name + ")"
stmts = append(stmts, &ast.AssignStmt{
Tok: token.ADD_ASSIGN,
Lhs: []ast.Expr{ast.NewIdent("n")},
Rhs: []ast.Expr{ast.NewIdent(inc)},
})
return
}
calllen := func(name string) (stmts []ast.Stmt) {
callexpr := &ast.CallExpr{
Fun: ast.NewIdent(name + ".Len"),
Args: []ast.Expr{},
}
assign := &ast.AssignStmt{
Tok: token.ADD_ASSIGN,
Lhs: []ast.Expr{ast.NewIdent("n")},
Rhs: []ast.Expr{callexpr},
}
stmts = append(stmts, assign)
return
}
foreach := func(name, field string, block []ast.Stmt) (stmts []ast.Stmt) {
rangestmt := &ast.RangeStmt{
Key: ast.NewIdent("_"),
Value: ast.NewIdent(name),
Body: &ast.BlockStmt{
List: block,
},
Tok: token.DEFINE,
X: ast.NewIdent(field),
}
stmts = append(stmts, rangestmt)
return
}
foreachatom := func(field string, block []ast.Stmt) (stmts []ast.Stmt) {
return foreach("atom", field, block)
}
foreachentry := func(field string, block []ast.Stmt) (stmts []ast.Stmt) {
return foreach("entry", field, block)
}
foreachi := func(field string, block []ast.Stmt) (stmts []ast.Stmt) {
rangestmt := &ast.RangeStmt{
Key: ast.NewIdent("i"),
Body: &ast.BlockStmt{
List: block,
},
Tok: token.DEFINE,
X: ast.NewIdent(field),
}
stmts = append(stmts, rangestmt)
return
}
foreachunknowns := func(block []ast.Stmt) (stmts []ast.Stmt) {
return foreachatom("self.Unknowns", block)
}
declvar := func(name, typ string) (stmts []ast.Stmt) {
stmts = append(stmts, &ast.DeclStmt{
Decl: &ast.GenDecl{
Tok: token.VAR,
Specs: []ast.Spec{
&ast.ValueSpec{
Names: []*ast.Ident{
ast.NewIdent(typ),
},
Type: ast.NewIdent(name),
},
},
},
})
return
}
makeslice := func(name, typ, size string) (stmts []ast.Stmt) {
stmts = append(stmts, &ast.ExprStmt{
X: ast.NewIdent(fmt.Sprintf("%s = make([]%s, %s)", name, typ, size)),
})
return
}
simpleassign := func(tok token.Token, l, r string) *ast.AssignStmt {
return &ast.AssignStmt{
Tok: tok,
Lhs: []ast.Expr{ast.NewIdent(l)},
Rhs: []ast.Expr{ast.NewIdent(r)},
}
}
struct2tag := func(s string) string {
name := tagnamemap[s]
return name
}
foreachatomsappendchildren := func(field string) (stmts []ast.Stmt) {
return foreachatom(field, []ast.Stmt{
simpleassign(token.ASSIGN, "r", "append(r, atom)"),
})
}
var hasunknowns bool
var atomnames []string
var atomtypes []string
var atomarrnames []string
var atomarrtypes []string
slicenamemap := map[string]string{}
unmarshalatom := func(typ, init string) (stmts []ast.Stmt) {
return []ast.Stmt{
&ast.AssignStmt{Tok: token.DEFINE,
Lhs: []ast.Expr{ast.NewIdent("atom")}, Rhs: []ast.Expr{ast.NewIdent("&" + typ + "{" + init + "}")},
},
&ast.IfStmt{
Init: &ast.AssignStmt{
Tok: token.ASSIGN,
Lhs: []ast.Expr{ast.NewIdent("_"), ast.NewIdent("err")},
Rhs: []ast.Expr{ast.NewIdent("atom.Unmarshal(b[n:n+size], offset+n)")},
},
Cond: ast.NewIdent("err != nil"),
Body: &ast.BlockStmt{List: parseerrreturn(struct2tag(typ))},
},
}
}
unmrashalatoms := func() (stmts []ast.Stmt) {
blocks := []ast.Stmt{}
blocks = append(blocks, &ast.AssignStmt{Tok: token.DEFINE, Lhs: []ast.Expr{ast.NewIdent("tag")},
Rhs: []ast.Expr{ast.NewIdent("Tag(pio.U32BE(b[n+4:]))")},
})
blocks = append(blocks, &ast.AssignStmt{Tok: token.DEFINE, Lhs: []ast.Expr{ast.NewIdent("size")},
Rhs: []ast.Expr{ast.NewIdent("int(pio.U32BE(b[n:]))")},
})
blocks = append(blocks, &ast.IfStmt{
Cond: ast.NewIdent("len(b) < n+size"),
Body: &ast.BlockStmt{List: parseerrreturn("TagSizeInvalid")},
})
cases := []ast.Stmt{}
for i, atom := range atomnames {
cases = append(cases, &ast.CaseClause{
List: []ast.Expr{ast.NewIdent(strings.ToUpper(struct2tag(atomtypes[i])))},
Body: []ast.Stmt{&ast.BlockStmt{
List: append(unmarshalatom(atomtypes[i], ""), simpleassign(token.ASSIGN, "self."+atom, "atom")),
}},
})
}
for i, atom := range atomarrnames {
selfatom := "self." + atom
cases = append(cases, &ast.CaseClause{
List: []ast.Expr{ast.NewIdent(strings.ToUpper(struct2tag(atomarrtypes[i])))},
Body: []ast.Stmt{&ast.BlockStmt{
List: append(unmarshalatom(atomarrtypes[i], ""),
simpleassign(token.ASSIGN, selfatom, "append("+selfatom+", atom)")),
}},
})
}
if hasunknowns {
init := "Tag_: tag, Data: b[n:n+size]"
selfatom := "self.Unknowns"
cases = append(cases, &ast.CaseClause{
Body: []ast.Stmt{&ast.BlockStmt{
List: append(unmarshalatom("Dummy", init), simpleassign(token.ASSIGN, selfatom, "append("+selfatom+", atom)")),
}},
})
}
blocks = append(blocks, &ast.SwitchStmt{
Tag: ast.NewIdent("tag"),
Body: &ast.BlockStmt{List: cases},
})
blocks = append(blocks, addns("size")...)
stmts = append(stmts, &ast.ForStmt{
Cond: ast.NewIdent("n+8 < len(b)"),
Body: &ast.BlockStmt{List: blocks},
})
return
}
marshalwrapstmts := func() (stmts []ast.Stmt) {
stmts = append(stmts, putxx("uint32", "4", strings.ToUpper(origtag), true)...)
stmts = append(stmts, addns("self.marshal(b[8:])+8")...)
stmts = append(stmts, putxx("uint32", "0", "n", true)...)
stmts = append(stmts, &ast.ReturnStmt{})
return
}
ifnotnil := func(name string, block []ast.Stmt) (stmts []ast.Stmt) {
stmts = append(stmts, &ast.IfStmt{
Cond: &ast.BinaryExpr{
X: ast.NewIdent(name),
Op: token.NEQ,
Y: ast.NewIdent("nil"),
},
Body: &ast.BlockStmt{List: block},
})
return
}
getchildrennr := func(name string) (stmts []ast.Stmt) {
stmts = append(stmts, &ast.AssignStmt{
Tok: token.DEFINE,
Lhs: []ast.Expr{ast.NewIdent(name)},
Rhs: []ast.Expr{ast.NewIdent("0")},
})
for _, atom := range atomnames {
stmts = append(stmts, ifnotnil("self."+atom, []ast.Stmt{
&ast.IncDecStmt{X: ast.NewIdent(name), Tok: token.INC},
})...)
}
if hasunknowns {
assign := &ast.AssignStmt{
Tok: token.ADD_ASSIGN,
Lhs: []ast.Expr{ast.NewIdent("_childrenNR")},
Rhs: []ast.Expr{ast.NewIdent("len(self.Unknowns)")},
}
stmts = append(stmts, assign)
}
return
}
checkcurlen := func(inc, debug string) (stmts []ast.Stmt) {
stmts = append(stmts, &ast.IfStmt{
Cond: &ast.BinaryExpr{
X: ast.NewIdent("len(b)"),
Op: token.LSS,
Y: ast.NewIdent("n+" + inc),
},
Body: &ast.BlockStmt{List: parseerrreturn(debug)},
})
return
}
checklendo := func(typ, name, debug string) (stmts []ast.Stmt) {
stmts = append(stmts, checkcurlen(typegetlens(typ), debug)...)
stmts = append(stmts, getxx(typ, "n", name, false)...)
stmts = append(stmts, addns(typegetlens(typ))...)
return
}
checkstructlendo := func(typ, name, debug string,
foreach func(string, []ast.Stmt) []ast.Stmt,
) (stmts []ast.Stmt) {
inc := typegetlens(typ) + "*len(" + name + ")"
stmts = append(stmts, checkcurlen(inc, debug)...)
stmts = append(stmts, foreach(name, append(
[]ast.Stmt{
&ast.AssignStmt{
Tok: token.ASSIGN,
Lhs: []ast.Expr{
ast.NewIdent(name + "[i]"),
},
Rhs: []ast.Expr{
&ast.CallExpr{
Fun: ast.NewIdent(typegetgetfn(typ)),
Args: []ast.Expr{ast.NewIdent("b[n:]")},
},
},
},
},
addns(typegetlens(typ))...,
))...)
return
}
checklencopy := func(name string) (stmts []ast.Stmt) {
lens := fmt.Sprintf("len(self.%s)", name)
stmts = append(stmts, checkcurlen(lens, name)...)
stmts = append(stmts, simplecall("copy", fmt.Sprintf("self.%s[:]", name), "b[n:]"))
stmts = append(stmts, addns(lens)...)
return
}
appendcode := func(args []ast.Expr,
marstmts *[]ast.Stmt, lenstmts *[]ast.Stmt, unmarstmts *[]ast.Stmt,
defmarstmts []ast.Stmt, deflenstmts []ast.Stmt, defunmarstmts []ast.Stmt,
) {
bodylist := func(i int, doit []ast.Stmt) []ast.Stmt {
return codeclonereplace(args[i].(*ast.FuncLit).Body.List, doit)
}
if len(args) == 1 {
*marstmts = append(*marstmts, bodylist(0, defmarstmts)...)
*lenstmts = append(*lenstmts, bodylist(0, deflenstmts)...)
*unmarstmts = append(*unmarstmts, bodylist(0, defunmarstmts)...)
} else {
*marstmts = append(*marstmts, bodylist(0, defmarstmts)...)
*lenstmts = append(*lenstmts, bodylist(1, deflenstmts)...)
*unmarstmts = append(*unmarstmts, bodylist(2, defunmarstmts)...)
}
}
getdefaultstmts := func(
typ, name, name2 string,
marstmts *[]ast.Stmt, lenstmts *[]ast.Stmt,
unmarstmts *[]ast.Stmt, childrenstmts *[]ast.Stmt,
) {
switch typ {
case "bytes", "bytesleft":
*marstmts = append(*marstmts, simplecall("copy", "b[n:]", "self."+name+"[:]"))
*marstmts = append(*marstmts, addns(fmt.Sprintf("len(self.%s[:])", name))...)
*lenstmts = append(*lenstmts, addns(fmt.Sprintf("len(self.%s[:])", name))...)
if typ == "bytes" {
*unmarstmts = append(*unmarstmts, checklencopy(name)...)
} else {
*unmarstmts = append(*unmarstmts, simpleassign(token.ASSIGN, "self."+name, "b[n:]"))
*unmarstmts = append(*unmarstmts, addns("len(b[n:])")...)
}
case "array":
*marstmts = append(*marstmts, foreachentry("self."+name, callputstruct(name2, "entry"))...)
*lenstmts = append(*lenstmts, calllenstruct(name2, "self."+name+"[:]")...)
*unmarstmts = append(*unmarstmts, checkstructlendo(name2, "self."+name, name, foreachi)...)
case "atoms":
*marstmts = append(*marstmts, foreachatom("self."+name, callmarshal("atom"))...)
*lenstmts = append(*lenstmts, foreachatom("self."+name, calllen("atom"))...)
*childrenstmts = append(*childrenstmts, foreachatomsappendchildren("self."+name)...)
case "slice":
*marstmts = append(*marstmts, foreachentry("self."+name, callputstruct(name2, "entry"))...)
*lenstmts = append(*lenstmts, calllenstruct(name2, "self."+name)...)
*unmarstmts = append(*unmarstmts, checkstructlendo(name2, "self."+name, name2, foreachi)...)
case "atom":
*marstmts = append(*marstmts, ifnotnil("self."+name, callmarshal("self."+name))...)
*lenstmts = append(*lenstmts, ifnotnil("self."+name, calllen("self."+name))...)
*childrenstmts = append(*childrenstmts, ifnotnil("self."+name, []ast.Stmt{
simpleassign(token.ASSIGN, "r", fmt.Sprintf("append(r, %s)", "self."+name)),
})...)
default:
*marstmts = append(*marstmts, putxxadd(typ, "self."+name, false)...)
*lenstmts = append(*lenstmts, addn(typegetlen(typ))...)
*unmarstmts = append(*unmarstmts, checklendo(typ, "self."+name, name)...)
}
}
for _, _stmt := range origfn.Body.List {
stmt := _stmt.(*ast.ExprStmt)
callexpr := stmt.X.(*ast.CallExpr)
typ := callexpr.Fun.(*ast.Ident).Name
if typ == "_unknowns" {
hasunknowns = true
} else if typ == "atom" {
name := getexprs(callexpr.Args[0])
name2 := getexprs(callexpr.Args[1])
atomnames = append(atomnames, name)
atomtypes = append(atomtypes, name2)
} else if typ == "atoms" {
name := getexprs(callexpr.Args[0])
name2 := getexprs(callexpr.Args[1])
atomarrnames = append(atomarrnames, name)
atomarrtypes = append(atomarrtypes, name2)
} else if typ == "slice" {
name := getexprs(callexpr.Args[0])
name2 := getexprs(callexpr.Args[1])
slicenamemap[name] = name2
}
}
lenstmts = append(lenstmts, addn(8)...)
unmarstmts = append(unmarstmts, simplecall("(&self.AtomPos).setPos", "offset", "len(b)"))
unmarstmts = append(unmarstmts, addn(8)...)
for _, _stmt := range origfn.Body.List {
stmt := _stmt.(*ast.ExprStmt)
callexpr := stmt.X.(*ast.CallExpr)
typ := callexpr.Fun.(*ast.Ident).Name
name := ""
if len(callexpr.Args) > 0 {
name = getexprs(callexpr.Args[0])
}
name2 := ""
if len(callexpr.Args) > 1 {
name2 = getexprs(callexpr.Args[1])
}
var defmarstmts, deflenstmts, defunmarstmts, defchildrenstmts []ast.Stmt
getdefaultstmts(typ, name, name2,
&defmarstmts, &deflenstmts, &defunmarstmts, &defchildrenstmts)
var code []ast.Expr
for _, arg := range callexpr.Args {
if fn, ok := arg.(*ast.CallExpr); ok {
if getexprs(fn.Fun) == "_code" {
code = fn.Args
}
}
}
if code != nil {
appendcode(code,
&marstmts, &lenstmts, &unmarstmts,
defmarstmts, deflenstmts, defunmarstmts,
)
continue
}
if strings.HasPrefix(typ, "_") {
if typ == "_unknowns" {
marstmts = append(marstmts, foreachunknowns(callmarshal("atom"))...)
lenstmts = append(lenstmts, foreachunknowns(calllen("atom"))...)
childrenstmts = append(childrenstmts, simpleassign(token.ASSIGN, "r", "append(r, self.Unknowns...)"))
}
if typ == "_skip" {
marstmts = append(marstmts, addns(name)...)
lenstmts = append(lenstmts, addns(name)...)
unmarstmts = append(unmarstmts, addns(name)...)
}
if typ == "_code" {
appendcode(callexpr.Args,
&marstmts, &lenstmts, &unmarstmts,
defmarstmts, deflenstmts, defunmarstmts,
)
}
continue
}
if name == "_childrenNR" {
marstmts = append(marstmts, getchildrennr(name)...)
marstmts = append(marstmts, putxxadd(typ, name, true)...)
lenstmts = append(lenstmts, addn(typegetlen(typ))...)
unmarstmts = append(unmarstmts, addn(typegetlen(typ))...)
continue
}
if strings.HasPrefix(name, "_len_") {
field := name[len("_len_"):]
marstmts = append(marstmts, putxxadd(typ, "len(self."+field+")", true)...)
lenstmts = append(lenstmts, addn(typegetlen(typ))...)
unmarstmts = append(unmarstmts, declvar(typegetvartype(typ), name)...)
unmarstmts = append(unmarstmts, getxx(typ, "n", name, false)...)
unmarstmts = append(unmarstmts, addn(typegetlen(typ))...)
unmarstmts = append(unmarstmts, makeslice("self."+field, slicenamemap[field], name)...)
continue
}
marstmts = append(marstmts, defmarstmts...)
lenstmts = append(lenstmts, deflenstmts...)
unmarstmts = append(unmarstmts, defunmarstmts...)
childrenstmts = append(childrenstmts, defchildrenstmts...)
}
if len(atomnames) > 0 || len(atomarrnames) > 0 || hasunknowns {
unmarstmts = append(unmarstmts, unmrashalatoms()...)
}
marstmts = append(marstmts, &ast.ReturnStmt{})
lenstmts = append(lenstmts, &ast.ReturnStmt{})
unmarstmts = append(unmarstmts, &ast.ReturnStmt{})
childrenstmts = append(childrenstmts, &ast.ReturnStmt{})
decls = append(decls, newdecl(origname, "Marshal", []*ast.Field{
&ast.Field{Names: []*ast.Ident{ast.NewIdent("b")}, Type: ast.NewIdent("[]byte")},
}, []*ast.Field{
&ast.Field{Names: []*ast.Ident{ast.NewIdent("n")}, Type: ast.NewIdent("int")},
}, marshalwrapstmts()))
decls = append(decls, newdecl(origname, "marshal", []*ast.Field{
&ast.Field{Names: []*ast.Ident{ast.NewIdent("b")}, Type: ast.NewIdent("[]byte")},
}, []*ast.Field{
&ast.Field{Names: []*ast.Ident{ast.NewIdent("n")}, Type: ast.NewIdent("int")},
}, marstmts))
decls = append(decls, newdecl(origname, "Len", []*ast.Field{}, []*ast.Field{
&ast.Field{Names: []*ast.Ident{ast.NewIdent("n")}, Type: ast.NewIdent("int")},
}, lenstmts))
decls = append(decls, newdecl("*"+origname, "Unmarshal", []*ast.Field{
&ast.Field{Names: []*ast.Ident{ast.NewIdent("b")}, Type: ast.NewIdent("[]byte")},
&ast.Field{Names: []*ast.Ident{ast.NewIdent("offset")}, Type: ast.NewIdent("int")},
}, []*ast.Field{
&ast.Field{Names: []*ast.Ident{ast.NewIdent("n")}, Type: ast.NewIdent("int")},
&ast.Field{Names: []*ast.Ident{ast.NewIdent("err")}, Type: ast.NewIdent("error")},
}, unmarstmts))
decls = append(decls, newdecl(origname, "Children", []*ast.Field{}, []*ast.Field{
&ast.Field{Names: []*ast.Ident{ast.NewIdent("r")}, Type: ast.NewIdent("[]Atom")},
}, childrenstmts))
return
}
func genatoms(filename, outfilename string) {
// Create the AST by parsing src.
fset := token.NewFileSet() // positions are relative to fset
file, err := parser.ParseFile(fset, filename, nil, 0)
if err != nil {
panic(err)
}
gen := &ast.File{}
gen.Name = ast.NewIdent("mp4io")
gen.Decls = []ast.Decl{
&ast.GenDecl{
Tok: token.IMPORT,
Specs: []ast.Spec{
&ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"gitlab.com/ics_cinnamon/joy4/utils/bits/pio"`}},
},
},
&ast.GenDecl{
Tok: token.IMPORT,
Specs: []ast.Spec{
&ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"time"`}},
},
},
}
tagnamemap := map[string]string{}
tagnamemap["ElemStreamDesc"] = "esds"
splittagname := func(fnname string) (ok bool, tag, name string) {
if len(fnname) > 5 && fnname[4] == '_' {
tag = fnname[0:4]
tag = strings.Replace(tag, "_", " ", 1)
name = fnname[5:]
ok = true
} else {
name = fnname
}
return
}
for _, decl := range file.Decls {
if fndecl, ok := decl.(*ast.FuncDecl); ok {
ok, tag, name := splittagname(fndecl.Name.Name)
if ok {
tagnamemap[name] = tag
}
}
}
tagfuncdecl := func(name, tag string) (decls ast.Decl) {
return newdecl(name, "Tag", []*ast.Field{}, []*ast.Field{
&ast.Field{Type: ast.NewIdent("Tag")},
}, []ast.Stmt{
&ast.ReturnStmt{
Results: []ast.Expr{ast.NewIdent(strings.ToUpper(tag))}}})
}
for k, v := range tagnamemap {
gen.Decls = append(gen.Decls, cc4decls(v)...)
gen.Decls = append(gen.Decls, tagfuncdecl(k, v))
}
gen.Decls = append(gen.Decls, cc4decls("mdat")...)
for _, decl := range file.Decls {
if fndecl, ok := decl.(*ast.FuncDecl); ok {
ok, tag, name := splittagname(fndecl.Name.Name)
if ok {
gen.Decls = append(gen.Decls, genatomdecl(fndecl, name, tag)...)
gen.Decls = append(gen.Decls, getatommarshalfn(fndecl, name, tag, tagnamemap)...)
} else {
gen.Decls = append(gen.Decls, genatomdecl(fndecl, name, tag)...)
gen.Decls = append(gen.Decls, getstructputgetlenfn(fndecl, name)...)
}
}
}
outfile, _ := os.Create(outfilename)
printer.Fprint(outfile, fset, gen)
outfile.Close()
}
func parse(filename, outfilename string) {
fset := token.NewFileSet()
file, err := parser.ParseFile(fset, filename, nil, 0)
if err != nil {
panic(err)
}
outfile, _ := os.Create(outfilename)
ast.Fprint(outfile, fset, file, nil)
outfile.Close()
}
func main() {
switch os.Args[1] {
case "parse":
parse(os.Args[2], os.Args[3])
case "gen":
genatoms(os.Args[2], os.Args[3])
}
}