function apply(TokenStream $ts, Directives $directives, BlueContext $blueContext) { $from = $ts->index(); $crossover = $this->pattern->match($ts); if (null === $crossover || $crossover instanceof Error) { return; } if ($this->hasExpansion) { $blueMacros = $this->getAllBlueMacrosFromCrossover($crossover->all(), $blueContext); if ($this->terminal && isset($blueMacros[$this->id])) { // already expanded $ts->jump($from); return; } $ts->unskip(...TokenStream::SKIPPABLE); $to = $ts->index(); $ts->extract($from, $to); $expansion = $this->expansion->expand($crossover, $this->cycle, $directives, $blueContext); $blueMacros[$this->id] = true; // paint blue context with tokens from expansion and disabled macros $node = $expansion->index(); while ($node instanceof Node) { $blueContext->addDisabledMacros($node->token, $blueMacros); $node = $node->next; } $ts->inject($expansion); } else { $ts->unskip(...TokenStream::SKIPPABLE); $ts->skip(T_WHITESPACE); $to = $ts->index(); $ts->extract($from, $to); } $this->cycle->next(); }
function hygienize(TokenStream $ts, array $context) : TokenStream { $ts->reset(); $cg = (object) ['node' => null, 'context' => $context, 'ts' => $ts]; $saveNode = function (Parser $parser) use($cg) { return midrule(function ($ts) use($cg, $parser) { $cg->node = $ts->index(); return $parser->parse($ts); }); }; traverse(chain(token(T_STRING, '··unsafe'), either(parentheses(), braces())), either($saveNode(token(T_VARIABLE)), chain($saveNode(identifier()), token(':')), chain(token(T_GOTO), $saveNode(identifier())))->onCommit(function (Ast $result) use($cg) { if (($t = $cg->node->token) && ($value = (string) $t) !== '$this') { $cg->node->token = new Token($t->type(), "{$value}·{$cg->context['scope']}", $t->line()); } }))->parse($ts); $ts->reset(); return $ts; }
function apply(TokenStream $ts) { $from = $ts->index(); $crossover = $this->pattern->parse($ts); if (null === $crossover || $crossover instanceof Error) { return; } if ($this->expansion) { // infer blue context from matched tokens $context = new BlueContext(); $tokens = $crossover->all(); array_walk_recursive($tokens, function (Token $token) use($context) { $context->inherit($token->context()); }); if (!$this->hasTag('·recursion')) { if ($context->contains($this->id())) { return; } } // already expanded $context->add($this->id()); $ts->unskip(...TokenStream::SKIPPABLE); $to = $ts->index(); $ts->extract($from, $to); $expansion = $this->mutate($this->expansion, $crossover); $this->cycle->next(); // paint blue context of expasion tokens $expansion->each(function (Token $token) use($context) { $token->context()->inherit($context); }); $ts->inject($expansion, $from); } else { $ts->unskip(...TokenStream::SKIPPABLE); $ts->skip(T_WHITESPACE); $to = $ts->index(); $ts->extract($from, $to); } }