调整版本并做测试
This commit is contained in:
130
pyenjoy/template/stat/ast/For.py
Normal file
130
pyenjoy/template/stat/ast/For.py
Normal file
@@ -0,0 +1,130 @@
|
||||
#!/usr/bin/env python3.9
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
JFinal For - For Directive
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
from .Stat import Stat, StatList
|
||||
from ..Scope import Scope
|
||||
from ...Env import Env
|
||||
|
||||
class For(Stat):
|
||||
"""For loop directive"""
|
||||
|
||||
def __init__(self, var_name: str, iter_expr: str, body: Stat):
|
||||
"""
|
||||
Initialize for directive
|
||||
|
||||
Args:
|
||||
var_name: Loop variable name
|
||||
iter_expr: Expression to iterate over
|
||||
body: Loop body
|
||||
"""
|
||||
self._var_name = var_name
|
||||
self._iter_expr = iter_expr
|
||||
self._body = body
|
||||
|
||||
def exec(self, env: Env, scope: Scope, writer) -> None:
|
||||
"""
|
||||
Execute for loop
|
||||
|
||||
Args:
|
||||
env: Template environment
|
||||
scope: Execution scope
|
||||
writer: Output writer
|
||||
"""
|
||||
try:
|
||||
# Wrap dict values to allow attribute access
|
||||
def wrap_dict(d):
|
||||
"""Wrap a dict to allow attribute access"""
|
||||
if isinstance(d, dict):
|
||||
# Create a wrapper that allows both dot access and bracket access
|
||||
class DictWrapper:
|
||||
def __init__(self, data):
|
||||
self.__dict__ = data
|
||||
def __getitem__(self, key):
|
||||
return data[key]
|
||||
return DictWrapper(d)
|
||||
return d
|
||||
|
||||
# Create wrapped vars similar to SimpleExprList.eval()
|
||||
wrapped_vars = {}
|
||||
for key, value in scope._data.items():
|
||||
if isinstance(value, dict):
|
||||
wrapped_vars[key] = wrap_dict(value)
|
||||
elif isinstance(value, list):
|
||||
# Wrap dictionaries in lists
|
||||
wrapped_vars[key] = [wrap_dict(item) for item in value]
|
||||
else:
|
||||
wrapped_vars[key] = value
|
||||
|
||||
# Get the iterable from the expression
|
||||
iterable = eval(self._iter_expr, {}, wrapped_vars)
|
||||
|
||||
# Convert iterable to list for easier manipulation
|
||||
items = list(iterable)
|
||||
size = len(items)
|
||||
|
||||
# Create a ForLoopInfo class to hold loop information
|
||||
class ForLoopInfo:
|
||||
def __init__(self, size, index, outer=None):
|
||||
self._size = size
|
||||
self._index = index
|
||||
self._outer = outer
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
return self._size
|
||||
|
||||
@property
|
||||
def index(self):
|
||||
return self._index
|
||||
|
||||
@property
|
||||
def count(self):
|
||||
return self._index + 1
|
||||
|
||||
@property
|
||||
def first(self):
|
||||
return self._index == 0
|
||||
|
||||
@property
|
||||
def last(self):
|
||||
return self._index == self._size - 1
|
||||
|
||||
@property
|
||||
def odd(self):
|
||||
return self._index % 2 == 0
|
||||
|
||||
@property
|
||||
def even(self):
|
||||
return self._index % 2 == 1
|
||||
|
||||
@property
|
||||
def outer(self):
|
||||
return self._outer
|
||||
|
||||
# Get outer for info if exists
|
||||
outer_for = scope._data.get("for")
|
||||
|
||||
# Iterate over the items
|
||||
for index, item in enumerate(items):
|
||||
# Create for loop info
|
||||
for_loop = ForLoopInfo(size, index, outer_for)
|
||||
|
||||
# Create a new scope for this iteration
|
||||
loop_scope = Scope(scope._data.copy(), scope._shared_objects.copy())
|
||||
loop_scope.set_parent(scope)
|
||||
loop_scope._data[self._var_name] = item
|
||||
loop_scope._data["for"] = for_loop
|
||||
|
||||
# Execute the loop body
|
||||
if self._body:
|
||||
self._body.exec(env, loop_scope, writer)
|
||||
except Exception as e:
|
||||
# Handle errors gracefully
|
||||
writer.write(f"Error in for loop: {e}")
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"For(var={self._var_name}, expr={self._iter_expr})"
|
||||
Reference in New Issue
Block a user