调整版本并做测试

This commit is contained in:
2026-02-27 17:10:54 +08:00
parent fa673138f6
commit 31be9d0e97
77 changed files with 679 additions and 25 deletions

View File

@@ -0,0 +1,48 @@
#!/usr/bin/env python3.9
# -*- coding: utf-8 -*-
"""
JFinal Define - Template Function Definition
"""
from .Stat import Stat
from ..Scope import Scope
from ...Env import Env
class Define(Stat):
"""Template function definition"""
def __init__(self, function_name: str):
"""
Initialize define statement
Args:
function_name: Function name
"""
self._function_name = function_name
def exec(self, env: Env, scope: Scope, writer) -> None:
"""
Execute define statement
Args:
env: Template environment
scope: Execution scope
writer: Output writer
"""
# Register the function with the environment
env.add_function(self._function_name, self)
def get_function_name(self) -> str:
"""Get function name"""
return self._function_name
def set_env_for_dev_mode(self, env: Env):
"""Set environment for dev mode"""
pass
def is_source_modified_for_dev_mode(self) -> bool:
"""Check if source is modified (for dev mode)"""
return False
def __repr__(self) -> str:
return f"Define({self._function_name})"

View 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})"

View File

@@ -0,0 +1,40 @@
#!/usr/bin/env python3.9
# -*- coding: utf-8 -*-
"""
JFinal Output - Output Directive
"""
from .Stat import Stat
from ..Scope import Scope
from ...Env import Env
from ...expr.ast import ExprList
class Output(Stat):
"""Output directive for template expressions"""
def __init__(self, expr_list: ExprList):
"""
Initialize output directive
Args:
expr_list: Expression list to evaluate
"""
self._expr_list = expr_list
def exec(self, env: Env, scope: Scope, writer) -> None:
"""
Execute output directive
Args:
env: Template environment
scope: Execution scope
writer: Output writer
"""
if self._expr_list:
result = self._expr_list.eval(scope)
if result is not None:
if hasattr(writer, 'write'):
writer.write(str(result))
def __repr__(self) -> str:
return f"Output({self._expr_list})"

View File

@@ -0,0 +1,79 @@
#!/usr/bin/env python3.9
# -*- coding: utf-8 -*-
"""
JFinal Stat - Abstract Syntax Tree Base Class
"""
from typing import Any
from ..Scope import Scope
from ...Env import Env
class Stat:
"""Base class for statement AST nodes"""
def exec(self, env: Env, scope: Scope, writer) -> Any:
"""
Execute the statement
Args:
env: Template environment
scope: Execution scope
writer: Output writer
Returns:
Execution result
"""
raise NotImplementedError("Stat.exec() must be implemented by subclasses")
def get_stat_list(self) -> 'StatList':
"""Get as StatList if applicable"""
return None
def __repr__(self) -> str:
return f"Stat({self.__class__.__name__})"
class StatList(Stat):
"""Statement list containing multiple statements"""
def __init__(self):
"""Initialize statement list"""
self._stats: list = []
def add_stat(self, stat: Stat):
"""
Add statement to list
Args:
stat: Statement to add
"""
if stat:
self._stats.append(stat)
def exec(self, env: Env, scope: Scope, writer) -> Any:
"""
Execute all statements in list
Args:
env: Template environment
scope: Execution scope
writer: Output writer
Returns:
Last statement result or None
"""
result = None
for stat in self._stats:
result = stat.exec(env, scope, writer)
return result
def get_stats(self) -> list:
"""Get all statements"""
return self._stats.copy()
def __len__(self) -> int:
"""Get number of statements"""
return len(self._stats)
def __repr__(self) -> str:
return f"StatList({len(self._stats)} statements)"

View File

@@ -0,0 +1,81 @@
#!/usr/bin/env python3.9
# -*- coding: utf-8 -*-
"""
JFinal Text - Text Statement
"""
from .Stat import Stat
from ..Scope import Scope
from ...Env import Env
class Text(Stat):
"""Text statement for template content"""
def __init__(self, content: str):
"""
Initialize text statement
Args:
content: Text content
"""
self._content = content
def exec(self, env: Env, scope: Scope, writer) -> None:
"""
Execute text statement
Args:
env: Template environment
scope: Execution scope
writer: Output writer
"""
if hasattr(writer, 'write'):
# Parse and evaluate template expressions
parsed_content = self._parse_expressions(env, scope)
writer.write(parsed_content)
def _parse_expressions(self, env: Env, scope: Scope) -> str:
"""
Parse and evaluate template expressions in content
Args:
env: Template environment
scope: Execution scope
Returns:
Parsed and evaluated content
"""
import re
def replace_expression(match):
"""Replace expression with evaluated value"""
expr_str = match.group(1).strip()
# Try to evaluate expression
try:
# First try variable access
if expr_str.isidentifier():
value = scope.get(expr_str)
return str(value) if value is not None else ''
# Try arithmetic expression
try:
# Simple arithmetic evaluation
# This is a simplified implementation
result = eval(expr_str, {})
return str(result)
except:
pass
# Fallback to original expression
return match.group(0)
except Exception as e:
return f"{match.group(0)} [Error: {e}]"
# Replace all #(...) expressions
pattern = r'#\((.*?)\)'
return re.sub(pattern, replace_expression, self._content)
def __repr__(self) -> str:
return f"Text('{self._content[:50]}...')"

View File

@@ -0,0 +1,12 @@
# Export statement AST classes
from .Stat import Stat, StatList
from .Text import Text
from .Define import Define
from .Output import Output
__all__ = [
'Stat', 'StatList',
'Text',
'Define',
'Output'
]