|
| 1 | +// Arkade Language Definition for Monaco Editor |
| 2 | + |
| 3 | +// Monarch tokenizer definition (for setMonarchTokensProvider) |
| 4 | +const arkadeMonarch = { |
| 5 | + defaultToken: 'invalid', |
| 6 | + |
| 7 | + keywords: [ |
| 8 | + 'contract', 'function', 'tapscript', 'require', 'if', 'else', |
| 9 | + 'for', 'in', 'let', 'internal', 'new' |
| 10 | + ], |
| 11 | + |
| 12 | + typeKeywords: [ |
| 13 | + 'pubkey', 'signature', 'bytes32', 'bytes20', 'bytes', |
| 14 | + 'asset', 'int', 'bool' |
| 15 | + ], |
| 16 | + |
| 17 | + builtinFunctions: [ |
| 18 | + 'checkSig', 'checkMultisig', 'checkSigFromStack', 'checkSigFromStackVerify', |
| 19 | + 'sha256', 'sha256Initialize', 'sha256Update', 'sha256Finalize', |
| 20 | + 'neg64', 'le64ToScriptNum', 'le32ToLe64', 'ecMulScalarVerify', 'tweakVerify', |
| 21 | + 'older', 'after', 'tweak' |
| 22 | + ], |
| 23 | + |
| 24 | + operators: [ |
| 25 | + '>=', '<=', '==', '!=', '>', '<', '+', '-', '*', '/', '=' |
| 26 | + ], |
| 27 | + |
| 28 | + tokenizer: { |
| 29 | + root: [ |
| 30 | + // Comments |
| 31 | + [/\/\/.*$/, 'comment'], |
| 32 | + [/\/\*/, 'comment', '@comment'], |
| 33 | + |
| 34 | + // Whitespace |
| 35 | + [/\s+/, 'white'], |
| 36 | + |
| 37 | + // Keywords |
| 38 | + [/\b(contract|function|tapscript|require|if|else|for|in|let|internal|new)\b/, 'keyword'], |
| 39 | + |
| 40 | + // Types |
| 41 | + [/\b(pubkey|signature|bytes32|bytes20|bytes|asset|int|bool)\b/, 'type'], |
| 42 | + |
| 43 | + // Built-in functions |
| 44 | + [/\b(checkSig|checkMultisig|checkSigFromStack|checkSigFromStackVerify|sha256|sha256Initialize|sha256Update|sha256Finalize|neg64|le64ToScriptNum|le32ToLe64|ecMulScalarVerify|tweakVerify|older|after|tweak)\b/, 'predefined'], |
| 45 | + |
| 46 | + // Transaction/this keywords |
| 47 | + [/\b(tx|this)\b/, 'variable.predefined'], |
| 48 | + |
| 49 | + // P2TR constructor |
| 50 | + [/\bP2TR\b/, 'type'], |
| 51 | + |
| 52 | + // Numbers |
| 53 | + [/\b\d+\b/, 'number'], |
| 54 | + |
| 55 | + // Strings |
| 56 | + [/"[^"]*"/, 'string'], |
| 57 | + |
| 58 | + // Operators |
| 59 | + [/[>=<!=]+/, 'operator'], |
| 60 | + [/[+\-*/]/, 'operator'], |
| 61 | + |
| 62 | + // Delimiters |
| 63 | + [/[{}()\[\];,.]/, 'delimiter'], |
| 64 | + |
| 65 | + // Identifiers |
| 66 | + [/[a-zA-Z_]\w*/, 'identifier'], |
| 67 | + ], |
| 68 | + |
| 69 | + comment: [ |
| 70 | + [/[^/*]+/, 'comment'], |
| 71 | + [/\*\//, 'comment', '@pop'], |
| 72 | + [/[/*]/, 'comment'] |
| 73 | + ] |
| 74 | + } |
| 75 | +}; |
| 76 | + |
| 77 | +// Language configuration (for setLanguageConfiguration) |
| 78 | +const arkadeLanguageConfig = { |
| 79 | + comments: { |
| 80 | + lineComment: '//', |
| 81 | + blockComment: ['/*', '*/'] |
| 82 | + }, |
| 83 | + brackets: [ |
| 84 | + ['{', '}'], |
| 85 | + ['[', ']'], |
| 86 | + ['(', ')'] |
| 87 | + ], |
| 88 | + autoClosingPairs: [ |
| 89 | + { open: '{', close: '}' }, |
| 90 | + { open: '[', close: ']' }, |
| 91 | + { open: '(', close: ')' }, |
| 92 | + { open: '"', close: '"' } |
| 93 | + ], |
| 94 | + surroundingPairs: [ |
| 95 | + { open: '{', close: '}' }, |
| 96 | + { open: '[', close: ']' }, |
| 97 | + { open: '(', close: ')' }, |
| 98 | + { open: '"', close: '"' } |
| 99 | + ] |
| 100 | +}; |
| 101 | + |
| 102 | +// Theme definition |
| 103 | +const arkadeTheme = { |
| 104 | + base: 'vs-dark', |
| 105 | + inherit: true, |
| 106 | + rules: [ |
| 107 | + { token: 'comment', foreground: '6A9955' }, |
| 108 | + { token: 'keyword', foreground: 'C586C0' }, |
| 109 | + { token: 'type', foreground: '4EC9B0' }, |
| 110 | + { token: 'predefined', foreground: 'DCDCAA' }, |
| 111 | + { token: 'variable.predefined', foreground: '9CDCFE' }, |
| 112 | + { token: 'number', foreground: 'B5CEA8' }, |
| 113 | + { token: 'string', foreground: 'CE9178' }, |
| 114 | + { token: 'operator', foreground: 'D4D4D4' }, |
| 115 | + { token: 'delimiter', foreground: 'D4D4D4' }, |
| 116 | + { token: 'identifier', foreground: '9CDCFE' } |
| 117 | + ], |
| 118 | + colors: { |
| 119 | + 'editor.background': '#1e1e1e', |
| 120 | + 'editor.foreground': '#d4d4d4', |
| 121 | + 'editorLineNumber.foreground': '#858585', |
| 122 | + 'editorCursor.foreground': '#aeafad', |
| 123 | + 'editor.selectionBackground': '#264f78', |
| 124 | + 'editor.inactiveSelectionBackground': '#3a3d41' |
| 125 | + } |
| 126 | +}; |
| 127 | + |
| 128 | +// Completions |
| 129 | +const arkadeCompletions = [ |
| 130 | + // Keywords |
| 131 | + { label: 'contract', kind: 'Keyword', insertText: 'contract ${1:Name}(${2:params}) {\n\t$0\n}', insertTextRules: 4 }, |
| 132 | + { label: 'function', kind: 'Keyword', insertText: 'function ${1:name}(${2:params}) {\n\t$0\n}', insertTextRules: 4 }, |
| 133 | + { label: 'require', kind: 'Keyword', insertText: 'require(${1:condition});', insertTextRules: 4 }, |
| 134 | + { label: 'tapscript', kind: 'Keyword', insertText: 'tapscript {\n\t$0\n}', insertTextRules: 4 }, |
| 135 | + { label: 'if', kind: 'Keyword', insertText: 'if (${1:condition}) {\n\t$0\n}', insertTextRules: 4 }, |
| 136 | + { label: 'for', kind: 'Keyword', insertText: 'for (${1:i}, ${2:item}) in ${3:array} {\n\t$0\n}', insertTextRules: 4 }, |
| 137 | + { label: 'let', kind: 'Keyword', insertText: 'let ${1:name} = ${2:value};', insertTextRules: 4 }, |
| 138 | + { label: 'internal', kind: 'Keyword', insertText: 'internal' }, |
| 139 | + |
| 140 | + // Types |
| 141 | + { label: 'pubkey', kind: 'TypeParameter', insertText: 'pubkey' }, |
| 142 | + { label: 'signature', kind: 'TypeParameter', insertText: 'signature' }, |
| 143 | + { label: 'bytes', kind: 'TypeParameter', insertText: 'bytes' }, |
| 144 | + { label: 'bytes20', kind: 'TypeParameter', insertText: 'bytes20' }, |
| 145 | + { label: 'bytes32', kind: 'TypeParameter', insertText: 'bytes32' }, |
| 146 | + { label: 'int', kind: 'TypeParameter', insertText: 'int' }, |
| 147 | + { label: 'bool', kind: 'TypeParameter', insertText: 'bool' }, |
| 148 | + { label: 'asset', kind: 'TypeParameter', insertText: 'asset' }, |
| 149 | + |
| 150 | + // Functions |
| 151 | + { label: 'checkSig', kind: 'Function', insertText: 'checkSig(${1:sig}, ${2:pubkey})', insertTextRules: 4, detail: 'Verify signature against pubkey' }, |
| 152 | + { label: 'checkMultisig', kind: 'Function', insertText: 'checkMultisig([${1:keys}], [${2:sigs}], ${3:threshold})', insertTextRules: 4, detail: 'Verify multiple signatures' }, |
| 153 | + { label: 'checkSigFromStack', kind: 'Function', insertText: 'checkSigFromStack(${1:sig}, ${2:pubkey}, ${3:msg})', insertTextRules: 4, detail: 'Verify signature from stack' }, |
| 154 | + { label: 'sha256', kind: 'Function', insertText: 'sha256(${1:data})', insertTextRules: 4, detail: 'SHA256 hash' }, |
| 155 | + { label: 'older', kind: 'Function', insertText: 'older(${1:delay})', insertTextRules: 4, detail: 'Relative CSV timelock' }, |
| 156 | + { label: 'after', kind: 'Function', insertText: 'after(${1:locktime})', insertTextRules: 4, detail: 'Absolute CLTV timelock' }, |
| 157 | + { label: 'tweak', kind: 'Function', insertText: 'tweak(emulator, ${1:functionName})', insertTextRules: 4, detail: 'Tweaked emulator key' }, |
| 158 | + |
| 159 | + // Transaction introspection |
| 160 | + { label: 'tx.time', kind: 'Property', insertText: 'tx.time', detail: 'Transaction locktime' }, |
| 161 | + { label: 'tx.inputs', kind: 'Property', insertText: 'tx.inputs[${1:i}]', insertTextRules: 4, detail: 'Transaction inputs' }, |
| 162 | + { label: 'tx.outputs', kind: 'Property', insertText: 'tx.outputs[${1:o}]', insertTextRules: 4, detail: 'Transaction outputs' }, |
| 163 | + { label: 'tx.input.current', kind: 'Property', insertText: 'tx.input.current', detail: 'Current input' }, |
| 164 | + |
| 165 | + // P2TR |
| 166 | + { label: 'P2TR', kind: 'Constructor', insertText: 'new P2TR(${1:internalKey})', insertTextRules: 4, detail: 'Create P2TR scriptPubKey' }, |
| 167 | +]; |
| 168 | + |
| 169 | +// Export all parts |
| 170 | +window.arkadeMonarch = arkadeMonarch; |
| 171 | +window.arkadeLanguageConfig = arkadeLanguageConfig; |
| 172 | +window.arkadeTheme = arkadeTheme; |
| 173 | +window.arkadeCompletions = arkadeCompletions; |
0 commit comments