Skip to content
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

Rewrite proposal to use AssignmentExpression #65

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

Arlen22
Copy link

@Arlen22 Arlen22 commented Jan 23, 2025

The ECMA262 parser grammar actually makes it extremely simple to implement the try keyword for all single expressions. It also is extremely simple to catch any errors that are thrown.

Syntax

  • AssignmentExpression:
    • try [ForbidNewLine] [lookahead≠{] AssignmentExpression

Runtime Evaluation (simplified slightly)

const A = Evaluate(Expression);
if(ISTHROWN(A)) return Result.error(A.VALUE);
const B = GetValue(A);
if(ISNORMAL(B)) return Result.ok(B.VALUE);
if(ISTHROWN(B)) return Result.error(B.VALUE);

Explanation

The definition for the "single expression" is called the Assignment Expression. It is so named because it is the expression that returns the result of assigning a value to a variable, allowing x=y=z=5. It is used in many places throughout ECMA262 as it is the highest form of a single expression.

The Assignment Expression is found in many places

  • Function arguments, and argument defaults ((x = 4, y = x=6) => x=5)(a=4);
  • if, while, and do while conditions.
  • The input expression in for and all expressions in for(;;)
  • The value of variable declarations.
  • The values in Array and Object literals
  • Then and Else branches of ternary expressions.
  • The yield expression, which is the yield keyword followed by an Assignment Expression, is itself also an Assignment Expression. The definition is recursive, allowing yield yield yield.
  • The arrow function expression body, with a lookahead prohibiting the curly brace.

In keeping with the examples above,

  • the try expression
    • is an Assignment Expression
      • This lets it be used almost anywhere a top-level expression is needed.
    • is composed of
      • the try keyword,
      • a lookahead prohibiting a curly brace as the first character,
      • an Assignment Expression.
        • This makes it take everything to the right of it that it possibly can, basically stopping only for commas or when otherwise limited by its parent expression (e.g. in Then branch of the ternary operator). This is preferrable since there is almost never a time where you would want to try only part of an expression.

All of this is based on my technical understanding of the ECMA262 spec, which is quite limited, but hopefully sufficient.

A note on commas

I use the term "single expressions" to differentiate from multiple expressions separated by commas.

However, when surrounded by parentheses, these multiple expressions are child to the single expression created by the parentheses. Therefore the try keyword may protect multiple expressions, and return the result of the last expression, using the parentheses. This is inherently how parentheses work. They combine multiple expressions into a single expression that returns the last value. So if needed, the try expression can be wrapped in parentheses.

In the ECMA262, multiple comma-separated expressions are only allowed in a few places, such as parentheses, return, and throw. They are really not allowed anywhere else without parentheses, whereas the Assignment Expression is used just about everywhere, and includes the parentheses case, so there was literally no point in trying to find ways to allow commas. It just makes everything a whole lot easier.

Copy link
Owner

@arthurfiorette arthurfiorette left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there are a lot of things here that need dedicated discussions before getting merged. I suggest you to split them into smaller PRs

/** @type {ResultConstructor} */
class Result {
/** @type {TryResultConstructor} */
class TryResult {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to change to TryResult? Result is an understandable type with the same name as in other languages.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Result seems too generic in the JavaScript world and it's very ambiguous what it's actually for. It could easily create name collisions in user space. TryResult is much less likely to collide and its purpose is clearer, though still somewhat ambiguous.

README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
.vscode/settings.json Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
- **`ok`**: A boolean indicating whether the expression executed successfully.
- **`error`**: The error thrown during execution, or `undefined` if no error occurred.
- **`value`**: The data returned from the execution, or `undefined` if an error occurred.
AssignmentExpression[In, Yield, Await] :
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll need to deeply study our syntax use-case and read similar proposals to see if this syntax is correct or not. Any sources inspired you to write it in this way?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got it from the ECMA262 spec. I also updated the spec.emu file, which looks a lot nicer than this does and integrates into the existing spec.

You can see what it looks like here: https://arlen22.github.io/proposal-safe-assignment-operator/

README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
README.md Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants