Skip to content

Commit 8381d0f

Browse files
committed
Simplify
1 parent 2fee65f commit 8381d0f

7 files changed

Lines changed: 105 additions & 50 deletions

File tree

src/TL_file_ref_map_schema.tl

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
// Root
2-
fileReferenceOrigins#45a1a693 db_schema:string db_schema_json:string ctxs:Vector<Origin> skipped:Vector<SkippedOrigin>= FileReferenceOrigins;
2+
fileReferenceOrigins#63adca68 db_schema:string db_schema_json:string origins:Vector<Origin> skipped:Vector<SkippedOrigin> actions:Vector<Action> = FileReferenceOrigins;
33

4-
origin#24443b33 flags:# predicate:string is_constructor:flags.0?true action:ActionOp stored_constructor:string skipped_flags:Vector<string> needs_parent:flags.3?string parent_is_constructor:flags.4?true = origin;
4+
origin#b62177bf flags:# predicate:string is_constructor:flags.0?true stored_constructor:string stored_params:Vector<FieldExtractor> skipped_flags:Vector<string> needs_parent:flags.3?string parent_is_constructor:flags.4?true = origin;
55

66
skippedOrigin#7c62809e flags:# predicate:string is_constructor:flags.0?true why:string = SkippedOrigin;
77

8-
// Actions
9-
callOp#c2ff3383 method:string args:Vector<TypedOpArg> = ActionOp;
10-
getMessageOp#84b69f70 flags:# peer:TypedOp id:TypedOp from_scheduled:flags.0?TypedOp = ActionOp;
11-
12-
// For string => TypedOp dictionaries
13-
typedOpArg#3a2930c2 key:string value:TypedOp = TypedOpArg;
8+
action#9539f410 stored_constructor:string action:ActionOp = Action;
149

1510
// Field extraction path
1611
paramNotFlag#acd9d5cf = ParamFlag;
@@ -23,7 +18,7 @@ pathPart#7b8b07d4 flags:# constructor:string param:string flag:ParamFlag = PathP
2318
path#0c3586a2 parts:Vector<PathPart> = Path;
2419
pathParent#58f13684 parts:Vector<PathPart> = Path;
2520

26-
// Extractor+storer
21+
// Extractor
2722
extractAndStore#72069549 from:Path to:string = FieldExtractor;
2823

2924
extractInputStickerSetFromDocumentAttributesAndStore#369d8d14 from:Path to:string = FieldExtractor;
@@ -38,17 +33,24 @@ extractChannelIdFromInputChannelAndStore#b662660e from:Path to:string = FieldExt
3833
extractUserIdFromUserAndStore#4778ec63 from:Path to:string = FieldExtractor;
3934
extractUserIdFromInputUserAndStore#7720aa2e from:Path to:string = FieldExtractor;
4035

36+
// Actions
37+
callOp#c2ff3383 method:string args:Vector<TypedOpArg> = ActionOp;
38+
getMessageOp#84b69f70 flags:# peer:TypedOp id:TypedOp from_scheduled:flags.0?TypedOp = ActionOp;
39+
40+
// For string => TypedOp dictionaries
41+
typedOpArg#3a2930c2 key:string value:TypedOp = TypedOpArg;
42+
4143
// Typed constructors, the type is specified to simplify codegen,
4244
// but isn't strictly necessary as it can be inferred from the TypedOpOp.
4345
// It is fully pre-validated during the generation of the definition file.
4446
typedOp#705b10ec type:string op:TypedOpOp = TypedOp;
4547

4648
// The actual ops
47-
copyOp#1630c9f5 from:FieldExtractor = TypedOpOp;
49+
copyOp#f48f418f from:string = TypedOpOp;
4850

49-
getInputChannelByIdOp#3eb8d855 from:FieldExtractor = TypedOpOp;
50-
getInputUserByIdOp#a3a4e6c2 from:FieldExtractor = TypedOpOp;
51-
getInputPeerByIdOp#acfb2a4a from:FieldExtractor = TypedOpOp;
51+
getInputChannelByIdOp#3cb47531 from:string = TypedOpOp;
52+
getInputUserByIdOp#c0ee4326 from:string = TypedOpOp;
53+
getInputPeerByIdOp#19813750 from:string = TypedOpOp;
5254

5355
// Literals & constructors (methods not allowed or needed here)
5456
constructorOp#107f8d8a constructor:string args:Vector<TypedOpArg> = TypedOpOp;

src/file_ref_map.dat

-1.99 KB
Binary file not shown.

src/file_ref_map.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tools/FileRefExtractor/BuildMode/Ast.php

Lines changed: 74 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,17 @@
3030

3131
final class Ast implements BuildMode
3232
{
33-
/** @var array<string, array{name: string, type: string}> */
34-
public array $stored = [];
3533
/** @var array<string, string> */
36-
public array $storedNames = [];
34+
public array $storedByPath = [];
35+
/** @var array<string, array{type: string, extractor: array}> */
36+
public array $stored = [];
3737
public int $storedFlags = 0;
3838

3939
public ?string $curKey = null;
4040

4141
private array $output = [];
4242
private array $skipped = [];
43+
private array $actions = [];
4344
private ?string $needsParent = null;
4445

4546
public function __construct(
@@ -63,12 +64,21 @@ public function finalize(string $refMapFile, string $refMapFileJson): void
6364
$dbSchema .= self::stringifySchema($constructor, $params)."\n";
6465
}
6566
$dbSchemaJSON = (new TL(null))->toJson($dbSchema);
67+
68+
$actions = [];
69+
foreach ($this->actions as $action) {
70+
if ($action['action']['_'] === 'callOp') {
71+
$action['action']['args'] = array_values($action['action']['args']);
72+
}
73+
$actions[] = $action;
74+
}
6675
$value = [
6776
'_' => 'fileReferenceOrigins',
6877
'db_schema' => $dbSchema,
6978
'db_schema_json' => json_encode($dbSchemaJSON, flags: JSON_THROW_ON_ERROR),
70-
'ctxs' => $this->output,
79+
'origins' => $this->output,
7180
'skipped' => $this->skipped,
81+
'actions' => $actions,
7282
];
7383
Magic::start(false);
7484

@@ -78,8 +88,6 @@ public function finalize(string $refMapFile, string $refMapFileJson): void
7888
$TL->init($s);
7989
$serialized = $TL->serializeObject(['type' => 'FileReferenceOrigins'], $value, '');
8090
$valueDe = $TL->deserialize($serialized, ['type' => '', 'connection' => null, 'encrypted' => true]);
81-
file_put_contents('/tmp/a.json', json_encode($valueDe, flags: JSON_THROW_ON_ERROR));
82-
file_put_contents('/tmp/b.json', json_encode($value, flags: JSON_THROW_ON_ERROR));
8391
Assert::true($value == $valueDe);
8492
file_put_contents($refMapFile, $serialized);
8593
file_put_contents($refMapFileJson, json_encode($valueDe, flags: JSON_THROW_ON_ERROR));
@@ -114,17 +122,17 @@ public function addNode(TLContext $ctx, ?array $action = null, ?string $why = nu
114122
$constructor = $action['stored_constructor'];
115123
unset($action['stored_constructor']);
116124

117-
$names = $this->storedNames;
125+
$stored = $this->stored;
118126
$flags = [];
119127
if ($this->storedFlags) {
120-
foreach ($names as $name => $type) {
128+
foreach ($stored as $name => ['type' => $type]) {
121129
if (str_starts_with($type, 'flags.')) {
122130
$flags[$name] = $type;
123131
}
124132
}
125-
$names = [
126-
'flags' => '#',
127-
...$names,
133+
$stored = [
134+
'flags' => ['type' => '#'],
135+
...$stored,
128136
];
129137
}
130138
$skipped = [];
@@ -134,7 +142,7 @@ public function addNode(TLContext $ctx, ?array $action = null, ?string $why = nu
134142
foreach ($existing as $name => $type) {
135143
if (str_starts_with($type, 'flags.')) {
136144
if (isset($flags[$name])) {
137-
unset($flags[$name], $names[$name]);
145+
unset($flags[$name], $stored[$name]);
138146
} else {
139147
$skipped[]= $name;
140148
}
@@ -144,29 +152,74 @@ public function addNode(TLContext $ctx, ?array $action = null, ?string $why = nu
144152
throw new AssertionError("Have leftover flags: ".implode(' ', $flags));
145153
}
146154
foreach ($existing as $name => $type) {
147-
if (isset($names[$name])) {
148-
if ($names[$name] === $type) {
149-
unset($names[$name]);
155+
if (isset($stored[$name])) {
156+
if ($stored[$name]['type'] === $type) {
157+
unset($stored[$name]);
150158
} else {
151-
throw new AssertionError("Type mismatch for $constructor.$name: have {$names[$name]}, need $type");
159+
throw new AssertionError("Type mismatch for $constructor.$name: have {$stored[$name]['type']}, need $type");
152160
}
153161
} elseif (!str_starts_with($type, 'flags.') && $name !== 'flags') {
154162
throw new AssertionError("Missing pre-existing parameter $constructor.$name for $constructor");
155163
}
156164
}
157-
foreach ($names as $name => $type) {
165+
foreach ($stored as $name => ['type' => $type]) {
158166
throw new AssertionError("Leftover parameter $constructor.$name:$type for ".self::stringifySchema($constructor, $existing));
159167
}
160168
} else {
161-
$this->outputSchema[$constructor] = $names;
169+
$types = [];
170+
foreach ($stored as $name => ['type' => $type]) {
171+
$types[$name] = $type;
172+
}
173+
$this->outputSchema[$constructor] = $types;
174+
}
175+
176+
if (isset($this->actions[$constructor])) {
177+
$existingAction = $this->actions[$constructor];
178+
Assert::eq($constructor, $existingAction['stored_constructor']);
179+
$existingAction = $existingAction['action'];
180+
Assert::eq($existingAction['_'], $action['_']);
181+
182+
// It's okay to fill missing params as the source of the data is always the same,
183+
// aka the source_constructor will always be of the same type, it should have all
184+
// needed flags, and the behavior will be consistent.
185+
if ($action['_'] === 'getMessageOp') {
186+
if (!isset($existingAction['from_scheduled']) && isset($action['from_scheduled'])) {
187+
$existingAction['from_scheduled'] = $action['from_scheduled'];
188+
} elseif (isset($existingAction['from_scheduled']) && !isset($action['from_scheduled'])) {
189+
$action['from_scheduled'] = $existingAction['from_scheduled'];
190+
}
191+
} else {
192+
Assert::eq($action['_'], 'callOp');
193+
foreach ($action['args'] as $k => $arg) {
194+
Assert::string($k);
195+
if (!isset($existingAction['args'][$arg['key']])) {
196+
$existingAction['args'][$arg['key']] = $arg;
197+
}
198+
}
199+
foreach ($existingAction['args'] as $k => $arg) {
200+
Assert::string($k);
201+
if (!isset($action['args'][$arg['key']])) {
202+
$action['args'][$arg['key']] = $arg;
203+
}
204+
}
205+
}
206+
Assert::eq($existingAction, $action, "Mismatched actions for $constructor");
207+
208+
$this->actions[$constructor]['action'] = $existingAction;
209+
} else {
210+
$this->actions[$constructor] = [
211+
'_' => 'action',
212+
'stored_constructor' => $constructor,
213+
'action' => $action,
214+
];
162215
}
163216

164217
$out = [
165218
'_' => 'origin',
166219
'predicate' => $ctx->position,
167220
'is_constructor' => $ctx->isConstructor,
168-
'action' => $action,
169221
'stored_constructor' => $constructor,
222+
'stored_params' => array_column($this->stored, 'extractor'),
170223
'skipped_flags' => $skipped,
171224
'parent_is_constructor' => false,
172225
];
@@ -178,7 +231,7 @@ public function addNode(TLContext $ctx, ?array $action = null, ?string $why = nu
178231

179232
$this->storedFlags = 0;
180233
$this->stored = [];
181-
$this->storedNames = [];
234+
$this->storedByPath = [];
182235
Assert::null($why);
183236
} elseif ($why !== null) {
184237
$this->skipped[] = [
@@ -189,7 +242,7 @@ public function addNode(TLContext $ctx, ?array $action = null, ?string $why = nu
189242
];
190243
Assert::null($action);
191244
Assert::isEmpty($this->stored);
192-
Assert::isEmpty($this->storedNames);
245+
Assert::isEmpty($this->storedByPath);
193246
Assert::eq($this->storedFlags, 0);
194247
} else {
195248
throw new AssertionError("Either 'action' or 'why' must be provided.");

tools/FileRefExtractor/Ops/CallOp.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public function build(TLContext $tl): void
7171
$tl->validateParams($this->method, false, $this->args);
7272
$types = [];
7373
foreach ($this->args as $from => $to) {
74-
$final[] = ['_' => 'typedOpArg', 'key' => $from, 'value' => $tl->build($to, $from)];
74+
$final[$from] = ['_' => 'typedOpArg', 'key' => $from, 'value' => $tl->build($to, $from)];
7575
$types[$from] = $to->getType($tl);
7676
}
7777

tools/FileRefExtractor/Path.php

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public function normalize(array $stack, string $current, bool $ignoreFlag): ?sel
8585
);
8686
}
8787

88-
public function buildPath(TLContext $tl, string $extractor): array
88+
public function buildPath(TLContext $tl, string $extractor): string
8989
{
9090
$new = [];
9191
foreach ($this->path as $k => $part) {
@@ -116,9 +116,9 @@ public function buildPath(TLContext $tl, string $extractor): array
116116
}
117117
$new[] = $newPart;
118118
}
119-
$serialized = $extractor.json_encode($new, flags: JSON_THROW_ON_ERROR);
120-
if (isset($tl->buildMode->stored[$serialized])) {
121-
$name = $tl->buildMode->stored[$serialized]['name'];
119+
$serialized = json_encode([$extractor, $this->isFromParent, $new], flags: JSON_THROW_ON_ERROR);
120+
if (isset($tl->buildMode->storedByPath[$serialized])) {
121+
$name = $tl->buildMode->storedByPath[$serialized];
122122
} else {
123123
$isFlag = $newPart['flag']['_'] === 'paramIsFlagPassthrough';
124124
$type = $this->getType($tl);
@@ -157,23 +157,23 @@ public function buildPath(TLContext $tl, string $extractor): array
157157
}
158158
$name = $tl->buildMode->curKey;
159159
Assert::notNull($name);
160-
if (isset($tl->buildMode->storedNames[$name])) {
160+
if (isset($tl->buildMode->stored[$name])) {
161161
throw new AssertionError("Need custom name (already have $name) for ".json_encode($this->path));
162162
}
163-
$tl->buildMode->storedNames[$name] = $type;
164-
$tl->buildMode->stored[$serialized] = [
165-
'name' => $name,
163+
$tl->buildMode->stored[$name] = [
166164
'type' => $type,
165+
'extractor' => [
166+
'_' => $extractor,
167+
'from' => ['_' => $this->isFromParent ? 'pathParent': 'path', 'parts' => $new],
168+
'to' => $name,
169+
],
167170
];
171+
$tl->buildMode->storedByPath[$serialized] = $name;
168172
}
169173
if ($this->isFromParent) {
170174
$tl->buildMode->setNeedsParent($this->path[0][0]);
171175
}
172-
return [
173-
'_' => $extractor,
174-
'from' => ['_' => $this->isFromParent ? 'pathParent': 'path', 'parts' => $new],
175-
'to' => $name,
176-
];
176+
return $name;
177177
}
178178
public function getType(TLContext $tl): string
179179
{

0 commit comments

Comments
 (0)