Skip to content

Commit dcfbcac

Browse files
authored
Merge pull request #8 from xp-lang/feature/init-blocks
Replace __init() function with init { } block
2 parents f3392bb + a8d253f commit dcfbcac

File tree

3 files changed

+39
-5
lines changed

3 files changed

+39
-5
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ To verify constructor parameters, add an initialization block as follows:
4848
use lang\IllegalArgumentException;
4949

5050
record Range(int $lo, int $hi) {
51-
public function __init() {
51+
init {
5252
if ($this->lo > $this->hi) {
5353
throw new IllegalArgumentException('Lower border may not exceed upper border');
5454
}

src/main/php/lang/ast/syntax/php/Records.class.php

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,24 @@ public function setup($language, $emitter) {
6666
$parse->expecting('}', 'record');
6767

6868
if (isset($body['__construct()'])) {
69-
$parse->raise('Records cannot have a constructor, use __init()', 'record', $line);
69+
$parse->raise('Records cannot have a constructor, use init { }', 'record', $line);
7070
}
7171

7272
return new RecordDeclaration([], $type, $components, $parent, $implements, $body, null, $comment, $line);
7373
});
7474

75+
// Initializer block
76+
$language->body('init', function($parse, &$body, $meta, $modifiers, $holder) {
77+
$line= $parse->token->line;
78+
$parse->forward();
79+
80+
$parse->expecting('{', 'initializer block');
81+
$statements= $this->statements($parse);
82+
$parse->expecting('}', 'initializer block');
83+
84+
$body['<init>']= $statements;
85+
});
86+
7587
$emitter->transform('record', function($codegen, $node) {
7688
$body= $node->body;
7789
$string= $object= $value= '';
@@ -99,8 +111,14 @@ public function setup($language, $emitter) {
99111
$value.= ', $value->'.$c->name;
100112
}
101113

102-
// Create constructor, inlining __init()
103-
if (isset($body['__init()'])) {
114+
// Create constructor, inlining <init>. Also support deprecated __init() function
115+
if (isset($body['<init>'])) {
116+
foreach ($body['<init>'] as $statement) {
117+
$constructor->body[]= $statement;
118+
}
119+
unset($body['<init>']);
120+
} else if (isset($body['__init()'])) {
121+
trigger_error('Use init { } instead', E_USER_DEPRECATED);
104122
foreach ($body['__init()']->body as $statement) {
105123
$constructor->body[]= $statement;
106124
}

src/test/php/lang/ast/syntax/php/unittest/RecordsTest.class.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,19 @@ public function can_use_typed_varargs() {
121121
Assert::equals([1, 2, 3], $p->members());
122122
}
123123

124+
#[Test]
125+
public function can_have_init_block() {
126+
$t= $this->type('record <T>(int $lo, int $hi) {
127+
public $initialized= false;
128+
129+
init {
130+
$this->initialized= true;
131+
}
132+
}');
133+
Assert::true($t->newInstance(1, 2)->initialized);
134+
}
135+
136+
/** @deprecated */
124137
#[Test]
125138
public function can_have_init_function() {
126139
$t= $this->type('record <T>(int $lo, int $hi) {
@@ -131,8 +144,10 @@ public function __init() {
131144
}
132145
}');
133146
Assert::true($t->newInstance(1, 2)->initialized);
147+
\xp::gc();
134148
}
135149

150+
/** @deprecated */
136151
#[Test]
137152
public function init_function_does_not_conflict_with_initializer_block() {
138153
$t= $this->type('record <T>(int $lo, int $hi) {
@@ -144,12 +159,13 @@ public function __init() {
144159
}
145160
}');
146161
Assert::true($t->getField('NONE')->get(null)->initialized);
162+
\xp::gc();
147163
}
148164

149165
#[Test, Expect(class: IllegalArgumentException::class, withMessage: 'lo > hi!')]
150166
public function can_verify() {
151167
$t= $this->type('record <T>(int $lo, int $hi) {
152-
public function __init() {
168+
init {
153169
if ($this->lo > $this->hi) {
154170
throw new \\lang\\IllegalArgumentException("lo > hi!");
155171
}

0 commit comments

Comments
 (0)