diff --git a/.github/workflows/bouncer.yml b/.github/workflows/bouncer.yml index 55a8bf884..aa1d350fc 100644 --- a/.github/workflows/bouncer.yml +++ b/.github/workflows/bouncer.yml @@ -67,7 +67,10 @@ jobs: 'ecosystem/api/toncenter/v3.yaml', 'ecosystem/api/toncenter/smc-index.json', 'tvm/instructions.mdx', - ].includes(f.filename) && !f.filename.endsWith('.py') && !f.filename.startsWith('snippets'), + ].includes(f.filename) && + !f.filename.endsWith('.py') && + !f.filename.startsWith('snippets') && + !f.filename.startsWith('resources/syntaxes/'), ); const additions = filtered.reduce((acc, it) => acc + it.additions, 0); if (additions > maxAdditions) { @@ -155,7 +158,7 @@ jobs: script: | const maxIssuesAllowed = Number(process.env.MAX_ISSUES_PER_PR ?? '3'); const body = context.payload.pull_request.body || ''; - const closePatterns = /\b(?:close[sd]?|fixes|fixed|resolve[sd]?|towards)\s+(?:https?:\/\/github\.com\/|[a-z0-9\-\_\/]*#\d+)/gi; + const closePatterns = /\b(?:close[sd]?|fixes|fixed|fix|resolve[sd]?|towards)\s+(?:https?:\/\/github\.com\/|[a-z0-9\-\_\/]*#\d+)/gi; const issueCount = [...body.matchAll(closePatterns)].length; if (issueCount > maxIssuesAllowed) { core.setFailed(`This pull request attempts to close ${issueCount} issues, while the maximum number allowed is ${maxIssuesAllowed}.`); diff --git a/docs.json b/docs.json index efe98fa1a..863e9566b 100644 --- a/docs.json +++ b/docs.json @@ -24,7 +24,23 @@ "background": "/resources/logo/og-image-bg.svg" }, "styling": { - "eyebrows": "breadcrumbs" + "eyebrows": "breadcrumbs", + "codeblocks": { + "theme": { + "light": "github-light-default", + "dark": "dark-plus" + }, + "languages": { + "custom": [ + "/resources/syntaxes/tolk.tmLanguage.json", + "/resources/syntaxes/tlb.tmLanguage.json", + "/resources/syntaxes/fift.tmLanguage.json", + "/resources/syntaxes/tasm.tmLanguage.json", + "/resources/syntaxes/func.tmLanguage.json", + "/resources/syntaxes/tact.tmLanguage.json" + ] + } + } }, "contextual": { "options": [ diff --git a/extra.css b/extra.css index 9414b769c..a1c8fbe4c 100644 --- a/extra.css +++ b/extra.css @@ -75,57 +75,3 @@ table { div[data-component-part="callout-content"]>.code-block:last-child { margin-bottom: 0; } - -/* - A temporary solution syntax highlighting of Tolk snippets: invoke Prism.js on a client-side. - See `snippets/tolk-highlight.jsx`. - @link https://github.com/ton-org/docs/issues/1473 - */ - -:root { - --tolk-token-comment: #808080; - --tolk-token-type-hint: #D500EC; - --tolk-token-keyword: #0000FF; - --tolk-token-struct: #007EA2; - --tolk-token-variable: #444444; - --tolk-token-attr-name: #808000; - --tolk-token-function: #A82D2D; - --tolk-token-number: #0B9000; - --tolk-token-string: #008000; - --tolk-token-string-bg: #FAF9EF; - --tolk-token-operator: #A0A000; - --tolk-token-punctuation: #808000; - --tolk-token-three-dots: #999999; -} - -code.language-tolk { color: var(--tolk-token-variable); } -.token.comment { color: var(--tolk-token-comment); font-style: italic; } -.token.type-hint { color: var(--tolk-token-type-hint); } -.token.boolean { color: var(--tolk-token-keyword); } -.token.keyword { color: var(--tolk-token-keyword); } -.token.self { color: var(--tolk-token-variable); font-weight: bold; } -.token.attr-name { color: var(--tolk-token-attr-name); } -.token.function { color: var(--tolk-token-function); } -.token.number { color: var(--tolk-token-number); } -.token.string { color: var(--tolk-token-string); background-color: var(--tolk-token-string-bg); } -.token.operator { color: var(--tolk-token-operator); } -.token.punctuation { color: var(--tolk-token-punctuation); } -.token.three-dots { color: var(--tolk-token-three-dots); } -.token.struct { color: var(--tolk-token-struct); } -.token.variable { color: var(--tolk-token-variable); } - -html.dark { - --tolk-token-comment: #808080; - --tolk-token-type-hint: #DF90F8; - --tolk-token-keyword: #D75F02; - --tolk-token-struct: #56C1FF; - --tolk-token-variable: #C5D2E0; - --tolk-token-attr-name: #808000; - --tolk-token-function: #F9B900; - --tolk-token-number: #33A033; - --tolk-token-string: #33A033; - --tolk-token-string-bg: #1B1C1E; - --tolk-token-operator: #A0A000; - --tolk-token-punctuation: #85B2A0; - --tolk-token-three-dots: #777777; -} diff --git a/extra.js b/extra.js index 8c7a19e45..0d08e578a 100644 --- a/extra.js +++ b/extra.js @@ -1,118 +1 @@ /* See: https://mintlify.com/docs/settings/custom-scripts#custom-javascript */ -/* - A temporary solution syntax highlighting of Tolk snippets: invoke Prism.js on a client-side. - Sources of Prism.js are embedded right here, it's not downloaded separately. - @link https://github.com/ton-org/docs/issues/1473 - - All code blocks for the Tolk language are highlighted: - ```tolk - // automatically highlighted: see isTolkBlockCode() - ``` - - Visual appearance is defined in `extra.css`. - */ - -(function() { - const TOLK_GRAMMAR = { - 'comment': [ - { pattern: /\/\/.*/, greedy: true }, - // http://stackoverflow.com/questions/13014947/regex-to-match-a-c-style-multiline-comment/36328890#36328890 - { pattern: /\/\*[^*]*\*+([^/*][^*]*\*+)*\//, greedy: true }, - ], - 'attr-name': /@[a-zA-Z0-9_]+/, - 'keyword': /\b(do|if|as|is|try|else|while|break|throw|catch|return|assert|repeat|continue|asm|builtin|import|export|true|false|null|redef|mutate|tolk|global|const|var|val|fun|get\sfun|struct|match|type|lazy|enum|private|readonly)\b/, - 'function': /[a-zA-Z$_][a-zA-Z0-9$_]*(?=(<[^>]+>)*\()/, - 'type-hint': /\b(int|cell|void|never|bool|slice|tuple|builder|continuation|coins|int\d+|uint\d+|bytes\d+|bits\d+|address|any_address|map|dict)\b/, - 'boolean': /\b(false|true|null)\b/, - 'self': /\b(self)\b/, - 'number': /\b(-?\d+|0x[\da-fA-F]+|0b[01]+)\b/, - 'string': [ - { pattern: /"""[\s\S]*?"""/, greedy: true }, - { pattern: /"[^\n"]*"\w?/, greedy: true }, - ], - 'operator': new RegExp("\\+|-|\\*|/|%|\\?|:|=|<|>|!|&|\\||\\^|==|!=|<=|>=|<<|>>|&&|\\|\\||~/|\\^/|\\+=|-=|\\*=|/=|%=|&=|\\|=|\\^=|->|<=>|~>>|\\^>>|<<=|>>=|=>"), - 'three-dots': /\.\.\./, - 'punctuation': /[.,;(){}\[\]]/, - 'struct': /\b[A-Z][a-z][a-zA-Z0-9$_]*\b/, - 'variable': [ - { pattern: /`[^`]+`/ }, - { pattern: /\b[a-zA-Z$_][a-zA-Z0-9$_]*\b/ }, - ], - }; - - // code blocks inserted with ```tolk are rendered as actually, - // because Mintlify knows nothing about custom languages; - // here we try to detect whether it's not func/fift/tlb - function isTolkBlockCode(/**HTMLElement*/ codeElement) { - if (codeElement.getAttribute('language') !== 'text') { - return false; - } - - // highlight all snippets inside the "Tolk" left menu sections - // (even small ones, like `var x = 123`; they cannot be distinguished from FunC, - // but on "Tolk" pages, no other languages are present) - const isTolkPage = window.location.href.includes('/languages/tolk'); - if (isTolkPage) { - return true; - } - - // highlight if markdown has a title: ```tolk title="filename.tolk" - const hasTitleFilenameTolk = codeElement - .closest('div.code-block') - ?.querySelector('div[data-component-part="code-block-header-filename"]') - ?.innerText - ?.toLowerCase() - ?.endsWith('tolk'); - if (hasTitleFilenameTolk) { - return true; - } - - // try to detect the language based on innerText; - // treat the occurrence of fun/struct/enum/etc. as Tolk; - // it works without false positives for quite big, "real-world", meaningful snippets; - // it does not work for small snippets like `var x = 123` or `if (x != 0) {}` - const innerText = codeElement.innerText; - return /\b(fun\s\w+|struct\s\w+|struct\s*\([0-9a-fx]{4,}|enum\s\w+|lazy\s\w+)\b/.test(innerText); - } - - // check if Prism was called for - function isCodeHighlighted(/**HTMLElement*/ codeElement) { - return codeElement.classList.contains('language-tolk'); - } - - // call Prism for - function highlightCode(/**HTMLElement*/ codeElement, Prism) { - codeElement.classList.add('language-tolk'); - codeElement.parentElement.style.backgroundColor = ''; // parent is
-    codeElement.parentElement.classList.remove('shiki'); // avoid css mixing
-    try {
-      Prism.highlightElement(codeElement);
-    } catch (ex) {
-      console.error('suppressed Prism error for code', codeElement, ex);
-    }
-  }
-
-  function highlightAllCodeElementsOnPage(Prism) {
-    let allCodes = document.querySelectorAll('code');
-    for (let i = 0; i < allCodes.length; ++i) {
-      if (isTolkBlockCode(allCodes[i]) && !isCodeHighlighted(allCodes[i])) {
-        highlightCode(allCodes[i], Prism)
-      }
-    }
-
-    // call it iteratively in case of dynamic content changes
-    setTimeout(function() {
-      highlightAllCodeElementsOnPage(Prism)
-    }, 500);
-  }
-
-  if (typeof window !== "undefined") {
-    /* PrismJS 1.30.0 */
-    var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(e){var n=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,r={},a={manual:e.Prism&&e.Prism.manual,disableWorkerMessageHandler:e.Prism&&e.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof i?new i(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,"&").replace(/=g.reach);A+=w.value.length,w=w.next){var P=w.value;if(n.length>e.length)return;if(!(P instanceof i)){var E,S=1;if(y){if(!(E=l(b,A,e,m))||E.index>=e.length)break;var L=E.index,O=E.index+E[0].length,C=A;for(C+=w.value.length;L>=C;)C+=(w=w.next).value.length;if(A=C-=w.value.length,w.value instanceof i)continue;for(var j=w;j!==n.tail&&(Cg.reach&&(g.reach=W);var I=w.prev;if(_&&(I=u(n,I,_),A+=_.length),c(n,I,S),w=u(n,I,new i(f,p?a.tokenize(N,p):N,k,N)),M&&u(n,w,M),S>1){var T={cause:f+","+d,reach:W};o(e,n,t,w.prev,A,T),g&&T.reach>g.reach&&(g.reach=T.reach)}}}}}}function s(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function u(e,n,t){var r=n.next,a={value:t,prev:n,next:r};return n.next=a,r.prev=a,e.length++,a}function c(e,n,t){for(var r=n.next,a=0;a"+i.content+""},!e.document)return e.addEventListener?(a.disableWorkerMessageHandler||e.addEventListener("message",(function(n){var t=JSON.parse(n.data),r=t.language,i=t.code,l=t.immediateClose;e.postMessage(a.highlight(i,a.languages[r],r)),l&&e.close()}),!1),a):a;var g=a.util.currentScript();function f(){a.manual||a.highlightAll()}if(g&&(a.filename=g.src,g.hasAttribute("data-manual")&&(a.manual=!0)),!a.manual){var h=document.readyState;"loading"===h||"interactive"===h&&g&&g.defer?document.addEventListener("DOMContentLoaded",f):window.requestAnimationFrame?window.requestAnimationFrame(f):window.setTimeout(f,16)}return a}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism);
-    Prism.languages.tolk = TOLK_GRAMMAR;
-
-    setTimeout(function() {
-      highlightAllCodeElementsOnPage(Prism);
-    }, 0);
-  }
-})();
diff --git a/resources/syntaxes/fift.tmLanguage.json b/resources/syntaxes/fift.tmLanguage.json
new file mode 100644
index 000000000..6cbe6ecbb
--- /dev/null
+++ b/resources/syntaxes/fift.tmLanguage.json
@@ -0,0 +1,145 @@
+{
+    "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
+    "name": "fift",
+    "scopeName": "source.fift",
+    "fileTypes": ["fif"],
+    "patterns": [
+        {
+            "include": "#comments"
+        },
+        {
+            "include": "#strings"
+        },
+        {
+            "include": "#numbers"
+        },
+        {
+            "include": "#stack_words"
+        },
+        {
+            "include": "#program_words"
+        },
+        {
+            "include": "#control_words"
+        },
+        {
+            "include": "#literals"
+        },
+        {
+            "include": "#commands"
+        }
+    ],
+    "repository": {
+        "comments": {
+            "patterns": [
+                {
+                    "match": "//.*$",
+                    "name": "comment.line.double-slash.fift"
+                }
+            ]
+        },
+        "strings": {
+            "patterns": [
+                {
+                    "begin": "\"",
+                    "end": "\"",
+                    "name": "string.quoted.double.fift",
+                    "patterns": [
+                        {
+                            "match": "\\\\.",
+                            "name": "constant.character.escape.fift"
+                        }
+                    ]
+                },
+                {
+                    "match": "abort\"[^\"]*\"",
+                    "name": "string.quoted.double.abort.fift"
+                },
+                {
+                    "match": "\\.\"[^\"]*\"",
+                    "name": "string.quoted.double.print.fift"
+                }
+            ]
+        },
+        "numbers": {
+            "patterns": [
+                {
+                    "match": "\\b-?[0-9]+(/-?[0-9]+)?\\b",
+                    "name": "constant.numeric.decimal.fift"
+                },
+                {
+                    "match": "\\b0x[0-9a-fA-F]+\\b",
+                    "name": "constant.numeric.hex.fift"
+                },
+                {
+                    "match": "\\b0b[01]+\\b",
+                    "name": "constant.numeric.binary.fift"
+                }
+            ]
+        },
+        "stack_words": {
+            "patterns": [
+                {
+                    "match": "\\b(dup|drop|swap|rot|-rot|over|tuck|nip|2dup|2drop|2swap|pick|roll|-roll|exch|exch2|\\?dup)\\b",
+                    "name": "keyword.operator.stack.fift"
+                }
+            ]
+        },
+        "program_words": {
+            "patterns": [
+                {
+                    "match": "\\b(PROGRAM|END>c|PROC|PROCINLINE|DECLPROC|DECLMETHOD)\\b",
+                    "name": "keyword.control.program.fift"
+                },
+                {
+                    "match": "\\b(CALLDICT|INLINECALLDICT)\\b",
+                    "name": "keyword.control.call.fift"
+                }
+            ]
+        },
+        "control_words": {
+            "patterns": [
+                {
+                    "match": "\\b(if|ifnot|cond|until|while|times)\\b",
+                    "name": "keyword.control.flow.fift"
+                },
+                {
+                    "match": "\\b(include)\\b",
+                    "name": "keyword.control.import.fift"
+                }
+            ]
+        },
+        "literals": {
+            "patterns": [
+                {
+                    "match": "\\b(true|false)\\b",
+                    "name": "constant.language.boolean.fift"
+                },
+                {
+                    "match": "b\\{[01]+\\}",
+                    "name": "constant.other.binary-slice.fift"
+                },
+                {
+                    "match": "x\\{[0-9a-fA-F_]+\\}",
+                    "name": "constant.other.hex-slice.fift"
+                },
+                {
+                    "match": "B\\{[0-9a-fA-F_]+\\}",
+                    "name": "constant.other.hex-bytes.fift"
+                },
+                {
+                    "match": "char .",
+                    "name": "constant.character.fift"
+                }
+            ]
+        },
+        "commands": {
+            "patterns": [
+                {
+                    "match": "\\b[A-Z][A-Z0-9_]*\\b",
+                    "name": "keyword.other.command.fift"
+                }
+            ]
+        }
+    }
+}
diff --git a/resources/syntaxes/func.tmLanguage.json b/resources/syntaxes/func.tmLanguage.json
new file mode 100644
index 000000000..d805d0530
--- /dev/null
+++ b/resources/syntaxes/func.tmLanguage.json
@@ -0,0 +1,192 @@
+{
+    "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
+    "name": "func",
+    "scopeName": "source.func",
+    "fileTypes": ["fc", "func"],
+    "patterns": [
+        {
+            "include": "#comments"
+        },
+        {
+            "include": "#strings"
+        },
+        {
+            "include": "#numbers"
+        },
+        {
+            "include": "#directives"
+        },
+        {
+            "include": "#keywords"
+        },
+        {
+            "include": "#types"
+        },
+        {
+            "include": "#specifiers"
+        },
+        {
+            "include": "#operators"
+        },
+        {
+            "include": "#function-calls"
+        },
+        {
+            "include": "#punctuation"
+        },
+        {
+            "include": "#identifiers"
+        }
+    ],
+    "repository": {
+        "comments": {
+            "patterns": [
+                {
+                    "name": "comment.line.double-semicolon.func",
+                    "match": ";;.*$"
+                },
+                {
+                    "name": "comment.block.func",
+                    "begin": "\\{-",
+                    "end": "-\\}",
+                    "patterns": [
+                        {
+                            "include": "#comments"
+                        }
+                    ]
+                }
+            ]
+        },
+        "strings": {
+            "patterns": [
+                {
+                    "name": "string.quoted.double.func",
+                    "match": "\"(?:[^\\\"\\\\]|\\\\.)*\"[Hhcu]?"
+                }
+            ]
+        },
+        "numbers": {
+            "patterns": [
+                {
+                    "name": "constant.numeric.hex.func",
+                    "match": "(?=|<=>|<<=|>>=|~>>=|\\^>>=|<<|>>|~>>|\\^>>|->|=|\\+=|-=|\\*=|\\/=|~\\/=|\\^\\/=|%|~%=|\\^%|&|\\|\\||~|\\^|\\?|\\.)"
+                }
+            ]
+        },
+        "function-calls": {
+            "patterns": [
+                {
+                    "name": "meta.function-call.builtin.func",
+                    "match": "(?x)\\b(?:throw_unless|equal_slices|send_raw_message|accept_message)\\b(?=\\s*\\()",
+                    "captures": {
+                        "0": {
+                            "name": "support.function.builtin.func"
+                        }
+                    }
+                },
+                {
+                    "name": "meta.function-call.method.func",
+                    "begin": "(?<=\\.|~)\\s*(`[^`]+`|[A-Za-z_\\$][^\\s+\\-*\\/%,.;(){}\\[\\]=<>|\\^~]*)\\s*(?=\\()",
+                    "beginCaptures": {
+                        "1": {
+                            "name": "support.function.method.func"
+                        }
+                    },
+                    "end": "(?=)",
+                    "patterns": []
+                },
+                {
+                    "name": "meta.function-call.func",
+                    "begin": "(?x)(?|\\^~]*)\\s*(?=\\()",
+                    "beginCaptures": {
+                        "1": {
+                            "name": "support.function.call.func"
+                        }
+                    },
+                    "end": "(?=)",
+                    "patterns": []
+                }
+            ]
+        },
+        "punctuation": {
+            "patterns": [
+                {
+                    "name": "punctuation.brackets.func",
+                    "match": "[()\\[\\]{}]"
+                },
+                {
+                    "name": "punctuation.separator.func",
+                    "match": "[,:;]"
+                }
+            ]
+        },
+        "identifiers": {
+            "patterns": [
+                {
+                    "name": "entity.name.function.definition.func",
+                    "match": "(?x)(?<=^|[;{]\\s*)(`[^`]+`|[A-Za-z_\\$][^\\s+\\-*\\/%,.;(){}\\[\\]=<>|\\^~]*)\\s*(?=\\()"
+                },
+                {
+                    "name": "variable.other.func",
+                    "match": "`[^`]+`|[A-Za-z_\\$][^\\s+\\-*\\/%,.;(){}\\[\\]=<>|\\^~]*"
+                }
+            ]
+        }
+    }
+}
diff --git a/resources/syntaxes/tact.tmLanguage.json b/resources/syntaxes/tact.tmLanguage.json
new file mode 100644
index 000000000..1f83feab7
--- /dev/null
+++ b/resources/syntaxes/tact.tmLanguage.json
@@ -0,0 +1,617 @@
+{
+  "name": "tact",
+  "scopeName": "source.tact",
+  "fileTypes": [
+    "tact"
+  ],
+  "patterns": [
+    {
+      "include": "#comment"
+    },
+    {
+      "include": "#annotation"
+    },
+    {
+      "include": "#literal"
+    },
+    {
+      "include": "#invalid"
+    },
+    {
+      "include": "#constant"
+    },
+    {
+      "include": "#type"
+    },
+    {
+      "include": "#expression"
+    },
+    {
+      "include": "#punctuation"
+    },
+    {
+      "include": "#keyword"
+    },
+    {
+      "include": "#function"
+    },
+    {
+      "include": "#variable"
+    }
+  ],
+  "repository": {
+    "comment": {
+      "patterns": [
+        {
+          "name": "comment.line.double-slash.tact",
+          "begin": "//",
+          "beginCaptures": {
+            "0": {
+              "name": "punctuation.definition.comment.line.double-slash.tact"
+            }
+          },
+          "patterns": [
+            {
+              "include": "#todo"
+            }
+          ],
+          "end": "$"
+        },
+        {
+          "name": "comment.block.tact",
+          "begin": "\\s*/\\*",
+          "beginCaptures": {
+            "0": {
+              "name": "comment.block.begin.tact punctuation.definition.comment.begin.tact"
+            }
+          },
+          "patterns": [
+            {
+              "include": "#todo"
+            }
+          ],
+          "end": "\\*/",
+          "endCaptures": {
+            "0": {
+              "name": "comment.block.end.tact punctuation.definition.comment.end.tact"
+            }
+          }
+        }
+      ]
+    },
+
+    "todo": {
+      "match": "\\b(FIXME|TODO|CHANGED|XXX|IDEA|HACK|NOTE|REVIEW|NB|BUG)\\b",
+      "name": "keyword.comment.todo.tact"
+    },
+
+    "annotation": {
+      "patterns": [
+        {
+          "comment": "@name() in native functions",
+          "begin": "^\\s*(@name)\\s*(\\()",
+          "beginCaptures": {
+            "1": {
+              "name": "entity.other.attribute-name.tact"
+            },
+            "2": {
+              "name": "punctuation.brackets.round.tact"
+            }
+          },
+          "patterns": [
+            {
+              "comment": "FunC identifier",
+              "match": "(.*?)",
+              "name": "entity.name.function.func.tact"
+            }
+          ],
+          "end": "\\)",
+          "endCaptures": {
+            "0": {
+              "name": "punctuation.brackets.round.tact"
+            }
+          }
+        },
+        {
+          "comment": "One or more @interface() before traits and contracts",
+          "begin": "(?",
+              "name": "keyword.operator.mapsto.tact"
+            },
+            {
+              "comment": "Decimal integer WITH leading zero",
+              "match": "\\b(0[0-9]*)\\b",
+              "name": "constant.numeric.decimal.tact"
+            },
+            {
+              "comment": "Decimal integer WITHOUT leading zero",
+              "match": "\\b([1-9](?:_?[0-9])*)\\b",
+              "name": "constant.numeric.decimal.tact"
+            }
+          ],
+          "end": "\\)",
+          "endCaptures": {
+            "0": {
+              "name": "punctuation.brackets.round.tact"
+            }
+          }
+        },
+        {
+          "comment": "Fallback match",
+          "match": "(?",
+            "begin": "(?",
+            "endCaptures": {
+              "0": {
+                "name": "punctuation.brackets.angle.tact"
+              }
+            }
+          },
+          {
+            "comment": "map or set",
+            "begin": "(?",
+            "endCaptures": {
+              "0": {
+                "name": "punctuation.brackets.angle.tact"
+              }
+            }
+          },
+          {
+            "include": "#as-tlb"
+          }
+        ]
+      },
+
+      "simple-type": {
+        "comment": "Simple types",
+        "match": "(?>)(?!=)",
+            "name": "keyword.operator.bitwise.tact"
+          },
+          {
+            "comment": "Augmented assignment operators",
+            "match": "(\\+=|-=|\\*=|/=|%=|\\^=|&=|\\|=|\\|\\|=|&&=|<<=|>>=)",
+            "name": "keyword.operator.assignment.tact"
+          },
+          {
+            "comment": "Assignment operator",
+            "match": "(?])=(?!=)",
+            "name": "keyword.operator.assignment.equal.tact"
+          },
+          {
+            "comment": "Comparison operators",
+            "match": "([!=]=|<=?|>=?)",
+            "name": "keyword.operator.comparison.tact"
+          },
+          {
+            "comment": "Arithmetic operators",
+            "match": "([+%*\\-])|(/(?!/))",
+            "name": "keyword.operator.arithmetic.tact"
+          },
+          {
+            "comment": "initOf expression",
+            "match": "\\b(initOf)\\b",
+            "name": "keyword.operator.new.tact"
+          },
+          {
+            "comment": "codeOf expression",
+            "match": "\\b(codeOf)\\b",
+            "name": "keyword.operator.new.tact"
+          },
+          {
+            "comment": "Ternary expression",
+            "begin": "(?!\\?\\.\\s*[^[:digit:]])(\\?)(?!\\?)",
+            "beginCaptures": {
+              "1": {
+                "name": "keyword.operator.ternary.tact"
+              }
+            },
+            "patterns": [
+              {
+                "include": "$self"
+              }
+            ],
+            "end": "\\s*(:)",
+            "endCaptures": {
+              "1": {
+                "name": "keyword.operator.ternary.tact"
+              }
+            }
+          }
+        ]
+      },
+
+      "punctuation": {
+        "patterns": [
+          {
+            "match": ",",
+            "name": "punctuation.comma.tact"
+          },
+          {
+            "match": "[{}]",
+            "name": "punctuation.brackets.curly.tact"
+          },
+          {
+            "match": "[()]",
+            "name": "punctuation.brackets.round.tact"
+          },
+          {
+            "match": ";",
+            "name": "punctuation.semi.tact"
+          },
+          {
+            "match": ":",
+            "name": "punctuation.colon.tact"
+          },
+          {
+            "match": "\\.",
+            "name": "punctuation.dot.tact"
+          }
+        ]
+      },
+
+      "keyword": {
+        "patterns": [
+          {
+            "match": "(?",
+                    "match": "=>",
+                    "name": "keyword.operator.mapsto.tasm"
+                },
+                {
+                    "include": "#literal"
+                },
+                {
+                    "include": "#code_block"
+                },
+                {
+                    "include": "#punctuation"
+                }
+            ]
+        },
+        "punctuation": {
+            "patterns": [
+                {
+                    "match": ",",
+                    "name": "punctuation.comma.tasm"
+                },
+                {
+                    "match": ";",
+                    "name": "punctuation.semi.tasm"
+                },
+                {
+                    "match": ":",
+                    "name": "punctuation.colon.tasm"
+                }
+            ]
+        }
+    }
+}
diff --git a/resources/syntaxes/tlb.tmLanguage.json b/resources/syntaxes/tlb.tmLanguage.json
new file mode 100644
index 000000000..836cd9746
--- /dev/null
+++ b/resources/syntaxes/tlb.tmLanguage.json
@@ -0,0 +1,262 @@
+{
+    "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
+    "name": "tlb",
+    "scopeName": "source.tlb",
+    "fileTypes": ["tlb"],
+    "patterns": [
+        {
+            "include": "#comment"
+        },
+        {
+            "include": "#constructors"
+        },
+        {
+            "include": "#typeDefinitions"
+        },
+        {
+            "include": "#typeParameters"
+        },
+        {
+            "include": "#fields"
+        },
+        {
+            "include": "#hashExpressions"
+        },
+        {
+            "include": "#operators"
+        },
+        {
+            "include": "#primitiveTypes"
+        },
+        {
+            "include": "#arrays"
+        },
+        {
+            "include": "#numbers"
+        },
+        {
+            "include": "#declarations"
+        }
+    ],
+    "repository": {
+        "comment": {
+            "patterns": [
+                {
+                    "name": "comment.line.double-slash.tlb",
+                    "begin": "//",
+                    "beginCaptures": {
+                        "0": {
+                            "name": "punctuation.definition.comment.line.double-slash.tlb"
+                        }
+                    },
+                    "end": "$"
+                },
+                {
+                    "name": "comment.block.tlb",
+                    "begin": "\\s*/\\*",
+                    "beginCaptures": {
+                        "0": {
+                            "name": "comment.block.begin.tlb punctuation.definition.comment.begin.tlb"
+                        }
+                    },
+                    "end": "\\*/",
+                    "endCaptures": {
+                        "0": {
+                            "name": "comment.block.end.tlb punctuation.definition.comment.end.tlb"
+                        }
+                    }
+                }
+            ]
+        },
+        "constructors": {
+            "patterns": [
+                {
+                    "match": "([a-zA-Z_][a-zA-Z0-9_]*)\\s*(\\$[01_]+|#[0-9a-fA-F_]*)",
+                    "captures": {
+                        "1": {
+                            "name": "entity.name.type.constructor.tlb"
+                        },
+                        "2": {
+                            "name": "constant.numeric.constructor-tag.tlb"
+                        }
+                    }
+                }
+            ]
+        },
+        "typeParameters": {
+            "patterns": [
+                {
+                    "match": "\\{([A-Z][a-zA-Z0-9]*):Type\\}",
+                    "captures": {
+                        "1": {
+                            "name": "support.type.parameter.tlb"
+                        }
+                    }
+                },
+                {
+                    "match": "\\{([a-z][a-zA-Z0-9]*):([^}]+)\\}",
+                    "captures": {
+                        "1": {
+                            "name": "variable.parameter.tlb"
+                        },
+                        "2": {
+                            "name": "support.type.parameter.tlb"
+                        }
+                    }
+                }
+            ]
+        },
+        "fields": {
+            "patterns": [
+                {
+                    "match": "([a-zA-Z_][a-zA-Z0-9_]*)\\s*(:)",
+                    "captures": {
+                        "1": {
+                            "name": "variable.other.property.tlb"
+                        },
+                        "2": {
+                            "name": "keyword.operator.colon.tlb"
+                        }
+                    }
+                },
+                {
+                    "match": "\\^\\s*\\(([^)]+)\\)",
+                    "captures": {
+                        "1": {
+                            "patterns": [
+                                {
+                                    "include": "#expressions"
+                                }
+                            ]
+                        },
+                        "0": {
+                            "name": "keyword.operator.reference.tlb"
+                        }
+                    }
+                }
+            ]
+        },
+        "hashExpressions": {
+            "patterns": [
+                {
+                    "match": "(##)\\s*\\(([^)]+)\\)",
+                    "captures": {
+                        "1": {
+                            "name": "entity.name.function.macro.tlb"
+                        },
+                        "2": {
+                            "patterns": [
+                                {
+                                    "include": "#expressions"
+                                }
+                            ]
+                        }
+                    }
+                },
+                {
+                    "match": "(##|~)",
+                    "name": "entity.name.function.macro.tlb"
+                }
+            ]
+        },
+        "operators": {
+            "patterns": [
+                {
+                    "match": "(\\+|\\-|\\*|\\|<=|>=|!=|=|<|>|\\^|~|\\?)",
+                    "name": "keyword.operator.tlb"
+                }
+            ]
+        },
+        "primitiveTypes": {
+            "patterns": [
+                {
+                    "match": "\\b((u)?int\\d+|Type|Bit|Maybe)\\b",
+                    "name": "support.type.primitive.tlb"
+                }
+            ]
+        },
+        "arrays": {
+            "patterns": [
+                {
+                    "begin": "\\[",
+                    "end": "\\]",
+                    "patterns": [
+                        {
+                            "include": "#expressions"
+                        }
+                    ],
+                    "name": "meta.array.tlb"
+                }
+            ]
+        },
+        "numbers": {
+            "patterns": [
+                {
+                    "match": "\\b\\d+\\b",
+                    "name": "constant.numeric.decimal.tlb"
+                },
+                {
+                    "match": "\\b0x[0-9a-fA-F]+\\b",
+                    "name": "constant.numeric.hex.tlb"
+                }
+            ]
+        },
+        "expressions": {
+            "patterns": [
+                {
+                    "include": "#hashExpressions"
+                },
+                {
+                    "include": "#operators"
+                },
+                {
+                    "include": "#primitiveTypes"
+                },
+                {
+                    "include": "#arrays"
+                },
+                {
+                    "include": "#numbers"
+                },
+                {
+                    "match": "\\b[a-zA-Z_][a-zA-Z0-9_]*\\b",
+                    "name": "variable.other.tlb"
+                }
+            ]
+        },
+        "typeDefinitions": {
+            "patterns": [
+                {
+                    "match": "=\\s*([A-Z][a-zA-Z0-9]*)(?:\\s+([a-zA-Z0-9_\\s]+))?\\s*(?:X)?\\s*;",
+                    "captures": {
+                        "1": {
+                            "name": "entity.name.class.tlb"
+                        },
+                        "2": {
+                            "patterns": [
+                                {
+                                    "include": "#expressions"
+                                }
+                            ]
+                        }
+                    }
+                }
+            ]
+        },
+        "declarations": {
+            "patterns": [
+                {
+                    "match": "([a-zA-Z_][a-zA-Z0-9_]*)#([0-9a-fA-F]+)",
+                    "captures": {
+                        "1": {
+                            "name": "entity.name.type.tlb"
+                        },
+                        "2": {
+                            "name": "constant.numeric.hex.tlb"
+                        }
+                    }
+                }
+            ]
+        }
+    }
+}
diff --git a/resources/syntaxes/tolk.tmLanguage.json b/resources/syntaxes/tolk.tmLanguage.json
new file mode 100644
index 000000000..dbf962fce
--- /dev/null
+++ b/resources/syntaxes/tolk.tmLanguage.json
@@ -0,0 +1,82 @@
+{
+    "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
+    "name": "tolk",
+    "scopeName": "source.tolk",
+    "foldingStartMarker": "\\{\\s*$",
+    "foldingStopMarker": "^\\s*\\}",
+    "fileTypes": ["tolk"],
+    "patterns": [
+        {
+            "name": "comment.line.double-slash",
+            "match": "//(.*)"
+        },
+        {
+            "name": "comment.block",
+            "begin": "/\\*",
+            "end": "\\*/"
+        },
+        {
+            "name": "string.quoted.triple",
+            "begin": "\"\"\"",
+            "end": "\"\"\"",
+            "patterns": [
+                {
+                    "name": "constant.character.escape",
+                    "match": "\\\\."
+                }
+            ]
+        },
+        {
+            "name": "string.quoted.double",
+            "begin": "\"",
+            "end": "\"",
+            "patterns": [
+                {
+                    "name": "constant.character.escape",
+                    "match": "\\\\."
+                }
+            ]
+        },
+        {
+            "name": "constant.numeric",
+            "match": "(-?([\\d]+|0x[\\da-fA-F]+|0b[01]+))\\b"
+        },
+        {
+            "name": "keyword.control",
+            "match": "\\b(do|if|try|else|while|break|throw|catch|return|assert|repeat|continue|asm|builtin|match|lazy)\\b"
+        },
+        {
+            "name": "keyword.operator",
+            "match": "\\+|-|\\*|/|%|\\?|:|,|;|\\(|\\)|\\[|\\]|{|}|=|<|>|!|&|\\||\\^|==|!=|<=|>=|<<|>>|&&|\\|\\||~/|\\^/|\\+=|-=|\\*=|/=|%=|&=|\\|=|\\^=|->|<=>|~>>|\\^>>|<<=|>>=|=>"
+        },
+        {
+            "name": "keyword.other",
+            "match": "\\b(import|export|private|readonly|true|false|null|redef|mutate|tolk|as|is|!is)\\b"
+        },
+        {
+            "name": "storage.type",
+            "match": "\\b(type|int|cell|void|bool|slice|tuple|builder|continuation|never|coins|int\\d+|uint\\d+)\\b"
+        },
+        {
+            "name": "storage.modifier",
+            "match": "\\b(global|const|var|val|fun|get|struct|enum|private|readonly)\\b"
+        },
+        {
+            "name": "entity.name.type",
+            "match": "@\\w+"
+        },
+        {
+            "name": "entity.name.function",
+            "match": "(`[^`]+`|[a-zA-Z$_][a-zA-Z0-9$_]*)(?=\\()"
+        },
+        {
+            "name": "variable.language",
+            "match": "\bself\b"
+        },
+        {
+            "name": "variable.name",
+            "match": "`[^`]+`|[a-zA-Z$_][a-zA-Z0-9$_]*"
+        }
+    ],
+    "repository": {}
+}