You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

用Python+Sly开发脚本解释器:如何为赋值左值建立引用变量?

解决赋值左值统一处理的方案

针对你用Python+Sly开发解释器时遇到的赋值左值冗余问题,核心思路是把所有左值解析为「可变容器+访问键/索引」的组合,通过这一组信息直接完成赋值,彻底避免重复遍历左值的流程。

具体实现思路

不管是普通变量还是嵌套对象/数组字段,最终都可以拆解为「存储值的可变容器」和「访问该值的键/索引」。比如:

  • bob → 容器是当前作用域的变量字典,键是"bob"
  • this.speed → 容器是this对象的字段字典,键是"speed"
  • eachthing.child[prevRef+2].name → 容器是eachthing.child[prevRef+2]对应的对象字段字典,键是"name"

基于这个逻辑,你可以在Sly中写递归的左值解析规则,一次性完成左值的遍历、验证,并返回最终的容器和键/索引:

# 自定义对象和数组类(用可变结构存字段/元素)
class ScriptObject:
    def __init__(self):
        self.fields = {}  # 可变字典,存对象字段

class ScriptArray:
    def __init__(self, elements):
        self.elements = list(elements)  # 可变列表,存数组元素

# Sly的左值解析规则
@_('ID')
def lvalue(self, p):
    # 普通变量:容器是当前作用域的变量字典
    return (self.current_scope.vars, p.ID)

@_('lvalue "." ID')
def lvalue(self, p):
    # 对象字段访问:递归解析前面的左值,拿到父容器和键
    parent_container, parent_key = p.lvalue
    parent_obj = parent_container[parent_key]
    # 验证父对象类型合法
    if not isinstance(parent_obj, ScriptObject):
        raise SyntaxError(f"{parent_key} is not an object")
    # 返回当前字段的容器(对象的字段字典)和键
    return (parent_obj.fields, p.ID)

@_('lvalue "[" expr "]"')
def lvalue(self, p):
    # 数组索引访问:递归解析前面的左值,拿到父容器和键
    parent_container, parent_key = p.lvalue
    parent_arr = parent_container[parent_key]
    # 验证父对象是数组
    if not isinstance(parent_arr, ScriptArray):
        raise SyntaxError(f"{parent_key} is not an array")
    # 计算索引值并验证合法性
    index = self.evaluate(p.expr)
    if not isinstance(index, int) or index < 0 or index >= len(parent_arr.elements):
        raise IndexError(f"Invalid index {index}")
    # 返回数组元素的容器(数组的元素列表)和索引
    return (parent_arr.elements, index)

然后处理赋值语句时,流程就完全统一了:

@_('lvalue "=" expr')
def assignment(self, p):
    # 1. 从左值解析结果拿到容器和键/索引(已完成所有合法性验证)
    target_container, target_key = p.lvalue
    # 2. 计算右值
    right_value = self.evaluate(p.expr)
    # 3. 类型校验(根据你的语言规则实现,比如变量的预期类型)
    expected_type = self.get_expected_type(target_container, target_key)
    if expected_type and not isinstance(right_value, expected_type):
        raise TypeError(f"Expected {expected_type.__name__}, got {type(right_value).__name__}")
    # 4. 直接赋值,无需重复遍历左值
    target_container[target_key] = right_value

为什么这个方案可行?

Python的可变对象(字典、列表、自定义类的可变属性)本身就支持这种"间接修改"——你拿到的容器是原对象的引用,修改容器里的键/索引值,就是直接修改原变量/对象字段的值,完全不需要额外的指针或索引存储机制。

这种方式把左值的遍历、验证和赋值彻底解耦,既消除了流程冗余,又符合解释器的执行逻辑。

内容的提问来源于stack exchange,提问作者Sean Duggan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 02:01:49