Files
strom/mc/proto_generator/native_decoder.go
T
2026-08-06 15:43:20 +02:00

694 lines
19 KiB
Go

package main
import (
"fmt"
"go/ast"
"go/token"
"slices"
"strconv"
"git.anygate.cloud/anygatecloud/strom/mc/proto_generator/protodef"
util2 "git.anygate.cloud/anygatecloud/strom/mc/util"
"github.com/go-viper/mapstructure/v2"
)
func DefaultDecoder(_ *Generator, varToSet ast.Expr, _ any, _ string) (s []ast.Stmt, err error) {
s = Stmts(
Assign(
Exprs(Ident("err")),
Exprs(Call(SelectorExprAndStr(varToSet, "Decode"), Ident("r"))),
),
IfErrNil(),
)
return
}
func UUIDDecoder(_ *Generator, varToSet ast.Expr, _ any, _ string) (s []ast.Stmt, err error) {
//_, err = io.ReadFull(r, U[:])
s = Stmts(
Assign(Exprs(Ident("_"), Ident("err")), Exprs(Call(Selector("io", "ReadFull"), Ident("r"), MultiIndex(varToSet, nil, nil, nil)))),
IfErrNil(),
)
return
}
func ContainerDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data protodef.Container
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
g.ContainerStack = append(g.ContainerStack, ContainerStackEntry{
Data: data,
VarToSet: varToSet,
})
defer func() { g.ContainerStack = g.ContainerStack[:len(g.ContainerStack)-1] }()
for _, field := range data {
var statements []ast.Stmt
cName := util2.CamelCase(field.Name)
if field.Anon {
cName = "Anon"
}
statements, err = g.VisitDecoder(SelectorExprAndStr(varToSet, cName), field.Type, name+cName)
if err != nil {
return
}
s = append(s, statements...)
}
return
}
func SimpleTypeDecoder(_ *Generator, varToSet ast.Expr, _ any, _ string) (s []ast.Stmt, err error) {
s = Stmts(
Assign(
Exprs(Ident("err")),
Exprs(Call(Selector("binary", "Read"), Ident("r"), Selector("binary", "BigEndian"), AddrOf(varToSet))),
),
IfErrNil(),
)
return
}
func StringDecoder(_ *Generator, varToSet ast.Expr, _ any, _ string) (s []ast.Stmt, err error) {
s = Stmts(
Assign(Exprs(varToSet, Ident("err")), Exprs(Call(Selector("proto_base", "DecodeString"), Ident("r")))),
IfErrNil(),
)
return
}
func OptionDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
pVarName := name + "Present"
tVarName := name + "PresentValue"
boolStmts, err := g.VisitDecoder(Ident(pVarName), "bool", name)
if err != nil {
return
}
t, err := g.VisitType(dataRaw)
if err != nil {
return
}
tStmts1 := Stmts(VarStmt(tVarName, t))
tStmts2, err := g.VisitDecoder(Ident(tVarName), dataRaw, name)
if err != nil {
return
}
// This looks so shit
tStmts := append(tStmts1, tStmts2...)
tStmts = append(tStmts, Assign121(varToSet, AddrOf(Ident(tVarName))))
s = append(s, VarStmt(pVarName, Ident("bool")))
s = append(s, boolStmts...)
s = append(s, If(Ident(pVarName), NewBlock(tStmts)))
return
}
func ArrayDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data protodef.Array
lName := "l" + util2.CamelCase(name)
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
var s2 []ast.Stmt
countType, err := g.VisitNameAndData("varint", nil)
if data.CountType != nil {
countType, err = g.VisitType(data.CountType)
if err != nil {
return
}
s2, err = g.VisitDecoder(Ident(lName), data.CountType, name)
if err != nil {
return
}
} else {
countStr := fmt.Sprint(data.Count)
var n int
n, err = strconv.Atoi(countStr)
var e ast.Expr
if err == nil {
e = NumLit(n)
} else {
e, _, err = g.ParseCompareTo(countStr)
}
s2 = append(s2, Assign121(Ident(lName), e))
}
normalType, err := g.VisitType(data.Type)
if err != nil {
return
}
arrayType, err := g.VisitNameAndData("array", dataRaw)
if err != nil {
return
}
tName := name + "Element"
rangeStatements := Stmts(VarStmt(tName, normalType))
s5, err := g.VisitDecoder(Ident(tName), data.Type, tName)
rangeStatements = append(rangeStatements, s5...)
rangeStatements = append(rangeStatements, Assign121(varToSet, Call(Ident("append"), varToSet, Ident(tName))))
if err != nil {
return
}
s1 := VarStmt(lName, countType)
s3 := Assign121(varToSet, CompLit(arrayType, Exprs()))
s4 := ForRange(nil, Ident(lName), NewBlock(rangeStatements))
s = append(s, s1)
s = append(s, s2...)
s = append(s, s3)
s = append(s, s4)
return
}
func TypeForwardDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data protodef.TypeForward
if err = mapstructure.Decode(dataRaw, &data); err != nil {
return
}
return g.VisitDecoder(varToSet, data.Type, name)
}
var BooleanValues = []string{"true", "false"}
// CaseExprType This exists to fix this
// "switch",
//
// {
// "compareTo": "itemCount",
// "fields": {
// "0": "void",
// "false": "void"
// },
// "default": [
//
// Protodef is best!!!
// they are also inconsistent with bool compare to sometimes they use false sometimes they use numbers
// that's why this bullshit exists
type CaseExprType int
const (
CaseExprTypeUnset CaseExprType = iota
CaseExprTypeNumber
CaseExprTypeBool
CaseExprTypeString
// CaseExprTypeOnlyNumber CaseExprTypeOnlyBool CaseExprTypeStringOnly These are special overwrite values retuned by
// the compare to for the case of being certain that it's the right type.
CaseExprTypeOnlyNumber
CaseExprTypeOnlyBool
CaseExprTypeStringOnly
)
func MultiTypeFix(s string, t *CaseExprType) (e ast.Expr) {
n, err := strconv.Atoi(s)
ct := CaseExprTypeUnset
if err == nil {
err = nil
e = NumLit(n)
ct = CaseExprTypeNumber
} else if slices.Contains(BooleanValues, s) {
e = Ident(s)
ct = CaseExprTypeBool
} else {
e = StrLit(s)
ct = CaseExprTypeString
}
if *t == CaseExprTypeUnset {
*t = ct
return
}
if *t == ct || (*t == CaseExprTypeOnlyNumber && ct == CaseExprTypeNumber) || (*t == CaseExprTypeOnlyBool && ct == CaseExprTypeBool) || (*t == CaseExprTypeNumber && ct == CaseExprTypeOnlyNumber) || (*t == CaseExprTypeBool && ct == CaseExprTypeOnlyBool) {
return
}
if ct == CaseExprTypeNumber && *t == CaseExprTypeOnlyBool {
if s == "0" {
e = Ident("false")
} else {
e = Ident("true")
}
return
}
e = nil
return
}
func SwitchDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data protodef.Switch
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
compareToExpr, cet, err := g.ParseCompareTo(data.CompareTo)
if err != nil {
return
}
for _, fName := range util2.OrderedKeys(data.Fields) {
fType := data.Fields[fName]
e := MultiTypeFix(fName, &cet)
if e == nil {
continue
}
var tType ast.Expr
tType, err = g.VisitType(fType)
if err != nil {
return
}
tName := name + util2.CamelCase(fName) + "Tmp"
s1 := VarStmt(tName, tType)
s3 := Assign121(varToSet, Ident(tName))
var caseDecodeValueStmts []ast.Stmt
caseDecodeValueStmts, err = g.VisitDecoder(Ident(tName), fType, tName)
if err != nil {
return
}
var caseStmts []ast.Stmt
caseStmts = append(caseStmts, s1)
caseStmts = append(caseStmts, caseDecodeValueStmts...)
caseStmts = append(caseStmts, s3)
s = append(s, Case(Exprs(e), caseStmts))
}
if data.Default != nil {
var tType ast.Expr
tType, err = g.VisitType(data.Default)
tName := name + "Tmp"
s1 := VarStmt(tName, tType)
s3 := Assign121(varToSet, Ident(tName))
var caseDecodeValueStmts []ast.Stmt
caseDecodeValueStmts, err = g.VisitDecoder(Ident(tName), data.Default, name)
if err != nil {
return
}
var caseStmts []ast.Stmt
caseStmts = append(caseStmts, s1)
caseStmts = append(caseStmts, caseDecodeValueStmts...)
caseStmts = append(caseStmts, s3)
s = append(s, Case(nil, caseStmts))
}
if len(s) != 0 {
s = Stmts(SwitchStmt(compareToExpr, NewBlock(s)))
}
return
}
var ToDoStmts = Stmts(Assign121(Ident("err"), Selector("proto_base", "ToDoError")))
func ToDoDecoder(_ *Generator, _ ast.Expr, _ any, _ string) (s []ast.Stmt, err error) {
err = ToDoError
return
}
func MapperDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data protodef.Mapper
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
kName := util2.CamelCase(name) + "Key"
kType, err := g.VisitType(data.Type)
if err != nil {
return
}
s1 := VarStmt(kName, kType)
s2, err := g.VisitDecoder(Ident(kName), data.Type, name)
if err != nil {
return
}
mName := name + "Map"
expressions := Exprs()
for _, k := range util2.OrderedKeys(data.Mappings) {
v := data.Mappings[k]
expressions = append(expressions, KeyValueExpr(NumLitStr(k), StrLit(v)))
}
g.Decl(mName, token.VAR, CompLit(MapType(kType, Ident("string")), expressions))
s3 := Assign(Exprs(varToSet, Ident("err")), Exprs(Call(Selector("proto_base", "ErroringIndex"), Ident(mName), Ident(kName))))
s = append(s, s1)
s = append(s, s2...)
s = append(s, s3)
s = append(s, IfErrNil())
return
}
func BufferDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data protodef.Buffer
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
// rawString, err := io.ReadAll(io.LimitReader(r, int64(l)))
if data.CountType != nil {
lName := "l" + util2.CamelCase(name)
var countType ast.Expr
countType, err = g.VisitType(data.CountType)
if err != nil {
return
}
var s2 []ast.Stmt
s2, err = g.VisitDecoder(Ident(lName), data.CountType, name)
if err != nil {
return
}
s1 := VarStmt(lName, countType)
s3 := Assign(Exprs(varToSet, Ident("err")), Exprs(Call(Selector("io", "ReadAll"), Call(Selector("io", "LimitReader"), Ident("r"), Call(Ident("int64"), Ident(lName))))))
s = append(s, s1)
s = append(s, s2...)
s = append(s, s3)
} else {
s = Stmts(Assign(Exprs(Ident("_"), Ident("err")), Exprs(Call(Selector("r", "Read"), MultiIndex(varToSet, nil, nil, nil)))))
}
s = append(s, IfErrNil())
return
}
func BitFieldDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data protodef.BitField
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
totalSize := 0
for _, field := range data {
totalSize += field.Size
}
packedTypeProtodef, err := BitSizeToProtodef(totalSize, false)
if err != nil {
return
}
t, err := g.VisitType(packedTypeProtodef)
if err != nil {
return
}
packed := name + "Packed"
packedVarStmt := VarStmt(packed, t)
stmts, err := g.VisitDecoder(Ident(packed), packedTypeProtodef, name)
if err != nil {
return
}
s = append(s, packedVarStmt)
s = append(s, stmts...)
slices.Reverse(data)
lShiftBy := 0
for _, field := range data {
var fieldTypeProtodef string
fieldTypeProtodef, err = BitSizeToProtodef(field.Size, field.Signed)
if err != nil {
return
}
var fieldType ast.Expr
fieldType, err = g.VisitType(fieldTypeProtodef)
if err != nil {
return
}
fieldToSet := SelectorExprAndStr(varToSet, util2.CamelCase(field.Name))
mask := (1 << field.Size) - 1
var getDataExpr ast.Expr
getDataExpr = BinAnd(
RightShift(Ident(packed), NumLit(lShiftBy)),
NumLit(mask))
if fieldTypeProtodef == "bool" {
getDataExpr = Equals(getDataExpr, NumLit(1))
} else if fieldTypeProtodef != packedTypeProtodef {
getDataExpr = Call(fieldType, getDataExpr)
}
s = append(s, Assign121(fieldToSet, getDataExpr))
if field.Signed {
s = append(s, If(
GreaterThanOrEqual(
fieldToSet,
LeftShift(NumLit(1), NumLit(field.Size-1)),
),
NewBlockEllipsis(
SubAssign(
fieldToSet,
LeftShift(NumLit(1), NumLit(field.Size)),
),
),
))
}
lShiftBy += field.Size
}
return
}
func RegistryEntryHolderSetDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data protodef.RegistryEntryHolderSet
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
idName := name + "Id"
varIntType, err := g.VisitNameAndData("varint", nil)
if err != nil {
return
}
IdVar := VarStmt(idName, varIntType)
idDecodeStatements, err := g.VisitDecoder(Ident(idName), "varint", name)
if err != nil {
return
}
baseType, err := g.VisitType(data.Base.Type)
if err != nil {
return
}
resName := name + "Result"
var basePath []ast.Stmt
basePath = append(basePath, VarStmt(resName, baseType))
baseDecodeStatements, err := g.VisitDecoder(Ident(resName), data.Base.Type, name+"Base")
if err != nil {
return
}
basePath = append(basePath, baseDecodeStatements...)
basePath = append(basePath, Assign121(varToSet, Ident(resName)))
idPath := IfElse(NotEquals(Ident(idName), NumLit(0)),
NewBlockEllipsis(Assign121(varToSet, Ident(idName))),
NewBlock(basePath))
s = Stmts(IdVar)
s = append(s, idDecodeStatements...)
s = append(s, idPath)
return
}
func RegistryEntryHolderDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data protodef.EntryHolderSet
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
idName := name + "Id"
varIntType, err := g.VisitNameAndData("varint", nil)
if err != nil {
return
}
IdVar := VarStmt(idName, varIntType)
idDecodeStatements, err := g.VisitDecoder(Ident(idName), "varint", name)
if err != nil {
return
}
otherwiseType, err := g.VisitType(data.Otherwise.Type)
if err != nil {
return
}
resName := name + "Result"
resNameIdent := Ident(resName)
var otherwisePath []ast.Stmt
otherwisePath = append(otherwisePath, VarStmt(resName, otherwiseType))
otherwiseDecodeStatements, err := g.VisitDecoder(resNameIdent, data.Otherwise.Type, name+"Otherwise")
if err != nil {
return
}
otherwisePath = append(otherwisePath, otherwiseDecodeStatements...)
otherwisePath = append(otherwisePath, Assign121(varToSet, resNameIdent))
idPath := IfElse(NotEquals(Ident(idName), NumLit(0)), NewBlockEllipsis(Assign121(varToSet, Ident(idName))), NewBlock(otherwisePath))
s = append(s, IdVar)
s = append(s, idDecodeStatements...)
s = append(s, idPath)
return
}
func VarIntDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
s = Stmts(Assign(Exprs(varToSet, Ident("err")), Exprs(Call(Selector("proto_base", "DecodeVarInt"), Ident("r")))), IfErrNil())
return
}
func VarLongDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
s = Stmts(Assign(Exprs(varToSet, Ident("err")), Exprs(Call(Selector("proto_base", "DecodeVarLong"), Ident("r")))), IfErrNil())
return
}
func VoidDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
return
}
func EntityMetadataLoopDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data protodef.EntityMetadataLoop
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
innerType, err := g.VisitType(data.Type)
if err != nil {
return
}
assignVts := Assign121(varToSet, Call(Ident("make"), MapType(Ident("uint8"), innerType)))
idVar := VarStmt("id", Ident("uint8"))
decodeIdStatements, err := g.VisitDecoder(Ident("id"), "u8", name)
endCheck := If(Equals(Ident("id"), NumLit(data.EndVal)), NewBlockEllipsis(Break()))
// r.Seek(-1, io.SeekCurrent)
seekBack := Assign(Exprs(Ident("_"), Ident("err")), Exprs(Call(Selector("r", "Seek"), NumLit(-1), Selector("io", "SeekCurrent"))))
declEntry := VarStmt("entry", innerType)
decodingEntryStmts, err := g.VisitDecoder(Ident("entry"), data.Type, name+"Inner")
if err != nil {
return
}
assignEntry := Assign121(Index(varToSet, Ident("id")), Ident("entry"))
var loopStmts []ast.Stmt
loopStmts = append(loopStmts, decodeIdStatements...)
loopStmts = append(loopStmts, endCheck)
loopStmts = append(loopStmts, seekBack)
loopStmts = append(loopStmts, IfErrNil())
loopStmts = append(loopStmts, declEntry)
loopStmts = append(loopStmts, decodingEntryStmts...)
loopStmts = append(loopStmts, assignEntry)
s = Stmts(assignVts, idVar, ForStmt(nil, nil, nil, NewBlock(loopStmts)))
/*
vts = make(map[uint8]{{data.type}})
var id uint8
for {
err = binary.Read(r, binary.BigEndian, &id)
if err != nil {
return
}
if id == {{data.EndId}} {
return
}
var data {{type(data.type)}}
{{unpack(data.type)}}
vts[id] = data
}
*/
return
}
func TopBitSetTerminatedArrayDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data struct {
Type any
}
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
normalType, err := g.VisitType(data.Type)
if err != nil {
return
}
arrayType, err := g.VisitNameAndData("array", dataRaw)
if err != nil {
return
}
tName := name + "Element"
hasMore := name + "HasMore"
headerName := name + "Header"
peekStmts := Stmts(
VarStmt(headerName, Ident("uint8")),
Assign(Exprs(Ident("err")), Exprs(Call(Selector("binary", "Read"), Ident("r"), Selector("binary", "BigEndian"), AddrOf(Ident(headerName))))),
If(Equals(Ident("err"), Selector("io", "EOF")),
NewBlockEllipsis(Assign121(Ident("err"), Nil()), Break())),
IfErrNil(),
Assign(Exprs(Ident("_"), Ident("err")), Exprs(Call(Selector("r", "Seek"), NumLit(-1), Selector("io", "SeekCurrent")))),
IfErrNil(),
Define121(Ident(hasMore), NotEquals(BinAnd(Ident(headerName), NumLit(0x80)), NumLit(0))),
)
rangeStatements := Stmts(VarStmt(tName, normalType))
s5, err := g.VisitDecoder(Ident(tName), data.Type, tName)
if err != nil {
return
}
rangeStatements = append(rangeStatements, s5...)
rangeStatements = append(rangeStatements, Assign121(varToSet, Call(Ident("append"), varToSet, Ident(tName))))
rangeStatements = append(rangeStatements, If(Not(Ident(hasMore)), NewBlockEllipsis(Break())))
loopStmts := append(peekStmts, rangeStatements...)
s = Stmts(
Assign121(varToSet, CompLit(arrayType, Exprs())),
ForStmt(nil, nil, nil, NewBlock(loopStmts)),
)
return
}
func (g *Generator) RegisterDecoderNatives() {
g.DecoderNatives = map[string]FunctionGeneratorFunc{
"container": ContainerDecoder,
"array": ArrayDecoder,
"option": OptionDecoder,
"bitflags": TypeForwardDecoder,
"switch": SwitchDecoder,
"mapper": MapperDecoder,
"buffer": BufferDecoder,
"bitfield": BitFieldDecoder,
"string": StringDecoder,
"void": VoidDecoder,
"varint": VarIntDecoder,
"varlong": VarLongDecoder,
"anonymousNbt": DefaultDecoder,
"anonOptionalNbt": DefaultDecoder, // I have no idea what the difference is between these two
"optionalNbt": DefaultDecoder,
"nbt": DefaultDecoder,
"lpVec3": DefaultDecoder,
"UUID": UUIDDecoder,
"restBuffer": DefaultDecoder,
"f32": SimpleTypeDecoder,
"f64": SimpleTypeDecoder,
"i8": SimpleTypeDecoder,
"i16": SimpleTypeDecoder,
"i32": SimpleTypeDecoder,
"i64": SimpleTypeDecoder,
"u8": SimpleTypeDecoder,
"u16": SimpleTypeDecoder,
"u32": SimpleTypeDecoder,
"u64": SimpleTypeDecoder,
"bool": SimpleTypeDecoder,
"registryEntryHolder": RegistryEntryHolderDecoder,
"registryEntryHolderSet": RegistryEntryHolderSetDecoder,
"entityMetadataLoop": EntityMetadataLoopDecoder,
"topBitSetTerminatedArray": TopBitSetTerminatedArrayDecoder,
"todo": ToDoDecoder,
}
}