Skip to content

Anonymous function which is not the last statement results in invalid JS output #640

Closed
@jonasseglare

Description

@jonasseglare

version

The latest commit fa434c1b719de62bd676acf27d440ffc8e3868bb after version v0.8.141

problem

Invalid JavaScript code is produced when an anonymous function appears in a body of statements, such as do or a function body but not at the last position among those statements.

The following code

(defn get-four []
  (fn [] 119)
  4)

compiles to

var get_four = function () {
function () {
return 119;
};
return 4;
};

which is not valid JavaScript. Here is part of the error message:

18:35:14 [vite] Internal server error: Transform failed with 1 error:
/Users/osdjn/prog/libtaxonomy-js/public/test/libtaxonomy/db.jsx:46:9: ERROR: Expected identifier but found "("
  Plugin: vite:esbuild
  File: /Users/osdjn/prog/libtaxonomy-js/public/test/libtaxonomy/db.jsx:46:9

  Expected identifier but found "("
  44 |  };
  45 |  var get_four = function () {
  46 |  function () {
     |           ^
  47 |  return 119;
  48 |  };

repro

Here is a good unit test that fails when I try to include it in compiler_test.cljs:

(deftest fn-statement-test
  (is (= 4 (jsv! "(do (fn [] 119) 4)"))))

expected behavior

Either Squint should not emit a function at all, or it should generate a name for the function so that the generated JavaScript code is valid. So I would suggest that Squint would output the following code for the function get-four:

var get_four = function () {
return 4;
};

attempted fix

I attempted to fix this issue with omit?, see below. That is, if the function doesn't have a name and we are generating code for a statement, we omit it. But with this fix, another unit test breaks.

(defn emit-function* [env expr opts]
  (let [name (when (symbol? (first expr)) (first expr))
        expr (if name (rest expr) expr)
        expr (if (seq? (first expr))
               ;; TODO: multi-arity:
               (first expr)
               expr)
        signature (first expr)
        arrow? (or (:arrow env) (:=> (meta signature)))
        env (assoc env :arrow arrow?)
        omit? (and (= :statement (:context env))
                   (nil? name))]
    (when-not omit?
      (if (some #(= '& %) signature)
         
         ...........

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions