问题标签 [reader-macro]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
1 回答
261 浏览

common-lisp - set-macro-character 和 set-dispatch-macro-character 有什么区别?

从这些函数的签名来看,最明显的区别就是set-macro-character可以为单个字符设置阅读器宏功能,也set-dispatch-macro-character可以为两个字符的任意组合设置。这是唯一的区别吗?我什么时候需要使用一个而不是另一个?

0 投票
1 回答
512 浏览

macros - Common Lisp 中阅读器宏的限制是什么

我在 JavaScript 中有自己的 Lisp 解释器,我已经工作了一段时间,现在我想实现像 Common Lisp 中的阅读器宏。

我已经创建了 Streams(除了特殊符号之外几乎可以工作,@ , ` '),但是当它加载包含脚本的页面(具有 400 行代码的lisp 文件)时,它会冻结浏览器几秒钟。这是因为我的 Streams 是基于 substring 函数的。如果我首先拆分令牌,然后使用迭代令牌的 TokenStream,它工作正常。

所以我的问题是,字符串流真的是 Common Lisp 中的东西吗?您能否在 CL 中添加创建全新语法(如 Python)的阅读器宏,这简化了我是否可以实现"""宏(不确定是否可以将 3 个字符作为阅读器宏)或其他将在 lisp 中实现模板文字的字符,例如:

或者

或者

会产生字符串

在 Common Lisp 中是否可能发生这样的事情,实现#\{#\:作为阅读器宏有多难?

我能想到的在 Lisp 中使用模板文字的唯一方法是这样的:

其中 tag 是返回带有 ${} 作为自由变量的字符串的宏。阅读器宏也可以返回被评估的 lisp 代码吗?

还有一个问题,你可以像这样实现阅读器宏:

其中 : 是阅读器宏,如果它在符号之前,它将符号转换为

如果它在里面,它会抛出错误。我问这个是因为使用基于令牌的宏:foo:bar并且foo:bar将是符号并且不会被我的阅读器宏处理。

还有一个问题可以将阅读器宏放在一行中,第二行使用它吗?这肯定只有字符串流才有可能,而我测试过的解释器用 JavaScript 编写的解释器是不可能的。

0 投票
1 回答
81 浏览

common-lisp - 如何禁用阅读器宏?

我使用本地时间的阅读器宏,直到我意识到我不需要它(想读回日期?只需使用格式或本地时间:格式日期字符串,它不会输出@...)。

但是,它与使用 Parenscript 代码冲突ps:@

冒号后的非法终止字符:#@

我可以在不重新启动图像的情况下禁用阅读器宏吗?

它的作用是

我没有在 Parenscript 方面看到阅读器宏。

0 投票
1 回答
116 浏览

macros - 如何在 Racket 中直接使用阅读器宏?

我正在尝试定义一个读取字符串长度的读取器宏。该字符串将包含在垂直条(管道)中。例如:

  • |yes|->3
  • ||->0
  • |The quick brown fox|->19
  • |\||-> 1— 管道字符可以通过在它前面加一个反斜杠来转义。
  • (let ((x |world|)) (+ |hello| x))->10

我设法写了这个:

10正如预期的那样,这将返回。

现在的问题是:我想直接在我的 Racket 代码中使用 reader 宏,而不必将字符串输入(eval (read (open-input-string ...))). 例如,我想像这样使用阅读器宏:

但是,当我运行上面的程序时出现错误消息:

我做错了什么?如何在我的代码中使用阅读器宏?

0 投票
1 回答
155 浏览

macros - Common Lisp Read Macro for "lazy infix or" 来解构关键字

我有一个 Common Lisp 阅读器宏来解析“或”关系的惰性/延迟声明,使用由管道字符(“|”)分隔的中缀语法以及标准列表括号和关键字文字。考虑 (:a :b|:c) 形式——它表示一个 2 部分元组,其中第一个元素肯定是 :a,第二个元素是 :b 或 :c。例如,可以推断出整个元组的有效形式是 (:a :b) 或 (:a :c)。

我已经有函数封装的逻辑来解构这些元组列表形式在读取宏之后。但是在阅读时,我需要解析像 :a|:b|:c 这样的表单,并用移除的管道对其进行标记,例如 (:lazy-or :a :b :c)。中缀语法的使用纯粹是为了面向读者的形式;中缀形式是短暂的,并在读取阶段立即被丢弃,以支持使用 :lazy-or 标记的等效合法 lisp 形式。

所以我做了一个 read 宏,它几乎可以按我的意愿工作,但目前需要在第一个 or-form 关键字元素之前使用一个额外的管道作为一种阅读器符号(我希望这不是必需的根本),并且它目前无法使用嵌套括号或拼接符号来推断类似的形式作为等效(就像在算术中一样,2+(3*4)是相同的操作顺序,等效形式, as 2+3*4)。

宏(源自“斜线阅读器”:http ://www.lispworks.com/documentation/HyperSpec/Body/f_rd_rd.htm ):

预期目标是在读取时应用/替换此重写规则: (macroexpand '(:a (:b | :c))) -> (:a (:lazy-or :b :c)) 或者,括号中未包含的变体形式相同(一种默认的操作顺序;空格不会产生影响): (macroexpand '(:a :b|:c)) -> (:a (: lazy-or :b :c)) (macroexpand '(:a :b | :c)) -> (:a (:lazy-or :b :c)) 嵌套表单应该直观地递归渲染: (macroexpand ' (:a (:b | (:c | :d)))) -> (:a (:lazy-or :b (:lazy-or :c :d)))

请注意,在基本形式的预期重写规则中 -- (macroexpand '(:a (:b | :c))) -> (:a (:lazy-or :b :c)) -- :a 不会以 or 形式加入,因为它没有中缀管道运算符来加入它;它以一种元组的形式与 or-form 的结果一起存在。如前所述,在进一步评估惰性形式时,可以想象,元组可能会产生 (:a :b) 或 (:a :c) - 以上暗示两者都是稍后解构的有效形式。

我非常接近。

问题是我不能完全理解,只有以下(使用上面的宏): (macroexpand '(:a |:b|:c )) -> (:A (:LAZY-OR :B :C) ) (macroexpand '(:a :b |:d|:e|:f|:g)) -> (:A :B '(:LAZY-OR :D :E :F :G)) 它实际上做的最多我打算这样做,它是一个功能性的基本解决方案:稍微修改执行规则以允许在读取时在中缀或表单的开头有一个额外的管道,而无需将表单连接到该管道的左侧,因此它可以使 :b 到 :c (第一种形式)或 :d 到 :g (第二种形式)成为 :lazy-or 形式列出的有效案例,并使该内部列表本身成为外部列表的成员/元组与非变量值 :a 和 :b 并排。它接近我想要的: (macroexpand '(:a :b :d|:e|:f|:g)) -> 应该,不 -> (:A :B '(:LAZY-OR :D :E :F :

有 3 个错误,按重要性排序:

  1. 需要额外的“前缀”管道

    额外的开口管道,在每个被读取的或形式开始时,我不想这样做。我想切割该管道以保持清洁和我自己的可读性偏好,并且仅在该读取宏的完全中缀位置使用该管道。

  2. 递归解析时向嵌套表单添加了额外的括号

    它为嵌套表单添加了额外的括号,尽管它可以很好地递归处理嵌套表单。

  3. 空白不被任意接受

    它不接受管道之间的空格。我尝试使用 read-preserving-whitespace 而不是 read,在这里无济于事。它应该接受管道和关键字形式之间的空格,就好像它们不存在一样,因为形式:a|:b:a | :b是等价的。

read 宏主要封装了工作逻辑,擅长递归和嵌套形式: (macroexpand '(:a |(|:b|:c)|(|:e|:f))) -> yield -> (:A (:LAZY-OR ((:LAZY-OR :B :C)) ((:LAZY-OR :E :F))))
;(几乎完美,完全按照预期递归扩展,唯一的问题除了需要开头的管道之外的形式是在最终的 :lazy-or 形式周围生成的双括号)。这样就可以从这种形式产生相同的结果(当前是“不平衡”读取括号错误): (macroexpand '(:a (:b | :c) | (:e | :f))) -> 应该,确实不屈服 -> (:A (:LAZY-OR (:LAZY-OR :B :C) (:LAZY-OR :E :F)))

除了 read 宏添加的额外括号,以及它无法在中缀形式中允许间距之外,真正关键的错误是无法在不包括第一个非中缀管道的情况下将 or-form 编写为中缀管道形式(附带前缀)。我真的碰到了一堵砖墙,试图匹配流,而不需要使用第一个管道字符作为读取解析器的一种标志。也许对“peek”函数之一的额外调用或两次调用会给我一个更专业的匹配形式,但我无法弄清楚如何解析它。

我考虑围绕现有的综合解决方案构建它,例如 NKF(“definfix”宏,https: //www.cliki.net/infix )和 CMU 中缀(https://github.com/rigetti/cmu-infix/blob /master/src/cmu-infix.lisp),但由于它们是更通用和更大的代码库,我认为我不需要为更多类型的表单/运算符重用中缀逻辑,仅此一个。从我在一个相当小的宏上的接近程度来看,我肯定更喜欢用一个小而简洁的解决方案来解决它,只要它仍然是递归的并且不容易出错。

任何关于为此目的更有效地使用读取宏的观点都将不胜感激。

0 投票
1 回答
67 浏览

common-lisp - Readtable 与 cl-annot (cl-syntax, jonathan) 和 pythonic-string-reader 冲突

我喜欢pythonic-string-reader来启用 python-esque 三引号:

用它:

它也适用于

但是后来我想加载 Jonathan 库,但我遇到了冲突:

这是不对的,因为我没有要求使用另一个 readtable。Jonathan 只在内部使用 cl-annot。

它是谁的错误(cl-syntax?)以及如何解决它?


它首先加载 Jonathan,然后启用 pythonic 字符串语法。但是,这不是一个可接受的解决方法(我想定义一个启用语法的用户包,用户可以在其中加载任何其他库)。


查看它想要合并 readtables 的 cl-syntax 行错误(merge-readtables-into *readtable* syntax) ),同时它似乎正确使用copy-readtable

有任何想法吗?谢谢。

0 投票
1 回答
55 浏览

common-lisp - 在读取器宏中使用时读取的递归-p 参数

我已经编写了 Scheme 的 s-expression 注释 ( SRFI 62 ) 的 Common Lisp 实现:

根据我对The RECURSIVE-P argument 的阅读,我的实现似乎不正确。我必须(read stream t nil t)改用(recursive-p即将参数设置为t)。我的理解正确吗?

我一直在使用上面明显不正确的实现,它似乎运行正常。如果我继续使用(read stream)而不是会发生什么(read stream t nil t)