Skip to content
This repository was archived by the owner on Aug 25, 2025. It is now read-only.

Commit 632d490

Browse files
author
amarcu
committed
Initial Commit
1 parent db59c98 commit 632d490

File tree

80 files changed

+7658
-2
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

80 files changed

+7658
-2
lines changed

.hhconfig

Whitespace-only changes.

.travis.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
language: php
2+
php:
3+
- hhvm
4+
5+
script:
6+
- hh_client
7+
- hhvm test/run_tests.php
8+
- hhvm examples/dorm/codegen.php examples/dorm/demo/DormUserSchema.php

PATENTS

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
Additional Grant of Patent Rights Version 2
2+
3+
"Software" means Hack Codegen software distributed by Facebook, Inc.
4+
5+
Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software
6+
("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable
7+
(subject to the termination provision below) license under any Necessary
8+
Claims, to make, have made, use, sell, offer to sell, import, and otherwise
9+
transfer the Software. For avoidance of doubt, no license is granted under
10+
Facebook’s rights in any patent claims that are infringed by (i) modifications
11+
to the Software made by you or any third party or (ii) the Software in
12+
combination with any software or other technology.
13+
14+
The license granted hereunder will terminate, automatically and without notice,
15+
if you (or any of your subsidiaries, corporate affiliates or agents) initiate
16+
directly or indirectly, or take a direct financial interest in, any Patent
17+
Assertion: (i) against Facebook or any of its subsidiaries or corporate
18+
affiliates, (ii) against any party if such Patent Assertion arises in whole or
19+
in part from any software, technology, product or service of Facebook or any of
20+
its subsidiaries or corporate affiliates, or (iii) against any party relating
21+
to the Software. Notwithstanding the foregoing, if Facebook or any of its
22+
subsidiaries or corporate affiliates files a lawsuit alleging patent
23+
infringement against you in the first instance, and you respond by filing a
24+
patent infringement counterclaim in that lawsuit against that party that is
25+
unrelated to the Software, the license granted hereunder will not terminate
26+
under section (i) of this paragraph due to such counterclaim.
27+
28+
A "Necessary Claim" is a claim of a patent owned by Facebook that is
29+
necessarily infringed by the Software standing alone.
30+
31+
A "Patent Assertion" is any lawsuit or other action alleging direct, indirect,
32+
or contributory infringement or inducement to infringe any patent, including a
33+
cross-claim or counterclaim.

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,17 @@ To install this package via composer, just add the package to require and start
2525
```json
2626
{
2727
"require": {
28-
"facebook/hackcodegen": "*"
28+
"facebook/hack-codegen": "*"
2929
}
3030
}
3131
```
3232

3333
## Usage
34-
Include the autoload file generated by composer and you are set. For example:
34+
Include the autoload file generated by composer and you are ready to start using it.
35+
For example:
3536

3637
```php
38+
<?hh
3739
require 'vendor/autoload.php';
3840

3941
echo codegen_file('HelloWorld.php')

composer.json

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{
2+
"name": "facebook/hack-codegen",
3+
"description": "Hack Codegen is a library for programatically generating Hack code",
4+
"keywords": ["code generation", "Hack"],
5+
"require": {
6+
"hhvm": "*"
7+
},
8+
"type": "library",
9+
"autoload": {
10+
"files": [
11+
"lib/utils.php",
12+
"lib/Str.php",
13+
"lib/StrBuffer.php",
14+
"lib/Filesystem.php",
15+
"src/SignedSourceBase.php",
16+
"src/SignedSource.php",
17+
"src/PartiallyGeneratedSignedSource.php",
18+
"src/PartiallyGeneratedCode.php",
19+
"src/HackBuilderKeys.php",
20+
"src/HackBuilderValues.php",
21+
"src/IHackCodegenConfig.php",
22+
"src/HackCodegenConfig.php",
23+
"src/CodegenWithVisibility.php",
24+
"src/ICodeBuilderRenderer.php",
25+
"src/ICodeBuilder.php",
26+
"src/HackBuilderRenderer.php",
27+
"src/BaseCodeBuilder.php",
28+
"src/HackBuilder.php",
29+
"src/ICodegenFormatter.php",
30+
"src/CodegenClassBase.php",
31+
"src/CodegenClass.php",
32+
"src/CodegenFunctionBase.php",
33+
"src/CodegenMethodBase.php",
34+
"src/CodegenConstructor.php",
35+
"src/CodegenEnum.php",
36+
"src/CodegenFile.php",
37+
"src/CodegenFunction.php",
38+
"src/CodegenGeneratedFrom.php",
39+
"src/CodegenImplementsInterface.php",
40+
"src/CodegenInterface.php",
41+
"src/CodegenMemberVar.php",
42+
"src/CodegenMethod.php",
43+
"src/CodegenShape.php",
44+
"src/CodegenTrait.php",
45+
"src/CodegenType.php",
46+
"src/CodegenUsesTrait.php"
47+
]
48+
}
49+
}

examples/dorm/CodegenDorm.php

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
<?hh // strict
2+
/**
3+
* Copyright (c) 2015-present, Facebook, Inc.
4+
* All rights reserved.
5+
*
6+
* This source code is licensed under the BSD-style license found in the
7+
* LICENSE file in the root directory of this source tree. An additional grant
8+
* of patent rights can be found in the PATENTS file in the same directory.
9+
*/
10+
11+
/**
12+
* For a given DormSchema, this class generates code for a class
13+
* that will allow to read the data from a database and store it
14+
* in the object.
15+
*/
16+
class CodegenDorm {
17+
18+
public function __construct(
19+
private DormSchema $schema,
20+
) {}
21+
22+
private function getSchemaName(): string {
23+
$name = get_class($this->schema);
24+
return Str::endsWith($name, 'Schema')
25+
? Str::substr($name, 0, -6)
26+
: $name;
27+
}
28+
29+
public function generate(): void {
30+
// Here's an example of how to generate the code for a class.
31+
// Notice the fluent interface. It's possible to generate
32+
// everything in the same method, however, for clarity
33+
// sometimes it's easier to use helper methods such as
34+
// getConstructor or getLoad in this examples.
35+
$class = codegen_class($this->getSchemaName())
36+
->setIsFinal()
37+
->setConstructor($this->getConstructor())
38+
->addMethod($this->getLoad())
39+
->addMethods($this->getGetters());
40+
41+
$rc = new ReflectionClass(get_class($this->schema));
42+
$path = $rc->getFileName();
43+
$pos = strrpos($path, '/');
44+
$dir = substr($path, 0, $pos + 1);
45+
46+
// This generates a file (we pass the file name) that contains the
47+
// class defined above and saves it.
48+
// Using setGeneratedFrom adds in the clas docblock a reference
49+
// to the script that is used to generate the file.
50+
// Notice that saving the file includes also verifying the checksum
51+
// of the existing file and merging it if it's partially generated.
52+
codegen_file($dir.$this->getSchemaName().'.php')
53+
->addClass($class)
54+
->setGeneratedFrom(codegen_generated_from_script())
55+
->save();
56+
}
57+
58+
private function getConstructor(): CodegenConstructor {
59+
// Example of how to generate a constructor. Very similar
60+
// to generating a method, but using codegen_constructor()
61+
// doesn't require to set the name since it's always __constructor
62+
return codegen_constructor()
63+
->setPrivate()
64+
->addParameter('private Map<string, mixed> $data');
65+
}
66+
67+
private function getLoad(): CodegenMethod {
68+
$sql = 'select * from '.
69+
$this->schema->getTableName().
70+
' where '.$this->schema->getIdField().'=$id';
71+
72+
// Here's how to build a block of code using hack_builder.
73+
// Notice that some methods have a sprintf style of arguments
74+
// to make it easier to build expressions.
75+
// There are specific methods that make easier to write "if",
76+
// "foreach", etc. See HackBuilder documentation.
77+
$body = hack_builder()
78+
->addLine('$conn = new PDO(\'%s\');', $this->schema->getDsn())
79+
->add('$cursor = ')
80+
->addMultilineCall('$conn->query', Vector {"\"$sql\""}, true)
81+
->addLine('$result = $cursor->fetch(PDO::FETCH_ASSOC);')
82+
->startIfBlock('!$result')
83+
->addReturn('null')
84+
->endIfBlock()
85+
->addReturn('new %s(new Map($result))', $this->getSchemaName());
86+
87+
// Here's an example of how to generate a method. It's common when
88+
// the code in the method is not trivial to build it using hack_builder.
89+
// Notice how the parameter and the return type are set.
90+
return codegen_method('load')
91+
->setIsStatic()
92+
->addParameter('int $id')
93+
->setReturnType('?'.$this->getSchemaName())
94+
->setBody($body->getCode());
95+
}
96+
97+
private function getGetters(): Vector<CodegenMethod> {
98+
$methods = Vector {};
99+
foreach ($this->schema->getFields() as $name => $field) {
100+
$return_type = $field->getType();
101+
$data = '$this->data[\''.$field->getDbColumn().'\']';
102+
$return_data = $data;
103+
if ($return_type == 'DateTime') {
104+
$return_data = 'new DateTime('.$data.')';
105+
} else {
106+
$return_data = "($return_type) $data";
107+
}
108+
if ($field->isOptional()) {
109+
$return_type = '?'.$return_type;
110+
$builder = hack_builder();
111+
if ($field->isManual()) {
112+
// This part illustrates how to include a manual section, which the
113+
// user can edit and it will be kept even if the code is regenerated.
114+
// Notice that each section needs to have a unique name, since that's
115+
// used to match the section when re-generating the code
116+
$builder
117+
->beginManualSection($name)
118+
->addInlineComment('You may manually change this section of code');
119+
}
120+
// using addWithSuggestedLineBreaks will allow the code
121+
// to break automatically on long lines on the specified places.
122+
$builder->addWithSuggestedLineBreaks(
123+
"return isset($data)\t? $return_data\t: null;",
124+
);
125+
if ($field->isManual()) {
126+
// You always need to close a manual section
127+
$builder->endManualSection();
128+
}
129+
$body = $builder->getCode();
130+
} else {
131+
$body = 'return '.$return_data.';';
132+
}
133+
$methods[] = codegen_method('get'.$name)
134+
->setReturnType($return_type)
135+
->setBody($body);
136+
}
137+
return $methods;
138+
}
139+
}

0 commit comments

Comments
 (0)