Skip to content

Instantly share code, notes, and snippets.

@asherkin
Created April 28, 2013 15:02
Show Gist options
  • Save asherkin/5477122 to your computer and use it in GitHub Desktop.
Save asherkin/5477122 to your computer and use it in GitHub Desktop.
<?php
class SplexSourcePawnEngine extends DivinerEngine {
public function buildFileContentHashes() {
$files = array();
$root = $this->getConfiguration()->getProjectRoot();
$finder = new FileFinder($root);
$finder
->excludePath('*/.*')
->withSuffix('inc')
->withType('f')
->setGenerateChecksums(true);
foreach ($finder->find() as $path => $hash) {
$path = Filesystem::readablePath($path, $root);
$files[$path] = $hash;
}
return $files;
}
public function willParseFiles(array $file_map) {
return;
}
public function parseFile($file, $data) {
$file_atom = new DivinerFileAtom();
$file_atom->setName($file);
$file_atom->setFile($file);
$lexer = new SplexSourcePawnFragmentLexer();
$parser = new SplexSourcePawnFragmentParser();
$tokens = $lexer->getTokens($data);
$functions = $parser->parse($tokens);
foreach ($functions as $function) {
$atom = new DivinerFunctionAtom();
$atom->setName($function['name']);
$atom->setFile($file);
if (isset($function['doc']))
$atom->setRawDocblock($function['doc']);
$metadata = $atom->getDocblockMetadata();
$docs = idx($metadata, 'param', '');
if ($docs) {
$docs = explode("\n", $docs);
}
foreach ($function['params'] as $param)
{
$dict = array();
if (isset($param['tag']))
$dict['type'] = $param['tag'];
if (isset($param['default']))
$dict['default'] = $param['default'];
if ($docs) {
$doc = array_shift($docs);
if ($doc)
$dict += $this->parseParamDoc($doc);
}
$name = $param['name'];
if (isset($param['array']))
$name .= "[" . (($param['array'] != -1)?($param['array']):("")) . "]";
$atom->addParameter($name, $dict);
}
$dict = array();
if (isset($function['return']))
$dict['doctype'] = $function['return'];
if (isset($metadata['return']))
$dict['docs'] = $metadata['return'];
$atom->setReturnTypeAttributes($dict);
$file_atom->addChild($atom);
}
return array($file_atom);
}
}
<?php
final class SplexSourcePawnFragmentLexer extends PhutilLexer {
protected function getRawRules() {
$keywords = array(
'break',
'case',
'const',
'continue',
'do',
'decl',
'else',
'enum',
'for',
'forward',
'if',
'native',
'new',
'public',
'return',
'static',
'stock',
'struct',
'switch',
'while',
);
$constants = array(
'true',
'false',
);
$identifier_pattern = "[a-zA-Z_][a-zA-Z0-9_]*";
return array(
'start' => array(
array('\\s+', null),
array('//[^?\\n]+', 'comment'),
array('#[^?\\n]+', 'directive'),
// This prevents the doc comment rule from over-consuming when we see
// an empty coment.
array('/\\*\\*/', 'comment'),
array('/\\*\\*.*?\\*/', 'doccomment'),
array('/\\*.*?\\*/', 'comment'),
// Unterminated multi-line comment.
array('/\\*.*$', 'comment'),
array('(?i:\\+\\+|--)\\b', 'other'),
array('[~!%^&*+=|<>/?@-]+', 'other'),
array('(?i:'.implode('|', $keywords).')\\b', 'keyword'),
array('(?i:'.implode('|', $constants).')\\b', 'constant'),
// Match "f(" as a function. This won't work
// if you put a comment between the symbol and the operator, but
// that's a bizarre usage.
array($identifier_pattern.'(?=\s*[\\(])', 'function'),
array($identifier_pattern.':', 'tag'),
array('\\.\\.\\.', 'varadic'),
array('\\[[0-9]*\\]', 'array'),
array('\\(', 'paren_start'),
array('\\)', 'paren_end'),
array('{', 'block_start'),
array('}', 'block_end'),
array(';', 'end_statement'),
array(',', 'comma'),
array($identifier_pattern, 'identifier'),
array('(\\d+\\.\\d*|\\d*\\.\\d+)([eE][+-]?[0-9]+)?', 'float'),
array('\\d+[eE][+-]?[0-9]+', 'float'),
array('0[0-7]+', 'octal'),
array('0[xX][a-fA-F0-9]+', 'hexadec'),
array('0[bB][0-1]+', 'binary'),
array('\d+', 'integer'),
array('"', 'string', 'string'),
),
'string' => array(
array('[^"\\\\]+', 'string'),
array('"', 'string', '!pop'),
array('\\\\.', 'k'),
),
// For "//" comments, we need to break out at a newline.
'line_comment' => array(
array('[^?\\n]+', 'comment'),
array('\\n', null, '!pop'),
),
'line_directive' => array(
array('[^?\\n]+', 'directive'),
array('\\n', null, '!pop'),
)
);
}
}
<?php
final class SplexSourcePawnFragmentParser {
public function parse(array $tokens)
{
$functions = array();
$scope = 0;
$function = array(); // type, name, doc, return, static
$params = array();
$param = array(); // tag, name, array, const
$parsing_params = false;
foreach ($tokens as $key => $token)
{
if ($token[0] === NULL)
{
continue;
}
if ($scope != 0 || $token[0] === "block_start")
{
if ($token[0] === "block_start")
$scope += 1;
elseif ($token[0] === "block_end")
$scope -= 1;
$function = array();
$params = array();
$param = array();
continue;
}
if ($token[0] === "end_statement")
{
$function = array();
$params = array();
$param = array();
continue;
}
if ($token[0] === "doccomment")
{
$function['doc'] = $token[1];
continue;
}
if ($token[0] === "keyword")
{
if ($parsing_params && $token[1] === "const")
{
$param['const'] = true;
continue;
}
if (!$parsing_params && ($token[1] === "native" || $token[1] === "forward" || $token[1] === "stock" || $token[1] === "public"))
{
$function['type'] = $token[1];
continue;
}
if (!$parsing_params && $token[1] === "static")
{
$function['static'] = true;
continue;
}
}
if ($token[0] === "function")
{
$function['name'] = $token[1];
continue;
}
if ($token[0] === "tag")
{
$tag = substr($token[1], 0, -1);
if ($parsing_params)
$param['tag'] = $tag;
else
$function['return'] = $tag;
continue;
}
if (!$parsing_params && $token[0] === "paren_start")
{
$parsing_params = true;
continue;
}
if ($parsing_params && ($token[0] === "paren_end" || $token[0] === "comma"))
{
if (isset($param['name']))
{
$params[] = $param;
}
$param = array();
if ($token[0] === "paren_end")
{
$parsing_params = false;
if (isset($function['name']))
{
$function['params'] = $params;
$functions[] = $function;
}
$param = array();
$params = array();
$function = array();
}
continue;
}
if ($parsing_params && $token[0] === "identifier")
{
$param['name'] = $token[1];
continue;
}
if ($parsing_params && $token[0] === "array")
{
if ($token[1] === "[]")
$param['array'] = "-1";
else
$param['array'] = substr($token[1], 1, -1);
continue;
}
if ($parsing_params && $token[0] === "other" && $token[1] === "=")
{
$nextToken = $tokens[$key + 1];
$param['default'] = $nextToken[1];
if ($nextToken[0] === "string")
{
$param['default'] .= $tokens[$key + 2][1];
$nextToken = $tokens[$key + 3];
if ($nextToken[0] === "string")
$param['default'] .= $nextToken[1];
}
continue;
}
}
return $functions;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment