PythonでLanguage Implementation Patternsのパーサと戯れる Packratパーサのキャッシュクリア
前回のコードだとparse
関数を複数回呼び出すと前回のキャッシュが残っていてパースがうまくいかない問題があった。parse
呼び出しごとにキャッシュをクリアするようにしたい。
キャッシュ
xparser.py
モジュールのトップレベルにキャッシュのリストとそのリストをループしてすべてのキャッシュをクリアする関数を定義:
_caches = [] def _clear_caches(): for cache in _caches: cache.clear()
_memo
デコレータで作成されるキャッシュを_caches
に追加するようにする:
def _memo(func): d = {} _caches.append(d) # ここを追加 @functools.wraps(func) def f(tokens): match d.get(tokens.i, None): case int(n): tokens.i = n case ValueError(_) as e: raise e case None: current_pos = tokens.i try: func(tokens) d[current_pos] = tokens.i except ValueError as e: d[current_pos] = e raise return f
あとはparse
関数が呼び出されるたびに_clear_caches
するようにする:
def parse(char_stream): _clear_caches() # ここを追加 tokens = Backtrackable(xl.lex(char_stream), 2) _list(tokens) _match(tokens, t.Eof)
使ってみる
>>> parse("[x=a]") >>> parse("[[[[[") Traceback (most recent call last): ... ValueError: Invalid token Lbrack() >>> parse("[abc=xyz, [d, [e]=[x], f, g]]")
前回見られた「二回目以降は第一回とトークン数が合えばパース成功、合わなければ失敗する」という挙動は修正されているようだ。
今回のコード
次回
Backtrackable
クラスがこれまで見たすべてのトークンを不必要に保持していて、パース終了時にはソースファイルのすべてのトークンがメモリに乗っているのを修正する。