@ 2013-08-02T12:51:04Z <?php
interface ILexer {
/**
* return associative array containing tokens for parser
* @param string $input code to tokenize
* @return array
*/
public function tokenize($input);
}
interface INameValidator {
/**
* Checks if name is valid. In a case of failure trigger syntax error.
* @param string $name
* @return void
*/
public function validate($name);
}
interface IParser {
/**
* Sets array of keywords.
* @param array $keywords associative array where key is keyword and value respective php instruction.
* @return void
*/
public function setKeywords(array $keywords);
/**
* Parses code. Checks for syntax errors.
* If no error occurs returns data for compiler to assemble php class
* otherwise trigger syntax error.
* @param string $input code to parse.
* @return array IParserResult
*/
public function parse($input);
}
interface IParseResult {
public function getDefinition();
public function getName();
public function getConstants();
}
interface ICompiler {
/**
* Compiles enum into valid php class
* @param string $input code to compile.
* @return string
*/
public function compile($input);
}
interface IErrorManager {
/**
* Triggers fatal error.
* @param string $message error message
* @return void
*/
public function ariseFatal($message);
/**
* Triggers warning.
* @param string $message error message
* @return void
*/
public function ariseWarning($message);
/**
* Triggers notice.
* @param string $message error message
* @return void
*/
public function ariseNotice($message);
}
//I know this lexer sucks.
class Lexer extends CompilerElement implements ILexer {
// Potential hidden dependency
private $specialChars = array(
'{' => 'start_body',
'}' => 'end_body'
);
public function tokenize($input) {
if (!is_string($input)) {
$this->getErrorManager()->ariseFatal(get_class($this).'::parse expects parameter 1 to be string. '.gettype($input).' given.');
}
$tokens = array();
$token = $this->getEmptyToken();
$tokenMetadata = $this->getDefaultTokenMetadata();
$inputLength = strlen($input);
for ($i = 0; $i < $inputLength; $i++) {
$current = $input[$i];
//check if special character
if (isset($this->specialChars[$current])) {
$token[$this->specialChars[$current]] = $current;
if ($i !== $inputLength - 1)
continue;
}
if (isset($token['end_body'])) {
$tokens[] = $token;
$token = $this->getEmptyToken();
$tokenMetadata = $this->getDefaultTokenMetadata();
if ($i === $inputLength - 1)
continue;
}
$isWhitespace = ctype_space($current);
if (isset($token['start_body'])) {
//skip if whitespace
if ($isWhitespace) {
continue;
}
if ($current === ',') {
$tokenMetadata['newItem'] = true;
$tokenMetadata['newItemNameResolved'] = false;
continue;
}
if ($current === '=') {
$tokenMetadata['newItemNameResolved'] = true;
continue;
}
if ($tokenMetadata['newItem']) {
$token['e_'.$current] = null;
$tokenMetadata['newItem'] = false;
} else {
end($token);
$lastKey = key($token);
if (!$tokenMetadata['newItemNameResolved']) {
unset($token[$lastKey]);
$token[$lastKey.$current] = null;
} else {
$token[$lastKey] .= $current;
}
}
continue;
}
if (!$tokenMetadata['typeResolved']) {
if ($isWhitespace) {
if (strlen($token['type']) === 0) {
continue;
} else {
$tokenMetadata['typeResolved'] = true;
}
} else {
$token['type'] .= $current;
}
} else if (!$tokenMetadata['nameResolved']) {
if ($isWhitespace) {
if (strlen($token['name']) === 0) {
continue;
} else {
$tokenMetadata['nameResolved'] = true;
}
} else {
$token['name'] .= $current;
}
}
}
return $tokens;
}
private function getEmptyToken() {
return array(
'type' => '',
'name' => ''
);
}
private function getDefaultTokenMetadata() {
return array(
'typeResolved' => false,
'nameResolved' => false,
'newItem' => true,
'newItemNameResolved' => false
);
}
public function __construct(IErrorManager $errorManager) {
parent::__construct($errorManager);
}
}
class NameValidator extends CompilerElement implements INameValidator {
private $allowedChars;
public function validate($name) {
if (!is_string($name)) {
$this->getErrorManager()->ariseFatal(get_class($this).'::validate expects parameter 1 to be string. '.gettype($name).' given.');
}
$nameLength = strlen($name);
for ($i = 0; $i < $nameLength; $i++) {
$current = $name[$i];
if ($i === 0 && !ctype_alpha($current)) {
$this->getErrorManager()->ariseFatal('Name should start with alphabetic characters. Given name '.$name.' starts with: '.$current);
}
if (!in_array(strtolower($current), $this->allowedChars, true)) {
$this->getErrorManager()->ariseFatal('Unexpected character '.$current.' in name '.$name.'.');
}
}
}
public function __construct(IErrorManager $errorManager) {
parent::__construct($errorManager);
// Yes, I hate that everything is allowed as name in php.
$this->allowedChars = str_split('abcdefghijklmnopqrstuvwxyz0123456789');
}
}
class Parser extends CompilerElement implements IParser {
private $lexer;
private $nameValidator;
private $keywords = array();
public function setKeywords(array $keywords) {
$this->keywords = $keywords;
}
public function parse($input) {
if (!is_string($input)) {
$this->getErrorManager()->ariseFatal(get_class($this).'::parse expects parameter 1 to be string. '.gettype($input).' given.');
}
$input = $this->cleanUp($input);
$errorManager = $this->getErrorManager();
$allTokens = $this->lexer->tokenize($input);
$result = array();
$currentResult = null;
$processingBody = false;
foreach ($allTokens as $tokens) {
foreach ($tokens as $token => $tokenValue) {
switch ($token) {
case 'type':
if ($currentResult !== null || !isset($this->keywords[$tokenValue])) {
$errorManager->ariseFatal('Syntax error. Unexpected '.$tokenValue);
}
$currentResult = new ParseResult($this->keywords[$tokenValue], $errorManager);
break;
case 'name':
if ($currentResult === null) {
$errorManager->ariseFatal('Syntax error. Unexpected '.$tokenValue);
}
$this->nameValidator->validate($tokenValue);
$currentResult->setName($tokenValue);
break;
case 'start_body':
if ($currentResult === null || $currentResult->getName() === null) {
$errorManager->ariseFatal('Syntax error. Unexpected '.$tokenValue);
}
$processingBody = true;
break;
case 'end_body':
if ($currentResult === null || $currentResult->getName() === null || $processingBody === false) {
$errorManager->ariseFatal('Syntax error. Unexpected '.$tokenValue);
}
$result[] = $currentResult;
$currentResult = null;
$processingBody = false;
break;
default:
if ($processingBody === true && $currentResult !== null) {
$name = ltrim($token, 'e_');
$this->nameValidator->validate($name);
if ($tokenValue === null) {
$constants = $currentResult->getConstants();
$last = end($constants);
$value = ($last !== false) ? $last + 1 : 0;
} else {
$value = $tokenValue;
}
$currentResult->setItem($name, $value);
} else {
$errorManager->ariseFatal('Syntax error. Unexpected '.$tokenValue);
}
break;
}
}
}
return $result;
}
private function cleanUp($input) {
return trim($input);
}
public function __construct(ILexer $lexer, INameValidator $nameValidator, IErrorManager $errorManager) {
parent::__construct($errorManager);
$this->lexer = $lexer;
$this->nameValidator = $nameValidator;
}
}
class ParseResult extends CompilerElement implements IParseResult {
private $definition;
private $name;
private $constants = array();
public function getDefinition() {
return $this->definition;
}
public function getName() {
return $this->name;
}
public function getConstants() {
return $this->constants;
}
public function setItem($name, $value) {
if (!is_string($name)) {
$this->getErrorManager()->ariseFatal('Enumeration item name can only be string.');
}
if (!is_numeric($value)) {
$this->getErrorManager()->ariseFatal('Enumeration item can only hold numeric value.');
}
$this->constants[$name] = (ctype_digit($value) === true) ? (int)$value : (double)$value;
}
public function setName($name) {
if (!is_string($name)) {
$this->getErrorManager()->ariseFatal(get_class($this).'::setName expects parameter 1 to be string. '.gettype($name).' given.');
}
$this->name = $name;
}
public function __construct($definition, IErrorManager $errorManager) {
parent::__construct($errorManager);
if (!is_string($definition)) {
$this->getErrorManager()->ariseFatal(get_class($this).'::__construct expects parameter 1 to be string. '.gettype($definition).' given.');
}
$this->definition = $definition;
}
}
abstract class CompilerElement {
private $errorManager;
protected function getErrorManager() {
return $this->errorManager;
}
protected function __construct(IErrorManager $errorManager) {
$this->errorManager = $errorManager;
}
}
class Enum2PhpCompiler implements ICompiler {
const INDENTATION_CHAR = "\t";
private $parser;
public function compile($input) {
$parseResult = $this->parser->parse($input);
$return = '';
foreach ($parseResult as $result) {
$return .= $this->generateClass($result);
}
return $return;
}
private function generateClass(IParseResult $parseResult) {
$return = $parseResult->getDefinition().' '.$parseResult->getName().' {'.PHP_EOL;
foreach ($parseResult->getConstants() as $name => $value) {
$return .= Enum2PhpCompiler::INDENTATION_CHAR.'const '.$name.' = '.$value.';'.PHP_EOL;
}
$return .= Enum2PhpCompiler::INDENTATION_CHAR.'private function __construct() {}'.PHP_EOL;
$return .= '}'.PHP_EOL;
return $return;
}
public function __construct(IParser $parser) {
$this->parser = $parser;
$this->parser->setKeywords(array('enum' => 'final class'));
}
}
class ErrorManager implements IErrorManager {
public function ariseFatal($message) {
$this->triggerError($message, E_USER_ERROR);
}
public function ariseWarning($message) {
$this->triggerError($message, E_USER_WARNING);
}
public function ariseNotice($message) {
$this->triggerError($message, E_USER_NOTICE);
}
private function triggerError($message, $type) {
trigger_error((string)$message, (int)$type);
}
}
Enable javascript to submit You have javascript disabled. You will not be able to edit any code.
Here you find the average performance (time & memory) of each version. A grayed out version indicates it didn't complete successfully (based on exit-code).
Version System time (s) User time (s) Memory (MiB) 8.3.7 0.009 0.012 16.88 8.3.6 0.003 0.017 18.18 8.3.5 0.010 0.005 21.93 8.3.4 0.012 0.006 18.71 8.3.3 0.011 0.004 19.01 8.3.2 0.004 0.004 20.34 8.3.1 0.008 0.000 22.04 8.3.0 0.008 0.000 22.33 8.2.19 0.012 0.003 16.58 8.2.18 0.011 0.004 18.42 8.2.17 0.011 0.004 22.96 8.2.16 0.009 0.006 20.56 8.2.15 0.004 0.004 24.18 8.2.14 0.006 0.003 24.66 8.2.13 0.005 0.003 26.16 8.2.12 0.008 0.000 19.23 8.2.11 0.005 0.005 22.13 8.2.10 0.004 0.008 17.84 8.2.9 0.008 0.000 19.30 8.2.8 0.000 0.008 17.97 8.2.7 0.007 0.007 17.46 8.2.6 0.003 0.006 17.93 8.2.5 0.003 0.005 18.07 8.2.4 0.004 0.004 18.16 8.2.3 0.000 0.008 18.02 8.2.2 0.000 0.008 17.80 8.2.1 0.000 0.008 17.68 8.2.0 0.003 0.005 17.87 8.1.28 0.007 0.013 25.92 8.1.27 0.003 0.006 23.84 8.1.26 0.008 0.000 26.35 8.1.25 0.008 0.000 28.09 8.1.24 0.000 0.009 23.96 8.1.23 0.009 0.003 19.23 8.1.22 0.003 0.005 17.75 8.1.21 0.000 0.008 18.77 8.1.20 0.007 0.003 17.35 8.1.19 0.009 0.000 17.52 8.1.18 0.000 0.008 18.10 8.1.17 0.004 0.004 18.76 8.1.16 0.000 0.007 22.16 8.1.15 0.003 0.007 18.69 8.1.14 0.009 0.000 17.48 8.1.13 0.004 0.004 17.83 8.1.12 0.004 0.004 17.45 8.1.11 0.008 0.000 17.44 8.1.10 0.004 0.004 17.51 8.1.9 0.000 0.008 17.59 8.1.8 0.008 0.000 17.52 8.1.7 0.003 0.005 17.49 8.1.6 0.006 0.003 17.59 8.1.5 0.003 0.006 17.56 8.1.4 0.004 0.008 17.53 8.1.3 0.008 0.000 17.65 8.1.2 0.008 0.000 17.74 8.1.1 0.003 0.006 17.57 8.1.0 0.004 0.004 17.36 8.0.30 0.000 0.007 18.77 8.0.29 0.004 0.004 17.18 8.0.28 0.000 0.007 18.46 8.0.27 0.004 0.004 17.35 8.0.26 0.000 0.007 16.78 8.0.25 0.000 0.007 16.96 8.0.24 0.003 0.005 17.01 8.0.23 0.007 0.000 17.05 8.0.22 0.004 0.004 17.02 8.0.21 0.000 0.007 16.98 8.0.20 0.004 0.004 17.03 8.0.19 0.004 0.004 16.99 8.0.18 0.006 0.003 16.95 8.0.17 0.000 0.009 16.89 8.0.16 0.004 0.004 16.83 8.0.15 0.000 0.008 16.95 8.0.14 0.004 0.004 16.87 8.0.13 0.000 0.006 13.32 8.0.12 0.003 0.005 16.98 8.0.11 0.004 0.004 16.95 8.0.10 0.000 0.008 16.98 8.0.9 0.003 0.005 16.85 8.0.8 0.016 0.007 17.03 8.0.7 0.000 0.008 17.01 8.0.6 0.006 0.003 16.79 8.0.5 0.008 0.000 16.95 8.0.3 0.008 0.014 17.25 8.0.2 0.005 0.017 17.40 8.0.1 0.005 0.002 16.96 8.0.0 0.015 0.006 16.71 7.4.33 0.002 0.002 15.00 7.4.32 0.003 0.003 16.61 7.4.30 0.000 0.007 16.70 7.4.29 0.004 0.004 16.51 7.4.28 0.000 0.008 16.58 7.4.27 0.000 0.007 16.74 7.4.26 0.000 0.007 16.62 7.4.25 0.005 0.003 16.59 7.4.24 0.004 0.004 16.56 7.4.23 0.000 0.007 16.62 7.4.22 0.007 0.010 16.71 7.4.21 0.003 0.012 16.62 7.4.20 0.003 0.003 16.50 7.4.19 0.007 0.000 16.68 7.4.16 0.006 0.010 16.71 7.4.15 0.006 0.013 17.40 7.4.14 0.013 0.008 17.86 7.4.13 0.008 0.010 16.59 7.4.12 0.009 0.009 16.63 7.4.11 0.016 0.005 16.39 7.4.10 0.014 0.010 16.52 7.4.9 0.007 0.013 16.53 7.4.8 0.000 0.018 16.61 7.4.7 0.010 0.007 16.49 7.4.6 0.000 0.017 16.55 7.4.5 0.000 0.010 16.54 7.4.4 0.006 0.010 22.77 7.4.3 0.010 0.007 16.54 7.4.0 0.005 0.013 14.92 7.3.33 0.006 0.000 13.31 7.3.32 0.000 0.005 13.25 7.3.31 0.004 0.004 16.28 7.3.30 0.004 0.004 16.23 7.3.29 0.009 0.009 16.34 7.3.28 0.017 0.005 16.35 7.3.27 0.009 0.009 17.40 7.3.26 0.013 0.013 16.61 7.3.25 0.012 0.006 16.34 7.3.24 0.004 0.013 16.73 7.3.23 0.009 0.009 16.66 7.3.21 0.014 0.004 16.28 7.3.20 0.007 0.017 19.39 7.3.19 0.000 0.021 16.66 7.3.18 0.013 0.003 16.63 7.3.17 0.018 0.006 16.31 7.3.16 0.014 0.004 16.45 7.3.12 0.010 0.008 14.89 7.3.11 0.010 0.010 14.77 7.3.10 0.008 0.008 14.90 7.3.9 0.006 0.006 14.96 7.3.8 0.006 0.006 14.87 7.3.7 0.004 0.015 14.80 7.3.6 0.007 0.004 14.97 7.3.5 0.000 0.015 14.77 7.3.4 0.003 0.010 14.97 7.3.3 0.008 0.008 14.95 7.3.2 0.007 0.007 16.80 7.3.1 0.008 0.008 16.61 7.3.0 0.009 0.006 16.38 7.2.33 0.007 0.011 16.67 7.2.32 0.009 0.009 16.39 7.2.31 0.012 0.013 16.71 7.2.30 0.010 0.007 16.78 7.2.29 0.014 0.007 16.75 7.2.25 0.000 0.021 15.21 7.2.24 0.007 0.014 15.11 7.2.23 0.015 0.004 15.15 7.2.22 0.015 0.000 15.23 7.2.21 0.003 0.010 14.85 7.2.20 0.004 0.015 14.93 7.2.19 0.006 0.009 14.96 7.2.18 0.009 0.003 14.91 7.2.17 0.008 0.006 15.10 7.2.0 0.010 0.003 19.02 7.1.33 0.000 0.012 15.65 7.1.32 0.003 0.013 15.79 7.1.31 0.007 0.007 15.41 7.1.30 0.003 0.006 15.73 7.1.29 0.009 0.006 15.66 7.1.28 0.003 0.010 15.70 7.1.27 0.009 0.000 15.66 7.1.26 0.007 0.011 15.82 7.1.10 0.003 0.009 18.04 7.1.7 0.006 0.009 16.96 7.1.6 0.016 0.009 19.82 7.1.5 0.010 0.007 16.73 7.1.0 0.010 0.070 22.34 7.0.20 0.007 0.004 16.82 7.0.14 0.007 0.070 22.22 7.0.10 0.020 0.053 20.05 7.0.9 0.020 0.047 20.11 7.0.8 0.010 0.043 20.05 7.0.7 0.020 0.073 20.14 7.0.6 0.023 0.040 20.09 7.0.5 0.007 0.080 20.44 7.0.4 0.010 0.037 20.14 7.0.3 0.007 0.037 20.07 7.0.2 0.003 0.040 20.11 7.0.1 0.010 0.040 19.95 7.0.0 0.003 0.070 20.01 5.6.28 0.003 0.073 21.02 5.6.25 0.003 0.050 20.68 5.6.24 0.010 0.037 20.60 5.6.23 0.007 0.040 20.75 5.6.22 0.000 0.043 20.58 5.6.21 0.017 0.073 20.58 5.6.20 0.000 0.050 20.99 5.6.19 0.000 0.047 21.10 5.6.18 0.000 0.043 21.19 5.6.17 0.010 0.037 21.01 5.6.16 0.010 0.033 21.12 5.6.15 0.007 0.037 21.19 5.6.14 0.003 0.047 21.14 5.6.13 0.003 0.043 21.17 5.6.12 0.007 0.037 21.09 5.6.11 0.007 0.040 21.16 5.6.10 0.010 0.037 21.13 5.6.9 0.007 0.087 21.17 5.6.8 0.013 0.050 20.58 5.6.7 0.010 0.077 20.54 5.6.6 0.013 0.073 20.46 5.6.5 0.010 0.077 20.55 5.6.4 0.003 0.087 20.46 5.6.3 0.010 0.080 20.45 5.6.2 0.010 0.077 20.40 5.6.1 0.007 0.077 20.52 5.6.0 0.013 0.073 20.42 5.5.38 0.003 0.040 20.47 5.5.37 0.007 0.060 20.59 5.5.36 0.003 0.043 20.42 5.5.35 0.010 0.037 20.42 5.5.34 0.010 0.037 20.84 5.5.33 0.007 0.040 20.85 5.5.32 0.010 0.077 21.00 5.5.31 0.003 0.043 21.02 5.5.30 0.007 0.040 20.91 5.5.29 0.013 0.050 20.89 5.5.28 0.003 0.050 20.91 5.5.27 0.010 0.040 20.92 5.5.26 0.003 0.040 20.84 5.5.25 0.013 0.080 20.74 5.5.24 0.003 0.080 20.23 5.5.23 0.007 0.077 20.37 5.5.22 0.003 0.083 20.36 5.5.21 0.007 0.080 20.36 5.5.20 0.007 0.083 20.31 5.5.19 0.007 0.063 20.19 5.5.18 0.017 0.070 20.29 5.5.16 0.013 0.043 20.21 5.5.15 0.003 0.080 20.08 5.5.14 0.013 0.057 20.34 5.5.13 0.007 0.070 20.34 5.5.12 0.007 0.067 20.32 5.5.11 0.010 0.070 20.20 5.5.10 0.013 0.073 20.20 5.5.9 0.007 0.077 20.17 5.5.8 0.010 0.077 20.07 5.5.7 0.013 0.050 20.18 5.5.6 0.003 0.077 20.14 5.5.5 0.000 0.087 20.06 5.5.4 0.007 0.077 20.15 5.5.3 0.007 0.080 20.21 5.5.2 0.010 0.070 20.16 5.5.1 0.010 0.077 20.14 5.5.0 0.007 0.067 20.10 5.4.45 0.003 0.037 19.39 5.4.44 0.007 0.047 19.49 5.4.43 0.010 0.037 19.25 5.4.42 0.010 0.037 19.46 5.4.41 0.007 0.077 19.34 5.4.40 0.017 0.067 18.89 5.4.39 0.003 0.050 19.24 5.4.38 0.017 0.057 19.23 5.4.37 0.010 0.077 19.07 5.4.36 0.003 0.083 19.27 5.4.35 0.010 0.077 19.14 5.4.34 0.007 0.073 19.21 5.4.32 0.007 0.073 19.07 5.4.31 0.013 0.073 19.08 5.4.30 0.000 0.083 19.23 5.4.29 0.000 0.057 19.07 5.4.28 0.013 0.067 18.92 5.4.27 0.010 0.067 19.06 5.4.26 0.003 0.077 19.24 5.4.25 0.003 0.080 19.23 5.4.24 0.010 0.073 18.97 5.4.23 0.010 0.073 19.14 5.4.22 0.007 0.057 18.91 5.4.21 0.013 0.047 18.91 5.4.20 0.000 0.087 19.23 5.4.19 0.013 0.063 18.91 5.4.18 0.007 0.080 19.23 5.4.17 0.010 0.050 19.04 5.4.16 0.003 0.037 19.02 5.4.15 0.007 0.050 19.13 5.4.14 0.007 0.070 16.43 5.4.13 0.010 0.067 16.27 5.4.12 0.003 0.073 16.53 5.4.11 0.003 0.047 16.57 5.4.10 0.010 0.073 16.42 5.4.9 0.010 0.070 16.59 5.4.8 0.013 0.060 16.43 5.4.7 0.010 0.070 16.44 5.4.6 0.007 0.063 16.38 5.4.5 0.007 0.077 16.54 5.4.4 0.010 0.060 16.38 5.4.3 0.013 0.033 16.39 5.4.2 0.010 0.067 16.43 5.4.1 0.010 0.040 16.54 5.4.0 0.020 0.053 15.94 5.3.29 0.010 0.073 14.74 5.3.28 0.013 0.067 14.72 5.3.27 0.010 0.073 14.69 5.3.26 0.000 0.043 14.80 5.3.25 0.010 0.037 14.63 5.3.24 0.000 0.050 14.80 5.3.23 0.003 0.047 14.79 5.3.22 0.007 0.070 14.63 5.3.21 0.007 0.043 14.76 5.3.20 0.007 0.073 14.68 5.3.19 0.003 0.073 14.70 5.3.18 0.010 0.073 14.80 5.3.17 0.003 0.063 14.71 5.3.16 0.000 0.077 14.71 5.3.15 0.007 0.070 14.65 5.3.14 0.017 0.063 14.76 5.3.13 0.007 0.070 14.73 5.3.12 0.003 0.077 14.80 5.3.11 0.003 0.070 14.66 5.3.10 0.013 0.050 14.26 5.3.9 0.007 0.073 14.18 5.3.8 0.007 0.063 14.21 5.3.7 0.003 0.077 14.14 5.3.6 0.007 0.070 14.23 5.3.5 0.013 0.067 14.07 5.3.4 0.013 0.060 14.18 5.3.3 0.003 0.053 13.97 5.3.2 0.007 0.040 13.92 5.3.1 0.003 0.043 13.77 5.3.0 0.017 0.060 13.91
preferences:dark mode live preview
47.02 ms | 401 KiB | 5 Q