Skip to content

Commit

Permalink
fix: make command tree updates lazy
Browse files Browse the repository at this point in the history
  • Loading branch information
vberlier committed Jul 15, 2022
1 parent 35a537e commit ec17f74
Showing 1 changed file with 35 additions and 14 deletions.
49 changes: 35 additions & 14 deletions bolt/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
from dataclasses import dataclass, field, replace
from typing import Any, Dict, Iterable, List, Optional, Set, Tuple, cast

from beet.core.utils import JsonDict
from beet.core.utils import JsonDict, log_time
from mecha import (
AdjacentConstraint,
AlternativeParser,
Expand Down Expand Up @@ -430,6 +430,11 @@ def get_stream_macro_scope(stream: TokenStream) -> Set[str]:
return stream.data.setdefault("macro_scope", set())


def get_stream_pending_macros(stream: TokenStream) -> List[AstMacro]:
"""Return pending macro declarations."""
return stream.data.setdefault("pending_macros", [])


@dataclass
class ToplevelHandler:
"""Handle toplevel root node."""
Expand Down Expand Up @@ -1043,14 +1048,32 @@ class MacroHandler:
parser: Parser

def __call__(self, stream: TokenStream) -> Any:
scope = get_stream_scope(stream)
pending_macros = get_stream_pending_macros(stream)

should_flush = not (
scope[0] in ["macro", "from"]
if scope
else (
(token := stream.peek())
and token.match(("literal", "macro"), ("literal", "from"))
)
)

if should_flush and pending_macros:
self.inject_syntax(stream, *pending_macros)
pending_macros.clear()

node = self.parser(stream)

if not isinstance(node, AstCommand):
return node

if node.identifier == "macro:name:subcommand":
node = self.create_macro(node)
self.inject_syntax(stream, node)
pending_macros.append(
replace(node, arguments=AstChildren(node.arguments[:-1]))
)
elif node.identifier in get_stream_macro_scope(stream):
call = AstMacroCall(identifier=node.identifier, arguments=node.arguments)
node = set_location(call, node)
Expand Down Expand Up @@ -1230,6 +1253,7 @@ def handle_import(self, stream: TokenStream, node: AstCommand) -> AstCommand:
def handle_from_import(self, stream: TokenStream, node: AstCommand) -> AstCommand:
identifiers = get_stream_identifiers(stream)
identifiers_storage = get_stream_identifiers_storage(stream)
pending_macros = get_stream_pending_macros(stream)

module = cast(AstResourceLocation, node.arguments[0])

Expand All @@ -1243,7 +1267,6 @@ def handle_from_import(self, stream: TokenStream, node: AstCommand) -> AstComman
compiled_module = None

arguments: List[AstNode] = [module]
macros: List[AstMacro] = []

subcommand = cast(AstCommand, node.arguments[1])
while True:
Expand All @@ -1252,7 +1275,7 @@ def handle_from_import(self, stream: TokenStream, node: AstCommand) -> AstComman
for name, macro in compiled_module.macros[item.name]:
imported_macro = AstImportedMacro(name=name, declaration=macro)
arguments.append(set_location(imported_macro, item))
macros.append(macro)
pending_macros.append(macro)
elif item.identifier:
arguments.append(item)
identifiers.add(item.name)
Expand All @@ -1265,9 +1288,6 @@ def handle_from_import(self, stream: TokenStream, node: AstCommand) -> AstComman
else:
break

if macros:
MacroHandler.inject_syntax(stream, *macros)

return set_location(AstFromImport(arguments=AstChildren(arguments)), node)


Expand Down Expand Up @@ -1339,10 +1359,6 @@ def __call__(self, stream: TokenStream) -> AstRoot:

node: AstRoot = self.parser(stream)

spec = get_stream_spec(stream)
identifiers = get_stream_identifiers(stream)
macro_scope = get_stream_macro_scope(stream)

for command in node.commands:
stack: List[AstCommand] = [command]

Expand All @@ -1358,12 +1374,17 @@ def __call__(self, stream: TokenStream) -> AstRoot:
):
should_replace = True

if pending_macros := get_stream_pending_macros(stream):
MacroHandler.inject_syntax(stream, *pending_macros)
pending_macros.clear()

deferred_stream = deferred_root.stream
deferred_stream.data["local_spec"] = False
deferred_stream.data["spec"] = spec
deferred_stream.data["identifiers"] |= identifiers
deferred_stream.data["spec"] = get_stream_spec(stream)
deferred_stream.data["identifiers"] |= get_stream_identifiers(stream)
deferred_stream.data["function"] = True
deferred_stream.data["macro_scope"] = macro_scope
deferred_stream.data["macro_scope"] = get_stream_macro_scope(stream)
deferred_stream.data["pending_macros"] = []
nested_root = delegate("nested_root", deferred_stream)

command = replace(
Expand Down

0 comments on commit ec17f74

Please sign in to comment.