1fff49891b5fc37e73b49ba0cab4c6a0cd57d0fd — Phil Hagelberg a month ago 526e5e6
Fix a bug where function arguments would get reordered for long arglists.
3 files changed, 23 insertions(+), 22 deletions(-)

M changelog.md
M src/fennel/specials.fnl
M test/core.fnl
M changelog.md => changelog.md +1 -0
@@ 7,6 7,7 @@ sandbox the compiler environment for safer code loading. Nothing is
blocked yet, but it emits warnings when macros use functionality that
is not considered safe; future versions will prevent this.

* Fix a bug where long arglists could get jumbled.
* Add plugin system.
* Sandbox compiler environment and emit a warning when it leaks.
* Fix a bug where repls would fail when provided with an overridden env.

M src/fennel/specials.fnl => src/fennel/specials.fnl +19 -22
@@ 179,38 179,35 @@ the number of expected arguments."
  (let [f-scope (doto (compiler.make-scope scope)
                  (tset :vararg false))
        f-chunk []
        fn-name (utils.sym? (. ast 2))
        multi (and fn-name (utils.multi-sym? (. fn-name 1)))
        (fn-name local-fn? index) (get-fn-name ast scope fn-name multi)]
        fn-sym (utils.sym? (. ast 2))
        multi (and fn-sym (utils.multi-sym? (. fn-sym 1)))
        (fn-name local-fn? index) (get-fn-name ast scope fn-sym multi)
        arg-list (compiler.assert (utils.table? (. ast index))
                                  "expected parameters table" ast)]
    (compiler.assert (or (not multi) (not multi.multi-sym-method-call))
                     (.. "unexpected multi symbol " (tostring fn-name))
                     (. ast index))
                     (.. "unexpected multi symbol " (tostring fn-name)) fn-sym)

    (fn get-arg-name [arg-count i name]
      (if (utils.varg? name)
          (do (compiler.assert (= i arg-count)
                               "expected vararg as last parameter" (. ast 2))
    (fn get-arg-name [arg]
      (if (utils.varg? arg)
          (do (compiler.assert (= arg (. arg-list (# arg-list)))
                               "expected vararg as last parameter" ast)
              (set f-scope.vararg true)
          (and (utils.sym? name)
               (not= (utils.deref name) "nil")
               (not (utils.multi-sym? (utils.deref name))))
          (compiler.declare-local name [] f-scope ast)
          (utils.table? name)
          (and (utils.sym? arg)
               (not= (utils.deref arg) "nil")
               (not (utils.multi-sym? (utils.deref arg))))
          (compiler.declare-local arg [] f-scope ast)
          (utils.table? arg)
          (let [raw (utils.sym (compiler.gensym scope))
                declared (compiler.declare-local raw [] f-scope ast)]
            (compiler.destructure name raw ast f-scope f-chunk {:declaration true
                                                                :nomulti true})
            (compiler.destructure arg raw ast f-scope f-chunk {:declaration true
                                                               :nomulti true})
          (compiler.assert false
                           (: "expected symbol for function parameter: %s"
                              :format (tostring name)) (. ast 2))))
                              :format (tostring arg)) (. ast 2))))

    (let [arg-list (compiler.assert (utils.table? (. ast index))
                                    "expected parameters"
                                    (if (= (type (. ast index)) "table")
                                        (. ast index) ast))
          arg-name-list (utils.kvmap arg-list (partial get-arg-name (# arg-list)))
    (let [arg-name-list (utils.map arg-list get-arg-name)
          (index docstring) (if (and (= (type (. ast (+ index 1))) :string)
                                     (< (+ index 1) (# ast)))
                                (values (+ index 1) (. ast (+ index 1)))

M test/core.fnl => test/core.fnl +3 -0
@@ 100,6 100,9 @@
               "(let [add (fn [x y z] (+ x y z)) f2 (partial add 1 2)] (f2 6))" 9
               "(let [add (fn [x y] (+ x y)) add2 (partial add)] (add2 99 2))" 101
               "(let [add (fn [x y] (+ x y)) inc (partial add 1)] (inc 99))" 100

               ;; many args
               "((fn f [a sin cos radC cx cy x y limit dis] sin) 8 529)" 529
    (each [code expected (pairs cases)]
      (l.assertEquals (fennel.eval code {:correlate true}) expected code))))