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

User-friendly operator declaration syntax #2270

Merged
merged 12 commits into from
Aug 9, 2023
Merged

User-friendly operator declaration syntax #2270

merged 12 commits into from
Aug 9, 2023

Conversation

lukaszcz
Copy link
Collaborator

@lukaszcz lukaszcz commented Aug 3, 2023

Adds the possibility to define operator fixities. They live in a separate namespace. Standard library defines a few in Stdlib.Data.Fixity:


syntax fixity rapp {arity: binary, assoc: right};
syntax fixity lapp {arity: binary, assoc: left, same: rapp};
syntax fixity seq {arity: binary, assoc: left, above: [lapp]};

syntax fixity functor {arity: binary, assoc: right};

syntax fixity logical {arity: binary, assoc: right, above: [seq]};
syntax fixity comparison {arity: binary, assoc: none, above: [logical]};

syntax fixity pair {arity: binary, assoc: right};
syntax fixity cons {arity: binary, assoc: right, above: [pair]};

syntax fixity step {arity: binary, assoc: right};
syntax fixity range {arity: binary, assoc: right, above: [step]};

syntax fixity additive {arity: binary, assoc: left, above: [comparison, range, cons]};
syntax fixity multiplicative {arity: binary, assoc: left, above: [additive]};

syntax fixity composition {arity: binary, assoc: right, above: [multiplicative]};

The fixities are identifiers in a separate namespace (different from symbol and module namespaces). They can be exported/imported and then used in operator declarations:

import Stdlib.Data.Fixity open;

syntax operator && logical;
syntax operator || logical;
syntax operator + additive;
syntax operator * multiplicative;

@lukaszcz lukaszcz added enhancement New feature or request parsing syntax labels Aug 3, 2023
@lukaszcz lukaszcz added this to the 0.4.3 milestone Aug 3, 2023
@lukaszcz lukaszcz self-assigned this Aug 3, 2023
@janmasrovira janmasrovira mentioned this pull request Aug 4, 2023
@lukaszcz lukaszcz marked this pull request as ready for review August 7, 2023 18:26
@jonaprieto
Copy link
Collaborator

I found instances of HasLoc for FixitySyntaxDef and OperatorSyntaxDef. However, in the editor, I got this:

Screenshot 2023-08-09 at 09 51 38

What is the issue?

@jonaprieto
Copy link
Collaborator

Please solve the conflicts and fix the following issues for fixity:

  • Prohibit the use of duplicate keys, , e.g. syntax fixity sub {..., same: "seq", same: "ladd"};
  • Prohibit the use of keys of the same kind, such as syntax fixity sub {..., same: "seq", above: "ladd"};

@lukaszcz
Copy link
Collaborator Author

lukaszcz commented Aug 9, 2023

  • Prohibit the use of duplicate keys, , e.g. syntax fixity sub {..., same: "seq", same: "ladd"};

It turns out JSON/Yaml allow duplicate keys and the behaviour is to silently ignore all but one of them 🤦🏻

I'll try to fix that, but I'm not sure if that's even possible with the current library interface.

  • Prohibit the use of keys of the same kind, such as syntax fixity sub {..., same: "seq", above: "ladd"};

This will give an error at scoping, but maybe the error message is not informative enough, so I can add a check at parsing stage.

@lukaszcz
Copy link
Collaborator Author

lukaszcz commented Aug 9, 2023

  • Prohibit the use of duplicate keys, , e.g. syntax fixity sub {..., same: "seq", same: "ladd"};

It turns out JSON/Yaml allow duplicate keys and the behaviour is to silently ignore all but one of them 🤦🏻

I'll try to fix that, but I'm not sure if that's even possible with the current library interface.

I give up on this one (for now). There just seems no way to make the Yaml parsing library fail with duplicate keys, and from the API it seems one can access only one key even in functions like forEachInObject. I tried to create a list of all keys, didn't work (duplicates already removed by the library). We would need to use a different library, or give up on Yaml.

  • Prohibit the use of keys of the same kind, such as syntax fixity sub {..., same: "seq", above: "ladd"};

This will give an error at scoping, but maybe the error message is not informative enough, so I can add a check at parsing stage.

Fixed that.

@paulcadman
Copy link
Collaborator

I give up on this one (for now). There just seems no way to make the Yaml parsing library fail with duplicate keys, and from the API it seems one can access only one key even in functions like forEachInObject. I tried to create a list of all keys, didn't work (duplicates already removed by the library). We would need to use a different library, or give up on Yaml.

The yaml library can emit warnings about duplicate keys that can be handled at decode time. Unfortunately the API is only easily available for the decodeFileWithWarnings API, not the ByteString decoding API.

We'd need the library to implement something like the following, for our use case (adapted from the implementation of decodeEither', which interestingly uses unsafePerformIO).

import Text.Libyaml qualified as Y

decodeEitherWarning :: FromJSON a => ByteString -> Either ParseException ([Warning], a)
decodeEitherWarning = either Left splitEither
              . unsafePerformIO
              . decodeHelper
              . Y.decode
    where
      splitEither :: ([Warning], Either String a) -> Either ParseException ([Warning], a)
      splitEither (_, Left s) = Left (AesonException s)
      splitEither (ws, Right x) = Right (ws, x)

@lukaszcz
Copy link
Collaborator Author

lukaszcz commented Aug 9, 2023

I give up on this one (for now). There just seems no way to make the Yaml parsing library fail with duplicate keys, and from the API it seems one can access only one key even in functions like forEachInObject. I tried to create a list of all keys, didn't work (duplicates already removed by the library). We would need to use a different library, or give up on Yaml.

The yaml library can emit warnings about duplicate keys that can be handled at decode time. Unfortunately the API is only easily available for the decodeFileWithWarnings API, not the ByteString decoding API.

We'd need the library to implement something like the following, for our use case (adapted from the implementation of decodeEither', which interestingly uses unsafePerformIO).

import Text.Libyaml qualified as Y

decodeEitherWarning :: FromJSON a => ByteString -> Either ParseException ([Warning], a)
decodeEitherWarning = either Left splitEither
              . unsafePerformIO
              . decodeHelper
              . Y.decode
    where
      splitEither :: ([Warning], Either String a) -> Either ParseException ([Warning], a)
      splitEither (_, Left s) = Left (AesonException s)
      splitEither (ws, Right x) = Right (ws, x)

Thanks! I'll take a look at this again then, but maybe we can raise this as a separate issue? This affects all places we use Yaml in: pragmas, iterators, fixities. I didn't go deep enough to try reimplementing stuff from Data.Yaml using Text.Libyaml, but this should be explored.

@jonaprieto jonaprieto merged commit eebe961 into main Aug 9, 2023
4 checks passed
@jonaprieto jonaprieto deleted the operator-syntax branch August 9, 2023 16:15
@janmasrovira
Copy link
Collaborator

janmasrovira commented Aug 21, 2023

@lukaszcz is it possible to use/hide an infixity in an open statement? From looking at the code it does not look like it

@lukaszcz
Copy link
Collaborator Author

Hmm, I might've missed it. It should be possible. If it doesn't work, we should open an issue for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request parsing syntax
Projects
None yet
Development

Successfully merging this pull request may close these issues.

User-friendly specification of operator priorities
4 participants