【问题标题】:ES6 style classes in ParenscriptParenscript 中的 ES6 样式类
【发布时间】:2018-07-15 17:00:21
【问题描述】:

有没有合适的方法来编写输出 ES6 类定义的 Parenscript 类宏?

如果类定义如下所示:

class Person {
    sayHello() {
        alert('hello');
    }

    walk() {
        alert('I am walking!');
    }
}

class Student extends Person {
    sayGoodBye() {
        alert('goodBye');
    }

    sayHello() {
        alert('hi, I am a student');
    }
}

我想在 Parenscript 中写成这样:

(def-class -person ()
  (say-hello () (alert "hello"))
  (walk () (alert "I am walking!")))

(def-class -student (-person)
  (say-good-bye () (alert "goodBye"))
  (say-hello () (alert "hi, I am a student")))

我尝试了几种方法 - 附在下面的答案中 - 但它们都不是完全令人满意的。有没有更好的解决方案,不涉及重新设计 Parenscript?

【问题讨论】:

    标签: ecmascript-6 common-lisp es6-class parenscript


    【解决方案1】:

    解决方案 1:

    (defpsmacro def-class (name (&optional extends) &body body)
      (multiple-value-bind (constructor others)
          (gadgets:splitfilter (lambda (x) (string-equal (car x) 'constructor)) body)
        (let ((constructor (case (length constructor)
                             (0 nil)
                             (1 (car constructor))
                             (otherwise
                              (error "Class can't have more than one constructor"))))
              (const-lambda-list nil)
              (const-body nil))
          (when constructor
            (setf const-lambda-list (second constructor))
            (set const-body (cddr constructor)))
          `(progn
             (defun ,name ,const-lambda-list
               ,@const-body)
             ,@(mapcar
                (lambda (item)
                  `(setf (@ ,name prototype ,(car item))
                         (lambda ,(second item) ,@(cddr item))))
                others)
             ,@(when extends
                     `((setf (@ ,name prototype) (chain -object (create (@ ,name prototype))))
                       (setf (@ ,name prototype constructor) ,name)))))))
    

    问题:

    • 输出 ES5 javascript。
    • (尚)不支持静态方法。

    【讨论】:

    • 我在paren6 写了一个更好的版本。
    【解决方案2】:

    解决方案 2:

    (defpsmacro def-class-es6 (name (&optional extends) &body body)
      (let ((output nil))
        (push (format nil "class ~a~a {~&"
                      (symbol-to-js-string name)
                      (if extends
                          (format nil " extends ~a" (symbol-to-js-string extends))
                          ""))
              output)
        (dolist (itm body)
          (when (atom itm)
            (error "Non-list item found in class body."))
          (let ((staticp nil))
            (when (eq (car itm) :static)
              (setf itm (if (listp (cadr itm)) (cadr itm) (cdr itm)))
              (setf staticp t))
            (destructuring-bind (mname lambda-list . statements) itm
              (push
               (format
                nil "~a~a (~{~a~^ ~}) {~a}~&"
                (if staticp "static " "")
                (symbol-to-js-string mname)
                (mapcar #'symbol-to-js-string lambda-list)
                ;; Use parenscript to express a method body, then peel the
                ;; block contents out and put them in our own block.
                (let ((fbody (eval `(ps (lambda ,lambda-list ,@statements)))))
                  (subseq fbody
                          (1+ (position #\{ fbody))
                          (position #\} fbody :from-end t))))
               output))))
        (push "}" output)
        `(lisp-raw ,(apply #'concatenate 'string (nreverse output)))))
    

    这个宏输出 ES6 代码,但是:

    • 依赖于我的 Parenscript extension,但未在官方分发中。
    • 非常hackish,不会很好地缩进。

    【讨论】:

      猜你喜欢
      • 2018-01-27
      • 2015-03-24
      • 1970-01-01
      • 2017-09-17
      • 1970-01-01
      • 2022-10-23
      • 2020-09-14
      • 2016-07-30
      相关资源
      最近更新 更多