636 lines
25 KiB
Go
636 lines
25 KiB
Go
package generator
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/edmand46/arpack/parser"
|
|
)
|
|
|
|
// GenerateTypeScript generates TypeScript code for the given messages
|
|
func GenerateTypeScript(messages []parser.Message, namespace string) ([]byte, error) {
|
|
return GenerateTypeScriptSchema(parser.Schema{Messages: messages}, namespace)
|
|
}
|
|
|
|
// GenerateTypeScriptSchema generates TypeScript code from a schema
|
|
func GenerateTypeScriptSchema(schema parser.Schema, namespace string) ([]byte, error) {
|
|
messages := schema.Messages
|
|
var b strings.Builder
|
|
|
|
b.WriteString("// <auto-generated> arpack </auto-generated>\n")
|
|
b.WriteString("// Code generated by arpack. DO NOT EDIT.\n\n")
|
|
|
|
enumNames := make(map[string]struct{}, len(schema.Enums))
|
|
for _, enum := range schema.Enums {
|
|
enumNames[enum.Name] = struct{}{}
|
|
}
|
|
|
|
// Generate enums
|
|
for _, enum := range schema.Enums {
|
|
writeTSEnum(&b, enum)
|
|
b.WriteString("\n")
|
|
}
|
|
|
|
// Generate messages
|
|
for i, msg := range messages {
|
|
if err := writeTSMessage(&b, msg, enumNames); err != nil {
|
|
return nil, fmt.Errorf("message %s: %w", msg.Name, err)
|
|
}
|
|
if i < len(messages)-1 {
|
|
b.WriteString("\n")
|
|
}
|
|
}
|
|
|
|
return []byte(b.String()), nil
|
|
}
|
|
|
|
func writeTSEnum(b *strings.Builder, enum parser.Enum) {
|
|
fmt.Fprintf(b, "export enum %s {\n", enum.Name)
|
|
for i, value := range enum.Values {
|
|
fmt.Fprintf(b, " %s = %s", value.Name, value.Value)
|
|
if i < len(enum.Values)-1 {
|
|
b.WriteString(",")
|
|
}
|
|
b.WriteString("\n")
|
|
}
|
|
b.WriteString("}\n")
|
|
}
|
|
|
|
func writeTSMessage(b *strings.Builder, msg parser.Message, enumNames map[string]struct{}) error {
|
|
segs := segmentFields(msg.Fields)
|
|
|
|
fmt.Fprintf(b, "export class %s {\n", msg.Name)
|
|
|
|
// Field declarations with defaults
|
|
for _, f := range msg.Fields {
|
|
defaultValue := tsDefaultValue(f)
|
|
fmt.Fprintf(b, " %s: %s = %s;\n", toCamelCase(f.Name), tsTypeName(f, enumNames), defaultValue)
|
|
}
|
|
b.WriteString("\n")
|
|
|
|
// Serialize method
|
|
b.WriteString(" serialize(view: DataView, offset: number): number {\n")
|
|
b.WriteString(" let pos = offset;\n")
|
|
for i, seg := range segs {
|
|
if seg.single != nil {
|
|
if err := writeTSSerializeField(b, "this", *seg.single, " ", enumNames); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
writeTSBoolGroupSerialize(b, "this", seg.bools, i, " ")
|
|
}
|
|
}
|
|
b.WriteString(" return pos - offset;\n")
|
|
b.WriteString(" }\n\n")
|
|
|
|
// Deserialize method
|
|
fmt.Fprintf(b, " static deserialize(view: DataView, offset: number): [%s, number] {\n", msg.Name)
|
|
b.WriteString(" let pos = offset;\n")
|
|
b.WriteString(fmt.Sprintf(" const msg = new %s();\n", msg.Name))
|
|
for i, seg := range segs {
|
|
if seg.single != nil {
|
|
if err := writeTSDeserializeField(b, "msg", *seg.single, " ", enumNames); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
writeTSBoolGroupDeserialize(b, "msg", seg.bools, i, " ")
|
|
}
|
|
}
|
|
b.WriteString(" return [msg, pos - offset];\n")
|
|
b.WriteString(" }\n")
|
|
|
|
b.WriteString("}\n")
|
|
return nil
|
|
}
|
|
|
|
func writeTSBoolGroupSerialize(b *strings.Builder, recv string, bools []parser.Field, groupIdx int, indent string) {
|
|
varName := fmt.Sprintf("_boolByte%d", groupIdx)
|
|
fmt.Fprintf(b, "%slet %s = 0;\n", indent, varName)
|
|
for bit, f := range bools {
|
|
fmt.Fprintf(b, "%sif (%s.%s) %s |= 1 << %d;\n", indent, recv, toCamelCase(f.Name), varName, bit)
|
|
}
|
|
fmt.Fprintf(b, "%sview.setUint8(pos, %s);\n", indent, varName)
|
|
b.WriteString(fmt.Sprintf("%spos += 1;\n", indent))
|
|
}
|
|
|
|
func writeTSBoolGroupDeserialize(b *strings.Builder, recv string, bools []parser.Field, groupIdx int, indent string) {
|
|
varName := fmt.Sprintf("_boolByte%d", groupIdx)
|
|
fmt.Fprintf(b, "%sconst %s = view.getUint8(pos);\n", indent, varName)
|
|
b.WriteString(fmt.Sprintf("%spos += 1;\n", indent))
|
|
for bit, f := range bools {
|
|
fmt.Fprintf(b, "%s%s.%s = (%s & (1 << %d)) !== 0;\n", indent, recv, toCamelCase(f.Name), varName, bit)
|
|
}
|
|
}
|
|
|
|
func writeTSSerializeField(b *strings.Builder, recv string, f parser.Field, indent string, enumNames map[string]struct{}) error {
|
|
access := recv + "." + toCamelCase(f.Name)
|
|
switch f.Kind {
|
|
case parser.KindPrimitive:
|
|
return writeTSSerializePrimitive(b, access, f, indent, enumNames)
|
|
case parser.KindNested:
|
|
fmt.Fprintf(b, "%spos += %s.serialize(view, pos);\n", indent, access)
|
|
case parser.KindFixedArray:
|
|
iVar := "_i" + f.Name
|
|
fmt.Fprintf(b, "%sfor (let %s = 0; %s < %d; %s++) {\n",
|
|
indent, iVar, iVar, f.FixedLen, iVar)
|
|
elemField := parser.Field{
|
|
Name: f.Name + "[" + iVar + "]",
|
|
Kind: f.Elem.Kind,
|
|
Primitive: f.Elem.Primitive,
|
|
NamedType: f.Elem.NamedType,
|
|
Quant: f.Elem.Quant,
|
|
TypeName: f.Elem.TypeName,
|
|
Elem: f.Elem.Elem,
|
|
FixedLen: f.Elem.FixedLen,
|
|
}
|
|
if err := writeTSSerializeField(b, recv, elemField, indent+" ", enumNames); err != nil {
|
|
return err
|
|
}
|
|
fmt.Fprintf(b, "%s}\n", indent)
|
|
case parser.KindSlice:
|
|
fmt.Fprintf(b, "%sview.setUint16(pos, %s.length, true);\n", indent, access)
|
|
b.WriteString(fmt.Sprintf("%spos += 2;\n", indent))
|
|
iVar := "_i" + f.Name
|
|
fmt.Fprintf(b, "%sfor (const %s of %s) {\n", indent, iVar, access)
|
|
elemField := parser.Field{
|
|
Name: iVar,
|
|
Kind: f.Elem.Kind,
|
|
Primitive: f.Elem.Primitive,
|
|
NamedType: f.Elem.NamedType,
|
|
Quant: f.Elem.Quant,
|
|
TypeName: f.Elem.TypeName,
|
|
Elem: f.Elem.Elem,
|
|
FixedLen: f.Elem.FixedLen,
|
|
}
|
|
if err := writeTSSerializeFieldElement(b, iVar, elemField, indent+" ", enumNames); err != nil {
|
|
return err
|
|
}
|
|
fmt.Fprintf(b, "%s}\n", indent)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func writeTSSerializeFieldElement(b *strings.Builder, access string, f parser.Field, indent string, enumNames map[string]struct{}) error {
|
|
switch f.Kind {
|
|
case parser.KindPrimitive:
|
|
return writeTSSerializePrimitiveElement(b, access, f, indent, enumNames)
|
|
case parser.KindNested:
|
|
fmt.Fprintf(b, "%spos += %s.serialize(view, pos);\n", indent, access)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func writeTSSerializePrimitiveElement(b *strings.Builder, access string, f parser.Field, indent string, enumNames map[string]struct{}) error {
|
|
if f.Quant != nil {
|
|
return writeTSSerializeQuantElement(b, access, f, indent)
|
|
}
|
|
|
|
valueExpr := tsSerializeValueExpr(access, f, enumNames)
|
|
switch f.Primitive {
|
|
case parser.KindFloat32:
|
|
fmt.Fprintf(b, "%sview.setFloat32(pos, %s, true);\n", indent, valueExpr)
|
|
b.WriteString(fmt.Sprintf("%spos += 4;\n", indent))
|
|
case parser.KindFloat64:
|
|
fmt.Fprintf(b, "%sview.setFloat64(pos, %s, true);\n", indent, valueExpr)
|
|
b.WriteString(fmt.Sprintf("%spos += 8;\n", indent))
|
|
case parser.KindInt8:
|
|
fmt.Fprintf(b, "%sview.setInt8(pos, %s);\n", indent, valueExpr)
|
|
b.WriteString(fmt.Sprintf("%spos += 1;\n", indent))
|
|
case parser.KindUint8:
|
|
fmt.Fprintf(b, "%sview.setUint8(pos, %s);\n", indent, valueExpr)
|
|
b.WriteString(fmt.Sprintf("%spos += 1;\n", indent))
|
|
case parser.KindBool:
|
|
fmt.Fprintf(b, "%sview.setUint8(pos, %s ? 1 : 0);\n", indent, valueExpr)
|
|
b.WriteString(fmt.Sprintf("%spos += 1;\n", indent))
|
|
case parser.KindInt16:
|
|
fmt.Fprintf(b, "%sview.setInt16(pos, %s, true);\n", indent, valueExpr)
|
|
b.WriteString(fmt.Sprintf("%spos += 2;\n", indent))
|
|
case parser.KindUint16:
|
|
fmt.Fprintf(b, "%sview.setUint16(pos, %s, true);\n", indent, valueExpr)
|
|
b.WriteString(fmt.Sprintf("%spos += 2;\n", indent))
|
|
case parser.KindInt32:
|
|
fmt.Fprintf(b, "%sview.setInt32(pos, %s, true);\n", indent, valueExpr)
|
|
b.WriteString(fmt.Sprintf("%spos += 4;\n", indent))
|
|
case parser.KindUint32:
|
|
fmt.Fprintf(b, "%sview.setUint32(pos, %s, true);\n", indent, valueExpr)
|
|
b.WriteString(fmt.Sprintf("%spos += 4;\n", indent))
|
|
case parser.KindInt64:
|
|
fmt.Fprintf(b, "%sview.setBigInt64(pos, %s, true);\n", indent, valueExpr)
|
|
b.WriteString(fmt.Sprintf("%spos += 8;\n", indent))
|
|
case parser.KindUint64:
|
|
fmt.Fprintf(b, "%sview.setBigUint64(pos, %s, true);\n", indent, valueExpr)
|
|
b.WriteString(fmt.Sprintf("%spos += 8;\n", indent))
|
|
case parser.KindString:
|
|
lenVar := "_slen" + sanitizeVarName(access)
|
|
fmt.Fprintf(b, "%sconst %s = new TextEncoder().encode(%s);\n", indent, lenVar, valueExpr)
|
|
fmt.Fprintf(b, "%sview.setUint16(pos, %s.length, true);\n", indent, lenVar)
|
|
b.WriteString(fmt.Sprintf("%spos += 2;\n", indent))
|
|
fmt.Fprintf(b, "%snew Uint8Array(view.buffer, pos, %s.length).set(%s);\n", indent, lenVar, lenVar)
|
|
fmt.Fprintf(b, "%spos += %s.length;\n", indent, lenVar)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func writeTSSerializePrimitive(b *strings.Builder, access string, f parser.Field, indent string, enumNames map[string]struct{}) error {
|
|
if f.Quant != nil {
|
|
return writeTSSerializeQuant(b, access, f, indent)
|
|
}
|
|
|
|
valueExpr := tsSerializeValueExpr(access, f, enumNames)
|
|
switch f.Primitive {
|
|
case parser.KindFloat32:
|
|
fmt.Fprintf(b, "%sview.setFloat32(pos, %s, true);\n", indent, valueExpr)
|
|
b.WriteString(fmt.Sprintf("%spos += 4;\n", indent))
|
|
case parser.KindFloat64:
|
|
fmt.Fprintf(b, "%sview.setFloat64(pos, %s, true);\n", indent, valueExpr)
|
|
b.WriteString(fmt.Sprintf("%spos += 8;\n", indent))
|
|
case parser.KindInt8:
|
|
fmt.Fprintf(b, "%sview.setInt8(pos, %s);\n", indent, valueExpr)
|
|
b.WriteString(fmt.Sprintf("%spos += 1;\n", indent))
|
|
case parser.KindUint8:
|
|
fmt.Fprintf(b, "%sview.setUint8(pos, %s);\n", indent, valueExpr)
|
|
b.WriteString(fmt.Sprintf("%spos += 1;\n", indent))
|
|
case parser.KindBool:
|
|
fmt.Fprintf(b, "%sview.setUint8(pos, %s ? 1 : 0);\n", indent, valueExpr)
|
|
b.WriteString(fmt.Sprintf("%spos += 1;\n", indent))
|
|
case parser.KindInt16:
|
|
fmt.Fprintf(b, "%sview.setInt16(pos, %s, true);\n", indent, valueExpr)
|
|
b.WriteString(fmt.Sprintf("%spos += 2;\n", indent))
|
|
case parser.KindUint16:
|
|
fmt.Fprintf(b, "%sview.setUint16(pos, %s, true);\n", indent, valueExpr)
|
|
b.WriteString(fmt.Sprintf("%spos += 2;\n", indent))
|
|
case parser.KindInt32:
|
|
fmt.Fprintf(b, "%sview.setInt32(pos, %s, true);\n", indent, valueExpr)
|
|
b.WriteString(fmt.Sprintf("%spos += 4;\n", indent))
|
|
case parser.KindUint32:
|
|
fmt.Fprintf(b, "%sview.setUint32(pos, %s, true);\n", indent, valueExpr)
|
|
b.WriteString(fmt.Sprintf("%spos += 4;\n", indent))
|
|
case parser.KindInt64:
|
|
fmt.Fprintf(b, "%sview.setBigInt64(pos, %s, true);\n", indent, valueExpr)
|
|
b.WriteString(fmt.Sprintf("%spos += 8;\n", indent))
|
|
case parser.KindUint64:
|
|
fmt.Fprintf(b, "%sview.setBigUint64(pos, %s, true);\n", indent, valueExpr)
|
|
b.WriteString(fmt.Sprintf("%spos += 8;\n", indent))
|
|
case parser.KindString:
|
|
lenVar := "_slen" + sanitizeVarName(access)
|
|
fmt.Fprintf(b, "%sconst %s = new TextEncoder().encode(%s);\n", indent, lenVar, valueExpr)
|
|
fmt.Fprintf(b, "%sview.setUint16(pos, %s.length, true);\n", indent, lenVar)
|
|
b.WriteString(fmt.Sprintf("%spos += 2;\n", indent))
|
|
fmt.Fprintf(b, "%snew Uint8Array(view.buffer, pos, %s.length).set(%s);\n", indent, lenVar, lenVar)
|
|
fmt.Fprintf(b, "%spos += %s.length;\n", indent, lenVar)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func writeTSSerializeQuant(b *strings.Builder, access string, f parser.Field, indent string) error {
|
|
q := f.Quant
|
|
maxUint := q.MaxUint()
|
|
varName := "_q" + sanitizeVarName(access)
|
|
if q.Bits == 8 {
|
|
fmt.Fprintf(b, "%sconst %s = Math.round((%s - (%g)) / (%g - (%g)) * %g);\n",
|
|
indent, varName, access, q.Min, q.Max, q.Min, maxUint)
|
|
fmt.Fprintf(b, "%sview.setUint8(pos, %s);\n", indent, varName)
|
|
b.WriteString(fmt.Sprintf("%spos += 1;\n", indent))
|
|
} else {
|
|
fmt.Fprintf(b, "%sconst %s = Math.round((%s - (%g)) / (%g - (%g)) * %g);\n",
|
|
indent, varName, access, q.Min, q.Max, q.Min, maxUint)
|
|
fmt.Fprintf(b, "%sview.setUint16(pos, %s, true);\n", indent, varName)
|
|
b.WriteString(fmt.Sprintf("%spos += 2;\n", indent))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func writeTSSerializeQuantElement(b *strings.Builder, access string, f parser.Field, indent string) error {
|
|
q := f.Quant
|
|
maxUint := q.MaxUint()
|
|
varName := "_q" + sanitizeVarName(access)
|
|
if q.Bits == 8 {
|
|
fmt.Fprintf(b, "%sconst %s = Math.round((%s - (%g)) / (%g - (%g)) * %g);\n",
|
|
indent, varName, access, q.Min, q.Max, q.Min, maxUint)
|
|
fmt.Fprintf(b, "%sview.setUint8(pos, %s);\n", indent, varName)
|
|
b.WriteString(fmt.Sprintf("%spos += 1;\n", indent))
|
|
} else {
|
|
fmt.Fprintf(b, "%sconst %s = Math.round((%s - (%g)) / (%g - (%g)) * %g);\n",
|
|
indent, varName, access, q.Min, q.Max, q.Min, maxUint)
|
|
fmt.Fprintf(b, "%sview.setUint16(pos, %s, true);\n", indent, varName)
|
|
b.WriteString(fmt.Sprintf("%spos += 2;\n", indent))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func writeTSDeserializeField(b *strings.Builder, recv string, f parser.Field, indent string, enumNames map[string]struct{}) error {
|
|
access := recv + "." + toCamelCase(f.Name)
|
|
switch f.Kind {
|
|
case parser.KindPrimitive:
|
|
return writeTSDeserializePrimitive(b, access, f, indent, enumNames)
|
|
case parser.KindNested:
|
|
fmt.Fprintf(b, "%sconst [_%s, _n%s] = %s.deserialize(view, pos);\n", indent, f.Name, f.Name, f.TypeName)
|
|
fmt.Fprintf(b, "%s%s = _%s;\n", indent, access, f.Name)
|
|
fmt.Fprintf(b, "%spos += _n%s;\n", indent, f.Name)
|
|
case parser.KindFixedArray:
|
|
iVar := "_i" + f.Name
|
|
fmt.Fprintf(b, "%s%s = new Array(%d);\n", indent, access, f.FixedLen)
|
|
fmt.Fprintf(b, "%sfor (let %s = 0; %s < %d; %s++) {\n",
|
|
indent, iVar, iVar, f.FixedLen, iVar)
|
|
elemField := parser.Field{
|
|
Name: f.Name + "[" + iVar + "]",
|
|
Kind: f.Elem.Kind,
|
|
Primitive: f.Elem.Primitive,
|
|
NamedType: f.Elem.NamedType,
|
|
Quant: f.Elem.Quant,
|
|
TypeName: f.Elem.TypeName,
|
|
Elem: f.Elem.Elem,
|
|
FixedLen: f.Elem.FixedLen,
|
|
}
|
|
if err := writeTSDeserializeField(b, recv, elemField, indent+" ", enumNames); err != nil {
|
|
return err
|
|
}
|
|
fmt.Fprintf(b, "%s}\n", indent)
|
|
case parser.KindSlice:
|
|
lenVar := "_len" + f.Name
|
|
fmt.Fprintf(b, "%sconst %s = view.getUint16(pos, true);\n", indent, lenVar)
|
|
b.WriteString(fmt.Sprintf("%spos += 2;\n", indent))
|
|
fmt.Fprintf(b, "%s%s = new Array(%s);\n", indent, access, lenVar)
|
|
iVar := "_i" + f.Name
|
|
fmt.Fprintf(b, "%sfor (let %s = 0; %s < %s; %s++) {\n", indent, iVar, iVar, lenVar, iVar)
|
|
elemField := parser.Field{
|
|
Name: f.Name + "[" + iVar + "]",
|
|
Kind: f.Elem.Kind,
|
|
Primitive: f.Elem.Primitive,
|
|
NamedType: f.Elem.NamedType,
|
|
Quant: f.Elem.Quant,
|
|
TypeName: f.Elem.TypeName,
|
|
Elem: f.Elem.Elem,
|
|
FixedLen: f.Elem.FixedLen,
|
|
}
|
|
if err := writeTSDeserializeFieldElement(b, recv, elemField, indent+" ", enumNames); err != nil {
|
|
return err
|
|
}
|
|
fmt.Fprintf(b, "%s}\n", indent)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func writeTSDeserializeFieldElement(b *strings.Builder, recv string, f parser.Field, indent string, enumNames map[string]struct{}) error {
|
|
access := recv + "." + toCamelCase(f.Name)
|
|
switch f.Kind {
|
|
case parser.KindPrimitive:
|
|
return writeTSDeserializePrimitiveElement(b, access, f, indent, enumNames)
|
|
case parser.KindNested:
|
|
fmt.Fprintf(b, "%sconst [_elem, _nElem] = %s.deserialize(view, pos);\n", indent, f.TypeName)
|
|
fmt.Fprintf(b, "%s%s = _elem;\n", indent, access)
|
|
fmt.Fprintf(b, "%spos += _nElem;\n", indent)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func writeTSDeserializePrimitiveElement(b *strings.Builder, access string, f parser.Field, indent string, enumNames map[string]struct{}) error {
|
|
if f.Quant != nil {
|
|
return writeTSDeserializeQuantElement(b, access, f, indent)
|
|
}
|
|
|
|
switch f.Primitive {
|
|
case parser.KindFloat32:
|
|
expr := fmt.Sprintf("view.getFloat32(pos, true)")
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
|
|
b.WriteString(fmt.Sprintf("%spos += 4;\n", indent))
|
|
case parser.KindFloat64:
|
|
expr := fmt.Sprintf("view.getFloat64(pos, true)")
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
|
|
b.WriteString(fmt.Sprintf("%spos += 8;\n", indent))
|
|
case parser.KindInt8:
|
|
expr := fmt.Sprintf("view.getInt8(pos)")
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
|
|
b.WriteString(fmt.Sprintf("%spos += 1;\n", indent))
|
|
case parser.KindUint8:
|
|
expr := fmt.Sprintf("view.getUint8(pos)")
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
|
|
b.WriteString(fmt.Sprintf("%spos += 1;\n", indent))
|
|
case parser.KindBool:
|
|
expr := fmt.Sprintf("view.getUint8(pos) !== 0")
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
|
|
b.WriteString(fmt.Sprintf("%spos += 1;\n", indent))
|
|
case parser.KindInt16:
|
|
expr := fmt.Sprintf("view.getInt16(pos, true)")
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
|
|
b.WriteString(fmt.Sprintf("%spos += 2;\n", indent))
|
|
case parser.KindUint16:
|
|
expr := fmt.Sprintf("view.getUint16(pos, true)")
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
|
|
b.WriteString(fmt.Sprintf("%spos += 2;\n", indent))
|
|
case parser.KindInt32:
|
|
expr := fmt.Sprintf("view.getInt32(pos, true)")
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
|
|
b.WriteString(fmt.Sprintf("%spos += 4;\n", indent))
|
|
case parser.KindUint32:
|
|
expr := fmt.Sprintf("view.getUint32(pos, true)")
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
|
|
b.WriteString(fmt.Sprintf("%spos += 4;\n", indent))
|
|
case parser.KindInt64:
|
|
expr := fmt.Sprintf("view.getBigInt64(pos, true)")
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
|
|
b.WriteString(fmt.Sprintf("%spos += 8;\n", indent))
|
|
case parser.KindUint64:
|
|
expr := fmt.Sprintf("view.getBigUint64(pos, true)")
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
|
|
b.WriteString(fmt.Sprintf("%spos += 8;\n", indent))
|
|
case parser.KindString:
|
|
lenVar := "_slen" + sanitizeVarName(access)
|
|
fmt.Fprintf(b, "%sconst %s = view.getUint16(pos, true);\n", indent, lenVar)
|
|
b.WriteString(fmt.Sprintf("%spos += 2;\n", indent))
|
|
expr := fmt.Sprintf("new TextDecoder().decode(new Uint8Array(view.buffer, pos, %s))", lenVar)
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
|
|
fmt.Fprintf(b, "%spos += %s;\n", indent, lenVar)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func writeTSDeserializePrimitive(b *strings.Builder, access string, f parser.Field, indent string, enumNames map[string]struct{}) error {
|
|
if f.Quant != nil {
|
|
return writeTSDeserializeQuant(b, access, f, indent)
|
|
}
|
|
|
|
switch f.Primitive {
|
|
case parser.KindFloat32:
|
|
expr := fmt.Sprintf("view.getFloat32(pos, true)")
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
|
|
b.WriteString(fmt.Sprintf("%spos += 4;\n", indent))
|
|
case parser.KindFloat64:
|
|
expr := fmt.Sprintf("view.getFloat64(pos, true)")
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
|
|
b.WriteString(fmt.Sprintf("%spos += 8;\n", indent))
|
|
case parser.KindInt8:
|
|
expr := fmt.Sprintf("view.getInt8(pos)")
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
|
|
b.WriteString(fmt.Sprintf("%spos += 1;\n", indent))
|
|
case parser.KindUint8:
|
|
expr := fmt.Sprintf("view.getUint8(pos)")
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
|
|
b.WriteString(fmt.Sprintf("%spos += 1;\n", indent))
|
|
case parser.KindBool:
|
|
expr := fmt.Sprintf("view.getUint8(pos) !== 0")
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
|
|
b.WriteString(fmt.Sprintf("%spos += 1;\n", indent))
|
|
case parser.KindInt16:
|
|
expr := fmt.Sprintf("view.getInt16(pos, true)")
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
|
|
b.WriteString(fmt.Sprintf("%spos += 2;\n", indent))
|
|
case parser.KindUint16:
|
|
expr := fmt.Sprintf("view.getUint16(pos, true)")
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
|
|
b.WriteString(fmt.Sprintf("%spos += 2;\n", indent))
|
|
case parser.KindInt32:
|
|
expr := fmt.Sprintf("view.getInt32(pos, true)")
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
|
|
b.WriteString(fmt.Sprintf("%spos += 4;\n", indent))
|
|
case parser.KindUint32:
|
|
expr := fmt.Sprintf("view.getUint32(pos, true)")
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
|
|
b.WriteString(fmt.Sprintf("%spos += 4;\n", indent))
|
|
case parser.KindInt64:
|
|
expr := fmt.Sprintf("view.getBigInt64(pos, true)")
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
|
|
b.WriteString(fmt.Sprintf("%spos += 8;\n", indent))
|
|
case parser.KindUint64:
|
|
expr := fmt.Sprintf("view.getBigUint64(pos, true)")
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
|
|
b.WriteString(fmt.Sprintf("%spos += 8;\n", indent))
|
|
case parser.KindString:
|
|
lenVar := "_slen" + sanitizeVarName(access)
|
|
fmt.Fprintf(b, "%sconst %s = view.getUint16(pos, true);\n", indent, lenVar)
|
|
b.WriteString(fmt.Sprintf("%spos += 2;\n", indent))
|
|
expr := fmt.Sprintf("new TextDecoder().decode(new Uint8Array(view.buffer, pos, %s))", lenVar)
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
|
|
fmt.Fprintf(b, "%spos += %s;\n", indent, lenVar)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func writeTSDeserializeQuant(b *strings.Builder, access string, f parser.Field, indent string) error {
|
|
q := f.Quant
|
|
maxUint := q.MaxUint()
|
|
varName := "_q" + sanitizeVarName(access)
|
|
if q.Bits == 8 {
|
|
fmt.Fprintf(b, "%sconst %s = view.getUint8(pos);\n", indent, varName)
|
|
b.WriteString(fmt.Sprintf("%spos += 1;\n", indent))
|
|
expr := fmt.Sprintf("%s / %g * (%g - (%g)) + (%g)", varName, maxUint, q.Max, q.Min, q.Min)
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, nil))
|
|
} else {
|
|
fmt.Fprintf(b, "%sconst %s = view.getUint16(pos, true);\n", indent, varName)
|
|
b.WriteString(fmt.Sprintf("%spos += 2;\n", indent))
|
|
expr := fmt.Sprintf("%s / %g * (%g - (%g)) + (%g)", varName, maxUint, q.Max, q.Min, q.Min)
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, nil))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func writeTSDeserializeQuantElement(b *strings.Builder, access string, f parser.Field, indent string) error {
|
|
q := f.Quant
|
|
maxUint := q.MaxUint()
|
|
varName := "_q" + sanitizeVarName(access)
|
|
if q.Bits == 8 {
|
|
fmt.Fprintf(b, "%sconst %s = view.getUint8(pos);\n", indent, varName)
|
|
b.WriteString(fmt.Sprintf("%spos += 1;\n", indent))
|
|
expr := fmt.Sprintf("%s / %g * (%g - (%g)) + (%g)", varName, maxUint, q.Max, q.Min, q.Min)
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, nil))
|
|
} else {
|
|
fmt.Fprintf(b, "%sconst %s = view.getUint16(pos, true);\n", indent, varName)
|
|
b.WriteString(fmt.Sprintf("%spos += 2;\n", indent))
|
|
expr := fmt.Sprintf("%s / %g * (%g - (%g)) + (%g)", varName, maxUint, q.Max, q.Min, q.Min)
|
|
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, nil))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func tsTypeName(f parser.Field, enumNames map[string]struct{}) string {
|
|
switch f.Kind {
|
|
case parser.KindPrimitive:
|
|
if tsIsEnumType(f, enumNames) {
|
|
return f.NamedType
|
|
}
|
|
return tsPrimitiveTypeName(f.Primitive)
|
|
case parser.KindNested:
|
|
return f.TypeName
|
|
case parser.KindFixedArray, parser.KindSlice:
|
|
return tsTypeName(*f.Elem, enumNames) + "[]"
|
|
}
|
|
return "unknown"
|
|
}
|
|
|
|
func tsPrimitiveTypeName(k parser.PrimitiveKind) string {
|
|
switch k {
|
|
case parser.KindFloat32, parser.KindFloat64:
|
|
return "number"
|
|
case parser.KindInt8, parser.KindInt16, parser.KindInt32, parser.KindUint8, parser.KindUint16, parser.KindUint32:
|
|
return "number"
|
|
case parser.KindInt64, parser.KindUint64:
|
|
return "bigint"
|
|
case parser.KindBool:
|
|
return "boolean"
|
|
case parser.KindString:
|
|
return "string"
|
|
}
|
|
return "unknown"
|
|
}
|
|
|
|
func tsDefaultValue(f parser.Field) string {
|
|
switch f.Kind {
|
|
case parser.KindPrimitive:
|
|
if tsIsEnumType(f, nil) {
|
|
return "0"
|
|
}
|
|
switch f.Primitive {
|
|
case parser.KindFloat32, parser.KindFloat64, parser.KindInt8, parser.KindInt16, parser.KindInt32,
|
|
parser.KindUint8, parser.KindUint16, parser.KindUint32:
|
|
return "0"
|
|
case parser.KindInt64, parser.KindUint64:
|
|
return "0n"
|
|
case parser.KindBool:
|
|
return "false"
|
|
case parser.KindString:
|
|
return `""`
|
|
}
|
|
case parser.KindNested:
|
|
return fmt.Sprintf("new %s()", f.TypeName)
|
|
case parser.KindFixedArray:
|
|
elemDefault := tsDefaultValue(*f.Elem)
|
|
elemType := tsTypeName(*f.Elem, nil)
|
|
return fmt.Sprintf("new Array<%s>(%d).fill(%s)", elemType, f.FixedLen, elemDefault)
|
|
case parser.KindSlice:
|
|
return "[]"
|
|
}
|
|
return "undefined"
|
|
}
|
|
|
|
func tsSerializeValueExpr(access string, f parser.Field, enumNames map[string]struct{}) string {
|
|
if !tsIsEnumType(f, enumNames) {
|
|
return access
|
|
}
|
|
return access + " as " + tsPrimitiveTypeName(f.Primitive)
|
|
}
|
|
|
|
func tsDeserializeValueExpr(expr string, f parser.Field, enumNames map[string]struct{}) string {
|
|
if !tsIsEnumType(f, enumNames) {
|
|
return expr
|
|
}
|
|
return "(" + expr + " as " + f.NamedType + ")"
|
|
}
|
|
|
|
func tsIsEnumType(f parser.Field, enumNames map[string]struct{}) bool {
|
|
if f.NamedType == "" || enumNames == nil {
|
|
return false
|
|
}
|
|
_, ok := enumNames[f.NamedType]
|
|
return ok
|
|
}
|
|
|
|
// toCamelCase converts PascalCase to camelCase (e.g., EntityID -> entityID)
|
|
func toCamelCase(s string) string {
|
|
if s == "" {
|
|
return ""
|
|
}
|
|
// First character to lowercase
|
|
result := strings.ToLower(s[:1]) + s[1:]
|
|
return result
|
|
}
|