Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions internal/importer/book/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ func (t *Table) IsRowEmpty(row int) bool {
// it will just return the start row. Otherwise, it will return the last
// none-empty row.
//
// NOTE: A block is a series of contiguous none-empty rows.
// NOTE: A block is a series of contiguous none-empty rows. So different blocks
// are seperated by one or more empty rows.
func (t *Table) FindBlockEndRow(startRow int) int {
for row := startRow; row <= len(t.Rows); row++ {
if t.IsRowEmpty(row) {
Expand All @@ -76,7 +77,8 @@ func (t *Table) FindBlockEndRow(startRow int) int {

// ExtractBlock extracts a block of rows.
//
// NOTE: A block is a series of contiguous none-empty rows.
// NOTE: A block is a series of contiguous none-empty rows. So different blocks
// are seperated by one or more empty rows.
func (t *Table) ExtractBlock(startRow int) (rows [][]string, endRow int) {
endRow = t.FindBlockEndRow(startRow)
rows = t.Rows[startRow : endRow+1]
Expand Down
9 changes: 8 additions & 1 deletion internal/protogen/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ func (x *sheetExporter) export() error {
return x.exportMessager()
case tableaupb.Mode_MODE_ENUM_TYPE, tableaupb.Mode_MODE_ENUM_TYPE_MULTI:
return x.exportEnum()
case tableaupb.Mode_MODE_STRUCT_TYPE:
case tableaupb.Mode_MODE_STRUCT_TYPE, tableaupb.Mode_MODE_STRUCT_TYPE_MULTI:
return x.exportStruct()
case tableaupb.Mode_MODE_UNION_TYPE:
return x.exportUnion()
Expand Down Expand Up @@ -186,6 +186,13 @@ func (x *sheetExporter) exportEnum() error {
func (x *sheetExporter) exportStruct() error {
x.g.P("// Generated from sheet: ", x.ws.GetOptions().GetName(), ".")
x.g.P("message ", x.ws.Name, " {")
// TODO: support worksheet options, but should not be treated as a
// standard config message, as this is a predefined message.
// if x.ws.Alias != "" {
// opts := &tableaupb.WorkbookOptions{Name: x.ws.Alias}
// x.g.P(" option (tableau.worksheet) = {", marshalToText(opts), "};")
// x.g.P("")
// }
// generate the fields
depth := 1
for i, field := range x.ws.Fields {
Expand Down
99 changes: 66 additions & 33 deletions internal/protogen/protogen.go
Original file line number Diff line number Diff line change
Expand Up @@ -519,14 +519,14 @@ func (gen *Generator) extractTypeInfoFromSpecialSheetMode(mode tableaupb.Mode, s
case tableaupb.Mode_MODE_ENUM_TYPE_MULTI:
for row := 0; row <= sheet.Table.MaxRow; row++ {
cols := sheet.Table.GetRow(row)
if isEnumTypeDefinitionBlockHeader(cols) {
if isEnumTypeBlockHeader(cols) {
if row < 1 {
continue
}
typeRow := sheet.Table.GetRow(row - 1)
typeName, _, _, err := extractEnumTypeRow(typeRow)
if err != nil {
return xerrors.Wrapf(err, "failed to parse enum type block at row: %d, sheet: %s", row, sheet.Name)
return xerrors.Wrapf(err, "failed to parse enum type block, sheet: %s, row: %d", sheet.Name, row)
}
// add type info
info := &xproto.TypeInfo{
Expand Down Expand Up @@ -554,7 +554,40 @@ func (gen *Generator) extractTypeInfoFromSpecialSheetMode(mode tableaupb.Mode, s
FirstFieldOptionName: firstFieldOptionName,
}
gen.typeInfos.Put(info)

case tableaupb.Mode_MODE_STRUCT_TYPE_MULTI:
for row := 0; row <= sheet.Table.MaxRow; row++ {
cols := sheet.Table.GetRow(row)
if isStructTypeBlockHeader(cols) {
if row < 1 {
continue
}
typeRow := sheet.Table.GetRow(row - 1)
typeName, _, _, err := extractStructTypeRow(typeRow)
if err != nil {
return xerrors.Wrapf(err, "failed to parse struct type block at row: %d, sheet: %s", row, sheet.Name)
}
blockBeginRow := row
block, blockEndRow := sheet.Table.ExtractBlock(blockBeginRow)
row = blockEndRow // skip row to next block
subSheet := book.NewTableSheet(sheet.Name, block)
desc := &internalpb.StructDescriptor{}
if err := parser.Parse(desc, subSheet); err != nil {
return xerrors.Wrapf(err, "failed to parse struct type block, sheet: %s, row: %d", sheet.Name, row)
}
firstFieldOptionName := ""
if len(desc.Fields) != 0 {
firstFieldOptionName = desc.Fields[0].Name
}
// add type info
info := &xproto.TypeInfo{
FullName: protoreflect.FullName(gen.ProtoPackage + "." + typeName),
ParentFilename: parentFilename,
Kind: types.MessageKind,
FirstFieldOptionName: firstFieldOptionName,
}
gen.typeInfos.Put(info)
}
}
case tableaupb.Mode_MODE_UNION_TYPE:
// add union self type info
info := &xproto.TypeInfo{
Expand Down Expand Up @@ -618,7 +651,7 @@ func (gen *Generator) parseSpecialSheetMode(mode tableaupb.Mode, ws *internalpb.
var worksheets []*internalpb.Worksheet
for row := 0; row <= sheet.Table.MaxRow; row++ {
cols := sheet.Table.GetRow(row)
if isEnumTypeDefinitionBlockHeader(cols) {
if isEnumTypeBlockHeader(cols) {
if row < 1 {
continue
}
Expand All @@ -628,11 +661,11 @@ func (gen *Generator) parseSpecialSheetMode(mode tableaupb.Mode, ws *internalpb.
subWs := proto.Clone(ws).(*internalpb.Worksheet)
subWs.Name, subWs.Alias, subWs.Note, err = extractEnumTypeRow(typeRow)
if err != nil {
return nil, xerrors.Wrapf(err, "failed to parse enum type block at row: %d, sheet: %s", row, sheet.Name)
return nil, xerrors.Wrapf(err, "failed to extract enum type block at row: %d, sheet: %s", row, sheet.Name)
}
block, blockEndRow := sheet.Table.ExtractBlock(blockBeginRow)
row = blockEndRow // skip row to next block
subSheet := book.NewTableSheet(sheet.Name, block)
subSheet := book.NewTableSheet(subWs.Name, block)
if err := parseEnumTypeValues(subWs, subSheet, parser); err != nil {
return nil, err
}
Expand All @@ -641,36 +674,36 @@ func (gen *Generator) parseSpecialSheetMode(mode tableaupb.Mode, ws *internalpb.
}
return worksheets, nil
case tableaupb.Mode_MODE_STRUCT_TYPE:
desc := &internalpb.StructDescriptor{}
if err := parser.Parse(desc, sheet); err != nil {
return nil, xerrors.Wrapf(err, "failed to parse struct type sheet: %s", sheet.Name)
}
bp := newBookParser("struct", "", "", gen)
shHeader := &tableHeader{
meta: &tableaupb.WorksheetOptions{
Namerow: 1,
Typerow: 2,
},
validNames: map[string]int{},
}
for _, field := range desc.Fields {
shHeader.namerow = append(shHeader.namerow, field.Name)
shHeader.typerow = append(shHeader.typerow, field.Type)
shHeader.noterow = append(shHeader.noterow, "")
if err := parseStructTypeValues(ws, sheet, parser, gen, debugBookName, debugSheetName); err != nil {
return nil, err
}
var parsed bool
var err error
for cursor := 0; cursor < len(shHeader.namerow); cursor++ {
subField := &internalpb.Field{}
cursor, parsed, err = bp.parseField(subField, shHeader, cursor, "")
if err != nil {
return nil, wrapDebugErr(err, debugBookName, debugSheetName, shHeader, cursor)
}
if parsed {
ws.Fields = append(ws.Fields, subField)
return []*internalpb.Worksheet{ws}, nil
case tableaupb.Mode_MODE_STRUCT_TYPE_MULTI:
var worksheets []*internalpb.Worksheet
for row := 0; row <= sheet.Table.MaxRow; row++ {
cols := sheet.Table.GetRow(row)
if isStructTypeBlockHeader(cols) {
if row < 1 {
continue
}
blockBeginRow := row
typeRow := sheet.Table.GetRow(row - 1)
var err error
subWs := proto.Clone(ws).(*internalpb.Worksheet)
subWs.Name, subWs.Alias, subWs.Note, err = extractStructTypeRow(typeRow)
if err != nil {
return nil, xerrors.Wrapf(err, "failed to extract struct type block at row: %d, sheet: %s", row, sheet.Name)
}
block, blockEndRow := sheet.Table.ExtractBlock(blockBeginRow)
row = blockEndRow // skip row to next block
subSheet := book.NewTableSheet(subWs.Name, block)
if err := parseStructTypeValues(subWs, subSheet, parser, gen, debugBookName, debugSheetName); err != nil {
return nil, err
}
worksheets = append(worksheets, subWs)
}
}
return []*internalpb.Worksheet{ws}, nil
return worksheets, nil
case tableaupb.Mode_MODE_UNION_TYPE:
desc := &internalpb.UnionDescriptor{}
if err := parser.Parse(desc, sheet); err != nil {
Expand Down
122 changes: 122 additions & 0 deletions internal/protogen/sheet_mode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package protogen

import (
"fmt"

"github.com/tableauio/tableau/internal/importer/book"
"github.com/tableauio/tableau/proto/tableaupb"
"github.com/tableauio/tableau/proto/tableaupb/internalpb"
"github.com/tableauio/tableau/xerrors"
)

const (
colNumber = "Number" // name of column "Number"
colName = "Name" // name of column "Name"
colType = "Type" // name of column "Type"
colAlias = "Alias" // name of column "Alias"
)

func isEnumTypeBlockHeader(cols []string) bool {
if len(cols) < 3 {
return false
}
return cols[0] == colNumber && cols[1] == colName && cols[2] == colAlias
}

// extractEnumTypeRow find the first none-empty column as "name", and then
// the two subsequent columns as "alias" and "note" if provided.
func extractEnumTypeRow(cols []string) (name, alias, note string, err error) {
for i, cell := range cols {
if cell != "" {
name = cell
if i+1 < len(cols) {
alias = cols[i+1]
}
if i+2 < len(cols) {
note = cols[i+2]
}
break
}
}
if name == "" {
err = fmt.Errorf("name cell not found in enum type name row")
}
return
}

func parseEnumTypeValues(ws *internalpb.Worksheet, sheet *book.Sheet, parser book.SheetParser) error {
desc := &internalpb.EnumDescriptor{}
if err := parser.Parse(desc, sheet); err != nil {
return xerrors.Wrapf(err, "failed to parse enum type sheet (block): %s", sheet.Name)
}
for i, value := range desc.Values {
number := int32(i + 1)
if value.Number != nil {
number = *value.Number
}
field := &internalpb.Field{
Number: number,
Name: value.Name,
Alias: value.Alias,
}
ws.Fields = append(ws.Fields, field)
}
return nil
}

func isStructTypeBlockHeader(cols []string) bool {
if len(cols) < 2 {
return false
}
return cols[0] == colName && cols[1] == colType
}

// extractStructTypeRow find the first none-empty column as "name", and then
// the two subsequent columns as "alias" and "note" if provided.
func extractStructTypeRow(cols []string) (name, alias, note string, err error) {
if len(cols) == 0 || cols[0] == "" {
err = fmt.Errorf("name cell not found in struct type name row")
return
}
name = cols[0]
if len(cols) >= 2 {
alias = cols[1]
}
if len(cols) >= 3 {
note = cols[2]
}
return
}

func parseStructTypeValues(ws *internalpb.Worksheet, sheet *book.Sheet, parser book.SheetParser, gen *Generator, debugBookName, debugSheetName string) error {
desc := &internalpb.StructDescriptor{}
if err := parser.Parse(desc, sheet); err != nil {
return xerrors.Wrapf(err, "failed to parse struct type sheet (block): %s", sheet.Name)
}
bp := newBookParser("struct", "", "", gen)
shHeader := &tableHeader{
meta: &tableaupb.WorksheetOptions{
Namerow: 1,
Typerow: 2,
},
validNames: map[string]int{},
}
for _, field := range desc.Fields {
shHeader.namerow = append(shHeader.namerow, field.Name)
shHeader.typerow = append(shHeader.typerow, field.Type)
shHeader.noterow = append(shHeader.noterow, "")
}
var parsed bool
var err error
for cursor := 0; cursor < len(shHeader.namerow); cursor++ {
subField := &internalpb.Field{}
cursor, parsed, err = bp.parseField(subField, shHeader, cursor, "")
if err != nil {
return wrapDebugErr(err, debugBookName, debugSheetName, shHeader, cursor)
}
if parsed {
ws.Fields = append(ws.Fields, subField)
}
}
return nil
}
55 changes: 0 additions & 55 deletions internal/protogen/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
"github.com/tableauio/tableau/internal/x/xfs"
"github.com/tableauio/tableau/options"
"github.com/tableauio/tableau/proto/tableaupb"
"github.com/tableauio/tableau/proto/tableaupb/internalpb"
"github.com/tableauio/tableau/xerrors"
)

Expand All @@ -24,60 +23,6 @@ const (
secondPass // generate config messagers from sheets
)

const (
colNumber = "Number" // name of column "Number"
colName = "Name" // name of column "Name"
colAlias = "Alias" // name of column "Alias"
)

func isEnumTypeDefinitionBlockHeader(cols []string) bool {
if len(cols) < 3 {
return false
}
return cols[0] == colNumber && cols[1] == colName && cols[2] == colAlias
}

// extractEnumTypeRow find the first none-empty column as "name", and then
// the two subsequent columns as "alias" and "note" if provided.
func extractEnumTypeRow(cols []string) (name, alias, note string, err error) {
for i, cell := range cols {
if cell != "" {
name = cell
if i+1 < len(cols) {
alias = cols[i+1]
}
if i+2 < len(cols) {
note = cols[i+2]
}
break
}
}
if name == "" {
err = fmt.Errorf("name cell not found in enum type row")
}
return
}

func parseEnumTypeValues(ws *internalpb.Worksheet, sheet *book.Sheet, parser book.SheetParser) error {
desc := &internalpb.EnumDescriptor{}
if err := parser.Parse(desc, sheet); err != nil {
return xerrors.Wrapf(err, "failed to parse enum type sheet: %s", sheet.Name)
}
for i, value := range desc.Values {
number := int32(i + 1)
if value.Number != nil {
number = *value.Number
}
field := &internalpb.Field{
Number: number,
Name: value.Name,
Alias: value.Alias,
}
ws.Fields = append(ws.Fields, field)
}
return nil
}

func prepareOutdir(outdir string, importFiles []string, delExisted bool) error {
existed, err := xfs.Exists(outdir)
if err != nil {
Expand Down
Loading