Skip to content
This repository was archived by the owner on Sep 9, 2019. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 10 additions & 14 deletions src/main/jay/grammars/xp.jay
Original file line number Diff line number Diff line change
Expand Up @@ -768,15 +768,15 @@ staticmember:
;

expression:
T_VARIABLE { $1= $yyLex->create(new VariableNode($1)); } chain_opt {
T_VARIABLE { $1= array('name' => $1); } lambda_body {
$$= $yyLex->create(new LambdaNode(array($1), $3));
}
| T_VARIABLE { $1= $yyLex->create(new VariableNode($1)); } chain_opt {
if ($3) {
$$= $3[0];
$3[1]->target= $1;
}
}
| T_VARIABLE { $1= $yyLex->create(new VariableNode($1)); } lambda_body {
$$= $yyLex->create(new LambdaNode(array($1), $3));
}
| '(' expression ')' chain_opt {
if ($4) {
$$= $4[0];
Expand Down Expand Up @@ -877,12 +877,8 @@ expression:
;

lambda_body:
T_ARROW expression {
$$= array(new ReturnNode($2));
}
| T_ARROW '{' statements_opt '}' {
$$= (array)$3;
}
T_ARROW expression { $$= array(new ReturnNode($2)); }
| T_ARROW '{' statements_opt '}' { $$= (array)$3; }
;

lambda_input:
Expand All @@ -896,8 +892,8 @@ lambda_input_parameters:
;

lambda_input_parameter:
T_VARIABLE { $$= new VariableNode($1); }
| typeref T_VARIABLE { $$= new VariableNode($2); }
T_VARIABLE initialization_opt { $$= array('name' => $1); $2 && $$['default']= $2; }
| typeref T_VARIABLE initialization_opt { $$= array('name' => $2, 'type' => $1); $2 && $$['default']= $2; }
;

literal:
Expand Down Expand Up @@ -1020,8 +1016,8 @@ chain:
| nav member '(' { $1= $yyLex->create(new MethodCallNode(NULL, $2, NULL, $1)); } expressionlist_opt ')' {
$1->arguments= $5;
}
| nav '(' { $1= $yyLex->create(new InstanceCallNode(NULL, NULL, $1)); } expressionlist_opt ')' {
$1->arguments= $4;
| '(' { $1= $yyLex->create(new InstanceCallNode(NULL, NULL, FALSE)); } expressionlist_opt ')' {
$1->arguments= $3;
}
;

Expand Down
4 changes: 2 additions & 2 deletions src/main/php/xp/compiler/emit/php/V52Emitter.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ protected function emitLambda($b, $lambda) {
$promoter= new LocalsToMemberPromoter();
$parameters= $replaced= array();
foreach ($lambda->parameters as $parameter) {
$parameters[]= array('name' => $parameter->name, 'type' => TypeName::$VAR);
$promoter->exclude($parameter->name);
$parameters[]= $parameter;
$promoter->exclude($parameter['name']);
}
$promoted= $promoter->promote($lambda);

Expand Down
8 changes: 6 additions & 2 deletions src/main/php/xp/compiler/emit/php/V53Emitter.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,12 @@ protected function emitLambda($b, $lambda) {
$b->append('function(');
$s= sizeof($lambda->parameters)- 1;
foreach ($lambda->parameters as $i => $param) {
$b->append('$')->append($param->name);
$finder->excluding($param->name);
$b->append('$')->append($param['name']);
if (isset($param['default'])) {
$b->append('=');
$this->emitOne($b, $param['default']);
}
$finder->excluding($param['name']);
$i < $s && $b->append(',');
}
$b->append(')');
Expand Down
2,596 changes: 1,308 additions & 1,288 deletions src/main/php/xp/compiler/syntax/xp/Parser.class.php

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ public function apply_capturing_local_variable() {
#[@test]
public function execution() {
$this->assertEquals(3, $this->run(
'return ($a -> $a + 1).(2);'
'return ($a -> $a + 1)(2);'
));
}

#[@test]
public function execution_via_variable() {
$this->assertEquals(3, $this->run(
'$plusone= $a -> $a + 1; return $plusone.(2);'
'$plusone= $a -> $a + 1; return $plusone(2);'
));
}
}
Original file line number Diff line number Diff line change
@@ -1,80 +1,37 @@
<?php namespace net\xp_lang\tests\execution\source;

/**
* Tests navigation operator
*
* Tests navigation operator `?.`
*/
class NavigationOperatorTest extends ExecutionTest {

/**
* Test member access
*
*/

#[@test]
public function member_access_on_null() {
$this->assertNull($this->run('$i= null; return $i?.member;'));
}

/**
* Test member access
*
*/
#[@test]
public function member_access_on_self() {
$this->assertTrue($this->run('$i= new self() { bool $member= true; }; return $i?.member;'));
}

/**
* Test method call
*
*/
#[@test]
public function method_call_on_null() {
$this->assertNull($this->run('$i= null; return $i?.toString();'));
}

/**
* Test method call
*
*/
#[@test]
public function method_call_on_self() {
$this->assertEquals('OK', $this->run('$i= new self() { string toString() { return "OK"; } }; return $i?.toString();'));
}

/**
* Test method call
*
*/
#[@test]
public function method_call_on_null_member() {
$this->assertNull($this->run('$i= new self() { lang.types.Integer $member= null; }; return $i?.member?.intValue();'));
}

/**
* Test method call
*
*/
#[@test]
public function method_call_on_member() {
$this->assertEquals(1, $this->run('$i= new self() { lang.types.Integer $member= new lang.types.Integer(1); }; return $i?.member?.intValue();'));
}

/**
* Test invocation
*
*/
#[@test]
public function invocation_on_null() {
$this->assertNull($this->run('$i= null; return $i?.(true);'));
}

/**
* Test member access
*
*/
#[@test]
public function invocation_on_lambda() {
$this->assertTrue($this->run('$i= #{ $a -> $a }; return $i?.(true);'));
}
}
71 changes: 22 additions & 49 deletions src/test/php/net/xp_lang/tests/syntax/xp/ChainingTest.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use xp\compiler\ast\MemberAccessNode;
use xp\compiler\ast\VariableNode;
use xp\compiler\ast\InstanceCreationNode;
use xp\compiler\ast\InstanceCallNode;
use xp\compiler\ast\MethodCallNode;
use xp\compiler\ast\StaticMethodCallNode;
use xp\compiler\ast\BracedExpressionNode;
Expand All @@ -18,10 +19,6 @@
*/
class ChainingTest extends ParserTestCase {

/**
* Test field access
*
*/
#[@test]
public function fieldAccess() {
$this->assertEquals(
Expand All @@ -30,10 +27,6 @@ public function fieldAccess() {
);
}

/**
* Test field access
*
*/
#[@test]
public function chainedFieldAccess() {
$this->assertEquals(
Expand All @@ -42,10 +35,6 @@ public function chainedFieldAccess() {
);
}

/**
* Test field access
*
*/
#[@test]
public function fieldNamedClassAccess() {
$this->assertEquals(
Expand All @@ -54,36 +43,24 @@ public function fieldNamedClassAccess() {
);
}

/**
* Test simple method call on an object
*
*/
#[@test]
public function methodCall() {
public function method_call() {
$this->assertEquals(
array(new MethodCallNode(new VariableNode('m'), 'invoke', array(new VariableNode('args')))),
$this->parse('$m.invoke($args);')
array(new MethodCallNode(new VariableNode('m'), 'func', array(new VariableNode('args')))),
$this->parse('$m.func($args);')
);
}

/**
* Test simple method call on chained fields
*
*/
#[@test]
public function methodCallOnChainedFields() {
public function method_call_on_chained_fields() {
$this->assertEquals(
array(new MethodCallNode(new MemberAccessNode(new MemberAccessNode(new VariableNode('m'), 'member'), 'data'), 'invoke', array(new VariableNode('args')))),
$this->parse('$m.member.data.invoke($args);')
);
}

/**
* Test chained method calls
*
*/
#[@test]
public function chainedMethodCalls() {
public function method_call_on_chained_method_call() {
$this->assertEquals(
array(new MethodCallNode(
new MethodCallNode(new VariableNode('l'), 'withAppender'),
Expand All @@ -93,10 +70,22 @@ public function chainedMethodCalls() {
);
}

/**
* Test chained method calls
*
*/
#[@test]
public function member_instance_call() {
$this->assertEquals(
array(new InstanceCallNode(new BracedExpressionNode(new MemberAccessNode(new VariableNode('m'), 'func')), array(new VariableNode('args')))),
$this->parse('($m.func)($args);')
);
}

#[@test]
public function member_instance_call_chained_to_method_call() {
$this->assertEquals(
array(new InstanceCallNode(new MethodCallNode(new VariableNode('m'), 'func', array(new VariableNode('args'))), array(new VariableNode('n')))),
$this->parse('$m.func($args)($n);')
);
}

#[@test]
public function chainedAfterNew() {
$this->assertEquals(
Expand All @@ -111,10 +100,6 @@ public function chainedAfterNew() {
);
}

/**
* Test chained method calls
*
*/
#[@test]
public function arrayOffsetOnMethod() {
$this->assertEquals(
Expand All @@ -129,10 +114,6 @@ public function arrayOffsetOnMethod() {
);
}

/**
* Test chained method calls
*
*/
#[@test]
public function chainedAfterStaticMethod() {
$this->assertEquals(
Expand All @@ -145,10 +126,6 @@ public function chainedAfterStaticMethod() {
);
}

/**
* Test chaining after function calls
*
*/
#[@test]
public function chainedAfterFunction() {
$this->assertEquals(
Expand All @@ -161,10 +138,6 @@ public function chainedAfterFunction() {
);
}

/**
* Test chained after bracing
*
*/
#[@test]
public function chainedAfterBraced() {
$this->assertEquals(
Expand Down
Loading