mirror of
https://github.com/compiler-explorer/compiler-explorer.git
synced 2026-07-16 17:26:58 -04:00
Fixes https://github.com/compiler-explorer/compiler-explorer/issues/5634. Adds the Lean 4 language and compiler. > Lean is an open-source programming language and proof assistant that enables correct, maintainable, and formally verified code Since it was first requested in https://github.com/compiler-explorer/compiler-explorer/issues/5634, it has become increasingly relevant due to interest in AI-assisted theorem proving, formalized mathematics, and verified software. --- Lean compiles in two steps: first to C source code using the `lean` executable, and then to assembly using the `leanc` compiler distributed with Lean (I believe it's Clang). The PR also includes a pane to visualize the emitted C source code that was modelled after the panes for Rust and Haskell IRs and after the C preprocessor pane for clang-format integration. Lean outputs mostly unindented C code, so I enabled the formatter by default. See companion infrastructure PR at https://github.com/compiler-explorer/infra/pull/2130. <img width="3024" height="1720" alt="image" src="https://github.com/user-attachments/assets/5e7a1e91-e748-4599-8190-d3cb09fca503" /> --------- Co-authored-by: Matt Godbolt <matt@godbolt.org>
348 lines
10 KiB
TypeScript
348 lines
10 KiB
TypeScript
// Copyright (c) 2026, Compiler Explorer Authors
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright notice,
|
|
// this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above copyright
|
|
// notice, this list of conditions and the following disclaimer in the
|
|
// documentation and/or other materials provided with the distribution.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
// POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
import * as monaco from 'monaco-editor';
|
|
|
|
// Based on https://github.com/leanprover/vscode-lean4/blob/bbe3ff12/vscode-lean4/syntaxes/lean4.json.
|
|
function definition(): monaco.languages.IMonarchLanguage {
|
|
return {
|
|
escapes: /\\(?:[\\'"ntr]|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4})/,
|
|
keywords: [
|
|
'local',
|
|
'scoped',
|
|
'partial',
|
|
'unsafe',
|
|
'nonrec',
|
|
'public',
|
|
'private',
|
|
'protected',
|
|
'noncomputable',
|
|
'meta',
|
|
'deriving',
|
|
'instance',
|
|
'inductive',
|
|
'coinductive',
|
|
'structure',
|
|
'theorem',
|
|
'axiom',
|
|
'abbrev',
|
|
'lemma',
|
|
'def',
|
|
'instance',
|
|
'class',
|
|
'with',
|
|
'extends',
|
|
'where',
|
|
'theorem',
|
|
'show',
|
|
'have',
|
|
'using',
|
|
'haveI',
|
|
'from',
|
|
'suffices',
|
|
'nomatch',
|
|
'nofun',
|
|
'no_index',
|
|
'def',
|
|
'class',
|
|
'structure',
|
|
'instance',
|
|
'elab',
|
|
'set_option',
|
|
'initialize',
|
|
'builtin_initialize',
|
|
'example',
|
|
'inductive_fixpoint',
|
|
'inductive',
|
|
'coinductive_fixpoint',
|
|
'coinductive',
|
|
'termination_by?',
|
|
'termination_by',
|
|
'decreasing_by',
|
|
'partial_fixpoint',
|
|
'axiom',
|
|
'universe',
|
|
'variable',
|
|
'module',
|
|
'import all',
|
|
'import',
|
|
'open',
|
|
'export',
|
|
'prelude',
|
|
'renaming',
|
|
'hiding',
|
|
'do',
|
|
'by?',
|
|
'by',
|
|
'let',
|
|
'letI',
|
|
'let_expr',
|
|
'extends',
|
|
'mutual',
|
|
'mut',
|
|
'where',
|
|
'rec',
|
|
'declare_syntax_cat',
|
|
'syntax',
|
|
'macro_rules',
|
|
'macro',
|
|
'max_prec',
|
|
'leading_parser',
|
|
'elab_rules',
|
|
'deriving',
|
|
'fun',
|
|
'section',
|
|
'namespace',
|
|
'end',
|
|
'prefix',
|
|
'postfix',
|
|
'infixl',
|
|
'infixr',
|
|
'infix',
|
|
'notation',
|
|
'abbrev',
|
|
'if',
|
|
'bif',
|
|
'then',
|
|
'else',
|
|
'calc',
|
|
'matches',
|
|
'match_expr',
|
|
'match',
|
|
'with',
|
|
'forall',
|
|
'for',
|
|
'while',
|
|
'repeat',
|
|
'unless',
|
|
'until',
|
|
'panic!',
|
|
'unreachable!',
|
|
'assert!',
|
|
'try',
|
|
'catch',
|
|
'finally',
|
|
'return',
|
|
'continue',
|
|
'break',
|
|
'exists',
|
|
'mod_cast',
|
|
'include_str',
|
|
'include',
|
|
'in',
|
|
'trailing_parser',
|
|
'tactic_tag',
|
|
'tactic_alt',
|
|
'tactic_extension',
|
|
'register_tactic_tag',
|
|
'binder_predicate',
|
|
'grind_propagator',
|
|
'builtin_grind_propagator',
|
|
'grind_pattern',
|
|
'simproc',
|
|
'builtin_simproc',
|
|
'simproc_decl',
|
|
'builtin_simproc_decl',
|
|
'dsimproc',
|
|
'builtin_dsimproc',
|
|
'dsimproc_decl',
|
|
'builtin_dsimproc_decl',
|
|
'show_panel_widgets',
|
|
'show_term',
|
|
'seal',
|
|
'unseal',
|
|
'nat_lit',
|
|
'norm_cast_add_elim',
|
|
'println!',
|
|
'declare_config_elab',
|
|
'register_error_explanation',
|
|
'register_builtin_option',
|
|
'register_option',
|
|
'register_parser_alias',
|
|
'register_simp_attr',
|
|
'register_linter_set',
|
|
'register_label_attr',
|
|
'recommended_spelling',
|
|
'reportIssue!',
|
|
'reprove',
|
|
'run_elab',
|
|
'run_cmd',
|
|
'run_meta',
|
|
'add_decl_doc',
|
|
'omit',
|
|
'opaque',
|
|
'dbg_trace',
|
|
'trace_goal',
|
|
'trace',
|
|
'throwErrorAt',
|
|
'throwError',
|
|
'throwNamedErrorAt',
|
|
'throwNamedError',
|
|
'logNamedWarningAt',
|
|
'logNamedWarning',
|
|
'logNamedErrorAt',
|
|
'logNamedError',
|
|
],
|
|
types: ['Prop', 'Type', 'Sort'],
|
|
invalidKeywords: ['sorry', 'admit'],
|
|
commands: [
|
|
'#print',
|
|
'#eval',
|
|
'#eval!',
|
|
'#reduce',
|
|
'#synth',
|
|
'#widget',
|
|
'#where',
|
|
'#version',
|
|
'#with_exporting',
|
|
'#check',
|
|
'#check_tactic',
|
|
'#check_tactic_failure',
|
|
'#check_failure',
|
|
'#check_simp',
|
|
'#discr_tree_key',
|
|
'#discr_tree_simp_key',
|
|
'#guard',
|
|
'#guard_expr',
|
|
'#guard_msgs',
|
|
],
|
|
invalidCommands: ['#exit'],
|
|
|
|
tokenizer: {
|
|
root: [
|
|
[/r(#*)"/, {token: 'string.quote', bracket: '@open', next: '@stringraw.$1'}],
|
|
{include: '@whitespace'},
|
|
|
|
[/"/, 'string', '@string'],
|
|
[/(?<![\]\w])'[^\\']'/, 'string'],
|
|
[/(?<![\]\w])(')(@escapes)(')/, ['string', 'string.escape', 'string']],
|
|
|
|
[/\b(0[xX][0-9a-fA-F]+|[0-9]+|-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?)\b/, 'number'],
|
|
[/«/, 'identifier', '@escapedIdentifier'],
|
|
[/\battribute\b\s*\[[^\]\s]*\]/, 'keyword.modifier'],
|
|
[/@\[[^\]\s]*\]/, 'keyword.modifier'],
|
|
[
|
|
/#[a-zA-Z_][a-zA-Z0-9_!]*/,
|
|
{
|
|
cases: {
|
|
'@invalidCommands': 'invalid',
|
|
'@commands': 'keyword',
|
|
'@default': '',
|
|
},
|
|
},
|
|
],
|
|
[/[{}()[\]]/, '@brackets'],
|
|
[
|
|
/[a-zA-Z_][a-zA-Z0-9_'?!]*/,
|
|
{
|
|
cases: {
|
|
'@invalidKeywords': 'invalid',
|
|
'@keywords': 'keyword',
|
|
'@types': 'keyword.type',
|
|
'@default': 'identifier',
|
|
},
|
|
},
|
|
],
|
|
],
|
|
|
|
whitespace: [
|
|
[/[ \t\r\n]+/, 'white'],
|
|
[/--.*$/, 'comment'],
|
|
[/\/--/, 'comment.doc', '@docComment'],
|
|
[/\/-!/, 'comment.doc', '@docComment'],
|
|
[/\/-/, 'comment', '@blockComment'],
|
|
],
|
|
|
|
docComment: [
|
|
[/[^/-]+/, 'comment.doc'],
|
|
[/\/-/, 'comment.doc', '@blockComment'],
|
|
[/-\//, 'comment.doc', '@pop'],
|
|
[/[/-]/, 'comment.doc'],
|
|
],
|
|
|
|
blockComment: [
|
|
[/[^/-]+/, 'comment'],
|
|
[/\/-/, 'comment', '@push'],
|
|
[/-\//, 'comment', '@pop'],
|
|
[/[/-]/, 'comment'],
|
|
],
|
|
|
|
string: [
|
|
[/[^\\"]+/, 'string'],
|
|
[/@escapes/, 'string.escape'],
|
|
[/\\./, 'string.escape.invalid'],
|
|
[/"/, 'string', '@pop'],
|
|
],
|
|
|
|
escapedIdentifier: [
|
|
[/[^»]+/, 'identifier'],
|
|
[/»/, 'identifier', '@pop'],
|
|
],
|
|
|
|
stringraw: [
|
|
[/[^"#]+/, {token: 'string'}],
|
|
[
|
|
/"(#*)/,
|
|
{
|
|
cases: {
|
|
'$1==$S2': {token: 'string.quote', bracket: '@close', next: '@pop'},
|
|
'@default': {token: 'string'},
|
|
},
|
|
},
|
|
],
|
|
[/["#]/, {token: 'string'}],
|
|
],
|
|
},
|
|
};
|
|
}
|
|
|
|
monaco.languages.register({id: 'lean'});
|
|
monaco.languages.setMonarchTokensProvider('lean', definition());
|
|
monaco.languages.setLanguageConfiguration('lean', {
|
|
comments: {
|
|
lineComment: '--',
|
|
blockComment: ['/-', '-/'],
|
|
},
|
|
|
|
brackets: [
|
|
['(', ')'],
|
|
['[', ']'],
|
|
['{', '}'],
|
|
],
|
|
|
|
autoClosingPairs: [
|
|
{open: '(', close: ')'},
|
|
{open: '[', close: ']'},
|
|
{open: '{', close: '}'},
|
|
{open: '"', close: '"', notIn: ['string', 'comment']},
|
|
],
|
|
|
|
surroundingPairs: [
|
|
{open: '(', close: ')'},
|
|
{open: '[', close: ']'},
|
|
{open: '{', close: '}'},
|
|
{open: '"', close: '"'},
|
|
],
|
|
});
|