r3-v2/r3.php

1570 lines
38 KiB
PHP
Executable File

#!/usr/bin/php
<?php
include "utils.php";
include "graph.php";
global $files;
function getTokens($type)
{
$fn = fopen('src/templates/token.db', "r");
$tokens = [];
while (!feof($fn)) {
$line = fgets($fn);
$matches = [];
if (preg_match('/^(' . $type . '.*$)/', $line, $matches)) {
$tokens[$matches[1]] = [];
}
}
fclose($fn);
return $tokens;
}
/**
* @throws ErrorException
*/
function loadSaved($file, $tokens) {
$saveFile = $file . '.saved';
echo "loading file " . $saveFile . "\n";
$loadedTokens = [];
$fn = fopen($saveFile, "r");
if (!$fn) {
throw new ErrorException('Could not open save file: ' . $saveFile . "\n");
}
$currentTokenKey = null;
while (!feof($fn)) {
$line = fgets($fn);
$tokenFound = false;
foreach ($tokens as $key => $store) {
if (preg_match('/\b' . $key . '\b/', $line))
{
if (array_key_exists($key, $loadedTokens)) {
throw new ErrorException("TOKEN ALREADY EXISTS! : $key\n");
}
$tokenFound = true;
$loadedTokens[$key] = [];
$currentTokenKey = $key;
break;
}
}
if (!$tokenFound && $line != false) {
array_push($loadedTokens[$currentTokenKey], $line);
}
}
fclose($fn);
return $loadedTokens;
}
function getFileData($file, &$tokens)
{
$currentTokens = [];
$fn = fopen($file, "r");
while (!feof($fn)) {
$line = fgets($fn);
foreach ($tokens as $key => $store) {
if (preg_match('/\b' . $key . '_END\b/', $line)) {
array_pop($currentTokens);
break;
}
}
$size = sizeof($currentTokens);
if ($size > 0) {
array_push($tokens[$currentTokens[$size - 1]], $line);
}
foreach ($tokens as $key => $store) {
if (preg_match('/\b' . $key . '_START\b/', $line)) {
array_push($currentTokens, $key);
break;
}
}
}
fclose($fn);
}
function save($file, $tokens) {
echo "saving file " . $file . "\n";
getFileData($file, $tokens);
$saveFile =$file . '.saved';
$saved = [];
$stores = [];
foreach ($tokens as $key => $store) {
if (sizeof($store) > 0) {
$stores[$key] = $store;
array_push($saved, $key . "\n");
foreach ($store as $line) {
array_push($saved, $line);
}
}
}
file_put_contents($saveFile, $saved);
echo "saved file $saveFile\n";
return [
$saveFile,
$stores
];
}
function deleteSavedFile($saveFile)
{
if ($saveFile && file_exists($saveFile)) {
unlink($saveFile);
} else {
echo "Did not unlink file $saveFile because it did not exist.\n";
}
}
function getWhitespace($contents, $token)
{
$matches = [];
if (preg_match('/^\n*(\s*)\b' . $token . '\b/m', $contents, $matches)) {
return [
'white-space' => $matches[1],
'inline-comment' => false
];
} else {
if (preg_match('/^\n*(\s*)\/\/\b' . $token . '\b/m', $contents, $matches)) {
return [
'white-space' => $matches[1],
'inline-comment' => true
];
}
return null;
}
}
function updateSection($file, $token, $updates, $separator = "") {
if (getType($updates) === 'array') {
$updates = implode($separator, $updates);
}
if (strlen($updates) <= 0) {
echo "No contents to be updated for token $token\n";
return false;
}
if (substr($updates, -1) !== "\n") {
$updates .= "\n";
}
$contents = file_get_contents($file);
$whiteSpaceObject = getWhitespace($contents, $token . '_END');
if ($whiteSpaceObject === null) {
/**
* This file does not contain the token which requires an update - we can return here
*/
echo "Skipping token $token because it was not found but it could be generated soon...\n";
return $token;
}
$endToken = $token . "_END";
if ($whiteSpaceObject['inline-comment']) {
$endToken = '//' . $endToken;
}
$whiteSpace = $whiteSpaceObject['white-space'];
$contents = preg_replace(
'/\b' . $token . '_START\b.*?\b' . $token . '_END\b/s',
$token . "_START\n" . $updates . $whiteSpace . $endToken,
$contents
);
file_put_contents($file, $contents);
return true;
}
function getPropertyListItems($store)
{
$propertyListItems = [];
foreach ($store as $item) {
$item = trim($item);
$result = preg_split('/=/', $item);
$propertyListItem = '- ' . $result[0]. ' (Default value ' . $result[1] . ")";
array_push($propertyListItems, $propertyListItem);
}
return $propertyListItems;
}
function getMethodListItems($store, $parentStore = [], $parent = null)
{
$methodListItems = [];
foreach ($store as $item) {
$overrides = false;
foreach ($parentStore as $parentItem) {
if (trim($parentItem) === trim($item)) {
$overrides=true;
}
}
$details = getMethodDetails($item);
if ($overrides === true) {
$methodListItem = '- ' . $details['methodName'] . '(' . $details['args'] . ")\n";
$methodListItem .= " " . wordwrap('Overrides for ' . $parent->nameSpace . $parent->name . '.' . $details['methodName'] . '()', 110, "\n ") . "\n";
} else {
$methodListItem = '- ' . $details['methodName'] . '(' . $details['args'] . ")\n";
$methodListItem .= " " . wordwrap($details['comment'], 110, "\n ") . "\n";
}
array_push($methodListItems, $methodListItem);
}
return $methodListItems;
}
function doGetInheritedTemplateUpdates($node, $restoreTokens, $inherited = true, $for)
{
try {
$saveFile = $node->file . '.saved';
if (!file_exists($saveFile)) {
save($node->file, $restoreTokens);
}
$tokens = loadSaved($node->file, $restoreTokens);
if ($node->parent !== null) {
$parentSaveFile = $node->parent->file . '.saved';
if (!file_exists($parentSaveFile)) {
save($node->parent->file, $restoreTokens);
}
}
$parentTokens = loadSaved($node->parent->file, $restoreTokens);
} catch (ErrorException $e) {
echo $e->getMessage();
exit(1);
}
$updates = '';
$firstTemplate = false;
if ($node->parent !== null && $node->parent->name !== "R3") {
$updates = rtrim(doGetInheritedTemplateUpdates($node->parent, $restoreTokens, true, $for)) . "\n";
} else {
$firstTemplate = true;
}
$template = file_get_contents('src/templates/generated_inherited.template');
$CLASS_NAME = $node->name;
$token = 'CUSTOM_OPTIONS';
$store = getTokenStore($token, $tokens);
if (sizeof($store) <= 0) {
if ($inherited) {
$PROPERTY_LIST = '<no inherited properties>';
} else {
$PROPERTY_LIST = '<no properties>';
}
} else {
$propertyListItems = getPropertyListItems($store);
$PROPERTY_LIST = implode("\n ", $propertyListItems);
}
$PROPERTY_LIST = trim($PROPERTY_LIST);
$token = 'CUSTOM_STATIC_OPTIONS';
$store = getTokenStore($token, $tokens);
if (sizeof($store) <= 0) {
if ($inherited) {
$STATIC_PROPERTY_LIST = '<no inherited static properties>';
} else {
$STATIC_PROPERTY_LIST = '<no static properties>';
}
} else {
$propertyListItems = getPropertyListItems($store);
$STATIC_PROPERTY_LIST = implode("\n ", $propertyListItems);
}
$STATIC_PROPERTY_LIST = trim($STATIC_PROPERTY_LIST);
$token = 'CUSTOM_METHODS';
$store = getTokenStore($token, $tokens);
$parentStore = getTokenStore($token, $parentTokens);
if (sizeof($store) <= 0) {
if ($inherited) {
$METHOD_LIST = '<no inherited methods>';
} else {
$METHOD_LIST = '<no methods>';
}
} else {
$methodListItems = getMethodListItems($store, $parentStore, $node->parent);
$METHOD_LIST = implode("\n ", $methodListItems);
}
$METHOD_LIST = trim($METHOD_LIST);
$token = 'CUSTOM_STATIC_METHODS';
$store = getTokenStore($token, $tokens);
$parentStore = getTokenStore($token, $parentTokens);
if (sizeof($store) <= 0) {
if ($inherited) {
$STATIC_METHOD_LIST = '<no inherited static methods>';
} else {
$STATIC_METHOD_LIST = '<no static methods>';
}
} else {
$methodListItems = getMethodListItems($store, $parentStore, $node->parent);
$STATIC_METHOD_LIST = implode("\n ", $methodListItems);
}
$STATIC_METHOD_LIST = trim($STATIC_METHOD_LIST);
if ($inherited) {
$description = 'Inherited from';
} else {
$description = 'Belonging to';
}
if ($firstTemplate) {
$updated = str_replace("FIRST_TEMPLATE", "Class " . $for, $template);
} else {
$updated = preg_replace('/^.*?FIRST_TEMPLATE.*\n/m', "", $template);
}
if ($inherited) {
$INHERITED = 'Inherited ';
} else {
$INHERITED = '';
}
$updated = str_replace('INHERITED', $INHERITED, $updated);
$updated = str_replace('DESCRIPTION', $description, $updated);
$updated = str_replace('CLASS_NAME', $CLASS_NAME, $updated);
$updated = preg_replace('/\bPROPERTY_LIST\b/', $PROPERTY_LIST, $updated);
$updated = preg_replace('/\bSTATIC_PROPERTY_LIST\b/', $STATIC_PROPERTY_LIST, $updated);
$updated = str_replace('STATIC_METHOD_LIST', $STATIC_METHOD_LIST, $updated);
$updated = str_replace('METHOD_LIST', $METHOD_LIST, $updated);
$updates .= $updated;
return $updates;
}
function generateInherited($file, $restoreTokens)
{
echo "Generating inherited fields for $file\n";
global $graph;
$node = $graph->search('file', $file);
if ($node === null) {
/**
* This node is not part of R3
*/
return;
}
if ($node->parent === null) {
/**
* This node has no inherited properties
*/
return;
}
if ($node->parent->name === 'R3') {
/**
* This is a base class
*/
return;
}
$updates = doGetInheritedTemplateUpdates($node, $restoreTokens, false, $node->nameSpace . $node->nameSpaceClassName);
updateSection($file, 'GENERATED_INHERITED' , $updates);
}
function generateInitOptions($file, $tokens)
{
$token = 'CUSTOM_OPTIONS';
$store = getTokenStore($token, $tokens);
if (sizeof($store) <= 0) {
return;
}
echo "Will be building options for $token\n";
$template = file_get_contents('src/templates/generated_custom_options_init.template');
$updates = '';
foreach ($store as $item) {
$item = trim($item);
$key_value = preg_split('/=/', $item);
if ($key_value === false) {
continue;
}
$key = $key_value[0];
$value = $key_value[1];
$updated = str_replace('KEY', $key, $template);
$updated = str_replace('VALUE', $value, $updated);
$updates .= $updated;
}
updateSection($file, 'GENERATED_OPTIONS_INIT' , $updates);
}
function generateInitStaticOptions($file, $tokens)
{
$token = 'CUSTOM_STATIC_OPTIONS';
$store = getTokenStore($token, $tokens);
if (sizeof($store) <= 0) {
return;
}
echo "Will be building static options for $token\n";
$template = file_get_contents('src/templates/generated_custom_static_options_init.template');
$updates = '';
foreach ($store as $item) {
$item = trim($item);
$key_value = preg_split('/=/', $item);
if ($key_value === false) {
continue;
}
$key = $key_value[0];
$value = $key_value[1];
$updated = str_replace('KEY', $key, $template);
$updated = str_replace('VALUE', $value, $updated);
$updates .= $updated;
}
updateSection($file, 'GENERATED_STATIC_OPTIONS_INIT' , $updates);
}
function getTokenStore($tokenName, $tokens)
{
if (is_array($tokens) && array_key_exists($tokenName, $tokens)) {
return $tokens[$tokenName];
}
return [];
}
function getInstanceMappings($tokens)
{
$instanceMappings = [];
foreach (getTokenStore('CUSTOM_INSTANCE_OPTIONS_MAPPING', $tokens) as $mapping) {
$mapping = trim($mapping);
$key_value = preg_split('/=/', $mapping);
if ($key_value === false) {
continue;
}
$key = $key_value[0];
$value = $key_value[1];
$instanceMappings[$key] = $value;
}
return $instanceMappings;
}
function isExcluded($key, $tokens)
{
if (array_key_exists('CUSTOM_EXCLUDED_FROM_INSTANCE_OPTIONS', $tokens)) {
$excluded = [];
foreach ($tokens['CUSTOM_EXCLUDED_FROM_INSTANCE_OPTIONS'] as $exclude) {
array_push($excluded, trim($exclude));
}
if (in_array($key, $excluded)) {
return true;
}
}
return false;
}
function doInstanceUpdate($template, $tokens, $asArray = false)
{
$token = 'CUSTOM_OPTIONS';
$store = getTokenStore($token, $tokens);
if (sizeof($store) <= 0) {
return null;
}
$instanceMappings = getInstanceMappings($tokens);
$updates = '';
if ($asArray) {
$updates = [];
}
foreach ($store as $item) {
$item = trim($item);
$key_value = preg_split('/=/', $item);
if ($key_value === false) {
continue;
}
$key = $key_value[0];
$value = $key_value[0];
if (array_key_exists($key, $instanceMappings)) {
$value = $instanceMappings[$key];
}
if (isExcluded($key, $tokens)){
continue;
}
$updated = str_replace('INSTANCE_KEY', $value, $template);
$updated = str_replace('KEY', $key, $updated);
if ($asArray) {
array_push($updates, $updated);
} else {
$updates .= $updated;
}
}
return $updates;
}
function generateCreateInstanceOptions($file, $tokens)
{
$template = file_get_contents('src/templates/generated_create_instance_options.template');
$updates = doInstanceUpdate($template, $tokens, true);
if ($updates) {
echo "Updating create instance options\n";
updateSection($file, 'GENERATED_CREATE_INSTANCE_OPTIONS', $updates, ",\n");
} else {
echo "No create instance options found to generate\n";
}
}
/**
* Process updateInstance options
*/
function generateUpdateInstanceOptions($file, $tokens)
{
$template = file_get_contents('src/templates/generated_update_instance_options.template');
$updates = doInstanceUpdate($template, $tokens);
if ($updates) {
echo "Updating update instance options\n";
updateSection($file, 'GENERATED_UPDATE_INSTANCE_OPTIONS', $updates);
} else {
echo "No update instance options found to generate\n";
}
}
/**
* Process updateFromInstance options
*/
function generateUpdateFromInstanceOptions($file, $tokens)
{
$template = file_get_contents('src/templates/generated_update_from_instance_options.template');
$updates = doInstanceUpdate($template, $tokens);
if ($updates) {
echo "Updating update from instance options\n";
updateSection($file, 'GENERATED_UPDATE_FROM_INSTANCE_OPTIONS', $updates);
} else {
echo "No update from instance options found to generate\n";
}
}
function generateEventListenersStart($file, $tokens)
{
$token = 'CUSTOM_STATIC_EVENT_LISTENERS';
$store = getTokenStore($token, $tokens);
if (sizeof($store) <= 0) {
return;
}
echo "Will be building events for $file\n";
$template = file_get_contents('src/templates/generated_static_event_listeners_start.template');
$updated = '';
foreach ($store as $item) {
$item = trim($item);
$eventName = preg_replace('/Event./', '', $item);
$methodName = 'ON_'.$eventName;
$methodName = to_camel_case_from_upper_underscore($methodName);
$updates = str_replace('EVENT_NAME', $item, $template);
$updates = str_replace('CALL_BACK', $methodName, $updates);
$updated .= $updates;
}
updateSection($file, 'GENERATED_STATIC_EVENT_LISTENERS_START' , $updated);
}
function generateEventListenersStop($file, $tokens)
{
$token = 'CUSTOM_STATIC_EVENT_LISTENERS';
$store = getTokenStore($token, $tokens);
if (sizeof($store) <= 0) {
return;
}
echo "Will be events for $file\n";
$template = file_get_contents('src/templates/generated_static_event_listeners_stop.template');
$updated = '';
foreach ($store as $item) {
$item = trim($item);
$updates = str_replace('EVENT_NAME', $item, $template);
$updated .= $updates;
}
updateSection($file, 'GENERATED_STATIC_EVENT_LISTENERS_STOP' , $updated);
}
/**
* @param $item
* @return array
*/
function getMethodDetails($item)
{
$item = trim($item);
$methodName = $item;
$matches = [];
$result = preg_match('/^(.*?)\(/', $item, $matches);
if ($result !== false && sizeof($matches) >= 2) {
$methodName = $matches[1];
}
$args = '';
$result = preg_match('/\((.*?)\)/', $item, $matches);
if ($result !== false && sizeof($matches) >= 2) {
$args = $matches[1];
}
$argsArray = preg_split('/,(\s*)/', $args);
$comment = 'No comment';
$result = preg_match('/.*?\).*?(\w.*$)/', $item, $matches);
if ($result !== false && sizeof($matches) >= 2) {
$comment = $matches[1];
}
$returns = preg_split('/@return[s]*\s*/', $comment);
if (sizeof($returns) > 1) {
$comment = $returns[0];
$returns = $returns[1];
} else {
$returns = null;
}
$methodTokenName = strtoupper(from_camel_case($methodName));
return [
'methodName' => $methodName,
'methodTokenName' => $methodTokenName,
'args' => $args,
'argsArray' => $argsArray,
'comment' => $comment,
'returns' => $returns
];
}
/**
* @param $template
* @param $tokens
* @param $token
* @return string|null
*/
function doMethodUpdate($template, $tokens, $token)
{
$store = getTokenStore($token, $tokens);
if (sizeof($store) <= 0) {
return null;
}
$updates = '';
foreach ($store as $item) {
$detail = getMethodDetails($item);
$argsArray = $detail['argsArray'];
$args = $detail['args'];
$methodTokenName = $detail['methodTokenName'];
$methodName = $detail['methodName'];
$comment = $detail['comment'];
$returns = $detail['returns'];
if (sizeof($argsArray) > 1) {
$args = implode(",\n ", $argsArray);
$args = "\n " . $args . "\n ";
$params = implode("\n * @param ", $argsArray);
$params = "\n * @param " . $params;
} else if (sizeof($argsArray) === 1) {
if ($args === '') {
$params = $args;
} else {
$params = "\n * @param " . $args;
}
}
if ($returns !== null) {
$returns = "\n * @returns " . $returns;
}
$comment = wordwrap($comment, 110, "\n * ");
$updated = $template;
if ($token === 'CUSTOM_METHODS') {
$potentialTemplate = strtolower('src/templates/' . $methodTokenName . '.template');
} else {
$potentialTemplate = strtolower('src/templates/static_' . $methodTokenName . '.template');
}
if (file_exists($potentialTemplate)) {
$functionTemplate = file_get_contents($potentialTemplate);
$updated = preg_replace('/^\s*FUNCTION_TEMPLATE/m', $functionTemplate, $updated);
} else {
$updated = preg_replace('/^.*?FUNCTION_TEMPLATE.*\n/m', '', $updated);
}
$updated = str_replace('METHOD_ARGS', $args, $updated);
$updated = str_replace('METHOD_NAME_UPPERCASE', $methodTokenName, $updated);
$updated = str_replace('METHOD_NAME', $methodName, $updated);
$updated = str_replace('COMMENT', $comment, $updated);
$updated = str_replace('PARAMS', $params, $updated);
$updated = str_replace('RETURNS', $returns, $updated);
$updates .= $updated;
}
return $updates;
}
function generateStaticMethods($file, $tokens)
{
$token = 'CUSTOM_STATIC_METHODS';
$template = file_get_contents('src/templates/generated_static_methods.template');
$updates = doMethodUpdate($template, $tokens, $token);
if ($updates) {
echo "Updating static methods\n";
updateSection($file, 'GENERATED_STATIC_METHODS', $updates);
} else {
echo "No static methods found to generate\n";
}
}
function getEventListenerUpdates($template, $tokens, $token)
{
$store = getTokenStore($token, $tokens);
if (sizeof($store) <= 0) {
return null;
}
$updates = '';
foreach ($store as $item) {
// $detail = getMethodDetails($item);
// $argsArray = $detail['argsArray'];
// $args = $detail['args'];
// $methodTokenName = $detail['methodTokenName'];
// $methodName = $detail['methodName'];
// $comment = $detail['comment'];
// $returns = $detail['returns'];
//
// if (sizeof($argsArray) > 1) {
// $args = implode(",\n ", $argsArray);
// $args = "\n " . $args . "\n ";
// $params = implode("\n * @param ", $argsArray);
// $params = "\n * @param " . $params;
// } else if (sizeof($argsArray) === 1) {
// if ($args === '') {
// $params = $args;
// } else {
// $params = "\n * @param " . $args;
// }
// }
//
// if ($returns !== null) {
// $returns = "\n * @returns " . $returns;
// }
//
// $comment = wordwrap($comment, 110, "\n * ");
//
// $updated = $template;
//
// if ($token === 'CUSTOM_METHODS') {
// $potentialTemplate = strtolower('src/templates/' . $methodTokenName . '.template');
// } else {
// $potentialTemplate = strtolower('src/templates/static_' . $methodTokenName . '.template');
// }
//
// if (file_exists($potentialTemplate)) {
// $functionTemplate = file_get_contents($potentialTemplate);
// $updated = preg_replace('/^\s*FUNCTION_TEMPLATE/m', $functionTemplate, $updated);
// } else {
// $updated = preg_replace('/^.*?FUNCTION_TEMPLATE.*\n/m', '', $updated);
// }
//
// $updated = str_replace('METHOD_ARGS', $args, $updated);
// $updated = str_replace('METHOD_NAME_UPPERCASE', $methodTokenName, $updated);
// $updated = str_replace('METHOD_NAME', $methodName, $updated);
// $updated = str_replace('COMMENT', $comment, $updated);
// $updated = str_replace('PARAMS', $params, $updated);
// $updated = str_replace('RETURNS', $returns, $updated);
$item = trim($item);
$eventName = preg_replace('/Event./', '', $item);
$methodName = 'ON_'.$eventName;
$methodTokenName = $methodName;
$methodName = to_camel_case_from_upper_underscore($methodName);
$updated = $template;
$methodArgs = 'data';
$params = "\n * @param " . $methodArgs . " (The event data passed as argument - typically an R3Object)";
$returns = "\n * @return null";
$potentialTemplate = strtolower('src/templates/static_' . $methodTokenName . '.template');
if (file_exists($potentialTemplate)) {
$functionTemplate = file_get_contents($potentialTemplate);
$updated = preg_replace('/^\s*FUNCTION_TEMPLATE/m', $functionTemplate, $updated);
} else {
$updated = preg_replace('/^.*?FUNCTION_TEMPLATE.*\n/m', '', $updated);
}
$updated = str_replace('METHOD_NAME_UPPERCASE', $methodTokenName, $updated);
$updated = str_replace('METHOD_NAME', $methodName, $updated);
$updated = str_replace('METHOD_ARGS', $methodArgs, $updated);
$comment = 'Listens to events of type ' . $item . ' and executes this function.';
$comment = wordwrap($comment, 110, "\n * ");
$updated = str_replace('COMMENT', $comment, $updated);
$updated = str_replace('PARAMS', $params, $updated);
$updated = str_replace('RETURNS', $returns, $updated);
$updates .= $updated;
}
return $updates;
}
function generateStaticEventListenerMethods($file, $tokens)
{
$token = 'CUSTOM_STATIC_EVENT_LISTENERS';
$template = file_get_contents('src/templates/generated_static_methods.template');
$updates = getEventListenerUpdates($template, $tokens, $token);
if ($updates) {
echo "Updating static event listeners.. \n";
updateSection($file, 'GENERATED_STATIC_EVENT_LISTENER_METHODS', $updates);
} else {
echo "No static event listeners found to generate\n";
}
}
function generateMethods($file, $tokens)
{
$token = 'CUSTOM_METHODS';
$template = file_get_contents('src/templates/generated_methods.template');
$updates = doMethodUpdate($template, $tokens, $token);
if ($updates) {
echo "Updating methods\n";
updateSection($file, 'GENERATED_METHODS', $updates);
} else {
echo "No methods found to generate\n";
}
}
function generateIndex($types)
{
/**
* Graph $graph
*/
global $graph;
foreach ($types as $type) {
$nodes = $graph->search('name', $type);
$template = file_get_contents('src/templates/index.template');
$imports = [];
$exports = [];
$nodes = array_merge([$nodes], $nodes->children);
foreach ($nodes as $child) {
$file = null;
if ($type === 'System') {
$file = str_replace('src/r3/r3-system', '.', $child->file);
}
if ($type === 'Component') {
$file = str_replace('src/r3/r3-component', '.', $child->file);
}
array_push($imports, "const " . $child->name . ' = require(\'' . $file . "');");
array_push($exports, $child->name);
}
$indexFile = null;
if ($type === 'System') {
$indexFile = 'src/r3/r3-system/index.js';
}
if ($type === 'Component') {
$indexFile = 'src/r3/r3-component/index.js';
}
file_put_contents($indexFile, $template);
updateSection($indexFile, 'GENERATED_IMPORTS', implode("\n", $imports));
updateSection($indexFile, 'GENERATED_EXPORTS', " " . implode(",\n ", $exports));
}
}
function generateR3($nodes)
{
$imports = [];
$defines = [];
$convenientDefines = [];
foreach ($nodes as $node) {
$file = str_replace('src/r3', '.', $node->file);
array_push($imports, "const " . $node->name . ' = require(\'' . $file . "');");
array_push($defines, $node->nameSpace . $node->nameSpaceClassName . ' = ' . $node->name);
if (sizeof($node->children) > 0 && substr_count($node->nameSpace, ".") > 1) {
$convenientDefine = "R3." . $node->nameSpaceClassName . ' = ' . $node->name;
array_push($convenientDefines, $convenientDefine);
}
}
$r3File = 'src/r3/r3-r3.js';
save($r3File, getTokens('CUSTOM'));
$tokens = loadSaved($r3File, getTokens('CUSTOM'));
$template = file_get_contents('src/templates/r3-base.template');
$version = file_get_contents('version');
$template = str_replace('DATE', date("Y M d - H:i:s a"), $template);
$template = str_replace('VERSION', $version, $template);
file_put_contents($r3File, $template);
$packageJson = file_get_contents('package.json');
$packageJson = preg_replace('/(.*version.*: ").*(".*)/', '${1}' . $version . '${2}', $packageJson);
file_put_contents('package.json', $packageJson);
updateSection($r3File, 'GENERATED_IMPORTS', implode("\n", $imports));
updateSection($r3File, 'GENERATED_DEFINES', implode(";\n", $defines) . ";");
updateSection($r3File, 'GENERATED_CONVENIENT_DEFINES', implode(";\n", $convenientDefines) . ";");
if (in_array('CUSTOM_CONVENIENT_DEFINES', array_keys($tokens))) {
updateSection($r3File, 'CUSTOM_CONVENIENT_DEFINES', $tokens['CUSTOM_CONVENIENT_DEFINES']);
}
$indexFile = 'src/r3/index.js';
$template = file_get_contents('src/templates/index.template');
file_put_contents($indexFile, $template);
$imports = ['const R3 = require(\'r3-r3.js\');'];
$exports = ' R3';
$indexBody = [];
array_push($indexBody, "\nconsole.log('r3.js - version ' + R3.version + ' compiled ' + R3.compileDate);\n\n");
foreach ($nodes as $node) {
/**
* Node $node
*/
if (preg_match('/\bSystem\w+\b/', $node->name)){
array_push($indexBody, $node->nameSpace . $node->nameSpaceClassName . ".Start();");
}
}
updateSection($indexFile, 'GENERATED_IMPORTS', implode("\n", $imports));
updateSection($indexFile, 'GENERATED_INDEX_BODY', implode("\n", $indexBody));
updateSection($indexFile, 'GENERATED_EXPORTS', $exports);
}
function generateEvents()
{
global $files;
$events = [];
foreach ($files as $file) {
// $file = './src/r3/' . $file;
// echo $file . "\n";
// continue;
if (
preg_match('/\.js$/', $file) &&
!preg_match('/r3\-event/', $file)
) {
echo "processing file " . $file . "\n";
$fn = fopen($file, "r");
while (!feof($fn)) {
$line = fgets($fn);
if (
preg_match('/Event\./', $line) &&
!preg_match('/Emit|Subscribe|.call|GetEventName|Async|prototype/', $line)
) {
$matches = [];
preg_match_all('/(Event\..*?)(\s+|,|;|$|\))/', $line, $matches);
if ($matches[1] && $matches[1][0]) {
$event = $matches[1][0];
if (in_array($event, $events)) {
// Do nothing
} else {
array_push($events, $event);
}
}
}
}
fclose($fn);
}
}
array_push($events, 'Event.START');
array_push($events, 'Event.PAUSE');
array_push($events, 'Event.RESTART');
sort($events);
$i = 1;
$eventList = '';
$eventFunction = "Event.GetEventName = function(eventId) {\n\n\tswitch(eventId) {\n";
foreach ($events as $event) {
$eventList .= $event . " = " . "0x" . dechex($i) . ";\n";
$eventFunction .= "\t\tcase 0x" . dechex($i). " : return '" . strtolower(str_replace('Event.', '', $event)) . "';\n";
$i++;
}
$eventList .= "Event.MAX_EVENTS = " . "0x" . dechex($i) . ";\n\n";
$eventFunction .= "\t\tdefault :\n\t\t\tthrow new Error('Event type not defined : ' + eventId);\n";
$eventFunction .= "\t}\n\n";
$eventFunction .= "};\n";
echo $eventList;
echo $eventFunction;
updateSection('./src/r3/r3-event.js', 'GENERATED_EVENTS' , $eventList . $eventFunction);
}
function generateR3Dist($nodes)
{
$r3jsFile = 'dist/r3.js';
$r3jsSource = 'src/r3/r3-r3.js';
$r3jsBaseTemplate = 'src/templates/r3-base.template';
$r3js = fopen($r3jsFile, "w");
ftruncate($r3js, 0);
// $version = file_get_contents('version');
// $packageJson = file_get_contents('package.json');
// $packageJson = preg_replace('/(.*version.*: ").*(".*)/', '${1}' . $version . '${2}', $packageJson);
// file_put_contents('package.json', $packageJson);
$version = file_get_contents('version');
$template = file_get_contents($r3jsBaseTemplate);
$template = str_replace('DATE', date("Y M d - H:i:s a"), $template);
$template = str_replace('VERSION', $version, $template);
fwrite($r3js, $template);
$generateTokens = getTokens('GENERATE');
$customTokens = getTokens('CUSTOM');
$savedGenerate = save($r3jsSource, $generateTokens)[1];
$savedCustom = save($r3jsSource, $customTokens)[1];
foreach ($nodes as $node) {
$contents = file_get_contents($node->file);
fwrite($r3js, $contents);
}
foreach ($savedGenerate as $key => $store)
{
if ($key === 'GENERATED_IMPORTS') {
continue;
}
foreach ($store as $line) {
fwrite($r3js, $line);
}
}
foreach ($savedCustom as $key => $store)
{
foreach ($store as $line) {
fwrite($r3js, $line);
}
}
$contents = file_get_contents('src/r3/index.js');
fwrite($r3js, $contents);
fclose($r3js);
/**
* Now start cleaning up the file
*/
$contents = file_get_contents($r3jsFile);
$contents = preg_replace('/\n^\/\/\bGENERATED_IMPORTS_START\b.*?\bGENERATED_IMPORTS_END.*?\n$/sm', '', $contents);
$contents = preg_replace('/\n^\s+\/\/\bGENERATED_EXPORTS_START\b.*?\bGENERATED_EXPORTS_END.*?$/sm', '', $contents);
$contents = preg_replace('/\n^\s+\bCUSTOM_OPTIONS_START\b.*?\bCUSTOM_OPTIONS_END.*?$/sm', '', $contents);
$contents = preg_replace('/\n^\s+\bCUSTOM_METHODS_START\b.*?\bCUSTOM_METHODS_END.*?$/sm', '', $contents);
$contents = preg_replace('/\n^\s+\bCUSTOM_STATIC_METHODS_START\b.*?\bCUSTOM_STATIC_METHODS_END.*?$/sm', '', $contents);
$contents = preg_replace('/\n^\s+\bCUSTOM_STATIC_EVENT_LISTENERS_START\b.*?\bCUSTOM_STATIC_EVENT_LISTENERS_END.*?$/sm', '', $contents);
// $contents = preg_replace('/^\s+\bCUSTOM_STATIC_EVENT_LISTENERS_START.*?$/sm', " Listens to the following Events:\n", $contents);
$contents = preg_replace('/\n^\bmodule\.exports\s+=\s+{.*?}$/sm', '', $contents);
$contents = preg_replace('/\n^\bmodule\.exports\s+=.*?$/sm', '', $contents);
$contents = preg_replace('/\n^\bconst.*?= require.*?$/sm', '', $contents);
foreach ($generateTokens as $generateTokenKey => $generateTokenValue) {
/**
* Remove generate tokens
*/
$contents = preg_replace('/.*\b' . $generateTokenKey . '(_START|_END)\b.*?\n/m', '', $contents );
}
foreach ($customTokens as $customTokenKey => $customTokenValue) {
/**
* Remove generate tokens
*/
$contents = preg_replace('/.*\b' . $customTokenKey . '(_START|_END)\b.*?\n/m', '', $contents );
}
$contents = preg_replace('/\n^\/\*\*\s+\*\*\/\s*?$/sm', '', $contents);
$contents = preg_replace('/\n\n\n+/sm', "\n\n", $contents);
file_put_contents($r3jsFile, $contents);
}
function updateParentSystems($nodes)
{
foreach ($nodes as $node) {
if (preg_match('/System/', $node->name)) {
$className = $node->name;
$parentName = $node->parent->name;
if ($node->parent->parent === null) {
/**
* We are working with the base system class
*/
$parentName = $node->name;
}
$contents = file_get_contents($node->file);
$contents = preg_replace('/PARENT_SYSTEM/', $parentName, $contents);
$contents = preg_replace('/CLASS_NAME/', $className, $contents);
$contents = preg_replace('/SYSTEM_NAME/', $className, $contents);
file_put_contents($node->file, $contents);
}
}
}
function buildNodeList($file)
{
echo "loading file $file\n";
global $nodeList;
$fn = fopen($file, "r");
$line = '';
$found = false;
while (!feof($fn) && !$found) {
$line = fgets($fn);
if (preg_match('/^class\s+/', $line)) {
$found = true;
break;
}
}
if ($found) {
// echo $line . "\n";
$matches = [];
$result = preg_match('/^class\s+(.*?)(\s+extends\s+(.*?)\s+|\s+?{)/', $line, $matches);
if ($result === false) {
throw new ErrorException('Could not match');
}
$extends = null;
if (sizeof($matches) === 4) {
$class = $matches[1];
$extends = $matches[3];
} else if (sizeof($matches) === 3) {
$class = $matches[1];
} else {
throw new ErrorException('Unhandled case');
}
$nameSpace = '';
$nameSpaceClassName = $class;
if ($extends) {
$nameSpaceClassName = str_replace($extends, '', $class);
$nameSpaceClassName = str_replace('R3', '', $nameSpaceClassName);
}
$node = new Node(
$file,
$class,
$nameSpace,
$nameSpaceClassName,
$extends
);
array_push($nodeList, $node);
} else {
echo "not found\n";
}
fclose($fn);
}
//function generateRuntimes()
//{
//
// updateSection(
// 'src/r3/r3-runtime.js',
// 'GENERATED_RUNTIMES',
// [
// 'Runtime.RUNTIME_DEFAULT'
// ]
// );
//
//}
$nodeList = [];
/**
* @throws ErrorException
*/
foreach ($files as $file) {
$saveFile = null;
if ($argv[2] == 'save') {
$saveFile = $file . '.saved';
if (file_exists($saveFile)) {
echo "A previous restore operation did not complete - please remove the saved file before trying this again\n";
echo "The save file is located at $saveFile\n";
echo "Remove easily with:\n";
echo "rm $saveFile\n";
exit(1);
}
$tokens = getTokens('CUSTOM');
$result = save($file, $tokens);
exit(0);
} else if ($argv[2] == 'restore') {
$saveFile = $file . '.saved';
$restoreTokens = getTokens('CUSTOM');
$restoreTokenKeys = array_keys($restoreTokens);
try {
$tokens = loadSaved($file, $restoreTokens);
} catch (ErrorException $e) {
echo $e->getMessage();
exit(1);
}
$skipped = [];
foreach ($tokens as $token => $store) {
if (in_array($token, $restoreTokenKeys)) {
updateSection($file, $token, $store);
}
}
/**
* Check if we have no saved custom methods but introduced them
* from a template
*/
if (!in_array('CUSTOM_METHODS', array_keys($tokens))){
$methodTokens = getTokens('CUSTOM_METHODS');
getFileData($file, $methodTokens);
if (sizeof($methodTokens['CUSTOM_METHODS']) > 0) {
$tokens['CUSTOM_METHODS'] = $methodTokens['CUSTOM_METHODS'];
}
}
generateMethods($file, $tokens);
generateStaticMethods($file, $tokens);
generateStaticEventListenerMethods($file, $tokens);
generateInitOptions($file, $tokens);
generateInitStaticOptions($file, $tokens);
generateCreateInstanceOptions($file, $tokens);
generateUpdateInstanceOptions($file, $tokens);
generateUpdateFromInstanceOptions($file, $tokens);
generateEventListenersStart($file, $tokens);
generateEventListenersStop($file, $tokens);
/**
* Try to restore the rest of the old data because now methods were generated.
* If not all data restores now - a method name / token has changed and we need
* to notify the user
*/
foreach ($tokens as $token => $store) {
if (in_array($token, $restoreTokenKeys)) {
$result = updateSection($file, $token, $store);
if ($result !== true && $result !== false) {
array_push($skipped, $result);
}
}
}
if (sizeof($skipped) !== 0) {
echo "Some tokens could not be restored because they could not be found in the new version\n";
print_r($skipped);
echo "Please restore them manually from the saved file :$saveFile\n";
echo "If you do not do it now - on the next template update code will be overwritten and you could lose code!!!\n";
exit(1);
} else {
deleteSavedFile($saveFile);
exit(0);
}
} else if ($argv[2] == 'build-dist') {
buildNodeList($file);
}
}
if ($argv[2] == 'generate-events') {
generateEvents();
}
if ($argv[2] == 'build-dist') {
global $nodeList;
/**
* Now generate the graph based on the new classes
*/
$graph = new Graph(
$nodeList
);
$restoreTokens = getTokens('CUSTOM');
$restoreTokenKeys = array_keys($restoreTokens);
/**
* Now start processing the files again - this time generating linked objects / inherited properties / methods
*/
foreach ($files as $file) {
generateInherited($file, $restoreTokens);
}
generateIndex(
[
'System',
'Component'
]
);
$nodes = $graph->walk();
// Remove R3 (first node) from the list
array_shift($nodes);
updateParentSystems($nodes);
generateR3($nodes);
generateR3Dist($nodes);
foreach ($files as $file) {
$saveFile = $file . '.saved';
deleteSavedFile($saveFile);
}
}
exit(0);
?>