sublimehq / Packages

Syntax highlighting files shipped with Sublime Text and Sublime Merge
https://sublimetext.com
Other
2.95k stars 586 forks source link

[RFC] Add new scopes to "jumping" flow control keywords/statements. #1228

Open FHTheron opened 6 years ago

FHTheron commented 6 years ago

Intro

First let me define what I mean with "jump" keywords. Things like if and else are of course also flow control keywords and they do result in the CPU executing branches, but I'm more specifically considering the jump in terms of visual code flow. For example, a subtle goto that radically changes the execution flow isn't always as visible as the effect it has.

Current scopes

In C these currently get the scope keyword.control.c, but this scope is also used (correctly) for if, while, and other actual flow control keywords.

In Python the scope is keyword.control.flow.python and includes loop keywords as well as return and raise.

New scopes

I suggest that some of these flow control keywords get scoped as two new flow control types - one type jumps within the current frame/call stack the other jumps out of the current call stack.

C

C++

Python

And many more languages with similar keywords/statements.

Alternative

The same colouring can be achieved if all languages define unique scopes for all flow control keywords. This will avoid having to define what each keyword's jump type is. Python has this for 2 keywords, Shell-Unix-Generic seems to have keyword.control.*.shell for all keywords. A colour scheme can then add each of these to colour them as desired. It does mean that the colour scheme now defines what jump type a jump keyword is, which may or may not matter.

Example screenshots

Current: current

Proposed, using new scopes with illustrative colours: proposed

FichteFoll commented 6 years ago

I like the rationale. I also used to do something similar when I had to use eclipse for some Java code.

What I'm wondering is whether we could define a set of commonly used jump types, i.e. jumping around and jumping out, and add sub-scopes for the actual keyword in question, plus the syntax.

I'm thinking of the following template for this: keyword.control.flow.jump.<jump-type>.<keyword>.<syntax-suffix>, with the jump types

Are there any more types of jumps that I didn't think of here? Note that I didn't follow the "out" and "around" terminlogy, because from a color scheme PoV the above distinction makes more sense. (Otherwise break would get the same color as return since they're both jumping "out" of something.)

For example, jumping out of a loop in C with break would be scoped as keyword.control.flow.jump.loop.break.c.

I'm unsure about assert, however. It's a conditional jump, similarly to an if statement that could jump to the corresponding else if the condition turns out to be false. The same analogy would apply to conditional jumps in assembler, e.g. jnz vs jmp.

And finally, highlighting functions as keywords may be semantically right in some languages, but this is going to be controversal. I see the argument for both sides but don't feel strong enough for either, in which case I'd just stick with the status quo.


While we're at it, maybe add some sub-types for keyword.control.flow as well, such as conditional and loop? Are there more flow statements/keywords that don't fit any of these two and jump?

keith-hall commented 6 years ago

The C# syntax is fairly expressive already:

(arguably, return and yield break have more similar jump out semantics than return and yield return in terms of control flow leaving the method)

so I like the idea of this proposal being standardized across languages for syntax highlighting purposes. Definitely assert shoudn't get a keyword scope in the languages where it is a method, but would still be useful to give it some specific (relevant) scope.

FichteFoll commented 6 years ago

So, I was a bit off with the keyword.control.flow, since according to both TextMate and ST conventions (which were inherited) keyword.control is already reserved for mostly flow control, but while keyword.control.loop also makes sense for a while keyword, grouping flow control keywords within loops in yet another subscope of that seems inappropriate from a color scheme perspective (again).

That would leave us with a list like the following:

keyword
    control
        conditional
            if
            else
            elseif
        exception
            try
            catch
        import
            from
        loop (do we even want to standardize sub-scopes of this?)
            do-while
            for
            repeat-until
            while
        flow
            exception (maybe flatten since this is the only exception-related flow keyword construct)
                throw
            goto
            loop (maybe flatten this, too)
                break
                continue
            return
            yield

Note that these all represent the general name of the construct, for example if a while loop is initiated with repeat it should still be a sub-scope of keyword.control.loop.while, or keyword.control.flow.exception.throw for raise. repeat-until

(I'm actually not sure why import should be a sub-scope of keyword.control. Seems to make more sense as keyword.import or keyword.other.import even.)

deathaxe commented 5 years ago

@wbond Can this be labeled RFC?

deathaxe commented 5 years ago

@FichteFoll @keith-hall : How to sort switch and case like statements into the tree?

I saw different solutions like

I think all of them are keyword.control.conditional as well as they just group a chain of if-else constructs in a more efficient way.

FichteFoll commented 5 years ago

That's a yes from me regarding keyword.control.conditional.

I think the widely used practice currently is to do keyword.control.<keyword-name>, with the exception of conditional weaved in for if and family. The problem is that we never really agreed upon a naming scheme here, but I still believe my last suggestion to be pretty close once the parenthesized comments are addressed.

FichteFoll commented 5 years ago

While reviweing #1850 I noticed I never thought about languages that use keywords to terminate control structures (like done or end or endwhile). What about keyword.control.<group>.end?

michaelblyons commented 5 years ago

While reviewing #1850 I noticed I never thought about languages that use keywords to terminate control structures (like done or end or endwhile). What about keyword.control.<group>.end?

Does this mean you'd also want to scope the opener as ...<group>.begin?

deathaxe commented 5 years ago

This would mean to scope all kinds of loops (i.e. while, for, repeat, ...) with keyword.control.loop.begin if the keywords are used to open a loop statement. Keywords like until, end, endfor, endwhile would be scoped keyword.control.loop.end then? This arises the question how to scope a while keyword, if the language allows to put it to the beginning and the end? Use two scopes for it depending on position?

Meta Example

do
  bar;
while(foo);
while (foo)
  bar
endwhile

Or do you prefer scopes like

Not sure if it makes sense or whether it is just too much? How to handle syntaxes which use the same end keyword for different kinds of loops then? Scope the same word with different scopes? Not sure about that.

Scopes like begin and end make sense only if they are used as general scopes which are located in the same level for all statements, which feels sometimes odd. Example:

How to handle repeat ... until loops here?

Finally I find keyword.control.loop.while vs. keyword.control.loop.end enough if end is a commonly used terminator keyword for one or more types of loops.

Otherwise keyword.control.loop.<group> is enough.

FichteFoll commented 5 years ago

Finally I find keyword.control.loop.while vs. keyword.control.loop.end enough if end is a commonly used terminator keyword for one or more types of loops.

That's what I was going with initially, but also for conditionals. Example:

while (foo)
  bar
endwhile
if (foo)
  bar
endif

while: keyword.control.loop.while endwhile: keyword.control.loop.end if: keyword.control.conditional.if endif: keyword.control.conditional.end

Keywords like until, end, endfor, endwhile would be scoped keyword.control.loop.end then?

Yes.

How to handle syntaxes which use the same end keyword for different kinds of loops then? Scope the same word with different scopes? Not sure about that.

I don't see a problem with that. Python also has two different scopes for from, as and in depending on how they are used, and I wouldn't want those to have the same. Lua uses end for everything, including function definitions.

Scopes like begin and end make sense only if they are used as general scopes which are located in the same level for all statements, which feels sometimes odd.

That's a warranted concern for the case where we want to have both begin and end. Another is languages that don't have keywords to close the control structures.

How to handle repeat ... until loops here?

keyword.control.loop.begin.repeat-until and keyword.control.loop.end.repeat-until (or alternatively with begin and end at the end)


I believe that leaves us at the following options:

  1. keyword.control.<loop/conditional>.end regardless of how it was opened; opening keywords as before
  2. keyword.control.loop.<begin/end>.repeat-until
  3. keyword.control.loop.repeat-until.<begin/end>

Each of these has advantages and disadvantages in general or special cases.

  1. is the simplest option; works anywhere but also has the least details
  2. allows different highlighting of opening and closing keywords but may be lackluster for languages without closing keywords
  3. is more flexible than 2) but isn't useful for color schemes.

I favor option 1.

FichteFoll commented 5 years ago

Here's an update of my most recent proposal regarding the exact scope names.

  1. moved import out of control. Imports don't/shouldn't affect flow control
  2. flattened the flow (jump) subgroups (exception and loop) as they barely provide a benefit and
  3. added switch/select/case
  4. added keyword.control.*.end
keyword
    context
        block
        resource
        import
    control
        conditional
            case
            else
            elseif
            if
            select
            switch
        exception
            catch
            defer
            finally
            try
        loop
            do-while
            for
            repeat-until
            while
        flow
            assert
            break
            continue
            exit
            goto
            return
            throw
            yield
        *
            end
    import
        from
        <keyword-name> (with/using/include/use)

More questions: what about then in if statements? Similarly, what aboutdo in for ... do; ... end?

Edit: added finally Edit: added defer and assert Edit: added panic Edit: added with under .import (indirectly) and .control.resource Edit: added 2nd level scope context Edit: renamed panic to exit

deathaxe commented 5 years ago

I favor option 1.

Me too.

Here's an update of my most recent proposal regarding the exact scope names.

Like it.

  1. Maybe add keyword.control.exception.finally?

  2. I like the dedicated keyword.import as it really does not belong to control structures. Is it meant for general purpose preprocessor stuff which is executed by the compiler at compile time or the interpreter at module import time as well? Ask because of #1860 and because of C/C++ using keyword.control.import for such keywords atm.

More questions: what about then in if statements? Similarly, what aboutdo in for ... do; ... end?

I tend to scope them the same way as the opening keyword of a loop to ensure them to get the same color. The D PR and Bash use a general keyword.other or keyword.control atm.

wbond commented 5 years ago

So, I could see adding keyword.import, but I'm not sure about removing keyword.control.import for now, since I don't think many color scheme color keyword by itself, but I could be completely wrong about that.

For now we may have to use keyword.control.import keyword.import to allow backwards compatibility.

FHTheron commented 5 years ago

screenshot from 2019-02-15 15-18-50

Ideally the colon on these three lines should have the same scope and whatever changes are made to conditional keyword scopes should probably apply to the punctuation.section.block character as well.

deathaxe commented 5 years ago

conditional keyword scopes should probably apply to the punctuation.section.block character as well.

This depends on your color scheme. if, elif, else are of keyword.control.conditional, which would not apply to the punctuation. A punctuation is not a keyword.

You are otherwise right with punctuations and metas to be scoped a bit inconsistent.

FHTheron commented 5 years ago

Just in case, the word "apply" might have been a bad choice.

I only meant that all those colons should have the same punctuation.section.conditional.block since they are part of conditional lines, not that they should be scoped as keywords. The "apply" referred to keeping it in sync so that if keyword.control.flow.conditional.python were to change to keyword.control.flow.conditional.if.python for example, it will be nice if the colon changed to punctuation.section.conditional.if.block to match.

FichteFoll commented 5 years ago

Go uses the defer keyword instead of finally to declare statements to be excuted when the current scope (in code) is left. Bash's trap is similar to this. It's not really a "jumping" keyword like return since it declares what is being jumped over rather than where from, so I'd think of it as being related to finally and thus get a subscope in exception, i.e. keyword.control.exception.defer. Opinions?

deathaxe commented 4 years ago

I'd vote to add the following scope to the list of defaults

keyword: assert scope: keyword.control.exception.assert

idea/reason: An assertion is something like a short try block, which raises an exception if the boolean result of the expression is false.

FichteFoll commented 4 years ago

I like that and added it to my latest proposal, as well as defer.

FichteFoll commented 4 years ago

Actually, wouldn't that go more in the direction of throwing an exception conditionally and thus belong to keyword.control.flow.assert?

deathaxe commented 4 years ago

None of the flow keywords is followed by an expression to evaluate. They are instead followed by arguments which are returned only. For instance throw Exception just creates an object and breaks the linear flow.

But I don't have a strong meaning about it. Basically, flow is very correct as well.

FichteFoll commented 4 years ago

Assert is special in that it combined conditional branching with flow control that jumps out of the current context. Considering that previous arguments seemed to be more in favor of targeting this special flow control of "exiting/moving the context exactly here", I'd say the jumping part (out of the function to the next try-catch or maybe even the entire program) is more important than the soft implication of a try block saying "something in here might throw".

Maybe someone else could give a third pair of eyes to this?


Now, for a related thing, the ? operator in rust should probably also get a keyword.control.flow scope, but I'm not sure which. It results in an Err type being returned from the current function, which is rust's equivalent of an exception, more or less, but you could also argue it's an assertion because it basically checks for an Err in an rvalue and unwrap that if it isn't. It's different from other languages where the operator just causes the remainder of the line to evaluate to null and would thus be classified as an operator.

And finally, there is the panic macro/function in rust/go, which is like the ultimate control flow word but not really a keyword? Do we prioritize semantic or syntactic accuracy here and if the former, should we introduce keyword.control.flow[.exception].panic?

FHTheron commented 4 years ago

I'd say the jumping part (out of the function to the next try-catch or maybe even the entire program) is more important

This is my view as well. I'd be more interested in the jump than the cause.

deathaxe commented 4 years ago

This is my view as well. I'd be more interested in the jump than the cause.

Convinced.

deathaxe commented 4 years ago

... there is the panic macro/function in rust/go,

It looks very much like the die or dump in Perl. I assigned keyword.control.flow.[die|dump].perl to them, even though they are called function in the docs. I found it more useful to make them stand out from "normal" builtin functions as they act pretty much like throw.

With assert in mind, we propably should panic a keyword.control.flow.panic. An extra sub scope feels a bit overwhelming at the moment.

deathaxe commented 4 years ago

How about the following keywords?


Python, JavaScript use await for coroutines, which might be scoped as keyword.control.flow.await, because it basically causes the caller to block until the asynchronous action has finished. Therefore it influences the control flow.


The keyword with is used in Python, JavaScript, Pascal.

Python: keyword.control.flow.with JavaScript: keyword.control.with

According to MDN with Description it somehow extends the scope of a context but does not directly control the flow. It therefore doesn't feel related with keywords like break, continue, ... which are scoped as keyword.control.flow as well.

How about keyword.control.[namespace|scope|storage].with?

FichteFoll commented 4 years ago

keyword.control.flow.await definitely makes sense. with not as much, because it defines an anchor point rather than a jump-away.

It's related to try and finally in that it ensures that cleanup happens after a block is left due to reaching the end or a different flow mechanism, but unlike finally it doesn't directly describe where to jump to or what to do when that happens. Still, this is structurally the closest match I can find and we wouldn't need another third-level scope. So I suggest keyword.control.exception.with, or alternatively keyword.control.with.

However, there is another type of with statement, e.g. in Visual Basic, that is not flow-related at all and should probably receive a keyword.declaration.with scope?

deathaxe commented 4 years ago

It's related to try and finally in that it ensures that cleanup happens after a block is left

Have this in mind, too. But keyword.control.exception.with feels a bit off topic as it is not directly related with try ... catch control structures.

Why?

A with Class as obj in Python is mainly meant to handle cleanup, but in JavaScript, Pascal and Visual Basic it also manipulates the content of the block's namespace.

In Visual Basic and Pascal with is used to simplify expressions by defining an object as global namespace of the code block.

In JavaScript with is used to extend the global namespace to manipulate the way how unqualified identifiers are searched. It's like a local using namespace ... expression.

Means, all with statements (except Python so far) are quite equal.

Not sure about whether to use keyword.control.with or keyword.declaration.with, but we should choose one, which makes sense for all syntaxes.

keith-hall commented 4 years ago

C# has a using keyword, which performs a similar function to with in other languages, would it make sense to unify that too even though the keyword isn't with? generally we go for semantic scopes rather than keeping scopes in sync with language nomenclature, so I'm voting for yes here.

I'm tempted to also say that it may be worth scoping with differently when it affects cleanup than when it affects the global namespace because they are separate uses and meanings after all.

FichteFoll commented 4 years ago

I'm tempted to also say that it may be worth scoping with differently when it affects cleanup than when it affects the global namespace because they are separate uses and meanings after all.

Definitely, imo. These two usages are nothing alike.

I guess we can categorize with (and using) into 2.5 categories:

  1. Resource-oriented (inspired by Java's try-resource), like Python's with … as …:
  2. Namespace-oriented (with using or with keywords), as used in JavaScript, Visual Basic, C#, Pascal, C++, ….
    1. Affecting the global namespace in an import-like fashion (usually using).
    2. Determining default namespace in a scoped block (With in VB, using in C#?)

Ideas:

  1. keyword.control.resource.with/using or keyword.control.exception.with
  2. Not related to control flow.
    1. keyword.import.namespace.with/using
    2. keyword.other.with ?

keyword.declaration serves a different purpose and shouldn't be used for with, but I find it hard to come up with a concrete scope name for 2.2.

michaelblyons commented 4 years ago

@keith-hall: C# has a using keyword, which performs a similar function to with in other languages, would it make sense to unify that too even though the keyword isn't with? generally we go for semantic scopes rather than keeping scopes in sync with language nomenclature, so I'm voting for yes here.

Seconded. Porting a using (var … = …) {…} in C# to IronPython uses with … as … : syntax. These are currently scoped keyword.control.using.

The other two usings I have used in C# are analogous to import in Python, both scoped as keyword.control.namespace:

@FichteFoll:

  1. keyword.control.resource.with/using or keyword.control.exception.with
  2. Not related to control flow.
    1. keyword.import.namespace.with/using
    2. keyword.other.with ?
  1. The first one. I'm not really a Java guy, so correct me if I misrepresent anything. Despite the similarity to try/finally, there isn't an implication of exception like a try block. It's mostly used to ensure disposal of resources (yes, even if there's an exception).
  2. In all the cases I've used in C#, keyword.import.namespace.with/using makes sense. There might be a case for the 2.ii, but I haven't encountered it.
deathaxe commented 4 years ago

The 2nd level scope keyword.import is not yet used anywhere. All kinds of imports use keyword.control.import instead. Not sure whether to start using the former one at this point.

deathaxe commented 4 years ago

The meaning of the keyword in different syntaxes is:

Syntax usecase
C++ add a namespace to the head of the scope chain for (unqualified) identifier lookup
C# add a namespace to the head of the scope chain for (unqualified) identifier lookup
JS add a namespace to the head of the scope chain for (unqualified) identifier lookup
Pascal add an object to the head of the scope chain for (unqualified) identifier lookup / shorter access to object attributes/methods
Python context control, no namespace/scope manipulation
VBScript add an object to the head of the scope chain for (unqualified) identifier lookup / shorter access to object attributes/methods

*) The rule applies to the using keyword in C++/C#.

The best matching existing scope which describes the majority of use cases of extending the namespace for identifier lookup (except Python) is:

keyword.control.import.[using|with]

FichteFoll commented 4 years ago

I'm with you on keyword.control.import.[using|with], except I'd like to get rid of control at some point and am undecided on using or with. Neither of these seem to win over the others, because they both describe their effects to a similar level. By the way, Rust uses use.

Any recommendations for Python's with case? So far, the only applicable suggestion so far seems to be my own of keyword.control.exception.with, emphasizing how it relates to try-finally.

deathaxe commented 4 years ago

I agree with keyword.import being a proper scope for it, but a lot of syntaxes need to be changed to keep things together. To avoid fragmentation, I'd suggest to finish changes according to this RFC and update string interpolation first. I think the Bash could need some tweaks to string interpolation. Groovy seems to need even more work about all of that. I am on tweaking Batch File atm.

The using and with are just the names of the keywords as if in keyword.control.conditional.if. There is no special semantic meaning.

Python's with seems to be something special as it just acts like a block with a special variable being passed to. Don't have a better idea than keyword.control.exception so far. From the point of colouring, it would even be the best solution.

michaelblyons commented 4 years ago

I agree with keyword.import being a proper scope for it, but a lot of syntaxes need to be changed to keep things together. [But let's finish the current changes before taking this on.]

Agreed.

The using and with are just the names of the keywords as if in keyword.control.conditional.if. There is no special semantic meaning.

Agreed.

Python's with seems to be something special as it just acts like a block with a special variable being passed to. Don't have a better idea than keyword.control.exception so far. From the point of colouring, it would even be the best solution.

I still like keyword.control.resource.with for this (and the corresponding keyword.control.resource.using for languages that use that word instead). The usage does not imply anything about exceptions, only about safe disposal of an object.

FichteFoll commented 4 years ago

There is no special semantic meaning.

The reason for my question was that we'd want to use one scope for the same semantic meaning, even if the keywords in different languages differ. But I guess within the keyword.import scope, we already know that the keyword is importing something and adding something for grouping with and using seems superfluous compared to some languages doing the same with import or #include.

I still like keyword.control.resource.with for this (and the corresponding keyword.control.resource.using for languages that use that word instead).

Do you have any examples for other languages using resource-based keywords like Python's with? I guess we can add a keyword.control.resource scope as it is different enough from the other scopes on that level (and then use the literal keyword for the next level).

I updated my proposal above.

michaelblyons commented 4 years ago

Do you have any examples for other languages using resource-based keywords like Python's with? I guess we can add a keyword.control.resource scope as it is different enough from the other scopes on that level (and then use the literal keyword for the next level).

Yes, C# is one. I made reference to it above, but I didn't write out a sample, so it may not have been super-clear. This is excerpted from the StreamReader examples:

Char[] buffer;
using (var sr = new StreamReader("TestFile1.txt")) {
    buffer = new Char[(int)sr.BaseStream.Length];
    await sr.ReadAsync(buffer, 0, (int)sr.BaseStream.Length);
}
Console.WriteLine(new String(buffer));

It's basically the same as this "Python:" 😉

with StreamReader(filename) as sr:
    # do buffered stuff

Even if you have a return inside the braces, C# will make sure to call Dispose() on the StreamReader, which becomes kind of nice when you nest them in this very contrived example:

using (var httpResponse = webRequest.Response.GetResponseStream())
using (var zipArchive = new ZipArchive(httpResponse))
using (var json = new JsonTextReader(zipArchive))
{
    return new JsonSerializer().Deserialize<MyType>(json);
}

Apparently GitHub doesn't know you can stack them without extra braces, but ST3 does. (Thanks @gwenzek!)

FichteFoll commented 4 years ago

All right, thanks. Now, one final question for confirmation: Java uses try for both try-catch and try-resource. The latter is indicated by an opening paren following the try, which is enough to differentiate between them in a syntax definition. Now, should try receive a different scope based on which version is being used? keyword.control.exception vs keyword.control.resource

(Imo yes, because these are different enough use cases. Also, most color schemes likely only target keyword.control as a whole currently, so we wouldn't be breaking anything in that regard.)

deathaxe commented 4 years ago

I think something like keyword.control.resource is appropriate for the use cases of VBS and Pascal as well.

Would keyword.control.context be a possible maybe more general alternative then?

The common idea behind all with/using/try/... concepts is to control the context of the executed code block by eighter ensuring resource disposal, extending the scope of variable lookup, ... .

This way, the keyword.control.import or later on keyword.import are dedicated to import like statements (alias preprocessor) only. I still find the idea of coloring preprocessor/import statements differnetly, than normal runtime code.

Thoughts?

michaelblyons commented 4 years ago

Would keyword.control.context be a possible maybe more general alternative then?

The common idea behind all with/using/try/... concepts is to control the context of the executed code block by eighter ensuring resource disposal, extending the scope of variable lookup, ... .

This is acceptable. =)

FichteFoll commented 4 years ago

The common idea behind all with/using/try/... concepts is to control the context of the executed code block by eighter ensuring resource disposal, extending the scope of variable lookup, ... .

Yes, that makes sense. However, since they don't really affect control flow, I'd like to suggest keyword.context.resource and keyword.context.import in the event we can afford moving them out of keyword.control since, as you mentioned, they don't affect control flow but rather the context.

I assume we would still have catch and finally in a keyword.control.exception then?

deathaxe commented 4 years ago

As it turns out more languages (e.g. Ruby) use keywords to control the namespace or the variable lookup, I'd suggest a more general wording for a scope.

In https://github.com/sublimehq/Packages/pull/2156#discussion_r341080243 the keyword.control.context was made, which seems to be an appropriate scope for context manipulating keywords in general. It also seems to be a good solution for the discussed keywords above with, using, ..., which all manipulate the variable lookup of a certain block of code by either importing namespaces or injecting new variables to the context.

An alternative might be keyword.control.block if we want to create an analogy to the existing punctuation.section.block scope.

FichteFoll commented 4 years ago

I agree with context beeing a good choice for these kinds of keywords, ideally with another subscope that describes their effect on the context, but I would like to hear @wbond's opinion on adding keyword.context (and keyword.import) because they do not affect control flow and thus shouldn't be in keyword.control. We already added keyword.declaration, although we have an additional fallback scope if color schemes don't define a color for keyword. A compromise might be keyword.other.context?

deathaxe commented 4 years ago

With regards to https://github.com/sublimehq/Packages/pull/2156#discussion_r341741331

Placing the exception under keyword[.control].context arises the question why not to place conditional or loop under it, too? They also create new contexts with local variables etc. which are cleaned up if the local block is left. I think a try .. catch block is nothing else then a - simple to write but more complex in function - flow control statement. It just helps to avoid dozens of if ... if else ... if else statements for error checking/handling.

Next to the existing scopes two major questions came up recently:

  1. How to scope keywords like with or using in languages like Python, Pascal or VBScript , which denote the beginning of a block of code with an extended scope for identifier lookup?
  2. How to scope general purpose keywords which just denote a new block of code but don't fit into the existing naming scheme, such as begin or do in Ruby (or begin in Erlang)?

The current situation is:

  1. We don't want to use keyword.control.flow as those are reserved for keywords like return etc. to exit a block of code (or context), which enables a color scheme to color them differently from the conditional or loop keywords.
  2. Even though such functions don't neccessarily modify the flow by conditional branching or looping, they may still impact the control flow in some way like any { ... } code block in C/C++.
  3. Up to now keyword.control.resource was the result as we only discussed keywords of 1.
  4. Many recent changes were made to apply the current scope name scheme to the default syntaxes. I wouldn't like to change all those scopes again (e.g.: exception).

Conclusion:

The only thing we need is a replacement scope for keyword.control.resource which can be generally applied to the discussed keywords. Maybe the ones I previously suggested - with the arguments for or against each of them.

I don't find that looking too bad when completing your scope scheme @FichteFoll.

keyword
    control
        block/context
            begin
            do
            with
            using
        conditional
        ...
        exception
        ...
        loop
        ...
        flow
        ...

A color scheme can address keyword.control for general purpose keyword colors and than add specialization for maybe keyword.control.flow only to only scope return etc. diffently. ... or add a color for each of them.


With regards to the keyword.import I want to suggest to better use a 2nd level scope name, which denotes to all kinds of preprocessor directives including #define, #if or whatever. While import could be understood as such, it's somehow irritating because of its current use to denote #include or import.

I know there are differences between compiled languages like C/C++ and interpreted ones, but in both cases all imports or defines are made before normal runtime code is executed uppon initialization of a module. A 2nd level scope should just address both.

FichteFoll commented 4 years ago

We should keep the import & preprocessor discussion at #1860.


Generic block keywords like do or begin definitely sound like good candidates for keyword.context.block.

For the resource context keywords, keyword.context.resource seems to work pretty well, too.

Conditional statements or keywords primarily affect control flow and the fact they may also involve different scoping is secondary and not even true for all languages (e.g. Python), so they should not go into .context.

Re-reading the last few posts here, I'm not actually sure where the proposal to move try and catch to keyword.context.resource came from. I mention it in https://github.com/sublimehq/Packages/pull/2156#discussion_r341741331, but I don't understand why. Probably as a reaction to your comment at https://github.com/sublimehq/Packages/pull/2156#discussion_r341080243 without thinking it through. They affect control flow more than context, just like with conditionals, so they shouldn't be moved away from keword.control.

I'll update the proposal above with the recent discussion points.

FichteFoll commented 4 years ago

What do you think of keyword.context.import for the with/using keywords that affect namespace resolution for the current context only?

deathaxe commented 4 years ago

We should keep the import & preprocessor discussion at #1860.

Yes, just forgot about this to be pending.

... where the proposal to move try and catch to keyword.context.resource came from.

From Java, I guess. It supports something like try (var = new Class) { ... } catch { ... } which is similar to pythons with statement. But I would keep it a normal keyword.control.exception, too.

Otherwise keyword.context.block and keyword.context.resource sounds not too bad, if we really need to distinguish them. I tend to not think so, but maybe I've not learned enough syntaxes so far to judge that. :-)

FichteFoll commented 4 years ago

if we really need to distinguish them.

I agree there is something weird about .context.block. "context" already implies some sort of block structure and .context.resource most likely does, too. Scopes and life-times may be an argument, but in Python scopes inherently leak their locals, for example.

Would this mean we should braces in C-like languages as keyword.context as well? Operators don't receive punctuation scopes either.

Still, maybe keyword.context is already enough? (Or stick to keyword.control.context after all?)

FichteFoll commented 4 years ago

In https://github.com/sublimehq/Packages/pull/2156#issuecomment-557211975, @wbond mentioned keyword.control.flow.termination for grouping the keywords that terminate excution, like exit, panic, die etc. I like that. (Edit: however, that cannot be applied to functions performing the same operation)

He also voiced his support for keyword.control.block and keyword.control.context over keyword.context. Would you mind explaining these choices, @wbond? To me, these types of keywords are explicitly not control-flow-related.