Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: introduce snippet gen support #483

Merged
merged 41 commits into from
Oct 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
7f4ce33
feat: introduce snippet gen support
dwsupplee Sep 26, 2022
4352317
latest updates
dwsupplee Aug 8, 2022
8e353cf
continued progress on DRYing up SnippetGenerator / code formatting
dwsupplee Aug 12, 2022
6052107
small tweaks
dwsupplee Aug 12, 2022
a2c82a8
test out ShouldNotApplySemicolonInterface
dwsupplee Aug 12, 2022
037302e
quick regen of tests
dwsupplee Aug 12, 2022
bf93fa2
remove getters to match other *Details based implemenations/minor ref…
dwsupplee Aug 12, 2022
ac61aa2
change signature
dwsupplee Aug 12, 2022
31a28d0
test regen
dwsupplee Aug 12, 2022
1c97447
revent name change in GapicClientExamplesGenerator
dwsupplee Aug 12, 2022
4a403ca
refactor out nested ifs
dwsupplee Aug 12, 2022
a3192c9
remove kms from prototests
dwsupplee Sep 26, 2022
aa8dcb2
include line length fixer
dwsupplee Sep 26, 2022
9138763
utilize line length formatter
dwsupplee Sep 26, 2022
d3e7241
refactorings/cleanup
dwsupplee Sep 26, 2022
76817d5
refresh tests
dwsupplee Sep 26, 2022
150dfed
chore(deps): update dependency bazel_skylib to v1.3.0 (#512)
renovate-bot Sep 1, 2022
b81b2e6
chore(deps): update gax to v1.17 (#514)
noahdietz Sep 12, 2022
075b26b
chore(deps): update rules_proto digest to ea52a32 (#511)
renovate-bot Sep 12, 2022
09c9059
prevent generation of empty docblocks
dwsupplee Sep 26, 2022
2b4dede
Merge branch 'main' into snippet-gen
dwsupplee Sep 26, 2022
a4f3318
Update src/Ast/AST.php
dwsupplee Sep 29, 2022
6d799e2
help clarify when you would use a function vs a method
dwsupplee Sep 29, 2022
b170d1f
remove arrayOf hack for param type
dwsupplee Sep 29, 2022
3340662
add docblock to exampleValue
dwsupplee Sep 29, 2022
c35e9d3
add todo on fixer
dwsupplee Sep 29, 2022
2c84d8e
refactor printf helper
dwsupplee Sep 29, 2022
991ca43
sample line length 80 -> 100
dwsupplee Sep 29, 2022
8982301
add comment regarding skip functionality
dwsupplee Sep 29, 2022
772de18
append a message to resource field description
dwsupplee Sep 29, 2022
7ce73b6
update prototests
dwsupplee Sep 29, 2022
758144f
modified approach for helper message
dwsupplee Sep 29, 2022
b177fbe
refresh tests
dwsupplee Sep 29, 2022
dafdfcb
cleaner approach
dwsupplee Sep 29, 2022
d7e472f
Update src/Generation/FieldDetails.php
dwsupplee Sep 29, 2022
c82c24b
refresh tests
dwsupplee Sep 29, 2022
ec366d4
append message using PhpDoc::preFormattedText instead of PhpDoc::text
dwsupplee Oct 5, 2022
5f05265
address regional endpoints/iam
dwsupplee Oct 5, 2022
5616adc
update call sample verbiage
dwsupplee Oct 5, 2022
558c94c
update goldens
dwsupplee Oct 5, 2022
a77aef8
add generated notice to main sample docblock when no callSample exists
dwsupplee Oct 6, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@
"require": {
"php": "^7.4 || ^8.0",
"google/protobuf": "^3.18",
"friendsofphp/php-cs-fixer": "^2.16",
"symfony/yaml": "^5.2"
"friendsofphp/php-cs-fixer": "^3",
"symfony/yaml": "^5.2",
"symplify/coding-standard": "9.3.26"
},
"require-dev": {
"phpunit/phpunit": "^9.5",
Expand Down
148 changes: 114 additions & 34 deletions src/Ast/AST.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,25 @@ abstract class AST
/** @var string Constant to reference `preg_match`. */
public const PREG_MATCH = "\0preg_match";

/** @var string Constant to reference `printf`. */
public const PRINT_F = "\0printf";

protected static function deref($obj): string
{
return $obj === static::SELF || $obj instanceof ResolvedType ? '::' : '->';
}

protected static function toPhp($x, &$omitSemicolon = false): string
{
$omitSemicolon = false;
if ($x instanceof ShouldNotApplySemicolonInterface) {
$omitSemicolon = true;
}

if (is_string($x)) {
if (strncmp($x, "\0", 1) === 0) {
// \0 prefix means the string that follows is used verbatim.
return substr($x, 1);
} elseif (substr($x, 0, 2) === '//') {
} elseif (substr($x, 0, 2) === '//' || $x === PHP_EOL) {
// '//' prefix means a comment.
$omitSemicolon = true;
return $x;
Expand Down Expand Up @@ -114,11 +120,11 @@ protected function clone(callable $fnOnClone)
/**
* Create a PHP file.
*
* @param PhpClass $class The class to be contained within this file.
* @param ?PhpClass $class The class to be contained within this file.
*
* @return PhpFile
*/
public static function file(PhpClass $class): PhpFile
public static function file(?PhpClass $class): PhpFile
{
return new PhpFile($class);
}
Expand All @@ -127,6 +133,7 @@ public static function file(PhpClass $class): PhpFile
* Create a class.
*
* @param Type $type The type of the class to create.
* @param ?ResolvedType $extends
*
* @return PhpClass
*/
Expand Down Expand Up @@ -171,6 +178,19 @@ public static function method(string $name): PhpMethod
return new PhpMethod($name);
}

/**
* Create a function.
*
* @param string $name The name of the function.
* @param bool $appendNewline Whether a newline should be appended to the end of the function declaration.
*
* @return PhpFunction
*/
public static function fn(string $name, bool $appendNewline = true): PhpFunction
{
return new PhpFunction($name, $appendNewline);
}

/**
* Create a parameter.
*
Expand Down Expand Up @@ -208,20 +228,33 @@ public static function comment(PhpDoc $comment): PhpComment
*/
public static function block(...$code): AST
{
$code = Vector::new($code)
->flatten()
->filter(fn ($x) => !is_null($x));
return new class($code) extends AST {
public function __construct($code)
return new PhpBlock($code);
}

/**
* Creates an inline variable comment.
*
* @param ResolvedType $type
* @param Variable $var
* @param string $comment
*
* @return Expression
*/
public static function inlineVarDoc(ResolvedType $type, Variable $var, string $comment = null): Expression
{
return new class($type, $var, $comment) extends Expression {
public function __construct(ResolvedType $type, Variable $var, string $comment = null)
{
$this->code = $code;
$this->type = $type;
$this->var = $var;
$this->comment = $comment;
}
public function toCode(): string
{
$omitSemicolon = false;
return $this->code
->map(fn ($x) => static::toPhp($x, $omitSemicolon) . ($omitSemicolon ? '' : ';') . "\n")
->join();
if ($this->comment) {
$this->comment = ' ' . $this->comment;
}
return "/** @var {$this->type->toCode()} {$this->var->toCode()}{$this->comment} */";
}
};
}
Expand Down Expand Up @@ -351,6 +384,9 @@ public function toCode(): string
$items = $isAssocArray ?
$this->keyValues->map(fn ($x) => static::toPhp($x[0]) . ' => ' . static::toPhp($x[1])) :
$this->keyValues->map(fn ($x) => static::toPhp($x[1]));
if (count($items) === 1 && substr($items[0], 0, 4) === 'new ') {
return "{$items}";
}
$itemsStr = $items->map(fn ($x) => "{$x},\n")->join();
$firstNl = count($items) === 0 ? '' : "\n";
return "[{$firstNl}{$itemsStr}]";
Expand Down Expand Up @@ -423,12 +459,12 @@ public function toCode(): string
}

/**
* Create an expression to call a method. This method returns a Callable into which the args are passed.
* Create an expression to call a method. This method returns a callable into which the args are passed.
*
* @param mixed $obj The object containing the method to call; or a built-in function.
* @param mixed $callee The method to call; or null if calling a built-in function.
*
* @return Callable The returned Callable returns an Expression once called with callee args.
* @return callable The returned callable returns an Expression once called with callee args.
*/
public static function call($obj, $callee = null): callable
{
Expand All @@ -448,21 +484,56 @@ public function toCode(): string
// Handle calling a function directly on a constructor.
// We assume that a constructor call will always start with `new `.
$objCode = static::toPhp($this->obj);
$calleeOnNewline = false;
if (substr($objCode, 0, 4) === 'new ') {
$objCode = '(' . $objCode . ')';
$calleeOnNewline = true;
} elseif (substr($objCode, 0, 5) === '(new ') {
$calleeOnNewline = true;
}
return $objCode . static::deref($this->obj) . static::toPhp($this->callee) . "({$args})";

return $objCode .
($calleeOnNewline ? PHP_EOL : null) .
static::deref($this->obj) .
static::toPhp($this->callee) .
"({$args})";
}
}
};
}

/**
* Create an object instantiation expression. This method returns a Callable into which the args are passed.
* Create an expression to call a static method. This method returns a callable into which the args are passed.
*
* @param ResolvedType $type The object type to intantiate the call from.
* @param mixed $callee The method to call.
*
* @return callable The returned callable returns an Expression once called with callee args.
*/
public static function staticCall(ResolvedType $type, $callee): callable
{
return fn (...$args) => new class($type, $callee, $args) extends Expression {
public function __construct($type, $callee, $args)
{
$this->type = $type;
$this->callee = $callee;
$this->args = Vector::new($args)->flatten();
}

public function toCode(): string
{
$args = $this->args->map(fn ($x) => static::toPhp($x))->join(', ');
return static::toPhp($this->type) . '::' . static::toPhp($this->callee) . "({$args})";
}
};
}

/**
* Create an object instantiation expression. This method returns a callable into which the args are passed.
*
* @param ResolvedType $type The type to instantiate.
*
* @return Callable The returned Callable returns an Expression once called with callee args.
* @return callable The returned callable returns an Expression once called with callee args.
*/
public static function new(ResolvedType $type): callable
{
Expand All @@ -472,6 +543,7 @@ public function __construct($type, $args)
$this->type = $type;
$this->args = $args;
}

public function toCode(): string
{
$args = $this->args->map(fn ($x) => static::toPhp($x))->join(', ');
Expand Down Expand Up @@ -576,18 +648,20 @@ public function toCode(): string
* Create an if statement.
*
* @param Expression $expr The conditional expression for the if statement.
* @param bool $appendNewline Whether a newline should be appended to the end of the statement.
*
* @return AST
*/
public static function if(Expression $expr): AST
public static function if(Expression $expr, bool $appendNewline = true): AST
{
return new class($expr) extends AST {
public function __construct($expr)
return new class($expr, $appendNewline) extends AST implements ShouldNotApplySemicolonInterface {
public function __construct($expr, $appendNewline)
{
$this->expr = $expr;
$this->then = null;
$this->elseif = Vector::new([]);
$this->else = null;
$this->appendNewline = $appendNewline;
}
public function then(...$code)
{
Expand All @@ -614,9 +688,15 @@ public function toCode(): string
" else {\n" .
static::toPhp($this->else) . "\n" .
"}";
return 'if (' . static::toPhp($this->expr) . ") {\n" .
$code = 'if (' . static::toPhp($this->expr) . ") {\n" .
static::toPhp($this->then) . "\n" .
"}{$elseif}{$else}\n";
"}{$elseif}{$else}";

if ($this->appendNewline) {
$code .= "\n";
}

return $code;
}
};
}
Expand Down Expand Up @@ -649,15 +729,15 @@ public function toCode(): string
}

/**
* Create a while statement. This method returns a Callable into which the loop code is passed.
* Create a while statement. This method returns a callable into which the loop code is passed.
*
* @param Expression $condition The condition checked at the top of the while loop.
*
* @return Callable The returned Callable returns a while statement once called with the loop code.
* @return callable The returned callable returns a while statement once called with the loop code.
*/
public static function while(Expression $condition): callable
{
return fn (...$code) => new class($condition, $code) extends AST {
return fn (...$code) => new class($condition, $code) extends AST implements ShouldNotApplySemicolonInterface {
public function __construct($condition, $code)
{
$this->condition = $condition;
Expand All @@ -667,23 +747,23 @@ public function toCode(): string
{
return 'while (' . static::toPhp($this->condition) . ") {\n" .
static::toPhp($this->code) .
"}\n";
"\n}\n";
}
};
}

/**
* Create a foreach statement. This method returns a Callable into which the foreach body code is passed.
* Create a foreach statement. This method returns a callable into which the foreach body code is passed.
*
* @param Expression $expr The expression to foreach over.
* @param Variable $var The variable into which each element is placed.
* @param Variable $indexVar Optional; The index variable, if required.
*
* @return Callable The returned Callable returns a foreach statement once called with the foreach body code.
* @return callable The returned callable returns a foreach statement once called with the foreach body code.
*/
public static function foreach(Expression $expr, Variable $var, ?Variable $indexVar = null): callable
{
return fn (...$code) => new class($expr, $var, $indexVar, $code) extends AST {
return fn (...$code) => new class($expr, $var, $indexVar, $code) extends AST implements ShouldNotApplySemicolonInterface {
public function __construct($expr, $var, $indexVar, $code)
{
$this->expr = $expr;
Expand All @@ -696,7 +776,7 @@ public function toCode(): string
$index = is_null($this->indexVar) ? '' : (static::toPhp($this->indexVar) . ' => ');
return 'foreach (' . static::toPhp($this->expr) . ' as ' . $index . static::toPhp($this->var) . ") {\n" .
static::toPhp($this->code) .
"}\n";
"\n}\n";
}
};
}
Expand All @@ -710,7 +790,7 @@ public function toCode(): string
*/
public static function try(...$tryCode): AST
{
return new class($tryCode) extends AST {
return new class($tryCode) extends AST implements ShouldNotApplySemicolonInterface {
public function __construct($tryCode)
{
$this->tryCode = AST::block(...$tryCode);
Expand All @@ -735,7 +815,7 @@ public function toCode(): string
(is_null($this->catch) ? '' : 'catch (' .
static::toPhp($this->catch[0]) . ' ' . static::toPhp($this->catch[1]) . ") {\n" .
static::toPhp($this->catch[2]) . "\n}") .
(is_null($this->finallyCode) ? '' : "finally {\n" . static::toPhp($this->finallyCode) . "\n}");
(is_null($this->finallyCode) ? '' : "finally {\n" . static::toPhp($this->finallyCode) . "\n}" . PHP_EOL);
}
};
}
Expand Down
2 changes: 1 addition & 1 deletion src/Ast/HasPhpDoc.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public function withPhpDoc(PhpDoc $phpDoc): self
*
* @return self
*/
public function WithPhpDocText(string $summaryText): self
public function withPhpDocText(string $summaryText): self
{
return $this->withPhpDoc(PhpDoc::block(PhpDoc::text($summaryText)));
}
Expand Down
48 changes: 48 additions & 0 deletions src/Ast/PhpBlock.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php
/*
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
declare(strict_types=1);

namespace Google\Generator\Ast;

use Google\Generator\Collections\Vector;

final class PhpBlock extends AST implements ShouldNotApplySemicolonInterface
{
private $code;

public function __construct($code)
{
$code = Vector::new($code)
->flatten()
->filter(fn ($x) => !is_null($x));
$this->code = $code;
}

public function toCode(): string
{
$omitSemicolon = false;

return $this->code
->map(function ($x) use ($omitSemicolon) {
$end = $x instanceof PhpBlock
? ''
: PHP_EOL;
return static::toPhp($x, $omitSemicolon) . ($omitSemicolon ? '' : ';') . $end;
dwsupplee marked this conversation as resolved.
Show resolved Hide resolved
})
->join();
}
}
Loading