From 032f719aba3d39d4ead521b2b6d8c3bab106c6e8 Mon Sep 17 00:00:00 2001 From: Fedor Vikhnin Date: Sat, 28 Dec 2024 21:14:38 +0300 Subject: [PATCH] read draft --- internal/tlcodegen/tlgen_kernel.go | 4 + .../{tlgen_cpp.go => tlgen_lang_cpp.go} | 15 ++ .../{tlgen_go.go => tlgen_lang_go.go} | 0 .../{tlgen_php.go => tlgen_lang_php.go} | 32 ++- internal/tlcodegen/type_rw.go | 102 +++++++-- internal/tlcodegen/type_rw_bool_php.go | 21 ++ internal/tlcodegen/type_rw_maybe_php.go | 39 ++++ internal/tlcodegen/type_rw_primitive_php.go | 29 +++ internal/tlcodegen/type_rw_struct_php.go | 201 ++++++++++++++++++ internal/tlcodegen/type_rw_tuple_cpp.go | 1 + internal/tlcodegen/type_rw_tuple_php.go | 86 ++++++++ internal/tlcodegen/type_rw_union_php.go | 37 ++++ 12 files changed, 542 insertions(+), 25 deletions(-) rename internal/tlcodegen/{tlgen_cpp.go => tlgen_lang_cpp.go} (95%) rename internal/tlcodegen/{tlgen_go.go => tlgen_lang_go.go} (100%) rename internal/tlcodegen/{tlgen_php.go => tlgen_lang_php.go} (84%) diff --git a/internal/tlcodegen/tlgen_kernel.go b/internal/tlcodegen/tlgen_kernel.go index 85218261..38f3a782 100644 --- a/internal/tlcodegen/tlgen_kernel.go +++ b/internal/tlcodegen/tlgen_kernel.go @@ -205,6 +205,10 @@ func (gen *Gen2) getType(lrc LocalResolveContext, t tlast.TypeRef, unionParent * func (gen *Gen2) generateType(myWrapper *TypeRWWrapper) error { tlType := myWrapper.origTL + if tlType[0].Construct.Name.String() == "test.dataIgnoreFlags" { + print("debug") + } + lrc := LocalResolveContext{ localTypeArgs: map[string]LocalTypeArg{}, localNatArgs: map[string]LocalNatArg{}, diff --git a/internal/tlcodegen/tlgen_cpp.go b/internal/tlcodegen/tlgen_lang_cpp.go similarity index 95% rename from internal/tlcodegen/tlgen_cpp.go rename to internal/tlcodegen/tlgen_lang_cpp.go index b9aaa00e..5aeb1652 100644 --- a/internal/tlcodegen/tlgen_cpp.go +++ b/internal/tlcodegen/tlgen_lang_cpp.go @@ -15,6 +15,21 @@ import ( "strings" ) +type TypeRWCPPData interface { + CPPFillRecursiveChildren(visitedNodes map[*TypeRWWrapper]bool) + cppTypeStringInNamespace(bytesVersion bool, hppInc *DirectIncludesCPP) string + cppTypeStringInNamespaceHalfResolved2(bytesVersion bool, typeReduction EvaluatedType) string + cppTypeStringInNamespaceHalfResolved(bytesVersion bool, hppInc *DirectIncludesCPP, halfResolved HalfResolvedArgument) string + cppDefaultInitializer(halfResolved HalfResolvedArgument, halfResolve bool) string + CPPHasBytesVersion() bool + CPPTypeResettingCode(bytesVersion bool, val string) string + CPPTypeWritingJsonCode(bytesVersion bool, val string, bare bool, natArgs []string, last bool) string + CPPTypeWritingCode(bytesVersion bool, val string, bare bool, natArgs []string, last bool) string + CPPTypeReadingCode(bytesVersion bool, val string, bare bool, natArgs []string, last bool) string + CPPTypeJSONEmptyCondition(bytesVersion bool, val string, ref bool, deps []string) string + CPPGenerateCode(hpp *strings.Builder, hppInc *DirectIncludesCPP, hppIncFwd *DirectIncludesCPP, hppDet *strings.Builder, hppDetInc *DirectIncludesCPP, cppDet *strings.Builder, cppDetInc *DirectIncludesCPP, bytesVersion bool, forwardDeclaration bool) +} + func cppStartNamespace(s *strings.Builder, ns []string) { for _, n := range ns { s.WriteString(fmt.Sprintf("namespace %s { ", n)) diff --git a/internal/tlcodegen/tlgen_go.go b/internal/tlcodegen/tlgen_lang_go.go similarity index 100% rename from internal/tlcodegen/tlgen_go.go rename to internal/tlcodegen/tlgen_lang_go.go diff --git a/internal/tlcodegen/tlgen_php.go b/internal/tlcodegen/tlgen_lang_php.go similarity index 84% rename from internal/tlcodegen/tlgen_php.go rename to internal/tlcodegen/tlgen_lang_php.go index 22a32f52..89c42a8d 100644 --- a/internal/tlcodegen/tlgen_php.go +++ b/internal/tlcodegen/tlgen_lang_php.go @@ -6,6 +6,19 @@ import ( "strings" ) +type TypeRWPHPData interface { + PhpClassName(withPath bool, bare bool) string + PhpClassNameReplaced() bool + PhpTypeName(withPath bool, bare bool) string + PhpGenerateCode(code *strings.Builder, bytes bool) error + // PhpDefaultInit return not null type initialization value + PhpDefaultInit() string + // PhpDefaultValue return default value for field of this type (can be null) + PhpDefaultValue() string + PhpIterateReachableTypes(reachableTypes *map[*TypeRWWrapper]bool) + PhpReadMethodCall(targetName string, bare bool, args []string) []string +} + type PhpClassMeta struct { UsedOnlyInInternal bool UsedInFunctions bool @@ -33,15 +46,20 @@ func (gen *Gen2) generateCodePHP(generateByteVersions []string) error { createdTypes := make(map[string]bool) for _, wrapper := range gen.generatedTypesList { - if wrapper.trw.PhpClassName(false, true) == "logs2_dictionarySetInfo" { - print("debug") - } if createdTypes[wrapper.trw.PhpClassName(true, true)] { continue } if !wrapper.PHPNeedsCode() { continue } + fmt.Println(fmt.Sprintf( + "PHP{%[1]s} in GO{%[2]s}", + wrapper.trw.PhpClassName(false, true), + wrapper.goGlobalName, + wrapper.NatParams, + wrapper.origTL[0].TemplateArguments, + wrapper.arguments), + ) err := phpGenerateCodeForWrapper(gen, wrapper, createdTypes, true, wrapper.PHPGenerateCode) if err != nil { return err @@ -159,3 +177,11 @@ func PHPSpecialMembersTypes(wrapper *TypeRWWrapper) string { } return "" } + +func phpFormatArgs(args []string) string { + s := "" + for _, arg := range args { + s += ", " + arg + } + return s +} diff --git a/internal/tlcodegen/type_rw.go b/internal/tlcodegen/type_rw.go index c4f99a50..c2e41130 100644 --- a/internal/tlcodegen/type_rw.go +++ b/internal/tlcodegen/type_rw.go @@ -8,6 +8,7 @@ package tlcodegen import ( "fmt" + "github.com/vkcom/tl/internal/utils" "golang.org/x/exp/slices" "regexp" "strconv" @@ -633,6 +634,84 @@ func (w *TypeRWWrapper) PHPNeedsCode() bool { return !w.trw.PhpClassNameReplaced() } +type TypeArgumentsTree struct { + value string + leaf bool + children []*TypeArgumentsTree +} + +func (t *TypeArgumentsTree) IsEmpty() bool { + if t.leaf { + return false + } + for _, child := range t.children { + if child != nil && !child.IsEmpty() { + return false + } + } + return true +} + +func (t *TypeArgumentsTree) EnumerateWithPrefixes() []string { + const natPrefix = "" + values := make([]string, 0) + t.enumerateWithPrefixes(&values, "") + values = utils.MapSlice(values, func(s string) string { return natPrefix + s }) + return values +} + +func (t *TypeArgumentsTree) EnumerateSubTreeWithPrefixes(childIndex int) []string { + if !(0 <= childIndex && childIndex < len(t.children)) { + panic("no such subtree") + } + ct := *t + ct.children = []*TypeArgumentsTree{t.children[childIndex]} + return ct.EnumerateWithPrefixes() +} + +func (t *TypeArgumentsTree) enumerateWithPrefixes(values *[]string, curPrefix string) { + const delimiter = "_" + if t.leaf { + *values = append(*values, curPrefix) + } else { + for _, child := range t.children { + if child != nil { + prefix := curPrefix + child.value + if !child.leaf { + prefix += delimiter + } + child.enumerateWithPrefixes(values, prefix) + } + } + } +} + +func (w *TypeRWWrapper) PHPGetNatTypeDependenciesDeclAsArray() []string { + t := TypeArgumentsTree{} + w.PHPGetNatTypeDependenciesDecl(&t) + return t.EnumerateWithPrefixes() +} + +func (w *TypeRWWrapper) PHPGetNatTypeDependenciesDecl(tree *TypeArgumentsTree) { + for i, template := range w.origTL[0].TemplateArguments { + tree.children = append(tree.children, nil) + actualArg := w.arguments[i] + if template.IsNat { + tree.children[i] = &TypeArgumentsTree{} + tree.children[i].leaf = true + tree.children[i].value = template.FieldName + } else { + tree.children[i] = &TypeArgumentsTree{} + tree.children[i].leaf = false + tree.children[i].value = template.FieldName + actualArg.tip.PHPGetNatTypeDependenciesDecl(tree.children[i]) + if tree.children[i].IsEmpty() { + tree.children[i] = nil + } + } + } +} + func (w *TypeRWWrapper) PhpIterateReachableTypes(reachableTypes *map[*TypeRWWrapper]bool) { if (*reachableTypes)[w] { return @@ -877,15 +956,6 @@ outer: return result } -type TypeRWPHPData interface { - PhpClassName(withPath bool, bare bool) string - PhpClassNameReplaced() bool - PhpTypeName(withPath bool, bare bool) string - PhpGenerateCode(code *strings.Builder, bytes bool) error - PhpDefaultValue() string - PhpIterateReachableTypes(reachableTypes *map[*TypeRWWrapper]bool) -} - // TODO remove skipAlias after we start generating go code like we do for C++ type TypeRW interface { // methods below are target language independent @@ -918,19 +988,7 @@ type TypeRW interface { typeJSON2ReadingCode(bytesVersion bool, directImports *DirectImports, ins *InternalNamespace, jvalue string, val string, natArgs []string, ref bool) string GenerateCode(bytesVersion bool, directImports *DirectImports) string - CPPFillRecursiveChildren(visitedNodes map[*TypeRWWrapper]bool) - cppTypeStringInNamespace(bytesVersion bool, hppInc *DirectIncludesCPP) string - cppTypeStringInNamespaceHalfResolved2(bytesVersion bool, typeReduction EvaluatedType) string - cppTypeStringInNamespaceHalfResolved(bytesVersion bool, hppInc *DirectIncludesCPP, halfResolved HalfResolvedArgument) string - cppDefaultInitializer(halfResolved HalfResolvedArgument, halfResolve bool) string - CPPHasBytesVersion() bool - CPPTypeResettingCode(bytesVersion bool, val string) string - CPPTypeWritingJsonCode(bytesVersion bool, val string, bare bool, natArgs []string, last bool) string - CPPTypeWritingCode(bytesVersion bool, val string, bare bool, natArgs []string, last bool) string - CPPTypeReadingCode(bytesVersion bool, val string, bare bool, natArgs []string, last bool) string - CPPTypeJSONEmptyCondition(bytesVersion bool, val string, ref bool, deps []string) string - CPPGenerateCode(hpp *strings.Builder, hppInc *DirectIncludesCPP, hppIncFwd *DirectIncludesCPP, hppDet *strings.Builder, hppDetInc *DirectIncludesCPP, cppDet *strings.Builder, cppDetInc *DirectIncludesCPP, bytesVersion bool, forwardDeclaration bool) - + TypeRWCPPData TypeRWPHPData } diff --git a/internal/tlcodegen/type_rw_bool_php.go b/internal/tlcodegen/type_rw_bool_php.go index 1a2097bb..cfcff5a1 100644 --- a/internal/tlcodegen/type_rw_bool_php.go +++ b/internal/tlcodegen/type_rw_bool_php.go @@ -27,3 +27,24 @@ func (trw *TypeRWBool) PhpDefaultValue() string { func (trw *TypeRWBool) PhpIterateReachableTypes(reachableTypes *map[*TypeRWWrapper]bool) { } + +func (trw *TypeRWBool) PhpReadMethodCall(targetName string, bare bool, args []string) []string { + if !bare { + return []string{ + fmt.Sprintf( + "[%[1]s, $success] = $stream->read_bool(0x%08[2]x, 0x%08[3]x);", + targetName, + trw.falseTag, + trw.trueTag, + ), + "if (!$success) {", + " return false;", + "}", + } + } + return nil +} + +func (trw *TypeRWBool) PhpDefaultInit() string { + return "false" +} diff --git a/internal/tlcodegen/type_rw_maybe_php.go b/internal/tlcodegen/type_rw_maybe_php.go index b3805cc8..9841237a 100644 --- a/internal/tlcodegen/type_rw_maybe_php.go +++ b/internal/tlcodegen/type_rw_maybe_php.go @@ -38,3 +38,42 @@ func (trw *TypeRWMaybe) PhpDefaultValue() string { func (trw *TypeRWMaybe) PhpIterateReachableTypes(reachableTypes *map[*TypeRWWrapper]bool) { trw.element.t.PhpIterateReachableTypes(reachableTypes) } + +func (trw *TypeRWMaybe) PhpReadMethodCall(targetName string, bare bool, args []string) []string { + if !bare { + result := []string{ + fmt.Sprintf( + "[$maybeContainsValue, $success] = $stream->read_bool(0x%08[1]x, 0x%08[2]x)", + trw.emptyTag, + trw.okTag, + ), + "if (!$success) {", + " return false;", + "}", + "if ($maybeContainsValue) {", + } + if trw.element.t == trw.getInnerTarget().t { + result = append(result, + fmt.Sprintf(" if (%[1]s == null) {", targetName), + fmt.Sprintf(" %[1]s = %[2]s;", targetName, trw.element.t.trw.PhpDefaultInit()), + " }", + ) + } + bodyReader := trw.element.t.trw.PhpReadMethodCall(targetName, trw.element.bare, args) + for i, _ := range bodyReader { + bodyReader[i] = " " + bodyReader[i] + } + result = append(result, bodyReader...) + result = append(result, + "} else {", + fmt.Sprintf(" %[1]s = null;", targetName), + "}", + ) + return result + } + return nil +} + +func (trw *TypeRWMaybe) PhpDefaultInit() string { + return trw.element.t.trw.PhpDefaultInit() +} diff --git a/internal/tlcodegen/type_rw_primitive_php.go b/internal/tlcodegen/type_rw_primitive_php.go index 81438f65..a5b0bbab 100644 --- a/internal/tlcodegen/type_rw_primitive_php.go +++ b/internal/tlcodegen/type_rw_primitive_php.go @@ -44,3 +44,32 @@ func (trw *TypeRWPrimitive) PhpDefaultValue() string { } func (trw *TypeRWPrimitive) PhpIterateReachableTypes(reachableTypes *map[*TypeRWWrapper]bool) {} + +func (trw *TypeRWPrimitive) phpIOMethodsSuffix() string { + switch trw.goType { + case "int32", "int64", "uint32", "string": + return trw.goType + case "float32": + return "float" + case "float64": + return "double" + default: + return fmt.Sprintf("", trw.tlType) + } +} + +func (trw *TypeRWPrimitive) PhpReadMethodCall(targetName string, bare bool, args []string) []string { + if !bare { + panic("can't be boxed") + } + return []string{ + fmt.Sprintf("[%[1]s, $success] = $stream->read_%[2]s();", targetName, trw.phpIOMethodsSuffix()), + "if (!$success) {", + " return false;", + "}", + } +} + +func (trw *TypeRWPrimitive) PhpDefaultInit() string { + return trw.PhpDefaultValue() +} diff --git a/internal/tlcodegen/type_rw_struct_php.go b/internal/tlcodegen/type_rw_struct_php.go index 95b7cf02..64a4cb50 100644 --- a/internal/tlcodegen/type_rw_struct_php.go +++ b/internal/tlcodegen/type_rw_struct_php.go @@ -2,11 +2,84 @@ package tlcodegen import ( "fmt" + "github.com/vkcom/tl/internal/tlast" "github.com/vkcom/tl/internal/utils" "sort" + "strconv" "strings" ) +func (trw *TypeRWStruct) PHPFindNatByName(name string) (localNat bool, indexInDeps int) { + for i, field := range trw.Fields { + if field.originalName == name { + return true, i + } + } + for i, argument := range trw.wr.origTL[0].TemplateArguments { + if argument.FieldName == name { + return false, i + } + } + panic(fmt.Sprintf("no such nat \"%s\"", name)) +} + +func (trw *TypeRWStruct) PHPGetFieldNatDependenciesValues(fieldIndex int) []string { + field := trw.Fields[fieldIndex] + argsValues := make([]string, 0) + currentType := field.t + trw.phpGetFieldArgs(currentType, &field.origTL.FieldType, &argsValues) + return argsValues +} + +func (trw *TypeRWStruct) PHPGetFieldMask(fieldIndex int) string { + fieldMask := trw.Fields[fieldIndex].fieldMask + if fieldMask != nil { + if fieldMask.isField { + return fmt.Sprintf("$this->%s", trw.Fields[fieldMask.FieldIndex].originalName) + } + return "$" + fieldMask.name + } + + return "" +} + +func (trw *TypeRWStruct) phpGetFieldArgs(currentType *TypeRWWrapper, currentTypeRef *tlast.TypeRef, argsValues *[]string) { + if len(currentTypeRef.Args) != len(currentType.origTL[0].TemplateArguments) { + generic := currentTypeRef.Type.String() + index := -1 + for i, arg := range trw.wr.origTL[0].TemplateArguments { + if arg.FieldName == generic { + index = i + break + } + } + var args TypeArgumentsTree + trw.wr.PHPGetNatTypeDependenciesDecl(&args) + for _, arg := range args.EnumerateSubTreeWithPrefixes(index) { + *argsValues = append(*argsValues, fmt.Sprintf("$%s", arg)) + } + return + } + for i, _ := range currentType.origTL[0].TemplateArguments { + actualArg := currentType.arguments[i] + if actualArg.isNat { + if actualArg.isArith { + *argsValues = append(*argsValues, strconv.FormatUint(uint64(actualArg.Arith.Res), 10)) + } else { + isLocal, index := trw.PHPFindNatByName(currentTypeRef.Args[i].T.String()) + if isLocal { + *argsValues = append(*argsValues, fmt.Sprintf("$this->%s", trw.Fields[index].originalName)) + } else { + *argsValues = append(*argsValues, "$"+trw.wr.origTL[0].TemplateArguments[index].FieldName) + } + } + } else { + trw.phpGetFieldArgs(actualArg.tip, ¤tTypeRef.Args[i].T, argsValues) + } + } + return +} + func (trw *TypeRWStruct) PhpClassNameReplaced() bool { unionParent := trw.PhpConstructorNeedsUnion() if unionParent == nil { @@ -119,6 +192,7 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro trw.PHPStructConstructor(code, necessaryFieldsInConstructor) trw.PHPStructRPCSpecialGetters(code) + trw.PHPReadMethods(code) trw.PHPStructFieldMaskCalculators(code, usedFieldMasksIndecies, usedFieldMasks) trw.PHPStructFunctionSpecificMethods(code) @@ -218,6 +292,90 @@ func (trw *TypeRWStruct) PHPStructFunctionSpecificMethods(code *strings.Builder) } } +func (trw *TypeRWStruct) PHPReadMethods(code *strings.Builder) { + if trw.wr.gen.options.AddFunctionBodies { + natParamsComment := strings.Join( + utils.MapSlice( + trw.wr.PHPGetNatTypeDependenciesDeclAsArray(), + func(s string) string { return fmt.Sprintf("\n * @param int $%s", s) }), + "", + ) + natParamsDecl := strings.Join( + utils.MapSlice( + trw.wr.PHPGetNatTypeDependenciesDeclAsArray(), + func(s string) string { return ", $" + s }), + "", + ) + code.WriteString(fmt.Sprintf(` + /** + * @param tl_input_stream $stream%[1]s + * @return bool + */ + public function read_boxed($stream%[2]s) { + [$magic, $success] = $stream->read_uint32(); + if (!$success || $magic != 0x%08[3]x) { + return false; + } + return $this->read($stream%[2]s); + } +`, + natParamsComment, + natParamsDecl, + trw.wr.tlTag, + )) + + code.WriteString(fmt.Sprintf(` + /** + * @param tl_input_stream $stream%[1]s + * @return bool + */ + public function read($stream%[2]s) { +`, + natParamsComment, + natParamsDecl, + trw.wr.tlTag, + )) + const tab = " " + for i, field := range trw.Fields { + //fmt.Printf("\tfield \"%s\" with fieldMask \"%s\" and deps %v\n", field.originalName, trw.PHPGetFieldMask(i), trw.PHPGetFieldNatDependenciesValues(i)) + if field.originalName == "x" && trw.PhpClassName(false, true) == "test_gigi" { + print("debug") + } + + fieldMask := trw.PHPGetFieldMask(i) + shift := 2 + textTab := func() string { return strings.Repeat(tab, shift) } + if fieldMask != "" { + code.WriteString( + fmt.Sprintf( + "%[1]sif (%[2]s & (1 << %[3]d) != 0) {\n", + textTab(), + fieldMask, + field.BitNumber, + ), + ) + shift += 1 + } + fieldRead := field.t.trw.PhpReadMethodCall("$this->"+field.originalName, field.bare, trw.PHPGetFieldNatDependenciesValues(i)) + for _, line := range fieldRead { + code.WriteString(textTab() + line + "\n") + } + if fieldMask != "" { + shift -= 1 + code.WriteString( + fmt.Sprintf( + "%[1]s}\n", + textTab(), + ), + ) + } + } + + code.WriteString(" return true;\n") + code.WriteString(" }\n") + } +} + func (trw *TypeRWStruct) PHPStructFieldMaskCalculators(code *strings.Builder, usedFieldMasksIndecies []int, usedFieldMasks map[int][]Field) { // print methods to calculate fieldmasks // fix order @@ -619,3 +777,46 @@ func (trw *TypeRWStruct) PhpConstructorNeedsUnion() (unionParent *TypeRWWrapper) return nil } + +func (trw *TypeRWStruct) PhpReadMethodCall(targetName string, bare bool, args []string) []string { + if specialCase := PHPSpecialMembersTypes(trw.wr); specialCase != "" { + return []string{fmt.Sprintf("$success = RPC_READ%s($stream, %s);", ifString(bare, "", "_boxed"), targetName)} + } + unionParent := trw.PhpConstructorNeedsUnion() + if unionParent == nil { + if len(trw.Fields) == 1 && trw.ResultType == nil && trw.Fields[0].fieldMask == nil { + var result []string + if !bare { + result = append(result, + "[$magic, $success] = $stream->read_uint32();", + fmt.Sprintf("if (!$success || $magic != 0x%08[1]x) {", trw.wr.tlTag), + " return false;", + "}", + ) + } + result = append(result, trw.Fields[0].t.trw.PhpReadMethodCall(targetName, trw.Fields[0].bare, args)...) + return result + } + //isDict, _, _, valueType := isDictionaryElement(trw.wr) + //if isDict && trw.wr.tlName.Namespace == "" { // TODO NOT A SOLUTION, BUT... + // return valueType.t.trw.PhpTypeName(withPath, bare) + //} + } + return []string{ + fmt.Sprintf("$success = %[2]s->read%[1]s($stream%[3]s);", ifString(bare, "", "_boxed"), targetName, phpFormatArgs(args)), + "if ($success) {", + " return false;", + "}", + } +} + +func (trw *TypeRWStruct) PhpDefaultInit() string { + core := trw.wr.PHPGenCoreType() + if core != trw.wr { + return core.trw.PhpDefaultInit() + } + if core.PHPIsTrueType() { + return "true" + } + return fmt.Sprintf("new %s()", core.trw.PhpClassName(true, true)) +} diff --git a/internal/tlcodegen/type_rw_tuple_cpp.go b/internal/tlcodegen/type_rw_tuple_cpp.go index 2d5502dd..fd3b72dc 100644 --- a/internal/tlcodegen/type_rw_tuple_cpp.go +++ b/internal/tlcodegen/type_rw_tuple_cpp.go @@ -168,6 +168,7 @@ bool %[8]s::%[1]sWrite(::basictl::tl_ostream & s, const std::array<%[2]s, %[3]d> // valueFieldName := "" switch { // TODO - does not work yet + // REAL TODO CPP /* case trw.dictLike && !bytesVersion: keyTypeString = trw.dictKeyField.t.TypeString(bytesVersion) diff --git a/internal/tlcodegen/type_rw_tuple_php.go b/internal/tlcodegen/type_rw_tuple_php.go index 6e99c3ca..29c2a4d0 100644 --- a/internal/tlcodegen/type_rw_tuple_php.go +++ b/internal/tlcodegen/type_rw_tuple_php.go @@ -40,3 +40,89 @@ func (trw *TypeRWBrackets) PhpDefaultValue() string { func (trw *TypeRWBrackets) PhpIterateReachableTypes(reachableTypes *map[*TypeRWWrapper]bool) { trw.element.t.PhpIterateReachableTypes(reachableTypes) } + +func (trw *TypeRWBrackets) PhpReadMethodCall(targetName string, bare bool, args []string) []string { + //fmt.Println(">>>>>", trw.wr.goGlobalName, trw.dictLike, trw.vectorLike, trw.dynamicSize, trw.size) + //fmt.Println(">>>>> >>>>>", args) + result := make([]string, 0) + switch { + // actual vector + case trw.vectorLike && !trw.dictLike: + elementName := fmt.Sprintf("$%s___element", trw.PhpClassName(false, true)) + elementRead := trw.element.t.trw.PhpReadMethodCall(elementName, trw.element.bare, args) + for i := range elementRead { + elementRead[i] = " " + elementRead[i] + } + result = append(result, + "[$vector_size, $success] = $stream->read_uint32();", + "if (!$success) {", + " return false;", + "}", + // TODO MAKE MORE EFFICIENT + fmt.Sprintf("%[1]s = [];", targetName), + "for($i = 0; $i < $vector_size; $i++) {", + fmt.Sprintf(" %[2]s = %[1]s;", trw.element.t.trw.PhpDefaultInit(), elementName), + ) + result = append(result, elementRead...) + result = append(result, + fmt.Sprintf(" %[1]s[] = %[2]s;", targetName, elementName), + "}", + ) + return result + // tuple with size as last argument + case !trw.vectorLike && !trw.dictLike: + elementName := fmt.Sprintf("$%s___element", trw.PhpClassName(false, true)) + tupleSize := args[len(args)-1] + elementArgs := args[:len(args)-1] + elementRead := trw.element.t.trw.PhpReadMethodCall(elementName, trw.element.bare, elementArgs) + for i := range elementRead { + elementRead[i] = " " + elementRead[i] + } + result = append(result, + // TODO MAKE MORE EFFICIENT + fmt.Sprintf("%[1]s = [];", targetName), + fmt.Sprintf("for($i = 0; $i < %[1]s; $i++) {", tupleSize), + fmt.Sprintf(" %[2]s = %[1]s;", trw.element.t.trw.PhpDefaultInit(), elementName), + ) + result = append(result, elementRead...) + result = append(result, + fmt.Sprintf(" %[1]s[] = %[2]s;", targetName, elementName), + "}", + ) + return result + // actual map / dictionary + case trw.dictLike: + keyElement := fmt.Sprintf("$%s___key", trw.PhpClassName(false, true)) + valueElement := fmt.Sprintf("$%s___value", trw.PhpClassName(false, true)) + keyRead := trw.dictKeyField.t.trw.PhpReadMethodCall(keyElement, trw.dictKeyField.bare, args) + for i := range keyRead { + keyRead[i] = " " + keyRead[i] + } + valueRead := trw.dictValueField.t.trw.PhpReadMethodCall(valueElement, trw.dictValueField.bare, args) + for i := range valueRead { + valueRead[i] = " " + valueRead[i] + } + + result = append(result, + "[$dict_size, $success] = $stream->read_uint32();", + "if (!$success) {", + " return false;", + "}", + // TODO MAKE MORE EFFICIENT + fmt.Sprintf("%[1]s = [];", targetName), + "for($i = 0; $i < $dict_size; $i++) {", + ) + result = append(result, keyRead...) + result = append(result, valueRead...) + result = append(result, + fmt.Sprintf(" %[1]s[%[2]s] = %[3]s;", targetName, keyElement, valueElement), + "}", + ) + return result + } + return []string{fmt.Sprintf("", trw.wr.goGlobalName)} +} + +func (trw *TypeRWBrackets) PhpDefaultInit() string { + return "[]" +} diff --git a/internal/tlcodegen/type_rw_union_php.go b/internal/tlcodegen/type_rw_union_php.go index 561176de..94dca19f 100644 --- a/internal/tlcodegen/type_rw_union_php.go +++ b/internal/tlcodegen/type_rw_union_php.go @@ -82,3 +82,40 @@ func (trw *TypeRWUnion) PhpIterateReachableTypes(reachableTypes *map[*TypeRWWrap field.t.PhpIterateReachableTypes(reachableTypes) } } + +func (trw *TypeRWUnion) PhpReadMethodCall(targetName string, bare bool, args []string) []string { + if bare { + panic("union can't be bare") + } + var result []string + result = append(result, + "[$tag, $success] = $stream->read_uint32();", + "if (!$success) {", + " return false;", + "}", + "switch ($tag) {", + ) + for _, field := range trw.Fields { + curType := field.t + result = append(result, + fmt.Sprintf(" case 0x%08[1]x:", curType.tlTag), + fmt.Sprintf(" $variant = new %s();", curType.trw.PhpTypeName(false, true)), + fmt.Sprintf(" $success = $variant->read($stream%s);", phpFormatArgs(args)), + " if (!$success) {", + " return false;", + " }", + fmt.Sprintf(" %[1]s = $variant", targetName), + " break;", + ) + } + result = append(result, + " default:", + " return false;", + "}", + ) + return result +} + +func (trw *TypeRWUnion) PhpDefaultInit() string { + return trw.Fields[0].t.trw.PhpDefaultInit() +}