From 2a2008123894e1ec9e958d7b70b78a24c785df82 Mon Sep 17 00:00:00 2001 From: Fedor Vikhnin Date: Sat, 2 Nov 2024 16:59:16 +0300 Subject: [PATCH 01/26] add basic writer --- internal/tlcodegen/helpers_php.go | 148 ++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 internal/tlcodegen/helpers_php.go diff --git a/internal/tlcodegen/helpers_php.go b/internal/tlcodegen/helpers_php.go new file mode 100644 index 0000000..94f9917 --- /dev/null +++ b/internal/tlcodegen/helpers_php.go @@ -0,0 +1,148 @@ +package tlcodegen + +const basictlPHP = ` +data = $data; + } + + public function get_offset(): int { + return $this->offset; + } + + public function remaining_size(): int { + return strlen($this->data) - $this->offset; + } + + /** @return tuple(int, bool) */ + public function read_int32() { + // TODO: 'l' - signed 32 bit SYSTEM DEPENDENT ENDIAN + $data = unpack('l', $this->data, $this->offset); + if ($data == false) { + return [0, false]; + } else { + $this->offset += 4; + return [$data[1], true]; + } + } + + /** @return tuple(int, bool) */ + public function read_uint32() { + $data = unpack('V', $this->data, $this->offset); + if ($data == false) { + return [0, false]; + } else { + $this->offset += 4; + return [$data[1], true]; + } + } + + /** @return tuple(bool, bool) */ + public function read_bool(int $false_tag, $true_tag) { + $tag = $this->read_uint32(); + if ($tag == false) { + return [false, false]; + } else if ($tag == $false_tag) { + return [false, true]; + } else if ($tag == $true_tag) { + return [true, true]; + } + return [false, false]; + } + + /** @return tuple(float, bool) */ + public function read_float() { + $data = unpack('f', $this->data, $this->offset); + if ($data == false) { + return [0, false]; + } else { + $this->offset += 4; + return [$data[1], true]; + } + } + + /** @return tuple(double, bool) */ + public function read_double() { + $data = unpack('d', $this->data, $this->offset); + if ($data == false) { + return [0, false]; + } else { + $this->offset += 8; + return [$data[1], true]; + } + } + + /** @return tuple(string, bool) */ + public function read_string() { + $size = $this->remaining_size(); + if ($size == 0) { + return ["", false]; + } + $first_byte = ord($this->data[$this->offset]); + $l = 0; + $p = 0; + if ($first_byte < tl_constants::tinyStringLen) { + $l = $first_byte; + $this->offset += 1; + $p = $l + 1; + } elseif ($first_byte == tl_constants::bigStringMarker) { + if ($size < 4) { + return ["", false]; + } + $l = (ord($this->data[$this->offset + 3]) << 16) + (ord($this->data[$this->offset + 2]) << 8) + (ord($this->data[$this->offset + 1]) << 0); + $this->offset += 4; + $p = $l; + if ($l <= tl_constants::tinyStringLen) { + return ["", false]; + } + } else { + if ($size < 8) { + return ["", false]; + } + $l64 = (ord($this->data[$this->offset + 7]) << 48) + (ord($this->data[$this->offset + 6]) << 40) + (ord($this->data[$this->offset + 5]) << 32) + (ord($this->data[$this->offset + 4]) << 24) + (ord($this->data[$this->offset + 3]) << 16) + (ord($this->data[$this->offset + 2]) << 8) + (ord($this->data[$this->offset + 1]) << 0); + // TODO: check l64 > maxint + $l = $l64; + $this->offset += 8; + $p = $l; + if ($l <= tl_constants::bigStringLen) { + return ["", false]; + } + } + $start = $this->offset; + if ($l > 0) { + if ($this->remaining_size() < $l) { + return ["", false]; + } + } + $padding = $this->paddingLen($p); + for ($i = 0; $i < $padding; $i++) { + if (ord($this->data[$this->offset + $l + $i]) != 0) { + return ["", false]; + } + } + $this->offset += $l + $padding; + return [substr($this->data, $start, $l), true]; + } + + function paddingLen(int $l): int { + return (4 - ($l % 4)) % 4; + } +} +?> +` From 5c67297fccaa2933e4f9eae26c6da1a2e76aed85 Mon Sep 17 00:00:00 2001 From: Fedor Vikhnin Date: Wed, 6 Nov 2024 18:45:45 +0300 Subject: [PATCH 02/26] add reader and writer + basic tests --- internal/tlcodegen/helpers_php.go | 91 +++++++- .../test/codegen_test/php/basictl.php | 220 ++++++++++++++++++ .../test/codegen_test/php/test_basictl.php | 138 +++++++++++ 3 files changed, 442 insertions(+), 7 deletions(-) create mode 100644 internal/tlcodegen/test/codegen_test/php/basictl.php create mode 100644 internal/tlcodegen/test/codegen_test/php/test_basictl.php diff --git a/internal/tlcodegen/helpers_php.go b/internal/tlcodegen/helpers_php.go index 94f9917..f2d4c27 100644 --- a/internal/tlcodegen/helpers_php.go +++ b/internal/tlcodegen/helpers_php.go @@ -34,7 +34,7 @@ class tl_input_stream { public function read_int32() { // TODO: 'l' - signed 32 bit SYSTEM DEPENDENT ENDIAN $data = unpack('l', $this->data, $this->offset); - if ($data == false) { + if (!$data) { return [0, false]; } else { $this->offset += 4; @@ -45,7 +45,7 @@ class tl_input_stream { /** @return tuple(int, bool) */ public function read_uint32() { $data = unpack('V', $this->data, $this->offset); - if ($data == false) { + if (!$data) { return [0, false]; } else { $this->offset += 4; @@ -55,8 +55,8 @@ class tl_input_stream { /** @return tuple(bool, bool) */ public function read_bool(int $false_tag, $true_tag) { - $tag = $this->read_uint32(); - if ($tag == false) { + [$tag, $success] = $this->read_uint32(); + if (!$success) { return [false, false]; } else if ($tag == $false_tag) { return [false, true]; @@ -69,7 +69,7 @@ class tl_input_stream { /** @return tuple(float, bool) */ public function read_float() { $data = unpack('f', $this->data, $this->offset); - if ($data == false) { + if (!$data) { return [0, false]; } else { $this->offset += 4; @@ -77,10 +77,10 @@ class tl_input_stream { } } - /** @return tuple(double, bool) */ + /** @return tuple(float, bool) */ public function read_double() { $data = unpack('d', $this->data, $this->offset); - if ($data == false) { + if (!$data) { return [0, false]; } else { $this->offset += 8; @@ -142,6 +142,83 @@ class tl_input_stream { function paddingLen(int $l): int { return (4 - ($l % 4)) % 4; + } +} + +class tl_output_stream { + /** @var string */ + private $data = ""; + + public function __construct(string $data) { + $this->data = $data; + } + + public function get_data(): string { + return $this->data; + } + + public function write_uint32(int $value) { + $this->data .= pack('V', $value); + } + + public function write_int32(int $value) { + $this->data .= pack('l', $value); + } + + public function write_bool(bool $value, int $false_tag, $true_tag) { + if ($value) { + $this->data .= pack('V', $true_tag); + } else { + $this->data .= pack('V', $false_tag); + } + } + + public function write_float(float $value) { + $this->data .= pack('f', $value); + } + + public function write_double(float $value) { + $this->data .= pack('d', $value); + } + + public function write_string(string $value) { + $l = strlen($value); + $p = 0; + if ($l <= tl_constants::tinyStringLen) { + $this->data .= chr($l); + $p = $l + 1; + } else if ($l <= tl_constants::bigStringLen) { + $this->data .= chr(tl_constants::bigStringMarker); + $this->data .= chr(($l & 255)); + $this->data .= chr((($l >> 8) & 255)); + $this->data .= chr((($l >> 16) & 255)); + $p = $l; + } else { + if ($l > tl_constants::hugeStringLen) { + $l = tl_constants::hugeStringLen; + $value = substr($value, 0, $l); + } + $this->data .= chr(tl_constants::hugeStringMarker); + $this->data .= chr(($l & 255)); + $this->data .= chr((($l >> 8) & 255)); + $this->data .= chr((($l >> 16) & 255)); + $this->data .= chr((($l >> 24) & 255)); + $this->data .= chr((($l >> 32) & 255)); + $this->data .= chr((($l >> 40) & 255)); + $this->data .= chr((($l >> 48) & 255)); + $p = $l; + } + $this->data .= $value; + if ($p % 4 == 1) { + $this->data .= chr(0); + $this->data .= chr(0); + $this->data .= chr(0); + } else if ($p % 4 == 2) { + $this->data .= chr(0); + $this->data .= chr(0); + } else if ($p % 4 == 3) { + $this->data .= chr(0); + } } } ?> diff --git a/internal/tlcodegen/test/codegen_test/php/basictl.php b/internal/tlcodegen/test/codegen_test/php/basictl.php new file mode 100644 index 0000000..1d54be6 --- /dev/null +++ b/internal/tlcodegen/test/codegen_test/php/basictl.php @@ -0,0 +1,220 @@ +data = $data; + } + + public function get_offset(): int { + return $this->offset; + } + + public function remaining_size(): int { + return strlen($this->data) - $this->offset; + } + + /** @return tuple(int, bool) */ + public function read_int32() { + // TODO: 'l' - signed 32 bit SYSTEM DEPENDENT ENDIAN + $data = unpack('l', $this->data, $this->offset); + if (!$data) { + return [0, false]; + } else { + $this->offset += 4; + return [$data[1], true]; + } + } + + /** @return tuple(int, bool) */ + public function read_uint32() { + $data = unpack('V', $this->data, $this->offset); + if (!$data) { + return [0, false]; + } else { + $this->offset += 4; + return [$data[1], true]; + } + } + + /** @return tuple(bool, bool) */ + public function read_bool(int $false_tag, $true_tag) { + [$tag, $success] = $this->read_uint32(); + if (!$success) { + return [false, false]; + } else if ($tag == $false_tag) { + return [false, true]; + } else if ($tag == $true_tag) { + return [true, true]; + } + return [false, false]; + } + + /** @return tuple(float, bool) */ + public function read_float() { + $data = unpack('f', $this->data, $this->offset); + if (!$data) { + return [0, false]; + } else { + $this->offset += 4; + return [$data[1], true]; + } + } + + /** @return tuple(float, bool) */ + public function read_double() { + $data = unpack('d', $this->data, $this->offset); + if (!$data) { + return [0, false]; + } else { + $this->offset += 8; + return [$data[1], true]; + } + } + + /** @return tuple(string, bool) */ + public function read_string() { + $size = $this->remaining_size(); + if ($size == 0) { + return ["", false]; + } + $first_byte = ord($this->data[$this->offset]); + $l = 0; + $p = 0; + if ($first_byte < tl_constants::tinyStringLen) { + $l = $first_byte; + $this->offset += 1; + $p = $l + 1; + } elseif ($first_byte == tl_constants::bigStringMarker) { + if ($size < 4) { + return ["", false]; + } + $l = (ord($this->data[$this->offset + 3]) << 16) + (ord($this->data[$this->offset + 2]) << 8) + (ord($this->data[$this->offset + 1]) << 0); + $this->offset += 4; + $p = $l; + if ($l <= tl_constants::tinyStringLen) { + return ["", false]; + } + } else { + if ($size < 8) { + return ["", false]; + } + $l64 = (ord($this->data[$this->offset + 7]) << 48) + (ord($this->data[$this->offset + 6]) << 40) + (ord($this->data[$this->offset + 5]) << 32) + (ord($this->data[$this->offset + 4]) << 24) + (ord($this->data[$this->offset + 3]) << 16) + (ord($this->data[$this->offset + 2]) << 8) + (ord($this->data[$this->offset + 1]) << 0); + // TODO: check l64 > maxint + $l = $l64; + $this->offset += 8; + $p = $l; + if ($l <= tl_constants::bigStringLen) { + return ["", false]; + } + } + $start = $this->offset; + if ($l > 0) { + if ($this->remaining_size() < $l) { + return ["", false]; + } + } + $padding = $this->paddingLen($p); + for ($i = 0; $i < $padding; $i++) { + if (ord($this->data[$this->offset + $l + $i]) != 0) { + return ["", false]; + } + } + $this->offset += $l + $padding; + return [substr($this->data, $start, $l), true]; + } + + function paddingLen(int $l): int { + return (4 - ($l % 4)) % 4; + } +} + +class tl_output_stream { + /** @var string */ + private $data = ""; + + public function __construct(string $data) { + $this->data = $data; + } + + public function get_data(): string { + return $this->data; + } + + public function write_uint32(int $value) { + $this->data .= pack('V', $value); + } + + public function write_int32(int $value) { + $this->data .= pack('l', $value); + } + + public function write_bool(bool $value, int $false_tag, $true_tag) { + if ($value) { + $this->data .= pack('V', $true_tag); + } else { + $this->data .= pack('V', $false_tag); + } + } + + public function write_float(float $value) { + $this->data .= pack('f', $value); + } + + public function write_double(float $value) { + $this->data .= pack('d', $value); + } + + public function write_string(string $value) { + $l = strlen($value); + $p = 0; + if ($l <= tl_constants::tinyStringLen) { + $this->data .= chr($l); + $p = $l + 1; + } else if ($l <= tl_constants::bigStringLen) { + $this->data .= chr(tl_constants::bigStringMarker); + $this->data .= chr(($l & 255)); + $this->data .= chr((($l >> 8) & 255)); + $this->data .= chr((($l >> 16) & 255)); + $p = $l; + } else { + if ($l > tl_constants::hugeStringLen) { + $l = tl_constants::hugeStringLen; + $value = substr($value, 0, $l); + } + $this->data .= chr(tl_constants::hugeStringMarker); + $this->data .= chr(($l & 255)); + $this->data .= chr((($l >> 8) & 255)); + $this->data .= chr((($l >> 16) & 255)); + $this->data .= chr((($l >> 24) & 255)); + $this->data .= chr((($l >> 32) & 255)); + $this->data .= chr((($l >> 40) & 255)); + $this->data .= chr((($l >> 48) & 255)); + $p = $l; + } + $this->data .= $value; + if ($p % 4 == 1) { + $this->data .= chr(0); + $this->data .= chr(0); + $this->data .= chr(0); + } else if ($p % 4 == 2) { + $this->data .= chr(0); + $this->data .= chr(0); + } else if ($p % 4 == 3) { + $this->data .= chr(0); + } + } +} +?> \ No newline at end of file diff --git a/internal/tlcodegen/test/codegen_test/php/test_basictl.php b/internal/tlcodegen/test/codegen_test/php/test_basictl.php new file mode 100644 index 0000000..24fd0cb --- /dev/null +++ b/internal/tlcodegen/test/codegen_test/php/test_basictl.php @@ -0,0 +1,138 @@ +serializing_data = $data; + $this->tl_data = $tl_data; + $this->data_type = $data_type; + } + + public function test_read_write_interaction(): bool + { + $w = new tl_output_stream(""); + switch ($this->data_type) { + case "string": { + $w->write_string($this->serializing_data); + break; + } + case "int32": { + $w->write_int32($this->serializing_data); + break; + } + case "uint32": { + $w->write_uint32($this->serializing_data); + break; + } + case "float": { + $w->write_float($this->serializing_data); + break; + } + case "double": { + $w->write_double($this->serializing_data); + break; + } + case "bool": { + $w->write_bool($this->serializing_data, 0, 1); + break; + } + } + $serialized_data = $w->get_data(); + if ($this->tl_data && $serialized_data != test_case::binary_to_string($this->tl_data)) { + return false; + } + $r = new tl_input_stream($w->get_data()); + $return_value = ""; + $success = true; + switch ($this->data_type) { + case "string": { + [$return_value, $success] = $r->read_string(); + break; + } + case "int32": { + [$return_value, $success] = $r->read_int32(); + break; + } + case "uint32": { + [$return_value, $success] = $r->read_uint32(); + break; + } + case "float": { + [$return_value, $success] = $r->read_float(); + break; + } + case "double": { + [$return_value, $success] = $r->read_double(); + break; + } + case "bool": { + [$return_value, $success] = $r->read_bool(0, 1); + break; + } + } + return $success && ($return_value == $this->serializing_data); + } + + static function binary_to_string(array $binary): string + { + $s = ""; + foreach ($binary as $byte) { + $s .= chr($byte); + } + return $s; + } +} +function bool_to_string(bool $x): string +{ + if ($x) { + return "true"; + } else { + return "false"; + } +} + +$tests = array( + "test-int32" => new test_case($data=123, $data_type="int32", $tl_data=[123, 0, 0, 0]), + "test-uint32" => new test_case($data=((1 << 8) + (1 << 16)), $data_type="int32", $tl_data=[0, 1, 1, 0]), + "test-bool-true" => new test_case($data=true, $data_type="bool", $tl_data=[1, 0, 0, 0]), + "test-bool-false" => new test_case($data=false, $data_type="bool", $tl_data=[0, 0, 0, 0]), + "test-small-string" => new test_case($data=str_repeat("B", 12), $data_type="string", $tl_data=false), + "test-big-string" => new test_case($data=str_repeat("A", 255), $data_type="string", $tl_data=false), + "test-huge-string" => new test_case($data=str_repeat("A", (1 << 24)), $data_type="string", $tl_data=false), +); + +$failed_tests = array(); + +foreach ($tests as $test_name => $test) { + $test_result = $test->test_read_write_interaction(); +// println("Test \"" . $test_name . "\": " . bool_to_string($test_result)); + if (!$test_result) { + $failed_tests[] = $test_name; + } +} + +if (count($failed_tests) == 0) { + printf("ALL TESTS PASSED!\n"); +} else { + printf("FAILED %d TESTS:\n", count($failed_tests)); + foreach ($failed_tests as $failed_test) { + printf("\t%s\n", $failed_test); + } +} +?> \ No newline at end of file From d521a2482283d0df08866e4bcac0387c0c2208ea Mon Sep 17 00:00:00 2001 From: Fedor Vikhnin Date: Wed, 13 Nov 2024 16:17:04 +0300 Subject: [PATCH 03/26] update php helper --- internal/tlcodegen/helpers_php.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/tlcodegen/helpers_php.go b/internal/tlcodegen/helpers_php.go index f2d4c27..4e70412 100644 --- a/internal/tlcodegen/helpers_php.go +++ b/internal/tlcodegen/helpers_php.go @@ -1,6 +1,7 @@ package tlcodegen -const basictlPHP = ` +const BasicTlPathPhp = "basictl.php" +const BasicTLCodePHP = ` Date: Wed, 13 Nov 2024 16:49:55 +0300 Subject: [PATCH 04/26] commit new abstractions --- internal/tlcodegen/tlgen.go | 128 ++++++++++++++++++++++++++++---- internal/tlcodegen/tlgen_php.go | 46 ++++++++++++ internal/tlcodegen/type_rw.go | 6 ++ 3 files changed, 165 insertions(+), 15 deletions(-) create mode 100644 internal/tlcodegen/tlgen_php.go diff --git a/internal/tlcodegen/tlgen.go b/internal/tlcodegen/tlgen.go index ebc5a74..52a6a8f 100644 --- a/internal/tlcodegen/tlgen.go +++ b/internal/tlcodegen/tlgen.go @@ -1361,6 +1361,15 @@ func sortComponents(target int, visited *map[int]bool, deps *map[int][]int, orde *order = append(*order, target) } +type LanguageTypeSystemInfo struct { + AllowedTypeGenerics bool + AllowedCompileTimeConstantGenerics bool +} + +func (lti LanguageTypeSystemInfo) OnlyFullyResolvedTypes() bool { + return !(lti.AllowedCompileTimeConstantGenerics && lti.AllowedTypeGenerics) +} + type ConstructorName = tlast.Name type Constructor struct { Type *TypeDefinition @@ -1408,6 +1417,85 @@ type TypeReduction struct { Arguments []EvaluatedType } +func (tr *TypeReduction) EraseTypes() TypeReduction { + erasedReduction := *tr + erasedReduction.Arguments = make([]EvaluatedType, 0) + + var typeIndex int + + for _, arg := range tr.Arguments { + switch arg.Index { + case TypeConstant: + erasedReduction.Arguments = append( + erasedReduction.Arguments, + EvaluatedType{Index: TypeVariable, TypeVariable: fmt.Sprintf("X%d", typeIndex)}, + ) + typeIndex++ + default: + erasedReduction.Arguments = append(erasedReduction.Arguments, arg) + } + } + return erasedReduction +} + +func (tr *TypeReduction) EraseConstants() TypeReduction { + erasedReduction := *tr + erasedReduction.Arguments = make([]EvaluatedType, 0) + + var conIndex int + + for _, arg := range tr.Arguments { + switch arg.Index { + case NumberConstant: + erasedReduction.Arguments = append( + erasedReduction.Arguments, + EvaluatedType{Index: NumberVariable, Variable: fmt.Sprintf("n%d", conIndex), VariableActsAsConstant: true}, + ) + conIndex++ + default: + erasedReduction.Arguments = append(erasedReduction.Arguments, arg) + } + } + return erasedReduction +} + +func (tr *TypeReduction) EraseConstantsAndTypes() TypeReduction { + erasedReduction := (*tr).EraseTypes() + erasedReduction = erasedReduction.EraseConstants() + return erasedReduction +} + +func (tr *TypeReduction) AncestorTemplateInTypeSystem(info LanguageTypeSystemInfo) TypeReduction { + ancestor := *tr + if info.AllowedTypeGenerics { + ancestor = ancestor.EraseTypes() + } + if info.AllowedCompileTimeConstantGenerics { + ancestor = ancestor.EraseConstants() + } + return ancestor +} + +func (tr *TypeReduction) IsFullyResolved() bool { + for _, arg := range tr.Arguments { + switch arg.Index { + case NumberConstant: + continue + case NumberVariable: + continue + case TypeConstant: + if !arg.Type.IsFullyResolved() { + return false + } + case TypeVariable: + return false + default: + panic("not all variants of reduction considered") + } + } + return true +} + func (tr *TypeReduction) ReferenceName() (name tlast.Name) { if tr.IsType { name = tr.Type.Name @@ -1435,7 +1523,11 @@ func (tr *TypeReduction) String() string { case 0: s += "Con" + strconv.FormatInt(int64(arg.Constant), 10) case 1: - s += "Var" + if arg.VariableActsAsConstant { + s += "ConstVar" + } else { + s += "Var" + } case 2: s += arg.Type.String() case 3: @@ -1484,7 +1576,8 @@ func processCombinators(types map[string]*tlast.Combinator) *TypesInfo { existingConstructors[currentConstructor] = &constructor } - typeReductions := make(map[*TypeDefinition]*map[string]*TypeReduction) + typeReductions := make(map[string]*TypeReduction) + visitedTypes := make(map[TypeName]bool) for _, comb := range existingTypes { if len(comb.TypeArguments) != 0 { @@ -1498,6 +1591,7 @@ func processCombinators(types map[string]*tlast.Combinator) *TypesInfo { &typeReductions, &existingTypes, &existingConstructors, + &visitedTypes, ) } @@ -1510,13 +1604,14 @@ func processCombinators(types map[string]*tlast.Combinator) *TypesInfo { func reduce( targetTypeReduction TypeReduction, - visitedReductions *map[*TypeDefinition]*map[string]*TypeReduction, + visitedReductions *map[string]*TypeReduction, types *map[TypeName]*TypeDefinition, constructors *map[ConstructorName]*Constructor, + visitedTypes *map[TypeName]bool, ) { for _, arg := range targetTypeReduction.Arguments { if arg.Index == TypeConstant { - reduce(*arg.Type, visitedReductions, types, constructors) + reduce(*arg.Type, visitedReductions, types, constructors, visitedTypes) } } @@ -1535,6 +1630,7 @@ func reduce( visitedReductions, types, constructors, + visitedTypes, ) } } @@ -1542,26 +1638,28 @@ func reduce( func reduceConstructor( constructor *Constructor, args []EvaluatedType, - visitedReductions *map[*TypeDefinition]*map[string]*TypeReduction, + visitedReductions *map[string]*TypeReduction, types *map[TypeName]*TypeDefinition, constructors *map[ConstructorName]*Constructor, + visitedTypes *map[TypeName]bool, ) { if constructor == nil || constructor.Type.IsBasic { return } - trs, ok := (*visitedReductions)[constructor.Type] - if !ok { - tmp := make(map[string]*TypeReduction) - (*visitedReductions)[constructor.Type] = &tmp - trs = &tmp + if (*visitedTypes)[constructor.Name] { + return + } else { + (*visitedTypes)[constructor.Name] = true + defer func() { + (*visitedTypes)[constructor.Name] = false + }() } constructorReduction := TypeReduction{IsType: false, Constructor: constructor, Arguments: args} - _, ok = (*trs)[constructorReduction.String()] - if !ok { - (*trs)[constructorReduction.String()] = &constructorReduction + if _, ok := (*visitedReductions)[constructorReduction.String()]; !ok { + (*visitedReductions)[constructorReduction.String()] = &constructorReduction } else { return } @@ -1572,7 +1670,7 @@ func reduceConstructor( fieldType := toTypeReduction(field.FieldType, types, constructors) if fieldType != nil { fillTypeReduction(fieldType, args, constructor.Type, &defaultFields) - reduce(*fieldType, visitedReductions, types, constructors) + reduce(*fieldType, visitedReductions, types, constructors, visitedTypes) } } } @@ -1707,7 +1805,7 @@ func toTypeReduction( type TypesInfo struct { Types map[TypeName]*TypeDefinition Constructors map[ConstructorName]*Constructor - TypeReductions map[*TypeDefinition]*map[string]*TypeReduction + TypeReductions map[string]*TypeReduction } // works for given constructor or for 1-st diff --git a/internal/tlcodegen/tlgen_php.go b/internal/tlcodegen/tlgen_php.go new file mode 100644 index 0000000..b2de42e --- /dev/null +++ b/internal/tlcodegen/tlgen_php.go @@ -0,0 +1,46 @@ +package tlcodegen + +import ( + "strings" +) + +type PhpClassMeta struct { + FileName string + GroupName string + + ClassName string +} + +const ( + PHPFileStart = "\n" +) + +func (gen *Gen2) PhpGeneratecode() error { + if err := gen.addCodeFile(BasicTlPathPhp, BasicTLCodePHP); err != nil { + return err + } + + // select files where to write code + gen.PhpChoosePaths() + + for _, wrapper := range gen.generatedTypesList { + var code strings.Builder + // add + code.WriteString(PHPFileStart) + // add copyright text + code.WriteString(gen.copyrightText) + + wrapper.PHPGenerateCode(&code, true) + + filepathName := wrapper.phpInfo.FileName + if err := gen.addCodeFile(filepathName, code.String()); err != nil { + return err + } + } + return nil +} + +func (gen *Gen2) PhpChoosePaths() { + +} diff --git a/internal/tlcodegen/type_rw.go b/internal/tlcodegen/type_rw.go index 4373c7b..08988e6 100644 --- a/internal/tlcodegen/type_rw.go +++ b/internal/tlcodegen/type_rw.go @@ -85,6 +85,8 @@ type TypeRWWrapper struct { cppDetailsFileName string groupName string + phpInfo PhpClassMeta + tlTag uint32 // TODO - turn into function tlName tlast.Name // TODO - turn into function constructor name or union name for code generation origTL []*tlast.Combinator @@ -488,6 +490,10 @@ func (w *TypeRWWrapper) IsTrueType() bool { return len(structElement.Fields) == 0 } +func (w *TypeRWWrapper) PHPGenerateCode(code *strings.Builder, bytes bool) { + +} + func (w *TypeRWWrapper) CPPFillRecursiveChildren(visitedNodes map[*TypeRWWrapper]bool) { if visitedNodes[w] { return From 828236a1d4eb1818d68145444adc012c26a23fab Mon Sep 17 00:00:00 2001 From: Fedor Vikhnin Date: Mon, 9 Dec 2024 12:47:53 +0300 Subject: [PATCH 05/26] reverse engineered php names --- internal/tlcodegen/tlgen.go | 6 +++++ internal/tlcodegen/tlgen_php.go | 14 +++++++---- internal/tlcodegen/type_rw.go | 6 +++++ internal/tlcodegen/type_rw_bool.go | 4 ++++ internal/tlcodegen/type_rw_maybe.go | 13 ++++++++++ internal/tlcodegen/type_rw_primitive.go | 14 +++++++++++ internal/tlcodegen/type_rw_struct.go | 32 +++++++++++++++++++++++++ internal/tlcodegen/type_rw_tuple.go | 8 +++++++ internal/tlcodegen/type_rw_union.go | 17 +++++++++++++ 9 files changed, 109 insertions(+), 5 deletions(-) diff --git a/internal/tlcodegen/tlgen.go b/internal/tlcodegen/tlgen.go index 52a6a8f..635400a 100644 --- a/internal/tlcodegen/tlgen.go +++ b/internal/tlcodegen/tlgen.go @@ -789,6 +789,7 @@ func GenerateCode(tl tlast.TL, options Gen2Options) (*Gen2, error) { gen.RootCPPNamespaceElements = strings.Split(options.RootCPPNamespace, "::") gen.DetailsCPPNamespaceElements = []string{options.RootCPPNamespace, "details"} // TODO - rename to prevent collisions with TL namespace details gen.DetailsCPPNamespace = options.RootCPPNamespace + "::details" + case "php": default: return nil, fmt.Errorf("unsupported language %q, only 'go' and 'cpp' are supported, plus '' for linting", options.Language) } @@ -1215,6 +1216,11 @@ func GenerateCode(tl tlast.TL, options Gen2Options) (*Gen2, error) { if err := gen.generateCodeCPP(generateByteVersions); err != nil { return nil, err } + case "php": + if err := gen.generateCodePHP(generateByteVersions); err != nil { + return nil, err + } + } if options.SchemaDocumentation { diff --git a/internal/tlcodegen/tlgen_php.go b/internal/tlcodegen/tlgen_php.go index b2de42e..e1b82c7 100644 --- a/internal/tlcodegen/tlgen_php.go +++ b/internal/tlcodegen/tlgen_php.go @@ -1,6 +1,8 @@ package tlcodegen import ( + "fmt" + "reflect" "strings" ) @@ -16,7 +18,7 @@ const ( //PHPFileEnd = "?>\n" ) -func (gen *Gen2) PhpGeneratecode() error { +func (gen *Gen2) generateCodePHP(generateByteVersions []string) error { if err := gen.addCodeFile(BasicTlPathPhp, BasicTLCodePHP); err != nil { return err } @@ -33,10 +35,12 @@ func (gen *Gen2) PhpGeneratecode() error { wrapper.PHPGenerateCode(&code, true) - filepathName := wrapper.phpInfo.FileName - if err := gen.addCodeFile(filepathName, code.String()); err != nil { - return err - } + fmt.Printf("TL[%[1]s] = Go {%[2]s, %[4]s} -> PHP {%[3]s}\n", wrapper.tlName.String(), wrapper.goGlobalName, wrapper.trw.PhpName(), reflect.TypeOf(wrapper.trw)) + + //filepathName := wrapper.phpInfo.FileName + //if err := gen.addCodeFile(filepathName, code.String()); err != nil { + // return err + //} } return nil } diff --git a/internal/tlcodegen/type_rw.go b/internal/tlcodegen/type_rw.go index 08988e6..d2fbb77 100644 --- a/internal/tlcodegen/type_rw.go +++ b/internal/tlcodegen/type_rw.go @@ -730,6 +730,10 @@ outer: return result } +type TypeRWPHPData interface { + PhpName() string +} + // TODO remove skipAlias after we start generating go code like we do for C++ type TypeRW interface { // methods below are target language independent @@ -774,6 +778,8 @@ type TypeRW interface { 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) + + TypeRWPHPData } type Field struct { diff --git a/internal/tlcodegen/type_rw_bool.go b/internal/tlcodegen/type_rw_bool.go index 5093806..9d9b5a7 100644 --- a/internal/tlcodegen/type_rw_bool.go +++ b/internal/tlcodegen/type_rw_bool.go @@ -109,3 +109,7 @@ func (trw *TypeRWBool) typeJSONReadingCode(bytesVersion bool, directImports *Dir func (trw *TypeRWBool) typeJSON2ReadingCode(bytesVersion bool, directImports *DirectImports, ins *InternalNamespace, jvalue string, val string, natArgs []string, ref bool) string { return wrapLast(false, fmt.Sprintf("%sJson2ReadBool(%s, %s)", trw.wr.gen.InternalPrefix(), jvalue, addAmpersand(ref, val))) } + +func (trw *TypeRWBool) PhpName() string { + return "boolean" +} diff --git a/internal/tlcodegen/type_rw_maybe.go b/internal/tlcodegen/type_rw_maybe.go index b2068e4..98e2ea8 100644 --- a/internal/tlcodegen/type_rw_maybe.go +++ b/internal/tlcodegen/type_rw_maybe.go @@ -118,3 +118,16 @@ func (trw *TypeRWMaybe) typeJSONReadingCode(bytesVersion bool, directImports *Di func (trw *TypeRWMaybe) typeJSON2ReadingCode(bytesVersion bool, directImports *DirectImports, ins *InternalNamespace, jvalue string, val string, natArgs []string, ref bool) string { return fmt.Sprintf("if err := %s.ReadJSON(legacyTypeNames, %s %s); err != nil { return err }", val, jvalue, joinWithCommas(natArgs)) } + +func (trw *TypeRWMaybe) PhpName() string { + target := trw.getInnerTarget() + return "maybe_" + target.trw.PhpName() +} + +func (trw *TypeRWMaybe) getInnerTarget() *TypeRWWrapper { + if inner, ok := trw.element.t.trw.(*TypeRWMaybe); ok { + return inner.getInnerTarget() + } else { + return trw.element.t + } +} diff --git a/internal/tlcodegen/type_rw_primitive.go b/internal/tlcodegen/type_rw_primitive.go index b789a0a..821b476 100644 --- a/internal/tlcodegen/type_rw_primitive.go +++ b/internal/tlcodegen/type_rw_primitive.go @@ -170,3 +170,17 @@ func (trw *TypeRWPrimitive) typeJSON2ReadingCode(bytesVersion bool, directImport func (trw *TypeRWPrimitive) GenerateCode(byteVersion bool, directImports *DirectImports) string { return "" } + +// TODO +func (trw *TypeRWPrimitive) PhpName() string { + switch trw.goType { + case "int32", "int64", "uint32": + return "int" + case "string": + return "string" + case "float32", "float64": + return "float" + default: + return fmt.Sprintf("", trw.tlType) + } +} diff --git a/internal/tlcodegen/type_rw_struct.go b/internal/tlcodegen/type_rw_struct.go index 8d4f505..a733f68 100644 --- a/internal/tlcodegen/type_rw_struct.go +++ b/internal/tlcodegen/type_rw_struct.go @@ -10,6 +10,7 @@ import ( "fmt" "log" "sort" + "strings" ) type TypeRWStruct struct { @@ -564,3 +565,34 @@ func (trw *TypeRWStruct) typeJSON2ReadingCode(bytesVersion bool, directImports * } return fmt.Sprintf("if err := %s.ReadJSON(legacyTypeNames, %s %s); err != nil { return err }", val, jvalue, joinWithCommas(natArgs)) } + +func (trw *TypeRWStruct) PhpName() string { + if len(trw.Fields) == 1 { + return trw.Fields[0].t.trw.PhpName() + } + + isDict, _, _, valueType := isDictionaryElement(trw.wr) + if isDict { + return valueType.t.trw.PhpName() + } + + name := trw.wr.tlName.Name + if len(trw.wr.tlName.Namespace) != 0 { + name = fmt.Sprintf("%s_%s", trw.wr.tlName.Namespace, name) + } + + elems := make([]string, 0, len(trw.wr.arguments)) + for _, arg := range trw.wr.arguments { + if arg.tip != nil { + elems = append(elems, arg.tip.trw.PhpName()) + } + } + + args := strings.Join(elems, "__") + if len(args) > 0 { + name += "__" + name += args + } + + return name +} diff --git a/internal/tlcodegen/type_rw_tuple.go b/internal/tlcodegen/type_rw_tuple.go index 7757855..8bd2880 100644 --- a/internal/tlcodegen/type_rw_tuple.go +++ b/internal/tlcodegen/type_rw_tuple.go @@ -210,3 +210,11 @@ func (trw *TypeRWBrackets) typeJSON2ReadingCode(bytesVersion bool, directImports goGlobalName := addBytes(trw.wr.goGlobalName, bytesVersion) return fmt.Sprintf("if err := %sReadJSON(legacyTypeNames, %s, %s%s); err != nil { return err }", trw.wr.ins.Prefix(directImports, ins)+goGlobalName, jvalue, addAmpersand(ref, val), joinWithCommas(natArgs)) } + +func (trw *TypeRWBrackets) PhpName() string { + if strings.HasPrefix(trw.wr.tlName.String(), BuiltinTupleName) || + strings.HasPrefix(trw.wr.tlName.String(), BuiltinVectorName) { + return "array_" + trw.element.t.trw.PhpName() + } + return fmt.Sprintf("", trw.wr.goGlobalName) +} diff --git a/internal/tlcodegen/type_rw_union.go b/internal/tlcodegen/type_rw_union.go index 21e5bf1..110b482 100644 --- a/internal/tlcodegen/type_rw_union.go +++ b/internal/tlcodegen/type_rw_union.go @@ -8,6 +8,7 @@ package tlcodegen import ( "fmt" + "strings" ) type TypeRWUnion struct { @@ -188,3 +189,19 @@ func (trw *TypeRWUnion) HasShortFieldCollision(wr *TypeRWWrapper) bool { } return false } + +func (trw *TypeRWUnion) PhpName() string { + name := trw.wr.tlName.Name + + elems := make([]string, 0, len(trw.wr.arguments)) + for _, arg := range trw.wr.arguments { + if arg.tip != nil { + elems = append(elems, "__", arg.tip.trw.PhpName()) + } + } + + args := strings.Join(elems, "") + name += args + + return name +} From ffe767e20c0f08248157f235d2d0a80a42400e81 Mon Sep 17 00:00:00 2001 From: Fedor Vikhnin Date: Mon, 9 Dec 2024 16:43:42 +0300 Subject: [PATCH 06/26] add paths --- internal/tlcodegen/tlgen_php.go | 8 +++++++- internal/tlcodegen/type_rw.go | 21 ++++++++++++++++++++- internal/tlcodegen/type_rw_bool.go | 6 +++++- internal/tlcodegen/type_rw_maybe.go | 9 +++++++-- internal/tlcodegen/type_rw_primitive.go | 7 +++++-- internal/tlcodegen/type_rw_struct.go | 25 +++++++++++++++---------- internal/tlcodegen/type_rw_tuple.go | 16 ++++++++++++++-- internal/tlcodegen/type_rw_union.go | 18 +++++++++++++----- 8 files changed, 86 insertions(+), 24 deletions(-) diff --git a/internal/tlcodegen/tlgen_php.go b/internal/tlcodegen/tlgen_php.go index e1b82c7..23c56e5 100644 --- a/internal/tlcodegen/tlgen_php.go +++ b/internal/tlcodegen/tlgen_php.go @@ -35,7 +35,13 @@ func (gen *Gen2) generateCodePHP(generateByteVersions []string) error { wrapper.PHPGenerateCode(&code, true) - fmt.Printf("TL[%[1]s] = Go {%[2]s, %[4]s} -> PHP {%[3]s}\n", wrapper.tlName.String(), wrapper.goGlobalName, wrapper.trw.PhpName(), reflect.TypeOf(wrapper.trw)) + fmt.Printf("TL[%[1]s] = Go {%[2]s, %[4]s} -> PHP {%[3]s, %[5]s}\n", + wrapper.tlName.String(), + wrapper.goGlobalName, + wrapper.trw.PhpClassName(true), + reflect.TypeOf(wrapper.trw), + wrapper.trw.PhpTypeName(true), + ) //filepathName := wrapper.phpInfo.FileName //if err := gen.addCodeFile(filepathName, code.String()); err != nil { diff --git a/internal/tlcodegen/type_rw.go b/internal/tlcodegen/type_rw.go index d2fbb77..5fa21c8 100644 --- a/internal/tlcodegen/type_rw.go +++ b/internal/tlcodegen/type_rw.go @@ -494,6 +494,24 @@ func (w *TypeRWWrapper) PHPGenerateCode(code *strings.Builder, bytes bool) { } +func (w *TypeRWWrapper) PHPTypePath() string { + _, isStruct := w.trw.(*TypeRWStruct) + _, isUnion := w.trw.(*TypeRWUnion) + if !(isStruct || isUnion) { + return "" + } + + category := "Types" + if strct, isStrct := w.trw.(*TypeRWStruct); isStrct && strct.ResultType != nil { + category = "Functions" + } + group := "_common" + if w.tlName.Namespace != "" { + group = w.tlName.Namespace + } + return fmt.Sprintf("TL\\%[1]s\\%[2]s\\", group, category) +} + func (w *TypeRWWrapper) CPPFillRecursiveChildren(visitedNodes map[*TypeRWWrapper]bool) { if visitedNodes[w] { return @@ -731,7 +749,8 @@ outer: } type TypeRWPHPData interface { - PhpName() string + PhpClassName(withPath bool) string + PhpTypeName(withPath bool) string } // TODO remove skipAlias after we start generating go code like we do for C++ diff --git a/internal/tlcodegen/type_rw_bool.go b/internal/tlcodegen/type_rw_bool.go index 9d9b5a7..ca4aca3 100644 --- a/internal/tlcodegen/type_rw_bool.go +++ b/internal/tlcodegen/type_rw_bool.go @@ -110,6 +110,10 @@ func (trw *TypeRWBool) typeJSON2ReadingCode(bytesVersion bool, directImports *Di return wrapLast(false, fmt.Sprintf("%sJson2ReadBool(%s, %s)", trw.wr.gen.InternalPrefix(), jvalue, addAmpersand(ref, val))) } -func (trw *TypeRWBool) PhpName() string { +func (trw *TypeRWBool) PhpClassName(withPath bool) string { return "boolean" } + +func (trw *TypeRWBool) PhpTypeName(withPath bool) string { + return trw.PhpClassName(withPath) +} diff --git a/internal/tlcodegen/type_rw_maybe.go b/internal/tlcodegen/type_rw_maybe.go index 98e2ea8..009cb27 100644 --- a/internal/tlcodegen/type_rw_maybe.go +++ b/internal/tlcodegen/type_rw_maybe.go @@ -119,9 +119,14 @@ func (trw *TypeRWMaybe) typeJSON2ReadingCode(bytesVersion bool, directImports *D return fmt.Sprintf("if err := %s.ReadJSON(legacyTypeNames, %s %s); err != nil { return err }", val, jvalue, joinWithCommas(natArgs)) } -func (trw *TypeRWMaybe) PhpName() string { +func (trw *TypeRWMaybe) PhpClassName(withPath bool) string { target := trw.getInnerTarget() - return "maybe_" + target.trw.PhpName() + return "maybe_" + target.trw.PhpClassName(withPath) +} + +func (trw *TypeRWMaybe) PhpTypeName(withPath bool) string { + target := trw.getInnerTarget() + return target.trw.PhpTypeName(withPath) + "|null" } func (trw *TypeRWMaybe) getInnerTarget() *TypeRWWrapper { diff --git a/internal/tlcodegen/type_rw_primitive.go b/internal/tlcodegen/type_rw_primitive.go index 821b476..571afaf 100644 --- a/internal/tlcodegen/type_rw_primitive.go +++ b/internal/tlcodegen/type_rw_primitive.go @@ -171,8 +171,7 @@ func (trw *TypeRWPrimitive) GenerateCode(byteVersion bool, directImports *Direct return "" } -// TODO -func (trw *TypeRWPrimitive) PhpName() string { +func (trw *TypeRWPrimitive) PhpClassName(withPath bool) string { switch trw.goType { case "int32", "int64", "uint32": return "int" @@ -184,3 +183,7 @@ func (trw *TypeRWPrimitive) PhpName() string { return fmt.Sprintf("", trw.tlType) } } + +func (trw *TypeRWPrimitive) PhpTypeName(withPath bool) string { + return trw.PhpClassName(withPath) +} diff --git a/internal/tlcodegen/type_rw_struct.go b/internal/tlcodegen/type_rw_struct.go index a733f68..febe441 100644 --- a/internal/tlcodegen/type_rw_struct.go +++ b/internal/tlcodegen/type_rw_struct.go @@ -566,14 +566,14 @@ func (trw *TypeRWStruct) typeJSON2ReadingCode(bytesVersion bool, directImports * return fmt.Sprintf("if err := %s.ReadJSON(legacyTypeNames, %s %s); err != nil { return err }", val, jvalue, joinWithCommas(natArgs)) } -func (trw *TypeRWStruct) PhpName() string { - if len(trw.Fields) == 1 { - return trw.Fields[0].t.trw.PhpName() +func (trw *TypeRWStruct) PhpClassName(withPath bool) string { + if len(trw.Fields) == 1 && trw.ResultType == nil && trw.wr.unionParent == nil { + return trw.Fields[0].t.trw.PhpClassName(withPath) } isDict, _, _, valueType := isDictionaryElement(trw.wr) if isDict { - return valueType.t.trw.PhpName() + return valueType.t.trw.PhpClassName(withPath) } name := trw.wr.tlName.Name @@ -584,15 +584,20 @@ func (trw *TypeRWStruct) PhpName() string { elems := make([]string, 0, len(trw.wr.arguments)) for _, arg := range trw.wr.arguments { if arg.tip != nil { - elems = append(elems, arg.tip.trw.PhpName()) + elems = append(elems, "__", arg.tip.trw.PhpClassName(false)) } } - args := strings.Join(elems, "__") - if len(args) > 0 { - name += "__" - name += args + name += strings.Join(elems, "") + if withPath { + name = trw.wr.PHPTypePath() + name } - return name } + +func (trw *TypeRWStruct) PhpTypeName(withPath bool) string { + if len(trw.Fields) == 1 && trw.ResultType == nil && trw.wr.unionParent == nil { + return trw.Fields[0].t.trw.PhpTypeName(withPath) + } + return trw.PhpClassName(withPath) +} diff --git a/internal/tlcodegen/type_rw_tuple.go b/internal/tlcodegen/type_rw_tuple.go index 8bd2880..cd4f8da 100644 --- a/internal/tlcodegen/type_rw_tuple.go +++ b/internal/tlcodegen/type_rw_tuple.go @@ -211,10 +211,22 @@ func (trw *TypeRWBrackets) typeJSON2ReadingCode(bytesVersion bool, directImports return fmt.Sprintf("if err := %sReadJSON(legacyTypeNames, %s, %s%s); err != nil { return err }", trw.wr.ins.Prefix(directImports, ins)+goGlobalName, jvalue, addAmpersand(ref, val), joinWithCommas(natArgs)) } -func (trw *TypeRWBrackets) PhpName() string { +func (trw *TypeRWBrackets) PhpClassName(withPath bool) string { if strings.HasPrefix(trw.wr.tlName.String(), BuiltinTupleName) || strings.HasPrefix(trw.wr.tlName.String(), BuiltinVectorName) { - return "array_" + trw.element.t.trw.PhpName() + return "array_" + trw.element.t.trw.PhpClassName(false) + } + return fmt.Sprintf("", trw.wr.goGlobalName) +} + +func (trw *TypeRWBrackets) PhpTypeName(withPath bool) string { + if strings.HasPrefix(trw.wr.tlName.String(), BuiltinTupleName) || + strings.HasPrefix(trw.wr.tlName.String(), BuiltinVectorName) { + elementText := trw.element.t.trw.PhpTypeName(withPath) + if _, ok := trw.element.t.trw.(*TypeRWMaybe); ok { + elementText = "(" + elementText + ")" + } + return elementText + "[]" } return fmt.Sprintf("", trw.wr.goGlobalName) } diff --git a/internal/tlcodegen/type_rw_union.go b/internal/tlcodegen/type_rw_union.go index 110b482..e1552be 100644 --- a/internal/tlcodegen/type_rw_union.go +++ b/internal/tlcodegen/type_rw_union.go @@ -190,18 +190,26 @@ func (trw *TypeRWUnion) HasShortFieldCollision(wr *TypeRWWrapper) bool { return false } -func (trw *TypeRWUnion) PhpName() string { +func (trw *TypeRWUnion) PhpClassName(withPath bool) string { name := trw.wr.tlName.Name + if len(trw.wr.tlName.Namespace) != 0 { + name = fmt.Sprintf("%s_%s", trw.wr.tlName.Namespace, name) + } elems := make([]string, 0, len(trw.wr.arguments)) for _, arg := range trw.wr.arguments { if arg.tip != nil { - elems = append(elems, "__", arg.tip.trw.PhpName()) + elems = append(elems, "__", arg.tip.trw.PhpClassName(false)) } } - args := strings.Join(elems, "") - name += args - + name += strings.Join(elems, "") + if withPath { + name = trw.wr.PHPTypePath() + name + } return name } + +func (trw *TypeRWUnion) PhpTypeName(withPath bool) string { + return trw.PhpClassName(withPath) +} From a77527d7c2f61e448e1daf6d9afa4d2604d0c0c7 Mon Sep 17 00:00:00 2001 From: Fedor Vikhnin Date: Tue, 10 Dec 2024 23:31:27 +0300 Subject: [PATCH 07/26] add non function struct body --- internal/tlcodegen/tlgen.go | 9 ++ internal/tlcodegen/tlgen_php.go | 34 ++++- internal/tlcodegen/type_rw.go | 53 ++++++- internal/tlcodegen/type_rw_bool.go | 9 ++ internal/tlcodegen/type_rw_maybe.go | 9 ++ internal/tlcodegen/type_rw_primitive.go | 18 +++ internal/tlcodegen/type_rw_struct.go | 190 ++++++++++++++++++++++++ internal/tlcodegen/type_rw_tuple.go | 8 + internal/tlcodegen/type_rw_union.go | 8 + 9 files changed, 327 insertions(+), 11 deletions(-) diff --git a/internal/tlcodegen/tlgen.go b/internal/tlcodegen/tlgen.go index 635400a..f697be7 100644 --- a/internal/tlcodegen/tlgen.go +++ b/internal/tlcodegen/tlgen.go @@ -1217,6 +1217,15 @@ func GenerateCode(tl tlast.TL, options Gen2Options) (*Gen2, error) { return nil, err } case "php": + if gen.copyrightText == "" { + gen.copyrightText = ` +/** + * AUTOGENERATED, DO NOT EDIT! If you want to modify it, check tl schema. + * + * This autogenerated code represents tl class for typed RPC API. + */ +` + } if err := gen.generateCodePHP(generateByteVersions); err != nil { return nil, err } diff --git a/internal/tlcodegen/tlgen_php.go b/internal/tlcodegen/tlgen_php.go index 23c56e5..c6c660d 100644 --- a/internal/tlcodegen/tlgen_php.go +++ b/internal/tlcodegen/tlgen_php.go @@ -2,6 +2,7 @@ package tlcodegen import ( "fmt" + "path/filepath" "reflect" "strings" ) @@ -26,14 +27,29 @@ func (gen *Gen2) generateCodePHP(generateByteVersions []string) error { // select files where to write code gen.PhpChoosePaths() + createdTypes := make(map[string]bool) + for _, wrapper := range gen.generatedTypesList { + if wrapper.PHPTypePath() == "" { + continue + } + if wrapper.PHPIsPrimitiveType() { + continue + } + if createdTypes[wrapper.trw.PhpClassName(true)] { + continue + } var code strings.Builder - // add + // add start symbol code.WriteString(PHPFileStart) + code.WriteString("\n") // add copyright text code.WriteString(gen.copyrightText) + code.WriteString(fmt.Sprintf("namespace VK\\%s;\n", strings.Join(wrapper.PHPTypePathElements(), "\\"))) - wrapper.PHPGenerateCode(&code, true) + if err := wrapper.PHPGenerateCode(&code, true); err != nil { + return err + } fmt.Printf("TL[%[1]s] = Go {%[2]s, %[4]s} -> PHP {%[3]s, %[5]s}\n", wrapper.tlName.String(), @@ -43,10 +59,16 @@ func (gen *Gen2) generateCodePHP(generateByteVersions []string) error { wrapper.trw.PhpTypeName(true), ) - //filepathName := wrapper.phpInfo.FileName - //if err := gen.addCodeFile(filepathName, code.String()); err != nil { - // return err - //} + fmt.Printf("Core[%s] = %s, %s\n", wrapper.goGlobalName, wrapper.PHPGenCoreType().goGlobalName, reflect.TypeOf(wrapper.PHPGenCoreType().trw)) + + filepathParts := []string{"VK"} + filepathParts = append(filepathParts, wrapper.PHPTypePathElements()...) + filepathParts = append(filepathParts, fmt.Sprintf("%s.php", wrapper.trw.PhpClassName(false))) + filepathName := filepath.Join(filepathParts...) + if err := gen.addCodeFile(filepathName, code.String()); err != nil { + return err + } + createdTypes[wrapper.trw.PhpClassName(true)] = true } return nil } diff --git a/internal/tlcodegen/type_rw.go b/internal/tlcodegen/type_rw.go index 5fa21c8..067a80e 100644 --- a/internal/tlcodegen/type_rw.go +++ b/internal/tlcodegen/type_rw.go @@ -490,15 +490,15 @@ func (w *TypeRWWrapper) IsTrueType() bool { return len(structElement.Fields) == 0 } -func (w *TypeRWWrapper) PHPGenerateCode(code *strings.Builder, bytes bool) { - +func (w *TypeRWWrapper) PHPGenerateCode(code *strings.Builder, bytes bool) error { + return w.trw.PhpGenerateCode(code, bytes) } -func (w *TypeRWWrapper) PHPTypePath() string { +func (w *TypeRWWrapper) PHPTypePathElements() []string { _, isStruct := w.trw.(*TypeRWStruct) _, isUnion := w.trw.(*TypeRWUnion) if !(isStruct || isUnion) { - return "" + return nil } category := "Types" @@ -509,7 +509,48 @@ func (w *TypeRWWrapper) PHPTypePath() string { if w.tlName.Namespace != "" { group = w.tlName.Namespace } - return fmt.Sprintf("TL\\%[1]s\\%[2]s\\", group, category) + return []string{"TL", group, category} +} + +func (w *TypeRWWrapper) PHPDefaultValue() string { + core := w.PHPGenCoreType() + return core.trw.PhpDefaultValue() +} + +func (w *TypeRWWrapper) PHPTypePath() string { + path := w.PHPTypePathElements() + if path == nil { + return "" + } else { + return strings.Join(path, "\\") + "\\" + } +} + +func (w *TypeRWWrapper) PHPGenCoreType() *TypeRWWrapper { + if w.unionParent == nil { + struct_, isStruct := w.trw.(*TypeRWStruct) + if isStruct && len(struct_.Fields) == 1 && struct_.ResultType == nil { + return struct_.Fields[0].t.PHPGenCoreType() + } + } + return w +} + +func (w *TypeRWWrapper) PHPIsPrimitiveType() bool { + core := w.PHPGenCoreType() + if _, isPrimitive := core.trw.(*TypeRWPrimitive); isPrimitive { + return true + } + if struct_, isStruct := core.trw.(*TypeRWStruct); isStruct { + isDict, _, _, valueType := isDictionaryElement(struct_.wr) + if isDict { + return valueType.t.PHPIsPrimitiveType() + } + } + if _, isBrackets := core.trw.(*TypeRWBrackets); isBrackets { + return true + } + return false } func (w *TypeRWWrapper) CPPFillRecursiveChildren(visitedNodes map[*TypeRWWrapper]bool) { @@ -751,6 +792,8 @@ outer: type TypeRWPHPData interface { PhpClassName(withPath bool) string PhpTypeName(withPath bool) string + PhpGenerateCode(code *strings.Builder, bytes bool) error + PhpDefaultValue() string } // TODO remove skipAlias after we start generating go code like we do for C++ diff --git a/internal/tlcodegen/type_rw_bool.go b/internal/tlcodegen/type_rw_bool.go index ca4aca3..9e5a476 100644 --- a/internal/tlcodegen/type_rw_bool.go +++ b/internal/tlcodegen/type_rw_bool.go @@ -8,6 +8,7 @@ package tlcodegen import ( "fmt" + "strings" ) type TypeRWBool struct { @@ -117,3 +118,11 @@ func (trw *TypeRWBool) PhpClassName(withPath bool) string { func (trw *TypeRWBool) PhpTypeName(withPath bool) string { return trw.PhpClassName(withPath) } + +func (trw *TypeRWBool) PhpGenerateCode(code *strings.Builder, bytes bool) error { + return fmt.Errorf("boolean doesn't have php code") +} + +func (trw *TypeRWBool) PhpDefaultValue() string { + return "false" +} diff --git a/internal/tlcodegen/type_rw_maybe.go b/internal/tlcodegen/type_rw_maybe.go index 009cb27..aa740e5 100644 --- a/internal/tlcodegen/type_rw_maybe.go +++ b/internal/tlcodegen/type_rw_maybe.go @@ -8,6 +8,7 @@ package tlcodegen import ( "fmt" + "strings" ) type TypeRWMaybe struct { @@ -136,3 +137,11 @@ func (trw *TypeRWMaybe) getInnerTarget() *TypeRWWrapper { return trw.element.t } } + +func (trw *TypeRWMaybe) PhpGenerateCode(code *strings.Builder, bytes bool) error { + return fmt.Errorf("maybe doesn't have php code") +} + +func (trw *TypeRWMaybe) PhpDefaultValue() string { + return "null" +} diff --git a/internal/tlcodegen/type_rw_primitive.go b/internal/tlcodegen/type_rw_primitive.go index 571afaf..3cd1969 100644 --- a/internal/tlcodegen/type_rw_primitive.go +++ b/internal/tlcodegen/type_rw_primitive.go @@ -9,6 +9,7 @@ package tlcodegen import ( "fmt" "log" + "strings" ) type TypeRWPrimitive struct { @@ -187,3 +188,20 @@ func (trw *TypeRWPrimitive) PhpClassName(withPath bool) string { func (trw *TypeRWPrimitive) PhpTypeName(withPath bool) string { return trw.PhpClassName(withPath) } + +func (trw *TypeRWPrimitive) PhpGenerateCode(code *strings.Builder, bytes bool) error { + return fmt.Errorf("primitives don't have php code") +} + +func (trw *TypeRWPrimitive) PhpDefaultValue() string { + switch trw.goType { + case "int32", "int64", "uint32": + return "0" + case "string": + return "\"\"" + case "float32", "float64": + return "0" + default: + return fmt.Sprintf("", trw.tlType) + } +} diff --git a/internal/tlcodegen/type_rw_struct.go b/internal/tlcodegen/type_rw_struct.go index febe441..f9c7083 100644 --- a/internal/tlcodegen/type_rw_struct.go +++ b/internal/tlcodegen/type_rw_struct.go @@ -601,3 +601,193 @@ func (trw *TypeRWStruct) PhpTypeName(withPath bool) string { } return trw.PhpClassName(withPath) } + +func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) error { + code.WriteString(`use VK\TL; + +/** + * @kphp-tl-class + */ +`) + code.WriteString(fmt.Sprintf("class %s ", trw.PhpClassName(false))) + if trw.wr.unionParent != nil { + code.WriteString(fmt.Sprintf("implements %s ", trw.wr.unionParent.PhpClassName(true))) + } + code.WriteString("{\n") + // print fieldmasks + for _, f := range trw.Fields { + if f.fieldMask == nil { + continue + } + code.WriteString( + fmt.Sprintf( + ` + /** Field mask for %[1]s field */ + const BIT_%[2]s_%[3]d = (1 << %[3]d); +`, + f.originalName, + strings.ToUpper(f.originalName), + f.BitNumber, + ), + ) + } + // print fields declarations + for _, f := range trw.Fields { + fieldType, defaultValue := fieldTypeAndDefaultValue(f) + code.WriteString( + fmt.Sprintf( + ` + /** @var %[1]s */ + public $%[2]s = %[3]s; +`, + fieldType, + f.originalName, + defaultValue, + ), + ) + } + // print constructor + necessaryFieldsInConstructor := make([]Field, 0) + usedFieldMasksIndecies := make([]int, 0) + usedFieldMasks := make(map[int][]Field) + for _, f := range trw.Fields { + if f.fieldMask == nil { + necessaryFieldsInConstructor = append(necessaryFieldsInConstructor, f) + } else { + index := f.fieldMask.FieldIndex + if !f.fieldMask.isField { + for i, argument := range trw.wr.NatParams { + if argument == f.fieldMask.name { + index = -(i + 1) + break + } + } + } + if usedFieldMasks[index] == nil { + usedFieldMasksIndecies = append(usedFieldMasksIndecies, index) + } + usedFieldMasks[index] = append(usedFieldMasks[index], f) + } + } + + code.WriteString(` + /** +`) + for _, f := range necessaryFieldsInConstructor { + fieldType, _ := fieldTypeAndDefaultValue(f) + code.WriteString(fmt.Sprintf(" * @param %[1]s $%[2]s\n", fieldType, f.originalName)) + } + + code.WriteString(` */ +`) + code.WriteString(" public function __construct(") + + for i, f := range necessaryFieldsInConstructor { + _, defaultValue := fieldTypeAndDefaultValue(f) + if i != 0 { + code.WriteString(", ") + } + code.WriteString(fmt.Sprintf("$%[1]s = %[2]s", f.originalName, defaultValue)) + } + + code.WriteString(") {\n") + for _, f := range necessaryFieldsInConstructor { + code.WriteString(fmt.Sprintf(" $this->$%[1]s = $%[1]s;\n", f.originalName)) + } + code.WriteString(" }\n") + + sort.Ints(usedFieldMasksIndecies) + for _, natIndex := range usedFieldMasksIndecies { + natName := "" + if natIndex < 0 { + natName = trw.wr.NatParams[-(natIndex + 1)] + } else { + natName = trw.Fields[natIndex].originalName + } + code.WriteString(` + /**`) + additionalArgs := make([]string, 0) + // arguments with ambiguous existence + for _, dependentField := range usedFieldMasks[natIndex] { + if _, isMaybe := dependentField.t.PHPGenCoreType().trw.(*TypeRWMaybe); isMaybe { + additionalArgs = append(additionalArgs, fmt.Sprintf("$has_%s", dependentField.originalName)) + code.WriteString(fmt.Sprintf("\n * @param bool $has_%s", dependentField.originalName)) + } + } + code.WriteString(` + * @return int + */ +`, + ) + code.WriteString( + fmt.Sprintf( + " public function calculate%[1]s(%[2]s) {\n $mask = 0;\n", + ToUpperFirst(natName), + strings.Join(additionalArgs, ", "), + ), + ) + + for _, dependentField := range usedFieldMasks[natIndex] { + condition := "" + if dependentField.t.IsTrueType() { + condition = fmt.Sprintf( + "$this->%[1]s", + dependentField.originalName, + ) + } else if _, isMaybe := dependentField.t.PHPGenCoreType().trw.(*TypeRWMaybe); isMaybe { + condition = fmt.Sprintf("$has_%s", dependentField.originalName) + } else { + condition = fmt.Sprintf( + "$this->%[1]s !== null", + dependentField.originalName, + ) + } + code.WriteString( + fmt.Sprintf( + ` + if (%[1]s) { + $mask |= BIT_%[2]s_%[3]d; + } +`, + condition, + strings.ToUpper(dependentField.originalName), + dependentField.BitNumber, + ), + ) + } + + code.WriteString(" return $mask;\n") + code.WriteString(" }\n") + } + + code.WriteString("\n}") + return nil +} + +func fieldTypeAndDefaultValue(f Field) (string, string) { + fieldType := f.t.trw.PhpTypeName(true) + defaultValue := f.t.trw.PhpDefaultValue() + if f.t.IsTrueType() { + fieldType = "boolean" + defaultValue = "true" + if f.fieldMask != nil { + defaultValue = "false" + } + } else { + if f.fieldMask != nil { + defaultValue = "null" + if _, isMaybe := f.t.PHPGenCoreType().trw.(*TypeRWMaybe); !isMaybe { + fieldType = fieldType + "|null" + } + } + } + return fieldType, defaultValue +} + +func (trw *TypeRWStruct) PhpDefaultValue() string { + core := trw.wr.PHPGenCoreType() + if core != trw.wr { + return core.PHPDefaultValue() + } + return "null" +} diff --git a/internal/tlcodegen/type_rw_tuple.go b/internal/tlcodegen/type_rw_tuple.go index cd4f8da..8a6bdab 100644 --- a/internal/tlcodegen/type_rw_tuple.go +++ b/internal/tlcodegen/type_rw_tuple.go @@ -230,3 +230,11 @@ func (trw *TypeRWBrackets) PhpTypeName(withPath bool) string { } return fmt.Sprintf("", trw.wr.goGlobalName) } + +func (trw *TypeRWBrackets) PhpGenerateCode(code *strings.Builder, bytes bool) error { + return fmt.Errorf("tuples don't have php code") +} + +func (trw *TypeRWBrackets) PhpDefaultValue() string { + return "[]" +} diff --git a/internal/tlcodegen/type_rw_union.go b/internal/tlcodegen/type_rw_union.go index e1552be..9903a10 100644 --- a/internal/tlcodegen/type_rw_union.go +++ b/internal/tlcodegen/type_rw_union.go @@ -213,3 +213,11 @@ func (trw *TypeRWUnion) PhpClassName(withPath bool) string { func (trw *TypeRWUnion) PhpTypeName(withPath bool) string { return trw.PhpClassName(withPath) } + +func (trw *TypeRWUnion) PhpGenerateCode(code *strings.Builder, bytes bool) error { + return nil +} + +func (trw *TypeRWUnion) PhpDefaultValue() string { + return "null" +} From e71c8f66211b1848299a3bc832b52bdd6fc7efb4 Mon Sep 17 00:00:00 2001 From: Fedor Vikhnin Date: Tue, 10 Dec 2024 23:55:38 +0300 Subject: [PATCH 08/26] add non function union body --- internal/tlcodegen/tlgen.go | 7 ++++--- internal/tlcodegen/type_rw_struct.go | 18 +++++++++++++++--- internal/tlcodegen/type_rw_union.go | 24 ++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/internal/tlcodegen/tlgen.go b/internal/tlcodegen/tlgen.go index f697be7..4c4ace0 100644 --- a/internal/tlcodegen/tlgen.go +++ b/internal/tlcodegen/tlgen.go @@ -1217,13 +1217,14 @@ func GenerateCode(tl tlast.TL, options Gen2Options) (*Gen2, error) { return nil, err } case "php": - if gen.copyrightText == "" { - gen.copyrightText = ` -/** + { + // TODO ADD FEATURE TO CHANGE IT + gen.copyrightText = `/** * AUTOGENERATED, DO NOT EDIT! If you want to modify it, check tl schema. * * This autogenerated code represents tl class for typed RPC API. */ + ` } if err := gen.generateCodePHP(generateByteVersions); err != nil { diff --git a/internal/tlcodegen/type_rw_struct.go b/internal/tlcodegen/type_rw_struct.go index f9c7083..67a98e2 100644 --- a/internal/tlcodegen/type_rw_struct.go +++ b/internal/tlcodegen/type_rw_struct.go @@ -603,8 +603,10 @@ func (trw *TypeRWStruct) PhpTypeName(withPath bool) string { } func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) error { - code.WriteString(`use VK\TL; - + if isUsingTLImport(trw) { + code.WriteString("\nuse VK\\TL;\n") + } + code.WriteString(` /** * @kphp-tl-class */ @@ -692,7 +694,7 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro code.WriteString(") {\n") for _, f := range necessaryFieldsInConstructor { - code.WriteString(fmt.Sprintf(" $this->$%[1]s = $%[1]s;\n", f.originalName)) + code.WriteString(fmt.Sprintf(" $this->%[1]s = $%[1]s;\n", f.originalName)) } code.WriteString(" }\n") @@ -764,6 +766,16 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro return nil } +func isUsingTLImport(trw *TypeRWStruct) bool { + for _, field := range trw.Fields { + fieldType, _ := fieldTypeAndDefaultValue(field) + if strings.Contains(fieldType, "TL\\") { + return true + } + } + return false +} + func fieldTypeAndDefaultValue(f Field) (string, string) { fieldType := f.t.trw.PhpTypeName(true) defaultValue := f.t.trw.PhpDefaultValue() diff --git a/internal/tlcodegen/type_rw_union.go b/internal/tlcodegen/type_rw_union.go index 9903a10..a67cfe7 100644 --- a/internal/tlcodegen/type_rw_union.go +++ b/internal/tlcodegen/type_rw_union.go @@ -215,6 +215,30 @@ func (trw *TypeRWUnion) PhpTypeName(withPath bool) string { } func (trw *TypeRWUnion) PhpGenerateCode(code *strings.Builder, bytes bool) error { + classes := make([]string, len(trw.Fields)) + for i, field := range trw.Fields { + classes[i] = fmt.Sprintf("%s::class", field.t.trw.PhpClassName(true)) + } + + code.WriteString(`use VK\TL; + +/** + * @kphp-tl-class + */ +`) + code.WriteString(fmt.Sprintf( + `interface %[1]s { + + /** Allows kphp implicitly load all available constructors */ + const CONSTRUCTORS = [ + %[2]s + ]; + +} +`, + trw.PhpClassName(false), + strings.Join(classes, ",\n "), + )) return nil } From b2f099a35cd38884ff5c1633d5494c130d498a01 Mon Sep 17 00:00:00 2001 From: Fedor Vikhnin Date: Wed, 11 Dec 2024 00:39:35 +0300 Subject: [PATCH 09/26] zero args constructor + skip internal methods --- internal/tlcodegen/tlgen_php.go | 3 +++ internal/tlcodegen/type_rw_struct.go | 3 +++ 2 files changed, 6 insertions(+) diff --git a/internal/tlcodegen/tlgen_php.go b/internal/tlcodegen/tlgen_php.go index c6c660d..adb04a2 100644 --- a/internal/tlcodegen/tlgen_php.go +++ b/internal/tlcodegen/tlgen_php.go @@ -39,6 +39,9 @@ func (gen *Gen2) generateCodePHP(generateByteVersions []string) error { if createdTypes[wrapper.trw.PhpClassName(true)] { continue } + if strct, isStrct := wrapper.trw.(*TypeRWStruct); isStrct && strct.ResultType != nil && strct.wr.HasAnnotation("internal") { + continue + } var code strings.Builder // add start symbol code.WriteString(PHPFileStart) diff --git a/internal/tlcodegen/type_rw_struct.go b/internal/tlcodegen/type_rw_struct.go index 67a98e2..f8ad251 100644 --- a/internal/tlcodegen/type_rw_struct.go +++ b/internal/tlcodegen/type_rw_struct.go @@ -679,6 +679,9 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro fieldType, _ := fieldTypeAndDefaultValue(f) code.WriteString(fmt.Sprintf(" * @param %[1]s $%[2]s\n", fieldType, f.originalName)) } + if len(necessaryFieldsInConstructor) == 0 { + code.WriteString(" * @kphp-inline\n") + } code.WriteString(` */ `) From e0bc3f6ed00f97695cb941cef437156cbf31c178 Mon Sep 17 00:00:00 2001 From: Fedor Vikhnin Date: Wed, 11 Dec 2024 11:38:15 +0300 Subject: [PATCH 10/26] php function bodies and smth else --- internal/tlcodegen/tlgen_php.go | 19 +++--- internal/tlcodegen/type_rw_primitive.go | 2 +- internal/tlcodegen/type_rw_struct.go | 83 ++++++++++++++++++++++++- 3 files changed, 92 insertions(+), 12 deletions(-) diff --git a/internal/tlcodegen/tlgen_php.go b/internal/tlcodegen/tlgen_php.go index adb04a2..c975b29 100644 --- a/internal/tlcodegen/tlgen_php.go +++ b/internal/tlcodegen/tlgen_php.go @@ -30,17 +30,18 @@ func (gen *Gen2) generateCodePHP(generateByteVersions []string) error { createdTypes := make(map[string]bool) for _, wrapper := range gen.generatedTypesList { - if wrapper.PHPTypePath() == "" { + if wrapper.PHPTypePath() == "" || + wrapper.PHPIsPrimitiveType() || + createdTypes[wrapper.trw.PhpClassName(true)] { continue } - if wrapper.PHPIsPrimitiveType() { - continue - } - if createdTypes[wrapper.trw.PhpClassName(true)] { - continue - } - if strct, isStrct := wrapper.trw.(*TypeRWStruct); isStrct && strct.ResultType != nil && strct.wr.HasAnnotation("internal") { - continue + if strct, isStrct := wrapper.trw.(*TypeRWStruct); isStrct { + if strct.ResultType == nil && strct.wr.IsTrueType() { + continue + } + if strct.ResultType != nil && strct.wr.HasAnnotation("internal") { + continue + } } var code strings.Builder // add start symbol diff --git a/internal/tlcodegen/type_rw_primitive.go b/internal/tlcodegen/type_rw_primitive.go index 3cd1969..e4e2608 100644 --- a/internal/tlcodegen/type_rw_primitive.go +++ b/internal/tlcodegen/type_rw_primitive.go @@ -198,7 +198,7 @@ func (trw *TypeRWPrimitive) PhpDefaultValue() string { case "int32", "int64", "uint32": return "0" case "string": - return "\"\"" + return "''" case "float32", "float64": return "0" default: diff --git a/internal/tlcodegen/type_rw_struct.go b/internal/tlcodegen/type_rw_struct.go index f8ad251..bb78b1c 100644 --- a/internal/tlcodegen/type_rw_struct.go +++ b/internal/tlcodegen/type_rw_struct.go @@ -603,7 +603,7 @@ func (trw *TypeRWStruct) PhpTypeName(withPath bool) string { } func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) error { - if isUsingTLImport(trw) { + if isUsingTLImport(trw) || trw.ResultType != nil { code.WriteString("\nuse VK\\TL;\n") } code.WriteString(` @@ -615,6 +615,9 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro if trw.wr.unionParent != nil { code.WriteString(fmt.Sprintf("implements %s ", trw.wr.unionParent.PhpClassName(true))) } + if trw.ResultType != nil { + code.WriteString(fmt.Sprintf("implements TL\\RpcFunction")) + } code.WriteString("{\n") // print fieldmasks for _, f := range trw.Fields { @@ -671,7 +674,19 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro usedFieldMasks[index] = append(usedFieldMasks[index], f) } } - + // print result type for function + if trw.ResultType != nil { + code.WriteString( + fmt.Sprintf( + ` + /** Allows kphp implicitly load function result class */ + private const RESULT = %s_result::class; +`, + trw.PhpClassName(true), + ), + ) + } + // print constructor code.WriteString(` /** `) @@ -765,7 +780,71 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro code.WriteString(" }\n") } + if trw.ResultType != nil { + code.WriteString( + fmt.Sprintf( + ` + /** + * @param TL\RpcFunctionReturnResult $function_return_result + * @return %[4]s + */ + public static function functionReturnValue($function_return_result) { + if ($function_return_result instanceof %[1]s_result) { + return $function_return_result->value; + } + warning('Unexpected result type in functionReturnValue: ' . ($function_return_result ? get_class($function_return_result) : 'null')); + return (new %[1]s_result())->value; + } + + /** + * @kphp-inline + * + * @param TL\RpcResponse $response + * @return %[4]s + */ + public static function result(TL\RpcResponse $response) { + return self::functionReturnValue($response->getResult()); + } + + /** + * @kphp-inline + * + * @return string + */ + public function getTLFunctionName() { + return '%[3]s'; + } +`, + trw.PhpClassName(false), + trw.PhpClassName(true), + trw.wr.tlName.String(), + trw.ResultType.trw.PhpTypeName(true), + ), + ) + } + code.WriteString("\n}") + + if trw.ResultType != nil { + code.WriteString( + fmt.Sprintf( + ` + +/** + * @kphp-tl-class + */ +class %[1]s_result implements TL\RpcFunctionReturnResult { + + /** @var %[2]s */ + public $value = %[3]s; + +}`, + trw.PhpClassName(false), + trw.ResultType.trw.PhpClassName(true), + trw.ResultType.trw.PhpDefaultValue(), + ), + ) + } return nil } From 40b2df86c2f6b410db21ffd965a3f5d728b5243d Mon Sep 17 00:00:00 2001 From: Fedor Vikhnin Date: Thu, 12 Dec 2024 01:20:52 +0300 Subject: [PATCH 11/26] add small fixes --- internal/tlcodegen/tlgen_php.go | 10 ++-- internal/tlcodegen/type_rw.go | 2 +- internal/tlcodegen/type_rw_bool.go | 4 +- internal/tlcodegen/type_rw_maybe.go | 4 +- internal/tlcodegen/type_rw_primitive.go | 4 +- internal/tlcodegen/type_rw_struct.go | 67 +++++++++++++++++-------- internal/tlcodegen/type_rw_tuple.go | 4 +- internal/tlcodegen/type_rw_union.go | 15 +++--- 8 files changed, 68 insertions(+), 42 deletions(-) diff --git a/internal/tlcodegen/tlgen_php.go b/internal/tlcodegen/tlgen_php.go index c975b29..f454e29 100644 --- a/internal/tlcodegen/tlgen_php.go +++ b/internal/tlcodegen/tlgen_php.go @@ -32,11 +32,11 @@ func (gen *Gen2) generateCodePHP(generateByteVersions []string) error { for _, wrapper := range gen.generatedTypesList { if wrapper.PHPTypePath() == "" || wrapper.PHPIsPrimitiveType() || - createdTypes[wrapper.trw.PhpClassName(true)] { + createdTypes[wrapper.trw.PhpClassName(true, false)] { continue } if strct, isStrct := wrapper.trw.(*TypeRWStruct); isStrct { - if strct.ResultType == nil && strct.wr.IsTrueType() { + if strct.ResultType == nil && strct.wr.IsTrueType() && strct.wr.unionParent == nil { continue } if strct.ResultType != nil && strct.wr.HasAnnotation("internal") { @@ -58,7 +58,7 @@ func (gen *Gen2) generateCodePHP(generateByteVersions []string) error { fmt.Printf("TL[%[1]s] = Go {%[2]s, %[4]s} -> PHP {%[3]s, %[5]s}\n", wrapper.tlName.String(), wrapper.goGlobalName, - wrapper.trw.PhpClassName(true), + wrapper.trw.PhpClassName(true, false), reflect.TypeOf(wrapper.trw), wrapper.trw.PhpTypeName(true), ) @@ -67,12 +67,12 @@ func (gen *Gen2) generateCodePHP(generateByteVersions []string) error { filepathParts := []string{"VK"} filepathParts = append(filepathParts, wrapper.PHPTypePathElements()...) - filepathParts = append(filepathParts, fmt.Sprintf("%s.php", wrapper.trw.PhpClassName(false))) + filepathParts = append(filepathParts, fmt.Sprintf("%s.php", wrapper.trw.PhpClassName(false, false))) filepathName := filepath.Join(filepathParts...) if err := gen.addCodeFile(filepathName, code.String()); err != nil { return err } - createdTypes[wrapper.trw.PhpClassName(true)] = true + createdTypes[wrapper.trw.PhpClassName(true, false)] = true } return nil } diff --git a/internal/tlcodegen/type_rw.go b/internal/tlcodegen/type_rw.go index 067a80e..5a81415 100644 --- a/internal/tlcodegen/type_rw.go +++ b/internal/tlcodegen/type_rw.go @@ -790,7 +790,7 @@ outer: } type TypeRWPHPData interface { - PhpClassName(withPath bool) string + PhpClassName(withPath bool, bare bool) string PhpTypeName(withPath bool) string PhpGenerateCode(code *strings.Builder, bytes bool) error PhpDefaultValue() string diff --git a/internal/tlcodegen/type_rw_bool.go b/internal/tlcodegen/type_rw_bool.go index 9e5a476..85a9c36 100644 --- a/internal/tlcodegen/type_rw_bool.go +++ b/internal/tlcodegen/type_rw_bool.go @@ -111,12 +111,12 @@ func (trw *TypeRWBool) typeJSON2ReadingCode(bytesVersion bool, directImports *Di return wrapLast(false, fmt.Sprintf("%sJson2ReadBool(%s, %s)", trw.wr.gen.InternalPrefix(), jvalue, addAmpersand(ref, val))) } -func (trw *TypeRWBool) PhpClassName(withPath bool) string { +func (trw *TypeRWBool) PhpClassName(withPath bool, bare bool) string { return "boolean" } func (trw *TypeRWBool) PhpTypeName(withPath bool) string { - return trw.PhpClassName(withPath) + return trw.PhpClassName(withPath, true) } func (trw *TypeRWBool) PhpGenerateCode(code *strings.Builder, bytes bool) error { diff --git a/internal/tlcodegen/type_rw_maybe.go b/internal/tlcodegen/type_rw_maybe.go index aa740e5..9c42e5f 100644 --- a/internal/tlcodegen/type_rw_maybe.go +++ b/internal/tlcodegen/type_rw_maybe.go @@ -120,9 +120,9 @@ func (trw *TypeRWMaybe) typeJSON2ReadingCode(bytesVersion bool, directImports *D return fmt.Sprintf("if err := %s.ReadJSON(legacyTypeNames, %s %s); err != nil { return err }", val, jvalue, joinWithCommas(natArgs)) } -func (trw *TypeRWMaybe) PhpClassName(withPath bool) string { +func (trw *TypeRWMaybe) PhpClassName(withPath bool, bare bool) string { target := trw.getInnerTarget() - return "maybe_" + target.trw.PhpClassName(withPath) + return "maybe_" + target.trw.PhpClassName(withPath, trw.element.bare) } func (trw *TypeRWMaybe) PhpTypeName(withPath bool) string { diff --git a/internal/tlcodegen/type_rw_primitive.go b/internal/tlcodegen/type_rw_primitive.go index e4e2608..cf03c56 100644 --- a/internal/tlcodegen/type_rw_primitive.go +++ b/internal/tlcodegen/type_rw_primitive.go @@ -172,7 +172,7 @@ func (trw *TypeRWPrimitive) GenerateCode(byteVersion bool, directImports *Direct return "" } -func (trw *TypeRWPrimitive) PhpClassName(withPath bool) string { +func (trw *TypeRWPrimitive) PhpClassName(withPath bool, bare bool) string { switch trw.goType { case "int32", "int64", "uint32": return "int" @@ -186,7 +186,7 @@ func (trw *TypeRWPrimitive) PhpClassName(withPath bool) string { } func (trw *TypeRWPrimitive) PhpTypeName(withPath bool) string { - return trw.PhpClassName(withPath) + return trw.PhpClassName(withPath, false) } func (trw *TypeRWPrimitive) PhpGenerateCode(code *strings.Builder, bytes bool) error { diff --git a/internal/tlcodegen/type_rw_struct.go b/internal/tlcodegen/type_rw_struct.go index bb78b1c..00d5f72 100644 --- a/internal/tlcodegen/type_rw_struct.go +++ b/internal/tlcodegen/type_rw_struct.go @@ -566,17 +566,25 @@ func (trw *TypeRWStruct) typeJSON2ReadingCode(bytesVersion bool, directImports * return fmt.Sprintf("if err := %s.ReadJSON(legacyTypeNames, %s %s); err != nil { return err }", val, jvalue, joinWithCommas(natArgs)) } -func (trw *TypeRWStruct) PhpClassName(withPath bool) string { +func (trw *TypeRWStruct) PhpClassName(withPath bool, bare bool) string { if len(trw.Fields) == 1 && trw.ResultType == nil && trw.wr.unionParent == nil { - return trw.Fields[0].t.trw.PhpClassName(withPath) + return trw.Fields[0].t.trw.PhpClassName(withPath, bare) + } + + if trw.ResultType == nil && trw.wr.IsTrueType() && trw.wr.unionParent == nil { + return "boolean" } isDict, _, _, valueType := isDictionaryElement(trw.wr) if isDict { - return valueType.t.trw.PhpClassName(withPath) + return valueType.t.trw.PhpClassName(withPath, bare) } name := trw.wr.tlName.Name + if !bare { + //name = trw.wr.origTL[0].TypeDecl.Name.Name + print("debug") + } if len(trw.wr.tlName.Namespace) != 0 { name = fmt.Sprintf("%s_%s", trw.wr.tlName.Namespace, name) } @@ -584,7 +592,7 @@ func (trw *TypeRWStruct) PhpClassName(withPath bool) string { elems := make([]string, 0, len(trw.wr.arguments)) for _, arg := range trw.wr.arguments { if arg.tip != nil { - elems = append(elems, "__", arg.tip.trw.PhpClassName(false)) + elems = append(elems, "__", arg.tip.trw.PhpClassName(false, arg.bare)) } } @@ -599,11 +607,13 @@ func (trw *TypeRWStruct) PhpTypeName(withPath bool) string { if len(trw.Fields) == 1 && trw.ResultType == nil && trw.wr.unionParent == nil { return trw.Fields[0].t.trw.PhpTypeName(withPath) } - return trw.PhpClassName(withPath) + return trw.PhpClassName(withPath, true) } func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) error { - if isUsingTLImport(trw) || trw.ResultType != nil { + if isUsingTLImport(trw) || + trw.ResultType != nil || + trw.wr.unionParent != nil { code.WriteString("\nuse VK\\TL;\n") } code.WriteString(` @@ -611,12 +621,15 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro * @kphp-tl-class */ `) - code.WriteString(fmt.Sprintf("class %s ", trw.PhpClassName(false))) + if "right1__test_gigi" == trw.PhpClassName(false, true) { + print("debug") + } + code.WriteString(fmt.Sprintf("class %s ", trw.PhpClassName(false, true))) if trw.wr.unionParent != nil { - code.WriteString(fmt.Sprintf("implements %s ", trw.wr.unionParent.PhpClassName(true))) + code.WriteString(fmt.Sprintf("implements %s ", trw.wr.unionParent.PhpClassName(true, true))) } if trw.ResultType != nil { - code.WriteString(fmt.Sprintf("implements TL\\RpcFunction")) + code.WriteString(fmt.Sprintf("implements TL\\RpcFunction ")) } code.WriteString("{\n") // print fieldmasks @@ -627,7 +640,7 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro code.WriteString( fmt.Sprintf( ` - /** Field mask for %[1]s field */ + /** Field mask for $%[1]s field */ const BIT_%[2]s_%[3]d = (1 << %[3]d); `, f.originalName, @@ -682,7 +695,7 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro /** Allows kphp implicitly load function result class */ private const RESULT = %s_result::class; `, - trw.PhpClassName(true), + trw.PhpClassName(true, true), ), ) } @@ -747,7 +760,16 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro ), ) - for _, dependentField := range usedFieldMasks[natIndex] { + if trw.PhpClassName(false, true) == "test_namesCheck" { + print("debug") + } + + fields := usedFieldMasks[natIndex] + sort.Slice(fields, func(i, j int) bool { + return fields[i].BitNumber <= fields[j].BitNumber + }) + + for _, dependentField := range fields { condition := "" if dependentField.t.IsTrueType() { condition = fmt.Sprintf( @@ -766,7 +788,7 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro fmt.Sprintf( ` if (%[1]s) { - $mask |= BIT_%[2]s_%[3]d; + $mask |= self::BIT_%[2]s_%[3]d; } `, condition, @@ -776,7 +798,7 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro ) } - code.WriteString(" return $mask;\n") + code.WriteString("\n return $mask;\n") code.WriteString(" }\n") } @@ -815,21 +837,20 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro return '%[3]s'; } `, - trw.PhpClassName(false), - trw.PhpClassName(true), + trw.PhpClassName(false, true), + trw.PhpClassName(true, true), trw.wr.tlName.String(), trw.ResultType.trw.PhpTypeName(true), ), ) } - code.WriteString("\n}") + code.WriteString("\n}\n") if trw.ResultType != nil { code.WriteString( fmt.Sprintf( ` - /** * @kphp-tl-class */ @@ -838,9 +859,10 @@ class %[1]s_result implements TL\RpcFunctionReturnResult { /** @var %[2]s */ public $value = %[3]s; -}`, - trw.PhpClassName(false), - trw.ResultType.trw.PhpClassName(true), +} +`, + trw.PhpClassName(false, true), + trw.ResultType.trw.PhpTypeName(true), trw.ResultType.trw.PhpDefaultValue(), ), ) @@ -883,5 +905,8 @@ func (trw *TypeRWStruct) PhpDefaultValue() string { if core != trw.wr { return core.PHPDefaultValue() } + if core.IsTrueType() { + return "true" + } return "null" } diff --git a/internal/tlcodegen/type_rw_tuple.go b/internal/tlcodegen/type_rw_tuple.go index 8a6bdab..e00bcbb 100644 --- a/internal/tlcodegen/type_rw_tuple.go +++ b/internal/tlcodegen/type_rw_tuple.go @@ -211,10 +211,10 @@ func (trw *TypeRWBrackets) typeJSON2ReadingCode(bytesVersion bool, directImports return fmt.Sprintf("if err := %sReadJSON(legacyTypeNames, %s, %s%s); err != nil { return err }", trw.wr.ins.Prefix(directImports, ins)+goGlobalName, jvalue, addAmpersand(ref, val), joinWithCommas(natArgs)) } -func (trw *TypeRWBrackets) PhpClassName(withPath bool) string { +func (trw *TypeRWBrackets) PhpClassName(withPath bool, bare bool) string { if strings.HasPrefix(trw.wr.tlName.String(), BuiltinTupleName) || strings.HasPrefix(trw.wr.tlName.String(), BuiltinVectorName) { - return "array_" + trw.element.t.trw.PhpClassName(false) + return "array_" + trw.element.t.trw.PhpClassName(false, trw.element.bare) } return fmt.Sprintf("", trw.wr.goGlobalName) } diff --git a/internal/tlcodegen/type_rw_union.go b/internal/tlcodegen/type_rw_union.go index a67cfe7..73624b0 100644 --- a/internal/tlcodegen/type_rw_union.go +++ b/internal/tlcodegen/type_rw_union.go @@ -190,7 +190,7 @@ func (trw *TypeRWUnion) HasShortFieldCollision(wr *TypeRWWrapper) bool { return false } -func (trw *TypeRWUnion) PhpClassName(withPath bool) string { +func (trw *TypeRWUnion) PhpClassName(withPath bool, bare bool) string { name := trw.wr.tlName.Name if len(trw.wr.tlName.Namespace) != 0 { name = fmt.Sprintf("%s_%s", trw.wr.tlName.Namespace, name) @@ -199,7 +199,7 @@ func (trw *TypeRWUnion) PhpClassName(withPath bool) string { elems := make([]string, 0, len(trw.wr.arguments)) for _, arg := range trw.wr.arguments { if arg.tip != nil { - elems = append(elems, "__", arg.tip.trw.PhpClassName(false)) + elems = append(elems, "__", arg.tip.trw.PhpClassName(false, arg.bare)) } } @@ -211,16 +211,17 @@ func (trw *TypeRWUnion) PhpClassName(withPath bool) string { } func (trw *TypeRWUnion) PhpTypeName(withPath bool) string { - return trw.PhpClassName(withPath) + return trw.PhpClassName(withPath, false) } func (trw *TypeRWUnion) PhpGenerateCode(code *strings.Builder, bytes bool) error { classes := make([]string, len(trw.Fields)) for i, field := range trw.Fields { - classes[i] = fmt.Sprintf("%s::class", field.t.trw.PhpClassName(true)) + classes[i] = fmt.Sprintf("%s::class", field.t.trw.PhpClassName(true, false)) } - code.WriteString(`use VK\TL; + code.WriteString(` +use VK\TL; /** * @kphp-tl-class @@ -231,12 +232,12 @@ func (trw *TypeRWUnion) PhpGenerateCode(code *strings.Builder, bytes bool) error /** Allows kphp implicitly load all available constructors */ const CONSTRUCTORS = [ - %[2]s + %[2]s ]; } `, - trw.PhpClassName(false), + trw.PhpClassName(false, false), strings.Join(classes, ",\n "), )) return nil From f72ac0e8125dd5531fd196c1daa9efea024ab425 Mon Sep 17 00:00:00 2001 From: Fedor Vikhnin Date: Thu, 12 Dec 2024 02:21:07 +0300 Subject: [PATCH 12/26] mystery solved: type arguments are always boxed, types are bare --- internal/tlcodegen/tlgen_php.go | 10 +++++----- internal/tlcodegen/type_rw_struct.go | 4 ++-- internal/tlcodegen/type_rw_union.go | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/internal/tlcodegen/tlgen_php.go b/internal/tlcodegen/tlgen_php.go index f454e29..156227c 100644 --- a/internal/tlcodegen/tlgen_php.go +++ b/internal/tlcodegen/tlgen_php.go @@ -32,7 +32,7 @@ func (gen *Gen2) generateCodePHP(generateByteVersions []string) error { for _, wrapper := range gen.generatedTypesList { if wrapper.PHPTypePath() == "" || wrapper.PHPIsPrimitiveType() || - createdTypes[wrapper.trw.PhpClassName(true, false)] { + createdTypes[wrapper.trw.PhpClassName(true, true)] { continue } if strct, isStrct := wrapper.trw.(*TypeRWStruct); isStrct { @@ -58,21 +58,21 @@ func (gen *Gen2) generateCodePHP(generateByteVersions []string) error { fmt.Printf("TL[%[1]s] = Go {%[2]s, %[4]s} -> PHP {%[3]s, %[5]s}\n", wrapper.tlName.String(), wrapper.goGlobalName, - wrapper.trw.PhpClassName(true, false), + wrapper.trw.PhpClassName(true, true), reflect.TypeOf(wrapper.trw), wrapper.trw.PhpTypeName(true), ) - fmt.Printf("Core[%s] = %s, %s\n", wrapper.goGlobalName, wrapper.PHPGenCoreType().goGlobalName, reflect.TypeOf(wrapper.PHPGenCoreType().trw)) + //fmt.Printf("Core[%s] = %s, %s\n", wrapper.goGlobalName, wrapper.PHPGenCoreType().goGlobalName, reflect.TypeOf(wrapper.PHPGenCoreType().trw)) filepathParts := []string{"VK"} filepathParts = append(filepathParts, wrapper.PHPTypePathElements()...) - filepathParts = append(filepathParts, fmt.Sprintf("%s.php", wrapper.trw.PhpClassName(false, false))) + filepathParts = append(filepathParts, fmt.Sprintf("%s.php", wrapper.trw.PhpClassName(false, true))) filepathName := filepath.Join(filepathParts...) if err := gen.addCodeFile(filepathName, code.String()); err != nil { return err } - createdTypes[wrapper.trw.PhpClassName(true, false)] = true + createdTypes[wrapper.trw.PhpClassName(true, true)] = true } return nil } diff --git a/internal/tlcodegen/type_rw_struct.go b/internal/tlcodegen/type_rw_struct.go index 00d5f72..6fb6944 100644 --- a/internal/tlcodegen/type_rw_struct.go +++ b/internal/tlcodegen/type_rw_struct.go @@ -582,7 +582,7 @@ func (trw *TypeRWStruct) PhpClassName(withPath bool, bare bool) string { name := trw.wr.tlName.Name if !bare { - //name = trw.wr.origTL[0].TypeDecl.Name.Name + name = trw.wr.origTL[0].TypeDecl.Name.Name print("debug") } if len(trw.wr.tlName.Namespace) != 0 { @@ -592,7 +592,7 @@ func (trw *TypeRWStruct) PhpClassName(withPath bool, bare bool) string { elems := make([]string, 0, len(trw.wr.arguments)) for _, arg := range trw.wr.arguments { if arg.tip != nil { - elems = append(elems, "__", arg.tip.trw.PhpClassName(false, arg.bare)) + elems = append(elems, "__", arg.tip.trw.PhpClassName(false, false)) } } diff --git a/internal/tlcodegen/type_rw_union.go b/internal/tlcodegen/type_rw_union.go index 73624b0..b5160b3 100644 --- a/internal/tlcodegen/type_rw_union.go +++ b/internal/tlcodegen/type_rw_union.go @@ -199,7 +199,7 @@ func (trw *TypeRWUnion) PhpClassName(withPath bool, bare bool) string { elems := make([]string, 0, len(trw.wr.arguments)) for _, arg := range trw.wr.arguments { if arg.tip != nil { - elems = append(elems, "__", arg.tip.trw.PhpClassName(false, arg.bare)) + elems = append(elems, "__", arg.tip.trw.PhpClassName(false, false)) } } @@ -217,7 +217,7 @@ func (trw *TypeRWUnion) PhpTypeName(withPath bool) string { func (trw *TypeRWUnion) PhpGenerateCode(code *strings.Builder, bytes bool) error { classes := make([]string, len(trw.Fields)) for i, field := range trw.Fields { - classes[i] = fmt.Sprintf("%s::class", field.t.trw.PhpClassName(true, false)) + classes[i] = fmt.Sprintf("%s::class", field.t.trw.PhpClassName(true, true)) } code.WriteString(` From 30ca9487af772031cd1a07ecdb5846e55a740f29 Mon Sep 17 00:00:00 2001 From: Fedor Vikhnin Date: Thu, 12 Dec 2024 02:36:41 +0300 Subject: [PATCH 13/26] check nullable field --- internal/tlcodegen/tlgen_php.go | 13 +++---------- internal/tlcodegen/type_rw.go | 16 ++++++++++++++++ internal/tlcodegen/type_rw_struct.go | 2 +- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/internal/tlcodegen/tlgen_php.go b/internal/tlcodegen/tlgen_php.go index 156227c..c7f454a 100644 --- a/internal/tlcodegen/tlgen_php.go +++ b/internal/tlcodegen/tlgen_php.go @@ -30,18 +30,11 @@ func (gen *Gen2) generateCodePHP(generateByteVersions []string) error { createdTypes := make(map[string]bool) for _, wrapper := range gen.generatedTypesList { - if wrapper.PHPTypePath() == "" || - wrapper.PHPIsPrimitiveType() || - createdTypes[wrapper.trw.PhpClassName(true, true)] { + if createdTypes[wrapper.trw.PhpClassName(true, true)] { continue } - if strct, isStrct := wrapper.trw.(*TypeRWStruct); isStrct { - if strct.ResultType == nil && strct.wr.IsTrueType() && strct.wr.unionParent == nil { - continue - } - if strct.ResultType != nil && strct.wr.HasAnnotation("internal") { - continue - } + if !wrapper.PHPNeedsCode() { + continue } var code strings.Builder // add start symbol diff --git a/internal/tlcodegen/type_rw.go b/internal/tlcodegen/type_rw.go index 5a81415..082ab5b 100644 --- a/internal/tlcodegen/type_rw.go +++ b/internal/tlcodegen/type_rw.go @@ -553,6 +553,22 @@ func (w *TypeRWWrapper) PHPIsPrimitiveType() bool { return false } +func (w *TypeRWWrapper) PHPNeedsCode() bool { + if w.PHPTypePath() == "" || + w.PHPIsPrimitiveType() { + return false + } + if strct, isStrct := w.trw.(*TypeRWStruct); isStrct { + if strct.ResultType == nil && strct.wr.IsTrueType() && strct.wr.unionParent == nil { + return false + } + if strct.ResultType != nil && strct.wr.HasAnnotation("internal") { + return false + } + } + return true +} + func (w *TypeRWWrapper) CPPFillRecursiveChildren(visitedNodes map[*TypeRWWrapper]bool) { if visitedNodes[w] { return diff --git a/internal/tlcodegen/type_rw_struct.go b/internal/tlcodegen/type_rw_struct.go index 6fb6944..d4a2ecb 100644 --- a/internal/tlcodegen/type_rw_struct.go +++ b/internal/tlcodegen/type_rw_struct.go @@ -771,7 +771,7 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro for _, dependentField := range fields { condition := "" - if dependentField.t.IsTrueType() { + if dependentField.t.IsTrueType() || dependentField.t.PHPNeedsCode() { condition = fmt.Sprintf( "$this->%[1]s", dependentField.originalName, From 641449b17c851f2efd72d89817064a6e9abf6639 Mon Sep 17 00:00:00 2001 From: Fedor Vikhnin Date: Thu, 12 Dec 2024 11:13:09 +0300 Subject: [PATCH 14/26] kphp special code --- internal/tlcodegen/type_rw_struct.go | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/internal/tlcodegen/type_rw_struct.go b/internal/tlcodegen/type_rw_struct.go index d4a2ecb..0fb6f5d 100644 --- a/internal/tlcodegen/type_rw_struct.go +++ b/internal/tlcodegen/type_rw_struct.go @@ -803,6 +803,25 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro } if trw.ResultType != nil { + kphpSpecialCode := "" + if trw.wr.HasAnnotation("kphp") { + kphpSpecialCode = fmt.Sprintf( + ` + + /** + * @param %[1]s $value + * @return %[2]s_result + */ + public static function createRpcServerResponse($value) { + $response = new %[2]s_result(); + $response->value = $value; + return $response; + }`, + trw.ResultType.trw.PhpTypeName(true), + trw.PhpClassName(true, true), + ) + } + code.WriteString( fmt.Sprintf( ` @@ -826,7 +845,7 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro */ public static function result(TL\RpcResponse $response) { return self::functionReturnValue($response->getResult()); - } + }%[5]s /** * @kphp-inline @@ -841,8 +860,10 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro trw.PhpClassName(true, true), trw.wr.tlName.String(), trw.ResultType.trw.PhpTypeName(true), + kphpSpecialCode, ), ) + } code.WriteString("\n}\n") From 2ccac3d282563aeaa5a34f918b93cb49ec0dff00 Mon Sep 17 00:00:00 2001 From: Fedor Vikhnin Date: Thu, 12 Dec 2024 11:22:43 +0300 Subject: [PATCH 15/26] add rpc function and response --- internal/tlcodegen/helpers_php.go | 73 +++++++++++++++++++++++++++++++ internal/tlcodegen/tlgen_php.go | 13 ++++++ 2 files changed, 86 insertions(+) diff --git a/internal/tlcodegen/helpers_php.go b/internal/tlcodegen/helpers_php.go index 4e70412..64ea7dc 100644 --- a/internal/tlcodegen/helpers_php.go +++ b/internal/tlcodegen/helpers_php.go @@ -224,3 +224,76 @@ class tl_output_stream { } ?> ` + +const RpcFunctionPHP = ` Date: Thu, 12 Dec 2024 12:04:50 +0300 Subject: [PATCH 16/26] merged masks for same bit --- internal/tlcodegen/type_rw_struct.go | 67 ++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/internal/tlcodegen/type_rw_struct.go b/internal/tlcodegen/type_rw_struct.go index 0fb6f5d..b3f95b0 100644 --- a/internal/tlcodegen/type_rw_struct.go +++ b/internal/tlcodegen/type_rw_struct.go @@ -729,6 +729,7 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro } code.WriteString(" }\n") + // print methods to calculate fieldmasks sort.Ints(usedFieldMasksIndecies) for _, natIndex := range usedFieldMasksIndecies { natName := "" @@ -766,34 +767,63 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro fields := usedFieldMasks[natIndex] sort.Slice(fields, func(i, j int) bool { - return fields[i].BitNumber <= fields[j].BitNumber + if fields[i].BitNumber == fields[j].BitNumber { + return i < j + } + return fields[i].BitNumber < fields[j].BitNumber }) + fieldsGroupedByBitNumber := make([][]Field, 0) for _, dependentField := range fields { - condition := "" - if dependentField.t.IsTrueType() || dependentField.t.PHPNeedsCode() { - condition = fmt.Sprintf( - "$this->%[1]s", - dependentField.originalName, - ) - } else if _, isMaybe := dependentField.t.PHPGenCoreType().trw.(*TypeRWMaybe); isMaybe { - condition = fmt.Sprintf("$has_%s", dependentField.originalName) - } else { - condition = fmt.Sprintf( - "$this->%[1]s !== null", - dependentField.originalName, - ) + if len(fieldsGroupedByBitNumber) == 0 || + fieldsGroupedByBitNumber[len(fieldsGroupedByBitNumber)-1][0].BitNumber != dependentField.BitNumber { + fieldsGroupedByBitNumber = append(fieldsGroupedByBitNumber, make([]Field, 0)) + } + fieldsGroupedByBitNumber[len(fieldsGroupedByBitNumber)-1] = append(fieldsGroupedByBitNumber[len(fieldsGroupedByBitNumber)-1], dependentField) + } + + for _, dependentFields := range fieldsGroupedByBitNumber { + conditions := make([]string, 0) + bitConstants := make([]string, 0) + for _, dependentField := range dependentFields { + condition := "" + if dependentField.t.IsTrueType() || dependentField.t.PHPNeedsCode() { + condition = fmt.Sprintf( + "$this->%[1]s", + dependentField.originalName, + ) + } else if _, isMaybe := dependentField.t.PHPGenCoreType().trw.(*TypeRWMaybe); isMaybe { + condition = fmt.Sprintf("$has_%s", dependentField.originalName) + } else { + condition = fmt.Sprintf( + "$this->%[1]s !== null", + dependentField.originalName, + ) + } + conditions = append(conditions, condition) + bitConstants = append(bitConstants, fmt.Sprintf( + "self::BIT_%[1]s_%[2]d", + strings.ToUpper(dependentField.originalName), + dependentField.BitNumber)) } + + finalCondition := conditions[0] + finalMask := bitConstants[0] + + if len(conditions) > 1 { + finalCondition = strings.Join(conditions, " && ") + finalMask = "(" + strings.Join(bitConstants, " | ") + ")" + } + code.WriteString( fmt.Sprintf( ` if (%[1]s) { - $mask |= self::BIT_%[2]s_%[3]d; + $mask |= %[2]s; } `, - condition, - strings.ToUpper(dependentField.originalName), - dependentField.BitNumber, + finalCondition, + finalMask, ), ) } @@ -802,6 +832,7 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro code.WriteString(" }\n") } + // print function specific methods and types if trw.ResultType != nil { kphpSpecialCode := "" if trw.wr.HasAnnotation("kphp") { From 795da08db720c162eb1aca06b4fec575f623b572 Mon Sep 17 00:00:00 2001 From: Fedor Vikhnin Date: Thu, 12 Dec 2024 13:38:19 +0300 Subject: [PATCH 17/26] float default update + correct order on fieldmask methods --- internal/tlcodegen/type_rw_primitive.go | 2 +- internal/tlcodegen/type_rw_struct.go | 26 +++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/internal/tlcodegen/type_rw_primitive.go b/internal/tlcodegen/type_rw_primitive.go index cf03c56..0b7a131 100644 --- a/internal/tlcodegen/type_rw_primitive.go +++ b/internal/tlcodegen/type_rw_primitive.go @@ -200,7 +200,7 @@ func (trw *TypeRWPrimitive) PhpDefaultValue() string { case "string": return "''" case "float32", "float64": - return "0" + return "0.0" default: return fmt.Sprintf("", trw.tlType) } diff --git a/internal/tlcodegen/type_rw_struct.go b/internal/tlcodegen/type_rw_struct.go index b3f95b0..21ef6e2 100644 --- a/internal/tlcodegen/type_rw_struct.go +++ b/internal/tlcodegen/type_rw_struct.go @@ -729,8 +729,22 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro } code.WriteString(" }\n") + //sort.Ints(usedFieldMasksIndecies) + sort.Slice(usedFieldMasksIndecies, func(i, j int) bool { + iGEQ0 := usedFieldMasksIndecies[i] >= 0 + jGEQ0 := usedFieldMasksIndecies[j] >= 0 + if iGEQ0 && jGEQ0 { + return usedFieldMasksIndecies[i] <= usedFieldMasksIndecies[j] + } else if iGEQ0 && !jGEQ0 { + return true + } else if !iGEQ0 && jGEQ0 { + return false + } else { + return usedFieldMasksIndecies[i] > usedFieldMasksIndecies[j] + } + }) + // print methods to calculate fieldmasks - sort.Ints(usedFieldMasksIndecies) for _, natIndex := range usedFieldMasksIndecies { natName := "" if natIndex < 0 { @@ -756,7 +770,7 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro code.WriteString( fmt.Sprintf( " public function calculate%[1]s(%[2]s) {\n $mask = 0;\n", - ToUpperFirst(natName), + toPhpFieldMaskName(natName), strings.Join(additionalArgs, ", "), ), ) @@ -922,6 +936,14 @@ class %[1]s_result implements TL\RpcFunctionReturnResult { return nil } +func toPhpFieldMaskName(natName string) string { + parts := strings.Split(natName, "_") + for i, _ := range parts { + parts[i] = ToUpperFirst(parts[i]) + } + return strings.Join(parts, "") +} + func isUsingTLImport(trw *TypeRWStruct) bool { for _, field := range trw.Fields { fieldType, _ := fieldTypeAndDefaultValue(field) From 08ff321e233fdbdc28eb03a5bac0b874500eb2bd Mon Sep 17 00:00:00 2001 From: Fedor Vikhnin Date: Fri, 13 Dec 2024 02:29:59 +0300 Subject: [PATCH 18/26] online useable types --- internal/tlcodegen/tlgen_php.go | 50 ++++++++++++++++++++++--- internal/tlcodegen/type_rw.go | 11 +++++- internal/tlcodegen/type_rw_bool.go | 5 ++- internal/tlcodegen/type_rw_maybe.go | 12 +++++- internal/tlcodegen/type_rw_primitive.go | 6 ++- internal/tlcodegen/type_rw_struct.go | 35 ++++++++++++----- internal/tlcodegen/type_rw_tuple.go | 8 +++- internal/tlcodegen/type_rw_union.go | 10 ++++- 8 files changed, 113 insertions(+), 24 deletions(-) diff --git a/internal/tlcodegen/tlgen_php.go b/internal/tlcodegen/tlgen_php.go index 4867be5..40adc95 100644 --- a/internal/tlcodegen/tlgen_php.go +++ b/internal/tlcodegen/tlgen_php.go @@ -8,10 +8,8 @@ import ( ) type PhpClassMeta struct { - FileName string - GroupName string - - ClassName string + UsedOnlyInInternal bool + UsedInFunctions bool } const ( @@ -25,6 +23,7 @@ func (gen *Gen2) generateCodePHP(generateByteVersions []string) error { } // select files where to write code + gen.PhpMarkAllInternalTypes() gen.PhpChoosePaths() if err := gen.PhpAdditionalFiles(); err != nil { return err @@ -39,6 +38,12 @@ func (gen *Gen2) generateCodePHP(generateByteVersions []string) error { if !wrapper.PHPNeedsCode() { continue } + if !wrapper.phpInfo.UsedInFunctions { + continue + } + if wrapper.phpInfo.UsedOnlyInInternal { + continue + } var code strings.Builder // add start symbol code.WriteString(PHPFileStart) @@ -56,7 +61,7 @@ func (gen *Gen2) generateCodePHP(generateByteVersions []string) error { wrapper.goGlobalName, wrapper.trw.PhpClassName(true, true), reflect.TypeOf(wrapper.trw), - wrapper.trw.PhpTypeName(true), + wrapper.trw.PhpTypeName(true, true), ) //fmt.Printf("Core[%s] = %s, %s\n", wrapper.goGlobalName, wrapper.PHPGenCoreType().goGlobalName, reflect.TypeOf(wrapper.PHPGenCoreType().trw)) @@ -86,3 +91,38 @@ func (gen *Gen2) PhpAdditionalFiles() error { } return nil } + +func (gen *Gen2) PhpMarkAllInternalTypes() { + internalFunctions := make([]*TypeRWWrapper, 0) + nonInternalFunctions := make([]*TypeRWWrapper, 0) + for _, wrapper := range gen.generatedTypesList { + if strct, isStrct := wrapper.trw.(*TypeRWStruct); isStrct && strct.ResultType != nil { + if strct.wr.HasAnnotation("internal") { + internalFunctions = append(internalFunctions, wrapper) + } else { + nonInternalFunctions = append(nonInternalFunctions, wrapper) + } + } + } + internalReachable := PHPGetAllReachableTypes(internalFunctions) + nonInternalReachable := PHPGetAllReachableTypes(nonInternalFunctions) + + for wrapper, _ := range internalReachable { + if !nonInternalReachable[wrapper] { + wrapper.phpInfo.UsedOnlyInInternal = true + } + wrapper.phpInfo.UsedInFunctions = true + } + + for wrapper, _ := range nonInternalReachable { + wrapper.phpInfo.UsedInFunctions = true + } +} + +func PHPGetAllReachableTypes(startTypes []*TypeRWWrapper) map[*TypeRWWrapper]bool { + reachable := make(map[*TypeRWWrapper]bool) + for _, startType := range startTypes { + startType.PhpIterateReachableTypes(&reachable) + } + return reachable +} diff --git a/internal/tlcodegen/type_rw.go b/internal/tlcodegen/type_rw.go index 082ab5b..4c28673 100644 --- a/internal/tlcodegen/type_rw.go +++ b/internal/tlcodegen/type_rw.go @@ -569,6 +569,14 @@ func (w *TypeRWWrapper) PHPNeedsCode() bool { return true } +func (w *TypeRWWrapper) PhpIterateReachableTypes(reachableTypes *map[*TypeRWWrapper]bool) { + if (*reachableTypes)[w] { + return + } + (*reachableTypes)[w] = true + w.trw.PhpIterateReachableTypes(reachableTypes) +} + func (w *TypeRWWrapper) CPPFillRecursiveChildren(visitedNodes map[*TypeRWWrapper]bool) { if visitedNodes[w] { return @@ -807,9 +815,10 @@ outer: type TypeRWPHPData interface { PhpClassName(withPath bool, bare bool) string - PhpTypeName(withPath bool) string + 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++ diff --git a/internal/tlcodegen/type_rw_bool.go b/internal/tlcodegen/type_rw_bool.go index 85a9c36..91b2104 100644 --- a/internal/tlcodegen/type_rw_bool.go +++ b/internal/tlcodegen/type_rw_bool.go @@ -115,7 +115,7 @@ func (trw *TypeRWBool) PhpClassName(withPath bool, bare bool) string { return "boolean" } -func (trw *TypeRWBool) PhpTypeName(withPath bool) string { +func (trw *TypeRWBool) PhpTypeName(withPath bool, bare bool) string { return trw.PhpClassName(withPath, true) } @@ -126,3 +126,6 @@ func (trw *TypeRWBool) PhpGenerateCode(code *strings.Builder, bytes bool) error func (trw *TypeRWBool) PhpDefaultValue() string { return "false" } + +func (trw *TypeRWBool) PhpIterateReachableTypes(reachableTypes *map[*TypeRWWrapper]bool) { +} diff --git a/internal/tlcodegen/type_rw_maybe.go b/internal/tlcodegen/type_rw_maybe.go index 9c42e5f..6569cea 100644 --- a/internal/tlcodegen/type_rw_maybe.go +++ b/internal/tlcodegen/type_rw_maybe.go @@ -125,9 +125,13 @@ func (trw *TypeRWMaybe) PhpClassName(withPath bool, bare bool) string { return "maybe_" + target.trw.PhpClassName(withPath, trw.element.bare) } -func (trw *TypeRWMaybe) PhpTypeName(withPath bool) string { +func (trw *TypeRWMaybe) PhpTypeName(withPath bool, bare bool) string { target := trw.getInnerTarget() - return target.trw.PhpTypeName(withPath) + "|null" + if !trw.element.bare { + target = trw.element.t + bare = trw.element.bare + } + return target.trw.PhpTypeName(withPath, bare) + "|null" } func (trw *TypeRWMaybe) getInnerTarget() *TypeRWWrapper { @@ -145,3 +149,7 @@ func (trw *TypeRWMaybe) PhpGenerateCode(code *strings.Builder, bytes bool) error func (trw *TypeRWMaybe) PhpDefaultValue() string { return "null" } + +func (trw *TypeRWMaybe) PhpIterateReachableTypes(reachableTypes *map[*TypeRWWrapper]bool) { + trw.element.t.PhpIterateReachableTypes(reachableTypes) +} diff --git a/internal/tlcodegen/type_rw_primitive.go b/internal/tlcodegen/type_rw_primitive.go index 0b7a131..d15e4b5 100644 --- a/internal/tlcodegen/type_rw_primitive.go +++ b/internal/tlcodegen/type_rw_primitive.go @@ -185,8 +185,8 @@ func (trw *TypeRWPrimitive) PhpClassName(withPath bool, bare bool) string { } } -func (trw *TypeRWPrimitive) PhpTypeName(withPath bool) string { - return trw.PhpClassName(withPath, false) +func (trw *TypeRWPrimitive) PhpTypeName(withPath bool, bare bool) string { + return trw.PhpClassName(withPath, true) } func (trw *TypeRWPrimitive) PhpGenerateCode(code *strings.Builder, bytes bool) error { @@ -205,3 +205,5 @@ func (trw *TypeRWPrimitive) PhpDefaultValue() string { return fmt.Sprintf("", trw.tlType) } } + +func (trw *TypeRWPrimitive) PhpIterateReachableTypes(reachableTypes *map[*TypeRWWrapper]bool) {} diff --git a/internal/tlcodegen/type_rw_struct.go b/internal/tlcodegen/type_rw_struct.go index 21ef6e2..116a38f 100644 --- a/internal/tlcodegen/type_rw_struct.go +++ b/internal/tlcodegen/type_rw_struct.go @@ -603,9 +603,13 @@ func (trw *TypeRWStruct) PhpClassName(withPath bool, bare bool) string { return name } -func (trw *TypeRWStruct) PhpTypeName(withPath bool) string { +func (trw *TypeRWStruct) PhpTypeName(withPath bool, bare bool) string { if len(trw.Fields) == 1 && trw.ResultType == nil && trw.wr.unionParent == nil { - return trw.Fields[0].t.trw.PhpTypeName(withPath) + return trw.Fields[0].t.trw.PhpTypeName(withPath, bare) + } + isDict, _, _, valueType := isDictionaryElement(trw.wr) + if isDict { + return valueType.t.trw.PhpTypeName(withPath, bare) } return trw.PhpClassName(withPath, true) } @@ -621,9 +625,6 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro * @kphp-tl-class */ `) - if "right1__test_gigi" == trw.PhpClassName(false, true) { - print("debug") - } code.WriteString(fmt.Sprintf("class %s ", trw.PhpClassName(false, true))) if trw.wr.unionParent != nil { code.WriteString(fmt.Sprintf("implements %s ", trw.wr.unionParent.PhpClassName(true, true))) @@ -651,6 +652,9 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro } // print fields declarations for _, f := range trw.Fields { + if "tree_stats_periodsListResultPeriodsIntCounters" == trw.PhpClassName(false, true) { + print("debug") + } fieldType, defaultValue := fieldTypeAndDefaultValue(f) code.WriteString( fmt.Sprintf( @@ -862,11 +866,15 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro $response->value = $value; return $response; }`, - trw.ResultType.trw.PhpTypeName(true), + trw.ResultType.trw.PhpTypeName(true, true), trw.PhpClassName(true, true), ) } + if trw.PhpClassName(false, true) == "money_checkSystemReady" { + print("debug") + } + code.WriteString( fmt.Sprintf( ` @@ -904,7 +912,7 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro trw.PhpClassName(false, true), trw.PhpClassName(true, true), trw.wr.tlName.String(), - trw.ResultType.trw.PhpTypeName(true), + trw.ResultType.trw.PhpTypeName(true, false), kphpSpecialCode, ), ) @@ -928,7 +936,7 @@ class %[1]s_result implements TL\RpcFunctionReturnResult { } `, trw.PhpClassName(false, true), - trw.ResultType.trw.PhpTypeName(true), + trw.ResultType.trw.PhpTypeName(true, true), trw.ResultType.trw.PhpDefaultValue(), ), ) @@ -955,7 +963,7 @@ func isUsingTLImport(trw *TypeRWStruct) bool { } func fieldTypeAndDefaultValue(f Field) (string, string) { - fieldType := f.t.trw.PhpTypeName(true) + fieldType := f.t.trw.PhpTypeName(true, true) defaultValue := f.t.trw.PhpDefaultValue() if f.t.IsTrueType() { fieldType = "boolean" @@ -984,3 +992,12 @@ func (trw *TypeRWStruct) PhpDefaultValue() string { } return "null" } + +func (trw *TypeRWStruct) PhpIterateReachableTypes(reachableTypes *map[*TypeRWWrapper]bool) { + for _, field := range trw.Fields { + field.t.PhpIterateReachableTypes(reachableTypes) + } + if trw.ResultType != nil { + trw.ResultType.PhpIterateReachableTypes(reachableTypes) + } +} diff --git a/internal/tlcodegen/type_rw_tuple.go b/internal/tlcodegen/type_rw_tuple.go index e00bcbb..2755ca9 100644 --- a/internal/tlcodegen/type_rw_tuple.go +++ b/internal/tlcodegen/type_rw_tuple.go @@ -219,10 +219,10 @@ func (trw *TypeRWBrackets) PhpClassName(withPath bool, bare bool) string { return fmt.Sprintf("", trw.wr.goGlobalName) } -func (trw *TypeRWBrackets) PhpTypeName(withPath bool) string { +func (trw *TypeRWBrackets) PhpTypeName(withPath bool, bare bool) string { if strings.HasPrefix(trw.wr.tlName.String(), BuiltinTupleName) || strings.HasPrefix(trw.wr.tlName.String(), BuiltinVectorName) { - elementText := trw.element.t.trw.PhpTypeName(withPath) + elementText := trw.element.t.trw.PhpTypeName(withPath, trw.element.bare) if _, ok := trw.element.t.trw.(*TypeRWMaybe); ok { elementText = "(" + elementText + ")" } @@ -238,3 +238,7 @@ func (trw *TypeRWBrackets) PhpGenerateCode(code *strings.Builder, bytes bool) er func (trw *TypeRWBrackets) PhpDefaultValue() string { return "[]" } + +func (trw *TypeRWBrackets) PhpIterateReachableTypes(reachableTypes *map[*TypeRWWrapper]bool) { + trw.element.t.PhpIterateReachableTypes(reachableTypes) +} diff --git a/internal/tlcodegen/type_rw_union.go b/internal/tlcodegen/type_rw_union.go index b5160b3..c811d4b 100644 --- a/internal/tlcodegen/type_rw_union.go +++ b/internal/tlcodegen/type_rw_union.go @@ -210,8 +210,8 @@ func (trw *TypeRWUnion) PhpClassName(withPath bool, bare bool) string { return name } -func (trw *TypeRWUnion) PhpTypeName(withPath bool) string { - return trw.PhpClassName(withPath, false) +func (trw *TypeRWUnion) PhpTypeName(withPath bool, bare bool) string { + return trw.PhpClassName(withPath, true) } func (trw *TypeRWUnion) PhpGenerateCode(code *strings.Builder, bytes bool) error { @@ -246,3 +246,9 @@ use VK\TL; func (trw *TypeRWUnion) PhpDefaultValue() string { return "null" } + +func (trw *TypeRWUnion) PhpIterateReachableTypes(reachableTypes *map[*TypeRWWrapper]bool) { + for _, field := range trw.Fields { + field.t.PhpIterateReachableTypes(reachableTypes) + } +} From abb724f986c889b6c15ccc46c02e474d6840cc59 Mon Sep 17 00:00:00 2001 From: Fedor Vikhnin Date: Sun, 15 Dec 2024 14:35:26 +0300 Subject: [PATCH 19/26] fix small diff --- internal/tlcodegen/tlgen_php.go | 76 ++++++++++------ internal/tlcodegen/type_rw.go | 44 ++++++++- internal/tlcodegen/type_rw_maybe.go | 12 +-- internal/tlcodegen/type_rw_struct.go | 128 +++++++++++++++++---------- internal/tlcodegen/type_rw_tuple.go | 4 +- internal/tlcodegen/type_rw_union.go | 15 ++-- 6 files changed, 184 insertions(+), 95 deletions(-) diff --git a/internal/tlcodegen/tlgen_php.go b/internal/tlcodegen/tlgen_php.go index 40adc95..f14d397 100644 --- a/internal/tlcodegen/tlgen_php.go +++ b/internal/tlcodegen/tlgen_php.go @@ -38,43 +38,63 @@ func (gen *Gen2) generateCodePHP(generateByteVersions []string) error { if !wrapper.PHPNeedsCode() { continue } - if !wrapper.phpInfo.UsedInFunctions { + if !wrapper.phpInfo.UsedInFunctions || wrapper.phpInfo.UsedOnlyInInternal { continue } - if wrapper.phpInfo.UsedOnlyInInternal { + if wrapper.PHPGenCoreType() != wrapper { continue } - var code strings.Builder - // add start symbol - code.WriteString(PHPFileStart) - code.WriteString("\n") - // add copyright text - code.WriteString(gen.copyrightText) - code.WriteString(fmt.Sprintf("namespace VK\\%s;\n", strings.Join(wrapper.PHPTypePathElements(), "\\"))) - - if err := wrapper.PHPGenerateCode(&code, true); err != nil { + err := phpGenerateCodeForWrapper(gen, wrapper, createdTypes, true, wrapper.PHPGenerateCode) + if err != nil { return err } + } + return nil +} - fmt.Printf("TL[%[1]s] = Go {%[2]s, %[4]s} -> PHP {%[3]s, %[5]s}\n", - wrapper.tlName.String(), - wrapper.goGlobalName, - wrapper.trw.PhpClassName(true, true), - reflect.TypeOf(wrapper.trw), - wrapper.trw.PhpTypeName(true, true), - ) - - //fmt.Printf("Core[%s] = %s, %s\n", wrapper.goGlobalName, wrapper.PHPGenCoreType().goGlobalName, reflect.TypeOf(wrapper.PHPGenCoreType().trw)) - - filepathParts := []string{"VK"} - filepathParts = append(filepathParts, wrapper.PHPTypePathElements()...) - filepathParts = append(filepathParts, fmt.Sprintf("%s.php", wrapper.trw.PhpClassName(false, true))) - filepathName := filepath.Join(filepathParts...) - if err := gen.addCodeFile(filepathName, code.String()); err != nil { - return err +func phpGenerateCodeForWrapper(gen *Gen2, wrapper *TypeRWWrapper, createdTypes map[string]bool, createInterfaceIfNeeded bool, codeGenerator func(code *strings.Builder, bytes bool) error) error { + var code strings.Builder + // add start symbol + code.WriteString(PHPFileStart) + code.WriteString("\n") + // add copyright text + code.WriteString(gen.copyrightText) + code.WriteString(fmt.Sprintf("namespace VK\\%s;\n", strings.Join(wrapper.PHPTypePathElements(), "\\"))) + + if err := codeGenerator(&code, true); err != nil { + return err + } + + if createInterfaceIfNeeded { + if strct, isStruct := wrapper.trw.(*TypeRWStruct); isStruct { + unionParent := strct.PhpConstructorNeedsUnion() + if unionParent != nil && unionParent == wrapper { + err := phpGenerateCodeForWrapper(gen, wrapper, createdTypes, false, func(code *strings.Builder, bytes bool) error { + return PhpGenerateInterfaceCode(code, bytes, wrapper, []*TypeRWWrapper{wrapper}) + }) + if err != nil { + return err + } + } } - createdTypes[wrapper.trw.PhpClassName(true, true)] = true } + + fmt.Printf("TL[%[1]s] = Go {%[2]s, %[4]s} -> PHP {%[3]s, %[5]s}\n", + wrapper.tlName.String(), + wrapper.goGlobalName, + wrapper.trw.PhpClassName(true, true), + reflect.TypeOf(wrapper.trw), + wrapper.trw.PhpTypeName(true, true), + ) + + filepathParts := []string{"VK"} + filepathParts = append(filepathParts, wrapper.PHPTypePathElements()...) + filepathParts = append(filepathParts, fmt.Sprintf("%s.php", wrapper.trw.PhpClassName(false, createInterfaceIfNeeded))) + filepathName := filepath.Join(filepathParts...) + if err := gen.addCodeFile(filepathName, code.String()); err != nil { + return err + } + createdTypes[wrapper.trw.PhpClassName(true, createInterfaceIfNeeded)] = true return nil } diff --git a/internal/tlcodegen/type_rw.go b/internal/tlcodegen/type_rw.go index 4c28673..baaf7a9 100644 --- a/internal/tlcodegen/type_rw.go +++ b/internal/tlcodegen/type_rw.go @@ -490,6 +490,23 @@ func (w *TypeRWWrapper) IsTrueType() bool { return len(structElement.Fields) == 0 } +func (w *TypeRWWrapper) PHPIsTrueType() bool { + structElement, ok := w.trw.(*TypeRWStruct) + if ok { + unionParent := structElement.PhpConstructorNeedsUnion() + if unionParent != nil { + return false + } + for _, argument := range w.origTL[0].TemplateArguments { + if argument.IsNat { + return false + } + } + return w.IsTrueType() + } + return false +} + func (w *TypeRWWrapper) PHPGenerateCode(code *strings.Builder, bytes bool) error { return w.trw.PhpGenerateCode(code, bytes) } @@ -527,15 +544,35 @@ func (w *TypeRWWrapper) PHPTypePath() string { } func (w *TypeRWWrapper) PHPGenCoreType() *TypeRWWrapper { - if w.unionParent == nil { + if w.PHPUnionParent() == nil { struct_, isStruct := w.trw.(*TypeRWStruct) - if isStruct && len(struct_.Fields) == 1 && struct_.ResultType == nil { + if isStruct && len(struct_.Fields) == 1 && struct_.ResultType == nil && struct_.Fields[0].fieldMask == nil { return struct_.Fields[0].t.PHPGenCoreType() } } return w } +func (w *TypeRWWrapper) PHPUnionParent() *TypeRWWrapper { + if w.unionParent != nil { + return w.unionParent.wr + } + if strct, isStruct := w.trw.(*TypeRWStruct); isStruct { + unionParent := strct.PhpConstructorNeedsUnion() + if unionParent != nil { + return unionParent + } + } + return nil +} + +func (w *TypeRWWrapper) PHPIsBare() bool { + if strct, isStruct := w.trw.(*TypeRWStruct); isStruct && strct.PhpConstructorNeedsUnion() != nil { + return false + } + return true +} + func (w *TypeRWWrapper) PHPIsPrimitiveType() bool { core := w.PHPGenCoreType() if _, isPrimitive := core.trw.(*TypeRWPrimitive); isPrimitive { @@ -559,7 +596,8 @@ func (w *TypeRWWrapper) PHPNeedsCode() bool { return false } if strct, isStrct := w.trw.(*TypeRWStruct); isStrct { - if strct.ResultType == nil && strct.wr.IsTrueType() && strct.wr.unionParent == nil { + unionParent := strct.PhpConstructorNeedsUnion() + if strct.ResultType == nil && strct.wr.IsTrueType() && unionParent == nil { return false } if strct.ResultType != nil && strct.wr.HasAnnotation("internal") { diff --git a/internal/tlcodegen/type_rw_maybe.go b/internal/tlcodegen/type_rw_maybe.go index 6569cea..e00b78e 100644 --- a/internal/tlcodegen/type_rw_maybe.go +++ b/internal/tlcodegen/type_rw_maybe.go @@ -122,23 +122,19 @@ func (trw *TypeRWMaybe) typeJSON2ReadingCode(bytesVersion bool, directImports *D func (trw *TypeRWMaybe) PhpClassName(withPath bool, bare bool) string { target := trw.getInnerTarget() - return "maybe_" + target.trw.PhpClassName(withPath, trw.element.bare) + return "maybe_" + target.t.trw.PhpClassName(withPath, target.bare) } func (trw *TypeRWMaybe) PhpTypeName(withPath bool, bare bool) string { target := trw.getInnerTarget() - if !trw.element.bare { - target = trw.element.t - bare = trw.element.bare - } - return target.trw.PhpTypeName(withPath, bare) + "|null" + return target.t.trw.PhpTypeName(withPath, target.bare) + "|null" } -func (trw *TypeRWMaybe) getInnerTarget() *TypeRWWrapper { +func (trw *TypeRWMaybe) getInnerTarget() Field { if inner, ok := trw.element.t.trw.(*TypeRWMaybe); ok { return inner.getInnerTarget() } else { - return trw.element.t + return trw.element } } diff --git a/internal/tlcodegen/type_rw_struct.go b/internal/tlcodegen/type_rw_struct.go index 116a38f..b0ceaa4 100644 --- a/internal/tlcodegen/type_rw_struct.go +++ b/internal/tlcodegen/type_rw_struct.go @@ -8,6 +8,7 @@ package tlcodegen import ( "fmt" + "github.com/vkcom/tl/internal/utils" "log" "sort" "strings" @@ -567,25 +568,27 @@ func (trw *TypeRWStruct) typeJSON2ReadingCode(bytesVersion bool, directImports * } func (trw *TypeRWStruct) PhpClassName(withPath bool, bare bool) string { - if len(trw.Fields) == 1 && trw.ResultType == nil && trw.wr.unionParent == nil { - return trw.Fields[0].t.trw.PhpClassName(withPath, bare) - } + unionParent := trw.PhpConstructorNeedsUnion() + if unionParent == nil { + if len(trw.Fields) == 1 && trw.ResultType == nil && trw.Fields[0].fieldMask == nil { + return trw.Fields[0].t.trw.PhpClassName(withPath, bare) + } - if trw.ResultType == nil && trw.wr.IsTrueType() && trw.wr.unionParent == nil { - return "boolean" - } + if trw.ResultType == nil && trw.wr.PHPIsTrueType() { + return "boolean" + } - isDict, _, _, valueType := isDictionaryElement(trw.wr) - if isDict { - return valueType.t.trw.PhpClassName(withPath, bare) + isDict, _, _, valueType := isDictionaryElement(trw.wr) + if isDict { + return valueType.t.trw.PhpClassName(withPath, bare) + } } name := trw.wr.tlName.Name if !bare { name = trw.wr.origTL[0].TypeDecl.Name.Name - print("debug") } - if len(trw.wr.tlName.Namespace) != 0 { + if trw.wr.tlName.Namespace != "" { name = fmt.Sprintf("%s_%s", trw.wr.tlName.Namespace, name) } @@ -604,20 +607,25 @@ func (trw *TypeRWStruct) PhpClassName(withPath bool, bare bool) string { } func (trw *TypeRWStruct) PhpTypeName(withPath bool, bare bool) string { - if len(trw.Fields) == 1 && trw.ResultType == nil && trw.wr.unionParent == nil { - return trw.Fields[0].t.trw.PhpTypeName(withPath, bare) - } - isDict, _, _, valueType := isDictionaryElement(trw.wr) - if isDict { - return valueType.t.trw.PhpTypeName(withPath, bare) + unionParent := trw.PhpConstructorNeedsUnion() + if unionParent == nil { + if len(trw.Fields) == 1 && trw.ResultType == nil && trw.Fields[0].fieldMask == nil { + return trw.Fields[0].t.trw.PhpTypeName(withPath, trw.Fields[0].bare) + } + isDict, _, _, valueType := isDictionaryElement(trw.wr) + if isDict { + return valueType.t.trw.PhpTypeName(withPath, bare) + } } - return trw.PhpClassName(withPath, true) + return trw.PhpClassName(withPath, bare) } func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) error { + unionParent := trw.PhpConstructorNeedsUnion() + if isUsingTLImport(trw) || trw.ResultType != nil || - trw.wr.unionParent != nil { + unionParent != nil { code.WriteString("\nuse VK\\TL;\n") } code.WriteString(` @@ -626,8 +634,8 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro */ `) code.WriteString(fmt.Sprintf("class %s ", trw.PhpClassName(false, true))) - if trw.wr.unionParent != nil { - code.WriteString(fmt.Sprintf("implements %s ", trw.wr.unionParent.PhpClassName(true, true))) + if unionParent != nil { + code.WriteString(fmt.Sprintf("implements %s ", unionParent.trw.PhpClassName(true, false))) } if trw.ResultType != nil { code.WriteString(fmt.Sprintf("implements TL\\RpcFunction ")) @@ -652,7 +660,7 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro } // print fields declarations for _, f := range trw.Fields { - if "tree_stats_periodsListResultPeriodsIntCounters" == trw.PhpClassName(false, true) { + if "trustId_link" == trw.PhpClassName(false, true) { print("debug") } fieldType, defaultValue := fieldTypeAndDefaultValue(f) @@ -678,8 +686,8 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro } else { index := f.fieldMask.FieldIndex if !f.fieldMask.isField { - for i, argument := range trw.wr.NatParams { - if argument == f.fieldMask.name { + for i, argument := range trw.wr.origTL[0].TemplateArguments { + if argument.IsNat && argument.FieldName == f.fieldMask.name { index = -(i + 1) break } @@ -733,29 +741,32 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro } code.WriteString(" }\n") - //sort.Ints(usedFieldMasksIndecies) - sort.Slice(usedFieldMasksIndecies, func(i, j int) bool { - iGEQ0 := usedFieldMasksIndecies[i] >= 0 - jGEQ0 := usedFieldMasksIndecies[j] >= 0 - if iGEQ0 && jGEQ0 { - return usedFieldMasksIndecies[i] <= usedFieldMasksIndecies[j] - } else if iGEQ0 && !jGEQ0 { - return true - } else if !iGEQ0 && jGEQ0 { - return false - } else { - return usedFieldMasksIndecies[i] > usedFieldMasksIndecies[j] - } - }) - - // print methods to calculate fieldmasks - for _, natIndex := range usedFieldMasksIndecies { + // fix order + names := utils.MapSlice(usedFieldMasksIndecies, func(natIndex int) string { natName := "" if natIndex < 0 { - natName = trw.wr.NatParams[-(natIndex + 1)] + natName = trw.wr.origTL[0].TemplateArguments[-(natIndex + 1)].FieldName } else { natName = trw.Fields[natIndex].originalName } + return natName + }) + + namesToIndices := make(map[string]int) + for i := range names { + namesToIndices[names[i]] = usedFieldMasksIndecies[i] + } + sort.Strings(names) + + fieldNameToFieldOrder := make(map[string]int) + for i := range trw.Fields { + fieldNameToFieldOrder[trw.Fields[i].originalName] = i + } + + // print methods to calculate fieldmasks + for _, name := range names { + natIndex := namesToIndices[name] + natName := name code.WriteString(` /**`) additionalArgs := make([]string, 0) @@ -803,9 +814,12 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro for _, dependentFields := range fieldsGroupedByBitNumber { conditions := make([]string, 0) bitConstants := make([]string, 0) + sort.Slice(dependentFields, func(i, j int) bool { + return fieldNameToFieldOrder[dependentFields[i].originalName] < fieldNameToFieldOrder[dependentFields[j].originalName] + }) for _, dependentField := range dependentFields { condition := "" - if dependentField.t.IsTrueType() || dependentField.t.PHPNeedsCode() { + if dependentField.t.PHPIsTrueType() || dependentField.t.PHPNeedsCode() { condition = fmt.Sprintf( "$this->%[1]s", dependentField.originalName, @@ -871,7 +885,7 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro ) } - if trw.PhpClassName(false, true) == "money_checkSystemReady" { + if trw.PhpClassName(false, true) == "playground_deleteObject" { print("debug") } @@ -912,7 +926,7 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro trw.PhpClassName(false, true), trw.PhpClassName(true, true), trw.wr.tlName.String(), - trw.ResultType.trw.PhpTypeName(true, false), + trw.ResultType.trw.PhpTypeName(true, trw.ResultType.PHPIsBare()), kphpSpecialCode, ), ) @@ -936,7 +950,7 @@ class %[1]s_result implements TL\RpcFunctionReturnResult { } `, trw.PhpClassName(false, true), - trw.ResultType.trw.PhpTypeName(true, true), + trw.ResultType.trw.PhpTypeName(true, trw.ResultType.PHPIsBare()), trw.ResultType.trw.PhpDefaultValue(), ), ) @@ -963,9 +977,12 @@ func isUsingTLImport(trw *TypeRWStruct) bool { } func fieldTypeAndDefaultValue(f Field) (string, string) { - fieldType := f.t.trw.PhpTypeName(true, true) + if f.t.trw.PhpTypeName(false, f.bare) == "messages_unreadCounterSettings" { + print("debug") + } + fieldType := f.t.trw.PhpTypeName(true, f.t.PHPIsBare()) defaultValue := f.t.trw.PhpDefaultValue() - if f.t.IsTrueType() { + if f.t.PHPIsTrueType() { fieldType = "boolean" defaultValue = "true" if f.fieldMask != nil { @@ -987,7 +1004,7 @@ func (trw *TypeRWStruct) PhpDefaultValue() string { if core != trw.wr { return core.PHPDefaultValue() } - if core.IsTrueType() { + if core.PHPIsTrueType() { return "true" } return "null" @@ -1001,3 +1018,16 @@ func (trw *TypeRWStruct) PhpIterateReachableTypes(reachableTypes *map[*TypeRWWra trw.ResultType.PhpIterateReachableTypes(reachableTypes) } } + +func (trw *TypeRWStruct) PhpConstructorNeedsUnion() (unionParent *TypeRWWrapper) { + if trw.ResultType == nil { + if trw.wr.unionParent != nil { + return trw.wr.unionParent.wr + } else if strings.ToLower(trw.wr.tlName.Name) != strings.ToLower(trw.wr.origTL[0].TypeDecl.Name.Name) { + // NOTE: constructor name is not same as type => type can become union in future? + return trw.wr + } + } + + return nil +} diff --git a/internal/tlcodegen/type_rw_tuple.go b/internal/tlcodegen/type_rw_tuple.go index 2755ca9..8d9ef38 100644 --- a/internal/tlcodegen/type_rw_tuple.go +++ b/internal/tlcodegen/type_rw_tuple.go @@ -214,7 +214,7 @@ func (trw *TypeRWBrackets) typeJSON2ReadingCode(bytesVersion bool, directImports func (trw *TypeRWBrackets) PhpClassName(withPath bool, bare bool) string { if strings.HasPrefix(trw.wr.tlName.String(), BuiltinTupleName) || strings.HasPrefix(trw.wr.tlName.String(), BuiltinVectorName) { - return "array_" + trw.element.t.trw.PhpClassName(false, trw.element.bare) + return "array_" + trw.element.t.trw.PhpClassName(false, false) } return fmt.Sprintf("", trw.wr.goGlobalName) } @@ -222,7 +222,7 @@ func (trw *TypeRWBrackets) PhpClassName(withPath bool, bare bool) string { func (trw *TypeRWBrackets) PhpTypeName(withPath bool, bare bool) string { if strings.HasPrefix(trw.wr.tlName.String(), BuiltinTupleName) || strings.HasPrefix(trw.wr.tlName.String(), BuiltinVectorName) { - elementText := trw.element.t.trw.PhpTypeName(withPath, trw.element.bare) + elementText := trw.element.t.trw.PhpTypeName(withPath, trw.element.t.PHPIsBare()) if _, ok := trw.element.t.trw.(*TypeRWMaybe); ok { elementText = "(" + elementText + ")" } diff --git a/internal/tlcodegen/type_rw_union.go b/internal/tlcodegen/type_rw_union.go index c811d4b..a700beb 100644 --- a/internal/tlcodegen/type_rw_union.go +++ b/internal/tlcodegen/type_rw_union.go @@ -8,6 +8,7 @@ package tlcodegen import ( "fmt" + "github.com/vkcom/tl/internal/utils" "strings" ) @@ -215,9 +216,13 @@ func (trw *TypeRWUnion) PhpTypeName(withPath bool, bare bool) string { } func (trw *TypeRWUnion) PhpGenerateCode(code *strings.Builder, bytes bool) error { - classes := make([]string, len(trw.Fields)) - for i, field := range trw.Fields { - classes[i] = fmt.Sprintf("%s::class", field.t.trw.PhpClassName(true, true)) + return PhpGenerateInterfaceCode(code, bytes, trw.wr, utils.MapSlice(trw.Fields, func(f Field) *TypeRWWrapper { return f.t })) +} + +func PhpGenerateInterfaceCode(code *strings.Builder, bytes bool, targetType *TypeRWWrapper, itsConstructors []*TypeRWWrapper) error { + constructors := make([]string, len(itsConstructors)) + for i, constructor := range itsConstructors { + constructors[i] = fmt.Sprintf("%s::class", constructor.trw.PhpClassName(true, true)) } code.WriteString(` @@ -237,8 +242,8 @@ use VK\TL; } `, - trw.PhpClassName(false, false), - strings.Join(classes, ",\n "), + targetType.trw.PhpClassName(false, false), + strings.Join(constructors, ",\n "), )) return nil } From 3354eb283d44ec8ebd85338ba654829b29b7a987 Mon Sep 17 00:00:00 2001 From: Fedor Vikhnin Date: Sun, 15 Dec 2024 15:23:00 +0300 Subject: [PATCH 20/26] zero diff without absences --- internal/tlcodegen/type_rw.go | 4 ++++ internal/tlcodegen/type_rw_maybe.go | 2 +- internal/tlcodegen/type_rw_struct.go | 19 ++++++++++--------- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/internal/tlcodegen/type_rw.go b/internal/tlcodegen/type_rw.go index baaf7a9..a96bfd2 100644 --- a/internal/tlcodegen/type_rw.go +++ b/internal/tlcodegen/type_rw.go @@ -502,6 +502,10 @@ func (w *TypeRWWrapper) PHPIsTrueType() bool { return false } } + // TODO: I HATE THIS SOOO MUCH + if strings.ToLower(w.tlName.String()) != "true" { + return false + } return w.IsTrueType() } return false diff --git a/internal/tlcodegen/type_rw_maybe.go b/internal/tlcodegen/type_rw_maybe.go index e00b78e..7e34b1e 100644 --- a/internal/tlcodegen/type_rw_maybe.go +++ b/internal/tlcodegen/type_rw_maybe.go @@ -127,7 +127,7 @@ func (trw *TypeRWMaybe) PhpClassName(withPath bool, bare bool) string { func (trw *TypeRWMaybe) PhpTypeName(withPath bool, bare bool) string { target := trw.getInnerTarget() - return target.t.trw.PhpTypeName(withPath, target.bare) + "|null" + return target.t.trw.PhpTypeName(withPath, target.t.PHPIsBare()) + "|null" } func (trw *TypeRWMaybe) getInnerTarget() Field { diff --git a/internal/tlcodegen/type_rw_struct.go b/internal/tlcodegen/type_rw_struct.go index b0ceaa4..6d45759 100644 --- a/internal/tlcodegen/type_rw_struct.go +++ b/internal/tlcodegen/type_rw_struct.go @@ -579,7 +579,7 @@ func (trw *TypeRWStruct) PhpClassName(withPath bool, bare bool) string { } isDict, _, _, valueType := isDictionaryElement(trw.wr) - if isDict { + if isDict && trw.wr.tlName.Namespace == "" { // TODO NOT A SOLUTION, BUT... return valueType.t.trw.PhpClassName(withPath, bare) } } @@ -613,7 +613,7 @@ func (trw *TypeRWStruct) PhpTypeName(withPath bool, bare bool) string { return trw.Fields[0].t.trw.PhpTypeName(withPath, trw.Fields[0].bare) } isDict, _, _, valueType := isDictionaryElement(trw.wr) - if isDict { + if isDict && trw.wr.tlName.Namespace == "" { // TODO NOT A SOLUTION, BUT... return valueType.t.trw.PhpTypeName(withPath, bare) } } @@ -660,7 +660,7 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro } // print fields declarations for _, f := range trw.Fields { - if "trustId_link" == trw.PhpClassName(false, true) { + if "logs2_setDictionary" == trw.PhpClassName(false, true) { print("debug") } fieldType, defaultValue := fieldTypeAndDefaultValue(f) @@ -885,7 +885,7 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro ) } - if trw.PhpClassName(false, true) == "playground_deleteObject" { + if trw.PhpClassName(false, true) == "healthLoyalty_tmpBuyShopItem2" { print("debug") } @@ -926,7 +926,7 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro trw.PhpClassName(false, true), trw.PhpClassName(true, true), trw.wr.tlName.String(), - trw.ResultType.trw.PhpTypeName(true, trw.ResultType.PHPIsBare()), + phpResultType(trw), kphpSpecialCode, ), ) @@ -950,7 +950,7 @@ class %[1]s_result implements TL\RpcFunctionReturnResult { } `, trw.PhpClassName(false, true), - trw.ResultType.trw.PhpTypeName(true, trw.ResultType.PHPIsBare()), + phpResultType(trw), trw.ResultType.trw.PhpDefaultValue(), ), ) @@ -958,6 +958,10 @@ class %[1]s_result implements TL\RpcFunctionReturnResult { return nil } +func phpResultType(trw *TypeRWStruct) string { + return trw.ResultType.trw.PhpTypeName(true, trw.ResultType.PHPIsBare()) +} + func toPhpFieldMaskName(natName string) string { parts := strings.Split(natName, "_") for i, _ := range parts { @@ -977,9 +981,6 @@ func isUsingTLImport(trw *TypeRWStruct) bool { } func fieldTypeAndDefaultValue(f Field) (string, string) { - if f.t.trw.PhpTypeName(false, f.bare) == "messages_unreadCounterSettings" { - print("debug") - } fieldType := f.t.trw.PhpTypeName(true, f.t.PHPIsBare()) defaultValue := f.t.trw.PhpDefaultValue() if f.t.PHPIsTrueType() { From f1f57bd996b0248c2592ada471aac9b8338e8065 Mon Sep 17 00:00:00 2001 From: Fedor Vikhnin Date: Mon, 16 Dec 2024 13:06:12 +0300 Subject: [PATCH 21/26] diff in generic functions --- internal/tlcodegen/tlgen_php.go | 14 ++++++++++++-- internal/tlcodegen/type_rw.go | 1 + internal/tlcodegen/type_rw_bool.go | 4 ++++ internal/tlcodegen/type_rw_maybe.go | 4 ++++ internal/tlcodegen/type_rw_primitive.go | 4 ++++ internal/tlcodegen/type_rw_struct.go | 19 +++++++++++++++++++ internal/tlcodegen/type_rw_tuple.go | 4 ++++ internal/tlcodegen/type_rw_union.go | 4 ++++ 8 files changed, 52 insertions(+), 2 deletions(-) diff --git a/internal/tlcodegen/tlgen_php.go b/internal/tlcodegen/tlgen_php.go index f14d397..e5107cf 100644 --- a/internal/tlcodegen/tlgen_php.go +++ b/internal/tlcodegen/tlgen_php.go @@ -32,6 +32,12 @@ func (gen *Gen2) generateCodePHP(generateByteVersions []string) error { createdTypes := make(map[string]bool) for _, wrapper := range gen.generatedTypesList { + if wrapper.tlName.String() == "exactlyOnce.uuid" { + print(wrapper.trw.PhpClassName(true, true)) + } + if wrapper.trw.PhpClassNameReplaced() { + continue + } if createdTypes[wrapper.trw.PhpClassName(true, true)] { continue } @@ -88,12 +94,16 @@ func phpGenerateCodeForWrapper(gen *Gen2, wrapper *TypeRWWrapper, createdTypes m ) filepathParts := []string{"VK"} - filepathParts = append(filepathParts, wrapper.PHPTypePathElements()...) - filepathParts = append(filepathParts, fmt.Sprintf("%s.php", wrapper.trw.PhpClassName(false, createInterfaceIfNeeded))) + //filepathParts = append(filepathParts, wrapper.PHPTypePathElements()...) + path := fmt.Sprintf("%s.php", wrapper.trw.PhpClassName(true, createInterfaceIfNeeded)) + filepathParts = append(filepathParts, strings.Split(path, "\\")...) filepathName := filepath.Join(filepathParts...) if err := gen.addCodeFile(filepathName, code.String()); err != nil { return err } + if wrapper.trw.PhpClassName(false, createInterfaceIfNeeded) == "gucene_Query" { + print(wrapper.trw.PhpClassName(true, createInterfaceIfNeeded)) + } createdTypes[wrapper.trw.PhpClassName(true, createInterfaceIfNeeded)] = true return nil } diff --git a/internal/tlcodegen/type_rw.go b/internal/tlcodegen/type_rw.go index a96bfd2..561a156 100644 --- a/internal/tlcodegen/type_rw.go +++ b/internal/tlcodegen/type_rw.go @@ -857,6 +857,7 @@ outer: 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 diff --git a/internal/tlcodegen/type_rw_bool.go b/internal/tlcodegen/type_rw_bool.go index 91b2104..4a3e085 100644 --- a/internal/tlcodegen/type_rw_bool.go +++ b/internal/tlcodegen/type_rw_bool.go @@ -115,6 +115,10 @@ func (trw *TypeRWBool) PhpClassName(withPath bool, bare bool) string { return "boolean" } +func (trw *TypeRWBool) PhpClassNameReplaced() bool { + return true +} + func (trw *TypeRWBool) PhpTypeName(withPath bool, bare bool) string { return trw.PhpClassName(withPath, true) } diff --git a/internal/tlcodegen/type_rw_maybe.go b/internal/tlcodegen/type_rw_maybe.go index 7e34b1e..d9e4ee0 100644 --- a/internal/tlcodegen/type_rw_maybe.go +++ b/internal/tlcodegen/type_rw_maybe.go @@ -125,6 +125,10 @@ func (trw *TypeRWMaybe) PhpClassName(withPath bool, bare bool) string { return "maybe_" + target.t.trw.PhpClassName(withPath, target.bare) } +func (trw *TypeRWMaybe) PhpClassNameReplaced() bool { + return true +} + func (trw *TypeRWMaybe) PhpTypeName(withPath bool, bare bool) string { target := trw.getInnerTarget() return target.t.trw.PhpTypeName(withPath, target.t.PHPIsBare()) + "|null" diff --git a/internal/tlcodegen/type_rw_primitive.go b/internal/tlcodegen/type_rw_primitive.go index d15e4b5..526524d 100644 --- a/internal/tlcodegen/type_rw_primitive.go +++ b/internal/tlcodegen/type_rw_primitive.go @@ -185,6 +185,10 @@ func (trw *TypeRWPrimitive) PhpClassName(withPath bool, bare bool) string { } } +func (trw *TypeRWPrimitive) PhpClassNameReplaced() bool { + return true +} + func (trw *TypeRWPrimitive) PhpTypeName(withPath bool, bare bool) string { return trw.PhpClassName(withPath, true) } diff --git a/internal/tlcodegen/type_rw_struct.go b/internal/tlcodegen/type_rw_struct.go index 6d45759..73ed9fb 100644 --- a/internal/tlcodegen/type_rw_struct.go +++ b/internal/tlcodegen/type_rw_struct.go @@ -567,6 +567,25 @@ func (trw *TypeRWStruct) typeJSON2ReadingCode(bytesVersion bool, directImports * return fmt.Sprintf("if err := %s.ReadJSON(legacyTypeNames, %s %s); err != nil { return err }", val, jvalue, joinWithCommas(natArgs)) } +func (trw *TypeRWStruct) PhpClassNameReplaced() bool { + unionParent := trw.PhpConstructorNeedsUnion() + if unionParent == nil { + if len(trw.Fields) == 1 && trw.ResultType == nil && trw.Fields[0].fieldMask == nil { + return true + } + + if trw.ResultType == nil && trw.wr.PHPIsTrueType() { + return true + } + + isDict, _, _, _ := isDictionaryElement(trw.wr) + if isDict && trw.wr.tlName.Namespace == "" { // TODO NOT A SOLUTION, BUT... + return true + } + } + return false +} + func (trw *TypeRWStruct) PhpClassName(withPath bool, bare bool) string { unionParent := trw.PhpConstructorNeedsUnion() if unionParent == nil { diff --git a/internal/tlcodegen/type_rw_tuple.go b/internal/tlcodegen/type_rw_tuple.go index 8d9ef38..2dacc5d 100644 --- a/internal/tlcodegen/type_rw_tuple.go +++ b/internal/tlcodegen/type_rw_tuple.go @@ -219,6 +219,10 @@ func (trw *TypeRWBrackets) PhpClassName(withPath bool, bare bool) string { return fmt.Sprintf("", trw.wr.goGlobalName) } +func (trw *TypeRWBrackets) PhpClassNameReplaced() bool { + return true +} + func (trw *TypeRWBrackets) PhpTypeName(withPath bool, bare bool) string { if strings.HasPrefix(trw.wr.tlName.String(), BuiltinTupleName) || strings.HasPrefix(trw.wr.tlName.String(), BuiltinVectorName) { diff --git a/internal/tlcodegen/type_rw_union.go b/internal/tlcodegen/type_rw_union.go index a700beb..f899668 100644 --- a/internal/tlcodegen/type_rw_union.go +++ b/internal/tlcodegen/type_rw_union.go @@ -191,6 +191,10 @@ func (trw *TypeRWUnion) HasShortFieldCollision(wr *TypeRWWrapper) bool { return false } +func (trw *TypeRWUnion) PhpClassNameReplaced() bool { + return false +} + func (trw *TypeRWUnion) PhpClassName(withPath bool, bare bool) string { name := trw.wr.tlName.Name if len(trw.wr.tlName.Namespace) != 0 { From 4c4f00589078dd244e09628778df40509769b3f6 Mon Sep 17 00:00:00 2001 From: Fedor Vikhnin Date: Mon, 16 Dec 2024 14:33:47 +0300 Subject: [PATCH 22/26] diff 12 --- internal/tlcodegen/tlgen.go | 55 ++++++++++++++++++++++++++++ internal/tlcodegen/tlgen_php.go | 10 ++--- internal/tlcodegen/type_rw.go | 4 +- internal/tlcodegen/type_rw_struct.go | 17 ++++++++- internal/tlcodegen/type_rw_union.go | 5 ++- 5 files changed, 81 insertions(+), 10 deletions(-) diff --git a/internal/tlcodegen/tlgen.go b/internal/tlcodegen/tlgen.go index 4c4ace0..e08eb8a 100644 --- a/internal/tlcodegen/tlgen.go +++ b/internal/tlcodegen/tlgen.go @@ -910,6 +910,40 @@ func GenerateCode(tl tlast.TL, options Gen2Options) (*Gen2, error) { if err != nil { return nil, fmt.Errorf("failed to parse internal builtin type representation for beautification: %w", err) } + + if gen.options.Language == "php" { + // CHANGE ALL GENERIC FUNCTIONS + rpcFunctionTypeRef := tlast.TypeRef{ + Type: tlast.Name{ + Name: PHPRPCFunctionMock, + }, + Bare: false, + } + rpcFunctionResultTypeRef := tlast.TypeRef{ + Type: tlast.Name{ + Name: PHPRPCFunctionResultMock, + }, + Bare: false, + } + tl = append(tl, &tlast.Combinator{ + TypeDecl: tlast.TypeDeclaration{ + Name: rpcFunctionTypeRef.Type, + }, + Construct: tlast.Constructor{Name: rpcFunctionTypeRef.Type}, + }) + tl = append(tl, &tlast.Combinator{ + TypeDecl: tlast.TypeDeclaration{ + Name: rpcFunctionResultTypeRef.Type, + }, + Construct: tlast.Constructor{Name: rpcFunctionResultTypeRef.Type}, + }) + for _, typ := range tl { + if typ.IsFunction && len(typ.TemplateArguments) == 1 { + phpRemoveTemplateFromGenericFunction(typ, &rpcFunctionTypeRef, &rpcFunctionResultTypeRef) + } + } + } + for i, typ := range tl { // replace built-in tName := typ.Construct.Name.String() // convert that old syntax to new syntax. @@ -1242,6 +1276,27 @@ func GenerateCode(tl tlast.TL, options Gen2Options) (*Gen2, error) { return gen, nil } +func phpRemoveTemplateFromGenericFunction(combinator *tlast.Combinator, newTypeRef, newTypeResultRef *tlast.TypeRef) { + template := combinator.TemplateArguments[0].FieldName + combinator.TemplateArguments = nil + for i := range combinator.Fields { + phpRemoveTemplateFromTypeDecl(&combinator.Fields[i].FieldType, template, newTypeRef) + } + phpRemoveTemplateFromTypeDecl(&combinator.FuncDecl, template, newTypeResultRef) +} + +func phpRemoveTemplateFromTypeDecl(declaration *tlast.TypeRef, template string, newTypeRef *tlast.TypeRef) { + if declaration.Type.String() == template { + *declaration = *newTypeRef + } else { + for i := range declaration.Args { + if !declaration.Args[i].IsArith { + phpRemoveTemplateFromTypeDecl(&declaration.Args[i].T, template, newTypeRef) + } + } + } +} + var TypeComparator = func(a, b *TypeRWWrapper) int { return strings.Compare(a.goGlobalName, b.goGlobalName) } diff --git a/internal/tlcodegen/tlgen_php.go b/internal/tlcodegen/tlgen_php.go index e5107cf..9b62f34 100644 --- a/internal/tlcodegen/tlgen_php.go +++ b/internal/tlcodegen/tlgen_php.go @@ -13,8 +13,9 @@ type PhpClassMeta struct { } const ( - PHPFileStart = "\n" + PHPFileStart = " Date: Tue, 17 Dec 2024 11:40:30 +0300 Subject: [PATCH 23/26] php rpc stuff --- internal/tlcodegen/tlgen.go | 68 ++++++++++++++++++++++++++-- internal/tlcodegen/tlgen_php.go | 21 +++++---- internal/tlcodegen/type_rw.go | 22 +++++++++ internal/tlcodegen/type_rw_struct.go | 6 +++ internal/tlcodegen/type_rw_union.go | 9 ++++ 5 files changed, 111 insertions(+), 15 deletions(-) diff --git a/internal/tlcodegen/tlgen.go b/internal/tlcodegen/tlgen.go index e08eb8a..9b6a17c 100644 --- a/internal/tlcodegen/tlgen.go +++ b/internal/tlcodegen/tlgen.go @@ -912,19 +912,61 @@ func GenerateCode(tl tlast.TL, options Gen2Options) (*Gen2, error) { } if gen.options.Language == "php" { - // CHANGE ALL GENERIC FUNCTIONS + // RPC SPECIAL CHANGES + const rpcRequestResultName = "ReqResult" + rpcResultsMapping := map[string]string{ + "reqError": "rpcResponseError", + "reqResultHeader": "rpcResponseHeader", + "_": "rpcResponseOk", + } + rpcRemovedTypes := map[string]bool{ + "rpcReqResult": true, + "rpcReqError": true, + "rpcInvokeReq": true, + } rpcFunctionTypeRef := tlast.TypeRef{ Type: tlast.Name{ Name: PHPRPCFunctionMock, }, - Bare: false, } rpcFunctionResultTypeRef := tlast.TypeRef{ Type: tlast.Name{ Name: PHPRPCFunctionResultMock, }, - Bare: false, } + rpcResponseTypeRef := tlast.TypeRef{ + Type: tlast.Name{ + Name: PHPRPCResponseMock, + }, + } + // TODO: RETURN ORIGINAL COMBINATOR + tl = append(tl, &tlast.Combinator{ + TypeDecl: tlast.TypeDeclaration{ + Name: tlast.Name{ + Name: "ReqResult", + }, + Arguments: []string{"X"}, + }, + Construct: tlast.Constructor{ + Name: tlast.Name{Name: "_"}, + }, + TemplateArguments: []tlast.TemplateArgument{ + { + FieldName: "X", + IsNat: false, + }, + }, + Fields: []tlast.Field{ + { + FieldName: "result", + FieldType: tlast.TypeRef{ + Type: tlast.Name{ + Name: "X", + }, + }, + }, + }, + }) tl = append(tl, &tlast.Combinator{ TypeDecl: tlast.TypeDeclaration{ Name: rpcFunctionTypeRef.Type, @@ -939,9 +981,25 @@ func GenerateCode(tl tlast.TL, options Gen2Options) (*Gen2, error) { }) for _, typ := range tl { if typ.IsFunction && len(typ.TemplateArguments) == 1 { - phpRemoveTemplateFromGenericFunction(typ, &rpcFunctionTypeRef, &rpcFunctionResultTypeRef) + phpRemoveTemplateFromGeneric(typ, &rpcFunctionTypeRef, &rpcFunctionResultTypeRef) + } else if !typ.IsFunction && + rpcResultsMapping[typ.Construct.Name.String()] != "" && + typ.TypeDecl.Name.String() == rpcRequestResultName { + typ.Construct.Name.Name = rpcResultsMapping[typ.Construct.Name.String()] + typ.TypeDecl = tlast.TypeDeclaration{Name: rpcResponseTypeRef.Type} + phpRemoveTemplateFromGeneric(typ, &rpcFunctionResultTypeRef, &rpcFunctionResultTypeRef) } } + var removedTypesIndecies []int + for i, typ := range tl { + if rpcRemovedTypes[typ.Construct.Name.String()] { + removedTypesIndecies = append(removedTypesIndecies, i) + } + } + sort.Ints(removedTypesIndecies) + for i, index := range removedTypesIndecies { + tl = append(tl[:index-i], tl[index-i+1:]...) + } } for i, typ := range tl { // replace built-in @@ -1276,7 +1334,7 @@ func GenerateCode(tl tlast.TL, options Gen2Options) (*Gen2, error) { return gen, nil } -func phpRemoveTemplateFromGenericFunction(combinator *tlast.Combinator, newTypeRef, newTypeResultRef *tlast.TypeRef) { +func phpRemoveTemplateFromGeneric(combinator *tlast.Combinator, newTypeRef, newTypeResultRef *tlast.TypeRef) { template := combinator.TemplateArguments[0].FieldName combinator.TemplateArguments = nil for i := range combinator.Fields { diff --git a/internal/tlcodegen/tlgen_php.go b/internal/tlcodegen/tlgen_php.go index 9b62f34..b62bac7 100644 --- a/internal/tlcodegen/tlgen_php.go +++ b/internal/tlcodegen/tlgen_php.go @@ -16,6 +16,7 @@ const ( PHPFileStart = " Date: Tue, 17 Dec 2024 15:47:31 +0300 Subject: [PATCH 24/26] php rpc methods --- internal/tlcodegen/tlgen.go | 1 + internal/tlcodegen/tlgen_php.go | 25 +- internal/tlcodegen/type_rw_struct.go | 445 +++++++++++++++++---------- internal/tlcodegen/type_rw_union.go | 10 +- 4 files changed, 292 insertions(+), 189 deletions(-) diff --git a/internal/tlcodegen/tlgen.go b/internal/tlcodegen/tlgen.go index 9b6a17c..ac78f73 100644 --- a/internal/tlcodegen/tlgen.go +++ b/internal/tlcodegen/tlgen.go @@ -990,6 +990,7 @@ func GenerateCode(tl tlast.TL, options Gen2Options) (*Gen2, error) { phpRemoveTemplateFromGeneric(typ, &rpcFunctionResultTypeRef, &rpcFunctionResultTypeRef) } } + // TODO DELETE AS NORMAL PEOPLE var removedTypesIndecies []int for i, typ := range tl { if rpcRemovedTypes[typ.Construct.Name.String()] { diff --git a/internal/tlcodegen/tlgen_php.go b/internal/tlcodegen/tlgen_php.go index b62bac7..2454db4 100644 --- a/internal/tlcodegen/tlgen_php.go +++ b/internal/tlcodegen/tlgen_php.go @@ -3,7 +3,6 @@ package tlcodegen import ( "fmt" "path/filepath" - "reflect" "strings" ) @@ -34,9 +33,6 @@ func (gen *Gen2) generateCodePHP(generateByteVersions []string) error { createdTypes := make(map[string]bool) for _, wrapper := range gen.generatedTypesList { - if wrapper.tlName.String() == "rpcResponseOk" { - print(wrapper.trw.PhpClassName(true, true)) - } if createdTypes[wrapper.trw.PhpClassName(true, true)] { continue } @@ -78,14 +74,6 @@ func phpGenerateCodeForWrapper(gen *Gen2, wrapper *TypeRWWrapper, createdTypes m } } - fmt.Printf("TL[%[1]s] = Go {%[2]s, %[4]s} -> PHP {%[3]s, %[5]s}\n", - wrapper.tlName.String(), - wrapper.goGlobalName, - wrapper.trw.PhpClassName(true, true), - reflect.TypeOf(wrapper.trw), - wrapper.trw.PhpTypeName(true, true), - ) - filepathParts := []string{"VK"} //filepathParts = append(filepathParts, wrapper.PHPTypePathElements()...) path := fmt.Sprintf("%s.php", wrapper.trw.PhpClassName(true, createInterfaceIfNeeded)) @@ -155,3 +143,16 @@ func PHPGetAllReachableTypes(startTypes []*TypeRWWrapper) map[*TypeRWWrapper]boo } return reachable } + +func PHPSpecialMembersTypes(wrapper *TypeRWWrapper) string { + if wrapper.tlName.String() == PHPRPCFunctionMock { + return "TL\\RpcFunction" + } + if wrapper.tlName.String() == PHPRPCFunctionResultMock { + return "TL\\RpcFunctionReturnResult" + } + if wrapper.tlName.String() == PHPRPCResponseMock { + return "TL\\RpcResponse" + } + return "" +} diff --git a/internal/tlcodegen/type_rw_struct.go b/internal/tlcodegen/type_rw_struct.go index f013b34..a66de0b 100644 --- a/internal/tlcodegen/type_rw_struct.go +++ b/internal/tlcodegen/type_rw_struct.go @@ -587,13 +587,7 @@ func (trw *TypeRWStruct) PhpClassNameReplaced() bool { } func (trw *TypeRWStruct) PhpClassName(withPath bool, bare bool) string { - if trw.wr.tlName.String() == PHPRPCFunctionMock { - return "" - } - if trw.wr.tlName.String() == PHPRPCFunctionResultMock { - return "" - } - if trw.wr.tlName.String() == PHPRPCResponseMock { + if PHPSpecialMembersTypes(trw.wr) != "" { return "" } unionParent := trw.PhpConstructorNeedsUnion() @@ -638,14 +632,8 @@ func (trw *TypeRWStruct) PhpClassName(withPath bool, bare bool) string { } func (trw *TypeRWStruct) PhpTypeName(withPath bool, bare bool) string { - if trw.wr.tlName.String() == PHPRPCFunctionMock { - return "TL\\RpcFunction" - } - if trw.wr.tlName.String() == PHPRPCFunctionResultMock { - return "TL\\RpcFunctionReturnResult" - } - if trw.wr.tlName.String() == PHPRPCResponseMock { - return "TL\\RpcResponse" + if specialCase := PHPSpecialMembersTypes(trw.wr); specialCase != "" { + return specialCase } unionParent := trw.PhpConstructorNeedsUnion() if unionParent == nil { @@ -661,62 +649,11 @@ func (trw *TypeRWStruct) PhpTypeName(withPath bool, bare bool) string { } func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) error { - unionParent := trw.PhpConstructorNeedsUnion() + trw.PHPStructHeader(code) + trw.PHPStructFieldMasks(code) + trw.PHPStructFields(code) + trw.PHPStructResultType(code) - if isUsingTLImport(trw) || - trw.ResultType != nil || - unionParent != nil { - code.WriteString("\nuse VK\\TL;\n") - } - code.WriteString(` -/** - * @kphp-tl-class - */ -`) - code.WriteString(fmt.Sprintf("class %s ", trw.PhpClassName(false, true))) - if unionParent != nil { - code.WriteString(fmt.Sprintf("implements %s ", unionParent.trw.PhpClassName(true, false))) - } - if trw.ResultType != nil { - code.WriteString(fmt.Sprintf("implements TL\\RpcFunction ")) - } - code.WriteString("{\n") - // print fieldmasks - for _, f := range trw.Fields { - if f.fieldMask == nil { - continue - } - code.WriteString( - fmt.Sprintf( - ` - /** Field mask for $%[1]s field */ - const BIT_%[2]s_%[3]d = (1 << %[3]d); -`, - f.originalName, - strings.ToUpper(f.originalName), - f.BitNumber, - ), - ) - } - // print fields declarations - for _, f := range trw.Fields { - if "logs2_setDictionary" == trw.PhpClassName(false, true) { - print("debug") - } - fieldType, defaultValue := fieldTypeAndDefaultValue(f) - code.WriteString( - fmt.Sprintf( - ` - /** @var %[1]s */ - public $%[2]s = %[3]s; -`, - fieldType, - f.originalName, - defaultValue, - ), - ) - } - // print constructor necessaryFieldsInConstructor := make([]Field, 0) usedFieldMasksIndecies := make([]int, 0) usedFieldMasks := make(map[int][]Field) @@ -739,48 +676,110 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro usedFieldMasks[index] = append(usedFieldMasks[index], f) } } - // print result type for function + + trw.PHPStructConstructor(code, necessaryFieldsInConstructor) + trw.PHPStructRPCSpecialGetters(code) + trw.PHPStructFieldMaskCalculators(code, usedFieldMasksIndecies, usedFieldMasks) + trw.PHPStructFunctionSpecificMethods(code) + + code.WriteString("\n}\n") + + trw.PHPStructFunctionSpecificTypes(code) + return nil +} + +func (trw *TypeRWStruct) PHPStructFunctionSpecificTypes(code *strings.Builder) { if trw.ResultType != nil { code.WriteString( fmt.Sprintf( ` - /** Allows kphp implicitly load function result class */ - private const RESULT = %s_result::class; +/** + * @kphp-tl-class + */ +class %[1]s_result implements TL\RpcFunctionReturnResult { + + /** @var %[2]s */ + public $value = %[3]s; + +} `, - trw.PhpClassName(true, true), + trw.PhpClassName(false, true), + phpResultType(trw), + trw.ResultType.trw.PhpDefaultValue(), ), ) } - // print constructor - code.WriteString(` - /** -`) - for _, f := range necessaryFieldsInConstructor { - fieldType, _ := fieldTypeAndDefaultValue(f) - code.WriteString(fmt.Sprintf(" * @param %[1]s $%[2]s\n", fieldType, f.originalName)) - } - if len(necessaryFieldsInConstructor) == 0 { - code.WriteString(" * @kphp-inline\n") - } +} - code.WriteString(` */ -`) - code.WriteString(" public function __construct(") +func (trw *TypeRWStruct) PHPStructFunctionSpecificMethods(code *strings.Builder) { + // print function specific methods and types + if trw.ResultType != nil { + kphpSpecialCode := "" + if trw.wr.HasAnnotation("kphp") { + kphpSpecialCode = fmt.Sprintf( + ` - for i, f := range necessaryFieldsInConstructor { - _, defaultValue := fieldTypeAndDefaultValue(f) - if i != 0 { - code.WriteString(", ") + /** + * @param %[1]s $value + * @return %[2]s_result + */ + public static function createRpcServerResponse($value) { + $response = new %[2]s_result(); + $response->value = $value; + return $response; + }`, + trw.ResultType.trw.PhpTypeName(true, true), + trw.PhpClassName(true, true), + ) } - code.WriteString(fmt.Sprintf("$%[1]s = %[2]s", f.originalName, defaultValue)) - } - code.WriteString(") {\n") - for _, f := range necessaryFieldsInConstructor { - code.WriteString(fmt.Sprintf(" $this->%[1]s = $%[1]s;\n", f.originalName)) + code.WriteString( + fmt.Sprintf( + ` + /** + * @param TL\RpcFunctionReturnResult $function_return_result + * @return %[4]s + */ + public static function functionReturnValue($function_return_result) { + if ($function_return_result instanceof %[1]s_result) { + return $function_return_result->value; + } + warning('Unexpected result type in functionReturnValue: ' . ($function_return_result ? get_class($function_return_result) : 'null')); + return (new %[1]s_result())->value; + } + + /** + * @kphp-inline + * + * @param TL\RpcResponse $response + * @return %[4]s + */ + public static function result(TL\RpcResponse $response) { + return self::functionReturnValue($response->getResult()); + }%[5]s + + /** + * @kphp-inline + * + * @return string + */ + public function getTLFunctionName() { + return '%[3]s'; + } +`, + trw.PhpClassName(false, true), + trw.PhpClassName(true, true), + trw.wr.tlName.String(), + phpResultType(trw), + kphpSpecialCode, + ), + ) + } - code.WriteString(" }\n") +} +func (trw *TypeRWStruct) PHPStructFieldMaskCalculators(code *strings.Builder, usedFieldMasksIndecies []int, usedFieldMasks map[int][]Field) { + // print methods to calculate fieldmasks // fix order names := utils.MapSlice(usedFieldMasksIndecies, func(natIndex int) string { natName := "" @@ -803,7 +802,6 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro fieldNameToFieldOrder[trw.Fields[i].originalName] = i } - // print methods to calculate fieldmasks for _, name := range names { natIndex := namesToIndices[name] natName := name @@ -830,10 +828,6 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro ), ) - if trw.PhpClassName(false, true) == "test_namesCheck" { - print("debug") - } - fields := usedFieldMasks[natIndex] sort.Slice(fields, func(i, j int) bool { if fields[i].BitNumber == fields[j].BitNumber { @@ -903,99 +897,212 @@ func (trw *TypeRWStruct) PhpGenerateCode(code *strings.Builder, bytes bool) erro code.WriteString("\n return $mask;\n") code.WriteString(" }\n") } +} - // print function specific methods and types - if trw.ResultType != nil { - kphpSpecialCode := "" - if trw.wr.HasAnnotation("kphp") { - kphpSpecialCode = fmt.Sprintf( - ` - +func (trw *TypeRWStruct) PHPStructConstructor(code *strings.Builder, necessaryFieldsInConstructor []Field) { + // print constructor + code.WriteString(` /** - * @param %[1]s $value - * @return %[2]s_result - */ - public static function createRpcServerResponse($value) { - $response = new %[2]s_result(); - $response->value = $value; - return $response; - }`, - trw.ResultType.trw.PhpTypeName(true, true), - trw.PhpClassName(true, true), - ) +`) + for _, f := range necessaryFieldsInConstructor { + fieldType, _ := fieldTypeAndDefaultValue(f) + code.WriteString(fmt.Sprintf(" * @param %[1]s $%[2]s\n", fieldType, f.originalName)) + } + if len(necessaryFieldsInConstructor) == 0 { + code.WriteString(" * @kphp-inline\n") + } + + code.WriteString(` */ +`) + code.WriteString(" public function __construct(") + + for i, f := range necessaryFieldsInConstructor { + _, defaultValue := fieldTypeAndDefaultValue(f) + if i != 0 { + code.WriteString(", ") } + code.WriteString(fmt.Sprintf("$%[1]s = %[2]s", f.originalName, defaultValue)) + } + + code.WriteString(") {\n") + for _, f := range necessaryFieldsInConstructor { + code.WriteString(fmt.Sprintf(" $this->%[1]s = $%[1]s;\n", f.originalName)) + } + code.WriteString(" }\n") +} - if trw.PhpClassName(false, true) == "healthLoyalty_tmpBuyShopItem2" { - print("debug") +func (trw *TypeRWStruct) PHPStructRPCSpecialGetters(code *strings.Builder) { + if unionParent := trw.wr.PHPUnionParent(); unionParent == nil || PHPSpecialMembersTypes(unionParent) == "" { + return + } + + const ThisType = "__this" + type SpecialField struct { + Name string + Type string + Default string + NullTypeIfNullValue bool + AddHasMethod bool + } + + fields := []SpecialField{ + { + "result", + "TL\\RpcFunctionReturnResult", + "null", + true, + false, + }, + { + "header", + ThisType, + "null", + true, + false, + }, + { + "error", + ThisType, + "null", + true, + true, + }, + } + + containsSuchField := func(name, ifTrue, ifFalse string) string { + for _, field := range trw.Fields { + if field.originalName == name { + return ifTrue + } } + return ifFalse + } - code.WriteString( - fmt.Sprintf( - ` + for _, field := range fields { + returnObject := field.Default + returnType := field.Default + if field.Type == ThisType && + strings.Contains(strings.ToLower(trw.PhpClassName(false, true)), strings.ToLower(field.Name)) { + returnObject = "$this" + returnType = trw.PhpTypeName(true, true) + } else { + if field.Type != ThisType { + returnObject = "$this->" + field.Name + returnType = field.Type + } + if field.NullTypeIfNullValue { + returnType = containsSuchField(field.Name, returnType, "null") + returnObject = containsSuchField(field.Name, returnObject, "null") + } + } + if field.AddHasMethod { + code.WriteString( + fmt.Sprintf( + ` /** - * @param TL\RpcFunctionReturnResult $function_return_result - * @return %[4]s + * @return bool */ - public static function functionReturnValue($function_return_result) { - if ($function_return_result instanceof %[1]s_result) { - return $function_return_result->value; - } - warning('Unexpected result type in functionReturnValue: ' . ($function_return_result ? get_class($function_return_result) : 'null')); - return (new %[1]s_result())->value; + public function is%[1]s() { + return %[2]s; } - - /** - * @kphp-inline - * - * @param TL\RpcResponse $response - * @return %[4]s - */ - public static function result(TL\RpcResponse $response) { - return self::functionReturnValue($response->getResult()); - }%[5]s - +`, + ToUpperFirst(field.Name), + containsSuchField(field.Name, "true", "false"), + ), + ) + } + code.WriteString( + fmt.Sprintf( + ` /** - * @kphp-inline - * - * @return string + * @return %[3]s */ - public function getTLFunctionName() { - return '%[3]s'; + public function get%[1]s() { + return %[2]s; } `, - trw.PhpClassName(false, true), - trw.PhpClassName(true, true), - trw.wr.tlName.String(), - phpResultType(trw), - kphpSpecialCode, + ToUpperFirst(field.Name), + returnObject, + returnType, ), ) - } +} - code.WriteString("\n}\n") - +func (trw *TypeRWStruct) PHPStructResultType(code *strings.Builder) { + // print result type for function if trw.ResultType != nil { code.WriteString( fmt.Sprintf( ` -/** - * @kphp-tl-class - */ -class %[1]s_result implements TL\RpcFunctionReturnResult { - - /** @var %[2]s */ - public $value = %[3]s; + /** Allows kphp implicitly load function result class */ + private const RESULT = %s_result::class; +`, + trw.PhpClassName(true, true), + ), + ) + } +} +func (trw *TypeRWStruct) PHPStructFields(code *strings.Builder) { + // print fields declarations + for _, f := range trw.Fields { + fieldType, defaultValue := fieldTypeAndDefaultValue(f) + code.WriteString( + fmt.Sprintf( + ` + /** @var %[1]s */ + public $%[2]s = %[3]s; +`, + fieldType, + f.originalName, + defaultValue, + ), + ) + } } + +func (trw *TypeRWStruct) PHPStructFieldMasks(code *strings.Builder) { + // print fieldmasks + for _, f := range trw.Fields { + if f.fieldMask == nil { + continue + } + code.WriteString( + fmt.Sprintf( + ` + /** Field mask for $%[1]s field */ + const BIT_%[2]s_%[3]d = (1 << %[3]d); `, - trw.PhpClassName(false, true), - phpResultType(trw), - trw.ResultType.trw.PhpDefaultValue(), + f.originalName, + strings.ToUpper(f.originalName), + f.BitNumber, ), ) } - return nil +} + +func (trw *TypeRWStruct) PHPStructHeader(code *strings.Builder) { + unionParent := trw.PhpConstructorNeedsUnion() + + if isUsingTLImport(trw) || + trw.ResultType != nil || + unionParent != nil { + code.WriteString("\nuse VK\\TL;\n") + } + code.WriteString(` +/** + * @kphp-tl-class + */ +`) + code.WriteString(fmt.Sprintf("class %s ", trw.PhpClassName(false, true))) + if unionParent != nil { + code.WriteString(fmt.Sprintf("implements %s ", unionParent.trw.PhpClassName(true, false))) + } + if trw.ResultType != nil { + code.WriteString(fmt.Sprintf("implements TL\\RpcFunction ")) + } + code.WriteString("{\n") } func phpResultType(trw *TypeRWStruct) string { diff --git a/internal/tlcodegen/type_rw_union.go b/internal/tlcodegen/type_rw_union.go index 9f2029b..89f9587 100644 --- a/internal/tlcodegen/type_rw_union.go +++ b/internal/tlcodegen/type_rw_union.go @@ -196,14 +196,8 @@ func (trw *TypeRWUnion) PhpClassNameReplaced() bool { } func (trw *TypeRWUnion) PhpClassName(withPath bool, bare bool) string { - if trw.wr.tlName.String() == PHPRPCFunctionMock { - return "TL\\RpcFunction" - } - if trw.wr.tlName.String() == PHPRPCFunctionResultMock { - return "TL\\RpcFunctionReturnResult" - } - if trw.wr.tlName.String() == PHPRPCResponseMock { - return "TL\\RpcResponse" + if specialCase := PHPSpecialMembersTypes(trw.wr); specialCase != "" { + return specialCase } name := trw.wr.tlName.Name if len(trw.wr.tlName.Namespace) != 0 { From af74804929c86d60135550e8915b4e6e988b4c60 Mon Sep 17 00:00:00 2001 From: Fedor Vikhnin Date: Tue, 17 Dec 2024 15:52:52 +0300 Subject: [PATCH 25/26] 0% diff --- internal/tlcodegen/tlgen_php.go | 3 +++ internal/tlcodegen/type_rw.go | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/internal/tlcodegen/tlgen_php.go b/internal/tlcodegen/tlgen_php.go index 2454db4..0fd798b 100644 --- a/internal/tlcodegen/tlgen_php.go +++ b/internal/tlcodegen/tlgen_php.go @@ -33,6 +33,9 @@ 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 } diff --git a/internal/tlcodegen/type_rw.go b/internal/tlcodegen/type_rw.go index 6143891..c4f99a5 100644 --- a/internal/tlcodegen/type_rw.go +++ b/internal/tlcodegen/type_rw.go @@ -584,7 +584,7 @@ func (w *TypeRWWrapper) PHPIsPrimitiveType() bool { } if struct_, isStruct := core.trw.(*TypeRWStruct); isStruct { isDict, _, _, valueType := isDictionaryElement(struct_.wr) - if isDict { + if isDict && struct_.wr.tlName.Namespace == "" { return valueType.t.PHPIsPrimitiveType() } } From a887d5d6ed3d5fa1af7f75667f78ef03e5b4ec64 Mon Sep 17 00:00:00 2001 From: Fedor Vikhnin Date: Mon, 23 Dec 2024 13:30:09 +0300 Subject: [PATCH 26/26] linter fixes --- internal/tlcodegen/tlgen_php.go | 4 ++-- internal/tlcodegen/type_rw_struct.go | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/tlcodegen/tlgen_php.go b/internal/tlcodegen/tlgen_php.go index 0fd798b..22a32f5 100644 --- a/internal/tlcodegen/tlgen_php.go +++ b/internal/tlcodegen/tlgen_php.go @@ -127,14 +127,14 @@ func (gen *Gen2) PhpMarkAllInternalTypes() { internalReachable := PHPGetAllReachableTypes(internalFunctions) nonInternalReachable := PHPGetAllReachableTypes(nonInternalFunctions) - for wrapper, _ := range internalReachable { + for wrapper := range internalReachable { if !nonInternalReachable[wrapper] { wrapper.phpInfo.UsedOnlyInInternal = true } wrapper.phpInfo.UsedInFunctions = true } - for wrapper, _ := range nonInternalReachable { + for wrapper := range nonInternalReachable { wrapper.phpInfo.UsedInFunctions = true } } diff --git a/internal/tlcodegen/type_rw_struct.go b/internal/tlcodegen/type_rw_struct.go index a66de0b..01cf477 100644 --- a/internal/tlcodegen/type_rw_struct.go +++ b/internal/tlcodegen/type_rw_struct.go @@ -1100,7 +1100,7 @@ func (trw *TypeRWStruct) PHPStructHeader(code *strings.Builder) { code.WriteString(fmt.Sprintf("implements %s ", unionParent.trw.PhpClassName(true, false))) } if trw.ResultType != nil { - code.WriteString(fmt.Sprintf("implements TL\\RpcFunction ")) + code.WriteString("implements TL\\RpcFunction ") } code.WriteString("{\n") } @@ -1111,7 +1111,7 @@ func phpResultType(trw *TypeRWStruct) string { func toPhpFieldMaskName(natName string) string { parts := strings.Split(natName, "_") - for i, _ := range parts { + for i := range parts { parts[i] = ToUpperFirst(parts[i]) } return strings.Join(parts, "") @@ -1171,7 +1171,7 @@ func (trw *TypeRWStruct) PhpConstructorNeedsUnion() (unionParent *TypeRWWrapper) if trw.ResultType == nil { if trw.wr.unionParent != nil { return trw.wr.unionParent.wr - } else if strings.ToLower(trw.wr.tlName.Name) != strings.ToLower(trw.wr.origTL[0].TypeDecl.Name.Name) { + } else if !strings.EqualFold(trw.wr.tlName.Name, trw.wr.origTL[0].TypeDecl.Name.Name) { // NOTE: constructor name is not same as type => type can become union in future? return trw.wr }