初始提交,未完全测试
This commit is contained in:
48
template/stat/ast/Define.py
Normal file
48
template/stat/ast/Define.py
Normal 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})"
|
||||
106
template/stat/ast/For.py
Normal file
106
template/stat/ast/For.py
Normal file
@@ -0,0 +1,106 @@
|
||||
#!/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:
|
||||
# Get the iterable from the expression
|
||||
iterable = eval(self._iter_expr, {}, scope._data.copy())
|
||||
|
||||
# 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})"
|
||||
40
template/stat/ast/Output.py
Normal file
40
template/stat/ast/Output.py
Normal 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})"
|
||||
79
template/stat/ast/Stat.py
Normal file
79
template/stat/ast/Stat.py
Normal 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)"
|
||||
81
template/stat/ast/Text.py
Normal file
81
template/stat/ast/Text.py
Normal 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]}...')"
|
||||
12
template/stat/ast/__init__.py
Normal file
12
template/stat/ast/__init__.py
Normal 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'
|
||||
]
|
||||
Reference in New Issue
Block a user