Skip to content
This repository has been archived by the owner on Sep 9, 2019. It is now read-only.

Feature: Variadics #50

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
50 changes: 30 additions & 20 deletions src/main/jay/grammars/php.jay
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ use xp\compiler\ast\DynamicInstanceOfNode;
use xp\compiler\ast\DynamicVariableReferenceNode;
use xp\compiler\ast\NoopNode;
use xp\compiler\ast\YieldNode;
use xp\compiler\ast\UnpackNode;
%}

%left ','
Expand Down Expand Up @@ -177,6 +178,7 @@ use xp\compiler\ast\YieldNode;
%token T_SHR 420
%token T_SHL 421
%token T_EXP 422
%token T_ELLIPSIS 423

%%

Expand Down Expand Up @@ -369,7 +371,7 @@ annotationmember:

annotationvalue:
literal
| T_NEW typename '(' expressionlist_opt ')' {
| T_NEW typename '(' arguments ')' {
$$= $yyLex->create(new InstanceCreationNode());
$$->type= $2;
$$->parameters= $4;
Expand Down Expand Up @@ -404,7 +406,9 @@ parameters:

parameter:
typeref T_VARIABLE initialization_opt { $$= array('name' => $2, 'type' => $1, 'check' => TRUE); $3 && $$['default']= $3; }
| typeref T_ELLIPSIS T_VARIABLE initialization_opt { $$= array('name' => $3, 'type' => $1, 'vararg' => TRUE, 'check' => TRUE); $4 && $$['default']= $4; }
| T_VARIABLE initialization_opt { $$= array('name' => $1, 'type' => new TypeName('var'), 'check' => FALSE); $2 && $$['default']= $2; }
| T_ELLIPSIS T_VARIABLE initialization_opt { $$= array('name' => $2, 'type' => new TypeName('var'), 'vararg' => TRUE, 'check' => FALSE); $3 && $$['default']= $3; }
;
// }}}

Expand Down Expand Up @@ -525,6 +529,17 @@ catch:
;
// }}}

arguments:
/* empty */ { $$= NULL; }
| argument { $$= [$1]; }
| argument ',' arguments { $$= $3 ? array_merge([$1], $3) : [$1]; }
;

argument:
T_ELLIPSIS expression { $$= new UnpackNode($2); }
| expression { $$= $1; }
;

// {{{ Expressions
expressionlist_opt:
/* empty */ { $$= NULL; }
Expand All @@ -542,12 +557,12 @@ expression_opt:
;

instancecreation:
typeref '(' expressionlist_opt ')' {
typeref '(' arguments ')' {
$$= new InstanceCreationNode();
$$->type= $1;
$$->parameters= $3;
}
| T_VARIABLE '(' expressionlist_opt ')' {
| T_VARIABLE '(' arguments ')' {
$$= new DynamicInstanceCreationNode();
$$->variable= $1;
$$->parameters= $3;
Expand All @@ -558,7 +573,7 @@ staticmember:
T_VARIABLE {
$$= new StaticMemberAccessNode(NULL, $1);
}
| T_WORD '(' expressionlist_opt ')' {
| T_WORD '(' arguments ')' {
$$= new StaticMethodCallNode(NULL, $1, $3);
}
| T_WORD {
Expand Down Expand Up @@ -596,7 +611,7 @@ expression:
$$= $4;
}
}
| T_WORD '(' { $2= $yyLex->create(new InvocationNode($1)); } expressionlist_opt ')' chain_opt {
| T_WORD '(' { $2= $yyLex->create(new InvocationNode($1)); } arguments ')' chain_opt {
$2->arguments= $4;
if ($6) {
$$= $6[0];
Expand Down Expand Up @@ -670,8 +685,8 @@ expression:
| '@' expression {
$$= $yyLex->create(new SilenceOperatorNode($2));
}
| T_FUNCTION '(' lambda_input ')' lambda_uses_opt '{' statements_opt '}' {
$$= $yyLex->create(new LambdaNode($3, (array)$7, $5));
| T_FUNCTION '(' parameters_opt ')' lambda_uses_opt '{' statements_opt '}' {
$$= $yyLex->create(new LambdaNode((array)$3, (array)$7, $5));
}
| '(' expression ')' chain_opt {
if ($4) {
Expand All @@ -683,25 +698,20 @@ expression:
}
;

lambda_input:
lambda_uses_opt:
/* empty */ { $$= array(); }
| lambda_input_parameters
| T_USE '(' lambda_uses ')' { $$= $3; }
;

lambda_input_parameters:
lambda_input_parameter { $$= array($1); }
| lambda_input_parameters ',' lambda_input_parameter { $$= array_merge($1, array($3)); }
lambda_uses:
lambda_use { $$= array($1); }
| lambda_uses ',' lambda_use { $$= array_merge($1, array($3)); }
;

lambda_input_parameter:
lambda_use:
T_VARIABLE initialization_opt { $$= array('name' => $1); $2 && $$['default']= $2; }
;

lambda_uses_opt:
/* empty */ { $$= array(); }
| T_USE '(' lambda_input_parameters ')' { $$= $3; }
;

literal:
scalar
| '[' { $p= $yyLex->position; } map_or_list ']' { $3->position= $p; $3->type= NULL; $$= $3; }
Expand Down Expand Up @@ -833,10 +843,10 @@ chain:
| T_OBJECT_OPERATOR '{' expression '}' {
$$= $yyLex->create(new DynamicVariableReferenceNode(NULL, $3));
}
| T_OBJECT_OPERATOR T_WORD '(' { $1= $yyLex->create(new MethodCallNode(NULL, $2)); } expressionlist_opt ')' {
| T_OBJECT_OPERATOR T_WORD '(' { $1= $yyLex->create(new MethodCallNode(NULL, $2)); } arguments ')' {
$1->arguments= $5;
}
| '(' { $1= $yyLex->create(new InstanceCallNode(NULL, NULL, FALSE)); } expressionlist_opt ')' {
| '(' { $1= $yyLex->create(new InstanceCallNode(NULL, NULL, FALSE)); } arguments ')' {
$1->arguments= $3;
}
;
Expand Down
30 changes: 21 additions & 9 deletions src/main/jay/grammars/xp.jay
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ use xp\compiler\ast\WithNode;
use xp\compiler\ast\ArmNode;
use xp\compiler\ast\BracedExpressionNode;
use xp\compiler\ast\YieldNode;
use xp\compiler\ast\UnpackNode;
%}

%left ','
Expand Down Expand Up @@ -126,7 +127,7 @@ use xp\compiler\ast\YieldNode;
%token T_OPERATOR 320
%token T_THROWS 321

%token T_DOTS 330
%token T_ELLIPSIS 330
%token T_AS 331
%token T_THIS 332
%token T_CONST 334
Expand Down Expand Up @@ -485,7 +486,7 @@ annotationmember:

annotationvalue:
literal
| T_NEW typename '(' expressionlist_opt ')' {
| T_NEW typename '(' arguments ')' {
$$= $yyLex->create(new InstanceCreationNode());
$$->type= $2;
$$->parameters= $4;
Expand Down Expand Up @@ -523,7 +524,7 @@ parameters:

parameter:
paramtyperef T_VARIABLE initialization_opt { $$= array_merge(array('name' => $2), $1); $3 && $$['default']= $3; }
| paramtyperef T_DOTS T_VARIABLE { $$= array_merge(array('name' => $3, 'vararg' => TRUE), $1); }
| paramtyperef T_ELLIPSIS T_VARIABLE { $$= array_merge(array('name' => $3, 'vararg' => TRUE), $1); }
| T_VARIABLE '.' T_WORD initialization_opt { $$= array('assign' => $3); $4 && $$['default']= $4; }
| T_VARIABLE initialization_opt { $$= array('name' => $1, 'type' => TypeName::$VAR, 'check' => FALSE); $2 && $$['default']= $2; }
;
Expand Down Expand Up @@ -721,6 +722,17 @@ finally:
;
// }}}

arguments:
/* empty */ { $$= NULL; }
| argument { $$= [$1]; }
| argument ',' arguments { $$= $3 ? array_merge([$1], $3) : [$1]; }
;

argument:
T_ELLIPSIS expression { $$= new UnpackNode($2); }
| expression { $$= $1; }
;

// {{{ Expressions
expressionlist_opt:
/* empty */ { $$= NULL; }
Expand All @@ -738,13 +750,13 @@ expression_opt:
;

instancecreation:
typename '(' expressionlist_opt ')' classbody_opt {
typename '(' arguments ')' classbody_opt {
$$= new InstanceCreationNode();
$$->type= $1;
$$->parameters= $3;
$$->body= $5;
}
| arraytype '{' expressionlist_opt '}' {
| arraytype '{' arguments '}' {
$$= new ArrayNode();
$$->type= $1;
$$->values= (array)$3;
Expand All @@ -760,7 +772,7 @@ staticmember:
T_VARIABLE {
$$= new StaticMemberAccessNode(NULL, $1);
}
| T_WORD '(' expressionlist_opt ')' {
| T_WORD '(' arguments ')' {
$$= new StaticMethodCallNode(NULL, $1, $3);
}
| T_WORD {
Expand Down Expand Up @@ -817,7 +829,7 @@ expression:
$$= $4;
}
}
| T_WORD '(' { $2= $yyLex->create(new InvocationNode($1)); } expressionlist_opt ')' chain_opt {
| T_WORD '(' { $2= $yyLex->create(new InvocationNode($1)); } arguments ')' chain_opt {
$2->arguments= $4;
if ($6) {
$$= $6[0];
Expand Down Expand Up @@ -1026,10 +1038,10 @@ chain:
| nav member {
$$= $yyLex->create(new MemberAccessNode(NULL, $2, $1));
}
| nav member '(' { $1= $yyLex->create(new MethodCallNode(NULL, $2, NULL, $1)); } expressionlist_opt ')' {
| nav member '(' { $1= $yyLex->create(new MethodCallNode(NULL, $2, NULL, $1)); } arguments ')' {
$1->arguments= $5;
}
| '(' { $1= $yyLex->create(new InstanceCallNode(NULL, NULL, FALSE)); } expressionlist_opt ')' {
| '(' { $1= $yyLex->create(new InstanceCallNode(NULL, NULL, FALSE)); } arguments ')' {
$1->arguments= $3;
}
;
Expand Down
26 changes: 26 additions & 0 deletions src/main/php/xp/compiler/ast/UnpackNode.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php namespace xp\compiler\ast;

/**
* Represents an argument to be unpacked
*/
class UnpackNode extends Node {
public $expression;

/**
* Constructor
*
* @param xp.compiler.ast.Node $expression
*/
public function __construct($expression) {
$this->expression= $expression;
}

/**
* Returns a hashcode
*
* @return string
*/
public function hashCode() {
return '...'.$this->expression->hashCode();
}
}
Loading