/**
* @param Parser $parser The parser that serves as context.
* @param TokensList $list The list of tokens that are being parsed.
* @param array $options Parameters for parsing.
*
* @return CreateDefinition[]
*/
public static function parse(Parser $parser, TokensList $list, array $options = array())
{
$ret = array();
$expr = new CreateDefinition();
/**
* The state of the parser.
*
* Below are the states of the parser.
*
* 0 -----------------------[ ( ]------------------------> 1
*
* 1 --------------------[ CONSTRAINT ]------------------> 1
* 1 -----------------------[ key ]----------------------> 2
* 1 -------------[ constraint / column name ]-----------> 2
*
* 2 --------------------[ data type ]-------------------> 3
*
* 3 ---------------------[ options ]--------------------> 4
*
* 4 --------------------[ REFERENCES ]------------------> 4
*
* 5 ------------------------[ , ]-----------------------> 1
* 5 ------------------------[ ) ]-----------------------> 6 (-1)
*
* @var int $state
*/
$state = 0;
for (; $list->idx < $list->count; ++$list->idx) {
/**
* Token parsed at this moment.
*
* @var Token $token
*/
$token = $list->tokens[$list->idx];
// End of statement.
if ($token->type === Token::TYPE_DELIMITER) {
break;
}
// Skipping whitespaces and comments.
if ($token->type === Token::TYPE_WHITESPACE || $token->type === Token::TYPE_COMMENT) {
continue;
}
if ($state === 0) {
if ($token->type === Token::TYPE_OPERATOR && $token->value === '(') {
$state = 1;
} else {
$parser->error(__('An opening bracket was expected.'), $token);
break;
}
} elseif ($state === 1) {
if ($token->type === Token::TYPE_KEYWORD && $token->value === 'CONSTRAINT') {
$expr->isConstraint = true;
} elseif ($token->type === Token::TYPE_KEYWORD && $token->flags & Token::FLAG_KEYWORD_KEY) {
$expr->key = Key::parse($parser, $list);
$state = 4;
} else {
$expr->name = $token->value;
if (!$expr->isConstraint) {
$state = 2;
}
}
} elseif ($state === 2) {
$expr->type = DataType::parse($parser, $list);
$state = 3;
} elseif ($state === 3) {
$expr->options = OptionsArray::parse($parser, $list, static::$FIELD_OPTIONS);
$state = 4;
} elseif ($state === 4) {
if ($token->type === Token::TYPE_KEYWORD && $token->value === 'REFERENCES') {
++$list->idx;
// Skipping keyword 'REFERENCES'.
$expr->references = Reference::parse($parser, $list);
} else {
--$list->idx;
}
$state = 5;
} elseif ($state === 5) {
if (!empty($expr->type) || !empty($expr->key)) {
$ret[] = $expr;
}
$expr = new CreateDefinition();
if ($token->value === ',') {
$state = 1;
} elseif ($token->value === ')') {
$state = 6;
++$list->idx;
break;
} else {
$parser->error(__('A comma or a closing bracket was expected.'), $token);
$state = 0;
break;
}
}
}
// Last iteration was not saved.
if (!empty($expr->type) || !empty($expr->key)) {
$ret[] = $expr;
}
if ($state !== 0 && $state !== 6) {
$parser->error(__('A closing bracket was expected.'), $list->tokens[$list->idx - 1]);
}
--$list->idx;
return $ret;
}