| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469 |
- /*
- * Part of the Carbon Language project, under the Apache License v2.0 with LLVM
- * Exceptions. See /LICENSE for license information.
- * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- */
- /*
- * Language: Carbon
- * Category: common, system
- * Website: https://github.com/carbon-language/carbon-lang/
- *
- * TODO: abstract, virtual, impl on methods.
- * TODO: private, protected.
- * TODO: Dedicated package and import highlighting.
- * TODO: Dedicated `impl` highlighting.
- * TODO: `impl forall` pattern highlighting.
- * TODO: Some way to keep keywords here and in other implementations in sync.
- */
- /** @type LanguageFn */
- export default function (hljs) {
- // Common keywords definition used in various contexts to at least highlight
- // these correctly. Note that some of these aren't yet used in Carbon but are
- // anticipated and we go ahead and syntax-highlight them.
- const KEYWORDS = {
- keyword: [
- 'abstract',
- 'addr',
- 'alias',
- 'and',
- 'api',
- 'as',
- 'auto',
- 'base',
- 'break',
- 'case',
- 'class',
- 'constraint',
- 'continue',
- 'default',
- 'else',
- 'extends',
- 'external',
- 'final',
- 'fn',
- 'for',
- 'forall',
- 'friend',
- 'if',
- 'impl',
- 'import',
- 'in',
- 'interface',
- 'is',
- 'let',
- 'library',
- 'like',
- 'match',
- 'self',
- 'static',
- 'namespace',
- 'not',
- 'observe',
- 'or',
- 'override',
- 'package',
- 'partial',
- 'private',
- 'protected',
- 'return',
- 'returned',
- 'then',
- 'type',
- '_',
- 'var',
- 'virtual',
- 'where',
- 'while',
- ],
- literal: ['false', 'true'],
- type: ['bool'],
- built_in: ['As'],
- };
- // Punctuation and operator regex lists that are expanded into the expression
- // context. Note that we don't necessarily use all of these in Carbon today.
- // There are a number of operators in particular that aren't yet being used.
- // But it is harmless to give them nicer syntax highlighting. Eventually, as
- // the language settles, we can explore specifically highlighting operators
- // that aren't valid as errors.
- const PUNCTUATION = [/->/, /\./];
- const OPERATORS = [
- />>=/,
- /<=>/,
- /<<=/,
- /&=/,
- /\^=/,
- /:=/,
- /==/,
- /=>/,
- /!=/,
- />=/,
- />>/,
- /<=/,
- /<>/,
- /<</,
- /<-/,
- /-=/,
- /--/,
- /%=/,
- /\|=/,
- /\+=/,
- /\+\+/,
- /\/=/,
- /\*=/,
- /~=/,
- /&/,
- /\\/,
- /\^/,
- /!/,
- />/,
- /</,
- /-/,
- /%/,
- /\|/,
- /\+/,
- /\?/,
- /\//,
- /\*/,
- /~/,
- ];
- const COMMA_SEPARATOR = {
- begin: [/,/, /\s*/],
- beginScope: {
- 1: 'punctuation',
- },
- };
- // The core expression patterns.
- const NUMBER_LITERAL = {
- scope: 'number',
- variants: [
- { match: /[1-9][_0-9]*(\.[_0-9]+(e[-+]?[1-9][0-9]*)?)?/ },
- { match: /0x[_0-9A-F]+(\.[_0-9A-F]+(p[-+]?[1-9][0-9]*)?)?/ },
- { match: /0b[_01]+/ },
- ],
- };
- const TYPE_LITERAL = {
- scope: 'type',
- match: /[iuf][1-9][0-9]*/,
- };
- const ESCAPE_SEQUENCE = {
- scope: 'char.escape',
- match: /\\([tnr'"0\\0]|x[0-9A-F]{2}|u\{[0-9A-F]{4,}\})/,
- };
- const BLOCK_STRING_LITERAL = {
- scope: 'string',
- begin: [/"""/, /\S*/, /\n/],
- // TODO: `subLanguages` doesn't support referencing part of the match yet.
- beginScope: {
- 2: 'symbol',
- },
- end: /\s*"""/,
- contains: [
- ESCAPE_SEQUENCE,
- {
- scope: 'char.escape',
- match: /\\\n/,
- },
- ],
- };
- const STRING_LITERAL = {
- scope: 'string',
- begin: /"/,
- end: /"/,
- illegal: /\n/,
- contains: [ESCAPE_SEQUENCE],
- };
- const UNPARENTHESIZED_EXPRESSION = [
- TYPE_LITERAL,
- NUMBER_LITERAL,
- BLOCK_STRING_LITERAL,
- STRING_LITERAL,
- {
- scope: 'punctuation',
- match: '(' + PUNCTUATION.map((re) => re.source).join('|') + ')',
- },
- {
- scope: 'operator',
- match: '(' + OPERATORS.map((re) => re.source).join('|') + ')',
- },
- {
- scope: 'variable.language',
- match: /\bSelf\b/,
- },
- {
- // Catch-all sub-mode at the end but excluding any nesting characters.
- match: /\w+/,
- keywords: KEYWORDS,
- },
- ];
- const STRUCT_LITERAL_DESIGNATOR = {
- begin: [/\./, /[a-zA-Z]\w*/, /\s*/, /[:=]/, /\s*/],
- beginScope: {
- 1: 'punctuation',
- 2: 'symbol',
- 4: 'punctuation',
- },
- };
- // Use a nesting structure so that we directly track balanced delimiters and
- // consume them. This allows patterns below to reliably "end" on closing
- // delimiters without being confused by others in the expression stream.
- // Sadly, Highlight.js doesn't support indirect mode recursion so we have to
- // fuse all the delimited modes into a single one to support arbitrary
- // recursing. We use callbacks to make sure that the closing delimiters match
- // the opening ones.
- const PARENTHESIZED_EXPRESSION = {
- scope: 'carbon-delimited-expression',
- begin: /(\(|\{(?=\s*\.[a-zA-Z]\w*\s*[:=])|\[)/,
- beginScope: 'punctuation',
- end: /(\)|\}|\])/,
- endScope: 'punctuation',
- contains: [
- 'self',
- // Tuple literals and struct literals are comma-separated parenthesized
- // expressions.
- COMMA_SEPARATOR,
- // Struct literals include designators. These aren't allowed in tuple
- // literals, but included here because we fuse into a single recursive mode.
- STRUCT_LITERAL_DESIGNATOR,
- ...UNPARENTHESIZED_EXPRESSION,
- ],
- };
- const EXPRESSION = [PARENTHESIZED_EXPRESSION, ...UNPARENTHESIZED_EXPRESSION];
- // The pattern patterns, including comma-separated sequences.
- const VALUE_PATTERN = {
- scope: 'carbon-value-pattern',
- // This begins to match on *any* (zero-length) input that *isn't* one of the
- // terminating sequences. This is important so that once we end one of these
- // patterns we don't immediately begin it again. The mode that introduces
- // this has already determined that a value pattern can start immediately,
- // so we don't need other characters in the beginning.
- begin: /(?![=,;\)\]\}])/,
- end: /\s*[=,;\)\]\}]/,
- returnEnd: true,
- contains: [...EXPRESSION],
- };
- const BINDING_PATTERN = {
- scope: 'carbon-binding-pattern',
- variants: [
- {
- begin: [/(\bvar\b)?/, /\s*/, /[a-zA-Z]\w*/, /:!?/, /\s*/],
- beginScope: {
- 1: 'keyword',
- 3: 'variable',
- 4: 'punctuation',
- },
- },
- {
- begin: [/(\bvar\b)?/, /\s*/, /_/, /:!?/, /\s*/],
- beginScope: {
- 1: 'keyword',
- 3: 'keyword',
- 4: 'punctuation',
- },
- },
- ],
- end: /\s*[=,;\)\]\}]/,
- returnEnd: true,
- contains: [...EXPRESSION],
- };
- const SELF_PATTERN = {
- scope: 'carbon-self-pattern',
- begin: [/(\b(addr|var)\b)?/, /\s*/, /\bme/, /:/, /\s*/],
- beginScope: {
- 1: 'keyword',
- 3: 'keyword',
- 4: 'punctuation',
- },
- end: /[=,;\)\]\}]/,
- returnEnd: true,
- contains: [...EXPRESSION],
- };
- const UNPARENTHESIZED_PATTERNS = [
- SELF_PATTERN,
- BINDING_PATTERN,
- VALUE_PATTERN,
- ];
- const PARENTHESIZED_PATTERN = {
- scope: 'carbon-parenthesized-pattern',
- begin: /\(/,
- beginScope: 'punctuation',
- end: /\)/,
- endScope: 'punctuation',
- contains: ['self', COMMA_SEPARATOR, ...UNPARENTHESIZED_PATTERNS],
- };
- const PATTERN_SEQUENCE = [
- COMMA_SEPARATOR,
- PARENTHESIZED_PATTERN,
- ...UNPARENTHESIZED_PATTERNS,
- ];
- // Both variable and `let` value declarations.
- const INITIALIZER = {
- scope: 'carbon-initializer',
- begin: [/\s*/, /=/, /\s*/],
- beginScope: {
- 2: 'punctuation',
- },
- end: /[,;\)\]\}]/,
- returnEnd: true,
- contains: [...EXPRESSION],
- };
- const VARIABLE = {
- variants: [
- {
- scope: 'carbon-var-declaration',
- begin: [/\bvar/, /\s+/],
- },
- {
- scope: 'carbon-let-declaration',
- begin: [/\blet/, /\s+/],
- },
- ],
- beginScope: {
- 1: 'keyword',
- },
- end: /;/,
- endScope: 'punctuation',
- contains: [PARENTHESIZED_PATTERN, BINDING_PATTERN, INITIALIZER],
- };
- // Parameters.
- const PARAMETER_LIST = {
- variants: [
- {
- scope: 'params',
- begin: /\(/,
- end: /\)/,
- },
- {
- scope: 'params',
- begin: /\[/,
- end: /\]/,
- },
- ],
- beginScope: 'punctuation',
- endScope: 'punctuation',
- contains: [INITIALIZER, ...PATTERN_SEQUENCE],
- };
- // Functions.
- const FUNCTION_NAME_COMPONENT = {
- begin: [/\s*/, /\.?/, hljs.UNDERSCORE_IDENT_RE],
- beginScope: {
- 2: 'punctuation',
- 3: 'title.function',
- },
- end: /\s*(\.|->|;|\{)/,
- returnEnd: true,
- contains: [PARAMETER_LIST],
- };
- const RETURNED_TYPE = {
- scope: 'carbon-return-type',
- end: /\s*[;{]/,
- returnEnd: true,
- contains: [...EXPRESSION],
- };
- const RETURN_SPECIFIER = {
- begin: [/\s*/, /->/, /\s*/],
- beginScope: {
- 2: 'punctuation',
- },
- starts: RETURNED_TYPE,
- };
- const FUNCTION = {
- scope: 'carbon-function',
- begin: [/(\b(virtual|abstract|impl)\b)?/, /\s*/, /\bfn\b/],
- beginScope: { 1: 'keyword', 3: 'keyword' },
- end: /\s*[;{]/,
- returnEnd: true,
- contains: [FUNCTION_NAME_COMPONENT, RETURN_SPECIFIER],
- };
- // Classes, interfaces, and constraints.
- const CLASS_NAME_COMPONENT = {
- begin: [/\s*/, /\.?/, /(?!extends\b)[a-zA-Z_]\w*/],
- beginScope: {
- 2: 'punctuation',
- 3: 'title.class',
- },
- end: /\s*(\.|extends|;|\{)/,
- returnEnd: true,
- contains: [PARAMETER_LIST],
- };
- const EXTENDED_TYPE = {
- scope: 'title.class.inherited',
- end: /\s*[;{]/,
- returnEnd: true,
- contains: [...EXPRESSION],
- };
- const EXTENDS_KEYWORD = {
- begin: [/extends/, /\s+/],
- beginScope: {
- 1: 'keyword',
- },
- starts: EXTENDED_TYPE,
- };
- const CLASS = {
- variants: [
- {
- scope: 'carbon-class',
- begin: [/(\b(base|abstract)\b)?/, /\s*/, /\bclass\b/],
- beginScope: {
- 1: 'keyword',
- 3: 'keyword',
- },
- },
- {
- scope: 'carbon-interface',
- beginKeywords: 'interface',
- },
- {
- scope: 'carbon-constraint',
- beginKeywords: 'constraint',
- },
- ],
- end: /\s*[;{]/,
- returnEnd: true,
- contains: [CLASS_NAME_COMPONENT, EXTENDS_KEYWORD],
- };
- // Statements -- very loosely. We bundle together top-level declaration
- // constructs, blocks, and statements.
- const STATEMENTS = [
- VARIABLE,
- FUNCTION,
- CLASS,
- {
- // We only match the assignment operator at the statement level.
- scope: 'operator',
- match: /=/,
- },
- {
- scope: 'punctuation',
- match: /;/,
- },
- ...EXPRESSION,
- ];
- const BLOCK = {
- scope: 'carbon-block',
- begin: /\{/,
- beginScope: 'punctuation',
- end: /\}/,
- endScope: 'punctuation',
- contains: ['self', hljs.C_LINE_COMMENT_MODE, ...STATEMENTS],
- };
- // Stitch everything together into the language definition.
- return {
- name: 'Carbon',
- aliases: ['carbon', 'carbon-lang'],
- keywords: KEYWORDS,
- illegal: '</',
- contains: [hljs.C_LINE_COMMENT_MODE, ...STATEMENTS, BLOCK],
- };
- }
|