From 34ddac45f361f96ae8ef95a0a9ee63cc3e27b18e Mon Sep 17 00:00:00 2001 From: Peter Judge Date: Sat, 27 Jun 2026 13:58:08 -0400 Subject: [PATCH] Improve scoping for INPUT statements, AS , variable definition, *-LOCK --- abl.tmLanguage.json | 63 +++++++++++++++---- spec/blocks/catch-blocks.spec.js | 50 +++++++++++++++ .../simple-single-line.spec.js | 19 ++++++ spec/for-each/for-each.spec.js | 45 +++++++++++++ spec/input-output/input-statements.spec.js | 51 +++++++++++++++ spec/misc-statements/if-then.spec.js | 2 +- spec/strings/strings.spec.js | 27 ++++++++ 7 files changed, 245 insertions(+), 12 deletions(-) create mode 100644 spec/blocks/catch-blocks.spec.js create mode 100644 spec/input-output/input-statements.spec.js create mode 100644 spec/strings/strings.spec.js diff --git a/abl.tmLanguage.json b/abl.tmLanguage.json index 0329700..eeb0bb7 100644 --- a/abl.tmLanguage.json +++ b/abl.tmLanguage.json @@ -317,6 +317,39 @@ } } }, + "input-statements": { + "comment": "INPUT CLEAR, INPUT CLOSE, INPUT FROM and INPUT THROUGH are statements, not functions", + "patterns": [ + { + "match": "\\s*([Ii][Nn][Pp][Uu][Tt])\\s+([Cc][Ll][Ee][Aa][Rr])\\b", + "captures": { + "1": { + "name": "keyword.other.ablt" + }, + "2": { + "name": "keyword.other.abl" + } + } + }, + { + "match": "(?i)\\b(input|output|input-output)\\s+((stream|stream-handle)\\s+([a-zA-Z_][a-zA-Z0-9_#$\\-%&]*)\\s+)?(close)", + "captures": { + "1": { + "name": "keyword.other.abl" + }, + "3": { + "name": "keyword.other.abl" + }, + "4": { + "name": "variable.other.abl" + }, + "5": { + "name": "keyword.other.abl" + } + } + } + ] + }, "as-type": { "begin": "\\s*([Aa][Ss])(\\s+([Cc][Ll][Aa][Ss]{2})\\s)?\\s*", "beginCaptures": { @@ -327,7 +360,7 @@ "name": "keyword.other.abl" } }, - "end": "(?=\\.|\\,|\\)|\\s)", + "end": "(?=\\.|\\,|\\)|\\s|:)", "patterns": [ { "include": "#primitive-type" @@ -461,6 +494,9 @@ "statements": { "name": "meta.statements.abl", "patterns": [ + { + "include": "#input-statements" + }, { "include": "#comment" }, @@ -495,7 +531,7 @@ "include": "#var-statement" }, { - "include": "#input-output-from-to" + "include": "#input-output-from-to-through" }, { "include": "#function-definition" @@ -1303,7 +1339,7 @@ }, "for-join": { "comment": "Captures something like ', salesrep where' or 'salesrep where', when the latter is at the beginning of a line. 'OF' phrases handled by of-phrase", - "match": "(?i)(?<=,|^)\\s*([a-zA-Z][a-zA-Z0-9_\\-#$%]*(\\.[a-zA-Z_][a-zA-Z0-9_\\-#$%]*)?)\\s+(?=where|no-lock|(exclusive-l(?:ock|oc|o)?)|(share(?:-lock|-loc|-lo|-l|-)?)|tenant-where|use-index|table-scan|using|(no-prefe(?:tch|tc|t)?)|left|outer-join|break|by|(transact(?:ion|io|i)?))\\s*", + "match": "(?i)(?<=,|^)\\s*([a-zA-Z][a-zA-Z0-9_\\-#$%]*(\\.[a-zA-Z_][a-zA-Z0-9_\\-#$%]*)?)\\s+(?=where|no-lock|(exclusive(?:-lock|-loc|-lo|-l)?)|(share(?:-lock|-loc|-lo|-l|-)?)|tenant-where|use-index|table-scan|using|(no-prefe(?:tch|tc|t)?)|left|outer-join|break|by|(transact(?:ion|io|i)?))\\s*", "captures": { "1": { "name": "storage.data.table.abl" @@ -1361,7 +1397,7 @@ "name": "keyword.other.abl" } }, - "end": "(?i)\\s*(?=where|no-lock|(exclusive-l(?:ock|oc|o)?)|(share(?:-lock|-loc|-lo|-l|-)?)|tenant-where|use-index|table-scan|using|(no-prefe(?:tch|tc|t)?)|left|outer-join|break|by|(transact(?:ion|io|i)?)|,|:|on)\\s*", + "end": "(?i)\\s*(?=where|no-lock|(exclusive(?:-lock|-loc|-lo|-l)?)|(share(?:-lock|-loc|-lo|-l|-)?)|tenant-where|use-index|table-scan|using|(no-prefe(?:tch|tc|t)?)|left|outer-join|break|by|(transact(?:ion|io|i)?)|,|:|on)\\s*", "patterns": [ { "match": "(?i)\\s*(each|first|last|of)\\s*", @@ -1649,8 +1685,8 @@ } ] }, - "input-output-from-to": { - "begin": "(?i)\\b(input|output)\\s+((stream|stream-handle)\\s+([a-zA-Z_][a-zA-Z0-9_#$\\-%&]*)\\s+)?(from|to)", + "input-output-from-to-through": { + "begin": "(?i)\\b(input|output)\\s+((stream|stream-handle)\\s+([a-zA-Z_][a-zA-Z0-9_#$\\-%&]*)\\s+)?(from|to|through)", "beginCaptures": { "1": { "name": "keyword.other.abl" @@ -2048,7 +2084,7 @@ } }, { - "match": "(?i)\\b((share(?:-lock|-loc|-lo|-l|-)?)|(exclusive-l(?:ock|oc|o)?)|no-lock|no-wait|(disp(?:lay|la|l)?))\\b", + "match": "(?i)\\b((share(?:-lock|-loc|-lo|-l)?)|(exclusive(?:-lock|-loc|-lo|-l)?)|no-lock|no-wait|(disp(?:lay|la|l)?))\\b", "captures": { "1": { "name": "keyword.other.abl" @@ -2578,7 +2614,7 @@ "name": "keyword.other.abl" } }, - "end": "(?i)(?=\\.)|\\b(?=(bgc(?:olor|olo|ol|o)?)|(column-lab(?:el|e)?)|context-help-id|dcolor|decimals|drop-target|extent|font|(fgc(?:olor|olo|ol|o)?)|(form(?:at|a)?)|(init(?:ial|ia|i)?)|label|(mouse-p(?:ointer|ointe|oint|oin|oi|o)?)|no-undo|not|(case-sen(?:sitive|sitiv|siti|sit|si|s)?)|(pfc(?:olor|olo|ol|o)?)|view-as|triggers)\\b", + "end": "(?i)(?=\\.)|\\b(?=((bgc(?:olor|olo|ol|o)?)|(column-lab(?:el|e)?)|context-help-id|dcolor|decimals|drop-target|extent|font|(fgc(?:olor|olo|ol|o)?)|(form(?:at|a)?)|(init(?:ial|ia|i)?)|label|(mouse-p(?:ointer|ointe|oint|oin|oi|o)?)|no-undo|not|(case-sen(?:sitive|sitiv|siti|sit|si|s)?)|(pfc(?:olor|olo|ol|o)?)|view-as|triggers)(?![#$\\-_%&]))\\b", "patterns": [ { "match": "\\b([Cc][Ll][Aa][Ss][Ss])\\b", @@ -2686,7 +2722,7 @@ "name": "meta.brace.round.abl" } }, - "end": "(?i)\\b(?=\\)|where|no-lock|(share(?:-lock|-loc|-lo|-l|-)?)|using|(no-prefe(?:tch|tc|t)?)|no-wait)\\s*", + "end": "(?i)\\b(?=\\)|where|no-lock|(share(?:-lock|-loc|-lo|-l)?)|using|(no-prefe(?:tch|tc|t)?)|no-wait)\\s*", "patterns": [ { "include": "#parens" @@ -2835,7 +2871,7 @@ } }, "block-label": { - "match": "(?i)^\\s*(?!((?:transact(?:ion|io|i)?)|no-lock|(?:exclusive-l(?:ock|oc|o)?)|(?:share(?:-lock|-loc|-lo|-l|-)?)):)([a-zA-Z][a-zA-Z0-9_\\-#$%\\-$#]*)(:)\\s", + "match": "(?i)^\\s*(?!((?:transact(?:ion|io|i)?)|no-lock|(?:exclusive(?:-lock|-loc|-lo|-l)?)|(?:share(?:-lock|-loc|-lo|-l)?)):)([a-zA-Z][a-zA-Z0-9_\\-#$%\\-$#]*)(:)\\s", "comment": "A colon followed by a space is only legal is for block labels. Block labels must also be at the beginning of a line. Scope name is per https://www.sublimetext.com/docs/scope_naming.html", "captures": { "2": { @@ -2916,7 +2952,12 @@ "name": "keyword.other.abl" } }, - "end": "(?=:)", + "end": "(:)", + "endCaptures": { + "1": { + "name": "punctuation.terminator.abl" + } + }, "patterns": [ { "include": "#as-type" diff --git a/spec/blocks/catch-blocks.spec.js b/spec/blocks/catch-blocks.spec.js new file mode 100644 index 0000000..15bdb9c --- /dev/null +++ b/spec/blocks/catch-blocks.spec.js @@ -0,0 +1,50 @@ +const { assert, expect } = require('chai'); +const shared = require('../shared.js'); + +describe('', () => { + let statement = `catch e as Progress.Lang.Error:`; + let expectedTokens = [ + { "startIndex": 0, "endIndex": 5, "scopes": ["source.abl", "keyword.other.abl"] }, // 'catch' + { "startIndex": 5, "endIndex": 6, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 6, "endIndex": 7, "scopes": ["source.abl", "variable.other.abl"] }, // 'e' + { "startIndex": 7, "endIndex": 8, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 8, "endIndex": 10, "scopes": ["source.abl", "keyword.other.abl"] }, // 'as' + { "startIndex": 10, "endIndex": 11, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 11, "endIndex": 30, "scopes": ["source.abl", "entity.name.type.abl"] }, // 'Progress.Lang.Error' + { "startIndex": 30, "endIndex": 31, "scopes": ["source.abl", "punctuation.terminator.abl"] } // ':' + ]; + shared.itShouldMatchExpectedScopes(statement, expectedTokens); +}) + +describe('', () => { + let statement = `catch e as Progress.Lang.Error : `; + let expectedTokens = [ + { "startIndex": 0, "endIndex": 5, "scopes": ["source.abl", "keyword.other.abl"] }, // 'catch' + { "startIndex": 5, "endIndex": 6, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 6, "endIndex": 7, "scopes": ["source.abl", "variable.other.abl"] }, // 'e' + { "startIndex": 7, "endIndex": 8, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 8, "endIndex": 10, "scopes": ["source.abl", "keyword.other.abl"] }, // 'as' + { "startIndex": 10, "endIndex": 11, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 11, "endIndex": 30, "scopes": ["source.abl", "entity.name.type.abl"] }, // 'Progress.Lang.Error' + { "startIndex": 30, "endIndex": 31, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 31, "endIndex": 32, "scopes": ["source.abl", "punctuation.terminator.abl"] }, // ':' + { "startIndex": 32, "endIndex": 34, "scopes": ["source.abl"] } // ' ' + ]; + shared.itShouldMatchExpectedScopes(statement, expectedTokens); +}) + +describe('', () => { + let statement = `catch eThing as ThingException: `; + let expectedTokens = [ + { "startIndex": 0, "endIndex": 5, "scopes": ["source.abl", "keyword.other.abl"] }, // 'catch' + { "startIndex": 5, "endIndex": 6, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 6, "endIndex": 12, "scopes": ["source.abl", "variable.other.abl"] }, // 'eThing' + { "startIndex": 12, "endIndex": 13, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 13, "endIndex": 15, "scopes": ["source.abl", "keyword.other.abl"] }, // 'as' + { "startIndex": 15, "endIndex": 16, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 16, "endIndex": 30, "scopes": ["source.abl", "entity.name.type.abl"] }, // 'ThingException' + { "startIndex": 30, "endIndex": 31, "scopes": ["source.abl", "punctuation.terminator.abl"] }, // ':' + { "startIndex": 31, "endIndex": 33, "scopes": ["source.abl"] } // ' ' + ]; + shared.itShouldMatchExpectedScopes(statement, expectedTokens); +}) diff --git a/spec/define-variable/simple-single-line.spec.js b/spec/define-variable/simple-single-line.spec.js index 57273db..ebbdd8d 100644 --- a/spec/define-variable/simple-single-line.spec.js +++ b/spec/define-variable/simple-single-line.spec.js @@ -179,3 +179,22 @@ describe('', () => { ]; shared.itShouldMatchExpectedScopes(statement, expectedTokens); }) + +describe('', () => { + let statement = `DEF VAR not-soft-qty AS DEC NO-UNDO.`; + let expectedTokens = [ + { "startIndex": 0, "endIndex": 3, "scopes": ["source.abl", "meta.define.abl", "keyword.other.abl"] }, // 'DEF' + { "startIndex": 3, "endIndex": 4, "scopes": ["source.abl", "meta.define.abl"] }, // ' ' + { "startIndex": 4, "endIndex": 7, "scopes": ["source.abl", "meta.define.abl", "keyword.other.abl"] }, // 'VAR' + { "startIndex": 7, "endIndex": 8, "scopes": ["source.abl", "meta.define.abl"] }, // ' ' + { "startIndex": 8, "endIndex": 20, "scopes": ["source.abl", "meta.define.abl", "variable.other.abl"] }, // 'not-soft-qty' + { "startIndex": 20, "endIndex": 25, "scopes": ["source.abl", "meta.define.abl"] }, // ' ' + { "startIndex": 25, "endIndex": 27, "scopes": ["source.abl", "meta.define.abl", "keyword.other.abl"] }, // 'AS' + { "startIndex": 27, "endIndex": 28, "scopes": ["source.abl", "meta.define.abl"] }, // ' ' + { "startIndex": 28, "endIndex": 31, "scopes": ["source.abl", "meta.define.abl", "storage.type.abl"] }, // 'DEC' + { "startIndex": 31, "endIndex": 32, "scopes": ["source.abl", "meta.define.abl"] }, // ' ' + { "startIndex": 32, "endIndex": 39, "scopes": ["source.abl", "meta.define.abl", "keyword.other.abl"] }, // 'NO-UNDO' + { "startIndex": 39, "endIndex": 40, "scopes": ["source.abl", "meta.define.abl", "punctuation.terminator.abl"] } // '.' + ]; + shared.itShouldMatchExpectedScopes(statement, expectedTokens); +}) diff --git a/spec/for-each/for-each.spec.js b/spec/for-each/for-each.spec.js index 8f57f2b..f73d0f1 100644 --- a/spec/for-each/for-each.spec.js +++ b/spec/for-each/for-each.spec.js @@ -212,3 +212,48 @@ describe('', () => { ]; shared.itShouldMatchExpectedScopes(statement, expectedTokens); }) + +describe('', () => { + let statement = `for each customer exclusive:`; + let expectedTokens = [ + { "startIndex": 0, "endIndex": 3, "scopes": ["source.abl", "keyword.other.abl"] }, // 'for' + { "startIndex": 3, "endIndex": 4, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 4, "endIndex": 8, "scopes": ["source.abl", "keyword.other.abl"] }, // 'each' + { "startIndex": 8, "endIndex": 9, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 9, "endIndex": 17, "scopes": ["source.abl", "storage.data.table.abl"] }, // 'customer' + { "startIndex": 17, "endIndex": 18, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 18, "endIndex": 27, "scopes": ["source.abl", "keyword.other.abl"] }, // 'exclusive' + { "startIndex": 27, "endIndex": 28, "scopes": ["source.abl", "punctuation.terminator.abl"] } // ':' + ]; + shared.itShouldMatchExpectedScopes(statement, expectedTokens); +}) + +describe('', () => { + let statement = `for each customer share:`; + let expectedTokens = [ + { "startIndex": 0, "endIndex": 3, "scopes": ["source.abl", "keyword.other.abl"] }, // 'for' + { "startIndex": 3, "endIndex": 4, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 4, "endIndex": 8, "scopes": ["source.abl", "keyword.other.abl"] }, // 'each' + { "startIndex": 8, "endIndex": 9, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 9, "endIndex": 17, "scopes": ["source.abl", "storage.data.table.abl"] }, // 'customer' + { "startIndex": 17, "endIndex": 18, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 18, "endIndex": 23, "scopes": ["source.abl", "keyword.other.abl"] }, // 'share' + { "startIndex": 23, "endIndex": 24, "scopes": ["source.abl", "punctuation.terminator.abl"] } // ':' + ]; + shared.itShouldMatchExpectedScopes(statement, expectedTokens); +}) + +describe('', () => { + let statement = `for each customer exclusive-lo:`; + let expectedTokens = [ + { "startIndex": 0, "endIndex": 3, "scopes": ["source.abl", "keyword.other.abl"] }, // 'for' + { "startIndex": 3, "endIndex": 4, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 4, "endIndex": 8, "scopes": ["source.abl", "keyword.other.abl"] }, // 'each' + { "startIndex": 8, "endIndex": 9, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 9, "endIndex": 17, "scopes": ["source.abl", "storage.data.table.abl"] }, // 'customer' + { "startIndex": 17, "endIndex": 18, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 18, "endIndex": 30, "scopes": ["source.abl", "keyword.other.abl"] }, // 'exclusive-lo' + { "startIndex": 30, "endIndex": 31, "scopes": ["source.abl", "punctuation.terminator.abl"] } // ':' + ]; + shared.itShouldMatchExpectedScopes(statement, expectedTokens); +}) diff --git a/spec/input-output/input-statements.spec.js b/spec/input-output/input-statements.spec.js new file mode 100644 index 0000000..e34448f --- /dev/null +++ b/spec/input-output/input-statements.spec.js @@ -0,0 +1,51 @@ +const { assert, expect } = require('chai'); +const shared = require('../shared.js'); + +describe('', () => { + let statement = + `INPUT-OUTPUT STREAM stream CLOSE.`; + + let expectedTokens = [ + { "startIndex": 0, "endIndex": 12, "scopes": ["source.abl", "keyword.other.abl"] }, // 'INPUT-OUTPUT' + { "startIndex": 12, "endIndex": 14, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 14, "endIndex": 20, "scopes": ["source.abl", "keyword.other.abl"] }, // 'STREAM' + { "startIndex": 20, "endIndex": 21, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 21, "endIndex": 27, "scopes": ["source.abl", "variable.other.abl"] }, // 'stream' + { "startIndex": 27, "endIndex": 28, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 28, "endIndex": 33, "scopes": ["source.abl", "keyword.other.abl"] }, // 'CLOSE' + { "startIndex": 33, "endIndex": 34, "scopes": ["source.abl", "punctuation.terminator.abl"] } // '.' + ]; + + shared.itShouldMatchExpectedScopes(statement, expectedTokens); +}) + +describe('', () => { + let statement = + `input close.`; + + let expectedTokens = [ + { "startIndex": 0, "endIndex": 5, "scopes": ["source.abl", "keyword.other.abl"] }, // 'input' + { "startIndex": 5, "endIndex": 6, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 6, "endIndex": 11, "scopes": ["source.abl", "keyword.other.abl"] }, // 'close' + { "startIndex": 11, "endIndex": 12, "scopes": ["source.abl", "punctuation.terminator.abl"] } // '.' + ]; + + shared.itShouldMatchExpectedScopes(statement, expectedTokens); +}) + +describe('', () => { + let statement = + `INPUT-OUTPUT STREAM-HANDLE handle CLOSE.`; + + let expectedTokens = [ + { "startIndex": 0, "endIndex": 12, "scopes": ["source.abl", "keyword.other.abl"] }, // 'INPUT-OUTPUT' + { "startIndex": 12, "endIndex": 13, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 13, "endIndex": 26, "scopes": ["source.abl", "keyword.other.abl"] }, // 'STREAM-HANDLE' + { "startIndex": 26, "endIndex": 27, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 27, "endIndex": 33, "scopes": ["source.abl", "variable.other.abl"] }, // 'handle' + { "startIndex": 33, "endIndex": 34, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 34, "endIndex": 39, "scopes": ["source.abl", "keyword.other.abl"] }, // 'CLOSE' + { "startIndex": 39, "endIndex": 40, "scopes": ["source.abl", "punctuation.terminator.abl"] } // '.' + ]; + shared.itShouldMatchExpectedScopes(statement, expectedTokens); +}) diff --git a/spec/misc-statements/if-then.spec.js b/spec/misc-statements/if-then.spec.js index bcd73a1..097e493 100644 --- a/spec/misc-statements/if-then.spec.js +++ b/spec/misc-statements/if-then.spec.js @@ -88,7 +88,7 @@ describe('', () => { { "startIndex": 20, "endIndex": 22, "scopes": ["source.abl", "keyword.other.abl"] }, // 'as' { "startIndex": 22, "endIndex": 23, "scopes": ["source.abl"] }, // ' ' { "startIndex": 23, "endIndex": 42, "scopes": ["source.abl", "entity.name.type.abl"] }, // 'Progress.Lang.Error' - { "startIndex": 42, "endIndex": 43, "scopes": ["source.abl"] } // ':' + { "startIndex": 42, "endIndex": 43, "scopes": ["source.abl", "punctuation.terminator.abl"] } // ':' ], [ { "startIndex": 0, "endIndex": 10, "scopes": ["source.abl"] }, // ' ' diff --git a/spec/strings/strings.spec.js b/spec/strings/strings.spec.js new file mode 100644 index 0000000..fbd09be --- /dev/null +++ b/spec/strings/strings.spec.js @@ -0,0 +1,27 @@ +const { assert, expect } = require('chai'); +const shared = require('../shared.js'); + +describe('', () => { + let statement = `substitute ("Unable to start Business Entity: &1"{&TRAN}, quoter (pcEntityName))`; + let expectedTokens = [ + { "startIndex": 0, "endIndex": 10, "scopes": ["source.abl", "support.function.abl"] }, // 'substitute' + { "startIndex": 10, "endIndex": 11, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 11, "endIndex": 12, "scopes": ["source.abl", "meta.brace.round.abl"] }, // '(' + { "startIndex": 12, "endIndex": 13, "scopes": ["source.abl", "string.quoted.double.abl", "punctuation.definition.string.begin.abl"] }, // '"' + { "startIndex": 13, "endIndex": 48, "scopes": ["source.abl", "string.quoted.double.abl"] }, // 'Unable to start Business Entity: &1' + { "startIndex": 48, "endIndex": 49, "scopes": ["source.abl", "string.quoted.double.abl", "punctuation.definition.string.end.abl"] }, // '"' + { "startIndex": 49, "endIndex": 50, "scopes": ["source.abl", "meta.preprocessor.abl", "punctuation.section.abl"] }, // '{' + { "startIndex": 50, "endIndex": 51, "scopes": ["source.abl", "meta.preprocessor.abl", "punctuation.definition.preprocessor.abl"] }, // '&' + { "startIndex": 51, "endIndex": 55, "scopes": ["source.abl", "meta.preprocessor.abl", "entity.name.function.preprocessor.abl"] }, // 'TRAN' + { "startIndex": 55, "endIndex": 56, "scopes": ["source.abl", "meta.preprocessor.abl", "punctuation.section.abl"] }, // '}' + { "startIndex": 56, "endIndex": 57, "scopes": ["source.abl", "punctuation.separator.comma.abl"] }, // ',' + { "startIndex": 57, "endIndex": 58, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 58, "endIndex": 64, "scopes": ["source.abl", "support.function.abl"] }, // 'quoter' + { "startIndex": 64, "endIndex": 65, "scopes": ["source.abl"] }, // ' ' + { "startIndex": 65, "endIndex": 66, "scopes": ["source.abl", "meta.brace.round.abl"] }, // '(' + { "startIndex": 66, "endIndex": 78, "scopes": ["source.abl", "variable.other.abl"] }, // 'pcEntityName' + { "startIndex": 78, "endIndex": 79, "scopes": ["source.abl", "meta.brace.round.abl"] }, // ')' + { "startIndex": 79, "endIndex": 80, "scopes": ["source.abl", "meta.brace.round.abl"] } // ')' + ]; + shared.itShouldMatchExpectedScopes(statement, expectedTokens); +}) \ No newline at end of file