Swift3:How to Handle Precedencegroup Now Operator Should Be Declare with a Body

Swift3 : how to handle precedencegroup now operator should be declare with a body?

As per SE-0077, the precedence of an operator is no longer determined by a magic number – instead you now use the higherThan and (if the group resides in another module) lowerThan precedencegroup relationships in order to define precedence relative to other groups.

For example (from the evolution proposal):

// module Swift
precedencegroup Additive { higherThan: Range }
precedencegroup Multiplicative { higherThan: Additive }

// module A
precedencegroup Equivalence {
higherThan: Comparative
lowerThan: Additive // possible, because Additive lies in another module
}
infix operator ~ : Equivalence

1 + 2 ~ 3 // same as (1 + 2) ~ 3, because Additive > Equivalence
1 * 2 ~ 3 // same as (1 * 2) ~ 3, because Multiplicative > Additive > Equivalence
1 < 2 ~ 3 // same as 1 < (2 ~ 3), because Equivalence > Comparative
1 += 2 ~ 3 // same as 1 += (2 ~ 3), because Equivalence > Comparative > Assignment
1 ... 2 ~ 3 // error, because Range and Equivalence are unrelated

Although in your case, as it appears that your operator is used for multiplication, you could simply use the standard library's MultiplicationPrecedence group, which is used for the * operator:

infix operator × : MultiplicationPrecedence

It is defined as:

precedencegroup MultiplicationPrecedence {
associativity: left
higherThan: AdditionPrecedence
}

For a full list of standard library precedence groups, as well as more info about this change, see the evolution proposal.

How to declare exponent/power operator with new precedencegroup in Swift 3?

Your code already compiles and runs – you don't need to define a precedence relationship or an associativity if you're simply using the operator in isolation, such as in the example you gave:

10 ^^ -12
10 ^^ -24

However, if you want to work with other operators, as well as chaining together multiple exponents, you'll want to define a precedence relationship that's higher than the MultiplicationPrecedence and a right associativity.

precedencegroup ExponentiativePrecedence {
associativity: right
higherThan: MultiplicationPrecedence
}

Therefore the following expression:

let x = 2 + 10 * 5 ^^ 2 ^^ 3

will be evaluated as:

let x = 2 + (10 * (5 ^^ (2 ^^ 3)))
// ^^ ^^ ^^--- Right associativity
// || \--------- ExponentiativePrecedence > MultiplicationPrecedence
// \--------------- MultiplicationPrecedence > AdditionPrecedence,
// as defined by the standard library

The full list of standard library precedence groups is available on the evolution proposal.

Swift - how to create custom operators to use in other modules?

I can confirm that that what you are seeing is what really happens. I just tried it myself and I've seen the same result.

My opinion is that >>= is somehow conflicting with some other operator (probably the bite shift operator: >>) or is being declared somewhere else too (you can see why I think that here). I did successfully declared custom operators in a framework and used those in the main app code before (you can see that here for example).

What I would suggest is rename your custom operator to something else. When I did that (renamed the custom operator to >>>=) the compiler stopped complaining and my app compiled just fine.

Later edit

Ok. So this might help a bit more. Basically when an operator is already declared and you want to add extra functionality to that operator (for example doing things like 3 * "Hello" like Johan Kool said he wanted to) all you have to do is overload that operator's method.

Basically, in your specific case I am now 100% that >>= is an already declared operator and you can go ahead and just add these lines in your framework:

public func >>=<A, B>(a: A?, f: A -> B?) -> B? {
if let a = a { return f(a) }
else { return .None }
}

This will make your operator work. BUT it will inherit the precedence and associativity of the original operator thus giving you less control over how it's supposed to behave.

Why must a protocol operator be implemented as a global function?

UPDATE

From the Xcode 8 beta 4 release notes:

Operators can be defined within types or extensions thereof. For example:

struct Foo: Equatable {
let value: Int
static func ==(lhs: Foo, rhs: Foo) -> Bool {
return lhs.value == rhs.value
}
}

Such operators must be declared as static (or, within a class, class final), and have the same
signature as their global counterparts. As part of this change, operator requirements declared in
protocols must also be explicitly declared static:

protocol Equatable {
static func ==(lhs: Self, rhs: Self) -> Bool
}

ORIGINAL

This was discussed on the swift-evolution list recently (2016-01-31 through 2016-02-09 so far). Here's what Chris Lattner said, regarding declaring operators in a struct or class scope:

Yep, this is a generally desirable feature (at least for symmetric operators). This would also be great to get dynamic dispatch of operators within class declarations. I don’t think we have a firm proposal nailing down how name lookup works with this though.

And later (replying to Haravikk):

What are the name lookup issues? Do you mean cases where an operator for Foo == Foo exists in more than one location?


Yes. Name lookup has to have a well defined search order, which
defines shadowing and invalid multiple definition rules.

Personally I’d just stick with what we have now, i.e- treat operator implementations within a specific class/struct as being globally
defined anyway and throw an error if the same signature is declared
more than once.


We need multiple modules to be able to define instances of an
operator, we need operators in extensions, and we need retroactive
conformance to work, as with any other member.

Equation (expression) parser with precedence?

The hard way

You want a recursive descent parser.

To get precedence you need to think recursively, for example, using your sample string,

1+11*5

to do this manually, you would have to read the 1, then see the plus and start a whole new recursive parse "session" starting with 11... and make sure to parse the 11 * 5 into its own factor, yielding a parse tree with 1 + (11 * 5).

This all feels so painful even to attempt to explain, especially with the added powerlessness of C. See, after parsing the 11, if the * was actually a + instead, you would have to abandon the attempt at making a term and instead parse the 11 itself as a factor. My head is already exploding. It's possible with the recursive decent strategy, but there is a better way...

The easy (right) way

If you use a GPL tool like Bison, you probably don't need to worry about licensing issues since the C code generated by bison is not covered by the GPL (IANAL but I'm pretty sure GPL tools don't force the GPL on generated code/binaries; for example Apple compiles code like say, Aperture with GCC and they sell it without having to GPL said code).

Download Bison (or something equivalent, ANTLR, etc.).

There is usually some sample code that you can just run bison on and get your desired C code that demonstrates this four function calculator:

http://www.gnu.org/software/bison/manual/html_node/Infix-Calc.html

Look at the generated code, and see that this is not as easy as it sounds. Also, the advantages of using a tool like Bison are 1) you learn something (especially if you read the Dragon book and learn about grammars), 2) you avoid NIH trying to reinvent the wheel. With a real parser-generator tool, you actually have a hope at scaling up later, showing other people you know that parsers are the domain of parsing tools.


Update:

People here have offered much sound advice. My only warning against skipping the parsing tools or just using the Shunting Yard algorithm or a hand rolled recursive decent parser is that little toy languages1 may someday turn into big actual languages with functions (sin, cos, log) and variables, conditions and for loops.

Flex/Bison may very well be overkill for a small, simple interpreter, but a one off parser+evaluator may cause trouble down the line when changes need to be made or features need to be added. Your situation will vary and you will need to use your judgement; just don't punish other people for your sins [2] and build a less than adequate tool.

My favorite tool for parsing

The best tool in the world for the job is the Parsec library (for recursive decent parsers) which comes with the programming language Haskell. It looks a lot like BNF, or like some specialized tool or domain specific language for parsing (sample code [3]), but it is in fact just a regular library in Haskell, meaning that it compiles in the same build step as the rest of your Haskell code, and you can write arbitrary Haskell code and call that within your parser, and you can mix and match other libraries all in the same code. (Embedding a parsing language like this in a language other than Haskell results in loads of syntactic cruft, by the way. I did this in C# and it works quite well but it is not so pretty and succinct.)

Notes:

1 Richard Stallman says, in Why you should not use Tcl

The principal lesson of Emacs is that
a language for extensions should not
be a mere "extension language". It
should be a real programming language,
designed for writing and maintaining
substantial programs. Because people
will want to do that!

[2] Yes, I am forever scarred from using that "language".

Also note that when I submitted this entry, the preview was correct, but SO's less than adequate parser ate my close anchor tag on the first paragraph, proving that parsers are not something to be trifled with because if you use regexes and one off hacks you will probably get something subtle and small wrong.

[3] Snippet of a Haskell parser using Parsec: a four function calculator extended with exponents, parentheses, whitespace for multiplication, and constants (like pi and e).

aexpr   =   expr `chainl1` toOp
expr = optChainl1 term addop (toScalar 0)
term = factor `chainl1` mulop
factor = sexpr `chainr1` powop
sexpr = parens aexpr
<|> scalar
<|> ident

powop = sym "^" >>= return . (B Pow)
<|> sym "^-" >>= return . (\x y -> B Pow x (B Sub (toScalar 0) y))

toOp = sym "->" >>= return . (B To)

mulop = sym "*" >>= return . (B Mul)
<|> sym "/" >>= return . (B Div)
<|> sym "%" >>= return . (B Mod)
<|> return . (B Mul)

addop = sym "+" >>= return . (B Add)
<|> sym "-" >>= return . (B Sub)

scalar = number >>= return . toScalar

ident = literal >>= return . Lit

parens p = do
lparen
result <- p
rparen
return result

Strange behavior about WEXITSTATUS with `G++ 4.9.4`

The WEXITSTATUS macro is a matter of the C standard library implementation, not the compiler per se. Typically (and in the case of GCC) the compiler doesn't supply the C standard library implementation. It is an independent package.

Most Linux distributions, including Ubuntu, use glibc as C standard library implementation.

In glibc until version 2.23, inclusive, the macro was defined in the following way when using C++ and __USE_MISC is set (see commit link below):

#   define __WAIT_INT(status)   (*(const int *) &(status))

// ...

# define WEXITSTATUS(status) __WEXITSTATUS (__WAIT_INT (status))

The actual implementation of the macro is inside __WEXITSTATUS, but the use of __WAIT_INT seems to be for the purpose of supporting the non-POSIX "union wait" variant of the wait interface. With this definition, a prvalue cannot be used with the macro, because it tries to take the address of status.

In 2016, with commit b49ab5f4503f36dcbf43f821f817da66b2931fe6 support for union wait - according to the NEWS entry deprecated in the early 1990s - has been removed and now the definition is simply

# define WEXITSTATUS(status)    __WEXITSTATUS (status)

Now it would work with a prvalue as well.

It seems that Ubuntu 16.04 still uses a glibc version from before that change, which isn't surprising since it was released at the time of the commit.

I don't know what POSIX has to say about whether or not it should be possible to use the macro with a int rvalue rather than the name of a variable.

That WEXITSTATUS can't always be used directly on a call to pclose seems to be known issue. Apparently the above-mentioned extension, which is now not present in glibc anymore, was (is?) also present in (some?) BSDs (and may originate from them?). See e.g. this question, in which the answer also expresses doubts about POSIX-compliance. However, OpenBSD, mentioned in the linked question, also removed union wait in 2014. According to the changelog it had been deprecated since 4.3BSD (released 1986).



Related Topics



Leave a reply



Submit