// Copyright 2017-2025 WIT.COM Inc. All rights reserved. // Use of this source code is governed by the GPL 3.0 package main // auto run protoc with the correct args import ( "os" "strings" "go.wit.com/lib/fhelp" "golang.org/x/text/cases" "golang.org/x/text/language" ) // this parses the .proto file and handles anything with `autogenpb: ` func (pf *File) protoParse() error { // does the file conform to the standard? (also reads in UUID & Version) // if err := pb.hasPluralMessage(pf); err != nil { // return err // } // os.Exit(0) uuid, version, err := fhelp.ValidProtobuf(pf.Filename) if err != nil { // the user can bypass this, but it's probably not worth allowing this if os.Getenv("PROTOBUF_REGRET") != "true" { return err } } pf.Uuid = uuid pf.Version = version // read in the .proto file data, err := os.ReadFile(pf.Filename) if err != nil { return err } var curmsg *MsgName // parse the proto file for message struct names for _, line := range strings.Split(string(data), "\n") { if strings.HasPrefix(line, "message ") { curmsg = pf.parseForMessage(line) } // this logic isn't right. find end of message with more bravado if strings.HasPrefix(line, "}") { curmsg = nil } if curmsg == nil { // log.Info("curmsg == nil", line) // can't contiue on nil below here continue } // log.Info("curmsg != nil", line) parts := strings.Fields(line) msgvar := parseMsgVar(line) if msgvar == nil { // log.Info("Junk in .proto file? line did not contain a message var:", line) continue } if msgvar.IsRepeated { // log.Info("ADDING ITER MAP", curmsg.Name, msgvar.VarType) pf.IterMap[curmsg.Name] = msgvar.VarType } if strings.Contains(line, "autogenpb:sort") { newS := cases.Title(language.English, cases.NoLower).String(parts[1]) // log.Info("Addded Sort:", newS, "in struct", curmsg.Name) curmsg.Sort = append(curmsg.Sort, newS) msgvar.HasSort = true } if strings.Contains(line, "autogenpb:unique") { newU := parts[1] newU = cases.Title(language.English, cases.NoLower).String(newU) // log.Info("Added Unique:", newU, "in struct", curmsg.Name) curmsg.Unique = append(curmsg.Unique, newU) msgvar.HasUnique = true } curmsg.Vars = append(curmsg.Vars, msgvar) } pf.makeSortTable() // for i, s := range slices.Backward(pf.ToSort) { return nil } func (pf *File) makeSortTable() { pf.sortWhat(pf.Bases) pf.sortWhat(pf.Base) // everything else for _, msg := range pf.MsgNames { pf.sortWhat(msg) } } func (pf *File) sortWhat(msg *MsgName) { for _, v := range msg.Vars { if !v.IsRepeated { continue } if check := pf.findMsg(v.VarType); check == nil { // the VarType must be a struct continue } s := new(Sort) s.MsgName = msg.Name s.VarType = v.VarType s.VarName = v.VarName s.Lockname = msg.Lockname pf.ToSort = append(pf.ToSort, s) } } func parseMsgVar(line string) *MsgVar { if strings.Contains(line, "//") { parts := strings.Split(line, "//") if len(parts) == 0 { // log.Info("parseMsgVar() nothing line", line) return nil } line = parts[0] } parts := strings.Fields(line) if len(parts) < 3 { // log.Info("parseMsgVar() len < 3", parts) return nil } if parts[0] == "message" { // this is the struct return nil } v := new(MsgVar) if parts[0] == "repeated" { v.IsRepeated = true v.VarType = parts[1] v.VarName = cases.Title(language.English, cases.NoLower).String(parts[2]) return v } v.VarType = parts[0] v.VarName = cases.Title(language.English, cases.NoLower).String(parts[1]) return v } // looks for mutex and marshal entries func (pf *File) parseForMessage(line string) *MsgName { fields := strings.Fields(line) if len(fields) == 0 || fields[0] != "message" { return nil } var msg *MsgName msg = new(MsgName) base := cases.Title(language.English, cases.NoLower).String(pf.Filebase) prefix := "message " + base + "s {" // only look for this for now if strings.HasPrefix(line, prefix) { pf.Bases = msg } else { prefix := "message " + base + " {" // only look for this for now if strings.HasPrefix(line, prefix) { pf.Base = msg } else { pf.MsgNames = append(pf.MsgNames, msg) } } msgName := cases.Title(language.English, cases.NoLower).String(fields[1]) // log.Info("found messge:", msgName) msg.Name = msgName msg.Lockname = pf.Filebase + "Mu" // this should be lowercase. do not export the Mutex msg.NeedIter = true if strings.Contains(line, "`autogenpb:mutex`") { msg.DoMutex = true // log.Info("Added Mutex=true:", msg.Name) } if strings.Contains(line, "`autogenpb:nomutex`") { msg.NoMutex = true // log.Info("Added Mutex=true:", msg.Name) } if strings.Contains(line, "`autogenpb:marshal`") { msg.DoMarshal = true // log.Info("Added Marshal=true:", msg.Name) } return msg }