curimit / SugarCpp

SugarCpp is a language which can compile to C++11.
135 stars 13 forks source link

eliminate parenthesis when invoking function #6

Open zxytim opened 11 years ago

zxytim commented 11 years ago

since you have borrowed lots of good features from coffee-script, how about the feature that invoke a function without parenthesis when it has argument(s), and with parenthesis when there is no argument?

Or introduce addtional simple syntax that improve the fluency of coding?

Thx

curimit commented 11 years ago

Since c++ is much more complicated than javascript. Simply eliminate parenthesis when invoking function will increase syntactic ambiguity. For example

// get < int > x
// which will treated as : get < int && int > x
get<int> x

But this is a good topic: how to eliminate parenthesis by introduce additional syntax. I'll consider about it.

zxytim commented 11 years ago

If you decide to add the livescript syntaxf <| xandx |> f as stated in https://github.com/curimit/SugarCpp/issues/15, then this problem may be kind of solved. But to my oppinion, we should expect a one-direction function invoke method, and it is easier to be nested.

I discussed with friends, and come up an idea like f0$x, f1$y, z, where $ is a symbol that will not appear in default grammar, like $, `, @, denote a function call. And similar to coffee-script,f0$x, f1$y, zshould be compiled tof0(x, f1(y, z)).

But it seems to reduce the readability of the code.

curimit commented 11 years ago

I think it is possible to eliminate parenthesis when invoking function, but it will be a lot of work to rewrite the grammar by using top-down LL(1) parser. I will try to implement this feature when I turn from Antlr3 to Antlr4.

dobkeratops commented 9 years ago

Interesting issue;

[1] I am looking into something similar in my own rust inspired experiment: In Rust the approach is to use much stronger type-inference to reduce the number of times you write type-parameters within function bodies. In function signatures, the parsing context is different and unambiguous. But also they do use a special syntax to introduce type parameters in the 'main context':-

eg in Rust: fn foo<T>(a:Vec<T>) { <T> is a typeparameter, unambiguous in type context following ":" let x=something::<T>(); // ::<T> is a typeparameter, :: disambiguates it. }`

Their "type context" is also selected by ":" e.g. in let:- let x:Vec<int>; // is unambiguously Type, after ":"

fn foo<T>()->Vec<T> { let x=Vec::new() // infers backwards x=Vec from the return value, no typeparams needed ..do stuff with x.. return x; } [2] I have experimented briefly with another idea to disambiguate <...> with limited rules, which would only handle a subset of cases. Namely < .* > on one line is always considered TypeParameters, unless separated by ";" or unbalanced parens/braces. Other expressions are allowed in type parameters if contained in parens. It simply precludes using cases like a<b,c>d a<b>c as expressions. This might be acceptable if it throws appropriate errors, e.g. did you mean a<b,(c>d). In the example of chained comparisons, maybe lo<x<hi is more common?

[3] I am interested in simply using square brackets like scala, foo[T](args) . Even after years of C++ I am finding this more pleasing; again I would take the rust approach of requiring disambiguation in the main context. foo:[T]

ozra commented 9 years ago

Being able to do LS/CS call style would indeed be nice. The $ syntax don't seem to have any benefits at all as to readability.

I think function calls should precede tightly. Where:

  int foo(a :int) = a * a
  int bar(a :int, b :int) = a + b

This:

  int main()
      a := foo 7 + bar 9, 10      

Should become:

    auto a = foo(7) + bar(9, 10);

not:

    auto a = foo(7 + bar(9, 10));

Also, let's say we have function foo taking one argument and returning some callable taking one arg:

   a := 47
   bar := foo a 42

Should imo become

   auto bar = foo(a)(42)

not

   auto bar = foo(a(42))

On the template ambiguity issue:

foo = get<int> x

a) If the compiler is type aware, it shouldn't be an issue. If function overloading also takes return type in to account (in contrast to C++) the <*> part could be deduced to begin with and not be needed, if it's not inferred by the parameter alone (which it presumably is in the example). b) One could choose other symbols than <> for "templating" syntax, like mentioned above, [], but then there's ambiguity with indexing to consider. c) One could solve it in by simply treating type templating as args along with values (then also accounting for cases where the templated types aren't part of wither args nor return type, and still not use special symbols for it)? d) In any event - readability and clarity of intent should be priority number one in syntax. So finally, in case of ambiguity, it could simply be better to demand explicit parens.

curimit commented 9 years ago

The <*> ambiguity has been solved now, I think this could be implemented by simply refactor the grammar file. I'll solve several ambiguities such as type casting and function call. I'll fix that somehow.

a := (int) x
b := (f) x