From 6c298487001400a60a0c2ab0594cd6307506569e Mon Sep 17 00:00:00 2001 From: huningxin Date: Wed, 26 Jun 2024 01:16:09 +0000 Subject: [PATCH] =?UTF-8?q?Deploying=20to=20gh-pages=20from=20@=20webmachi?= =?UTF-8?q?nelearning/webnn-samples@70f6eb30aea5bcf3de0550ee2d3e227eec8593?= =?UTF-8?q?5c=20=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nnotepad/js/index.js | 3 +- nnotepad/js/nnotepad.js | 205 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 204 insertions(+), 4 deletions(-) diff --git a/nnotepad/js/index.js b/nnotepad/js/index.js index ebe923dd..fcb4fbb9 100644 --- a/nnotepad/js/index.js +++ b/nnotepad/js/index.js @@ -15,9 +15,10 @@ document.addEventListener('DOMContentLoaded', async (e) => { console.warn(ex); } + NNotepad.addMonacoLanguage(monaco); const editor = monaco.editor.create($('#input'), { value: inputValue, - language: 'markdown', + language: NNotepad.monacoLanguageId, lineNumbers: 'on', automaticLayout: true, theme: 'vs', diff --git a/nnotepad/js/nnotepad.js b/nnotepad/js/nnotepad.js index a1a7c348..e7c8dfea 100644 --- a/nnotepad/js/nnotepad.js +++ b/nnotepad/js/nnotepad.js @@ -113,9 +113,7 @@ export class NNotepad { const kUnaryOperators = { '-': 'neg', - '!': - 'logicalNot', // See - // https://github.com/webmachinelearning/webnn/issues/496#issuecomment-2123895106 + '!': 'logicalNot', }; const kDefaultDataType = 'float32'; @@ -583,4 +581,205 @@ export class NNotepad { buffer: maybeProxyForFloat16Array(result.outputs[`output-${index}`]), })); } + + // ============================================================ + // Monarch Tokens Provider + // ============================================================ + + // The language ID configured when calling `addMonacoLanguage()`, which + // should be passed to `monaco.editor.create()`. + static get monacoLanguageId() { + return 'nnotepad'; + } + + // Register and configure the NNotepad language with Monaco. + + static addMonacoLanguage(monaco) { + monaco.languages.register({id: NNotepad.monacoLanguageId}); + + monaco.languages.setLanguageConfiguration( + NNotepad.monacoLanguageId, NNotepad.monacoLanguageConfiguration); + + monaco.languages.setMonarchTokensProvider( + NNotepad.monacoLanguageId, NNotepad.monarchTokensProvider); + + if ('MLGraphBuilder' in self) { + // Introspect MLGraphBuilder methods to populate autocompletion. + const proto = self.MLGraphBuilder.prototype; + const methods = + Object.getOwnPropertyNames(proto) + .map((name) => Object.getOwnPropertyDescriptor(proto, name)) + .filter( + (desc) => desc.enumerable && typeof desc.value === 'function') + .map((desc) => desc.value.name); + + monaco.languages.registerCompletionItemProvider( + NNotepad.monacoLanguageId, { + provideCompletionItems: (model, position) => { + const suggestions = methods.map( + (name) => ({ + label: name, + kind: monaco.languages.CompletionItemKind.Keyword, + insertText: name, + })); + return {suggestions}; + }, + }); + } + } + + // Return a Monaco language configuration. + // https://code.visualstudio.com/api/language-extensions/language-configuration-guide + + static get monacoLanguageConfiguration() { + return { + // For comment toggling. + comments: { + lineComment: '#', + }, + + // For matching/highlighting. + brackets: [['{', '}'], ['[', ']'], ['(', ')']], + + // To auto-close as you type the open character. + autoClosingPairs: [ + {'open': '{', 'close': '}'}, + {'open': '[', 'close': ']'}, + {'open': '(', 'close': ')'}, + {'open': '\'', 'close': '\'', 'notIn': ['string', 'comment']}, + {'open': '"', 'close': '"', 'notIn': ['string']}, + ], + }; + } + + // Return a Monarch syntax declaration, for use with the Monaco editor. + // https://microsoft.github.io/monaco-editor/monarch.html + + static get monarchTokensProvider() { + return { + defaultToken: 'invalid', + + brackets: [ + ['{', '}', 'delimiter.curly'], + ['[', ']', 'delimiter.square'], + ['(', ')', 'delimiter.parenthesis'], + ], + + // Common token patterns + ws: /[ \t\r\n]*/, + string: /"(?:[^\\\n\r"]|\\.)*"|'(?:[^\\\n\r']|\\.)*'/, + number: /NaN|Infinity|-Infinity|-?\d+(\.\d+)?([eE]-?\d+)?/, + suffix: /u8|u32|u64|i8|i32|i64|f16|f32/, + identifier: /[A-Za-z]\w*/, + + tokenizer: { + root: [ + {include: '@whitespace'}, + {include: '@comment'}, + + // Assignment + ['(@identifier)(@ws)(=)', ['variable.name', 'white', 'operator']], + + {include: '@expr'}, + ], + + // Expression + expr: [ + {include: '@whitespace'}, + {include: '@comment'}, + + // Number + ['@number', 'number.float', '@suffix'], + + // Array + [/\[/, '@brackets', '@array'], + + // String + ['@string', 'string'], + + // Boolean + [/true|false/, 'keyword'], + + // Dictionary + [/{/, '@brackets', '@dict'], + + // Function invocation + [ + '(@identifier)(@ws)(\\()', + [ + 'identifier', + 'white', + {token: '@brackets', next: '@func'}, + ], + ], + + // Identifier + ['@identifier', 'identifier'], + + // Delimited subexpression + [/\(/, '@brackets', '@subexpr'], + + // operators + [/==|<=|<|>=|>|\+|-|\*|\/|\^|!/, 'operator'], + ], + + // Function call + func: [ + {include: '@expr'}, + [/,/, 'delimiter'], + [/\)/, '@brackets', '@pop'], + ], + + // Dictionary + dict: [ + {include: '@whitespace'}, + {include: '@comment'}, + ['@string', 'string', '@propdef'], + ['@identifier', 'identifier', '@propdef'], + [/,/, 'delimiter'], + [/}/, '@brackets', '@pop'], + ], + + propdef: [ + {include: '@whitespace'}, + {include: '@comment'}, + [':', {token: 'delimiter', switchTo: '@propvalue'}], + ], + + propvalue: [ + {include: '@expr'}, + [/,/, 'delimiter', '@pop'], + [/(?=})/, '', '@pop'], + ], + + // Array + array: [ + {include: '@expr'}, + [/,/, 'delimiter'], + [']', {token: '@brackets', switchTo: '@suffix'}], + ], + + // Delimited subexpression + subexpr: [ + {include: '@expr'}, + [/\)/, '@brackets', '@pop'], + ], + + whitespace: [ + [/[ \t\r\n]+/, 'white'], + ], + + comment: [ + [/(#|\/\/).*$/, 'comment'], + ], + + suffix: [ + [ + '(@ws)((?:@suffix)?)', + ['white', {token: 'annotation', next: '@pop'}], + ], + ], + }, + }; + } }