- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
出于所有意图和目的,我有一堆具有这种 AST 结构的函数和函数调用。它是一个函数数组。
const ast = [
{
type: 'function',
name: 'doX',
inputs: [
{
name: 'x',
type: 'String'
}
],
calls: [
{
type: 'call',
name: 'do123',
args: [
{
type: 'literal',
value: 123
},
{
type: 'reference',
value: 'x'
}
]
},
{
type: 'call',
name: 'test',
args: [
{
type: 'borrow',
value: 'x'
}
],
block: [
{
type: 'call',
name: 'set',
args: [
{
type: 'reference',
value: 'a'
},
{
type: 'move',
value: {
type: 'call',
name: 'multiply',
args: [
{
type: 'borrow',
value: 'x'
},
{
type: 'literal',
value: 2
}
]
}
}
]
},
{
type: 'call',
name: 'doFoo',
args: [
{
name: 'a',
value: {
type: 'literal',
value: 'foo'
}
},
{
name: 'b',
value: {
type: 'reference',
value: 'x'
}
}
]
}
]
}
]
}
]
这将是这样的结果:
function doX(x) {
do123(123, x)
test(x) {
set(a, multiply(x, 2))
doFoo('foo', a)
}
}
现在忘记我也在尝试处理词法范围(即嵌套函数)这一事实,因为这可能只会使这个问题变得不必要地复杂。
另请注意,一切皆函数,因此您需要set(foo, 'bar')
来实例化一个变量。尽管它以命令式方式执行,但它不是函数式语言 AST。这只是为了简化问题,所以不会有各种复杂的类型。这个例子只有函数和调用。
另请注意,我们在其中有borrow
(“引用”的几种类型之一)。您可以拥有借用(共享所有权)或移动(转让所有权),借用可以标记为可变或不可变(默认值不)。目标是重现 Rust 所做的事情,让这个迷你/演示“编译器”完全按照 Rust 对借用检查器所做的事情进行操作。
此外,我们在该函数中创建了一个新的局部作用域,并定义了变量 a
。
目标是弄清楚这一点:
The lifetime of each variable (when it can be
free
d from memory, like in Rust). And to insert afree(name)
call into the AST.
使用 Rust 借用检查器,它会检查变量的所有者和生命周期,以便判断它是否被正确使用以及何时超出范围。
所以首先我们必须收集变量声明(然后提升它们,这样我们就知道有多少局部变量,这样我们就可以创建合适大小的激活记录)。为此,我认为我们只需要向下遍历 AST 一次。
其次,我开始迷失了究竟要做什么才能完成 (1)。首先,创建一个 map
。然后从头开始遍历 AST。对于每个变量,检查它是否在 map 中(是否已被标记/遍历/遇到)。如果它不在 map 中,请将其添加到 map 中,还不知道为什么我们需要这样做。为每个范围创建一个新 map 。在每个范围的末尾,释放变量。这就是我所处的位置。
process(ast)
function process(ast) {
ast.forEach(fxn => {
let stack = []
let locals = { count: 0, vars: {} }
fxn.inputs.forEach(input => {
locals.vars[input.name] = locals.count++
})
fxn.calls.forEach(call => {
handleCall(call, locals)
})
function handleCall(call, locals) {
if (call.name == 'set') {
let name = call.args[0].value
locals.vars[name] = locals.count++
}
if (call.block) {
call.block.forEach(nestedCall => {
handleCall(nestedCall, locals)
})
}
}
})
}
现在的问题是,如何添加借用检查,以便知道在哪里插入 free(name)
?
process(ast)
function process(ast) {
ast.forEach(fxn => {
let stack = []
let locals = { count: 0, vars: {} }
fxn.inputs.forEach(input => {
locals.vars[input.name] = {
id: locals.count++,
status: '?'
}
})
fxn.calls.forEach(call => {
handleCall(call, locals)
})
function handleCall(call, locals) {
if (call.name == 'set') {
let name = call.args[0].value
let local = locals.vars[name] = {
id: locals.count++
}
let value = call.args[1]
if (value.type == 'move') {
local.status = 'owner'
} else if (value.type == 'borrow') {
local.status = 'borrow'
} else {
// literal
}
if (value.value.type == 'call') {
handleCall(value.value, locals)
}
} else {
}
if (call.block) {
let newLocals = {}
call.block.forEach(nestedCall => {
handleCall(nestedCall, newLocals)
})
}
}
})
}
我开始迷失在杂草中,只见树木不见森林。到目前为止,我已经阅读了很多关于 Rust 中的借用检查器的信息,但不知道它是如何实现的。我查看了 Polonius 的源代码,阅读了大部分 Oxide paper ,并阅读有关生命周期、借用、可变性和所有权的文档,以及一些编译器组 session 记录和 blog posts .但似乎没有人以简单的方式解释在实践中进行借用检查的算法。
寻求有关此特定示例的一些帮助,以帮助我开始研究 JavaScript 中的借用检查器的算法。想知道是否可以概述算法应该做什么,以便弄清楚变量是否被正确借用以及何时可以释放它们,使用这个或稍微复杂一点的想出的例子。
不过,在我真正编写算法之前,我需要更好地了解算法应该做什么,它应该如何工作。这就是这个问题的内容。如果您知道如何编写它的演示,那就太好了!但只是对步骤进行更深入的解释(而不是掩盖关键步骤)也会有所帮助。
最佳答案
我可以看到一些问题:
"reference"
和 "borrow"
,这令人困惑,因为它们在 Rust 中的含义相同。doX
参数的类型,这意味着您无法正确处理该变量,因为它可能是一个移动,这可能会导致调用函数的范围问题.b
是如何成为对 x
的引用的?Rust/理解所有权:
https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html
这是上面链接的概要:
对于所有这些,当我说“变量”时,我的意思是“使用堆的变量”。另外,请随意将“引用”替换/解释为“借用”。
变量在其作用域结束时被丢弃,如果它仍然有效。丢弃意味着释放内存。范围是从引入变量到最后一次使用它的时间。如果对该变量的任何引用仍在范围内,则为错误。
默认情况下,变量是移动而不是复制。
复制变量时,会创建一个新的唯一变量并复制数据。这会创建一个全新的自变量。
当一个变量移动到另一个变量时,初始变量被标记为无效并且不能再使用。 (这种内存管理方式的一个很大的折衷。)新变量指向与旧变量相同的堆数据。如果在标记为无效后使用初始变量,则为错误。
可以通过以下三种方式之一将变量分配给另一个变量来移动:
如果您将一个变量传递给另一个函数并希望在该调用之后继续使用它,那么该函数必须通过返回它来“归还它”(与预期的另一个主要偏差)。这只是 (2) 后跟 (3),例如x = f(x).
可以为变量创建两种类型的引用:不可变(默认)和可变。 引用只是指向变量而不是数据。
您可以对一个变量有无限数量的不可变引用。您只能有一个可变引用,并且前提是范围内没有其他类型的引用(包括不可变引用)。
当引用超出范围时,它们不会调用drop。当引用指向的变量已被删除时,引用继续存在是错误的。
如果我要实现这个,我会按顺序执行以下操作:
关于javascript - 难以在 JavaScript 中实现简化的借用检查器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66407890/
hello1 hello2 hello3 hello4 hello5 hello6
有没有更简短的写法: (apply f (cons a (cons b (cons c d)))) ? 谢谢! (我正在编写一些调用其他函数的辅助函数,这种“模式”似乎经常出现
.NET团队北京时间2024年5月22日已正式发布.NET Aspire ,在博客文章里做了详细的介绍:.NET Aspire 正式发布:简化 .NET 云原生开发 - .NET 博客 (micros
在this dbfiddle demo我有一个 DELETE FROM...WHERE 最后像这样: ...... DELETE FROM data_table WHERE
我有几个 if 语句,如下面的一个。我假设这是一种非常糟糕/长期的编码方式,但不确定我应该做些什么不同的事情。有人有什么建议吗? 谢谢 For a = 1 To Leagues If a =
有什么类似的战术simpl为 Program Fixpoint ? 特别是,如何证明以下无关紧要的陈述? Program Fixpoint bla (n:nat) {measure n} := mat
我使用此代码来跟踪表单上是否有任何更改: $(document).on('input', '.track', function() { var form = $(this); }); 由于这不
我有以下函数,我想用 for 循环来简化它,但不知道该怎么做。任何帮助都感激不尽。基本上,如果字段值为 0 或 null,则我的总值(字段)应为 0,否则,如果字段值从 1 到 1000,则总值变为
我正在尝试对时间字符串执行非常简单的解析 data Time = Time Int Int Int String -- example input: 07:00:00AM timeParser ::
为了使我的代码更具可读性和更简单,我对这段代码绞尽脑汁: var refresh = setInterval(datumTijd, 1000); function datumTijd() { do
这个问题已经有答案了: Check if a variable is in an ad-hoc list of values (8 个回答) 已关闭 9 年前。 只是一个基本的if声明,试图使其更简单
我有一个这样的 if 语句 int val = 1; if (val == 0 || val == 1 || val == 2 || ...); 有没有更简单的方法?例如: int val = 1;
我有一个程序,其中有一些 if 语句,与我将要向您展示的程序类似。我想知道你们是否可以帮助我以任何方式简化这个方程。我之所以问这个问题,是因为在我的 Notepad++ 中,它持续了 443 列,如果
是否可以简化这个 if 语句? 如果是,答案是什么? if (type) { if(NdotL >= 0.0) { color
我有一个包含亚马逊大河的 shapefile。仅 shapefile 就有 37.9 MB,连同属性表高达 42.1 MB。我正在生成所有巴西亚马逊的 PNG 图像,每个 1260x940 像素,sh
System.out.printf("%7s", "a"); System.out.printf("%7s", "b"); System.out.printf("%7s", "c"); S
假设我们有客户端-服务器应用程序,由一个 makefile 编译。服务器使用 libtask 为并行客户端提供服务。客户端使用 ncurses 来处理某些图形。目录树如下所示: ./ --bin/ -
我在 Mono 密码转换的重新实现中找到了这段代码。 我没有修改或简化任何东西 - 这就是它的实际运行方式(有评论如//Dispose unmanaged objects,但实际上什么也没做)。 现在
我需要一些帮助来简化这个包含数百行的庞大代码,但我真的不知道该怎么做。代码看起来真的很乱,我需要的是返回具有预定义文本颜色的模型。有什么简单的方法吗? 我必须多解释一点:- 有一个包含许多型号的手机列
这里有一些代码可以正常工作,但我认为可以简化/缩短。它基本上是点击一个列表项,获取它的 ID,然后根据 ID 显示/隐藏/删除元素。 关于如何使用函数或循环来简化它的建议? $("#btn_remov
我是一名优秀的程序员,十分优秀!