Example #1
1
function yay_parse(string $source, Directives $directives = null, BlueContext $blueContext = null) : string
{
    if ($gc = gc_enabled()) {
        gc_disable();
    }
    // important optimization!
    static $globalDirectives = null;
    if (null === $globalDirectives) {
        $globalDirectives = new ArrayObject();
    }
    $directives = $directives ?: new Directives();
    $blueContext = $blueContext ?: new BlueContext();
    $cg = (object) ['ts' => TokenStream::fromSource($source), 'directives' => $directives, 'cycle' => new Cycle($source), 'globalDirectives' => $globalDirectives, 'blueContext' => $blueContext];
    foreach ($cg->globalDirectives as $d) {
        $cg->directives->add($d);
    }
    traverse(midrule(function (TokenStream $ts) use($directives, $blueContext) {
        $token = $ts->current();
        tail_call:
        if (null === $token) {
            return;
        }
        // skip when something looks like a new macro to be parsed
        if ('macro' === (string) $token) {
            return;
        }
        // here we do the 'magic' to match and expand userland macros
        $directives->apply($ts, $token, $blueContext);
        $token = $ts->next();
        goto tail_call;
    }), consume(chain(token(T_STRING, 'macro')->as('declaration'), optional(repeat(rtoken('/^·\\w+$/')))->as('tags'), lookahead(token('{')), commit(chain(braces()->as('pattern'), operator('>>'), braces()->as('expansion')))->as('body'), optional(token(';'))), CONSUME_DO_TRIM)->onCommit(function (Ast $macroAst) use($cg) {
        $scope = Map::fromEmpty();
        $tags = Map::fromValues(array_map('strval', $macroAst->{'tags'}));
        $pattern = new Pattern($macroAst->{'declaration'}->line(), $macroAst->{'body pattern'}, $tags, $scope);
        $expansion = new Expansion($macroAst->{'body expansion'}, $tags, $scope);
        $macro = new Macro($tags, $pattern, $expansion, $cg->cycle);
        $cg->directives->add($macro);
        // allocate the userland macro
        // allocate the userland macro globally if it's declared as global
        if ($macro->tags()->contains('·global')) {
            $cg->globalDirectives[] = $macro;
        }
    }))->parse($cg->ts);
    $expansion = (string) $cg->ts;
    if ($gc) {
        gc_enable();
    }
    return $expansion;
}
                     /* time to leave the comment?? */
                     $tmp = substr($code, $character_index - 1, 1);
                     if ($tmp == '*') {
                         $scope = CODE;
                     }
                     /* we only enter multi-line-comment mode from CODE scope AFAIK */
                 }
             }
         }
     }
     break;
 case '{':
     if ($scope == CODE) {
         /* start-of-block curly brace */
         /* Sigbjørn special: do not wrap and indent empty blocks (object literal) */
         if (lookahead($code, $character_index, true) == '}') {
             /* we have an object literal. We'll simply add a closing brace and jump ahead */
             $character_index = strpos($code, '}', $character_index);
             $post = '}';
             break;
         }
         $num_indents++;
         $post = "\n";
         $post .= str_repeat("\t", $num_indents);
         $at_start_of_statement_or_expression = true;
     } else {
         if ($scope == ESCAPE) {
             $scope = $before_escape_scope;
         }
     }
     break;