Packages: [RFC] Add new scopes to "jumping" flow control keywords/statements.

Created on 16 Oct 2017  Â·  50Comments  Â·  Source: sublimehq/Packages

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

  • Jump "around"

    • goto

    • break

    • continue

  • Jump "out"

    • return

    • Some standard functions that also result in (possibly) dramatic call stack jumps and these should be scoped the same as the keywords.



      • exit()


      • assert()



C++

  • Jump "around"

    • Same as C

  • Jump "out"

    • Based on C

    • throw

Python

  • Jump "around"

    • break

    • continue

    • Not pass.

  • Jump "out"

    • return (already scoped with keyword.control.flow.return.python)

    • raise (already scoped with keyword.control.flow.raise.python)

    • assert

    • Perhaps yield ?

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

RFC

Most helpful comment

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
    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

All 50 comments

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

  • return,
  • exception,
  • loop, and
  • goto.

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?

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.

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.)

@wbond Can this be labeled RFC?

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

I saw different solutions like

  • C/C++, D, Go, keyword.control
  • C#, JavaScript keyword.control.switch, keyword.control.switch.case
  • Bash keyword.control.case, keyword.control.case.in, keyword.control.case.end, ...

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.

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.

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?

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?

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

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

Or do you prefer scopes like

  • keyword.control.loop.while.begin and keyword.control.loop.while.end?

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:

  • keyword.control.loop.begin.while and keyword.control.loop.end.while
  • keyword.control.loop.begin.for and keyword.control.loop.end.for

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.

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.

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
    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

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.

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.

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.

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.

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.

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?

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.

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

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

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.

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?

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.

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

Convinced.

... 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.

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?

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?

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.

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.

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.

@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:

  • using System.IO; = import io
  • using Bar = Namespace.Bar; = from Namespace import Bar (as Bar)

@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.

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.

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]

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.

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.

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.

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.

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!)

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.)

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?

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. =)

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?

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.

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?

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.

    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.

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.

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

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. :-)

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?)

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.

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.

Was this page helpful?
0 / 5 - 0 ratings