mc root source folder cleanup

This commit is contained in:
adman
2026-06-27 13:54:54 +02:00
parent b2784574bd
commit 666f250b3e
480 changed files with 325 additions and 325 deletions
+67
View File
@@ -0,0 +1,67 @@
package main
import (
"go/ast"
"os"
"strconv"
"strings"
)
type TypesInfo struct {
Types
Direction string
State string
}
type PacketInfo struct {
TName, Name, Direction, State, PacketId, ProtocolVersion, MinecraftVersion string
PacketDef any
}
func GeneratePacketInfoFile(versions []string, packetInfos []PacketInfo) (err error) {
f := NewFile("proto_generated")
imports := []string{"github.com/admin-else/strom/mc/proto_base"}
for _, v := range versions {
vUnderscore := strings.ReplaceAll(v, ".", "_")
imports = append(imports, "github.com/admin-else/strom/mc/proto_generated/v"+vUnderscore)
}
AppendDecl(f, Import(imports...))
var packetInfoExprs []ast.Expr
for _, p := range packetInfos {
vUnderscore := "v" + strings.ReplaceAll(p.MinecraftVersion, ".", "_")
typeName := p.TName
var typeExpr ast.Expr
if p.PacketDef == "void" {
typeExpr = Selector("proto_base", "Void")
} else {
typeExpr = Selector(vUnderscore, typeName)
}
packetId, _ := strconv.ParseInt(p.PacketId, 0, 32)
protocolVersion, _ := strconv.Atoi(p.ProtocolVersion)
packetInfoExprs = append(packetInfoExprs, CompLit(nil, []ast.Expr{
KeyValueExpr(Ident("Type"), AddrOf(CompLit(typeExpr, nil))),
KeyValueExpr(Ident("Name"), StrLit(p.Name)),
KeyValueExpr(Ident("Direction"), Selector("proto_base", p.Direction)),
KeyValueExpr(Ident("State"), Selector("proto_base", p.State)),
KeyValueExpr(Ident("PacketId"), NumLit(int(packetId))),
KeyValueExpr(Ident("ProtocolVersion"), NumLit(protocolVersion)),
}))
}
var supportedVersionsExprs []ast.Expr
for _, v := range versions {
supportedVersionsExprs = append(supportedVersionsExprs, StrLit(v))
}
AppendDecl(f, VarValues("SupportedVersions", CompLit(Slice(Ident("string")), supportedVersionsExprs)))
AppendDecl(f, VarValues("Packets", CompLit(Slice(Selector("proto_base", "PacketInfo")), packetInfoExprs)))
out, err := os.Create("proto_generated/packet_info.go")
if err != nil {
return
}
defer out.Close()
return PrintToFile(f, out)
}
+436
View File
@@ -0,0 +1,436 @@
package main
import (
"crypto/sha256"
"errors"
"fmt"
"go/ast"
"go/token"
"io"
"os"
"runtime/debug"
"slices"
"strconv"
"strings"
data2 "github.com/admin-else/strom/mc/data"
util2 "github.com/admin-else/strom/mc/util"
)
var ToDoError = errors.New("to do")
type Types struct {
Types map[string]any
}
type State struct {
ToClient, ToServer Types
}
type Protocol struct {
Types
Handshaking, Status, Login, Configuration, Play State
}
type ContainerStackEntry struct {
Data []struct {
Name string
Type any
Anon bool
}
VarToSet ast.Expr
}
type ExprGeneratorFunc func(g *Generator, data any) (ast.Expr, error)
type CompareToGeneratorFunc func(g *Generator, parts []string, inExpr ast.Expr, data any) (e ast.Expr, cet CaseExprType, err error)
type FunctionGeneratorFunc func(g *Generator, varToSet ast.Expr, data any, name string) ([]ast.Stmt, error)
type Generator struct {
packetInfos []PacketInfo
// These persist the entire generate-call
Natives map[string]ExprGeneratorFunc
DecoderNatives map[string]FunctionGeneratorFunc
EncoderNatives map[string]FunctionGeneratorFunc
CompareToNatives map[string]CompareToGeneratorFunc
Protocol Protocol
File *ast.File
// These persist in the current GenerateType call
CurrentlyGeneratingTypes Types
// These persist 1 type generation
CurrentlyGeneratingTypesPrefix string
CurrentlyGeneratingTypeName string
// Change during type generation
Depth int
Declared []string
ContainerStack []ContainerStackEntry
}
func (g *Generator) Decl(name string, t token.Token, e ast.Expr) {
if slices.Contains(g.Declared, name) {
return
}
g.Declared = append(g.Declared, name)
AppendDecl(g.File, &ast.GenDecl{
Tok: t,
Specs: []ast.Spec{
&ast.ValueSpec{
Names: []*ast.Ident{
Ident(name),
},
Values: []ast.Expr{e},
},
},
})
}
func ParseType(t any) (tName string, tData any, err error) {
switch t := t.(type) {
case string:
tName = t
return
case []any:
if len(t) != 2 {
err = fmt.Errorf("unable to parse type %v", t)
return
}
var ok bool
tName, ok = t[0].(string)
if !ok {
err = fmt.Errorf("unable to parse type %v", t)
return
}
tData = t[1]
return
}
err = fmt.Errorf("unable to parse type %v", t)
return
}
func (g *Generator) VisitType(data any) (e ast.Expr, err error) {
tName, tData, err := ParseType(data)
if err != nil {
return
}
return g.VisitNameAndData(tName, tData)
}
func (g *Generator) VisitNameAndData(tName string, tData any) (e ast.Expr, err error) {
g.Depth += 1
defer func() { g.Depth -= 1 }()
n, found := g.Natives[tName]
if found {
return n(g, tData)
}
t, found := g.Protocol.Types.Types[tName]
if t != "native" && found {
return Ident(util2.CamelCase(tName)), nil
}
t, found = g.CurrentlyGeneratingTypes.Types[tName]
if found {
return Ident(g.CurrentlyGeneratingTypesPrefix + util2.CamelCase(tName)), nil
}
err = fmt.Errorf("unknown type %s", tName)
return
}
func (g *Generator) VisitDecoder(varToSet ast.Expr, data any, name string) (e []ast.Stmt, err error) {
g.Depth += 1
defer func() { g.Depth -= 1 }()
tName, tData, err := ParseType(data)
if err != nil {
return
}
d, found := g.DecoderNatives[tName]
if found {
return d(g, varToSet, tData, name)
}
t, found := g.Protocol.Types.Types[tName]
if t == "native" {
err = fmt.Errorf("decoder native not implemented %v", tName)
return
}
return DefaultDecoder(g, varToSet, tData, name)
}
func (g *Generator) VisitEncoder(varToSet ast.Expr, data any, name string) (e []ast.Stmt, err error) {
g.Depth += 1
defer func() { g.Depth -= 1 }()
tName, tData, err := ParseType(data)
if err != nil {
return
}
d, found := g.EncoderNatives[tName]
if found {
return d(g, varToSet, tData, name)
}
t, found := g.Protocol.Types.Types[tName]
if t == "native" {
err = fmt.Errorf("encoder native not implemented %v", tName)
return
}
return DefaultEncoder(g, varToSet, tData, name)
}
// FixPointerReceivers
// We cannot declare a function on a ptr type as described by https://go.dev/ref/spec#Method_declarations.
// So we wrap them in a struct.
func FixPointerReceivers(e ast.Expr) (td ast.Expr, ret ast.Expr) {
_, isStruct := e.(*ast.StructType)
ret = Ident("ret")
if isStruct {
td = e
return
}
ret = Selector("ret", "Val")
s := NewStruct()
AddFieldToStruct(s, "Val", e)
td = s
return
}
func (g *Generator) GenerateTypes(prefix string, types Types) (err error) {
g.CurrentlyGeneratingTypes = types
g.CurrentlyGeneratingTypesPrefix = prefix
for _, k := range util2.OrderedKeys(types.Types) {
v := types.Types[k]
g.Depth = 0
e, err2 := g.VisitType(v)
if errors.Is(err2, ToDoError) {
e = Selector("proto_base", "ToDo")
err2 = nil
}
if err2 != nil {
return err2
}
if e == nil { // This is for types we implement ourselves
continue
}
tName := prefix + util2.CamelCase(k)
g.CurrentlyGeneratingTypeName = tName
e, retExpr := FixPointerReceivers(e)
AppendDecl(g.File, TypeDecl(tName, e))
args := []NameAndType{{"r", Ident("io.ReadSeeker")}}
rets := []NameAndType{{"err", Ident("error")}}
decodeFunction := NewFuncWithReceiver("Decode", "ret", Pointer(Ident(tName)), args, rets)
g.Depth = 0
s, err2 := g.VisitDecoder(retExpr, v, tName)
if err2 != nil {
s = ToDoStmts
fmt.Println("failed to make decoder for", k, err2)
}
decodeFunction.Body = NewBlock(append(s, Return()))
AppendDecl(g.File, decodeFunction)
args = []NameAndType{{"w", Ident("io.Writer")}}
rets = []NameAndType{{"err", Ident("error")}}
encodeFunction := NewFuncWithReceiver("Encode", "ret", Pointer(Ident(tName)), args, rets)
g.Depth = 0
s, err2 = g.VisitEncoder(retExpr, v, tName)
if err2 != nil {
s = ToDoStmts
fmt.Println("failed to make encoder for", k, err2)
}
encodeFunction.Body = NewBlock(append(s, Return()))
AppendDecl(g.File, encodeFunction)
}
return
}
func (g *Generator) GenerateProtocol(protocol Protocol, version string) (err error) {
versionData, err := data2.LookUpVersionByName(version)
if err != nil {
return
}
prefixTypeMap := map[string]TypesInfo{
"": {protocol.Types, "", ""},
"HandshakingToServer": {protocol.Handshaking.ToServer, "ToServer", "Handshaking"},
"HandshakingToClient": {protocol.Handshaking.ToClient, "ToClient", "Handshaking"},
"StatusToServer": {protocol.Status.ToServer, "ToServer", "Status"},
"StatusToClient": {protocol.Status.ToClient, "ToClient", "Status"},
"LoginToServer": {protocol.Login.ToServer, "ToServer", "Login"},
"LoginToClient": {protocol.Login.ToClient, "ToClient", "Login"},
"ConfigurationToServer": {protocol.Configuration.ToServer, "ToServer", "Configuration"},
"ConfigurationToClient": {protocol.Configuration.ToClient, "ToClient", "Configuration"},
"PlayToServer": {protocol.Play.ToServer, "ToServer", "Play"},
"PlayToClient": {protocol.Play.ToClient, "ToClient", "Play"},
}
// Move common packet to their own areas to make packets more identifiable
for _, k := range util2.OrderedKeys(protocol.Types.Types) {
v := protocol.Types.Types[k]
if strings.Contains(k, "packet") {
delete(protocol.Types.Types, k)
for _, prefix := range util2.OrderedKeys(prefixTypeMap) {
types := prefixTypeMap[prefix]
if prefix == "" {
continue
}
types.Types.Types[k] = v
}
}
}
for _, prefix := range util2.OrderedKeys(prefixTypeMap) {
types := prefixTypeMap[prefix]
for _, k := range util2.OrderedKeys(types.Types.Types) {
typeData := types.Types.Types[k]
if k != "packet" {
continue
}
packetIds := typeData.([]any)[1].([]any)[0].(map[string]any)["type"].([]any)[1].(map[string]any)["mappings"].(map[string]any)
packetIdsStrings := util2.AssertAndConvertMapValues[string](packetIds)
packetIdsRev := util2.ReverseMap(packetIdsStrings)
v := typeData.([]any)[1].([]any)[1].(map[string]any)["type"].([]any)[1].(map[string]any)["fields"].(map[string]any)
for _, k2 := range util2.OrderedKeys(v) {
v2 := v[k2].(string)
typeName := prefix + util2.CamelCase(v2)
g.packetInfos = append(g.packetInfos, PacketInfo{
PacketDef: v2,
TName: typeName,
Name: k2,
Direction: types.Direction,
State: types.State,
PacketId: packetIdsRev[k2],
ProtocolVersion: strconv.Itoa(int(versionData.Version)),
MinecraftVersion: version,
})
}
}
}
for _, prefix := range util2.OrderedKeys(prefixTypeMap) {
types := prefixTypeMap[prefix]
err = g.GenerateTypes(prefix, types.Types)
if err != nil {
return
}
}
return
}
func ToolVersion() string {
info, ok := debug.ReadBuildInfo()
if !ok {
return "devel"
}
return info.Main.Version
}
func GoVersion() string {
info, ok := debug.ReadBuildInfo()
if !ok {
return "unknown"
}
return info.GoVersion
}
func HashFile(path string) (string, error) {
// Read from embedded filesystem since minecraft-data is embedded via go:embed
b, err := data2.MinecraftData.ReadFile(path)
if err != nil {
return "", err
}
h := sha256.New()
h.Write(b)
return fmt.Sprintf("sha256:%x", h.Sum(nil)), nil
}
func Generate(version string, w io.Writer, sourceHash string) (packetInfos []PacketInfo, err error) {
protocol := Protocol{}
err = data2.LoadVersionedJson(version, "protocol", &protocol)
if err != nil {
return
}
g := &Generator{Protocol: protocol}
g.File = NewFile("v" + strings.ReplaceAll(version, ".", "_"))
// Add file header comment for IDE recognition and reproducibility
sourcePath := "minecraft-data/" + data2.Paths.Data[version]["protocol"] + "/protocol.json"
toolVersion := ToolVersion()
goVersion := GoVersion()
comment := fmt.Sprintf("Code generated by strom. DO NOT EDIT.\nsource: %s (%s)\nversion: %s (%s)",
sourcePath, sourceHash, toolVersion, goVersion)
AddFileComment(g.File, comment)
AppendDecl(g.File, Import("encoding/binary", "io", "github.com/admin-else/strom/mc/proto_base", "github.com/admin-else/strom/mc/nbt", "github.com/google/uuid"))
g.RegisterNatives()
g.RegisterDecoderNatives()
g.RegisterEncoderNatives()
g.RegisterCompareToNatives()
err = g.GenerateProtocol(protocol, version)
if err != nil {
return
}
packetInfos = g.packetInfos
err = PrintToFile(g.File, w)
return
}
func generateVersion(v string) (packetInfos []PacketInfo, err error) {
vUnderscore := strings.ReplaceAll(v, ".", "_")
err = os.MkdirAll("proto_generated/v"+vUnderscore, 0755)
if err != nil {
return
}
f, err := os.Create("proto_generated/v" + vUnderscore + "/proto.go")
if err != nil {
return
}
defer f.Close()
// Compute hash of source protocol.json for reproducibility
sourcePath := "minecraft-data/" + data2.Paths.Data[v]["protocol"] + "/protocol.json"
sourceHash, err := HashFile(sourcePath)
if err != nil {
return
}
packetInfos, err = Generate(v, f, sourceHash)
if err != nil {
return
}
return
}
func GenerateVersions(versions []string) (err error) {
err = os.RemoveAll("proto_generated/")
if err != nil {
return
}
err = os.MkdirAll("proto_generated/", 0755)
if err != nil {
return
}
var packetInfos, newPacketInfos []PacketInfo
for _, version := range versions {
fmt.Println("generating", version)
newPacketInfos, err = generateVersion(version)
if err != nil {
return
}
packetInfos = append(packetInfos, newPacketInfos...)
}
return GeneratePacketInfoFile(versions, packetInfos)
}
func main() {
err := GenerateVersions([]string{"1.21.8", "1.21.9", "1.21.11"})
if err != nil {
panic(err)
}
}
+131
View File
@@ -0,0 +1,131 @@
package main
import (
"errors"
"fmt"
"go/ast"
"strings"
"github.com/admin-else/strom/mc/proto_generator/protodef"
util2 "github.com/admin-else/strom/mc/util"
"github.com/go-viper/mapstructure/v2"
)
func (g *Generator) ParseCompareTo(compareTo string) (e ast.Expr, cet CaseExprType, err error) {
parts := strings.Split(compareTo, "/")
downPrefixCount := 0
for _, part := range parts {
if part == ".." {
downPrefixCount++
}
}
parts = parts[downPrefixCount:]
startingPoint := g.ContainerStack[len(g.ContainerStack)-downPrefixCount-1]
e, cet, err = g.VisitCompareTo(parts, startingPoint.VarToSet, util2.CombineNamAndData("container", startingPoint.Data))
// return ParseCompareToLegacy(compareTo, varToSet)
return
}
func (g *Generator) VisitCompareTo(parts []string, inExpr ast.Expr, data any) (e ast.Expr, cet CaseExprType, err error) {
tName, tData, err := ParseType(data)
if err != nil {
return
}
d, found := g.CompareToNatives[tName]
if found {
return d(g, parts, inExpr, tData)
}
err = fmt.Errorf("native compare to not implemented for %v", tName)
return
}
func ContainerCompareTo(g *Generator, parts []string, inExpr ast.Expr, dataRaw any) (e ast.Expr, cet CaseExprType, err error) {
var data protodef.Container
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
name, parts, ok := util2.PopFront(parts)
if !ok {
err = errors.New("expected name part")
return
}
for _, field := range data {
if field.Name == name {
return g.VisitCompareTo(parts, SelectorExprAndStr(inExpr, util2.CamelCase(field.Name)), field.Type)
}
}
err = errors.New("field not found")
return
}
func ReturnInputCompareTo(_ *Generator, _ []string, inExpr ast.Expr, _ any) (e ast.Expr, cet CaseExprType, err error) {
return inExpr, CaseExprTypeUnset, nil
}
func BitfieldCompareTo(_ *Generator, parts []string, inExpr ast.Expr, dataRaw any) (e ast.Expr, cet CaseExprType, err error) {
var data protodef.BitField
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
fieldName, parts, found := util2.PopFront(parts)
if !found {
err = errors.New("expected name part")
return
}
var field protodef.BitFieldEntry
for _, f := range data {
if f.Name == fieldName {
field = f
break
}
}
if field.Size == 1 {
cet = CaseExprTypeOnlyBool
} else {
cet = CaseExprTypeOnlyNumber
}
e = SelectorExprAndStr(inExpr, util2.CamelCase(fieldName))
return
}
func BitflagsCompareTo(_ *Generator, parts []string, inExpr ast.Expr, dataRaw any) (e ast.Expr, cet CaseExprType, err error) {
var data protodef.BitFlags
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
name, parts, ok := util2.PopFront(parts)
if !ok {
err = errors.New("expected name part")
return
}
for i, flag := range data.Flags {
if flag != name {
continue
}
e = NotEquals(BinAnd(inExpr, NumLitHex(1<<i)), NumLit(0))
return
}
err = errors.New("flag not found")
return
}
func (g *Generator) RegisterCompareToNatives() {
g.CompareToNatives = map[string]CompareToGeneratorFunc{
"container": ContainerCompareTo,
"bool": ReturnInputCompareTo,
"mapper": ReturnInputCompareTo,
"varint": ReturnInputCompareTo,
"bitfield": BitfieldCompareTo,
"u8": ReturnInputCompareTo,
"i8": ReturnInputCompareTo,
"bitflags": BitflagsCompareTo,
"switch": ReturnInputCompareTo,
"varlong": ReturnInputCompareTo,
}
}
+659
View File
@@ -0,0 +1,659 @@
package main
import (
"go/ast"
"go/token"
"slices"
"strconv"
"github.com/admin-else/strom/mc/proto_generator/protodef"
util2 "github.com/admin-else/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 {
var n int
n, err = strconv.Atoi(data.Count)
var e ast.Expr
if err == nil {
e = NumLit(n)
} else {
e, _, err = g.ParseCompareTo(data.Count)
}
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 {
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...)
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
}
rShiftBy := totalSize - field.Size
fieldToSet := SelectorExprAndStr(varToSet, util2.CamelCase(field.Name))
var getDataExpr ast.Expr
getDataExpr = RightShift(
LeftShift(
Ident(packed),
NumLit(lShiftBy)),
NumLit(rShiftBy),
)
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
}
var countType ast.Expr
countType, err = g.VisitType("varint")
if err != nil {
return
}
baseType, err := g.VisitType(data.Base.Type)
if err != nil {
return
}
otherwiseArrayType, err := g.VisitNameAndData("array", map[string]any{"type": data.Otherwise.Type})
if err != nil {
return
}
otherwiseType, err := g.VisitType(data.Otherwise.Type)
if err != nil {
return
}
lName := "l" + util2.CamelCase(name)
s1 := VarStmt(lName, countType)
s2, err := g.VisitDecoder(Ident(lName), "varint", name)
if err != nil {
return
}
s3 := Assign121(Ident(lName), Sub(Ident(lName), NumLit(1)))
resultName := name + "Result"
b1s1 := VarStmt(resultName, baseType)
b1s2, err := g.VisitDecoder(Ident(resultName), data.Base.Type, resultName)
b1s3 := Assign121(varToSet, Ident(resultName))
b1s4 := Return()
var b1 []ast.Stmt
b1 = append(b1, b1s1)
b1 = append(b1, b1s2...)
b1 = append(b1, b1s3)
b1 = append(b1, b1s4)
tName := name + "Element"
rangeStatements := Stmts(VarStmt(tName, otherwiseType))
rangeStatementsDecode, err := g.VisitDecoder(Ident(tName), data.Otherwise.Type, tName)
rangeStatements = append(rangeStatements, rangeStatementsDecode...)
rangeStatements = append(rangeStatements, Assign121(Ident(resultName), Call(Ident("append"), Ident(resultName), Ident(tName))))
s5 := If(Equals(Ident(lName), NumLit(-1)), NewBlock(b1))
s6 := VarStmt(resultName, otherwiseArrayType)
s7 := ForRange(nil, Ident(lName), NewBlock(rangeStatements))
s = append(s, s1)
s = append(s, s2...)
s = append(s, s3)
s = append(s, s5)
s = append(s, s6)
s = append(s, s7)
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 (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
"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": ToDoDecoder, // RegistryEntryHolderSetDecoder
"entityMetadataLoop": EntityMetadataLoopDecoder,
"topBitSetTerminatedArray": ToDoDecoder,
"todo": ToDoDecoder,
}
}
+428
View File
@@ -0,0 +1,428 @@
package main
import (
"go/ast"
"go/token"
"slices"
"strconv"
"github.com/admin-else/strom/mc/proto_generator/protodef"
util2 "github.com/admin-else/strom/mc/util"
"github.com/go-viper/mapstructure/v2"
)
func DefaultEncoder(_ *Generator, varToSet ast.Expr, _ any, _ string) (s []ast.Stmt, err error) {
s = Stmts(
Assign121(
Ident("err"),
Call(SelectorExprAndStr(varToSet, "Encode"), Ident("w")),
),
IfErrNil(),
)
return
}
func ContainerEncoder(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.VisitEncoder(SelectorExprAndStr(varToSet, cName), field.Type, name+util2.CamelCase(cName))
if err != nil {
return
}
s = append(s, statements...)
}
return
}
func SimpleTypeEncoder(_ *Generator, data ast.Expr, _ any, _ string) (s []ast.Stmt, err error) {
s = Stmts(
Assign121(
Ident("err"),
Call(Selector("binary", "Write"), Ident("w"), Selector("binary", "BigEndian"), data),
),
IfErrNil(),
)
return
}
func ArrayEncoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data protodef.Array
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
if data.CountType == nil {
data.CountType = "varint"
}
ct, err := g.VisitType(data.CountType)
if err != nil {
return
}
iName := "i" + name
//s, err = g.VisitEncoder(varToSet, data.Type, name)
var s1 []ast.Stmt
if data.Count == "" {
s1, err = g.VisitEncoder(Call(ct, Call(Ident("len"), varToSet)), data.CountType, name)
if err != nil {
return
}
}
s2, err := g.VisitEncoder(Index(varToSet, Ident(iName)), data.Type, name+"Inner")
if err != nil {
}
s2 = Stmts(ForRange(Ident(iName), Call(Ident("len"), varToSet), NewBlock(s2)))
s = append(s1, s2...)
return
}
func ToDoEncoder(_ *Generator, _ ast.Expr, _ any, _ string) (s []ast.Stmt, err error) {
err = ToDoError
return
}
func OptionEncoder(g *Generator, data ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
cond := NotEquals(data, Nil())
s1, err := g.VisitEncoder(cond, "bool", name)
if err != nil {
return
}
s2, err := g.VisitEncoder(DeRef(data), dataRaw, name)
if err != nil {
return
}
s = append(s1, If(cond, NewBlock(s2)))
return
}
func BufferEncoder(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
}
if data.CountType != nil {
var countType ast.Expr
countType, err = g.VisitType(data.CountType)
if err != nil {
return
}
var s2 []ast.Stmt
s2, err = g.VisitEncoder(Call(countType, Call(Ident("len"), varToSet)), data.CountType, name)
if err != nil {
return
}
s = append(s, s2...)
} else {
s = append(s, Define121(Ident("arr"), varToSet))
varToSet = MultiIndex(Ident("arr"), nil, nil, nil)
}
s = append(s, Assign(Exprs(Ident("_"), Ident("err")), Exprs(Call(Selector("w", "Write"), varToSet))))
s = append(s, IfErrNil())
return
}
func BitFieldEncoder(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
}
packedVarName := name + "Packed"
packedExpr := Ident(packedVarName)
packedTypeStr := "uint" + strconv.Itoa(totalSize)
s = append(s, VarStmt(packedVarName, Ident(packedTypeStr)))
slices.Reverse(data)
shiftBy := 0
for _, field := range data {
boolFix := packedTypeStr
if field.Size == 1 {
boolFix = "proto_base.Bool2" + boolFix
}
s = append(s, OrAssign( // lisp ahh
packedExpr,
LeftShift(
Grouping(
BinAnd(
Call(
Ident(boolFix),
SelectorExprAndStr(
varToSet,
util2.CamelCase(field.Name),
),
),
NumLitHex((1<<field.Size)-1),
),
),
NumLitHex(shiftBy),
),
))
shiftBy += field.Size
}
encodePacked, err := g.VisitEncoder(packedExpr, "u"+strconv.Itoa(totalSize), name)
if err != nil {
return
}
s = append(s, encodePacked...)
return
}
func SwitchEncoder(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
}
varName := name
if fType == "void" {
varName = "_"
}
s1 := Define(Exprs(Ident(varName), Ident("ok")), Exprs(TypeAssert(varToSet, tType)))
s2 := If(Not(Ident("ok")), NewBlockEllipsis(Assign121(Ident("err"), Selector("proto_base", "BadTypeError")), Return()))
var caseDecodeValueStmts []ast.Stmt
caseDecodeValueStmts, err = g.VisitEncoder(Ident(name), fType, name)
if err != nil {
return
}
var caseStmts []ast.Stmt
caseStmts = append(caseStmts, s1)
caseStmts = append(caseStmts, s2)
caseStmts = append(caseStmts, caseDecodeValueStmts...)
s = append(s, Case(Exprs(e), caseStmts))
}
if data.Default != nil {
var tType ast.Expr
tType, err = g.VisitType(data.Default)
if err != nil {
return
}
s1 := Define(Exprs(Ident("_"), Ident("ok")), Exprs(TypeAssert(varToSet, tType)))
s2 := If(Not(Ident("ok")), NewBlockEllipsis(Assign121(Ident("err"), Selector("proto_base", "BadTypeError")), Return()))
defaultStmts := []ast.Stmt{s1, s2}
var defaultEncodingStmts []ast.Stmt
defaultEncodingStmts, err = g.VisitEncoder(TypeAssert(varToSet, tType), data.Default, name)
if err != nil {
return
}
defaultStmts = append(defaultStmts, defaultEncodingStmts...)
s = append(s, Case(nil, defaultStmts))
}
if len(s) != 0 {
s = Stmts(SwitchStmt(compareToExpr, NewBlock(s)))
}
return
}
func TypeForwardEncoder(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.VisitEncoder(varToSet, data.Type, name)
}
func MapperEncoder(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
}
kType, err := g.VisitType(data.Type)
if err != nil {
return
}
mName := name + "ReverseMap"
exprs := Exprs()
for _, k := range util2.OrderedKeys(data.Mappings) {
v := data.Mappings[k]
exprs = append(exprs, KeyValueExpr(StrLit(v), NumLitStr(k)))
}
g.Decl(mName, token.VAR, CompLit(MapType(Ident("string"), kType), exprs))
vName := "v" + name
s1 := VarStmt(vName, kType)
s2 := Assign(Exprs(Ident(vName), Ident("err")), Exprs(Call(Selector("proto_base", "ErroringIndex"), Ident(mName), varToSet)))
s3 := IfErrNil()
s4, err := g.VisitEncoder(Ident(vName), data.Type, name)
if err != nil {
return
}
s = append(s, s1)
s = append(s, s2)
s = append(s, s3)
s = append(s, s4...)
return
}
func StringEncoder(_ *Generator, varToSet ast.Expr, _ any, _ string) (s []ast.Stmt, err error) {
s = Stmts(
Assign121(Ident("err"), Call(Selector("proto_base", "EncodeString"), Ident("w"), varToSet)), IfErrNil())
return
}
func UUIDEncoder(_ *Generator, varToSet ast.Expr, _ any, _ string) (s []ast.Stmt, err error) {
s = Stmts(Assign(Exprs(Ident("_"), Ident("err")), Exprs(Call(Selector("w", "Write"), MultiIndex(varToSet, nil, nil, nil)))), IfErrNil())
return
}
func RegistryEntryHolderEncoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data protodef.EntryHolderSet
err = mapstructure.Decode(dataRaw, &data)
otherwiseType, err := g.VisitType(data.Otherwise.Type)
if err != nil {
return
}
knownTypeName := name + "KnownType"
encode0statements, err := g.VisitEncoder(NumLit(0), "varint", name+"Zero")
if err != nil {
return
}
otherwiseEncodeStatements, err := g.VisitEncoder(Ident(knownTypeName), data.Otherwise.Type, name+"Otherwise")
otherwiseEncodeStatements = append(encode0statements, otherwiseEncodeStatements...)
if err != nil {
return
}
baseType, err := g.VisitType("varint")
if err != nil {
return
}
baseEncodeStatements, err := g.VisitEncoder(Ident(knownTypeName), "varint", name)
if err != nil {
return
}
statements := Stmts()
statements = append(statements, Case(Exprs(baseType), baseEncodeStatements))
statements = append(statements, Case(Exprs(otherwiseType), otherwiseEncodeStatements))
statements = append(statements, Case(nil, Stmts(Assign121(Ident("err"), Selector("proto_base", "BadTypeError")))))
s = Stmts(TypeSwitch(Define121(Ident(knownTypeName), TypeAssert(varToSet, Ident("type"))), NewBlock(statements)))
return
}
func VarIntEncoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
s = Stmts(Assign121(Ident("err"), Call(Selector("proto_base", "EncodeVarInt"), Ident("w"), varToSet)), IfErrNil())
return
}
func VarLongEncoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
s = Stmts(Assign121(Ident("err"), Call(Selector("proto_base", "EncodeVarLong"), Ident("w"), varToSet)), IfErrNil())
return
}
func VoidEncoder(_ *Generator, _ ast.Expr, _ any, _ string) (s []ast.Stmt, err error) {
return
}
func EntityMetadataLoopEncoder(g *Generator, vts ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data protodef.EntityMetadataLoop
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
/*
for _, v := range vts.Val {
WriteData(w, v)
}
WriteU8(w, 0xFF)
*/
encodeV, err := g.VisitEncoder(Ident("v"), data.Type, name)
if err != nil {
return
}
forStmt := ForRangeKV(Ident("_"), Ident("v"), vts, NewBlock(encodeV))
encodeEndId, err := g.VisitEncoder(Call(Ident("uint8"), NumLit(data.EndVal)), "u8", name)
if err != nil {
return
}
s = append(s, forStmt)
s = append(s, encodeEndId...)
return
}
func (g *Generator) RegisterEncoderNatives() {
g.EncoderNatives = map[string]FunctionGeneratorFunc{
"container": ContainerEncoder,
"array": ArrayEncoder,
"option": OptionEncoder,
"bitflags": TypeForwardEncoder,
"switch": SwitchEncoder,
"mapper": MapperEncoder,
"buffer": BufferEncoder,
"bitfield": BitFieldEncoder,
"void": VoidEncoder,
"varint": VarIntEncoder,
"varlong": VarLongEncoder,
"anonymousNbt": DefaultEncoder,
"anonOptionalNbt": DefaultEncoder, // I have no idea what the difference is between these two
"UUID": UUIDEncoder,
"restBuffer": DefaultEncoder,
"lpVec3": DefaultEncoder,
"string": StringEncoder,
"f32": SimpleTypeEncoder,
"f64": SimpleTypeEncoder,
"i8": SimpleTypeEncoder,
"i16": SimpleTypeEncoder,
"i32": SimpleTypeEncoder,
"i64": SimpleTypeEncoder,
"u8": SimpleTypeEncoder,
"u16": SimpleTypeEncoder,
"u32": SimpleTypeEncoder,
"u64": SimpleTypeEncoder,
"bool": SimpleTypeEncoder,
"registryEntryHolder": RegistryEntryHolderEncoder,
"registryEntryHolderSet": ToDoEncoder,
"entityMetadataLoop": EntityMetadataLoopEncoder,
"topBitSetTerminatedArray": ToDoEncoder,
"todo": ToDoEncoder,
}
}
+230
View File
@@ -0,0 +1,230 @@
package main
import (
"errors"
"fmt"
"go/ast"
"github.com/admin-else/strom/mc/proto_generator/protodef"
"github.com/admin-else/strom/mc/util"
"github.com/go-viper/mapstructure/v2"
)
func VisitContainerType(g *Generator, dataRaw any) (ast.Expr, error) {
var data []struct {
Name string
Type any
Anon bool
}
err := mapstructure.Decode(dataRaw, &data)
if err != nil {
return nil, err
}
g.ContainerStack = append(g.ContainerStack, ContainerStackEntry{
Data: data,
VarToSet: nil,
})
defer func() { g.ContainerStack = g.ContainerStack[:len(g.ContainerStack)-1] }()
s := NewStruct()
for _, field := range data {
var t ast.Expr
t, err = g.VisitType(field.Type)
if err != nil {
return nil, err
}
if field.Anon {
field.Name = "Anon" // lol
}
AddFieldToStruct(s, util.CamelCase(field.Name), t)
}
return s, nil
}
func VisitBufferType(_ *Generator, dataRaw any) (e ast.Expr, err error) {
var data struct {
CountType any
Count int
}
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
if data.CountType != nil {
if data.CountType == "varint" {
e = Slice(Ident("byte"))
return
}
return nil, fmt.Errorf("unsupported count type: %v", data.CountType) // TODO: old versions use uint16 as count type
}
e = Array(Ident("byte"), data.Count)
return
}
func VisitArrayTypeVisitorType(g *Generator, dataRaw any) (e ast.Expr, err error) {
var data struct {
CountType any
Type any
}
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
e, err = g.VisitType(data.Type)
if err != nil {
return nil, err
}
return Slice(e), nil
}
func VisitDontGenerateType(_ *Generator, _ any) (ast.Expr, error) {
return nil, nil
}
func VisitToDoType(_ *Generator, _ any) (e ast.Expr, err error) {
err = ToDoError
return
}
func VisitOptionType(g *Generator, dataRaw any) (e ast.Expr, err error) {
e, err = g.VisitType(dataRaw)
if err != nil {
return
}
e = Pointer(e)
return
}
func BitSizeToProtodef(totalSize int, singed bool) (e string, err error) {
if !singed && totalSize == 1 {
e = "bool"
return
}
if singed {
e = "i"
} else {
e = "u"
}
if totalSize <= 8 {
e += "8"
} else if totalSize <= 16 {
e += "16"
} else if totalSize <= 32 {
e += "32"
} else if totalSize <= 64 {
e += "64"
} else {
err = errors.New("bitfield size too large")
}
return
}
func VisitBitFieldType(g *Generator, dataRaw any) (e ast.Expr, err error) {
var data protodef.BitField
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
ret := NewStruct()
for _, field := range data {
var p string
p, err = BitSizeToProtodef(field.Size, field.Signed)
if err != nil {
return
}
var fieldType ast.Expr
fieldType, err = g.VisitType(p)
if err != nil {
return
}
AddFieldToStruct(ret, util.CamelCase(field.Name), fieldType)
}
e = ret
return
}
func VisitBitFlagsType(g *Generator, dataRaw any) (e ast.Expr, err error) {
var data struct {
Flags []string
Type any
}
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
return g.VisitType(data.Type)
}
func MakeIdentVisitor(name string) func(g *Generator, dataRaw any) (e ast.Expr, err error) {
return func(g *Generator, dataRaw any) (e ast.Expr, err error) {
e = Ident(name)
return
}
}
func MakeSelectorVisitor(x, sel string) func(g *Generator, dataRaw any) (e ast.Expr, err error) {
return func(g *Generator, dataRaw any) (e ast.Expr, err error) {
e = Selector(x, sel)
return
}
}
func VoidType(_ *Generator, _ any) (e ast.Expr, err error) {
e = NewStruct()
return
}
func EntityMetadataLoopType(g *Generator, v any) (e ast.Expr, err error) {
var data protodef.EntityMetadataLoop
err = mapstructure.Decode(v, &data)
if err != nil {
return
}
innerType, err := g.VisitType(data.Type)
if err != nil {
return
}
e = MapType(Ident("byte"), innerType)
return
}
func (g *Generator) RegisterNatives() {
g.Natives = map[string]ExprGeneratorFunc{
"container": VisitContainerType,
"buffer": VisitBufferType,
"varint": MakeIdentVisitor("int32"),
"varlong": MakeIdentVisitor("int64"),
"array": VisitArrayTypeVisitorType,
"mapper": MakeIdentVisitor("string"),
"native": VisitDontGenerateType,
"anonymousNbt": MakeSelectorVisitor("nbt", "Anon"),
"anonOptionalNbt": MakeSelectorVisitor("nbt", "Anon"), // I have no idea what the difference is between these two
"void": VoidType,
"bool": MakeIdentVisitor("bool"),
"u8": MakeIdentVisitor("uint8"),
"u16": MakeIdentVisitor("uint16"),
"u32": MakeIdentVisitor("uint32"),
"u64": MakeIdentVisitor("uint64"),
"i8": MakeIdentVisitor("int8"),
"i16": MakeIdentVisitor("int16"),
"i32": MakeIdentVisitor("int32"),
"i64": MakeIdentVisitor("int64"),
"f32": MakeIdentVisitor("float32"),
"f64": MakeIdentVisitor("float64"),
"registryEntryHolder": MakeIdentVisitor("any"), // Go really fucking needs good tagged unions
"registryEntryHolderSet": MakeIdentVisitor("any"),
"entityMetadataLoop": EntityMetadataLoopType,
"option": VisitOptionType,
"switch": MakeIdentVisitor("any"),
"UUID": MakeSelectorVisitor("uuid", "UUID"),
"bitfield": VisitBitFieldType,
"pstring": VisitDontGenerateType,
"string": MakeIdentVisitor("string"),
"restBuffer": MakeSelectorVisitor("proto_base", "RestBuffer"),
"bitflags": VisitBitFlagsType,
"topBitSetTerminatedArray": VisitToDoType,
"todo": VisitToDoType,
"lpVec3": MakeSelectorVisitor("proto_base", "LpVec3d"),
}
}
+587
View File
@@ -0,0 +1,587 @@
package main
import (
"bytes"
"fmt"
"go/ast"
"go/format"
"go/token"
"io"
"strings"
)
func NewStruct() (s *ast.StructType) {
return &ast.StructType{
Fields: &ast.FieldList{
List: []*ast.Field{},
},
}
}
func AddFieldToStruct(s *ast.StructType, fieldName string, t ast.Expr) {
s.Fields.List = append(s.Fields.List, &ast.Field{
Names: []*ast.Ident{
{
Name: fieldName,
},
},
Type: t,
})
}
//func AddAnonFieldToStruct(s *ast.StructType, t ast.Expr) {
// s.Fields.List = append(s.Fields.List, &ast.Field{
// Names: []*ast.Ident{},
// Type: t,
// })
//}
func Import(path ...string) ast.Decl {
specs := make([]ast.Spec, len(path))
for i, p := range path {
specs[i] = &ast.ImportSpec{
Path: StrLit(p),
}
}
return &ast.GenDecl{
Tok: token.IMPORT,
Specs: specs,
}
}
func Ident(name string) (id *ast.Ident) {
return ast.NewIdent(name)
}
func VarStmt(name string, t ast.Expr) *ast.DeclStmt {
return &ast.DeclStmt{Decl: Var(name, t)}
}
func VarValues(name string, v ...ast.Expr) ast.Decl {
return &ast.GenDecl{
Tok: token.VAR,
Specs: []ast.Spec{
&ast.ValueSpec{
Names: []*ast.Ident{Ident(name)},
Values: v,
},
},
}
}
func Var(name string, t ast.Expr) ast.Decl {
return &ast.GenDecl{
Tok: token.VAR,
Specs: []ast.Spec{
&ast.ValueSpec{
Names: []*ast.Ident{
{
Name: name,
},
},
Type: t,
},
},
}
}
func Slice(elementType ast.Expr) (e ast.Expr) {
return &ast.ArrayType{
Len: nil, // nil Length means it's a slice, not an array
Elt: elementType,
}
}
func NumLit(n int) *ast.BasicLit {
return NumLitStr(fmt.Sprint(n))
}
func NumLitHex(n int) *ast.BasicLit {
return NumLitStr(fmt.Sprintf("0x%X", n))
}
func NumLitStr(n string) *ast.BasicLit {
return &ast.BasicLit{
ValuePos: 0,
Kind: token.INT,
Value: n,
}
}
func Array(elementType ast.Expr, len int) ast.Expr {
return &ast.ArrayType{
Len: NumLit(len),
Elt: elementType,
}
}
func TypeDecl(name string, t ast.Expr) ast.Decl {
return &ast.GenDecl{
Tok: token.TYPE,
Specs: []ast.Spec{
&ast.TypeSpec{
Name: &ast.Ident{
Name: name,
},
Type: t,
},
},
}
}
func Selector(x, sel string) (e ast.Expr) {
return &ast.SelectorExpr{
X: Ident(x),
Sel: Ident(sel),
}
}
func SelectorExprAndStr(x ast.Expr, sel string) (e ast.Expr) {
return &ast.SelectorExpr{
X: x,
Sel: Ident(sel),
}
}
func Pointer(elementType ast.Expr) (e ast.Expr) {
return &ast.StarExpr{
X: elementType,
}
}
func Call(fn ast.Expr, args ...ast.Expr) (e *ast.CallExpr) {
return &ast.CallExpr{
Fun: fn,
Args: args,
}
}
func Assign121(lhs, rhs ast.Expr) (s *ast.AssignStmt) {
return &ast.AssignStmt{
Lhs: []ast.Expr{lhs},
Tok: token.ASSIGN,
Rhs: []ast.Expr{rhs},
}
}
func Assign(lhs, rhs []ast.Expr) (s *ast.AssignStmt) {
return &ast.AssignStmt{
Lhs: lhs,
Tok: token.ASSIGN,
Rhs: rhs,
}
}
func Define(lhs, rhs []ast.Expr) (s *ast.AssignStmt) {
return &ast.AssignStmt{
Lhs: lhs,
Tok: token.DEFINE,
Rhs: rhs,
}
}
func Define121(lhs, rhs ast.Expr) (s *ast.AssignStmt) {
return &ast.AssignStmt{
Lhs: []ast.Expr{lhs},
Tok: token.DEFINE,
Rhs: []ast.Expr{rhs},
}
}
func SubAssign(lhs, rhs ast.Expr) (s *ast.AssignStmt) {
return &ast.AssignStmt{
Lhs: []ast.Expr{lhs},
Tok: token.SUB_ASSIGN,
Rhs: []ast.Expr{rhs},
}
}
func OrAssign(lhs, rhs ast.Expr) (s *ast.AssignStmt) {
return &ast.AssignStmt{
Lhs: []ast.Expr{lhs},
Tok: token.OR_ASSIGN,
Rhs: []ast.Expr{rhs},
}
}
func Exprs(exprs ...ast.Expr) []ast.Expr {
return exprs
}
func Stmts(stmts ...ast.Stmt) []ast.Stmt {
return stmts
}
func ExprStmt(expr ast.Expr) *ast.ExprStmt {
return &ast.ExprStmt{
X: expr,
}
}
func If(cond ast.Expr, body *ast.BlockStmt) *ast.IfStmt {
return &ast.IfStmt{
Cond: cond,
Body: body,
}
}
func IfElse(cond ast.Expr, body *ast.BlockStmt, els *ast.BlockStmt) *ast.IfStmt {
return &ast.IfStmt{
Cond: cond,
Body: body,
Else: els,
}
}
func NotEquals(lhs, rhs ast.Expr) *ast.BinaryExpr {
return &ast.BinaryExpr{
X: lhs,
Op: token.NEQ,
Y: rhs,
}
}
func Equals(lhs, rhs ast.Expr) *ast.BinaryExpr {
return &ast.BinaryExpr{
X: lhs,
Op: token.EQL,
Y: rhs,
}
}
func GreaterThanOrEqual(lhs, rhs ast.Expr) *ast.BinaryExpr {
return &ast.BinaryExpr{
X: lhs,
Op: token.GEQ,
Y: rhs,
}
}
func Nil() ast.Expr {
return Ident("nil")
}
func NewFile(name string) *ast.File {
return &ast.File{
Name: &ast.Ident{
Name: name,
},
Decls: []ast.Decl{},
}
}
type NameAndType struct {
Name string
Type ast.Expr
}
func NewFunc(name string, arguments []NameAndType, returns []NameAndType) *ast.FuncDecl {
params := &ast.FieldList{
List: make([]*ast.Field, len(arguments)),
}
for i, arg := range arguments {
params.List[i] = &ast.Field{
Names: []*ast.Ident{Ident(arg.Name)},
Type: arg.Type,
}
}
results := &ast.FieldList{
List: make([]*ast.Field, len(returns)),
}
for i, ret := range returns {
results.List[i] = &ast.Field{
Names: []*ast.Ident{{Name: ret.Name}},
Type: ret.Type,
}
}
return &ast.FuncDecl{
Name: Ident(name),
Type: &ast.FuncType{
Params: params,
Results: results,
},
Body: &ast.BlockStmt{},
}
}
func NewFuncWithReceiver(name, receiverName string, receiver ast.Expr, arguments []NameAndType, returns []NameAndType) *ast.FuncDecl {
f := NewFunc(name, arguments, returns)
f.Recv = &ast.FieldList{
List: []*ast.Field{
{
Names: []*ast.Ident{{Name: receiverName}},
Type: receiver,
},
},
}
return f
}
func NewBlock(statements []ast.Stmt) *ast.BlockStmt {
return &ast.BlockStmt{
List: statements,
}
}
func NewBlockEllipsis(statements ...ast.Stmt) *ast.BlockStmt {
return &ast.BlockStmt{
List: statements,
}
}
func Break() *ast.BranchStmt {
return &ast.BranchStmt{
Tok: token.BREAK,
}
}
//func MergeBlocks(blocks ...*ast.BlockStmt) *ast.BlockStmt {
// list := make([]ast.Stmt, 0)
// for _, block := range blocks {
// if block != nil {
// list = append(list, block.List...)
// }
// }
// return &ast.BlockStmt{
// List: list,
// }
//}
func Return(exprs ...ast.Expr) *ast.ReturnStmt {
return &ast.ReturnStmt{
Results: exprs,
}
}
func AppendDecl(file *ast.File, decl ast.Decl) {
file.Decls = append(file.Decls, decl)
}
// AddFileComment adds a comment block at the top of the file
func AddFileComment(f *ast.File, comment string) {
f.Doc = &ast.CommentGroup{}
lines := strings.Split(comment, "\n")
for _, line := range lines {
f.Doc.List = append(f.Doc.List, &ast.Comment{Text: "// " + line})
}
}
func PrintToFile(f *ast.File, w io.Writer) error {
// Extract doc comment header if present
var header string
if f.Doc != nil {
for _, c := range f.Doc.List {
header += c.Text + "\n"
}
f.Doc = nil // Clear so go/format doesn't print it
}
// Format the file
var buf bytes.Buffer
if err := format.Node(&buf, token.NewFileSet(), f); err != nil {
return err
}
// Find where "package " starts in formatted output
formatted := buf.String()
pkgIndex := strings.Index(formatted, "package ")
if pkgIndex < 0 {
pkgIndex = 0
}
// Write header, then formatted content starting from package
w.Write([]byte(header))
w.Write([]byte(formatted[pkgIndex:]))
return nil
}
func IfErrNil() *ast.IfStmt {
return If(
NotEquals(Ident("err"), Nil()), NewBlockEllipsis(Return()),
)
}
func AddrOf(e ast.Expr) *ast.UnaryExpr {
return &ast.UnaryExpr{
Op: token.AND,
X: e,
}
}
func DeRef(e ast.Expr) *ast.StarExpr {
return &ast.StarExpr{
X: e,
}
}
func ForRange(K, X ast.Expr, block *ast.BlockStmt) *ast.RangeStmt {
return &ast.RangeStmt{
Key: K, // The loop variable "i"
Value: nil, // No second variable (common for index-only range loops)
X: X, // The collection being ranged over "l"
Tok: token.DEFINE, // ":=" token
Body: block,
}
}
func ForRangeKV(K, V, X ast.Expr, block *ast.BlockStmt) *ast.RangeStmt {
return &ast.RangeStmt{
Key: K,
Value: V,
X: X,
Tok: token.DEFINE,
Body: block,
}
}
func Index(X, I ast.Expr) *ast.IndexExpr {
return &ast.IndexExpr{
X: X,
Index: I,
}
}
func MultiIndex(X ast.Expr, Low, High, Max ast.Expr) *ast.SliceExpr {
return &ast.SliceExpr{
X: X,
Low: Low,
High: High,
Max: Max,
Slice3: Max != nil,
}
}
func SwitchStmt(Tag ast.Expr, block *ast.BlockStmt) *ast.SwitchStmt {
return &ast.SwitchStmt{
Tag: Tag,
Body: block,
}
}
//func SwitchStmtInit(init ast.Stmt, block *ast.BlockStmt) *ast.SwitchStmt {
// return &ast.SwitchStmt{
// Init: init,
// Body: block,
// }
//}
func StrLit(s string) *ast.BasicLit {
return &ast.BasicLit{
Kind: token.STRING,
Value: `"` + s + `"`,
}
}
func Case(exprs []ast.Expr, stmts []ast.Stmt) *ast.CaseClause {
return &ast.CaseClause{
List: exprs,
Body: stmts,
}
}
func MapType(key, value ast.Expr) ast.Expr {
return &ast.MapType{
Key: key,
Value: value,
}
}
func CompLit(t ast.Expr, elts []ast.Expr) *ast.CompositeLit {
return &ast.CompositeLit{
Type: t,
Elts: elts,
}
}
//func VarAssign(name string, value ast.Expr) *ast.GenDecl {
// return &ast.GenDecl{
// Tok: token.VAR,
// Specs: []ast.Spec{
// &ast.ValueSpec{
// Names: []*ast.Ident{
// {
// Name: name,
// },
// },
// Values: []ast.Expr{value},
// },
// },
// }
//}
func KeyValueExpr(key, value ast.Expr) *ast.KeyValueExpr {
return &ast.KeyValueExpr{
Key: key,
Value: value,
}
}
func TypeAssert(x, t ast.Expr) *ast.TypeAssertExpr {
return &ast.TypeAssertExpr{
X: x,
Type: t,
}
}
func TypeSwitch(x ast.Stmt, block *ast.BlockStmt) *ast.TypeSwitchStmt {
return &ast.TypeSwitchStmt{
Assign: x,
Body: block,
}
}
func Not(x ast.Expr) *ast.UnaryExpr {
return &ast.UnaryExpr{
Op: token.NOT,
X: x,
}
}
func Sub(lhs, rhs ast.Expr) *ast.BinaryExpr {
return &ast.BinaryExpr{
X: lhs,
Op: token.SUB,
Y: rhs,
}
}
func BinAnd(lhs, rhs ast.Expr) *ast.BinaryExpr {
return &ast.BinaryExpr{
X: lhs,
Op: token.AND,
Y: rhs,
}
}
func RightShift(lhs, rhs ast.Expr) *ast.BinaryExpr {
return &ast.BinaryExpr{
X: lhs,
Op: token.SHR,
Y: rhs,
}
}
func LeftShift(lhs, rhs ast.Expr) *ast.BinaryExpr {
return &ast.BinaryExpr{
X: lhs,
Op: token.SHL,
Y: rhs,
}
}
func Grouping(e ast.Expr) *ast.ParenExpr {
return &ast.ParenExpr{
X: e,
}
}
func ForStmt(init ast.Stmt, cond ast.Expr, post ast.Stmt, body *ast.BlockStmt) *ast.ForStmt {
return &ast.ForStmt{
Init: init,
Cond: cond,
Post: post,
Body: body,
}
}
+72
View File
@@ -0,0 +1,72 @@
package protodef
type (
BitFieldEntry struct {
Name string
Signed bool
Size int
}
BitField []BitFieldEntry
EntryHolderSet struct {
BaseName string
Otherwise struct {
Name string
Type any
}
}
Switch struct {
CompareTo string
Fields map[string]any
Default any
}
// TypeForward is not a real type, I just didn't implement it all yet, and it's just the underlying type
TypeForward struct {
Type string
}
Buffer struct {
Count int
CountType any
}
Array struct {
CountType any
Count string
Type any
}
Container []struct {
Name string
Type any
Anon bool
}
Mapper struct {
Mappings map[string]string
Type any
}
RegistryEntryHolderSet struct {
Base struct {
Name string
Type any
}
Otherwise struct {
Name string
Type any
}
}
BitFlags struct {
Flags []string
Type any
}
EntityMetadataLoop struct {
EndVal int
Type any
}
)