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
2 changes: 1 addition & 1 deletion src/main/jay/grammars/php.jay
Original file line number Diff line number Diff line change
Expand Up @@ -846,7 +846,7 @@ typeref:
;

typename:
qualifiedname { $$= new TypeName($1); }
qualifiedname { $$= 'callable' === $1 ? new TypeName('->var', null) : new TypeName($1); }
;

arraytype:
Expand Down
13 changes: 13 additions & 0 deletions src/main/jay/grammars/xp.jay
Original file line number Diff line number Diff line change
Expand Up @@ -1051,6 +1051,7 @@ typeref:
typename
| arraytype
| maptype
| functiontype
;

typename:
Expand All @@ -1076,6 +1077,18 @@ typeparameter:
| '?' T_EXTENDS qualifiedname { $$= new TypeName($3.'+'); }
;

signature:
'(' ')' { $$= array(); }
| typeref { $$= array($1); }
| '(' typeref ')' { $$= array($2); }
| '(' signature ',' typeref ')' { $$= array_merge($2, array($4)); }
;

functiontype:
'{' '?' T_ARROW typeref '}' { $$= new TypeName('->'.$4->compoundName(), null); }
| '{' signature T_ARROW typeref '}' { $$= new TypeName('->'.$4->compoundName(), $2); }
;

name_list:
typename { $$= array($1); }
| typename ',' name_list { $$= array_merge(array($1), $3); }
Expand Down
2 changes: 2 additions & 0 deletions src/main/php/xp/compiler/emit/php/Emitter.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -1312,6 +1312,8 @@ protected function emitParameters($b, array $parameters, $delim) {
// No runtime type checks
} else if ($t->isArray() || $t->isMap()) {
$b->append('array ');
} else if ($t->isFunction()) {
$b->append('callable ');
} else if ($t->isClass() && !$this->scope[0]->declarations[0]->name->isPlaceHolder($t)) {
$b->append($this->literal($ptr))->append(' ');
} else if ('{' === $delim) {
Expand Down
2 changes: 1 addition & 1 deletion src/main/php/xp/compiler/syntax/php/Parser.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -2402,7 +2402,7 @@ public function yyparse($yyLex) {
} break;

case 236: #line 849 "src/main/jay/grammars/php.jay"
{ $yyVal= new TypeName($yyVals[0+$yyTop]); } break;
{ $yyVal= 'callable' === $yyVals[0+$yyTop] ? new TypeName('->var', null) : new TypeName($yyVals[0+$yyTop]); } break;

case 237: #line 853 "src/main/jay/grammars/php.jay"
{ $yyVal= new TypeName('var[]'); } break;
Expand Down
2,686 changes: 1,365 additions & 1,321 deletions src/main/php/xp/compiler/syntax/xp/Parser.class.php

Large diffs are not rendered by default.

262 changes: 262 additions & 0 deletions src/main/php/xp/compiler/types/FunctionTypeOf.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
<?php namespace xp\compiler\types;

class FunctionTypeOf extends Types {
protected $return= null;
protected $parameters= null;

/**
* Constructor
*
* @param xp.compiler.types.Types $return
* @param xp.compiler.types.Types[] $parameters
*/
public function __construct(Types $return, $parameters) {
$this->return= $return;
$this->parameters= $parameters;
}

/**
* Returns modifiers
*
* @return int
*/
public function modifiers() {
return MODIFIER_PUBLIC;
}

/**
* Returns name
*
* @return string
*/
public function name() {
return sprintf(
'function(%s): %s',
null === $this->parameters ? '?' : implode(', ', array_map(function($type) { return $type->name(); }, $this->parameters)),
$this->return->name()
);
}

/**
* Returns parent type
*
* @return xp.compiler.types.Types
*/
public function parent() {
return null;
}

/**
* Returns literal for use in code
*
* @return string
*/
public function literal() {
return 'callable';
}

/**
* Returns type kind (one of the *_KIND constants).
*
* @return string
*/
public function kind() {
return self::FUNCTION_KIND;
}

/**
* Checks whether a given type instance is a subclass of this class.
*
* @param xp.compiler.types.Types
* @return bool
*/
public function isSubclassOf(Types $t) {
return false;
}

/**
* Returns whether this type is enumerable (that is: usable in foreach)
*
* @return bool
*/
public function isEnumerable() {
return false;
}

/**
* Returns the enumerator for this class or null if none exists.
*
* @see php://language.oop5.iterations
* @return xp.compiler.types.Enumerator
*/
public function getEnumerator() {
return null;
}

/**
* Returns whether a constructor exists
*
* @return bool
*/
public function hasConstructor() {
return false;
}

/**
* Returns the constructor
*
* @return xp.compiler.types.Constructor
*/
public function getConstructor() {
return null;
}

/**
* Returns whether a method with a given name exists
*
* @param string name
* @return bool
*/
public function hasMethod($name) {
return false;
}

/**
* Returns a method by a given name
*
* @param string name
* @return xp.compiler.types.Method
*/
public function getMethod($name) {
return null;
}

/**
* Gets a list of extension methods
*
* @return [:xp.compiler.types.Method[]]
*/
public function getExtensions() {
return array();
}

/**
* Returns whether an operator by a given symbol exists
*
* @param string symbol
* @return bool
*/
public function hasOperator($symbol) {
return false;
}

/**
* Returns an operator by a given name
*
* @param string symbol
* @return xp.compiler.types.Operator
*/
public function getOperator($symbol) {
return null;
}

/**
* Returns a field by a given name
*
* @param string name
* @return bool
*/
public function hasField($name) {
return false;
}

/**
* Returns a field by a given name
*
* @param string name
* @return xp.compiler.types.Field
*/
public function getField($name) {
return null;
}

/**
* Returns a property by a given name
*
* @param string name
* @return bool
*/
public function hasProperty($name) {
return false;
}

/**
* Returns a property by a given name
*
* @param string name
* @return xp.compiler.types.Property
*/
public function getProperty($name) {
return null;
}

/**
* Returns a constant by a given name
*
* @param string name
* @return bool
*/
public function hasConstant($name) {
return false;
}

/**
* Returns a constant by a given name
*
* @param string name
* @return xp.compiler.types.Constant
*/
public function getConstant($name) {
return null;
}

/**
* Returns whether this class has an indexer
*
* @return bool
*/
public function hasIndexer() {
return false;
}

/**
* Returns indexer
*
* @return xp.compiler.types.Indexer
*/
public function getIndexer() {
return null;
}

/**
* Returns a lookup map of generic placeholders
*
* @return [:int]
*/
public function genericPlaceholders() {
return array();
}

/**
* Creates a string representation of this object
*
* @return string
*/
public function toString() {
return sprintf(
'%s@(%s)',
$this->getClassName(),
$this->name()
);
}
}
2 changes: 2 additions & 0 deletions src/main/php/xp/compiler/types/Scope.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@ public function resolveType(TypeName $name, $register= true) {
return new PrimitiveTypeOf($name);
} else if ($name->isGeneric()) {
return new GenericType($this->resolveType(new TypeName($name->name), $register), $name->components);
} else if ($name->isFunction()) {
return new FunctionTypeOf($this->resolveType($name->functionReturnType(), $register), $name->components);
}

if ($this->declarations) {
Expand Down
39 changes: 29 additions & 10 deletions src/main/php/xp/compiler/types/TypeName.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@
* Type literals and their representation
* --------------------------------------
* ```
* int : TypeName('int')
* var : TypeName('var')
* string : TypeName('string')
* bool[] : TypeName('bool[]')
* [:var] : TypeName('[:var]')
* List<T> : TypeName('List', [TypeName('T')])
* Map<K, V> : TypeName('Map', [TypeName('K'), TypeName('V')])
* int : TypeName('int')
* var : TypeName('var')
* string : TypeName('string')
* bool[] : TypeName('bool[]')
* [:var] : TypeName('[:var]')
* List<T> : TypeName('List', [TypeName('T')])
* Map<K, V> : TypeName('Map', [TypeName('K'), TypeName('V')])
* function(int): string : TypeName('->string', [TypeName('int')])
* ```
*
* @test xp://net.xp_lang.tests.types.TypeNameTest
Expand Down Expand Up @@ -49,7 +50,7 @@ public function __construct($name, $components= array()) {
* @return bool
*/
public function isClass() {
return !$this->isArray() && !$this->isMap() && !$this->isVariable() && !$this->isVoid() && !$this->isPrimitive();
return !$this->isArray() && !$this->isMap() && !$this->isVariable() && !$this->isVoid() && !$this->isPrimitive() && !$this->isFunction();
}

/**
Expand Down Expand Up @@ -115,13 +116,31 @@ public function mapComponentType() {
return $this->isMap() ? new self(substr($this->name, 2, -1)) : null;
}

/**
* Return whether this type is a function type
*
* @return bool
*/
public function isFunction() {
return 0 === strncmp($this->name, '->', 2);
}

/**
* Return function return type or null if this is not a function
*
* @return xp.compiler.types.TypeName
*/
public function functionReturnType() {
return $this->isFunction() ? new self(substr($this->name, 2)) : null;
}

/**
* Return whether this type is a generic
*
* @return bool
*/
public function isGeneric() {
return !empty($this->components);
return 0 !== strncmp($this->name, '->', 2) && !empty($this->components);
}

/**
Expand Down Expand Up @@ -153,7 +172,7 @@ public function isPlaceholder(self $ref) {
public function equals($cmp) {
if (!$cmp instanceof self || $this->name !== $cmp->name) return false;

foreach ($this->components as $i => $c) {
foreach ((array)$this->components as $i => $c) {
if (!$c->equals($cmp->components[$i])) return false;
}
return true;
Expand Down
Loading