diff --git a/src/Builtin/BuiltinFunc/Cap.php b/src/Builtin/BuiltinFunc/Cap.php index abaddad63..ad6b9933e 100644 --- a/src/Builtin/BuiltinFunc/Cap.php +++ b/src/Builtin/BuiltinFunc/Cap.php @@ -6,8 +6,10 @@ use GoPhp\Argv; use GoPhp\Error\RuntimeError; +use GoPhp\GoType\ArrayType; use GoPhp\GoValue\Array\ArrayValue; use GoPhp\GoValue\Int\IntValue; +use GoPhp\GoValue\PointerValue; use GoPhp\GoValue\Slice\SliceValue; use function GoPhp\assert_argc; @@ -25,17 +27,25 @@ public function __invoke(Argv $argv): IntValue { assert_argc($this, $argv, 1); - $v = $argv[0]; + $v = $argv[0]->value; - if ($v->value instanceof ArrayValue) { - return new IntValue($v->value->len()); + if ($v instanceof PointerValue && ($v->type()->pointsTo instanceof ArrayType)) { + if ($v->isNil()) { + return new IntValue(0); + } + + $v = $v->deref(); + } + + if ($v instanceof ArrayValue) { + return new IntValue($v->len()); } - if ($v->value instanceof SliceValue) { - return new IntValue($v->value->cap()); + if ($v instanceof SliceValue) { + return new IntValue($v->cap()); } - throw RuntimeError::wrongArgumentTypeForBuiltin($v->value, $this->name); + throw RuntimeError::wrongArgumentTypeForBuiltin($v, $this->name); } public function name(): string diff --git a/src/Builtin/BuiltinFunc/Len.php b/src/Builtin/BuiltinFunc/Len.php index ae35bc3b7..6ade17e16 100644 --- a/src/Builtin/BuiltinFunc/Len.php +++ b/src/Builtin/BuiltinFunc/Len.php @@ -6,7 +6,9 @@ use GoPhp\Argv; use GoPhp\Error\RuntimeError; +use GoPhp\GoType\ArrayType; use GoPhp\GoValue\Int\IntValue; +use GoPhp\GoValue\PointerValue; use GoPhp\GoValue\Sequence; use function GoPhp\assert_argc; @@ -26,6 +28,14 @@ public function __invoke(Argv $argv): IntValue $v = $argv[0]->value; + if ($v instanceof PointerValue && ($v->type()->pointsTo instanceof ArrayType)) { + if ($v->isNil()) { + return new IntValue(0); + } + + $v = $v->deref(); + } + if (!$v instanceof Sequence) { throw RuntimeError::wrongArgumentTypeForBuiltin($v, $this->name); } diff --git a/src/GoValue/Func/Func.php b/src/GoValue/Func/Func.php index f41bce6f0..3f3bad370 100644 --- a/src/GoValue/Func/Func.php +++ b/src/GoValue/Func/Func.php @@ -182,13 +182,13 @@ private function doBind(Environment $env): void } $boundInstance = $this->boundInstance instanceof PointerValue - ? $this->boundInstance->getPointsTo() + ? $this->boundInstance->deref() : $this->boundInstance; $receiverType = $this->receiver->type; if ($boundInstance instanceof PointerValue) { - $boundInstance = $boundInstance->getPointsTo(); + $boundInstance = $boundInstance->deref(); } if ($receiverType instanceof PointerType) { diff --git a/src/GoValue/Map/KeyValueTupleMap.php b/src/GoValue/Map/KeyValueTupleMap.php index aae37652d..c1b31d484 100644 --- a/src/GoValue/Map/KeyValueTupleMap.php +++ b/src/GoValue/Map/KeyValueTupleMap.php @@ -63,6 +63,10 @@ public function len(): int public function delete(Hashable&GoValue $at): void { unset($this->values[$at->hash()]); + + if ($this->len > 0) { + --$this->len; + } } public function iter(): iterable diff --git a/src/GoValue/PointerValue.php b/src/GoValue/PointerValue.php index 28f573b90..cc6c0f785 100644 --- a/src/GoValue/PointerValue.php +++ b/src/GoValue/PointerValue.php @@ -42,7 +42,7 @@ public function isNil(): bool return $this->pointsTo === NIL; } - public function getPointsTo(): AddressableValue + public function deref(): AddressableValue { if ($this->isNil()) { throw PanicError::nilDereference(); @@ -59,7 +59,7 @@ public function unwrap(): string public function operate(Operator $op): AddressableValue { return match ($op) { - Operator::Mul => $this->getPointsTo(), + Operator::Mul => $this->deref(), Operator::BitAnd => PointerValue::fromValue($this), default => throw RuntimeError::undefinedOperator($op, $this), }; diff --git a/src/Interpreter.php b/src/Interpreter.php index b90377b83..6dd1ca672 100644 --- a/src/Interpreter.php +++ b/src/Interpreter.php @@ -1516,7 +1516,7 @@ private function evalSelectorExpr(SelectorExpr $expr): GoValue $value = try_unwind($value); if ($value instanceof PointerValue) { - $value = $value->getPointsTo(); + $value = $value->deref(); $check = true; } } while ($check); diff --git a/tests/Functional/files/builtin.go b/tests/Functional/files/builtin.go index cf25b2b84..a1a56f472 100644 --- a/tests/Functional/files/builtin.go +++ b/tests/Functional/files/builtin.go @@ -3,6 +3,13 @@ package main func main() { test_copy() test_append() + test_delete() + test_new() + test_len() + test_cap() + test_make() + test_complex_real_imag() + test_print_println() } func test_copy() { @@ -53,3 +60,141 @@ func test_append() { s3 = append(s3, "str"...) println(len(s3), cap(s3), s3[0], s3[1], s3[2], s3[3], s3[4], s3[5], s3[6], s3[7]) } + +func test_delete() { + println("test_delete") + + // 1 + var s1 map[int]string = map[int]string{0: "A", 1: "B", 2: "C", 3: "D"} + delete(s1, 2) + println(len(s1), s1[0], s1[1], s1[2], s1[3]) + + // 2 + var s2 map[string]int = map[string]int{"A": 0, "B": 1, "C": 2, "D": 3} + delete(s2, "B") + delete(s2, "C") + println(len(s2), s2["A"], s2["B"], s2["C"], s2["D"]) +} + +func test_new() { + println("test_new") + + // 1 + var p1 *int = new(int) + *p1 = 5 + println(*p1) + + // 2 + var p2 *string = new(string) + *p2 = "Hello" + println(*p2) + + // 3 + var p3 *[]int = new([]int) + *p3 = []int{0, 1, 2} + println((*p3)[0], (*p3)[1], (*p3)[2]) +} + +func test_len() { + println("test_len") + + // 1 + var s1 []int = []int{0, 1, 2, 3} + println(len(s1)) + + // 2 + var s2 map[int]string = map[int]string{0: "A", 1: "B", 2: "C", 3: "D"} + println(len(s2)) + + // 3 + var s3 string = "Hello, world!" + println(len(s3)) + + // 4 + var s4 [5]int = [5]int{0, 1, 2, 3, 4} + println(len(s4)) + + // 5 + var s5 *[5]int = new([5]int) + println(len(s5)) + + // 6 + var s6 *[5]int = nil + println(len(s6)) +} + +func test_cap() { + println("test_cap") + + // 1 + var s1 []int = make([]int, 3, 5) + println(cap(s1)) + + // 2 + var s2 []int = nil + println(cap(s2)) + + // 3 + var s3 *[5]int = new([5]int) + println(cap(s3)) + + // 4 + var s4 *[5]int = nil + println(cap(s4)) + + // 4 + var s5 [5]int = [5]int{0, 1, 2, 3, 4} + println(cap(s5)) +} + +func test_complex_real_imag() { + println("test_complex") + + // 1 + var c1 complex64 = 5 + 6i + println(c1, real(c1), imag(c1)) + + // 2 + var c2 complex128 = 7 + 8i + println(real(c2), imag(c2)) + + // 3 + var c3 complex64 = complex(9, 10) + println(real(c3), imag(c3)) + + // 4 + var c4 complex128 = complex(11, 12) + println(real(c4), imag(c4)) +} + +func test_make() { + println("test_make") + + // 1 + var s1 []int = make([]int, 3) + println(len(s1), cap(s1)) + + // 2 + var s2 []string = make([]string, 3, 5) + println(len(s2), cap(s2)) + + // 3 + var s3 map[int]string = make(map[int]string) + println(len(s3)) + + // 4 + var s4 map[string]int = make(map[string]int, 3) + println(len(s4)) +} + +func test_print_println() { + println("test_print") + + print("Hello, ") + print("world!") + print("hello", "world", 1, 2, 3) + + println("Hello,-") + println("world!") + println("hello", "world", 1, 2, 3) +} diff --git a/tests/Functional/output/builtin.out b/tests/Functional/output/builtin.out index 63b0e414c..aaf571435 100644 --- a/tests/Functional/output/builtin.out +++ b/tests/Functional/output/builtin.out @@ -10,3 +10,37 @@ test_append 5 8 97 98 99 45 6 8 97 98 99 45 9 9 16 97 98 99 45 9 100 115 116 +test_delete +3 A B D +2 0 0 0 3 +test_new +5 +Hello +0 1 2 +test_len +4 +4 +13 +5 +5 +0 +test_cap +5 +0 +5 +0 +5 +test_make +3 3 +3 5 +0 +0 +test_complex +(+5.000000+6.000000) 5.000000 6.000000 +7.000000 8.000000 +9.000000 10.000000 +11.000000 12.000000 +test_print +Hello, world!helloworld123Hello,- +world! +hello world 1 2 3