diff --git a/scripts/bundle.js b/scripts/bundle.js index 0f20da1a..251a2439 100644 --- a/scripts/bundle.js +++ b/scripts/bundle.js @@ -58,6 +58,7 @@ bundleOne('typescript/typescript'); bundleOne('vb/vb'); bundleOne('xml/xml'); bundleOne('yaml/yaml'); +bundleOne('sophia/sophia'); bundleOne('solidity/solidity'); bundleOne('sb/sb'); bundleOne('mysql/mysql'); diff --git a/src/monaco.contribution.ts b/src/monaco.contribution.ts index 094dacea..bd1b5303 100644 --- a/src/monaco.contribution.ts +++ b/src/monaco.contribution.ts @@ -42,6 +42,7 @@ import './ruby/ruby.contribution'; import './rust/rust.contribution'; import './sb/sb.contribution'; import './scss/scss.contribution'; +import './sophia/sophia.contribution'; import './solidity/solidity.contribution'; import './sql/sql.contribution'; import './st/st.contribution'; diff --git a/src/sophia/sophia.contribution.ts b/src/sophia/sophia.contribution.ts new file mode 100644 index 00000000..8871979b --- /dev/null +++ b/src/sophia/sophia.contribution.ts @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { registerLanguage } from '../_.contribution'; + +registerLanguage({ + id: 'aes', + extensions: ['.aes'], + aliases: ['aes', 'sophia', 'Sophia'], + loader: () => import('./sophia') +}); diff --git a/src/sophia/sophia.test.ts b/src/sophia/sophia.test.ts new file mode 100644 index 00000000..7f5b1de7 --- /dev/null +++ b/src/sophia/sophia.test.ts @@ -0,0 +1,275 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import { testTokenization } from '../test/testRunner'; + +testTokenization('aes', [ + [{ + line: 'contract HackBG =', + tokens: [ + { startIndex: 0, type: 'keyword.contract.aes' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.aes' }, + { startIndex: 15, type: '' }, + { startIndex: 16, type: 'delimiter.aes' }, + ] + }], + + [{ + line: 'record state = { developers : list(developer) }', + tokens: [ + { startIndex: 0, type: 'keyword.record.aes' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'keyword.state.aes' }, + { startIndex: 12, type: '' }, + { startIndex: 13, type: 'delimiter.aes' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'delimiter.curly.aes' }, + { startIndex: 16, type: '' }, + { startIndex: 17, type: 'identifier.aes' }, + { startIndex: 27, type: '' }, + { startIndex: 28, type: 'delimiter.aes' }, + { startIndex: 29, type: '' }, + { startIndex: 30, type: 'keyword.list.aes' }, + { startIndex: 34, type: 'delimiter.parenthesis.aes' }, + { startIndex: 35, type: 'identifier.aes' }, + { startIndex: 44, type: 'delimiter.parenthesis.aes' }, + { startIndex: 45, type: '' }, + { startIndex: 46, type: 'delimiter.curly.aes' }, + ] + }], + + [{ + line: 'record developer = {', + tokens: [ + { startIndex: 0, type: 'keyword.record.aes' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.aes' }, + { startIndex: 16, type: '' }, + { startIndex: 17, type: 'delimiter.aes' }, + { startIndex: 18, type: '' }, + { startIndex: 19, type: 'delimiter.curly.aes' } + ] + }], + + [{ + line: 'name : string,', + tokens: [ + { startIndex: 0, type: 'identifier.aes' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.aes' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'keyword.string.aes' }, + { startIndex: 13, type: 'delimiter.aes' } + + ] + }], + + [{ + line: 'experience : int,', + tokens: [ + { startIndex: 0, type: 'identifier.aes' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'delimiter.aes' }, + { startIndex: 12, type: '' }, + { startIndex: 13, type: 'keyword.int.aes' }, + { startIndex: 16, type: 'delimiter.aes' } + + ] + }], + + [{ + line: 'skillset : list(string) }', + tokens: [ + { startIndex: 0, type: 'identifier.aes' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'delimiter.aes' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'keyword.list.aes' }, + { startIndex: 15, type: 'delimiter.parenthesis.aes' }, + { startIndex: 16, type: 'keyword.string.aes' }, + { startIndex: 22, type: 'delimiter.parenthesis.aes' }, + { startIndex: 23, type: '' }, + { startIndex: 24, type: 'delimiter.curly.aes' }, + ] + }], + + [{ + line: 'entrypoint init() = { developers = {} }', + tokens: [ + { startIndex: 0, type: 'keyword.entrypoint.aes' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'identifier.aes' }, + { startIndex: 15, type: 'delimiter.parenthesis.aes' }, + { startIndex: 17, type: '' }, + { startIndex: 18, type: 'delimiter.aes' }, + { startIndex: 19, type: '' }, + { startIndex: 20, type: 'delimiter.curly.aes' }, + { startIndex: 21, type: '' }, + { startIndex: 22, type: 'identifier.aes' }, + { startIndex: 32, type: '' }, + { startIndex: 33, type: 'delimiter.aes' }, + { startIndex: 34, type: '' }, + { startIndex: 35, type: 'delimiter.curly.aes' }, + { startIndex: 37, type: '' }, + { startIndex: 38, type: 'delimiter.curly.aes' } + ] + }], + + // Comments - single line + [{ + line: '//', + tokens: [ + { startIndex: 0, type: 'comment.aes' } + ] + }], + + [{ + line: ' // a comment', + tokens: [ + { startIndex: 0, type: '' }, + { startIndex: 4, type: 'comment.aes' } + ] + }], + + [{ + line: '// a comment', + tokens: [ + { startIndex: 0, type: 'comment.aes' } + ] + }], + + [{ + line: '//sticky comment', + tokens: [ + { startIndex: 0, type: 'comment.aes' } + ] + }], + + [{ + line: '/almost a comment', + tokens: [ + { startIndex: 0, type: 'delimiter.aes' }, + { startIndex: 1, type: 'identifier.aes' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.aes' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'identifier.aes' } + ] + }], + + [{ + line: '/* //*/ a', + tokens: [ + { startIndex: 0, type: 'comment.aes' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.aes' } + ] + }], + + [{ + line: '1 / 2 /* comment', + tokens: [ + { startIndex: 0, type: 'number.aes' }, + { startIndex: 1, type: '' }, + { startIndex: 2, type: 'delimiter.aes' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'number.aes' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'comment.aes' } + ] + }], + + [{ + line: 'let x : int = 1 // my comment // is a nice one', + tokens: [ + { startIndex: 0, type: 'keyword.let.aes' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'identifier.aes' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.aes' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'keyword.int.aes' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'delimiter.aes' }, + { startIndex: 13, type: '' }, + { startIndex: 14, type: 'number.aes' }, + { startIndex: 15, type: '' }, + { startIndex: 16, type: 'comment.aes' } + ] + }], + + // Comments - range comment, single line + [{ + line: '/* a simple comment */', + tokens: [ + { startIndex: 0, type: 'comment.aes' } + ] + }], + + [{ + line: 'let x : int = /* a simple comment */ 1', + tokens: [ + { startIndex: 0, type: 'keyword.let.aes' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'identifier.aes' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.aes' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'keyword.int.aes' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'delimiter.aes' }, + { startIndex: 13, type: '' }, + { startIndex: 14, type: 'comment.aes' }, + { startIndex: 36, type: '' }, + { startIndex: 37, type: 'number.aes' }, + ] + }], + + [{ + line: 'let x = /* comment */ 1 */', + tokens: [ + { startIndex: 0, type: 'keyword.let.aes' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'identifier.aes' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.aes' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'comment.aes' }, + { startIndex: 21, type: '' }, + { startIndex: 22, type: 'number.aes' }, + { startIndex: 23, type: '' } + ] + }], + + [{ + line: 'let x = /**/', + tokens: [ + { startIndex: 0, type: 'keyword.let.aes' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'identifier.aes' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.aes' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'comment.aes' }, + ] + }], + + [{ + line: 'let x = /*/', + tokens: [ + { startIndex: 0, type: 'keyword.let.aes' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'identifier.aes' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.aes' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'comment.aes' } + ] + }], + +]); diff --git a/src/sophia/sophia.ts b/src/sophia/sophia.ts new file mode 100644 index 00000000..dad0284e --- /dev/null +++ b/src/sophia/sophia.ts @@ -0,0 +1,177 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import IRichLanguageConfiguration = monaco.languages.LanguageConfiguration; +import ILanguage = monaco.languages.IMonarchLanguage; + +export const conf: IRichLanguageConfiguration = { + comments: { + lineComment: '//', + blockComment: ['/*', '*/'], + }, + brackets: [['{', '}'], ['[', ']'], ['(', ')'], ['<', '>']], + autoClosingPairs: [ + { open: '"', close: '"', notIn: ['string', 'comment'] }, + { open: '{', close: '}', notIn: ['string', 'comment'] }, + { open: '[', close: ']', notIn: ['string', 'comment'] }, + { open: '(', close: ')', notIn: ['string', 'comment'] }, + ] +}; + +export const language = { + defaultToken: '', + tokenPostfix: '.aes', + + brackets: [ + { token: 'delimiter.curly', open: '{', close: '}' }, + { token: 'delimiter.parenthesis', open: '(', close: ')' }, + { token: 'delimiter.square', open: '[', close: ']' }, + { token: 'delimiter.angle', open: '<', close: '>' } + ], + + keywords: [ + // Main keywords + 'contract', + 'library', + 'entrypoint', + 'function', + 'stateful', + 'state', + 'hash', + 'signature', + 'tuple', + 'list', + 'address', + 'string', + 'bool', + 'int', + 'record', + 'datatype', + 'type', + 'option', + 'oracle', + 'oracle_query', + 'Call', + 'Bits', + 'Bytes', + 'Oracle', + 'String', + 'Crypto', + 'Address', + 'Auth', + 'Chain', + 'bits', + 'bytes', + 'event', + 'let', + 'map', + 'private', + 'public', + 'true', + 'false', + 'var', + 'if', + 'else', + 'throw' + ], + + operators: [ + '=', '>', '<', '!', '~', '?', '::', ':', + '==', '<=', '>=', '!=', '&&', '||', '++', '--', + '+', '-', '*', '/', '&', '|', '^', '%', '<<', + '>>', '>>>', '+=', '-=', '*=', '/=', '&=', '|=', + '^=', '%=', '<<=', '>>=', '>>>=' + ], + + // we include these common regular expressions + symbols: /[=>](?!@symbols)/, '@brackets'], + [/@symbols/, { + cases: { + '@operators': 'delimiter', + '@default': '' + } + }], + + // numbers + [/\d*\d+[eE]([\-+]?\d+)?(@floatsuffix)/, 'number.float'], + [/\d*\.\d+([eE][\-+]?\d+)?(@floatsuffix)/, 'number.float'], + [/0[xX][0-9a-fA-F']*[0-9a-fA-F](@integersuffix)/, 'number.hex'], + [/0[0-7']*[0-7](@integersuffix)/, 'number.octal'], + [/0[bB][0-1']*[0-1](@integersuffix)/, 'number.binary'], + [/\d[\d']*\d(@integersuffix)/, 'number'], + [/\d(@integersuffix)/, 'number'], + + // delimiter: after number because of .\d floats + [/[;,.]/, 'delimiter'], + + // strings + [/"([^"\\]|\\.)*$/, 'string.invalid'], // non-teminated string + [/"/, 'string', '@string'], + + // characters + [/'[^\\']'/, 'string'], + [/(')(@escapes)(')/, ['string', 'string.escape', 'string']], + [/'/, 'string.invalid'] + ], + + whitespace: [ + [/[ \t\r\n]+/, ''], + [/\/\*\*(?!\/)/, 'comment.doc', '@doccomment'], + [/\/\*/, 'comment', '@comment'], + [/\/\/.*$/, 'comment'], + ], + + comment: [ + [/[^\/*]+/, 'comment'], + [/\*\//, 'comment', '@pop'], + [/[\/*]/, 'comment'] + ], + //Identical copy of comment above, except for the addition of .doc + doccomment: [ + [/[^\/*]+/, 'comment.doc'], + [/\*\//, 'comment.doc', '@pop'], + [/[\/*]/, 'comment.doc'] + ], + + string: [ + [/[^\\"]+/, 'string'], + [/@escapes/, 'string.escape'], + [/\\./, 'string.escape.invalid'], + [/"/, 'string', '@pop'] + ], + }, +}; diff --git a/test/setup.js b/test/setup.js index 4ec20e61..e72fb2c1 100644 --- a/test/setup.js +++ b/test/setup.js @@ -69,6 +69,7 @@ define(['require'], function () { 'release/dev/scheme/scheme.test', 'release/dev/scss/scss.test', 'release/dev/shell/shell.test', + 'release/dev/sophia/sophia.test', 'release/dev/solidity/solidity.test', 'release/dev/sql/sql.test', 'release/dev/st/st.test',