Skip to content

try/for/if/do expressions don't support return/break/continue/yield #202

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
edemaine opened this issue Jan 11, 2023 · 5 comments
Open
Labels
enhancement New feature or request partially completed Some of the requested functionality has already been implemented

Comments

@edemaine
Copy link
Collaborator

edemaine commented Jan 11, 2023

compiled :=
  try
    require('@danielx/civet').compile str, options
  catch err
    return "error"

transpiles to

const compiled = (() => {
  try {
    return require("@danielx/civet").compile(str, options);
  } catch (err) {
    return "error";
  }
})();

I would have expected the return in the catch block to escape the entire function, not just the IIFE.

This is a general issue with IIFEs, including for expressions. I'm not sure what the best solution is. For now I guess we could throw an error if there's a return inside the try block...

@edemaine edemaine added the bug Something isn't working label Jan 11, 2023
@STRd6
Copy link
Contributor

STRd6 commented Jan 11, 2023

CoffeeScript's solution is to raise a parse error but I think we can do better.

const returnSymbol = Symbol("return")

const compiled = (() => {
  try {
    return {[returnSymbol]:
      require("@danielx/civet").compile(str, options)
    };
  } catch (err) {
    return "error";
  }
})();

if (typeof compiled === "object" && returnSymbol in compiled) return compiled[returnSymbol]

Something along those lines.

@edemaine
Copy link
Collaborator Author

edemaine commented Jan 11, 2023

Agreed! Another option would be to use exceptions (again 😅 ):

try {
  const compiled = (() => {
    try {
      return require("@danielx/civet").compile(str, options);
    } catch (err) {
      throw new ReturnError("error");
    }
  })();
} catch (e) {
  if (e instanceof ReturnError) return e;
  throw e;
}

But I think I prefer your solution so we don't mess with the source of exceptions...

@STRd6
Copy link
Contributor

STRd6 commented Jan 11, 2023

Also related break label inside of nested iteration iifes (contingent on our eventual label support).

@STRd6 STRd6 assigned STRd6 and unassigned STRd6 Jan 12, 2023
@edemaine edemaine changed the title try expressions don't support return try & for expressions don't support return Feb 16, 2023
@edemaine edemaine changed the title try & for expressions don't support return try/for/do expressions don't support return/break/continue Feb 17, 2023
@juh9870
Copy link

juh9870 commented Mar 26, 2023

Another solution might be not using IFFEs for this at all.
Code in the original post can be compiled into something like

let compiled$temp;

try {
  compiled$temp = require("@danielx/civet").compile(str, options);
} catch (err) {
  return "error";
}
const compiled = compiled$temp;

@edemaine
Copy link
Collaborator Author

@juh9870 Yes, this approach is covered in #381.

Reading about Janet, I realize that this is a special case of a more general feature. See Janet's prompt, return, and signals in general (which is how I believe prompt and return are implemented). We could imagine exposing this to the user as well, and building this functionality on top of it:

out := ::here f()
function f()
  break ::here = 5
---
class PromptHere {}
const out = (function(){
  try {
    return f()
  } catch (e) {
    if (e instanceof PromptHere) {
      return e.value
    } else {
      throw e;
    }
  }
})()
function f() {
  throw new PromptHere(5)
}

@edemaine edemaine changed the title try/for/do expressions don't support return/break/continue try/for/do expressions don't support return/break/continue/yield Dec 22, 2023
@edemaine edemaine mentioned this issue Dec 22, 2023
@edemaine edemaine changed the title try/for/do expressions don't support return/break/continue/yield try/for/if/do expressions don't support return/break/continue/yield Jan 19, 2024
STRd6 added a commit that referenced this issue Feb 29, 2024
#202 - Don't wrap StatementExpressions in IIFE in declaration
@STRd6 STRd6 added enhancement New feature or request partially completed Some of the requested functionality has already been implemented and removed bug Something isn't working labels Mar 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request partially completed Some of the requested functionality has already been implemented
Projects
None yet
Development

No branches or pull requests

3 participants