Skip to content

Commit

Permalink
sistana: analyzer returns description only
Browse files Browse the repository at this point in the history
  • Loading branch information
GreyElaina committed Sep 21, 2024
1 parent c46e2dd commit 1f29371
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 50 deletions.
73 changes: 24 additions & 49 deletions src/arclet/alconna/sistana/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ class Analyzer(Generic[T]):

complete_on_determined: bool = True

def loopflow(self, snapshot: AnalyzeSnapshot[T], buffer: Buffer[T]) -> tuple[LoopflowDescription, AnalyzeSnapshot[T]]:
def loopflow(self, snapshot: AnalyzeSnapshot[T], buffer: Buffer[T]) -> LoopflowDescription:
while True:
traverse = snapshot.traverses[-1]
context = traverse.subcommand
mix = traverse.mix

if snapshot.determined and self.complete_on_determined and mix.satisfied:
return LoopflowDescription.completed, snapshot
return LoopflowDescription.completed

pointer_type, pointer_val = traverse.ref.data[-1]

Expand All @@ -67,37 +67,30 @@ def loopflow(self, snapshot: AnalyzeSnapshot[T], buffer: Buffer[T]) -> tuple[Loo
mix.pop_track(pointer_val)

snapshot.determine(traverse.ref)
return LoopflowDescription.completed, snapshot
return LoopflowDescription.completed

# 这里如果没有 satisfied,如果是 option 的 track,则需要 reset
if pointer_type == "option":
mix.reset(pointer_val)

return LoopflowDescription.unsatisfied, snapshot
return LoopflowDescription.unsatisfied

if pointer_type == "prefix":
if not isinstance(token.val, str):
return LoopflowDescription.header_expect_str, snapshot
return LoopflowDescription.header_expect_str

if context.prefixes is not None:
matched = context.prefixes.get_closest_prefix(buffer.runes[0]) # type: ignore
if matched == "":
return LoopflowDescription.prefix_mismatch, snapshot
prefix = context.prefixes.get_closest_prefix(buffer.runes[0]) # type: ignore
if prefix == "":
return LoopflowDescription.prefix_mismatch

buffer.runes[0:1] = (
buffer.runes[0][: len(matched)],
buffer.runes[0][len(matched) :],
)
buffer.next().apply()
# FIXME: 现在这里会吃掉很多东西……比如说把第一个 segment 吃的只剩 header.
# ahead 不能处理这种情况,详情见下。

# 这种方式不优雅,想个好点的。
token.apply()
buffer.pushleft(token.val[len(prefix) :])

traverse.ref = traverse.ref.parent.header() # 直接进 header.
elif pointer_type == "header":
if not isinstance(token.val, str):
return LoopflowDescription.header_expect_str, snapshot
return LoopflowDescription.header_expect_str

token.apply()

Expand All @@ -113,7 +106,7 @@ def loopflow(self, snapshot: AnalyzeSnapshot[T], buffer: Buffer[T]) -> tuple[Loo
if v:
buffer.runes.insert(0, v)
else:
return LoopflowDescription.header_mismatch, snapshot
return LoopflowDescription.header_mismatch

traverse.ref = traverse.ref.parent
else:
Expand All @@ -136,10 +129,7 @@ def loopflow(self, snapshot: AnalyzeSnapshot[T], buffer: Buffer[T]) -> tuple[Loo
)
continue
elif not subcommand.soft_keyword:
return (
LoopflowDescription.unsatisfied_switch_subcommand,
snapshot,
)
return LoopflowDescription.unsatisfied_switch_subcommand
# else: soft keycmd,直接进 mainline
elif token.val in context.options:
origin_option = context.options[token.val]
Expand All @@ -152,8 +142,8 @@ def loopflow(self, snapshot: AnalyzeSnapshot[T], buffer: Buffer[T]) -> tuple[Loo
traverse.ref = traverse.ref.option(token.val)

if not origin_option.allow_duplicate and origin_option.keyword in traverse.option_traverses:
return LoopflowDescription.option_duplicated, snapshot
return LoopflowDescription.option_duplicated

traverse.option_traverses.append(
OptionTraverse(
trigger=token.val,
Expand Down Expand Up @@ -181,10 +171,7 @@ def loopflow(self, snapshot: AnalyzeSnapshot[T], buffer: Buffer[T]) -> tuple[Loo
if not track.satisfied:
if not subcommand.soft_keyword:
mix.reset(option.keyword)
return (
LoopflowDescription.switch_unsatisfied_option,
snapshot,
)
return LoopflowDescription.switch_unsatisfied_option
else:
track.complete()
traverse.ref = traverse.ref.parent
Expand All @@ -207,22 +194,16 @@ def loopflow(self, snapshot: AnalyzeSnapshot[T], buffer: Buffer[T]) -> tuple[Loo
)
continue
elif not subcommand.soft_keyword: # and not phase.satisfied
return (
LoopflowDescription.unsatisfied_switch_subcommand,
snapshot,
)

return LoopflowDescription.unsatisfied_switch_subcommand

elif token.val in context.options:
target_option = context.options[token.val]
track = mix.tracks[target_option.keyword]

if not track.satisfied:
if not target_option.soft_keyword:
mix.reset(target_option.keyword)
return (
LoopflowDescription.option_switch_prohibited_direction,
snapshot,
)
return LoopflowDescription.option_switch_prohibited_direction
else:
track.complete()
traverse.ref = traverse.ref.parent
Expand All @@ -232,7 +213,7 @@ def loopflow(self, snapshot: AnalyzeSnapshot[T], buffer: Buffer[T]) -> tuple[Loo
mix.pop_track(target_option.keyword)

continue

if context.compacts is not None:
prefix = context.compacts.get_closest_prefix(token.val)
if prefix:
Expand Down Expand Up @@ -265,15 +246,14 @@ def loopflow(self, snapshot: AnalyzeSnapshot[T], buffer: Buffer[T]) -> tuple[Loo
buffer.pushleft(token.val[prefix_len:])
continue


if pointer_type == "subcommand":
track = mix.tracks[context.header]

try:
response = track.forward(buffer, context.separators)
except OutOfData:
# 称不上是 context switch,continuation 不改变 context。
return LoopflowDescription.out_of_data_subcommand, snapshot
return LoopflowDescription.out_of_data_subcommand
except Rejected:
raise
except ParsePanic:
Expand All @@ -283,25 +263,22 @@ def loopflow(self, snapshot: AnalyzeSnapshot[T], buffer: Buffer[T]) -> tuple[Loo
else:
if response is None:
# track 上没有 fragments 可供分配了,此时又没有再流转到其他 traverse
return LoopflowDescription.unexpected_segment, snapshot
return LoopflowDescription.unexpected_segment
elif pointer_type == "option":
# option fragments 的处理是原子性的,整段成功才会 apply changes,否则会被 reset。
origin_option = context.options[pointer_val]
track = mix.tracks[origin_option.keyword]

if traverse.option_traverses.count(origin_option.keyword) > 1:
rx_getter = traverse.option_traverses[-2].track._assign_getter(
track.fragments[0].name
)
print(traverse.option_traverses[-2])
rx_getter = traverse.option_traverses[-2].track._assign_getter(track.fragments[0].name)
else:
rx_getter = None

try:
response = track.forward(buffer, origin_option.separators, rx_getter)
except OutOfData:
mix.reset(origin_option.keyword)
return LoopflowDescription.out_of_data_option, snapshot
return LoopflowDescription.out_of_data_option
except Rejected:
raise
except ParsePanic:
Expand All @@ -318,5 +295,3 @@ def loopflow(self, snapshot: AnalyzeSnapshot[T], buffer: Buffer[T]) -> tuple[Loo

if origin_option.allow_duplicate:
mix.pop_track(origin_option.keyword)

# TODO: option.receiver 的处理
1 change: 0 additions & 1 deletion src/arclet/alconna/sistana/model/pattern.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from elaina_triehard import TrieHard

from .pointer import Pointer
from .receiver import Rx
from .track import Preset

if TYPE_CHECKING:
Expand Down

0 comments on commit 1f29371

Please sign in to comment.