Index: parser.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/api/parser.inc,v
retrieving revision 1.41.2.41
diff -u -r1.41.2.41 parser.inc
--- parser.inc 2 Feb 2010 19:12:38 -0000 1.41.2.41
+++ parser.inc 6 Feb 2010 18:01:45 -0000
@@ -6,6 +6,16 @@
* The PHP documentation parser that generates content for api.module.
*/
+module_load_include('inc', 'pgp', 'engine/pgp.parser');
+module_load_include('inc', 'pgp', 'engine/pgp.reader');
+module_load_include('inc', 'pgp', 'engine/pgp.writer');
+module_load_include('inc', 'pgp', 'engine/pgp.editor');
+module_load_include('inc', 'pgp', 'engine/pgp.list');
+module_load_include('inc', 'pgp', 'engine/pgp.object');
+
+// Constant to allow for switching between API parser and Grammar Parser.
+define('USE_PARSER', 'YES');
+
function api_parse_file($callback, $file_path, $branch, $file_name) {
$docblock = array(
'object_name' => $file_name,
@@ -13,10 +23,14 @@
'object_type' => 'file',
'file_name' => $file_name,
'title' => strpos($file_name, '/') ? substr($file_name, strrpos($file_name, '/') + 1) : $file_name,
+ 'summary' => '',
'documentation' => '',
'version' => '',
'modified' => filemtime($file_path),
'source' => str_replace(array("\r\n", "\r"), array("\n", "\n"), file_get_contents($file_path)),
+ 'content' => '',
+ 'start_line' => 0,
+ 'see' => '',
);
$match = array();
@@ -59,6 +73,8 @@
* Read in the file at the given path and parse its documentation.
*/
function api_parse_php_file($docblock) {
+if (USE_PARSER == 'NO') {
+
$docblock['code'] = api_format_php($docblock['source']);
$docblocks = array($docblock);
@@ -168,6 +184,195 @@
api_save_documentation($docblocks);
}
+else {
+ api_parse_php_file_with_pgp($docblock);
+}
+}
+
+/**
+ * Returns a PGPEditor object. (Singleton)
+ *
+ * @return PGPEditor
+ */
+function api_get_editor() {
+ static $editor;
+ if (!$editor) {
+ $editor = new PGPEditor();
+ }
+ return $editor;
+}
+
+/**
+ * Read in the file at the given path and parse its documentation.
+ *
+ * @param array $docblock
+ * An array of the documentation block.
+ */
+function api_parse_php_file_with_pgp($docblock) {
+ // Edit grammar statements.
+ $editor = api_get_editor();
+
+ // Build grammar statements.
+ $reader = $editor->getReader();
+ $reader->setSnippet($docblock['source']);
+ $reader->addTokenNames();
+ $reader->buildGrammar();
+
+ // Retrieve items of interest.
+ $statements = $reader->getStatements();
+ if (!$statements) {
+ // This is a text file or template file with no functions, constants, etc.
+ $docblock['code'] = api_format_php($docblock['source']);
+ api_save_documentation(array($docblock));
+ // Free up memory.
+ $reader->reset();
+ pgp_log_memory_use('reset');
+ return;
+ }
+
+ // Reserve the first array slot for the file documentation block.
+ $docblocks = array();
+ $docblock['code'] = api_format_php($docblock['source']);
+ $docblocks[] = $docblock;
+
+ // Set default documenation block array for items other than the file.
+ $default_block = api_default_block($docblock);
+
+ api_documentation_loop($statements, $default_block, $docblocks); // api_documentation_loop($statements, $default_block);
+
+ // Free up memory.
+ $reader->reset();
+
+ api_save_documentation($docblocks);
+}
+
+/**
+ * Build a list of documentation items.
+ *
+ * @param array $statements
+ * A PGPBody object of body statements.
+ * @param array $docblock
+ * The default documentation block item for the file.
+ * @param array $docblocks
+ * The array of documentation block items for the file.
+ */
+function api_documentation_loop($statements, $default_block, &$docblocks) {
+// global $is_file_block;
+
+ $editor = api_get_editor();
+
+ // Traverse statement list to gather documentation items.
+ $current = $statements->first();
+ while ($current->next != NULL) {
+ $statement = $current->data;
+ $type = is_object($statement) ? $statement->type : $statement['type'];
+ // Common processing.
+ switch ($type) {
+// case T_INTERFACE:
+ case T_CLASS:
+ $default_block['class'] = '';
+ case T_FUNCTION:
+ case T_DEFINE:
+ case T_GLOBAL:
+// $docblock = api_documentation_item($statement, $default_block);
+ $docblock = $default_block;
+ $docblock['object_type'] = $editor->statementTypeToString($statement);
+ $docblock['object_name'] = $default_block['class'] . $editor->statementOperandToText($statement);
+ $docblock['title'] = $editor->statementOperandToText($statement);
+ $docblock['start_line'] = $current->line;
+
+ $docblock['content'] = $editor->commentToString($statement->comment);
+ unset($statement->comment);
+ $docblock['code'] = api_format_php("toString() ."\n?>");
+
+ if (in_array($statement->type, array(T_CLASS, T_FUNCTION))) {
+ $docblock['signature'] = $editor->functionGetSignature($statement);
+ }
+ break;
+
+ case T_DOC_COMMENT:
+ $docblock = $default_block;
+ // Copied from api_documentation_comment.
+ $docblock['content'] = $editor->commentToString($statement);
+ if (strpos($docblock['content'], '@mainpage') !== FALSE) {
+ // This is here so the block passes the if block after the switch.
+ $docblock['object_type'] = 'mainpage';
+ $docblock['object_name'] = $docblock['branch'];
+ }
+ if (strpos($docblock['content'], '@file') !== FALSE) {
+ $editor->getReader()->debugPrint2("found @file comment");
+ $docblock['object_type'] = 'file'; // Redundant?
+ $docblock['content'] = str_replace('@file', '', $docblock['content']);
+ $docblock['documentation'] = api_format_documentation($docblock['content']);
+ $docblock['summary'] = api_documentation_summary($docblock['documentation']);
+ // TODO This assumes only one "unattached" doc comment in the file!
+ $docblocks[0]['documentation'] = $docblock['documentation'];
+ $docblocks[0]['summary'] = $docblock['summary'];
+ // Reset the docblock so we do not add it again to the list.
+ $docblock = array();
+ }
+ elseif (strpos($docblock['content'], '@defgroup') !== FALSE) {
+ // This is here so the block passes the if block after the switch.
+ $docblock['object_type'] = 'group';
+ $docblock['object_name'] = 'group_xxx';
+ }
+ break;
+
+ default:
+ $docblock = array();
+ continue;
+
+// case T_CONST:
+// case T_VAR:
+// $docblock = api_documentation_global($statement, $branch_name, $file_name);
+// break;
+ }
+ if ($docblock && $docblock['object_type'] != '') {
+ if ($docblock['object_name'] == '') {
+ dpm("empty name\n");
+ dpm($docblock);
+ }
+ $docblocks[] = $docblock;
+ }
+
+ // Additional recursive processing on statements with bodies.
+ switch ($type) {
+// case T_INTERFACE:
+ case T_CLASS:
+ $default_block['class'] = $docblock['title'] . '::';
+ case T_FUNCTION:
+ api_documentation_loop($statement->body, $default_block, $docblocks);
+ break;
+ }
+ $current = $current->next;
+ }
+}
+
+/**
+ * Return default documentation block array.
+ *
+ * @param array $docblock
+ * An array of the documentation block.
+ * @return array
+ */
+function api_default_block($docblock) {
+ $default = array(
+ 'object_name' => '',
+ 'branch' => $docblock['branch'],
+ 'object_type' => '',
+ 'file_name' => $docblock['file_name'],
+ 'title' => '',
+ 'summary' => '',
+ 'documentation' => '',
+ 'code' => '',
+// 'version' => '', // Is this needed in other items?
+ 'modified' => $docblock['modified'], // Only needed for 'file' item, but it simplifies parameters in other functions.
+ 'start_line' => 0,
+ 'see' => '',
+ 'class' => '', // TODO Added this
+ );
+ return $default;
+}
/**
* Find functions called in a formatted block of code.
@@ -202,13 +407,15 @@
$dids = array();
// Look for @file block first so $docblocks[0] gets filled in before it is processed.
+// foreach ($docblocks as $docblock) {
+// if (preg_match('/' . API_RE_TAG_START . 'file/', $docblock['content'])) {
+// $docblocks[0]['content'] = str_replace('@file', '', $docblock['content']);
+// break;
+// }
+// }
foreach ($docblocks as $docblock) {
- if (preg_match('/' . API_RE_TAG_START . 'file/', $docblock['content'])) {
- $docblocks[0]['content'] = str_replace('@file', '', $docblock['content']);
- break;
- }
- }
- foreach ($docblocks as $docblock) {
+if (USE_PARSER == 'YES') {
+
if (preg_match('/' . API_RE_TAG_START . 'mainpage/', $docblock['content'])) {
$mainpage_matches = array();
preg_match('/' . API_RE_TAG_START . 'mainpage (.*?)\n/', $docblock['content'], $mainpage_matches);
@@ -234,11 +441,14 @@
continue;
}
+ $docblock['parameters'] = '';
+ $docblock['return_value'] = '';
+ $docblock['see'] = '';
if (!empty($docblock['content'])) {
// Find parameter definitions.
$param_match = array();
$offset = 0;
- $docblock['parameters'] = '';
+// $docblock['parameters'] = '';
while (preg_match('/' . API_RE_TAG_START . 'param(.*?)(?=\n' . API_RE_TAG_START . '|\n\n|$)/s', substr($docblock['content'], $offset), $param_match, PREG_OFFSET_CAPTURE)) {
$docblock['content'] = str_replace($param_match[0][0], '', $docblock['content']);
$docblock['parameters'] .= "\n\n". $param_match[1][0];
@@ -248,7 +458,7 @@
// Find return value definitions.
$return_matches = array();
- $docblock['return_value'] = '';
+// $docblock['return_value'] = '';
preg_match_all('/' . API_RE_TAG_START . 'return(.*?)(\n' . API_RE_TAG_START . '|\n\n|$)/s', $docblock['content'], $return_matches, PREG_SET_ORDER);
foreach ($return_matches as $return_match) {
$docblock['content'] = str_replace($return_match[0], '', $docblock['content']);
@@ -257,12 +467,13 @@
$docblock['return_value'] = api_format_documentation($docblock['return_value']);
// Find @see lines.
+ $see_match = array(); // TODO Mis-named variable.
$offset = 0;
- $docblock['see'] = '';
- while (preg_match('/' . API_RE_TAG_START . 'see(.*?)(?=\n' . API_RE_TAG_START . '|\n\n|$)/s', substr($docblock['content'], $offset), $match, PREG_OFFSET_CAPTURE)) {
- $docblock['content'] = str_replace($match[0][0], '', $docblock['content']);
- $docblock['see'] .= "\n\n". $match[1][0];
- $offset = $match[0][1];
+// $docblock['see'] = '';
+ while (preg_match('/' . API_RE_TAG_START . 'see(.*?)(?=\n' . API_RE_TAG_START . '|\n\n|$)/s', substr($docblock['content'], $offset), $see_match, PREG_OFFSET_CAPTURE)) {
+ $docblock['content'] = str_replace($see_match[0][0], '', $docblock['content']);
+ $docblock['see'] .= "\n\n". $see_match[1][0];
+ $offset = $see_match[0][1];
}
$docblock['see'] = api_format_documentation($docblock['see']);
@@ -298,18 +509,19 @@
$docblock['documentation'] = api_format_documentation($docblock['content']);
}
- if (!isset($docblock['summary'])) {
+ if (!$docblock['summary']) { // if (!isset($docblock['summary'])) {
$docblock['summary'] = api_documentation_summary($docblock['documentation']);
}
- $docblock['start_line'] = substr_count(substr($docblocks[0]['source'], 0, $docblock['code_start']), "\n");
- if (!isset($docblock['code'])) {
- if (isset($docblock['code_end'])) {
- $docblock['code'] = api_format_php("");
- }
- else {
- $docblock['code'] = '';
- }
- }
+// $docblock['start_line'] = substr_count(substr($docblocks[0]['source'], 0, $docblock['code_start']), "\n");
+// if (!isset($docblock['code'])) {
+// if (isset($docblock['code_end'])) {
+// $docblock['code'] = api_format_php("");
+// }
+// else {
+// $docblock['code'] = '';
+// }
+// }
+} // END of use_parser
$did = db_result(db_query("SELECT did FROM {api_documentation} WHERE object_name = '%s' AND branch_id = %d AND object_type = '%s' AND file_name = '%s'", $docblock['object_name'], $docblocks[0]['branch']->branch_id, $docblock['object_type'], $docblock['file_name']));
if ($did > 0) {
@@ -354,7 +566,7 @@
}
$dids[] = $did;
- }
+ } // END of foreach
$old_dids = array_diff($old_dids, $dids);
if (count($old_dids) > 0) {
@@ -571,7 +783,7 @@
switch ($type) {
case T_OPEN_TAG:
case T_CLOSE_TAG:
- $output .= ''. $value .'';
+ $output .= ''. $value .''; // TODO typo s/b boundary
break;
case T_COMMENT: