运行试图输出Javascript代码的通用lisp宏时键入错误。为什么?

时间:2018-11-05 18:04:43

标签: common-lisp

我刚刚开始学习普通口唇症,并且正在尝试以一种使我的日常工作更轻松的方式进行锻炼。特别是,我试图创建一组函数和宏,它们使用最少的语法并输出一些我经常使用的JavaScript。

这是我编写的代码:

;;;; This program is aimed at creating a very high level language that writes
;;;; complex and formally correct Javascript with minimal code.

(defvar *namespace* nil)

(defmacro conc (var &body body)
  `(setf ,var (concatenate 'string output ,@body)))

(defun public-var (name value)
  (let ((output ""))
    (conc output *namespace* "." name " = " value ";")
    output))

(defmacro namespace (ns &rest contents)
  `(let ((*namespace* (concatenate 'string "window." ,ns)) (output ""))
     (conc output "(function(ns){")
     (let ((*namespace* "ns"))
       ,(loop for e in contents collect `(conc output (apply ,(first e) (list ,@(rest e))))))
     (conc output "}(" *namespace* " = " *namespace* " || {}));")
     output))

想法是能够编写这样的代码:

(namespace "namespace"
  (#'public-var "hello" "world")
  (#'public-var "something" "else"))

并获得以下输出:

(function(ns){
  ns.hello = world;
  ns.something = else;
}(window.namespace = window.namespace || {}));

我知道我仍然需要处理输出的缩进和换行,但这还不是重点(这些应该是抽象出更复杂逻辑的第一个构建块)。问题是我遇到了这个错误,我不知道为什么(严重的是,我已经花了数小时研究和尝试不同的事情):

Illegal function object:
(CONC OUTPUT (APPLY #'PUBLIC-VAR (LIST "ciao" "mondo"))).
   [Condition of type TYPE-ERROR]

Restarts:
 0: [RETRY] Retry SLIME REPL evaluation request.
 1: [*ABORT] Return to SLIME's top level.
 2: [ABORT] Abort entirely from this (lisp) process.

Backtrace:
  0: (IDE.BASE::IDE-INVOKE-DEBUGGER-FROM-NON-CG-PROCESS "Error" #<TYPE-ERROR @ #x22de54b2> T NIL NIL)
  1: (ERROR TYPE-ERROR :DATUM (CONC OUTPUT (APPLY #'PUBLIC-VAR (LIST "ciao" "mondo"))) :EXPECTED-TYPE (OR SYMBOL FUNCTION) ...)
  2: ((CONC OUTPUT (APPLY #'PUBLIC-VAR (LIST "ciao" "mondo"))))
  3: (LET ((*NAMESPACE* "ns")) ((CONC OUTPUT (APPLY #'PUBLIC-VAR #))))
  4: (LET ((*NAMESPACE* (CONCATENATE 'STRING "window." "webtrekk_dl")) (OUTPUT "")) ..)
  5: (EVAL (NAMESPACE "webtrekk_dl" (#'PUBLIC-VAR "ciao" "mondo")))
 --more--

我也尝试了单个作品。例如:

 (let ((output ""))  (CONC OUTPUT (APPLY #'PUBLIC-VAR (LIST "ciao" "mondo"))))

工作并得到以下输出:

".ciao = mondo;"

知道我在做什么错吗?

1 个答案:

答案 0 :(得分:2)

,(loop for e in contents collect `(conc output …))

这将返回一个列表:

((conc output …)
 (conc output …)
 …)

通过将运算符(即列表的第一个元素)应用于参数来评估列表。

有效运算符只是符号或lambda形式。 conc表单作为运算符无效。您最有可能想要以下内容:

(progn
  (conc output …)
  …)

请注意,我不知道您的JavaScript输出真正应该做什么。它忽略ns参数,并设置两个新的全局变量。这似乎没有用。