aboutsummaryrefslogtreecommitdiff
path: root/plugin
diff options
context:
space:
mode:
Diffstat (limited to 'plugin')
-rw-r--r--plugin/AGENTS/ARCH.md10
-rw-r--r--plugin/ThirdPartyNotices.md5
-rw-r--r--plugin/examples/highlighting.cps8
-rw-r--r--plugin/syntaxes/cie-pseudocode.tmLanguage.json63
-rw-r--r--plugin/test/highlighting.test.js38
5 files changed, 118 insertions, 6 deletions
diff --git a/plugin/AGENTS/ARCH.md b/plugin/AGENTS/ARCH.md
index a8986d1..31c5974 100644
--- a/plugin/AGENTS/ARCH.md
+++ b/plugin/AGENTS/ARCH.md
@@ -97,10 +97,12 @@ only a subset of its syntax:
- Highlighted builtins: LENGTH, MID, RIGHT, LEFT, LCASE, UCASE, ASC, CHR, IS_NUM,
NUM_TO_STR, STR_TO_NUM and EOF. The compiler's complete table is in
`lib/CodeGen/Builtins.h` and also includes MALLOC, FREE and REALLOC.
-- CASE, CLASS, CONSTANT, OVERLOAD/OPERATOR and #LIB are supported by the compiler
- but lack corresponding plugin language rules. SET, DATE and random-file
- operations remain unsupported by the compiler too. Extending editor support
- requires an explicit scope change.
+- Highlighting covers CASE/ENDCASE/OTHERWISE, CLASS/ENDCLASS/PUBLIC/PRIVATE,
+ CONSTANT, TEMPLATE, OVERLOAD/OPERATOR, EXTERN declarations, INCLUDE_OBJ, #LIB
+ and ellipses using C++ scopes. OVERLOAD borrows a declaration modifier, #LIB
+ borrows #pragma and INCLUDE_OBJ borrows #include. #LIB must occupy its own line.
+ These rules do not add indentation support for the corresponding constructs.
+ SET, DATE and random-file operations remain unsupported by the compiler.
Language defaults use real Tabs, display width 4, disabled indentation detection,
full automatic indentation, on-type formatting and native bracket pair colors.
diff --git a/plugin/ThirdPartyNotices.md b/plugin/ThirdPartyNotices.md
index 72c3190..581724f 100644
--- a/plugin/ThirdPartyNotices.md
+++ b/plugin/ThirdPartyNotices.md
@@ -3,7 +3,10 @@
Language configuration and comment/string grammar structures are adapted from
Microsoft VS Code’s built-in C++ extension. Exception keywords reuse its
`keyword.control.try.cpp`, `keyword.control.catch.cpp` and
-`keyword.control.throw.cpp` scopes; ENDTRY uses the TRY scope.
+`keyword.control.throw.cpp` scopes; ENDTRY uses the TRY scope. Selection, class,
+access, constant, template, operator and external-declaration highlighting also
+reuse C++ scopes. OVERLOAD borrows a declaration modifier, #LIB borrows #pragma
+and INCLUDE_OBJ borrows #include; ellipses use the C++ variadic scope.
https://github.com/microsoft/vscode/tree/main/extensions/cpp
diff --git a/plugin/examples/highlighting.cps b/plugin/examples/highlighting.cps
index 7b30bb7..b5deaee 100644
--- a/plugin/examples/highlighting.cps
+++ b/plugin/examples/highlighting.cps
@@ -6,6 +6,8 @@ TYPE Student
DECLARE Initial : CHAR
ENDTYPE
+CONSTANT Limit = 3
+
DECLARE Values : ARRAY[1:3] OF INTEGER
DECLARE Index : INTEGER
DECLARE Total : REAL
@@ -45,3 +47,9 @@ TRY
CATCH
OUTPUT "Caught an exception"
ENDTRY
+
+CASE OF Index
+ 1 : OUTPUT "First"
+ 2 TO Limit : OUTPUT "In range"
+ OTHERWISE : OUTPUT "Other"
+ENDCASE
diff --git a/plugin/syntaxes/cie-pseudocode.tmLanguage.json b/plugin/syntaxes/cie-pseudocode.tmLanguage.json
index 0ae08cc..d0830a8 100644
--- a/plugin/syntaxes/cie-pseudocode.tmLanguage.json
+++ b/plugin/syntaxes/cie-pseudocode.tmLanguage.json
@@ -9,6 +9,69 @@
"include": "#strings"
},
{
+ "match": "^\\s*(#)(LIB)\\s*$",
+ "captures": {
+ "1": {
+ "name": "punctuation.definition.directive.cpp"
+ },
+ "2": {
+ "name": "keyword.control.directive.pragma.cpp"
+ }
+ }
+ },
+ {
+ "match": "(?<!\\w)(?:CASE|ENDCASE)(?!\\w)",
+ "name": "keyword.control.switch.cpp"
+ },
+ {
+ "match": "(?<!\\w)(?:OTHERWISE)(?!\\w)",
+ "name": "keyword.control.default.cpp"
+ },
+ {
+ "match": "(?<!\\w)(?:CONSTANT)(?!\\w)",
+ "name": "storage.modifier.const.cpp"
+ },
+ {
+ "match": "(?<!\\w)(?:CLASS|ENDCLASS)(?!\\w)",
+ "name": "storage.type.class.cpp"
+ },
+ {
+ "match": "(?<!\\w)(?:PUBLIC)(?!\\w)",
+ "name": "storage.type.modifier.access.control.public.cpp"
+ },
+ {
+ "match": "(?<!\\w)(?:PRIVATE)(?!\\w)",
+ "name": "storage.type.modifier.access.control.private.cpp"
+ },
+ {
+ "match": "(?<!\\w)(?:TEMPLATE)(?!\\w)",
+ "name": "storage.type.template.cpp"
+ },
+ {
+ "match": "(?<!\\w)(?:OPERATOR)(?!\\w)",
+ "name": "keyword.other.operator.overload.cpp"
+ },
+ {
+ "match": "(?<!\\w)(?:OVERLOAD)(?!\\w)",
+ "name": "storage.modifier.cpp"
+ },
+ {
+ "match": "(?<!\\w)(?:EXTERN)(?!\\w)",
+ "name": "storage.modifier.specifier.extern.cpp"
+ },
+ {
+ "match": "(?<!\\w)(?:EXTERN_FUNCTION|EXTERN_PROCEDURE)(?!\\w)",
+ "name": "storage.modifier.cpp"
+ },
+ {
+ "match": "(?<!\\w)(?:INCLUDE_OBJ)(?!\\w)",
+ "name": "keyword.control.directive.include.cpp"
+ },
+ {
+ "match": "\\.\\.\\.",
+ "name": "punctuation.vararg-ellipses.cpp"
+ },
+ {
"match": "(?<!\\w)(?:TRY|ENDTRY)(?!\\w)",
"name": "keyword.control.try.cpp"
},
diff --git a/plugin/test/highlighting.test.js b/plugin/test/highlighting.test.js
index f7a67db..bfdf0a2 100644
--- a/plugin/test/highlighting.test.js
+++ b/plugin/test/highlighting.test.js
@@ -58,6 +58,42 @@ test('both assignment characters share the C++ assignment scope', () => {
assert.ok(!scopesAt('X - 1', '-').includes('keyword.operator.assignment.cpp'));
});
+test('supported keywords reuse C++ scopes without matching identifiers or quoted text', () => {
+ for (const [words, scope] of [
+ [['CASE', 'ENDCASE'], 'keyword.control.switch.cpp'],
+ [['OTHERWISE'], 'keyword.control.default.cpp'],
+ [['CONSTANT'], 'storage.modifier.const.cpp'],
+ [['CLASS', 'ENDCLASS'], 'storage.type.class.cpp'],
+ [['PUBLIC'], 'storage.type.modifier.access.control.public.cpp'],
+ [['PRIVATE'], 'storage.type.modifier.access.control.private.cpp'],
+ [['TEMPLATE'], 'storage.type.template.cpp'],
+ [['OPERATOR'], 'keyword.other.operator.overload.cpp'],
+ [['OVERLOAD', 'EXTERN_FUNCTION', 'EXTERN_PROCEDURE'], 'storage.modifier.cpp'],
+ [['EXTERN'], 'storage.modifier.specifier.extern.cpp'],
+ [['INCLUDE_OBJ'], 'keyword.control.directive.include.cpp']
+ ]) for (const word of words) {
+ assert.ok(scopesAt(word, word).includes(scope), word);
+ for (const text of [word.toLowerCase(), `${word}Value`, `_${word}`, `${word}_1`]) {
+ assert.ok(!scopesAt(text, text).includes(scope), text);
+ }
+ assert.ok(scopesAt(`// ${word}`, word).some(s => s.startsWith('comment.')));
+ assert.ok(scopesAt(`OUTPUT "${word}"`, word).some(s => s.startsWith('string.')));
+ }
+});
+
+test('library directives require their own line and ellipses use the C++ variadic scope', () => {
+ assert.ok(scopesAt('\t#LIB ', '#').includes('punctuation.definition.directive.cpp'));
+ assert.ok(scopesAt('\t#LIB ', 'LIB').includes('keyword.control.directive.pragma.cpp'));
+ for (const text of ['#lib', '#LIBRARY', '#LIB // comment', 'X #LIB', '// #LIB', 'OUTPUT "#LIB"']) {
+ assert.ok(!scopesAt(text, '#')
+ .includes('punctuation.definition.directive.cpp'), text);
+ }
+ for (const text of ['TEMPLATE <Types...>', 'EXTERN "C" EXTERN_PROCEDURE print(C_INT, ...)', 'CALL print(Values...)']) {
+ assert.ok(scopesAt(text, '...').includes('punctuation.vararg-ellipses.cpp'), text);
+ }
+ assert.ok(!scopesAt('Value.Field', '.').includes('punctuation.vararg-ellipses.cpp'));
+});
+
test('exception keywords reuse C++ scopes and ignore non-keyword occurrences', () => {
for (const [word, scope] of [
['TRY', 'keyword.control.try.cpp'],
@@ -82,7 +118,7 @@ test('comments, strings, lowercase and keyword prefixes cannot become keywords',
for (const text of ['c_int', 'C_INTValue', 'MyC_INT', 'C_TYPE_1']) {
assert.ok(!scopesAt(text, text).some(s => s.startsWith('storage.')), text);
}
- for (const text of ['if X then', 'IFValue <- 1', 'CASE OF X', 'CLASS Example']) {
+ for (const text of ['if X then', 'IFValue <- 1', 'SET OF X', 'DEFINE X', 'RANDOM']) {
assert.ok(!scopesAt(text, text.split(' ')[0]).some(
s => /^(keyword|storage)\./.test(s)), text);
}