Skip to content

Compile-time metaprogramming #327

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

Closed
thekid opened this issue Oct 31, 2017 · 2 comments
Closed

Compile-time metaprogramming #327

thekid opened this issue Oct 31, 2017 · 2 comments

Comments

@thekid
Copy link
Member

thekid commented Oct 31, 2017

Scope of Change

The XP Compiler will be extended to support compile-time metaprogramming

Rationale

Build libraries like xp-forge/partial into compiler.

Functionality

<<value>>
class Person {
  private int $id;
  private string $name;
}

The compiler finds an implementation which was previously registered via Transformations::register() for class nodes. The function gets executed and transforms the above to the following PHP:

class Person implements \lang\Value {
  private $id;
  private $name;

  public function __construct(int $id, string $name) {
    $this->id= $id;
    $this->name= $name;
  }

  public function id() { return $this->id; }

  public function name() { return $this->name; }

  // toString(), hashCode() and compareTo() omitted for brevity
}

Security considerations

Speed impact

Dependencies

xp-framework/compiler#19

Related documents

https://dzone.com/articles/compile-time-metaprogramming
http://groovy-lang.org/metaprogramming.html#_available_ast_transformations
http://groovy-lang.org/metaprogramming.html#developing-ast-xforms
http://notatube.blogspot.de/2010/12/project-lombok-creating-custom.html
xp-framework/compiler#15
https://wiki.php.net/rfc/parser-extension-api
microsoft/TypeScript#5595

@thekid thekid added the language label Nov 4, 2017
@thekid
Copy link
Member Author

thekid commented Nov 5, 2017

E.g. inside the partial library, using a convenience class instead of assembling the code using AST nodes.

Transformations::register('class', function($class) {
  if (array_key_exists('value', $class->value->annotations)) {
    $class->value->implements[]= '\lang\Value';

    foreach ($class->value->body as $type => $node) {
      if ('$' !== $type{0}) continue;
      $fields[]= $node->value->name;
    }

    $args= $init= [];
    foreach ($fields as $name) {
      $class->value->body[$name.'()']= new Code('public function '.$name.'() {
        return $this->'.$name.';
      }');
      $args[]= '$'.$name;
      $init[]= '$this->'.$name.'= $'.$name.';';
    }

    $class->value->body['__construct()']= new Code('public function __construct('.
      implode(', ', $args).') { '.implode('', $init).' }'
    );

    $class->value->body['toString()']= new Code('public function toString() {
      return nameof($this)."@".\util\Objects::stringOf(get_object_vars($this));
    }');
    $class->value->body['hashCode()']= new Code('public function hashCode() {
      return nameof($this);
    }');
    $class->value->body['compareTo()']= new Code('public function compareTo($value) {
      return 1;
    }');
  }
  return $class;
});
$ cat Demo.php
<?php

use util\cmd\Console;

<<value>>
class Demo {
  private string $id, $name;

  public static function main(array<string> $args) {
    Console::writeLine(new self(...$args));
  }
}

$ xp Demo 1549 Timm
Demo@[
  id => "1549"
  name => "Timm"
]

@thekid
Copy link
Member Author

thekid commented Nov 5, 2017

API is now far more concise:

use lang\ast\transform\Transformations;
use lang\ast\nodes\Method;
use lang\ast\nodes\Signature;
use lang\ast\Code;

Transformations::register('class', function($class) {
  if ($class->value->annotation('getters')) {
    foreach ($class->value->properties() as $property) {
      $class->value->inject(new Method(
        ['public'],
        $property->name,
        new Signature([], $property->type),
        [new Code('return $this->'.$property->name.';')]
      ));
    }
  }
  yield $class;
});

See https://github.com./xp-framework/ast

thekid added a commit to xp-framework/compiler that referenced this issue Nov 6, 2017
@thekid thekid closed this as completed Nov 6, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant