summaryrefslogtreecommitdiff
path: root/src/ste/Transcompiler.php
diff options
context:
space:
mode:
Diffstat (limited to 'src/ste/Transcompiler.php')
-rw-r--r--src/ste/Transcompiler.php181
1 files changed, 146 insertions, 35 deletions
diff --git a/src/ste/Transcompiler.php b/src/ste/Transcompiler.php
index d223b53..88c008e 100644
--- a/src/ste/Transcompiler.php
+++ b/src/ste/Transcompiler.php
@@ -1,13 +1,9 @@
<?php
-// File: Transcompiler.php
-
-// Namespace: kch42\ste
namespace kch42\ste;
-/*
- * Class: Transcompiler
- * Contains the STE transcompiler. You'll only need this, if you want to manually transcompile a STE template.
+/**
+ * Contains the STE compiler. You'll only need this, if you want to manually compile a STE template.
*/
class Transcompiler
{
@@ -18,33 +14,44 @@ class Transcompiler
return $typ . '_' . str_replace('.', '_', uniqid('', true));
}
+ private static function mark_builtin_callable(callable $c)
+ {
+ return $c;
+ }
+
public static function init_builtins()
{
if (self::$builtins !== null) {
return;
}
+ /** @var callable[] builtins */
self::$builtins = array(
- "if" => array("\\kch42\\ste\\Transcompiler", "builtin_if"),
- "cmp" => array("\\kch42\\ste\\Transcompiler", "builtin_cmp"),
- "not" => array("\\kch42\\ste\\Transcompiler", "builtin_not"),
- "even" => array("\\kch42\\ste\\Transcompiler", "builtin_even"),
- "for" => array("\\kch42\\ste\\Transcompiler", "builtin_for"),
- "foreach" => array("\\kch42\\ste\\Transcompiler", "builtin_foreach"),
- "infloop" => array("\\kch42\\ste\\Transcompiler", "builtin_infloop"),
- "break" => array("\\kch42\\ste\\Transcompiler", "builtin_break"),
- "continue" => array("\\kch42\\ste\\Transcompiler", "builtin_continue"),
- "block" => array("\\kch42\\ste\\Transcompiler", "builtin_block"),
- "load" => array("\\kch42\\ste\\Transcompiler", "builtin_load"),
- "mktag" => array("\\kch42\\ste\\Transcompiler", "builtin_mktag"),
- "tagcontent" => array("\\kch42\\ste\\Transcompiler", "builtin_tagcontent"),
- "set" => array("\\kch42\\ste\\Transcompiler", "builtin_set"),
- "setlocal" => array("\\kch42\\ste\\Transcompiler", "builtin_setlocal"),
- "get" => array("\\kch42\\ste\\Transcompiler", "builtin_get"),
- "calc" => array("\\kch42\\ste\\Transcompiler", "builtin_calc")
+ "if" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_if")),
+ "cmp" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_cmp")),
+ "not" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_not")),
+ "even" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_even")),
+ "for" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_for")),
+ "foreach" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_foreach")),
+ "infloop" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_infloop")),
+ "break" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_break")),
+ "continue" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_continue")),
+ "block" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_block")),
+ "load" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_load")),
+ "mktag" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_mktag")),
+ "tagcontent" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_tagcontent")),
+ "set" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_set")),
+ "setlocal" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_setlocal")),
+ "get" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_get")),
+ "calc" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_calc"))
);
}
+ /**
+ * @param TagNode $ast
+ * @return string
+ * @throws ParseCompileError
+ */
private static function builtin_if($ast)
{
$output = "";
@@ -53,9 +60,9 @@ class Transcompiler
$else = null;
foreach ($ast->sub as $node) {
- if (($node instanceof TagNode) and ($node->name == "then")) {
+ if (($node instanceof TagNode) && $node->name == "then") {
$then = $node->sub;
- } elseif (($node instanceof TagNode) and ($node->name == "else")) {
+ } elseif (($node instanceof TagNode) && $node->name == "else") {
$else = $node->sub;
} else {
$condition[] = $node;
@@ -78,6 +85,12 @@ class Transcompiler
}
return $output;
}
+
+ /**
+ * @param TagNode $ast
+ * @return string
+ * @throws ParseCompileError
+ */
private static function builtin_cmp($ast)
{
$operators = array(
@@ -116,7 +129,10 @@ class Transcompiler
if (!isset($ast->params["op"])) {
throw new ParseCompileError("self::Transcompile error: op not given in <ste:cmp>.", $ast->tpl, $ast->offset);
}
- if ((count($ast->params["op"]) == 1) and ($ast->params["op"][0] instanceof TextNode)) {
+ if (
+ count($ast->params["op"]) == 1
+ && ($ast->params["op"][0] instanceof TextNode)
+ ) {
/* Operator is known at compile time, this saves *a lot* of output code! */
$op = trim($ast->params["op"][0]->text);
$op_php = null;
@@ -144,6 +160,12 @@ class Transcompiler
}
return $code;
}
+
+ /**
+ * @param TagNode $ast
+ * @return string
+ * @throws ParseCompileError
+ */
private static function builtin_not($ast)
{
$code = "\$outputstack[] = '';\n\$outputstack_i++;\n";
@@ -151,6 +173,12 @@ class Transcompiler
$code .= "\$outputstack_i--;\n\$outputstack[\$outputstack_i] .= (!\$ste->evalbool(array_pop(\$outputstack))) ? 'yes' : '';\n";
return $code;
}
+
+ /**
+ * @param TagNode $ast
+ * @return string
+ * @throws ParseCompileError
+ */
private static function builtin_even($ast)
{
$code = "\$outputstack[] = '';\n\$outputstack_i++;\n";
@@ -158,6 +186,12 @@ class Transcompiler
$code .= "\$outputstack_i--;\n\$tmp_even = array_pop(\$outputstack);\n\$outputstack[\$outputstack_i] .= (is_numeric(\$tmp_even) and (\$tmp_even % 2 == 0)) ? 'yes' : '';\n";
return $code;
}
+
+ /**
+ * @param TagNode $ast
+ * @return string
+ * @throws ParseCompileError
+ */
private static function builtin_for($ast)
{
$code = "";
@@ -179,7 +213,10 @@ class Transcompiler
$step = null; /* i.e. not known at compilation time */
if (empty($ast->params["step"])) {
$step = 1;
- } elseif ((count($ast->params["step"]) == 1) and ($ast->params["step"][0] instanceof TextNode)) {
+ } elseif (
+ count($ast->params["step"]) == 1
+ && ($ast->params["step"][0] instanceof TextNode)
+ ) {
$step = $ast->params["step"][0]->text + 0;
} else {
list($val, $pre) = self::_transcompile($ast->params["step"], true);
@@ -216,6 +253,12 @@ class Transcompiler
return $code;
}
+
+ /**
+ * @param TagNode $ast
+ * @return string
+ * @throws ParseCompileError
+ */
private static function builtin_foreach($ast)
{
$loopname = self::tempvar("foreachloop");
@@ -282,18 +325,40 @@ class Transcompiler
return $code;
}
+
+ /**
+ * @param TagNode $ast
+ * @return string
+ * @throws ParseCompileError
+ */
private static function builtin_infloop($ast)
{
return "while(true)\n{\n" . self::indent_code(self::loopbody(self::indent_code(self::_transcompile($ast->sub)))) . "\n}\n";
}
+
+ /**
+ * @param TagNode $ast
+ * @return string
+ */
private static function builtin_break($ast)
{
return "throw new \\kch42\\ste\\BreakException();\n";
}
+
+ /**
+ * @param TagNode $ast
+ * @return string
+ */
private static function builtin_continue($ast)
{
return "throw new \\kch42\\ste\\ContinueException();\n";
}
+
+ /**
+ * @param TagNode $ast
+ * @return string
+ * @throws ParseCompileError
+ */
private static function builtin_block($ast)
{
if (empty($ast->params["name"])) {
@@ -315,6 +380,12 @@ class Transcompiler
return $code;
}
+
+ /**
+ * @param TagNode $ast
+ * @return string
+ * @throws ParseCompileError
+ */
private static function builtin_load($ast)
{
if (empty($ast->params["name"])) {
@@ -325,6 +396,12 @@ class Transcompiler
$code .= "\$outputstack[\$outputstack_i] .= \$ste->load(" . $val . ");\n";
return $code;
}
+
+ /**
+ * @param TagNode $ast
+ * @return string
+ * @throws ParseCompileError
+ */
private static function builtin_mktag($ast)
{
$code = "";
@@ -356,10 +433,21 @@ class Transcompiler
return $code;
}
+
+ /**
+ * @param TagNode $ast
+ * @return string
+ */
private static function builtin_tagcontent($ast)
{
return "\$outputstack[\$outputstack_i] .= \$sub(\$ste);";
}
+
+ /**
+ * @param TagNode $ast
+ * @return string
+ * @throws ParseCompileError
+ */
private static function builtin_set($ast)
{
if (empty($ast->params["var"])) {
@@ -376,6 +464,12 @@ class Transcompiler
return $code;
}
+
+ /**
+ * @param TagNode $ast
+ * @return string
+ * @throws ParseCompileError
+ */
private static function builtin_setlocal($ast)
{
if (empty($ast->params["var"])) {
@@ -392,6 +486,12 @@ class Transcompiler
return $code;
}
+
+ /**
+ * @param TagNode $ast
+ * @return string
+ * @throws ParseCompileError
+ */
private static function builtin_get($ast)
{
if (empty($ast->params["var"])) {
@@ -401,6 +501,12 @@ class Transcompiler
list($val, $pre) = self::_transcompile($ast->params["var"], true);
return "$pre\$outputstack[\$outputstack_i] .= \$ste->get_var_by_name(" . $val . ");";
}
+
+ /**
+ * @param TagNode $ast
+ * @return string
+ * @throws ParseCompileError
+ */
private static function builtin_calc($ast)
{
$code = "\$outputstack[] = '';\n\$outputstack_i++;\n";
@@ -425,6 +531,12 @@ class Transcompiler
return "try\n{\n" . self::indent_code($code) . "\n}\ncatch(\\kch42\\ste\\BreakException \$e) { break; }\ncatch(\\kch42\\ste\\ContinueException \$e) { continue; }\n";
}
+ /**
+ * @param ASTNode[] $ast
+ * @param bool $avoid_outputstack
+ * @return array|string
+ * @throws ParseCompileError
+ */
private static function _transcompile($ast, $avoid_outputstack = false)
{ /* The real self::transcompile function, does not add boilerplate code. */
$code = "";
@@ -477,16 +589,15 @@ class Transcompiler
return $code;
}
- /*
- * Function: transcompile
- * Transcompiles an abstract syntax tree to PHP.
- * You only need this function, if you want to manually transcompile a template.
+ /**
+ * Compiles an abstract syntax tree to PHP.
+ * You only need this function, if you want to manually compile a template.
*
- * Parameters:
- * $ast - The abstract syntax tree to transcompile.
+ * @param ASTNode[] $ast The abstract syntax tree to compile.
*
- * Returns:
- * PHP code. The PHP code is an anonymous function expecting a <STECore> instance as its parameter and returns a string (everything that was not pached into a section).
+ * @return string PHP code. The PHP code is an anonymous function expecting an {@see STECore} instance as its
+ * parameter and returns a string (everything that was not packed into a section).
+ * @throws ParseCompileError
*/
public static function transcompile($ast)
{ /* self::Transcompile and add some boilerplate code. */