├── .github └── workflows │ └── mdbook.yml ├── .gitignore ├── LICENSE ├── README.md ├── book.toml ├── src ├── SUMMARY.md ├── declarations │ ├── declarations.md │ └── inductive.md ├── export_format.md ├── expressions │ ├── expressions.md │ └── implementing_expressions.md ├── foreword.md ├── further_reading.md ├── future_work.md ├── kernel_concepts │ ├── clarifying_language.md │ ├── instantiation_and_abstraction.md │ ├── kernel_concepts.md │ ├── the_big_picture.md │ └── weak_and_strong_reduction.md ├── levels.md ├── names.md ├── title_page.md ├── trust │ ├── adversarial_inputs.md │ ├── trust.md │ └── unsafe_declarations.md ├── type_checking │ ├── definitional_equality.md │ ├── reduction.md │ └── type_inference.md └── whats_a_kernel.md └── theme └── highlight.js /.github/workflows/mdbook.yml: -------------------------------------------------------------------------------- 1 | # Sample workflow for building and deploying a mdBook site to GitHub Pages 2 | # 3 | # To get started with mdBook see: https://rust-lang.github.io/mdBook/index.html 4 | # 5 | name: Deploy mdBook site to Pages 6 | 7 | on: 8 | # Runs on pushes targeting the default branch 9 | push: 10 | branches: ["main"] 11 | 12 | # Allows you to run this workflow manually from the Actions tab 13 | workflow_dispatch: 14 | 15 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 16 | permissions: 17 | contents: read 18 | pages: write 19 | id-token: write 20 | 21 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 22 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 23 | concurrency: 24 | group: "pages" 25 | cancel-in-progress: false 26 | 27 | jobs: 28 | # Build job 29 | build: 30 | runs-on: ubuntu-latest 31 | env: 32 | MDBOOK_VERSION: 0.4.36 33 | steps: 34 | - uses: actions/checkout@v4 35 | - name: Install mdBook 36 | run: | 37 | curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf -y | sh 38 | rustup update 39 | cargo install --version ${MDBOOK_VERSION} mdbook 40 | - name: Setup Pages 41 | id: pages 42 | uses: actions/configure-pages@v4 43 | - name: Build with mdBook 44 | run: mdbook build 45 | - name: Upload artifact 46 | uses: actions/upload-pages-artifact@v3 47 | with: 48 | path: ./book 49 | 50 | # Deployment job 51 | deploy: 52 | environment: 53 | name: github-pages 54 | url: ${{ steps.deployment.outputs.page_url }} 55 | runs-on: ubuntu-latest 56 | needs: build 57 | steps: 58 | - name: Deploy to GitHub Pages 59 | id: deployment 60 | uses: actions/deploy-pages@v4 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out/ 2 | .DS_Store 3 | book -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2.0 (Apache) 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. 13 | 14 | "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. 15 | 16 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. 17 | 18 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. 19 | 20 | "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. 21 | 22 | "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). 23 | 24 | "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. 25 | 26 | "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." 27 | 28 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 29 | 30 | 2. Grant of Copyright License. 31 | 32 | Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 33 | 34 | 3. Grant of Patent License. 35 | 36 | Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 37 | 38 | 4. Redistribution. 39 | 40 | You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: 41 | 42 | 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and 43 | 44 | 2. You must cause any modified files to carry prominent notices stating that You changed the files; and 45 | 46 | 3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and 47 | 48 | 4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. 49 | 50 | You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 51 | 52 | 5. Submission of Contributions. 53 | 54 | Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 55 | 56 | 6. Trademarks. 57 | 58 | This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 59 | 60 | 7. Disclaimer of Warranty. 61 | 62 | Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 63 | 64 | 8. Limitation of Liability. 65 | 66 | In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 67 | 68 | 9. Accepting Warranty or Additional Liability. 69 | 70 | While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. 71 | 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Type Checking in Lean 4 2 | ----------------------- 3 | 4 | This is a book about Lean 4's kernel and implementing external type checkers; it's built with mdBook. 5 | 6 | A hosted copy can be found at https://ammkrn.github.io/type_checking_in_lean4/ 7 | 8 | Users can build and view the book locally in their browser by [installing mdbook](https://rust-lang.github.io/mdBook/guide/installation.html) and running: 9 | ```bash 10 | mdbook watch --open # opens the output in `out/` in your default browser 11 | ``` -------------------------------------------------------------------------------- /book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | title = "Type Checking in Lean 4" 3 | authors = ["Christopher A. Bailey", "contributions from the Lean community"] 4 | language = "en" 5 | multilingual = false 6 | src = "src" 7 | 8 | [output.html] 9 | git-repository-url = "https://github.com/ammkrn/type_checking_in_lean4" 10 | -------------------------------------------------------------------------------- /src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Type Checking in Lean 4 2 | 3 | [Type Checking in Lean 4](title_page.md) 4 | [Foreword](foreword.md) 5 | 6 | - [What's a kernel?](./whats_a_kernel.md) 7 | - [Trust](./trust/trust.md) 8 | - [Unsafe declarations](./trust/unsafe_declarations.md) 9 | - [Adversarial inputs](./trust/adversarial_inputs.md) 10 | - [Export format](./export_format.md) 11 | - [Kernel concepts](./kernel_concepts/kernel_concepts.md) 12 | - [The big picture](./kernel_concepts/the_big_picture.md) 13 | - [Clarifying language](./kernel_concepts/clarifying_language.md) 14 | - [Instantiation and abstraction](./kernel_concepts/instantiation_and_abstraction.md) 15 | - [Weak and strong reduction](./kernel_concepts/weak_and_strong_reduction.md) 16 | - [Names](./names.md) 17 | - [Levels](./levels.md) 18 | - [Expressions](./expressions/expressions.md) 19 | - [Notes on Implementing Expressions](./expressions/implementing_expressions.md) 20 | - [Declarations](./declarations/declarations.md) 21 | - [The Secret Life of Inductive Types](./declarations/inductive.md) 22 | - [Type Inference](./type_checking/type_inference.md) 23 | - [Definitional Equality](./type_checking/definitional_equality.md) 24 | - [Reduction](./type_checking/reduction.md) 25 | - [Open issues & future work](./future_work.md) 26 | - [Further reading](./further_reading.md) -------------------------------------------------------------------------------- /src/declarations/declarations.md: -------------------------------------------------------------------------------- 1 | # Declarations 2 | 3 | Declarations are the big ticket items, and are the last domain elements we need to define. 4 | 5 | 6 | ``` 7 | declarationInfo ::= Name, (universe params : List Level), (type : Expr) 8 | 9 | declar ::= 10 | Axiom declarationInfo 11 | | Definition declarationInfo (value : Expr) ReducibilityHint 12 | | Theorem declarationInfo (value : Expr) 13 | | Opaque declarationInfo (value : Expr) 14 | | Quot declarationInfo 15 | | InductiveType 16 | declarationInfo 17 | is_recursive: Bool 18 | num_params: Nat 19 | num_indices: Nat 20 | -- The name of this type, and any others in a mutual block 21 | allIndNames: Name+ 22 | -- The names of the constructors for *this* type only, 23 | -- not including the constructors for mutuals that may 24 | -- be in this block. 25 | constructorNames: Name* 26 | 27 | | Constructor 28 | declarationInfo 29 | (inductiveName : Name) 30 | (numParams : Nat) 31 | (numFields : Nat) 32 | 33 | | Recursor 34 | declarationInfo 35 | numParams : Nat 36 | numIndices : Nat 37 | numMotives : Nat 38 | numMinors : Nat 39 | RecRule+ 40 | isK : Bool 41 | 42 | RecRule ::= (constructor name : Name), (number of constructor args : Nat), (val : Expr) 43 | ``` 44 | 45 | 46 | ## Checking a declaration 47 | 48 | 49 | For all declarations, the following preliminary checks are performed before any additional procedures specific to certain kinds of declaration: 50 | 51 | + The universe parameters in the declaration's `declarationInfo` must not have duplicates. For example, a declaration `def Foo.{u, v, u} ...` would be prohibited. 52 | 53 | + The declaration's type must not have free variables; all variables in a "finished" declaration must correspond to a binder. 54 | 55 | + The declaration's type must be a type (`infer declarationInfo.type` must produce a `Sort`). In Lean, a declaration `def Foo : Nat.succ := ..` is not permitted; `Nat.succ` is a value, not a type. 56 | 57 | ### Axiom 58 | 59 | The only checks done against axioms are those done for all declarations which ensure the `declarationInfo` passes muster. If an axiom has a valid set of universe parameters and a valid type with no free variables, it is admitted to the environment. 60 | 61 | ### Quot 62 | 63 | The `Quot` declarations are `Quot`, `Quot.mk`, `Quot.ind`, and `Quot.lift`. These declarations have prescribed types which are known to be sound within Lean's theory, so the environment's quotient declarations must match those types exactly. These types are hard-coded into kernel implementations since they are not prohibitively complex. 64 | 65 | ### Definition, theorem, opaque 66 | 67 | Definition, theorem, and opaque are interesting in that they both a type and a value. Checking these declarations involves inferring a type for the declaration's value, then asserting that the inferred type is definitionally equal to the ascribed type in the `declarationInfo`. 68 | 69 | In the case of a theorem, the `declarationInfo`'s type is what the user claims the type is, and therefore what the user is claiming to prove, while the value is what the user has offered as a proof of that type. Inferring the type of the received value amounts to checking what the proof is actually a proof of, and the definitional equality assertion ensures that the thing the value proves is actually what the user intended to prove. 70 | 71 | #### Reducibility hints 72 | 73 | Reducibility hints contain information about how a declaration should be unfolded. An `abbreviation` will generally always be unfolded, `opaque` will not be unfolded, and `regular N` might be unfolded depending on the value of `N`. The `regular` reducibility hints correspond to a definition's "height", which refers to the number of declarations that definition uses to define itself. A definition `x` with a value that refers to definition `y` will have a height value greater than `y`. -------------------------------------------------------------------------------- /src/declarations/inductive.md: -------------------------------------------------------------------------------- 1 | 2 | # The Secret Life of Inductive Types 3 | 4 | ### Inductive 5 | 6 | For clarity, the whole shebang of "an inductive declaration" is a type, a list of constructors, and a list of recursors. The declaration's type and constructors are specified by the user, and the recursor is derived from those elements. Each recursor also gets a list of "recursor rules", also known as computation rules, which are value level expressions used in iota reduction (a fancy word for pattern matching). Going forward, we will do our best do distinguish between "an inductive type" and "an inductive declaration". 7 | 8 | Lean's kernel natively supports mutual inductive declarations, in which case there is a list of (type, list constructor) pairs. The kernel supports nested inductive declarations by temporarily transforming them to mutual inductives (more on this below). 9 | 10 | ### Inductive types 11 | 12 | The kernel requires the "inductive type" part of an inductive declaration to actually be a type, and not a value (`infer ty` must produce some `sort `). For mutual inductives, the types being declared must all be in the same universe and have the same parameters. 13 | 14 | ### Constructor 15 | 16 | For any constructor of an inductive type, the following checks are enforced by the kernel: 17 | 18 | + The constructor's type/telescope has to share the same parameters as the type of the inductive being declared. 19 | 20 | + For the non-parameter elements of the constructor type's telescope, the binder type must actually be a type (must infer as `Sort _`). 21 | 22 | + For any non-parameter element of the constructor type's telescope, the element's inferred sort must be less than or equal to the inductive type's sort, or the inductive type being declared has to be a prop. 23 | 24 | + No argument to the constructor may contain a non-positive occurrence of the type being declared (readers can explore this issue in depth [here](https://counterexamples.org/strict-positivity.html?highlight=posi#positivity-strict-and-otherwise)). 25 | 26 | + The end of the constructor's telescope must be a valid application of arguments to the type being declared. For example, we require the `List.cons ..` constructor to end with `.. -> List A`, and it would be an error for `List.cons` to end with `.. -> Nat` 27 | 28 | #### Nested inductives 29 | 30 | Checking nested inductives is a more laborious procedure that involves temporarily specializing the nested parts of the inductive types in a mutual block so that we just have a "normal" (non-nested) set of mutual inductives, checking the specialized types, then unspecializing everything and admitting those types. 31 | 32 | Consider this definition of S-expressions, with the nested construction `Array Sexpr`: 33 | 34 | ``` 35 | inductive Sexpr 36 | | atom (c : Char) : Sexpr 37 | | ofArray : Array Sexpr -> Sexpr 38 | ``` 39 | 40 | Zooming out, the process of checking a nested inductive declaration has three steps: 41 | 42 | 1. Convert the nested inductive declaration to a mutual inductive declaration by specializing the "container types" in which the current type is being nested. If the container type is itself defined in terms of other types, we'll need to reach those components for specialization as well. In the example above, we use `Array` as a container type, and `Array` is defined in terms of `List`, so we need to treat both `Array` and `List` as container types. 43 | 44 | 2. Do the normal checks and construction steps for a mutual inductive type. 45 | 46 | 3. Convert the specialized nested types back to the original form (un-specializing), adding the recovered/unspecialized declarations to the environment. 47 | 48 | An example of this specialization would be the conversion of the `Sexpr` nested inductive above as: 49 | 50 | ``` 51 | mutual 52 | inductive Sexpr 53 | | atom : Char -> Sexpr 54 | | ofList : ListSexpr -> Sexpr 55 | 56 | inductive ListSexpr 57 | | nil : ListSexpr 58 | | cons : Sexpr -> ListSexpr -> ListSexpr 59 | 60 | inductive ArraySexpr 61 | | mk : ListSexpr -> ArraySexpr 62 | end 63 | ``` 64 | 65 | Then recovering the original inductive declaration in the process of checking these types. To clarify, when we say "specialize", the new `ListSexpr` and `ArraySexpr` types above are specialized in the sense that they're defined only as lists and arrays of `Sexpr`, as opposed to being generic over some arbitrary type as with the regular `List` type. 66 | 67 | 68 | ### Recursors 69 | 70 | For now, see [iota reduction in the section on reduction](../type_checking/reduction.md#iota-reduction-pattern-matching) 71 | -------------------------------------------------------------------------------- /src/export_format.md: -------------------------------------------------------------------------------- 1 | # Export format 2 | 3 | An exporter is a program which emits Lean declarations using the kernel language, for consumption by external type checkers. Producing an export file is a complete exit from the Lean ecosystem; the data in the file can be checked with entirely external software, and the exporter itself is not a trusted component. Rather than inspecting the export file itself to see whether the declarations were exported as the developer intended, the exported declarations are checked by the external checker, and are displayed back to the user by a pretty printer, which produces output far more readable than the export file. Readers can (and are encouraged to) write their own external checkers for Lean export files. 4 | 5 | The official exporter is [lean4export](https://github.com/leanprover/lean4export). 6 | 7 | There are [ongoing discussions](https://github.com/leanprover/lean4export/issues/3) about how best to evolve the export format. 8 | 9 | ## (ver 2.0.0) 10 | 11 | For clarity, some of the compound items are decorated here with a name, for example `(name : T)`, but they appear in the export file as just an element of `T`. 12 | 13 | The export scheme for mutual and nested inductives is as follows: 14 | + `Inductive.inductiveNames` contains the names of all types in the `mutual .. end` block. The names of any other inductive types used in a nested (but not mutual) construction will not be included. 15 | + `Inductive.constructorNames` contains the names of all constructors for THAT inductive type, and no others (no constructors of the other types in a mutual block, and no constructors from any nested construction). 16 | 17 | **NOTE:** readers writing their own parsers and/or checkers should initialize names[0] as the anonymous name, and levels[0] as universe zero, as they are not emitted by the exporter, but are expected to occupy the name and level indices for 0. 18 | 19 | ``` 20 | File ::= ExportFormatVersion Item* 21 | 22 | ExportFormatVersion ::= nat '.' nat '.' nat 23 | 24 | Item ::= Name | Universe | Expr | RecRule | Declaration 25 | 26 | Declaration ::= 27 | | Axiom 28 | | Quotient 29 | | Definition 30 | | Theorem 31 | | Inductive 32 | | Constructor 33 | | Recursor 34 | 35 | nidx, uidx, eidx, ridx ::= nat 36 | 37 | Name ::= 38 | | nidx "#NS" nidx string 39 | | nidx "#NI" nidx nat 40 | 41 | Universe ::= 42 | | uidx "#US" uidx 43 | | uidx "#UM" uidx uidx 44 | | uidx "#UIM" uidx uidx 45 | | uidx "#UP" nidx 46 | 47 | Expr ::= 48 | | eidx "#EV" nat 49 | | eidx "#ES" uidx 50 | | eidx "#EC" nidx uidx* 51 | | eidx "#EA" eidx eidx 52 | | eidx "#EL" Info nidx eidx eidx 53 | | eidx "#EP" Info nidx eidx eidx 54 | | eidx "#EZ" nidx eidx eidx eidx 55 | | eidx "#EJ" nidx nat eidx 56 | | eidx "#ELN" nat 57 | | eidx "#ELS" (hexhex)* 58 | -- metadata node w/o extensions 59 | | eidx "#EM" mptr eidx 60 | 61 | Info ::= "#BD" | "#BI" | "#BS" | "#BC" 62 | 63 | Hint ::= "O" | "A" | "R" nat 64 | 65 | RecRule ::= ridx "#RR" (ctorName : nidx) (nFields : nat) (val : eidx) 66 | 67 | Axiom ::= "#AX" (name : nidx) (type : eidx) (uparams : nidx*) 68 | 69 | Def ::= "#DEF" (name : nidx) (type : eidx) (value : eidx) (hint : Hint) (uparams : nidx*) 70 | 71 | Opaq ::= "#OPAQ" (name : nidx) (type : eidx) (value : eidx) (uparams : nidx*) 72 | 73 | Theorem ::= "#THM" (name : nidx) (type : eidx) (value : eidx) (uparams: nidx*) 74 | 75 | Quotient ::= "#QUOT" (name : nidx) (type : eidx) (uparams : nidx*) 76 | 77 | Inductive ::= 78 | "#IND" 79 | (name : nidx) 80 | (type : eidx) 81 | (isReflexive: 0 | 1) 82 | (isRecursive: 0 | 1) 83 | (numNested : nat) 84 | (numParams: nat) 85 | (numIndices: nat) 86 | (numInductives: nat) 87 | (inductiveNames: nidx {numInductives}) 88 | (numConstructors : nat) 89 | (constructorNames : nidx {numConstructors}) 90 | (uparams: nidx*) 91 | 92 | Constructor ::= 93 | "#CTOR" 94 | (name : nidx) 95 | (type : eidx) 96 | (parentInductive : nidx) 97 | (constructorIndex : nat) 98 | (numParams : nat) 99 | (numFields : nat) 100 | (uparams: nidx*) 101 | 102 | Recursor ::= 103 | "#REC" 104 | (name : nidx) 105 | (type : eidx) 106 | (numInductives : nat) 107 | (inductiveNames: nidx {numInductives}) 108 | (numParams : nat) 109 | (numIndices : nat) 110 | (numMotives : nat) 111 | (numMinors : nat) 112 | (numRules : nat) 113 | (recRules : ridx {numRules}) 114 | (k : 1 | 0) 115 | (uparams : nidx*) 116 | ``` 117 | -------------------------------------------------------------------------------- /src/expressions/expressions.md: -------------------------------------------------------------------------------- 1 | # Expressions 2 | 3 | ## Complete syntax 4 | 5 | Expressions will be explained in more detail below, but just to get it out in the open, the complete syntax for expressions, including the string and nat literal extensions, is as follows: 6 | 7 | ``` 8 | Expr ::= 9 | | boundVariable 10 | | freeVariable 11 | | const 12 | | sort 13 | | app 14 | | lambda 15 | | forall 16 | | let 17 | | proj 18 | | literal 19 | 20 | BinderInfo ::= Default | Implicit | InstanceImplicit | StrictImplicit 21 | 22 | const ::= Name, Level* 23 | sort ::= Level 24 | app ::= Expr Expr 25 | -- a deBruijn index 26 | boundVariable ::= Nat 27 | lambda ::= Name, (binderType : Expr), BinderInfo, (body : Expr) 28 | forall ::= Name, (binderType : Expr), BinderInfo, (body : Expr) 29 | let ::= Name, (binderType : Expr), (val : Expr) (body : Expr) 30 | proj ::= Name Nat Expr 31 | literal ::= natLit | stringLit 32 | 33 | -- Arbitrary precision nat/unsigned integer 34 | natLit ::= Nat 35 | -- UTF-8 string 36 | stringLit ::= String 37 | 38 | -- fvarId can be implemented by unique names or deBruijn levels; 39 | -- unique names are more versatile, deBruijn levels have better 40 | -- cache behavior 41 | freeVariable ::= Name, Expr, BinderInfo, fvarId 42 | ``` 43 | 44 | Some notes: 45 | 46 | + The `Nat` used by nat literals should be an arbitrary precision natural/bignum. 47 | 48 | + The expressions that have binders (lambda, pi, let, free variable) can just as easily bundle the three arguments (binder_name, binder_type, binder_style) as one argument `Binder`, where a binder is `Binder ::= Name BinderInfo Expr`. In the pseudocode that appears elsewhere I will usually treat them as though they have that property, because it's easier to read. 49 | 50 | + Free variable identifiers can be either unique identifiers, or they can be deBruijn levels. 51 | 52 | + The expression type used in Lean proper also has an `mdata` constructor, which declares an expression with attached metadata. This metadata does not effect the expression's behavior in the kernel, so we do not include this constructor. 53 | 54 | 55 | ## Binder information 56 | 57 | Expressions constructed with the lambda, pi, let, and free variable constructors contain binder information, in the form of a name, a binder "style", and the binder's type. The binder's name and style are only for use by the pretty printer, and do not alter the core procedures of inference, reduction, or equality checking. In the pretty printer however, the binder style may alter the output depending on the pretty printer options. For example, the user may or may not want to display implicit or instance implicits (typeclass variables) in the output. 58 | 59 | ### Sort 60 | 61 | `sort` is simply a wrapper around a level, allowing it to be used as an expression. 62 | 63 | 64 | ### Bound variables 65 | 66 | Bound variables are implemented as natural numbers representing [deBruijn indices](https://en.wikipedia.org/wiki/De_Bruijn_index). 67 | 68 | ### Free variables 69 | 70 | Free variables are used to convey information about bound variables in situations where the binder is currently unavailable. Usually this is because the kernel has traversed into the body of a binding expression, and has opted not to carry a structured context of the binding information, instead choosing to temporarily swap out the bound variable for a free variable, with the option of swapping in a new (maybe different) bound variable to reconstruct the binder. This unavailability description may sound vague, but a literal explanation that might help is that expressions are implemented as trees without any kind of parent pointer, so when we descend into child nodes (especially across function boundaries), we end up just losing sight of the elements above where we currently are in a given expression. 71 | 72 | When an open expression is closed by reconstructing binders, the bindings may have changed, invalidating previously valid deBruijn indices. The use of unique names or deBruijn levels allow this re-closing of binders to be done in a way that compensates for any changes and ensures the new deBruijn indices of the re-bound variables are valid with respect the reconstructed telescope (see [this section](./kernel_concepts.md#implementing-free-variable-abstraction)). 73 | 74 | Going forward, we may use some form of the term "free variable identifier" to refer to the objects in whatever scheme (unique IDs or deBruijn levels) an implementation may be using. 75 | 76 | ### `Const` 77 | 78 | The `const` constructor is how an expression refers to another declaration in the environment, it must do so by reference. 79 | 80 | In example below, `def plusOne` creates a `Definition` declaration, which is checked, then admitted to the environment. Declarations cannot be placed directly in expressions, so when the type of `plusOne_eq_succ` invokes the previous declaration `plusOne`, it must do so by name. An expression is created: `Expr.const (plusOne, [])`, and when the kernel finds this `const` expression, it can look up the declaration referred to by name, `plusOne`, in the environment: 81 | 82 | ``` 83 | def plusOne : Nat -> Nat := fun x => x + 1 84 | 85 | theorem plusOne_eq_succ (n : Nat) : plusOne n = n.succ := rfl 86 | ``` 87 | 88 | Expressions created with the `const` constructor also carry a list of levels which are substituted into any unfolded or inferred declarations taken from the environment by looking up the definition the `const` expression refers to. For example, inferring the type of `const List [Level.param(x)]` involves looking up the declaration for `List` in the current environment, retrieving its type and universe parameters, then substituting `x` for the universe parameter with which `List` was initially declared. 89 | 90 | 91 | ### Lambda, Pi 92 | 93 | `lambda` and `pi` expressions (Lean proper uses the name `forallE` instead of `pi`) refer to function abstraction and the "forall" binder (dependent function types) respectively. 94 | 95 | 96 | ``` 97 | binderName body 98 | | | 99 | fun (foo : Bar) => 0 100 | | 101 | binderType 102 | 103 | -- `BinderInfo` is reflected by the style of brackets used to 104 | -- surround the binder. 105 | ``` 106 | 107 | ### Let 108 | 109 | `let` is exactly what it sounds like. While `let` expressions are binders, they do not have a `BinderInfo`, their binder info is treated as `Default`. 110 | 111 | ``` 112 | binderName val 113 | | | 114 | let (foo : Bar) := 0; foo 115 | | | 116 | binderType .... body 117 | ``` 118 | 119 | 120 | ### App 121 | 122 | `app` expressions represent the application of an argument to a function. App nodes are binary (have only two children, a single function and an single argument), so `f x_0 x_1 .. x_N` is represented by `App(App(App(f, x_0), x_1)..., x_N)`, or visualized as a tree: 123 | 124 | ``` 125 | App 126 | / \ 127 | ... x_N 128 | / 129 | ... 130 | App 131 | / \ 132 | App x_1 133 | / \ 134 | f x_0 135 | 136 | ``` 137 | 138 | An exceedingly common kernel operation for manipulating expressions is folding and unfolding sequences of applications, getting `(f, [x_0, x_1, .., x_N])` from the tree structure above, or folding `f, [x_0, x_1, .., x_N]` into the tree above. 139 | 140 | 141 | ### Projections 142 | 143 | The `proj` constructor represents structure projections. Inductive types that are not recursive, have only one constructor, and have no indices can be structures. 144 | 145 | The constructor takes a name, which is the name of the type, a natural number indicating the field being projected, and the actual structure the projection is being applied to. 146 | 147 | Be aware that in the kernel, projection indices are 0-based, despite being 1-based in Lean's vernacular, where 0 is the first non-parameter argument to the constructor. 148 | 149 | For example, the kernel expression `proj Prod 0 (@Prod.mk A B a b)` would project the `a`, because it is the 0th field after skipping the parameters `A` and `B`. 150 | 151 | While the behavior offered by `proj` can be accomplished by using the type's recursor, `proj` more efficiently handles frequent kernel operations. 152 | 153 | ### Literals 154 | 155 | Lean's kernel optionally supports arbitrary precision Nat and String literals. As needed, the kernel can transform a nat literal `n` to `Nat.zero` or `Nat.succ m`, or convert a string literal `s` to `String.mk List.nil` or `String.mk (List.cons (Char.ofNat _) ...)`. 156 | 157 | String literals are lazily converted to lists of characters for testing definitional equality, and when they appear as the major premise in reduction of a recursor. 158 | 159 | Nat literals are supported in the same positions as strings (definitional equality and major premises of a recursor application), but the kernel also provide support for addition, multiplication, exponentiation, subtraction, mod, division, as well as boolean equality and "less than or equal" comparisons on nat literals. -------------------------------------------------------------------------------- /src/expressions/implementing_expressions.md: -------------------------------------------------------------------------------- 1 | # Implementing Expressions 2 | 3 | A few noteworthy points about the expression type for readers interested in writing their own kernel in whole or in part... 4 | 5 | ## Stored data 6 | 7 | Expressions need to store some data inline or cache it somewhere to prevent prohibitively expensive recomputation. For example, creating an expression `app x y` needs to calculate and then store the hash digest of the resulting app expression, and it needs to do so by getting the cached hash digests of `x` and `y` instead of traversing the entire tree of `x` to recursively calculate the digest of `x`, then doing the same for `y`. 8 | 9 | The data you will probably want to store inline are the hash digest, the number of loose bound variables in an expression, and whether or not the expression has free variables. The latter two are useful for optimizing instantiation and abstraction respectively. 10 | 11 | An example "smart constructor" for `app` expressions would be: 12 | 13 | ``` 14 | def mkApp x y: 15 | let hash := hash x.storedHash y.storedHash 16 | let numLooseBvars := max x.numLooseBvars y.numLooseBvars 17 | let hasFvars := x.hasFvars || y.hasFvars 18 | .app x y (cachedData := hash numLooseBVars hasFVars) 19 | ``` 20 | 21 | ## No deep copies 22 | 23 | Expressions should be implemented such that child expressions used to construct some parent expression are not deep copied. Put another way, creating an expression `app x y` should not recursively copy the elements of `x` and `y`, rather it should take some kind of reference, whether it's a pointer, integer index, reference to a garbage collected object, reference counted object, or otherwise (any of these strategies should deliver acceptable performance). If your default strategy for constructing expressions involves deep copies, you will not be able to construct any nontrivial environments without consuming massive amounts of memory. 24 | 25 | ## Example implementation for number of loose bound variables 26 | 27 | 28 | ``` 29 | numLooseBVars e: 30 | match e with 31 | | Sort | Const | FVar | StringLit | NatLit => 0 32 | | Var dbjIdx => dbjIdx + 1, 33 | | App fun arg => max fun.numLooseBvars arg.numLooseBvars 34 | | Pi binder body | Lambda binder body => 35 | | max binder.numLooseBVars (body.numLooseBVars - 1) 36 | | Let binder val body => 37 | | max (max binder.numLooseBvars val.numLooseBvars) (body.numLooseBvars - 1) 38 | | Proj _ _ structure => structure.numLooseBvars 39 | ``` 40 | 41 | For `Var` expressions, the number of loose bound variables is the deBruijn index plus one, because we're counting the number of binders that would need to be applied for that variable to no longer be loose (the `+1` is because deBruijn indices are 0-based). For the expression `Var(0)`, one binder needs to be placed above the bound variable in order for the variable to no longer be loose. For `Var(3)`, we need four: 42 | 43 | ``` 44 | -- 3 2 1 0 45 | fun a b c d => Var(3) 46 | ``` 47 | 48 | When we create a new binder (lambda, pi, or let), we can subtract 1 (using saturating/natural number subtraction) from the number of loose bvars in the body, because the body is now under one additional binder. 49 | 50 | -------------------------------------------------------------------------------- /src/foreword.md: -------------------------------------------------------------------------------- 1 | # Foreword 2 | 3 | The author would like to thank: 4 | 5 | Mario Carneiro 6 | 7 | Leonardo de Moura 8 | 9 | Sebastian Ullrich 10 | 11 | Gabriel Ebner 12 | 13 | Jonathan Protzenko 14 | 15 | The [Lean Zulip](https://leanprover.zulipchat.com/) community. 16 | 17 | Each and every contributor to Lean4, Mathlib, and the broader Lean ecosystem. 18 | 19 | --- 20 | 21 | This book is dedicated to the memory of Philip Elliot Bailey _(31 January, 1987 - 9 December, 2023)_. 22 | -------------------------------------------------------------------------------- /src/further_reading.md: -------------------------------------------------------------------------------- 1 | # Further reading 2 | 3 | + Mario Carneiro's [thesis on Lean's type theory](https://github.com/digama0/lean-type-theory) 4 | 5 | + Lean's official kernel: https://github.com/leanprover/lean4/tree/master/src/kernel 6 | 7 | + [lean4lean](https://github.com/digama0/lean4lean/tree/master), a reimplementation of Lean's kernel in Lean4. 8 | 9 | + [lean4export](https://github.com/leanprover/lean4export), the recommended/official exporter for Lean 4 environments. 10 | 11 | + [lean4checker](https://github.com/leanprover/lean4checker) 12 | 13 | + Peter Dybjer's original description of the inductive types implemented by Lean: P. Dybjer. Inductive families. Formal aspects of computing, 6(4):440–465, 1994. 14 | 15 | + Conor McBride and James McKinna's paper [_I am not a number: I am a free variable_](http://www.e-pig.org/downloads/notanum.pdf) describing the locally nameless approach to bound/free variables 16 | 17 | + Information about non-positive occurrences in inductive types, from _Counterexamples in Type Systems_: https://counterexamples.org/strict-positivity.html?highlight=posi#positivity-strict-and-otherwise 18 | 19 | + Freek Wiedijk. Pollack-inconsistency. Electronic Notes in Theoretical Computer Science, 285:85–100, 2012 20 | -------------------------------------------------------------------------------- /src/future_work.md: -------------------------------------------------------------------------------- 1 | # Future work and open issues 2 | 3 | ## File format 4 | 5 | There is an open rfc [here](https://github.com/leanprover/lean4export/issues/3) about moving the export file format to json, which would be a major version change. 6 | 7 | ## Ensuring Nat/String are defined properly. 8 | 9 | The Lean community has not yet settled on a particular solution for determining whether the declarations in an export file for `Nat`, `String`, and the operations covered by the relevant kernel extensions match those expected by extensions in a way that does not pull the exporter into the trusted code. 10 | 11 | An approach similar to that taken for `Eq` and the `Quot` declarations (defining them by hand within the type checker, then asserting they're the same) is not feasible due to the complexity of the fully elaborated terms for the supported binary operations on `Nat`. 12 | 13 | ## Improving Pollack consistency 14 | 15 | Lean 4 offers very powerful facilities for defining custom syntax, macros, and pretty printer behaviors, and almost every aspect of Lean 4's internals is available to users. These elements of Lean's design were effective responses to real world feedback from the mathlib community during Lean 3's lifetime. 16 | 17 | While these features were important factors in Lean's success as a tool for enabling large formalization efforts, they are also in tension with Lean4's Pollack consistency[^pollack], or lack thereof. Without replicating the macro and syntax extension capabilities in the pretty printer, type checkers cannot consistently read terms back to the user in a form that is recognizable. However, the idea of adding these features to a pretty printer is an unappealing expansion of the trusted code base. An alternative approach is to drop the pretty printer in favor of a trusted parser (ala metamath zero), but Lean's parser can be modified on the fly in userspace with custom syntax declarations. 18 | 19 | As Lean matures and adoption increases, there is likely to be a push for progress in the development of techniques and practices that allow users to take advantage of Lean's extensibility while sacrificing the least degree of Pollack consistency. 20 | 21 | ## Forward reasoning 22 | 23 | Existing type checkers implement a form of backward reasoning; an alternate strategy for type checking is to accept and check forward reasoning chains worked out by an external program, potentially allowing for an even simpler type checker. 24 | 25 | [^pollack]: Freek Wiedijk. Pollack-inconsistency. Electronic Notes in Theoretical Computer Science, 285:85–100, 2012 -------------------------------------------------------------------------------- /src/kernel_concepts/clarifying_language.md: -------------------------------------------------------------------------------- 1 | # Clarifying language 2 | 3 | 4 | ## Type, Sort, Prop 5 | 6 | `Prop` refers to `Sort 0` 7 | 8 | `Type n` refers to `Sort (n+1)` 9 | 10 | `Sort n` is how these are actually represented in the kernel, and can always be used. 11 | 12 | The reason why `Type ` and `Prop` are sometimes used instead of always adhering to `Sort n` is that elements of `Type ` have certain important qualities and behaviors that are not observed by those of `Prop` and vice versa. 13 | 14 | Example: elements of `Prop` can be considered for definitional proof irrelevance, while elements of `Type _` can use large elimination without needing to satisfy other tests. 15 | 16 | 17 | ## Level/universe and Sort 18 | 19 | The terms "level" and "universe" are basically synonymous; they refer to the same kind of kernel object. 20 | 21 | A small distinction that's sometimes made is that "universe parameter" may be implicitly restricted to levels that are variables/parameters. This is because "universe parameters" refers to the set of levels that parameterize a Lean declaration, which can only be identifiers, and are therefore restricted to identifiers. If this doesn't mean anything to you, don't worry about it for now. As an example, a Lean declaration may begin with `def Foo.{u} ..` meaning "a definition parameterized by the universe variable `u`", but it may not begin with `def Foo.{1} ..`, because `1` is an explicit level, and not a parameter. 22 | 23 | On the other hand, `Sort _` is an expression that represents a level. 24 | 25 | ## Value vs. type 26 | 27 | Expressions can be either values or types. Readers are probably familiar with the idea that `Nat.zero` is a value, while `Nat` is a type. An expression `e` is a value or "value level expression" if `infer e != Sort _`. An expression `e` is a type or "type level expression" if `infer(e) = Sort _`. 28 | 29 | 30 | ## Parameters vs. indices 31 | 32 | The distinction between a parameter and index comes into play when dealing with inductive types. Roughly speaking, elements of a telescope that come before the colon in a declaration are parameters, and elements that come after the colon are indices: 33 | 34 | ``` 35 | parameter ----v v---- index 36 | inductive Nat.le (n : Nat) : Nat → Prop 37 | ``` 38 | 39 | The distinction is non-negligible within the kernel, because parameters are fixed within a declaration, while indices are not. 40 | -------------------------------------------------------------------------------- /src/kernel_concepts/instantiation_and_abstraction.md: -------------------------------------------------------------------------------- 1 | # Instantiation and abstraction 2 | 3 | Instantiation refers to substitution of bound variables for the appropriate arguments. Abstraction refers to replacement of free variables with the appropriate bound variable when replacing binders. Lean's kernel uses deBruijn indices for bound variables and unique identifiers for free variables. 4 | 5 | For our purposes, a free variable is a variable in an expression that refers to a binder which has been "opened", and is no longer immediately available to us, so we replace the corresponding bound variable with a free variable that has some information about the binder we're leaving behind. 6 | 7 | To illustrate, let's say we have some lambda expression `(fun (x : A) => )` and we're doing type inference. Type inference has to traverse into the `` part of the expression, which may contain a bound variable that refers to `x`. When we traverse into the body, we can either add `x` to some stateful context of binders and take the whole stateful context into the body with us, or we can temporarily replace all of the bound variables that refer to `x` with a free variable, allowing us to traverse into the body without having to carry any additional context. 8 | 9 | If we eventually come back to where we were before we opened the binder, abstraction allows us to replace all of the free variables that were once bound variables referring to `x` with new bound variables that again refer to `x`, with the correct deBruijn indices. 10 | 11 | ## Implementing free variable abstraction 12 | 13 | For deBruijn levels, the free variables keep track of a number that says "I am a free variable representing the nth bound variable *from the top of the telescope*". 14 | 15 | This is the opposite of a deBruijn index, which is a number indicating "the nth bound variable from the bottom of the telescope". 16 | 17 | Top and bottom here refer to visualizing the expression's telescope as a tree: 18 | 19 | ``` 20 | fun 21 | / \ 22 | a fun 23 | / \ 24 | b ... 25 | \ 26 | fun 27 | / \ 28 | e bvar(0) 29 | ``` 30 | 31 | For example, with a lambda `fun (a b c d e) => bvar(0)`, the bound variable refers to `e`, by referencing "the 0th from the bottom". 32 | 33 | In the lambda expression `fun (a b c d e) => fvar(4)`, the free variable is a deBruijn level representing `e` again, but this time as "the 4th from the top of the telescope". 34 | 35 | Why the distinction? When we create a free variable during strong reduction, we know a couple of things: we know that the free variable we're about to sub in might get moved around by further reduction, we know how many open binder are *ABOVE* us (because we had to visit them to get here), and we know we might need to quote/abstract this expression to replace the binders, meaning we need to re-bind the free variable. However, in that moment, we do NOT know how many binders remain below us, so we cannot say how many variables from the bottom that variable might be when it's eventually abstracted/quoted. 36 | 37 | For implementations using unique identifiers to tag free variables, this problem is solved by having the actual telescope that's being reconstructed during abstraction. As long as you have the expression and a list of the uniquely-tagged free variables, you can abstract, because the position of the free variables within the list indicates their binder position. 38 | 39 | -------------------------------------------------------------------------------- /src/kernel_concepts/kernel_concepts.md: -------------------------------------------------------------------------------- 1 | 2 | # Kernel concepts 3 | 4 | This chapter begins with a high level road map, which everyone should read, then covers some ideas needed to understand the kernel's nuts and bolts, and is less focused on theory. The ideas in the later sections do not need to be completely understood up-front, so readers should feel free to skim them and come back as needed. -------------------------------------------------------------------------------- /src/kernel_concepts/the_big_picture.md: -------------------------------------------------------------------------------- 1 | # The big picture 2 | 3 | To give the reader a road map, the entire procedure of checking an export file consists of these steps: 4 | 5 | + Parse an export file, yielding a collection of components for each primitive sort: names, levels, and expressions, as well as a collection of declarations. 6 | 7 | + The collection of parsed declarations represents an environment, which is a mapping from each declaration's name to the declaration itself; these are the actual targets of the type checking process. 8 | 9 | + For each declaration in the environment, the kernel requires that the declaration is not already declared in the environment, has no duplicate universe parameters, that the declaration's type is actually a type and not a value (that `infer declar.ty` returns an expression `Sort `), and that the declaration's type has no free variables. 10 | 11 | + For definitions, theorems, and opaque declarations, assert that inferring the type of the definition's value yields an expression which is definitionally equal to the type the user assigned to the declaration. This is where the rubber meets the road in terms of asserting that proofs are correct, and for theorems, this is the step that corresponds to "the user says this is a proof of `P`, does the value actually constitute a valid proof of `P`". 12 | 13 | + For inductive declarations, their constructors, and recursors, check that they are properly formed and comply with the rules of Lean's type theory (more on this later). 14 | 15 | + If the export file includes the primitive declarations for quotient types, ensure those declarations have the correct types, and that the `Eq` type exists, and is defined properly (since quotients rely on equality). 16 | 17 | + Finally, pretty print any declarations requested by the user, so they can check that the declarations checked match the declarations they exported. 18 | 19 | -------------------------------------------------------------------------------- /src/kernel_concepts/weak_and_strong_reduction.md: -------------------------------------------------------------------------------- 1 | # Weak and strong reduction 2 | 3 | The implementation details of Lean's reduction strategies is discussed in [another chapter](../type_checking/reduction.md); this section is specifically to clarify the difference between the general concepts of weak and strong reduction. 4 | 5 | ## Weak reduction 6 | 7 | Weak reduction refers to reduction that stops at binders which do not have an argument applied to them. By binders, we mean lambda, pi, and let expressions. 8 | 9 | For example, weak reduction can reduce `(fun (x y : Nat) => y + x) (0 : Nat)` to `(fun (y : Nat) => y + 0)`, but can do no further reduction. 10 | 11 | When we say or 'weak head normal form reduction', or just reduction without specifically identifying it as 'strong', we're talking about weak reduction. Strong reduction just happens as a byproduct of applying weak reduction after we've opened a binder somewhere else. 12 | 13 | ## Strong reduction 14 | 15 | Strong reduction refers to reduction under open binders; when we run across a binder without an accompanying argument (like a lambda expression with no `app` node applying an argument), we can traverse into the body and potentially do further reduction by creating and substituting in a free variable. Strong reduction is needed for type inference and definitional equality checking. For type inference, we also need the ability to "re-close" open terms, replacing free variables with the correct bound variables after some reduction has been done in the body. This is not as simple as just replacing it with the same bound variable as before, because bound variables may have shifted, invalidating their old deBruijn index relative to the new rebuilt expression. 16 | 17 | As with weak reduction, strong reduction can still reduce `(fun (x y : Nat) => y + x) (0 : Nat)` to `(fun (y : Nat) => y + 0)`, and instead of getting stuck, it can continue by substituting `y` for a free variable, reducing the expression further to `((fVar id, y, Nat) + 0)`, and `(fvar id, y, Nat)`. 18 | 19 | As long as we keep the free variable information around _somewhere_, we can re-combine that information with the reduced `(fVar id, y, Nat)` to recreate `(fun (y : Nat) => bvar(0))` 20 | -------------------------------------------------------------------------------- /src/levels.md: -------------------------------------------------------------------------------- 1 | # Universe levels 2 | 3 | This section will describe universe levels from an implementation perspective, and will cover what readers need to know when it comes to type checking Lean declarations. More in-depth treatment of their role in Lean's type theory can be found in [TPIL4](https://lean-lang.org/theorem_proving_in_lean4/dependent_type_theory.html#types-as-objects), or section 2 of [Mario Carneiro's thesis](https://github.com/digama0/lean-type-theory) 4 | 5 | The syntax for universe levels is as follows: 6 | 7 | ``` 8 | Level ::= Zero | Succ Level | Max Level Level | IMax Level Level | Param Name 9 | ``` 10 | 11 | Properties of the `Level` type that readers should take note of are the existence of a partial order on universe levels, the presence of variables (the `Param` constructor), and the distinction between `Max` and `IMax`. 12 | 13 | `Max` simply constructs a universe level that represents the larger of the left and right arguments. For example, `Max(1, 2)` simplifies to `2`, and `Max(u, u+1)` simplifies to `u+1`. The `IMax` constructor represents the larger of the left and right arguments, *unless* the right argument simplifies to `Zero`, in which case the entire `IMax` resolves to `0`. 14 | 15 | The important part about `IMax` is its interaction with the type inference procedure to ensure that, for example, `forall (x y : Sort 3), Nat` is inferred as `Sort 4`, but `forall (x y : Sort 3), True` is inferred as `Prop`. 16 | 17 | ## Partial order on levels 18 | 19 | Lean's `Level` type is equipped with a partial order, meaning there's a "less than or equals" test we can perform on pairs of levels. The rather nice implementation below comes from Gabriel Ebner's Lean 3 checker [trepplein](https://github.com/gebner/trepplein/tree/master). While there are quite a few cases that need to be covered, the only complex matches are those relying on `cases`, which checks whether `x ≤ y` by examining whether `x ≤ y` holds when a parameter `p` is substituted for `Zero`, and when `p` is substituted for `Succ p`. 20 | 21 | ``` 22 | leq (x y : Level) (balance : Integer): bool := 23 | Zero, _ if balance >= 0 => true 24 | _, Zero if balance < 0 => false 25 | Param(i), Param(j) => i == j && balance >= 0 26 | Param(_), Zero => false 27 | Zero, Param(_) => balance >= 0 28 | Succ(l1_), _ => leq l1_ l2 (balance - 1) 29 | _, Succ(l2_) => leq l1 l2_ (balance + 1) 30 | 31 | -- descend left 32 | Max(a, b), _ => (leq a l2 balance) && (leq b l2 balance) 33 | 34 | -- descend right 35 | (Param(_) | Zero), Max(a, b) => (leq l1 a balance) || (leq l1 b balance) 36 | 37 | -- imax 38 | IMax(a1, b1), IMax(a2, b2) if a1 == a2 && b1 == b2 => true 39 | IMax(_, p @ Param(_)), _ => cases(p) 40 | _, IMax(_, p @ Param(_)) => cases(p) 41 | IMax(a, IMax(b, c)), _ => leq Max(IMax(a, c), IMax(b, c)) l2 balance 42 | IMax(a, Max(b, c)), _ => leq (simplify Max(IMax(a, b), IMax(a, c))) l2 balance 43 | _, IMax(a, IMax(b, c)) => leq l1 Max(IMax(a, c), IMax(b, c)) balance 44 | _, IMax(a, Max(b, c)) => leq l1 (simplify Max(IMax(a, b), IMax(a, c))) balance 45 | 46 | 47 | cases l1 l2 p: bool := 48 | leq (simplify $ subst l1 p zero) (simplify $ subst l2 p zero) 49 | ∧ 50 | leq (simplify $ subst l1 p (Succ p)) (simplify $ subst l2 p (Succ p)) 51 | ``` 52 | 53 | ## Equality for levels 54 | 55 | The `Level` type recognizes equality by antisymmetry, meaning two levels `l1` and `l2` are equal if `l1 ≤ l2` and `l2 ≤ l1`. 56 | 57 | # Implementation notes 58 | 59 | Be aware that the exporter does not export `Zero`, but it is assumed to be the 0th element of `Level`. 60 | 61 | For what it's worth, the implementation of `Level` does not have a large impact on performance, so don't feel the need to aggressively optimize here. 62 | -------------------------------------------------------------------------------- /src/names.md: -------------------------------------------------------------------------------- 1 | # Names 2 | 3 | The first of the kernel's primitive types is `Name`, which is sort of what it sounds like; it provides kernel items with a way of addressing things. 4 | 5 | ``` 6 | Name ::= anonymous | str Name String | num Name Nat 7 | ``` 8 | 9 | Elements of the `Name` type are displayed as dot-separated names, which users of Lean are probably familiar with. For example, `num (str (anonymous) "foo") 7` is displayed as `foo.7`. 10 | 11 | # Implementation notes 12 | 13 | The implementation of names assumes UTF-8 strings, with characters as unicode scalars (these assumptions about the implementing language's string type are also important for the string literal kernel extension). 14 | 15 | Some information on the lexical structure of names can be found [here](https://github.com/leanprover/lean4/blob/504b6dc93f46785ccddb8c5ff4a8df5be513d887/doc/lexical_structure.md?plain=1#L40) 16 | 17 | The exporter does not explicitly output the anonymous name, and expects it to be the 0th element of the imported names. 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/title_page.md: -------------------------------------------------------------------------------- 1 | # Type Checking in Lean 4 2 | 3 | This document exists to help readers better understand Lean's kernel, clarify the trust assumptions involved in using Lean, and serve as a resource for those who wish to write their own external type checkers for Lean's kernel language. 4 | -------------------------------------------------------------------------------- /src/trust/adversarial_inputs.md: -------------------------------------------------------------------------------- 1 | # Adversarial inputs 2 | 3 | A topic that often accompanies the more general trust question is Lean's robustness against adversarial inputs. 4 | 5 | A correct type checker will restrict the input it receives to the rules of Lean's type system under whatever axioms the operator allows. If the operator restricts the permitted axioms to the three "official" ones (`propext`, `Quot.sound`, `Classical.choice`), an input file should not be able to offer a proof of the prelude's `False` which is accepted by the type checker under any circumstances. 6 | 7 | However, a minimal type checker will not actively protect against inputs which provide Lean declarations that are logically sound, but are designed to fool a human operator. For example, redefining deep dependencies an adversary knows will not be examined by a referee, or introducing unicode lookalikes to produce a pretty printer output that conceals modification of key definitions. 8 | 9 | The idea that "a user might think a theorem has been formally proved, while in fact he or she 10 | is misled about what it is that the system has actually done" is addressed by the idea of Pollack consistency and is explored in this publication[^pollack] by Freek Wiedijk. 11 | 12 | Note that there is nothing in principle preventing developers from writing software or extending a type checker to provide protection against such attacks, it's just not captured by the minimal functionality required by the kernel. However, the extent to which Lean's users have embraced its powerful custom syntax and macro systems may pose some challenges for those interested in improving the story here. Readers should consider this somewhat of an [open issue for future work](../future_work.md#improving-pollack-consistency) 13 | 14 | [^pollack]: Freek Wiedijk. Pollack-inconsistency. Electronic Notes in Theoretical Computer Science, 285:85–100, 2012 15 | -------------------------------------------------------------------------------- /src/trust/trust.md: -------------------------------------------------------------------------------- 1 | 2 | # Trust 3 | 4 | A big part of Lean's value proposition is the ability to construct mathematical proofs, including proofs about program correctness. A common question from users is how much trust, and in what exactly, is involved in trusting Lean. 5 | 6 | An answer to this question has two parts: what users need to trust in order to trust proofs in Lean, and what users need to trust in order to trust executable programs obtained by compiling a Lean program. 7 | 8 | Concretely, the distinction is that proofs (which includes statements about programs) and uncompiled programs can be expressed directly in Lean's kernel language and checked by an implementation of the kernel. They do not need to be compiled to an executable, therefore the trust is limited to whatever implementation of the kernel they're being checked with, and the Lean compiler does not become part of the trusted code base. 9 | 10 | Trusting the correctness of compiled Lean programs requires trust in Lean's compiler, which is separate from the kernel and is not part of Lean's core logic. There is a distinction between trusting _statements about programs_ in Lean, and trusting _programs produced by the Lean compiler_. Statements about Lean programs are proofs, and fall into the category that only requires trust in the kernel. Trusting that proofs about a program _extend to the behavior of a compiled program_ brings the compiler into the trusted code base. 11 | 12 | **NOTE**: Tactics and other metaprograms, even tactics that are compiled, do *not* need to be trusted _at all_; they are untrusted code which is used to produce kernel terms for use by something else. A proposition `P` can be proved in Lean using an arbitrarily complex compiled metaprogram without expanding the trusted code base beyond the kernel, because the metaprogram is required to produce a proof expressed in Lean's kernel language. 13 | 14 | + These statements hold for proofs that are [exported](../export_format.md). To satisfy more ~~pedantic~~ vigilant readers, this does necessarily entail some degree of trust in, for example, the operating system on the computer used to run the exporter and verifier, the hardware, etc. 15 | 16 | + For proofs that are not exported, users are additionally trusting the elements of Lean outside the kernel (the elaborator, parser, etc.). 17 | 18 | ## A more itemized list 19 | 20 | A more itemized description of the trust involved in Lean 4 comes from a post by Mario Carneiro on the Lean Zulip. 21 | 22 | > In general: 23 | > 24 | > 1. You trust that the lean logic is sound (author's note: this would include any kernel extensions, like those for Nat and String) 25 | > 26 | > 2. If you didn't prove the program correct, you trust that the elaborator has converted your input into the lean expression denoting the program you expect. 27 | > 28 | > 3. If you did prove the program correct, you trust that the proofs about the program have been checked (use external checkers to eliminate this) 29 | > 30 | > 4. You trust that the hardware / firmware / OS software running all of these things didn't break or lie to you 31 | > 32 | > 5. (When running the program) You trust that the hardware / firmware / OS software faithfully executes the program according to spec and there are no debuggers or magnets on the hard drive or cosmic rays messing with your output 33 | > 34 | > For compiled executables: 35 | > 36 | > 6. You trust that any compiler overrides (extern / implemented_by) do not violate the lean logic (i.e. the model matches the implementation) 37 | > 38 | > 7. You trust the lean compiler (which lowered the lean code to C) to preserve the semantics of the program 39 | > 40 | > 8. You trust clang / LLVM to convert the C program into an executable with the same semantics 41 | 42 | The first set of points applies to both proofs and compiled executables, while the second set applies specifically to compiled executable programs. 43 | 44 | ## Trust for external checkers 45 | 46 | 1. You're still trusting Lean's logic is sound. 47 | 48 | 2. You're trusting that the developers of the external checker properly implemented the program. 49 | 50 | 3. You're trusting the implementing language's compiler or interpreter. If you run multiple external checkers, you can think of them as circles in a venn diagram; you're trusting that the part where the circles intersect is free of soundness issues. 51 | 52 | 4. For the Nat and String kernel extensions, you're probably trusting a bignum library and the UTF-8 string type of the implementing language. 53 | 54 | The advantages of using external checkers are: 55 | 56 | + Users can check their results with something that is completely disjoint from the Lean ecosystem, and is not dependent on any parts of Lean's code base. 57 | 58 | + External checkers can be written to take advantage of mature compilers or interpreters. 59 | 60 | + For kernel extensions, users can cross-check the results of multiple bignum/string implementations. 61 | 62 | + Using the export feature is the only way to get out of trusting the parts of Lean outside the kernel, so there's a benefit to doing this even if the export file is checked by something like [lean4lean](https://github.com/digama0/lean4lean/tree/master). Users worried about fallout from misuse of Lean's metaprogramming features are therefore encouraged to use the export feature. 63 | -------------------------------------------------------------------------------- /src/trust/unsafe_declarations.md: -------------------------------------------------------------------------------- 1 | # Unsafe declarations 2 | 3 | Lean's vernacular allows users to write declarations marked as `unsafe`, which are permitted to do things that are normally forbidden. For example, Lean permits the following definition: 4 | 5 | ``` 6 | unsafe def y : Nat := y 7 | ``` 8 | 9 | Unsafe declarations are not exported[^note1], do not need to be trusted, and (for the record) are not permitted in proofs, even in the vernacular. Permitting unsafe declarations in the vernacular is still beneficial for Lean users, because it gives users more freedom when writing code that is used to produce proofs but doesn't have to be a proof in and of itself. 10 | 11 | The aesop library provides us with an excellent real world example. [Aesop](https://github.com/leanprover-community/aesop) is an automation framework; it helps users generate proofs. At some point in development, the authors of aesop felt that the best way to express a certain part of their system was with a mutually defined inductive type, [seen here](https://github.com/leanprover-community/aesop/blob/69404390bdc1de946bf0a2e51b1a69f308e56d7a/Aesop/Tree/Data.lean#L375). It just so happens that this set of inductive type has an invalid occurrence of one of the types being declared within Lean's theory, and would not be permitted by Lean's kernel, so it needs to be marked `unsafe`. 12 | 13 | Permitting this definition as an `unsafe` declaration is still a win-win. The Aesop developers were able to use Lean to write their library the way they wanted, in Lean, without having to call out to (and learn) a separate metaprogramming DSL, they didn't have to jump through hoops to satisfy the kernel, and users of aesop can still export and verify the proofs produced *by* aesop without having to verify aesop itself. 14 | 15 | [^note1]: There's technically nothing preventing an unsafe declaration from being put in an export file (especially since the exporter is not a trusted component), but checks run by the kernel will prevent unsafe declarations from being added to the environment if they are actually unsafe. A properly implemented type checker would throw an error if it received an export file declaring the aesop library code described above. 16 | -------------------------------------------------------------------------------- /src/type_checking/definitional_equality.md: -------------------------------------------------------------------------------- 1 | # Definitional equality 2 | 3 | Definitional equality is implemented as a function that takes two expressions as input, and returns `true` if the two expressions are definitionally equal within Lean's theory, and `false` if they are not. 4 | 5 | Within the kernel, definitional equality is important simply because it's a necessary part of type checking. Definitional equality is still an important concept for Lean users who do not venture into the kernel, because definitional equalities are comparatively nice to work with in Lean's vernacular; for any `a` and `b` that are definitionally equal, Lean doesn't need any prompting or additional input from the user to determine whether two expressions are equal. 6 | 7 | There are two big-picture parts of implementing the definitional equality procedure. First, the individual tests that are used to check for different definitional equalities. For readers who are just interested in understanding definitional equality from the perspective of an end user, this is probably what you want to know. 8 | 9 | Readers interested in writing a type checker should also understand how the individual checks are composed along with reduction and caching to make the problem tractable; naively running each check and reducing along the way is likely to yield unacceptable performance results. 10 | 11 | ## Sort equality 12 | 13 | Two `Sort` expressions are definitionally equal if the levels they represent are equal by antisymmetry using the partial order on levels. 14 | 15 | ``` 16 | defEq (Sort x) (Sort y): 17 | x ≤ y ∧ y ≤ x 18 | ``` 19 | 20 | ## Const equality 21 | 22 | Two `Const` expressions are definitionally equal if their names are identical, and their levels are equal under antisymmetry. 23 | 24 | ``` 25 | defEq (Const n xs) (Const m ys): 26 | n == m ∧ forall (x, y) in (xs, ys), antisymmEq x y 27 | 28 | -- also assert that xs and ys have the same length if your `zip` doesn't do so. 29 | ``` 30 | 31 | ## Bound Variables 32 | 33 | For implementations using a substitution-based strategy like locally nameless (if you're following the C++ or lean4lean implementations, this is you), encountering a bound variable is an error; bound variables should have been replaced during weak reduction if they referred to an argument, or they should have been replaced with a free variable via strong reduction as part of a definitional equality check for a pi or lambda expression. 34 | 35 | For closure-based implementations, look up the elements corresponding to the bound variables and assert that they are definitionally equal. 36 | 37 | ## Free Variables 38 | 39 | Two free variables are definitionally equal if they have the same identifier (unique ID or deBruijn level). Assertions about the equality of the binder types should have been performed wherever the free variables were constructed (like the definitional equality check for pi/lambda expressions), so it is not necessary to re-check that now. 40 | 41 | ``` 42 | defEqFVar (id1, _) (id2, _): 43 | id1 == id2 44 | ``` 45 | 46 | ## App 47 | 48 | Two application expressions are definitionally equal if their function component and argument components are definitionally equal. 49 | 50 | ``` 51 | defEqApp (App f a) (App g b): 52 | defEq f g && defEq a b 53 | ``` 54 | 55 | 56 | ## Pi 57 | 58 | Two Pi expressions are definitionally equal if their binder types are definitionally equal, and their body types, after substituting in the appropriate free variable, are definitionally equal. 59 | 60 | ``` 61 | defEq (Pi s a) (Pi t b) 62 | if defEq s.type t.type 63 | then 64 | let thisFvar := fvar s 65 | defEq (inst a thisFvar) (inst b thisFvar) 66 | else 67 | false 68 | ``` 69 | 70 | ## Lambda 71 | 72 | Lambda uses the same test as Pi: 73 | 74 | ``` 75 | defEq (Lambda s a) (Lambda t b) 76 | if defEq s.type t.type 77 | then 78 | let thisFvar := fvar s 79 | defEq (inst a thisFvar) (inst b thisFvar) 80 | else 81 | false 82 | ``` 83 | 84 | ## Structural eta 85 | 86 | Lean recognizes definitional equality of two elements `x` and `y` if they're both instances of some structure type, and the fields are definitionally equal using the following procedure comparing the constructor arguments of one and the projected fields of the other: 87 | 88 | ``` 89 | defEqEtaStruct x y: 90 | let (yF, yArgs) := unfoldApps y 91 | if 92 | yF is a constructor for an inductive type `T` 93 | && `T` can be a struct 94 | && yArgs.len == T.numParams + T.numFields 95 | && defEq (infer x) (infer y) 96 | then 97 | forall i in 0..t.numFields, defEq Proj(i+T.numParams, x) yArgs[i+T.numParams] 98 | 99 | -- we add `T.numParams` to the index because we only want 100 | -- to test the non-param arguments. we already know the 101 | -- parameters are defEq because the inferred types are 102 | -- definitionally equal. 103 | ``` 104 | 105 | The more pedestrian case of congruence `T.mk a .. N` = `T.mk x .. M` if `[a, .., N] = [x, .., M]`, is simply handled by the `App` test. 106 | 107 | ## Unit-like equality 108 | 109 | Lean recognizes definitional equality of two elements `x: S p_0 .. p_N` and `y: T p_0 .. p_M` under the following conditions: 110 | 111 | + `S` is an inductive type 112 | + `S` has no indices 113 | + `S` has only one constructor which takes no arguments other than the parameters of `S`, `p_0 .. p_N` 114 | + The types `S p_0 .. p_N` and `T p0 .. p_M` are definitionally equal 115 | 116 | Intuitively this definitional equality is fine, because all of the information that elements of these types can convey is captured by their types, and we're requiring those types to be definitionally equal. 117 | 118 | ## Eta expansion 119 | 120 | ``` 121 | defEqEtaExpansion x y : bool := 122 | match x, (whnf $ infer y) with 123 | | Lambda .., Pi binder _ => defEq x (App (Lambda binder (Var 0)) y) 124 | | _, _ => false 125 | ``` 126 | 127 | The lambda created on the right, `(fun _ => $0) y` trivially reduces to `y`, but the addition of the lambda binder gives the `x` and `y'` a chance to match with the rest of the definitional equality procedure. 128 | 129 | ## Proof irrelevant equality 130 | 131 | Lean treats proof irrelevant equality as definitional. For example, Lean's definitional equality procedure treats any two proofs of `2 + 2 = 4` as definitionally equal expressions. 132 | 133 | If a type `T` infers as `Sort 0`, we know it's a proof, because it is an element of `Prop` (remember that `Prop` is `Sort 0`). 134 | 135 | ``` 136 | defEqByProofIrrelevance p q : 137 | infer(p) == S ∧ 138 | infer(q) == T ∧ 139 | infer(S) == Sort(0) ∧ 140 | infer(T) == Sort(0) ∧ 141 | defEq(S, T) 142 | ``` 143 | 144 | If `p` is a proof of type `A` and `q` is a proof of type `B`, then if `A` is definitionally equal to `B`, `p` and `q` are definitionally equal by proof irrelevance. 145 | 146 | ## Natural numbers (nat literals) 147 | 148 | Two nat literals are definitionally equal if they can be reduced to `Nat.zero`, or they can be reduced as (`Nat.succ x`, `Nat.succ y`), where `x` and `y` are definitionally equal. 149 | 150 | ``` 151 | match X, Y with 152 | | Nat.zero, Nat.zero => true 153 | | NatLit 0, NatLit 0 => true 154 | | Nat.succ x, NatLit (y+1) => defEq x (NatLit y) 155 | | NatLit (x+1), Nat.succ y => defEq (NatLit x) y 156 | | NatLit (x+1), NatLit (y+1) => x == y 157 | | _, _ => false 158 | ``` 159 | 160 | ## String literal 161 | 162 | `StringLit(s), App(String.mk, a)` 163 | 164 | The string literal `s` is converted to an application of `Const(String.mk, [])` to a `List Char`. Because Lean's `Char` type is used to represent unicode scalar values, their integer representation is a 32-bit unsigned integer. 165 | 166 | To illustrate, the string literal "ok", which uses two characters corresponding to the 32 bit unsigned integers `111` and `107` is converted to: 167 | 168 | >(String.mk (((List.cons Char) (Char.ofNat.[] NatLit(111))) (((List.cons Char) (Char.ofNat NatLit(107))) (List.nil Char)))) 169 | 170 | ## Lazy delta reduction and congruence 171 | 172 | The available kernel implementations implement a "lazy delta reduction" procedure as part of the definitional equality check, which unfolds definitions lazily using [reducibility hints](./declarations.md#reducibility-hints) and checks for congruence when things look promising. This is a much more efficient strategy than eagerly reducing both expressions completely before checking for definitional equality. 173 | 174 | If we have two expressions `a` and `b`, where `a` is an application of a definition with height 10, and `b` is an application of a definition with height 12, the lazy delta procedure takes the more efficient route of unfolding `b` to try and get closer to `a`, as opposed to unfolding both of them completely, or blindly choosing one side to unfold. 175 | 176 | If the lazy delta procedure finds two expressions which are an application of a `const` expression to arguments, and the `const` expressions refer to the same declaration, the expressions are checked for congruence (whether they're the same consts applied to definitionally equal arguments). Congruence failures are cached, and for readers writing their own kernel, caching these failures turns out to be a performance critical optimization, since the congruence check involves a potentially expensive call to `def_eq_args`. 177 | 178 | ## Syntactic equality (also structural or pointer equality) 179 | 180 | Two expressions are definitionally equal if they refer to exactly the same implementing object, as long as the type checker ensures that two objects are equal if and only if they are constructed from the same components (where the relevant constructors are those for Name, Level, and Expr). -------------------------------------------------------------------------------- /src/type_checking/reduction.md: -------------------------------------------------------------------------------- 1 | # Reduction 2 | 3 | Reduction is about nudging expressions toward their [normal form](https://en.wikipedia.org/wiki/Normal_form_(abstract_rewriting)) so we can determine whether expressions are definitionally equal. For example, we need to perform beta reduction to determine that `(fun x => x) Nat.zero` is definitionally equal to `Nat.zero`, and delta reduction to determine that `id List.nil` is definitionally equal to `List.nil`. 4 | 5 | Reduction in Lean's kernel has two properties that introduce concerns which sometimes go unaddressed in basic textbook treatments of the topic. First, reduction in some cases is interleaved with inference. Among other things, this means reduction may need to be performed with open terms, even though the reduction procedures themselves are not creating free variables. Second, `const` expressions which are applied to multiple arguments may need to be considered together with those arguments during reduction (as in iota reduction), so sequences of applications need to be unfolded together at the beginning of reduction. 6 | 7 | ## Beta reduction 8 | 9 | Beta reduction is about reducing function application. Concretely, the reduction: 10 | 11 | ``` 12 | (fun x => x) a ~~> a 13 | ``` 14 | 15 | An implementation of beta reduction must despine an expression to collect any arguments in `app` expressions, check whether the expression to which they're applied is a lambda, then substitute the appropriate argument for any appearances of the corresponding bound variable in the function body: 16 | 17 | ``` 18 | betaReduce e: 19 | betaReduceAux e.unfoldApps 20 | 21 | betaReduceAux f args: 22 | match f, args with 23 | | lambda _ body, arg :: rest => betaReduceAux (inst body arg) rest 24 | | _, _ => foldApps f args 25 | ``` 26 | 27 | An important performance optimization for the instantiation (substitution) component of beta reduction is what's sometimes referred to as "generalized beta reduction", which involves gathering the arguments that have a corresponding lambda and substituting them in all at once. This optimization means that for `n` sequential lambda expressions with applied arguments, we only perform one traversal of the expression to substitute the appropriate arguments, instead of `n` traversals. 28 | 29 | ``` 30 | betaReduce e: 31 | betaReduceAux e.unfoldApps [] 32 | 33 | betaReduceAux f remArgs argsToApply: 34 | match f, remArgs with 35 | | lambda _ body, arg :: rest => betaReduceAux body rest (arg :: argsToApply) 36 | | _, _ => foldApps (inst f argsToApply) remArgs 37 | ``` 38 | 39 | ## Zeta reduction (reducing `let` expressions) 40 | 41 | Zeta reduction is a fancy name for reduction of `let` expressions. Concretely, reducing 42 | 43 | ``` 44 | let (x : T) := y; x + 1 ~~> (y : T) + 1 45 | ``` 46 | 47 | An implementation can be as simple as: 48 | 49 | ``` 50 | reduce Let _ val body: 51 | instantiate body val 52 | ``` 53 | 54 | ## Delta reduction (definition unfolding) 55 | 56 | Delta reduction refers to unfolding definitions (and theorems). Delta reduction is done by replacing a `const ..` expr with the referenced declaration's value, after swapping out the declaration's generic universe parameters for the ones that are relevant to the current context. 57 | 58 | If the current environment contains a definition `x` which was declared with universe parameters `u*`and value `v`, then we may delta reduce an expression `Const(x, w*)` by replacing it with `val`, then substituting the universe parameters `u*` for those in `w*`. 59 | 60 | ``` 61 | deltaReduce Const name levels: 62 | if environment[name] == (d : Declar) && d.val == v then 63 | substituteLevels (e := v) (ks := d.uparams) (vs := levels) 64 | ``` 65 | 66 | If we had to remove any applied arguments to reach the `const` expression that was delta reduced, those arguments should be reapplied to the reduced definition. 67 | 68 | ## Projection reduction 69 | 70 | A `proj` expression has a natural number index indicating the field to be projected, and another expression which is the structure itself. The actual expression comprising the structure should be a sequence of arguments applied to `const` referencing a constructor. 71 | 72 | Keep in mind that for fully elaborated terms, the arguments to the constructor will include any parameters, so an instance of the `Prod` constructor would be e.g. `Prod.mk A B (a : A) (b : B)`. 73 | 74 | The natural number indicating the projected field is 0-based, where 0 is the first *non-parameter* argument to the constructor, since a projection cannot be used to access the structure's parameters. 75 | 76 | With this in mind, it becomes clear that once we despine the constructor's arguments into `(constructor, [arg0, .., argN])`, we can reduce the projection by simply taking the argument at position `i + num_params`, where `num_params` is what it sounds like, the number of parameters for the structure type. 77 | 78 | ``` 79 | reduce proj fieldIdx structure: 80 | let (constructorApp, args) := unfoldApps (whnf structure) 81 | let num_params := environment[constructorApp].num_params 82 | args[fieldIdx + numParams] 83 | 84 | -- Following our `Prod` example, constructorApp will be `Const(Prod.mk, [u, v])` 85 | -- args will be `[A, B, a, b]` 86 | ``` 87 | 88 | ### Special case for projections: String literals 89 | 90 | The kernel extension for string literals introduces one special case in projection reduction, and one in iota reduction. 91 | 92 | Projection reduction for string literals: Because the projection expression's structure might reduce to a string literal (Lean's `String` type is defined as a structure with one field, which is a `List Char`) 93 | 94 | If the structure reduces as a `StringLit (s)`, we convert that to `String.mk (.. : List Char)` and proceed as usual for projection reduction. 95 | 96 | 97 | 98 | ## Nat literal reduction 99 | 100 | The kernel extension for nat literals includes reduction of `Nat.succ` as well as the binary operations of addition, subtraction, multiplication, exponentiation, division, mod, boolean equality, and boolean less than or equal. 101 | 102 | If the expression being reduced is `Const(Nat.succ, []) n` where `n` can be reduced to a nat literal `n'`, we reduce to `NatLit(n'+1)` 103 | 104 | If the expression being reduced is `Const(Nat., []) x y` where `x` and `y` can be reduced to nat literals `x'` and `y'`, we apply the native version of the appropriate `` to `x'` and `y'`, returning the resulting nat literal. 105 | 106 | 107 | Examples: 108 | ``` 109 | Const(Nat.succ, []) NatLit(100) ~> NatLit(100+1) 110 | 111 | Const(Nat.add, []) NatLit(2) NatLit(3) ~> NatLit(2+3) 112 | 113 | Const(Nat.add, []) (Const Nat.succ [], NatLit(10)) NatLit(3) ~> NatLit(11+3) 114 | ``` 115 | 116 | ## Iota reduction (pattern matching) 117 | 118 | Iota reduction is about applying reduction strategies that are specific to, and derived from, a given inductive declaration. What we're talking about is application of an inductive declaration's recursor (or the special case of `Quot` which we'll see later). 119 | 120 | Each recursor has a set of "recursor rules", one recursor rule for each constructor. In contrast to the recursor, which presents as a type, these recursor rules are value level expressions showing how to eliminate an element of type `T` created with constructor `T.c`. For example, `Nat.rec` has a recursor rule for `Nat.zero`, and another for `Nat.succ`. 121 | 122 | For an inductive declaration `T`, one of the elements demanded by `T`'s recursor is an actual `(t : T)`, which is the thing we're eliminating. This `(t : T)` argument is known as the "major premise". Iota reduction performs pattern matching by taking apart the major premise to see what constructor was used to make `t`, then retrieving and applying the corresponding recursor rule from the environment. 123 | 124 | Because the recursor's type signature also demands the parameters, motives, and minor premises required, we don't need to change the arguments to the recursor to perform reduction on e.g. `Nat.zero` as opposed to `Nat.succ`. 125 | 126 | In practice, it's sometimes necessary to do some initial manipulation to expose the constructor used to create the major premise, since it may not be found as a direct application of a constructor. For example, a `NatLit(n)` expression will need to be transformed into either `Nat.zero`, or `App Const(Nat.succ, []) ..`. For structures, we may also perform structural eta expansion, transforming an element `(t : T)` into `T.mk t.1 .. t.N`, thereby exposing the application of the `mk` constructor, permitting iota reduction to proceed (if we can't figure out what constructor was used to create the major premise, reduction fails). 127 | 128 | ## List.rec type 129 | 130 | ``` 131 | forall 132 | {α : Type.{u}} 133 | {motive : (List.{u} α) -> Sort.{u_1}}, 134 | (motive (List.nil.{u} α)) -> 135 | (forall (head : α) (tail : List.{u} α), (motive tail) -> (motive (List.cons.{u} α head tail))) -> (forall (t : List.{u} α), motive t) 136 | ``` 137 | 138 | ## List.nil rec rule 139 | 140 | ``` 141 | fun 142 | (α : Type.{u}) 143 | (motive : (List.{u} α) -> Sort.{u_1}) 144 | (nilCase : motive (List.nil.{u} α)) 145 | (consCase : forall (head : α) (tail : List.{u} α), (motive tail) -> (motive (List.cons.{u} α head tail))) => 146 | nilCase 147 | ``` 148 | 149 | ## List.cons rec rule 150 | 151 | ``` 152 | fun 153 | (α : Type.{u}) 154 | (motive : (List.{u} α) -> Sort.{u_1}) 155 | (nilCase : motive (List.nil.{u} α)) 156 | (consCase : forall (head : α) (tail : List.{u} α), (motive tail) -> (motive (List.cons.{u} α head tail))) 157 | (head : α) 158 | (tail : List.{u} α) => 159 | consCase head tail (List.rec.{u_1, u} α motive nilCase consCase tail) 160 | ``` 161 | 162 | 163 | ### k-like reduction 164 | 165 | For some inductive types, known as "subsingleton eliminators", we can proceed with iota reduction even when the major premise's constructor is not directly exposed, as long as we know its type. This may be the case when, for example, the major premise appears as a free variable. This is known as k-like reduction, and is permitted because all elements of a subsingleton eliminator are identical. 166 | 167 | To be a subsingleton eliminator, an inductive declaration must be an inductive prop, must not be a mutual or nested inductive, must have exactly one constructor, and the sole constructor must take only the type's parameters as arguments (it cannot "hide" any information that isn't fully captured in its type signature). 168 | 169 | For example, the value of any element of the type `Eq Char 'x'` is fully determined just by its type, because all elements of this type are identical. 170 | 171 | If iota reduction finds a major premise which is a subsingleton eliminator, it is permissible to substitute the major premise for an application of the type's constructor, because that is the only element the free variable could actually be. For example, a major premise which is a free variable of type `Eq Char 'a'` may be substituted for an explicitly constructed `Eq.refl Char 'a'`. 172 | 173 | Getting to the nuts and bolts, if we neglected to look for and apply k-like reduction, free variables that are subsingleton eliminators would fail to identify the corresponding recursor rule, iota reduction would fail, and certain conversions expected to succeed would no longer succeed. 174 | 175 | ### `Quot` reduction; `Quot.ind` and `Quot.lift` 176 | 177 | `Quot` introduces two special cases which need to be handled by the kernel, one for `Quot.ind`, and one for `Quot.lift`. 178 | 179 | Both `Quot.ind` and `Quot.lift` deal with application of a function `f` to an argument `(a : α)`, where the `a` is a component of some `Quot r`, formed with `Quot.mk r a`. 180 | 181 | To execute the reduction, we need to pull out the argument that is the `f` element and the argument that is the `Quot` where we can find `(a : α)`, then apply the function `f` to `a`. Finally, we reapply any arguments that were part of some outer expression not related to the invocation of `Quot.ind` or `Quot.lift`. 182 | 183 | Since this is only a reduction step, we rely on the type checking phases done elsewhere to provide assurances that the expression as a whole is well typed. 184 | 185 | The type signatures for `Quot.ind` and `Quot.mk` are recreated below, mapping the elements of the telescope to what we should find as the arguments. The elements with a `*` are the ones we're interested in for reduction. 186 | 187 | ``` 188 | Quotient primitive Quot.ind.{u} : ∀ {α : Sort u} {r : α → α → Prop} 189 | {β : Quot r → Prop}, (∀ (a : α), β (Quot.mk r a)) → ∀ (q : Quot r), β q 190 | 191 | 0 |-> {α : Sort u} 192 | 1 |-> {r : α → α → Prop} 193 | 2 |-> {β : Quot r → Prop} 194 | 3* |-> (∀ (a : α), β (Quot.mk r a)) 195 | 4* |-> (q : Quot r) 196 | ... 197 | ``` 198 | 199 | ``` 200 | Quotient primitive Quot.lift.{u, v} : {α : Sort u} → 201 | {r : α → α → Prop} → {β : Sort v} → (f : α → β) → 202 | (∀ (a b : α), r a b → f a = f b) → Quot r → β 203 | 204 | 0 |-> {α : Sort u} 205 | 1 |-> {r : α → α → Prop} 206 | 2 |-> {β : Sort v} 207 | 3* |-> (f : α → β) 208 | 4 |-> (∀ (a b : α), r a b → f a = f b) 209 | 5* |-> Quot r 210 | ... 211 | ``` 212 | -------------------------------------------------------------------------------- /src/type_checking/type_inference.md: -------------------------------------------------------------------------------- 1 | # Type Inference 2 | 3 | Type inference is a procedure for determining the type of a given expression, and is one of the core functionalities of Lean's kernel. Type inference is how we determine that `Nat.zero` is an element of the type `Nat`, or that `(fun (x : Char) => var(0))` is an element of the type `Char -> Char`. 4 | 5 | This section begins by examining the simplest complete procedure for type inference, then the more performant but slightly more complex version of each procedure. 6 | 7 | We will also look at a number of additional correctness assertions that Lean's kernel makes during type inference. 8 | 9 | ## Bound variables 10 | 11 | If you're following Lean's implementation and using the locally nameless approach, you should not run into bound variables during type inference, because all open binders will be instantiated with the appropriate free variables. 12 | 13 | When we come across a binder, we need to traverse into the body to determine the body's type. There are two main approaches one can take to preserve the information about the binder type; the one used by Lean proper is to create a free variable that retains the binder's type information, replace the corresponding bound variables with the free variable using instantiation, and then enter the body. This is nice, because we don't have to keep track of a separate piece of state for a typing context. 14 | 15 | For closure-based implementations, you will generally have a separate typing context that keeps track of the open binders; running into a bound variable then means that you will index into your typing context to get the type of that variable. 16 | 17 | ## Free variables 18 | 19 | When a free variable is created, it's given the type information from the binder it represents, so we can just take that type information as the result of inference. 20 | 21 | ``` 22 | infer FVar id binder: 23 | binder.type 24 | ``` 25 | 26 | ## Function application 27 | 28 | ``` 29 | infer App(f, arg): 30 | match (whnf $ infer f) with 31 | | Pi binder body => 32 | assert! defEq(binder.type, infer arg) 33 | instantiate(body, arg) 34 | | _ => error 35 | ``` 36 | 37 | The additional assertion needed here is that the type of `arg` matches the type of `binder`. For example, in the expression 38 | 39 | `(fun (n : Nat) => 2 * n) 10`, we would need to assert that `defEq(Nat, infer(10))`. 40 | 41 | While existing implementations prefer to perform this check inline, one could potentially store this equality assertion for processing elsewhere. 42 | 43 | ## Lambda 44 | 45 | ``` 46 | infer Lambda(binder, body): 47 | assert! infersAsSort(binder.type) 48 | let binderFvar := fvar(binder) 49 | let bodyType := infer $ instantiate(body, binderFVar) 50 | Pi binder (abstract bodyType binderFVar) 51 | ``` 52 | 53 | # Pi 54 | 55 | ``` 56 | infer Pi binder body: 57 | let l := inferSortOf binder 58 | let r := inferSortOf $ instantiate body (fvar(binder)) 59 | imax(l, r) 60 | 61 | inferSortOf e: 62 | match (whnf (infer e)) with 63 | | sort level => level 64 | | _ => error 65 | ``` 66 | 67 | ## Sort 68 | 69 | The type of any `Sort n` is just `Sort (n+1)`. 70 | 71 | ``` 72 | infer Sort level: 73 | Sort (succ level) 74 | ``` 75 | 76 | ## Const 77 | 78 | `const` expressions are used to refer to other declarations by name, and any other declaration referred to must have been previously declared and had its type checked. Since we therefore already know what the type of the referred to declaration is, we can just look it up in the environment. We do have to substitute in the current declaration's universe levels for the indexed definition's universe parameters however. 79 | 80 | ``` 81 | infer Const name levels: 82 | let knownType := environment[name].type 83 | substituteLevels (e := knownType) (ks := knownType.uparams) (vs := levels) 84 | ``` 85 | 86 | ## Let 87 | 88 | ``` 89 | infer Let binder val body: 90 | assert! inferSortOf binder 91 | assert! defEq(infer(val), binder.type) 92 | infer (instantiate body val) 93 | ``` 94 | 95 | ## Proj 96 | 97 | We're trying to infer the type of something like `Proj (projIdx := 0) (structure := Prod.mk A B (a : A) (b : B))`. 98 | 99 | Start by inferring the type of the structure offered; from that we can get the structure name and look up the structure and constructor type in the environment. 100 | 101 | Traverse the constructor type's telescope, substituting the parameters of `Prod.mk` into the telescope for the constructor type. If we looked up the constructor type `A -> B -> (a : A) -> (b : B) -> Prod A B`, substitute A and B, leaving the telescope `(a : A) -> (b : B) -> Prod A B`. 102 | 103 | The remaining parts of the constructor's telescope represent the structure's fields and have the type information in the binder, so we can just examine `telescope[projIdx]` and take the binder type. We do have to take care of one more thing; because later structure fields can depend on earlier structure fields, we need to instantiate the rest of the telescope (the body at each stage) with `proj thisFieldIdx s` where `s` is the original structure in the proj expression we're trying to infer. 104 | 105 | ``` 106 | infer Projection(projIdx, structure): 107 | let structType := whnf (infer structure) 108 | let (const structTyName levels) tyArgs := structType.unfoldApps 109 | let InductiveInfo := env[structTyName] 110 | -- This inductive should only have the one constructor since it's claiming to be a structure. 111 | let ConstructorInfo := env[InductiveInfo.constructorNames[0]] 112 | 113 | let mut constructorType := substLevels ConstructorInfo.type (newLevels := levels) 114 | 115 | for tyArg in tyArgs.take constructorType.numParams 116 | match (whnf constructorType) with 117 | | pi _ body => inst body tyArg 118 | | _ => error 119 | 120 | for i in [0:projIdx] 121 | match (whnf constructorType) with 122 | | pi _ body => inst body (proj i structure) 123 | | _ => error 124 | 125 | match (whnf constructorType) with 126 | | pi binder _=> binder.type 127 | | _ => error 128 | ``` 129 | 130 | ## Nat literals 131 | 132 | Nat literals infer as the constant referring to the declaration `Nat`. 133 | 134 | ``` 135 | infer NatLiteral _: 136 | Const(Nat, []) 137 | ``` 138 | 139 | ## String literals 140 | 141 | String literals infer as the constant referring to the declaration `String`. 142 | 143 | ``` 144 | infer StringLiteral _: 145 | Const(String, []) 146 | ``` 147 | 148 | -------------------------------------------------------------------------------- /src/whats_a_kernel.md: -------------------------------------------------------------------------------- 1 | # What is the kernel? 2 | 3 | The kernel is an implementation of Lean's logic in software; a computer program with the minimum amount of machinery required to construct elements of Lean's logical language and check those elements for correctness. The major components are: 4 | 5 | + A sort of names used for addressing. 6 | 7 | + A sort of universe levels. 8 | 9 | + A sort of expressions (lambdas, variables, etc.) 10 | 11 | + A sort of declarations (axioms, definitions, theorems, inductive types, etc.) 12 | 13 | + Environments, which are maps of names to declarations. 14 | 15 | + Functionality for manipulating expressions. For example bound variable substitution and substitution of universe parameters. 16 | 17 | + Core operations used in type checking, including type inference, reduction, and definitional equality checking. 18 | 19 | + Functionality for manipulating and checking inductive type declarations. For example, generating a type's recursors (elimination rules), and checking whether a type's constructors agree with the type's specification. 20 | 21 | + Optional kernel extensions which permit the operations above to be performed on nat and string literals. 22 | 23 | The purpose of isolating a small kernel and requiring Lean definitions to be translated to a minimal kernel language is to increase the trustworthiness of the proof system. Lean's design allows users to interact with a full-featured proof assistant which offers nice things like robust metaprogramming, rich editor support, and extensible syntax, while also permitting extraction of constructed proof terms into a form that can be verified without having to trust the correctness of the code that implements the higher level features that makes Lean (the proof assistant) productive and pleasant to use. 24 | 25 | In section 1.2.3 of the [_Certified Programming with Dependent Types_](http://adam.chlipala.net/cpdt/), Adam Chlipala defines what is sometimes referred to as the de Bruijn criterion, or de Bruijn principle. 26 | 27 | > Proof assistants satisfy the “de Bruijn criterion” when they produce proof terms in small kernel languages, even when they use complicated and extensible procedures to seek out proofs in the first place. These core languages have feature complexity on par with what you find in proposals for formal foundations for mathematics (e.g., ZF set theory). To believe a proof, we can ignore the possibility of bugs during search and just rely on a (relatively small) proof-checking kernel that we apply to the result of the search. 28 | 29 | Lean's kernel is small enough that developers can write their own implementation and independently check proofs in Lean by using an exporter[^1]. Lean's export format contains enough information about the exported declarations that users can optionally restrict their implementation to certain subsets of the full kernel. For example, users interested in the core functionality of inference, reduction, and definitional equality may opt out of implementing the functionality for checking inductive specifications. 30 | 31 | In addition to the list of items above, external type checkers will also need a parser for [Lean's export format](./export_format.md), and a pretty printer, for input and output respectively. The parser and pretty printer are not part of the kernel, but they are important if one wants to have interesting interactions with the kernel. 32 | 33 | [^1]: Writing your own type checker is not an afternoon project, but it is well within the realm of what is achievable for citizen scientists. 34 | -------------------------------------------------------------------------------- /theme/highlight.js: -------------------------------------------------------------------------------- 1 | /* 2 | Highlight.js 10.3.2 (31e1fc40) 3 | License: BSD-3-Clause 4 | Copyright (c) 2006-2020, Ivan Sagalaev 5 | */ 6 | var hljs=function(){"use strict";function e(n){Object.freeze(n) 7 | ;var t="function"==typeof n 8 | ;return Object.getOwnPropertyNames(n).forEach((function(r){ 9 | !Object.hasOwnProperty.call(n,r)||null===n[r]||"object"!=typeof n[r]&&"function"!=typeof n[r]||t&&("caller"===r||"callee"===r||"arguments"===r)||Object.isFrozen(n[r])||e(n[r]) 10 | })),n}class n{constructor(e){void 0===e.data&&(e.data={}),this.data=e.data} 11 | ignoreMatch(){this.ignore=!0}}function t(e){ 12 | return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'") 13 | }function r(e,...n){var t={};for(const n in e)t[n]=e[n] 14 | ;return n.forEach((function(e){for(const n in e)t[n]=e[n]})),t}function a(e){ 15 | return e.nodeName.toLowerCase()}var i=Object.freeze({__proto__:null, 16 | escapeHTML:t,inherit:r,nodeStream:function(e){var n=[];return function e(t,r){ 17 | for(var i=t.firstChild;i;i=i.nextSibling)3===i.nodeType?r+=i.nodeValue.length:1===i.nodeType&&(n.push({ 18 | event:"start",offset:r,node:i}),r=e(i,r),a(i).match(/br|hr|img|input/)||n.push({ 19 | event:"stop",offset:r,node:i}));return r}(e,0),n},mergeStreams:function(e,n,r){ 20 | var i=0,s="",o=[];function l(){ 21 | return e.length&&n.length?e[0].offset!==n[0].offset?e[0].offset"}function u(e){ 24 | s+=""}function g(e){("start"===e.event?c:u)(e.node)} 25 | for(;e.length||n.length;){var d=l() 26 | ;if(s+=t(r.substring(i,d[0].offset)),i=d[0].offset,d===e){o.reverse().forEach(u) 27 | ;do{g(d.splice(0,1)[0]),d=l()}while(d===e&&d.length&&d[0].offset===i) 28 | ;o.reverse().forEach(c) 29 | }else"start"===d[0].event?o.push(d[0].node):o.pop(),g(d.splice(0,1)[0])} 30 | return s+t(r.substr(i))}});const s=e=>!!e.kind;class o{constructor(e,n){ 31 | this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){ 32 | this.buffer+=t(e)}openNode(e){if(!s(e))return;let n=e.kind 33 | ;e.sublanguage||(n=`${this.classPrefix}${n}`),this.span(n)}closeNode(e){ 34 | s(e)&&(this.buffer+="")}value(){return this.buffer}span(e){ 35 | this.buffer+=``}}class l{constructor(){this.rootNode={ 36 | children:[]},this.stack=[this.rootNode]}get top(){ 37 | return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){ 38 | this.top.children.push(e)}openNode(e){const n={kind:e,children:[]} 39 | ;this.add(n),this.stack.push(n)}closeNode(){ 40 | if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){ 41 | for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)} 42 | walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){ 43 | return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n), 44 | n.children.forEach((n=>this._walk(e,n))),e.closeNode(n)),e}static _collapse(e){ 45 | "string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{ 46 | l._collapse(e)})))}}class c extends l{constructor(e){super(),this.options=e} 47 | addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNode())} 48 | addText(e){""!==e&&this.add(e)}addSublanguage(e,n){const t=e.root 49 | ;t.kind=n,t.sublanguage=!0,this.add(t)}toHTML(){ 50 | return new o(this,this.options).value()}finalize(){return!0}}function u(e){ 51 | return e?"string"==typeof e?e:e.source:null} 52 | const g="[a-zA-Z]\\w*",d="[a-zA-Z_]\\w*",h="\\b\\d+(\\.\\d+)?",f="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",p="\\b(0b[01]+)",m={ 53 | begin:"\\\\[\\s\\S]",relevance:0},b={className:"string",begin:"'",end:"'", 54 | illegal:"\\n",contains:[m]},v={className:"string",begin:'"',end:'"', 55 | illegal:"\\n",contains:[m]},x={ 56 | begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/ 57 | },E=function(e,n,t={}){var a=r({className:"comment",begin:e,end:n,contains:[] 58 | },t);return a.contains.push(x),a.contains.push({className:"doctag", 59 | begin:"(?:TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):",relevance:0}),a 60 | },_=E("//","$"),w=E("/\\*","\\*/"),N=E("#","$");var y=Object.freeze({ 61 | __proto__:null,IDENT_RE:g,UNDERSCORE_IDENT_RE:d,NUMBER_RE:h,C_NUMBER_RE:f, 62 | BINARY_NUMBER_RE:p, 63 | RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~", 64 | SHEBANG:(e={})=>{const n=/^#![ ]*\//;return e.binary&&(e.begin=function(...e){ 65 | return e.map((e=>u(e))).join("")}(n,/.*\b/,e.binary,/\b.*/)),r({ 66 | className:"meta",begin:n,end:/$/,relevance:0,"on:begin":(e,n)=>{ 67 | 0!==e.index&&n.ignoreMatch()}},e)},BACKSLASH_ESCAPE:m,APOS_STRING_MODE:b, 68 | QUOTE_STRING_MODE:v,PHRASAL_WORDS_MODE:x,COMMENT:E,C_LINE_COMMENT_MODE:_, 69 | C_BLOCK_COMMENT_MODE:w,HASH_COMMENT_MODE:N,NUMBER_MODE:{className:"number", 70 | begin:h,relevance:0},C_NUMBER_MODE:{className:"number",begin:f,relevance:0}, 71 | BINARY_NUMBER_MODE:{className:"number",begin:p,relevance:0},CSS_NUMBER_MODE:{ 72 | className:"number", 73 | begin:h+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?", 74 | relevance:0},REGEXP_MODE:{begin:/(?=\/[^/\n]*\/)/,contains:[{className:"regexp", 75 | begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[m,{begin:/\[/,end:/\]/, 76 | relevance:0,contains:[m]}]}]},TITLE_MODE:{className:"title",begin:g,relevance:0 77 | },UNDERSCORE_TITLE_MODE:{className:"title",begin:d,relevance:0},METHOD_GUARD:{ 78 | begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0},END_SAME_AS_BEGIN:function(e){ 79 | return Object.assign(e,{"on:begin":(e,n)=>{n.data._beginMatch=e[1]}, 80 | "on:end":(e,n)=>{n.data._beginMatch!==e[1]&&n.ignoreMatch()}})} 81 | }),R="of and for in not or if then".split(" ");function k(e){function n(n,t){ 82 | return RegExp(u(n),"m"+(e.case_insensitive?"i":"")+(t?"g":""))}class t{ 83 | constructor(){ 84 | this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0} 85 | addRule(e,n){ 86 | n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]), 87 | this.matchAt+=function(e){return RegExp(e.toString()+"|").exec("").length-1 88 | }(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null) 89 | ;const e=this.regexes.map((e=>e[1]));this.matcherRe=n(function(e,n="|"){ 90 | for(var t=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./,r=0,a="",i=0;i0&&(a+=n),a+="(";o.length>0;){var l=t.exec(o) 92 | ;if(null==l){a+=o;break} 93 | a+=o.substring(0,l.index),o=o.substring(l.index+l[0].length), 94 | "\\"===l[0][0]&&l[1]?a+="\\"+(Number(l[1])+s):(a+=l[0],"("===l[0]&&r++)}a+=")"} 95 | return a}(e),!0),this.lastIndex=0}exec(e){ 96 | this.matcherRe.lastIndex=this.lastIndex;const n=this.matcherRe.exec(e) 97 | ;if(!n)return null 98 | ;const t=n.findIndex(((e,n)=>n>0&&void 0!==e)),r=this.matchIndexes[t] 99 | ;return n.splice(0,t),Object.assign(n,r)}}class a{constructor(){ 100 | this.rules=[],this.multiRegexes=[], 101 | this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){ 102 | if(this.multiRegexes[e])return this.multiRegexes[e];const n=new t 103 | ;return this.rules.slice(e).forEach((([e,t])=>n.addRule(e,t))), 104 | n.compile(),this.multiRegexes[e]=n,n}resumingScanAtSamePosition(){ 105 | return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,n){ 106 | this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){ 107 | const n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex 108 | ;let t=n.exec(e) 109 | ;if(this.resumingScanAtSamePosition())if(t&&t.index===this.lastIndex);else{ 110 | const n=this.getMatcher(0);n.lastIndex=this.lastIndex+1,t=n.exec(e)} 111 | return t&&(this.regexIndex+=t.position+1, 112 | this.regexIndex===this.count&&this.considerAll()),t}}function i(e,n){ 113 | const t=e.input[e.index-1],r=e.input[e.index+e[0].length] 114 | ;"."!==t&&"."!==r||n.ignoreMatch()} 115 | if(e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.") 116 | ;return function t(s,o){const l=s;if(s.compiled)return l 117 | ;s.compiled=!0,s.__beforeBegin=null,s.keywords=s.keywords||s.beginKeywords 118 | ;let c=null 119 | ;if("object"==typeof s.keywords&&(c=s.keywords.$pattern,delete s.keywords.$pattern), 120 | s.keywords&&(s.keywords=function(e,n){var t={} 121 | ;return"string"==typeof e?r("keyword",e):Object.keys(e).forEach((function(n){ 122 | r(n,e[n])})),t;function r(e,r){ 123 | n&&(r=r.toLowerCase()),r.split(" ").forEach((function(n){var r=n.split("|") 124 | ;t[r[0]]=[e,O(r[0],r[1])]}))} 125 | }(s.keywords,e.case_insensitive)),s.lexemes&&c)throw Error("ERR: Prefer `keywords.$pattern` to `mode.lexemes`, BOTH are not allowed. (see mode reference) ") 126 | ;return l.keywordPatternRe=n(s.lexemes||c||/\w+/,!0), 127 | o&&(s.beginKeywords&&(s.begin="\\b("+s.beginKeywords.split(" ").join("|")+")(?=\\b|\\s)", 128 | s.__beforeBegin=i), 129 | s.begin||(s.begin=/\B|\b/),l.beginRe=n(s.begin),s.endSameAsBegin&&(s.end=s.begin), 130 | s.end||s.endsWithParent||(s.end=/\B|\b/), 131 | s.end&&(l.endRe=n(s.end)),l.terminator_end=u(s.end)||"", 132 | s.endsWithParent&&o.terminator_end&&(l.terminator_end+=(s.end?"|":"")+o.terminator_end)), 133 | s.illegal&&(l.illegalRe=n(s.illegal)), 134 | void 0===s.relevance&&(s.relevance=1),s.contains||(s.contains=[]), 135 | s.contains=[].concat(...s.contains.map((function(e){return function(e){ 136 | return e.variants&&!e.cached_variants&&(e.cached_variants=e.variants.map((function(n){ 137 | return r(e,{variants:null},n)}))),e.cached_variants?e.cached_variants:M(e)?r(e,{ 138 | starts:e.starts?r(e.starts):null}):Object.isFrozen(e)?r(e):e}("self"===e?s:e) 139 | }))),s.contains.forEach((function(e){t(e,l) 140 | })),s.starts&&t(s.starts,o),l.matcher=function(e){const n=new a 141 | ;return e.contains.forEach((e=>n.addRule(e.begin,{rule:e,type:"begin" 142 | }))),e.terminator_end&&n.addRule(e.terminator_end,{type:"end" 143 | }),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n}(l),l}(e)}function M(e){ 144 | return!!e&&(e.endsWithParent||M(e.starts))}function O(e,n){ 145 | return n?Number(n):function(e){return R.includes(e.toLowerCase())}(e)?0:1} 146 | const L={props:["language","code","autodetect"],data:function(){return{ 147 | detectedLanguage:"",unknownLanguage:!1}},computed:{className(){ 148 | return this.unknownLanguage?"":"hljs "+this.detectedLanguage},highlighted(){ 149 | if(!this.autoDetect&&!hljs.getLanguage(this.language))return console.warn(`The language "${this.language}" you specified could not be found.`), 150 | this.unknownLanguage=!0,t(this.code);let e 151 | ;return this.autoDetect?(e=hljs.highlightAuto(this.code), 152 | this.detectedLanguage=e.language):(e=hljs.highlight(this.language,this.code,this.ignoreIllegals), 153 | this.detectectLanguage=this.language),e.value},autoDetect(){ 154 | return!(this.language&&(e=this.autodetect,!e&&""!==e));var e}, 155 | ignoreIllegals:()=>!0},render(e){return e("pre",{},[e("code",{ 156 | class:this.className,domProps:{innerHTML:this.highlighted}})])}},j={install(e){ 157 | e.component("highlightjs",L)} 158 | },I=t,T=r,{nodeStream:S,mergeStreams:A}=i,B=Symbol("nomatch") 159 | ;return function(t){ 160 | var r=[],a=Object.create(null),i=Object.create(null),s=[],o=!0,l=/(^(<[^>]+>|\t|)+|\n)/gm,u="Could not find the language '{}', did you forget to load/include a language module?" 161 | ;const g={disableAutodetect:!0,name:"Plain text",contains:[]};var d={ 162 | noHighlightRe:/^(no-?highlight)$/i, 163 | languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-", 164 | tabReplace:null,useBR:!1,languages:null,__emitter:c};function h(e){ 165 | return d.noHighlightRe.test(e)}function f(e,n,t,r){var a={code:n,language:e} 166 | ;N("before:highlight",a);var i=a.result?a.result:p(a.language,a.code,t,r) 167 | ;return i.code=a.code,N("after:highlight",i),i}function p(e,t,r,i){var s=t 168 | ;function l(e,n){var t=_.case_insensitive?n[0].toLowerCase():n[0] 169 | ;return Object.prototype.hasOwnProperty.call(e.keywords,t)&&e.keywords[t]} 170 | function c(){null!=y.subLanguage?function(){if(""!==O){var e=null 171 | ;if("string"==typeof y.subLanguage){ 172 | if(!a[y.subLanguage])return void M.addText(O) 173 | ;e=p(y.subLanguage,O,!0,R[y.subLanguage]),R[y.subLanguage]=e.top 174 | }else e=m(O,y.subLanguage.length?y.subLanguage:null) 175 | ;y.relevance>0&&(L+=e.relevance),M.addSublanguage(e.emitter,e.language)} 176 | }():function(){if(!y.keywords)return void M.addText(O);let e=0 177 | ;y.keywordPatternRe.lastIndex=0;let n=y.keywordPatternRe.exec(O),t="";for(;n;){ 178 | t+=O.substring(e,n.index);const r=l(y,n);if(r){const[e,a]=r 179 | ;M.addText(t),t="",L+=a,M.addKeyword(n[0],e)}else t+=n[0] 180 | ;e=y.keywordPatternRe.lastIndex,n=y.keywordPatternRe.exec(O)} 181 | t+=O.substr(e),M.addText(t)}(),O=""}function g(e){ 182 | return e.className&&M.openNode(e.className),y=Object.create(e,{parent:{value:y} 183 | })}function h(e,t,r){let a=function(e,n){var t=e&&e.exec(n) 184 | ;return t&&0===t.index}(e.endRe,r);if(a){if(e["on:end"]){const r=new n(e) 185 | ;e["on:end"](t,r),r.ignore&&(a=!1)}if(a){for(;e.endsParent&&e.parent;)e=e.parent 186 | ;return e}}if(e.endsWithParent)return h(e.parent,t,r)}function f(e){ 187 | return 0===y.matcher.regexIndex?(O+=e[0],1):(S=!0,0)}function b(e){ 188 | var n=e[0],t=s.substr(e.index),r=h(y,e,t);if(!r)return B;var a=y 189 | ;a.skip?O+=n:(a.returnEnd||a.excludeEnd||(O+=n),c(),a.excludeEnd&&(O=n));do{ 190 | y.className&&M.closeNode(),y.skip||y.subLanguage||(L+=y.relevance),y=y.parent 191 | }while(y!==r.parent) 192 | ;return r.starts&&(r.endSameAsBegin&&(r.starts.endRe=r.endRe), 193 | g(r.starts)),a.returnEnd?0:n.length}var v={};function x(t,a){var i=a&&a[0] 194 | ;if(O+=t,null==i)return c(),0 195 | ;if("begin"===v.type&&"end"===a.type&&v.index===a.index&&""===i){ 196 | if(O+=s.slice(a.index,a.index+1),!o){const n=Error("0 width match regex") 197 | ;throw n.languageName=e,n.badRule=v.rule,n}return 1} 198 | if(v=a,"begin"===a.type)return function(e){var t=e[0],r=e.rule 199 | ;const a=new n(r),i=[r.__beforeBegin,r["on:begin"]] 200 | ;for(const n of i)if(n&&(n(e,a),a.ignore))return f(t) 201 | ;return r&&r.endSameAsBegin&&(r.endRe=RegExp(t.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")), 202 | r.skip?O+=t:(r.excludeBegin&&(O+=t), 203 | c(),r.returnBegin||r.excludeBegin||(O=t)),g(r),r.returnBegin?0:t.length}(a) 204 | ;if("illegal"===a.type&&!r){ 205 | const e=Error('Illegal lexeme "'+i+'" for mode "'+(y.className||"")+'"') 206 | ;throw e.mode=y,e}if("end"===a.type){var l=b(a);if(l!==B)return l} 207 | if("illegal"===a.type&&""===i)return 1 208 | ;if(T>1e5&&T>3*a.index)throw Error("potential infinite loop, way more iterations than matches") 209 | ;return O+=i,i.length}var _=E(e) 210 | ;if(!_)throw console.error(u.replace("{}",e)),Error('Unknown language: "'+e+'"') 211 | ;var w=k(_),N="",y=i||w,R={},M=new d.__emitter(d);!function(){ 212 | for(var e=[],n=y;n!==_;n=n.parent)n.className&&e.unshift(n.className) 213 | ;e.forEach((e=>M.openNode(e)))}();var O="",L=0,j=0,T=0,S=!1;try{ 214 | for(y.matcher.considerAll();;){ 215 | T++,S?S=!1:y.matcher.considerAll(),y.matcher.lastIndex=j 216 | ;const e=y.matcher.exec(s);if(!e)break;const n=x(s.substring(j,e.index),e) 217 | ;j=e.index+n}return x(s.substr(j)),M.closeAllNodes(),M.finalize(),N=M.toHTML(),{ 218 | relevance:L,value:N,language:e,illegal:!1,emitter:M,top:y}}catch(n){ 219 | if(n.message&&n.message.includes("Illegal"))return{illegal:!0,illegalBy:{ 220 | msg:n.message,context:s.slice(j-100,j+100),mode:n.mode},sofar:N,relevance:0, 221 | value:I(s),emitter:M};if(o)return{illegal:!1,relevance:0,value:I(s),emitter:M, 222 | language:e,top:y,errorRaised:n};throw n}}function m(e,n){ 223 | n=n||d.languages||Object.keys(a);var t=function(e){const n={relevance:0, 224 | emitter:new d.__emitter(d),value:I(e),illegal:!1,top:g} 225 | ;return n.emitter.addText(e),n}(e),r=t 226 | ;return n.filter(E).filter(w).forEach((function(n){var a=p(n,e,!1);a.language=n, 227 | a.relevance>r.relevance&&(r=a),a.relevance>t.relevance&&(r=t,t=a) 228 | })),r.language&&(t.second_best=r),t}function b(e){ 229 | return d.tabReplace||d.useBR?e.replace(l,(e=>"\n"===e?d.useBR?"
":e:d.tabReplace?e.replace(/\t/g,d.tabReplace):e)):e 230 | }function v(e){let n=null;const t=function(e){var n=e.className+" " 231 | ;n+=e.parentNode?e.parentNode.className:"";const t=d.languageDetectRe.exec(n) 232 | ;if(t){var r=E(t[1]) 233 | ;return r||(console.warn(u.replace("{}",t[1])),console.warn("Falling back to no-highlight mode for this block.",e)), 234 | r?t[1]:"no-highlight"}return n.split(/\s+/).find((e=>h(e)||E(e)))}(e) 235 | ;if(h(t))return;N("before:highlightBlock",{block:e,language:t 236 | }),d.useBR?(n=document.createElement("div"), 237 | n.innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n")):n=e 238 | ;const r=n.textContent,a=t?f(t,r,!0):m(r),s=S(n);if(s.length){ 239 | const e=document.createElement("div");e.innerHTML=a.value,a.value=A(s,S(e),r)} 240 | a.value=b(a.value),N("after:highlightBlock",{block:e,result:a 241 | }),e.innerHTML=a.value,e.className=function(e,n,t){var r=n?i[n]:t,a=[e.trim()] 242 | ;return e.match(/\bhljs\b/)||a.push("hljs"), 243 | e.includes(r)||a.push(r),a.join(" ").trim() 244 | }(e.className,t,a.language),e.result={language:a.language,re:a.relevance, 245 | relavance:a.relevance},a.second_best&&(e.second_best={ 246 | language:a.second_best.language,re:a.second_best.relevance, 247 | relavance:a.second_best.relevance})}const x=()=>{if(!x.called){x.called=!0 248 | ;var e=document.querySelectorAll("pre code");r.forEach.call(e,v)}} 249 | ;function E(e){return e=(e||"").toLowerCase(),a[e]||a[i[e]]} 250 | function _(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach((e=>{i[e]=n 251 | }))}function w(e){var n=E(e);return n&&!n.disableAutodetect}function N(e,n){ 252 | var t=e;s.forEach((function(e){e[t]&&e[t](n)}))}Object.assign(t,{highlight:f, 253 | highlightAuto:m,fixMarkup:function(e){ 254 | return console.warn("fixMarkup is deprecated and will be removed entirely in v11.0"), 255 | console.warn("Please see https://github.com/highlightjs/highlight.js/issues/2534"), 256 | b(e)},highlightBlock:v,configure:function(e){ 257 | e.useBR&&(console.warn("'useBR' option is deprecated and will be removed entirely in v11.0"), 258 | console.warn("Please see https://github.com/highlightjs/highlight.js/issues/2559")), 259 | d=T(d,e)},initHighlighting:x,initHighlightingOnLoad:function(){ 260 | window.addEventListener("DOMContentLoaded",x,!1)}, 261 | registerLanguage:function(e,n){var r=null;try{r=n(t)}catch(n){ 262 | if(console.error("Language definition for '{}' could not be registered.".replace("{}",e)), 263 | !o)throw n;console.error(n),r=g} 264 | r.name||(r.name=e),a[e]=r,r.rawDefinition=n.bind(null,t), 265 | r.aliases&&_(r.aliases,{languageName:e})},listLanguages:function(){ 266 | return Object.keys(a)},getLanguage:E,registerAliases:_, 267 | requireLanguage:function(e){var n=E(e);if(n)return n 268 | ;throw Error("The '{}' language is required, but not loaded.".replace("{}",e))}, 269 | autoDetection:w,inherit:T,addPlugin:function(e){s.push(e)},vuePlugin:j 270 | }),t.debugMode=function(){o=!1},t.safeMode=function(){o=!0 271 | },t.versionString="10.3.2";for(const n in y)"object"==typeof y[n]&&e(y[n]) 272 | ;return Object.assign(t,y),t}({})}() 273 | ;"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs); 274 | hljs.registerLanguage("apache",function(){"use strict";return function(e){ 275 | var n={className:"number", 276 | begin:"\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?"};return{ 277 | name:"Apache config",aliases:["apacheconf"],case_insensitive:!0, 278 | contains:[e.HASH_COMMENT_MODE,{className:"section",begin:"", 279 | contains:[n,{className:"number",begin:":\\d{1,5}" 280 | },e.inherit(e.QUOTE_STRING_MODE,{relevance:0})]},{className:"attribute", 281 | begin:/\w+/,relevance:0,keywords:{ 282 | nomarkup:"order deny allow setenv rewriterule rewriteengine rewritecond documentroot sethandler errordocument loadmodule options header listen serverroot servername" 283 | },starts:{end:/$/,relevance:0,keywords:{literal:"on off all deny allow"}, 284 | contains:[{className:"meta",begin:"\\s\\[",end:"\\]$"},{className:"variable", 285 | begin:"[\\$%]\\{",end:"\\}",contains:["self",{className:"number", 286 | begin:"[\\$%]\\d+"}]},n,{className:"number",begin:"\\d+"},e.QUOTE_STRING_MODE]} 287 | }],illegal:/\S/}}}()); 288 | hljs.registerLanguage("bash",function(){"use strict";return function(e){ 289 | const s={};Object.assign(s,{className:"variable",variants:[{ 290 | begin:/\$[\w\d#@][\w\d_]*/},{begin:/\$\{/,end:/\}/,contains:["self",{begin:/:-/, 291 | contains:[s]}]}]});const n={className:"subst",begin:/\$\(/,end:/\)/, 292 | contains:[e.BACKSLASH_ESCAPE]},t={begin:/<<-?\s*(?=\w+)/,starts:{ 293 | contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,className:"string"})]} 294 | },a={className:"string",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,s,n]} 295 | ;n.contains.push(a);const i={begin:/\$\(\(/,end:/\)\)/,contains:[{ 296 | begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,s]},c=e.SHEBANG({ 297 | binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10}),o={ 298 | className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0, 299 | contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{ 300 | name:"Bash",aliases:["sh","zsh"],keywords:{$pattern:/\b[a-z._-]+\b/, 301 | keyword:"if then else elif fi for while in do done case esac function", 302 | literal:"true false", 303 | built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp" 304 | },contains:[c,e.SHEBANG(),o,i,e.COMMENT("(?")+")",i={ 310 | className:"keyword",begin:"\\b[a-z\\d_]*_t\\b"},s={className:"string", 311 | variants:[{begin:'(u8?|U|L)?"',end:'"',illegal:"\\n", 312 | contains:[e.BACKSLASH_ESCAPE]},{ 313 | begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)", 314 | end:"'",illegal:"."},e.END_SAME_AS_BEGIN({ 315 | begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},o={ 316 | className:"number",variants:[{begin:"\\b(0b[01']+)"},{ 317 | begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{ 318 | begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" 319 | }],relevance:0},c={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{ 320 | "meta-keyword":"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include" 321 | },contains:[{begin:/\\\n/,relevance:0},e.inherit(s,{className:"meta-string"}),{ 322 | className:"meta-string",begin:/<.*?>/,end:/$/,illegal:"\\n" 323 | },n,e.C_BLOCK_COMMENT_MODE]},l={className:"title",begin:t(r)+e.IDENT_RE, 324 | relevance:0},d=t(r)+e.IDENT_RE+"\\s*\\(",u={ 325 | keyword:"int float while private char char8_t char16_t char32_t catch import module export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const for static_cast|10 union namespace unsigned long volatile static protected bool template mutable if public friend do goto auto void enum else break extern using asm case typeid wchar_t short reinterpret_cast|10 default double register explicit signed typename try this switch continue inline delete alignas alignof constexpr consteval constinit decltype concept co_await co_return co_yield requires noexcept static_assert thread_local restrict final override atomic_bool atomic_char atomic_schar atomic_uchar atomic_short atomic_ushort atomic_int atomic_uint atomic_long atomic_ulong atomic_llong atomic_ullong new throw return and and_eq bitand bitor compl not not_eq or or_eq xor xor_eq", 326 | built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr _Bool complex _Complex imaginary _Imaginary", 327 | literal:"true false nullptr NULL"},m=[c,i,n,e.C_BLOCK_COMMENT_MODE,o,s],p={ 328 | variants:[{begin:/=/,end:/;/},{begin:/\(/,end:/\)/},{ 329 | beginKeywords:"new throw return else",end:/;/}],keywords:u,contains:m.concat([{ 330 | begin:/\(/,end:/\)/,keywords:u,contains:m.concat(["self"]),relevance:0}]), 331 | relevance:0},_={className:"function",begin:"("+a+"[\\*&\\s]+)+"+d, 332 | returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:u,illegal:/[^\w\s\*&:<>]/, 333 | contains:[{begin:"decltype\\(auto\\)",keywords:u,relevance:0},{begin:d, 334 | returnBegin:!0,contains:[l],relevance:0},{className:"params",begin:/\(/, 335 | end:/\)/,keywords:u,relevance:0,contains:[n,e.C_BLOCK_COMMENT_MODE,s,o,i,{ 336 | begin:/\(/,end:/\)/,keywords:u,relevance:0, 337 | contains:["self",n,e.C_BLOCK_COMMENT_MODE,s,o,i]}] 338 | },i,n,e.C_BLOCK_COMMENT_MODE,c]};return{ 339 | aliases:["c","cc","h","c++","h++","hpp","hh","hxx","cxx"],keywords:u, 340 | disableAutodetect:!0,illegal:"",keywords:u,contains:["self",i]},{begin:e.IDENT_RE+"::",keywords:u},{ 343 | className:"class",beginKeywords:"enum class struct union",end:/[{;:<>=]/, 344 | contains:[{beginKeywords:"final class struct"},e.TITLE_MODE]}]),exports:{ 345 | preprocessor:c,strings:s,keywords:u}}}}()); 346 | hljs.registerLanguage("c",function(){"use strict";return function(e){ 347 | var n=e.requireLanguage("c-like").rawDefinition() 348 | ;return n.name="C",n.aliases=["c","h"],n}}()); 349 | hljs.registerLanguage("coffeescript",function(){"use strict" 350 | ;const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]) 351 | ;return function(r){var t,i={ 352 | keyword:e.concat(["then","unless","until","loop","by","when","and","or","is","isnt","not"]).filter((t=["var","const","let","function","static"], 353 | e=>!t.includes(e))).join(" "), 354 | literal:n.concat(["yes","no","on","off"]).join(" "), 355 | built_in:a.concat(["npm","print"]).join(" ")},s="[A-Za-z$_][0-9A-Za-z$_]*",o={ 356 | className:"subst",begin:/#\{/,end:/}/,keywords:i 357 | },c=[r.BINARY_NUMBER_MODE,r.inherit(r.C_NUMBER_MODE,{starts:{end:"(\\s*/)?", 358 | relevance:0}}),{className:"string",variants:[{begin:/'''/,end:/'''/, 359 | contains:[r.BACKSLASH_ESCAPE]},{begin:/'/,end:/'/,contains:[r.BACKSLASH_ESCAPE] 360 | },{begin:/"""/,end:/"""/,contains:[r.BACKSLASH_ESCAPE,o]},{begin:/"/,end:/"/, 361 | contains:[r.BACKSLASH_ESCAPE,o]}]},{className:"regexp",variants:[{begin:"///", 362 | end:"///",contains:[o,r.HASH_COMMENT_MODE]},{begin:"//[gim]{0,3}(?=\\W)", 363 | relevance:0},{begin:/\/(?![ *]).*?(?![\\]).\/[gim]{0,3}(?=\W)/}]},{begin:"@"+s 364 | },{subLanguage:"javascript",excludeBegin:!0,excludeEnd:!0,variants:[{ 365 | begin:"```",end:"```"},{begin:"`",end:"`"}]}];o.contains=c 366 | ;var l=r.inherit(r.TITLE_MODE,{begin:s}),d="(\\(.*\\))?\\s*\\B[-=]>",g={ 367 | className:"params",begin:"\\([^\\(]",returnBegin:!0,contains:[{begin:/\(/, 368 | end:/\)/,keywords:i,contains:["self"].concat(c)}]};return{name:"CoffeeScript", 369 | aliases:["coffee","cson","iced"],keywords:i,illegal:/\/\*/, 370 | contains:c.concat([r.COMMENT("###","###"),r.HASH_COMMENT_MODE,{ 371 | className:"function",begin:"^\\s*"+s+"\\s*=\\s*"+d,end:"[-=]>",returnBegin:!0, 372 | contains:[l,g]},{begin:/[:\(,=]\s*/,relevance:0,contains:[{className:"function", 373 | begin:d,end:"[-=]>",returnBegin:!0,contains:[g]}]},{className:"class", 374 | beginKeywords:"class",end:"$",illegal:/[:="\[\]]/,contains:[{ 375 | beginKeywords:"extends",endsWithParent:!0,illegal:/[:="\[\]]/,contains:[l]},l] 376 | },{begin:s+":",end:":",returnBegin:!0,returnEnd:!0,relevance:0}])}}}()); 377 | hljs.registerLanguage("cpp",function(){"use strict";return function(e){ 378 | var i=e.requireLanguage("c-like").rawDefinition();return i.disableAutodetect=!1, 379 | i.name="C++",i.aliases=["cc","c++","h++","hpp","hh","hxx","cxx"],i}}()); 380 | hljs.registerLanguage("csharp",function(){"use strict";return function(e){ 381 | var n={ 382 | keyword:["abstract","as","base","break","case","class","const","continue","do","else","event","explicit","extern","finally","fixed","for","foreach","goto","if","implicit","in","interface","internal","is","lock","namespace","new","operator","out","override","params","private","protected","public","readonly","record","ref","return","sealed","sizeof","stackalloc","static","struct","switch","this","throw","try","typeof","unchecked","unsafe","using","virtual","void","volatile","while"].concat(["add","alias","and","ascending","async","await","by","descending","equals","from","get","global","group","init","into","join","let","nameof","not","notnull","on","or","orderby","partial","remove","select","set","unmanaged","value","var","when","where","with","yield"]).join(" "), 383 | built_in:"bool byte char decimal delegate double dynamic enum float int long nint nuint object sbyte short string ulong unit ushort", 384 | literal:"default false null true"},i=e.inherit(e.TITLE_MODE,{ 385 | begin:"[a-zA-Z](\\.?\\w)*"}),a={className:"number",variants:[{ 386 | begin:"\\b(0b[01']+)"},{ 387 | begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{ 388 | begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" 389 | }],relevance:0},s={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}] 390 | },t=e.inherit(s,{illegal:/\n/}),r={className:"subst",begin:"{",end:"}", 391 | keywords:n},l=e.inherit(r,{illegal:/\n/}),c={className:"string",begin:/\$"/, 392 | end:'"',illegal:/\n/,contains:[{begin:"{{"},{begin:"}}"},e.BACKSLASH_ESCAPE,l] 393 | },o={className:"string",begin:/\$@"/,end:'"',contains:[{begin:"{{"},{begin:"}}" 394 | },{begin:'""'},r]},d=e.inherit(o,{illegal:/\n/,contains:[{begin:"{{"},{ 395 | begin:"}}"},{begin:'""'},l]}) 396 | ;r.contains=[o,c,s,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.C_BLOCK_COMMENT_MODE], 397 | l.contains=[d,c,t,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.inherit(e.C_BLOCK_COMMENT_MODE,{ 398 | illegal:/\n/})];var g={variants:[o,c,s,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE] 399 | },E={begin:"<",end:">",contains:[{beginKeywords:"in out"},i] 400 | },_=e.IDENT_RE+"(<"+e.IDENT_RE+"(\\s*,\\s*"+e.IDENT_RE+")*>)?(\\[\\])?",b={ 401 | begin:"@"+e.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"], 402 | keywords:n,illegal:/::/,contains:[e.COMMENT("///","$",{returnBegin:!0, 403 | contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{ 404 | begin:"\x3c!--|--\x3e"},{begin:""}]}] 405 | }),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#", 406 | end:"$",keywords:{ 407 | "meta-keyword":"if else elif endif define undef warning error line region endregion pragma checksum" 408 | }},g,a,{beginKeywords:"class interface",end:/[{;=]/,illegal:/[^\s:,]/, 409 | contains:[{beginKeywords:"where class" 410 | },i,E,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace", 411 | end:/[{;=]/,illegal:/[^\s:]/, 412 | contains:[i,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{ 413 | beginKeywords:"record",end:/[{;=]/,illegal:/[^\s:]/, 414 | contains:[i,E,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"meta", 415 | begin:"^\\s*\\[",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{ 416 | className:"meta-string",begin:/"/,end:/"/}]},{ 417 | beginKeywords:"new return throw await else",relevance:0},{className:"function", 418 | begin:"("+_+"\\s+)+"+e.IDENT_RE+"\\s*(\\<.+\\>)?\\s*\\(",returnBegin:!0, 419 | end:/\s*[{;=]/,excludeEnd:!0,keywords:n,contains:[{ 420 | beginKeywords:"public private protected static internal protected abstract async extern override unsafe virtual new sealed partial" 421 | },{begin:e.IDENT_RE+"\\s*(\\<.+\\>)?\\s*\\(",returnBegin:!0, 422 | contains:[e.TITLE_MODE,E],relevance:0},{className:"params",begin:/\(/,end:/\)/, 423 | excludeBegin:!0,excludeEnd:!0,keywords:n,relevance:0, 424 | contains:[g,a,e.C_BLOCK_COMMENT_MODE] 425 | },e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},b]}}}()); 426 | hljs.registerLanguage("css",function(){"use strict";return function(e){var n={ 427 | begin:/(?:[A-Z\_\.\-]+|--[a-zA-Z0-9_-]+)\s*:/,returnBegin:!0,end:";", 428 | endsWithParent:!0,contains:[{className:"attribute",begin:/\S/,end:":", 429 | excludeEnd:!0,starts:{endsWithParent:!0,excludeEnd:!0,contains:[{ 430 | begin:/[\w-]+\(/,returnBegin:!0,contains:[{className:"built_in",begin:/[\w-]+/ 431 | },{begin:/\(/,end:/\)/, 432 | contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.CSS_NUMBER_MODE]}] 433 | },e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,e.C_BLOCK_COMMENT_MODE,{ 434 | className:"number",begin:"#[0-9A-Fa-f]+"},{className:"meta",begin:"!important"}] 435 | }}]};return{name:"CSS",case_insensitive:!0,illegal:/[=\/|'\$]/, 436 | contains:[e.C_BLOCK_COMMENT_MODE,{className:"selector-id", 437 | begin:/#[A-Za-z0-9_-]+/},{className:"selector-class",begin:/\.[A-Za-z0-9_-]+/},{ 438 | className:"selector-attr",begin:/\[/,end:/\]/,illegal:"$", 439 | contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},{className:"selector-pseudo", 440 | begin:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{begin:"@(page|font-face)", 441 | lexemes:"@[a-z-]+",keywords:"@page @font-face"},{begin:"@",end:"[{;]", 442 | illegal:/:/,returnBegin:!0,contains:[{className:"keyword", 443 | begin:/@\-?\w[\w]*(\-\w+)*/},{begin:/\s/,endsWithParent:!0,excludeEnd:!0, 444 | relevance:0,keywords:"and or not only",contains:[{begin:/[a-z-]+:/, 445 | className:"attribute"},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.CSS_NUMBER_MODE] 446 | }]},{className:"selector-tag",begin:"[a-zA-Z-][a-zA-Z0-9_-]*",relevance:0},{ 447 | begin:"{",end:"}",illegal:/\S/,contains:[e.C_BLOCK_COMMENT_MODE,n]}]}}}()); 448 | hljs.registerLanguage("diff",function(){"use strict";return function(e){return{ 449 | name:"Diff",aliases:["patch"],contains:[{className:"meta",relevance:10, 450 | variants:[{begin:/^@@ +\-\d+,\d+ +\+\d+,\d+ +@@$/},{ 451 | begin:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{begin:/^\-\-\- +\d+,\d+ +\-\-\-\-$/}]},{ 452 | className:"comment",variants:[{begin:/Index: /,end:/$/},{begin:/={3,}/,end:/$/ 453 | },{begin:/^\-{3}/,end:/$/},{begin:/^\*{3} /,end:/$/},{begin:/^\+{3}/,end:/$/},{ 454 | begin:/^\*{15}$/}]},{className:"addition",begin:"^\\+",end:"$"},{ 455 | className:"deletion",begin:"^\\-",end:"$"},{className:"addition",begin:"^\\!", 456 | end:"$"}]}}}()); 457 | hljs.registerLanguage("go",function(){"use strict";return function(e){var n={ 458 | keyword:"break default func interface select case map struct chan else goto package switch const fallthrough if range type continue for import return var go defer bool byte complex64 complex128 float32 float64 int8 int16 int32 int64 string uint8 uint16 uint32 uint64 int uint uintptr rune", 459 | literal:"true false iota nil", 460 | built_in:"append cap close complex copy imag len make new panic print println real recover delete" 461 | };return{name:"Go",aliases:["golang"],keywords:n,illegal:"e(n))).join("")}return function(a){var s={className:"number", 479 | relevance:0,variants:[{begin:/([\+\-]+)?[\d]+_[\d_]+/},{begin:a.NUMBER_RE}] 480 | },i=a.COMMENT();i.variants=[{begin:/;/,end:/$/},{begin:/#/,end:/$/}];var t={ 481 | className:"variable",variants:[{begin:/\$[\w\d"][\w\d_]*/},{begin:/\$\{(.*?)}/}] 482 | },r={className:"literal",begin:/\bon|off|true|false|yes|no\b/},l={ 483 | className:"string",contains:[a.BACKSLASH_ESCAPE],variants:[{begin:"'''", 484 | end:"'''",relevance:10},{begin:'"""',end:'"""',relevance:10},{begin:'"',end:'"' 485 | },{begin:"'",end:"'"}]},c={begin:/\[/,end:/\]/,contains:[i,r,t,l,s,"self"], 486 | relevance:0 487 | },g="("+[/[A-Za-z0-9_-]+/,/"(\\"|[^"])*"/,/'[^']*'/].map((n=>e(n))).join("|")+")" 488 | ;return{name:"TOML, also INI",aliases:["toml"],case_insensitive:!0,illegal:/\S/, 489 | contains:[i,{className:"section",begin:/\[+/,end:/\]+/},{ 490 | begin:n(g,"(\\s*\\.\\s*",g,")*",n("(?=",/\s*=\s*[^#\s]/,")")),className:"attr", 491 | starts:{end:/$/,contains:[i,c,r,t,l,s]}}]}}}()); 492 | hljs.registerLanguage("java",function(){"use strict";function e(e){ 493 | return e?"string"==typeof e?e:e.source:null}function n(e){return a("(",e,")?")} 494 | function a(...n){return n.map((n=>e(n))).join("")}function s(...n){ 495 | return"("+n.map((n=>e(n))).join("|")+")"}return function(e){ 496 | var r="false synchronized int abstract float private char boolean var static null if const for true while long strictfp finally protected import native final void enum else break transient catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private module requires exports do",i={ 497 | className:"meta",begin:"@[\xc0-\u02b8a-zA-Z_$][\xc0-\u02b8a-zA-Z_$0-9]*", 498 | contains:[{begin:/\(/,end:/\)/,contains:["self"]}] 499 | },t=e=>a("[",e,"]+([",e,"_]*[",e,"]+)?"),c={className:"number",variants:[{ 500 | begin:`\\b(0[bB]${t("01")})[lL]?`},{begin:`\\b(0${t("0-7")})[dDfFlL]?`},{ 501 | begin:a(/\b0[xX]/,s(a(t("a-fA-F0-9"),/\./,t("a-fA-F0-9")),a(t("a-fA-F0-9"),/\.?/),a(/\./,t("a-fA-F0-9"))),/([pP][+-]?(\d+))?/,/[fFdDlL]?/) 502 | },{begin:a(/\b/,s(a(/\d*\./,t("\\d")),t("\\d")),/[eE][+-]?[\d]+[dDfF]?/)},{ 503 | begin:a(/\b/,t(/\d/),n(/\.?/),n(t(/\d/)),/[dDfFlL]?/)}],relevance:0};return{ 504 | name:"Java",aliases:["jsp"],keywords:r,illegal:/<\/|#/, 505 | contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/, 506 | relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}] 507 | }),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{ 508 | className:"class",beginKeywords:"class interface enum",end:/[{;=]/, 509 | excludeEnd:!0,keywords:"class interface enum",illegal:/[:"\[\]]/,contains:[{ 510 | beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{ 511 | beginKeywords:"new throw return else",relevance:0},{className:"class", 512 | begin:"record\\s+"+e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,excludeEnd:!0, 513 | end:/[{;=]/,keywords:r,contains:[{beginKeywords:"record"},{ 514 | begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0, 515 | contains:[e.UNDERSCORE_TITLE_MODE]},{className:"params",begin:/\(/,end:/\)/, 516 | keywords:r,relevance:0,contains:[e.C_BLOCK_COMMENT_MODE] 517 | },e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"function", 518 | begin:"([\xc0-\u02b8a-zA-Z_$][\xc0-\u02b8a-zA-Z_$0-9]*(<[\xc0-\u02b8a-zA-Z_$][\xc0-\u02b8a-zA-Z_$0-9]*(\\s*,\\s*[\xc0-\u02b8a-zA-Z_$][\xc0-\u02b8a-zA-Z_$0-9]*)*>)?\\s+)+"+e.UNDERSCORE_IDENT_RE+"\\s*\\(", 519 | returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:r,contains:[{ 520 | begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0, 521 | contains:[e.UNDERSCORE_TITLE_MODE]},{className:"params",begin:/\(/,end:/\)/, 522 | keywords:r,relevance:0, 523 | contains:[i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE] 524 | },e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},c,i]}}}()); 525 | hljs.registerLanguage("javascript",function(){"use strict" 526 | ;const e="[A-Za-z$_][0-9A-Za-z$_]*",n=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],a=["true","false","null","undefined","NaN","Infinity"],s=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]) 527 | ;function r(e){return i("(?=",e,")")}function t(e){return i("(",e,")?")} 528 | function i(...e){return e.map((e=>{ 529 | return(n=e)?"string"==typeof n?n:n.source:null;var n})).join("")} 530 | return function(c){const o=e,l={begin:/<[A-Za-z0-9\\._:-]+/, 531 | end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(e,n)=>{ 532 | const a=e[0].length+e.index,s=e.input[a];"<"!==s?">"===s&&(((e,{after:n})=>{ 533 | const a=e[0].replace("<","`\\b0[${e}][${n}]([${n}_]*[${n}])?n?`,b=/[1-9]([0-9_]*\d)?/,E=/\d([0-9_]*\d)?/,u=i(/[eE][+-]?/,E),_={ 537 | className:"number",variants:[{begin:d("bB","01")},{begin:d("oO","0-7")},{ 538 | begin:d("xX","0-9a-fA-F")},{begin:i(/\b/,b,"n")},{begin:i(/(\b0)?\./,E,t(u))},{ 539 | begin:i(/\b/,b,t(i(/\./,t(E))),t(u))},{begin:/\b0[\.n]?/}],relevance:0},m={ 540 | className:"subst",begin:"\\$\\{",end:"\\}",keywords:g,contains:[]},N={ 541 | begin:"html`",end:"",starts:{end:"`",returnEnd:!1, 542 | contains:[c.BACKSLASH_ESCAPE,m],subLanguage:"xml"}},y={begin:"css`",end:"", 543 | starts:{end:"`",returnEnd:!1,contains:[c.BACKSLASH_ESCAPE,m],subLanguage:"css"} 544 | },f={className:"string",begin:"`",end:"`",contains:[c.BACKSLASH_ESCAPE,m]},A={ 545 | className:"comment",variants:[c.COMMENT("/\\*\\*","\\*/",{relevance:0, 546 | contains:[{className:"doctag",begin:"@[A-Za-z]+",contains:[{className:"type", 547 | begin:"\\{",end:"\\}",relevance:0},{className:"variable", 548 | begin:o+"(?=\\s*(-)|$)",endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/, 549 | relevance:0}]}]}),c.C_BLOCK_COMMENT_MODE,c.C_LINE_COMMENT_MODE] 550 | },p=[c.APOS_STRING_MODE,c.QUOTE_STRING_MODE,N,y,f,_,c.REGEXP_MODE] 551 | ;m.contains=p.concat({begin:/{/,end:/}/,keywords:g,contains:["self"].concat(p)}) 552 | ;const O=[].concat(A,m.contains),T=O.concat([{begin:/\(/,end:/\)/,keywords:g, 553 | contains:["self"].concat(O)}]),R={className:"params",begin:/\(/,end:/\)/, 554 | excludeBegin:!0,excludeEnd:!0,keywords:g,contains:T};return{name:"Javascript", 555 | aliases:["js","jsx","mjs","cjs"],keywords:g,exports:{PARAMS_CONTAINS:T}, 556 | illegal:/#(?![$_A-z])/,contains:[c.SHEBANG({label:"shebang",binary:"node", 557 | relevance:5}),{label:"use_strict",className:"meta",relevance:10, 558 | begin:/^\s*['"]use (strict|asm)['"]/ 559 | },c.APOS_STRING_MODE,c.QUOTE_STRING_MODE,N,y,f,A,_,{ 560 | begin:i(/[{,\n]\s*/,r(i(/(\/\/.*$)*/,/(\/\*(.|\n)*\*\/)*/,/\s*/,o+"\\s*:"))), 561 | relevance:0,contains:[{className:"attr",begin:o+r("\\s*:"),relevance:0}]},{ 562 | begin:"("+c.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*", 563 | keywords:"return throw case",contains:[A,c.REGEXP_MODE,{className:"function", 564 | begin:"(\\([^()]*(\\([^()]*(\\([^()]*\\))*[^()]*\\))*[^()]*\\)|"+c.UNDERSCORE_IDENT_RE+")\\s*=>", 565 | returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{ 566 | begin:c.UNDERSCORE_IDENT_RE},{className:null,begin:/\(\s*\)/,skip:!0},{ 567 | begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:g,contains:T}]}]},{ 568 | begin:/,/,relevance:0},{className:"",begin:/\s/,end:/\s*/,skip:!0},{variants:[{ 569 | begin:"<>",end:""},{begin:l.begin,"on:begin":l.isTrulyOpeningTag,end:l.end}], 570 | subLanguage:"xml",contains:[{begin:l.begin,end:l.end,skip:!0,contains:["self"]}] 571 | }],relevance:0},{className:"function",beginKeywords:"function",end:/[{;]/, 572 | excludeEnd:!0,keywords:g,contains:["self",c.inherit(c.TITLE_MODE,{begin:o}),R], 573 | illegal:/%/},{className:"function", 574 | begin:c.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\))*[^()]*\\))*[^()]*\\)\\s*{", 575 | returnBegin:!0,contains:[R,c.inherit(c.TITLE_MODE,{begin:o})]},{variants:[{ 576 | begin:"\\."+o},{begin:"\\$"+o}],relevance:0},{className:"class", 577 | beginKeywords:"class",end:/[{;=]/,excludeEnd:!0,illegal:/[:"\[\]]/,contains:[{ 578 | beginKeywords:"extends"},c.UNDERSCORE_TITLE_MODE]},{begin:/\b(?=constructor)/, 579 | end:/[\{;]/,excludeEnd:!0,contains:[c.inherit(c.TITLE_MODE,{begin:o}),"self",R] 580 | },{begin:"(get|set)\\s+(?="+o+"\\()",end:/{/,keywords:"get set", 581 | contains:[c.inherit(c.TITLE_MODE,{begin:o}),{begin:/\(\)/},R]},{begin:/\$[(.]/}] 582 | }}}()); 583 | hljs.registerLanguage("json",function(){"use strict";return function(n){var e={ 584 | literal:"true false null" 585 | },i=[n.C_LINE_COMMENT_MODE,n.C_BLOCK_COMMENT_MODE],t=[n.QUOTE_STRING_MODE,n.C_NUMBER_MODE],a={ 586 | end:",",endsWithParent:!0,excludeEnd:!0,contains:t,keywords:e},l={begin:"{", 587 | end:"}",contains:[{className:"attr",begin:/"/,end:/"/, 588 | contains:[n.BACKSLASH_ESCAPE],illegal:"\\n"},n.inherit(a,{begin:/:/ 589 | })].concat(i),illegal:"\\S"},s={begin:"\\[",end:"\\]",contains:[n.inherit(a)], 590 | illegal:"\\S"};return t.push(l,s),i.forEach((function(n){t.push(n)})),{ 591 | name:"JSON",contains:t,keywords:e,illegal:"\\S"}}}()); 592 | hljs.registerLanguage("kotlin",function(){"use strict";return function(e){ 593 | var n={ 594 | keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual", 595 | built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing", 596 | literal:"true false null"},a={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@" 597 | },i={className:"subst",begin:"\\${",end:"}",contains:[e.C_NUMBER_MODE]},s={ 598 | className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},t={className:"string", 599 | variants:[{begin:'"""',end:'"""(?=[^"])',contains:[s,i]},{begin:"'",end:"'", 600 | illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/, 601 | contains:[e.BACKSLASH_ESCAPE,s,i]}]};i.contains.push(t);var r={className:"meta", 602 | begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?" 603 | },l={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/, 604 | end:/\)/,contains:[e.inherit(t,{className:"meta-string"})]}] 605 | },c=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),o={variants:[{ 606 | className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/,contains:[]}] 607 | },d=o;return d.variants[1].contains=[o],o.variants[1].contains=[d],{ 608 | name:"Kotlin",aliases:["kt"],keywords:n,contains:[e.COMMENT("/\\*\\*","\\*/",{ 609 | relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+"}] 610 | }),e.C_LINE_COMMENT_MODE,c,{className:"keyword", 611 | begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol", 612 | begin:/@\w+/}]}},a,r,l,{className:"function",beginKeywords:"fun",end:"[(]|$", 613 | returnBegin:!0,excludeEnd:!0,keywords:n, 614 | illegal:/fun\s+(<.*>)?[^\s\(]+(\s+[^\s\(]+)\s*=/,relevance:5,contains:[{ 615 | begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0, 616 | contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin://, 617 | keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/, 618 | endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/, 619 | endsWithParent:!0,contains:[o,e.C_LINE_COMMENT_MODE,c],relevance:0 620 | },e.C_LINE_COMMENT_MODE,c,r,l,t,e.C_NUMBER_MODE]},c]},{className:"class", 621 | beginKeywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0, 622 | illegal:"extends implements",contains:[{ 623 | beginKeywords:"public protected internal private constructor" 624 | },e.UNDERSCORE_TITLE_MODE,{className:"type",begin://,excludeBegin:!0, 625 | excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,]|$/, 626 | excludeBegin:!0,returnEnd:!0},r,l]},t,{className:"meta",begin:"^#!/usr/bin/env", 627 | end:"$",illegal:"\n"},{className:"number", 628 | begin:"\\b(0[bB]([01]+[01_]+[01]+|[01]+)|0[xX]([a-fA-F0-9]+[a-fA-F0-9_]+[a-fA-F0-9]+|[a-fA-F0-9]+)|(([\\d]+[\\d_]+[\\d]+|[\\d]+)(\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))?|\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))([eE][-+]?\\d+)?)[lLfF]?", 629 | relevance:0}]}}}()); 630 | hljs.registerLanguage("less",function(){"use strict";return function(e){ 631 | var n="([\\w-]+|@{[\\w-]+})",a=[],s=[],t=function(e){return{className:"string", 632 | begin:"~?"+e+".*?"+e}},r=function(e,n,a){return{className:e,begin:n,relevance:a} 633 | },i={begin:"\\(",end:"\\)",contains:s,relevance:0} 634 | ;s.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,t("'"),t('"'),e.CSS_NUMBER_MODE,{ 635 | begin:"(url|data-uri)\\(",starts:{className:"string",end:"[\\)\\n]", 636 | excludeEnd:!0} 637 | },r("number","#[0-9A-Fa-f]+\\b"),i,r("variable","@@?[\\w-]+",10),r("variable","@{[\\w-]+}"),r("built_in","~?`[^`]*?`"),{ 638 | className:"attribute",begin:"[\\w-]+\\s*:",end:":",returnBegin:!0,excludeEnd:!0 639 | },{className:"meta",begin:"!important"});var c=s.concat({begin:"{",end:"}", 640 | contains:a}),l={beginKeywords:"when",endsWithParent:!0,contains:[{ 641 | beginKeywords:"and not"}].concat(s)},o={begin:n+"\\s*:",returnBegin:!0, 642 | end:"[;}]",relevance:0,contains:[{className:"attribute",begin:n,end:":", 643 | excludeEnd:!0,starts:{endsWithParent:!0,illegal:"[<=$]",relevance:0,contains:s} 644 | }]},g={className:"keyword", 645 | begin:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b", 646 | starts:{end:"[;{}]",returnEnd:!0,contains:s,relevance:0}},d={ 647 | className:"variable",variants:[{begin:"@[\\w-]+\\s*:",relevance:15},{ 648 | begin:"@[\\w-]+"}],starts:{end:"[;}]",returnEnd:!0,contains:c}},b={variants:[{ 649 | begin:"[\\.#:&\\[>]",end:"[;{}]"},{begin:n,end:"{"}],returnBegin:!0, 650 | returnEnd:!0,illegal:"[<='$\"]",relevance:0, 651 | contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,l,r("keyword","all\\b"),r("variable","@{[\\w-]+}"),r("selector-tag",n+"%?",0),r("selector-id","#"+n),r("selector-class","\\."+n,0),r("selector-tag","&",0),{ 652 | className:"selector-attr",begin:"\\[",end:"\\]"},{className:"selector-pseudo", 653 | begin:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{begin:"\\(",end:"\\)",contains:c},{ 654 | begin:"!important"}]} 655 | ;return a.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,g,d,o,b),{ 656 | name:"Less",case_insensitive:!0,illegal:"[=>'/<($\"]",contains:a}}}()); 657 | hljs.registerLanguage("lua",function(){"use strict";return function(e){ 658 | var t="\\[=*\\[",a="\\]=*\\]",n={begin:t,end:a,contains:["self"] 659 | },o=[e.COMMENT("--(?!\\[=*\\[)","$"),e.COMMENT("--\\[=*\\[",a,{contains:[n], 660 | relevance:10})];return{name:"Lua",keywords:{$pattern:e.UNDERSCORE_IDENT_RE, 661 | literal:"true false nil", 662 | keyword:"and break do else elseif end for goto if in local not or repeat return then until while", 663 | built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove" 664 | },contains:o.concat([{className:"function",beginKeywords:"function",end:"\\)", 665 | contains:[e.inherit(e.TITLE_MODE,{ 666 | begin:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{className:"params", 667 | begin:"\\(",endsWithParent:!0,contains:o}].concat(o) 668 | },e.C_NUMBER_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"string", 669 | begin:t,end:a,contains:[n],relevance:5}])}}}()); 670 | hljs.registerLanguage("makefile",function(){"use strict";return function(e){ 671 | var i={className:"variable",variants:[{ 672 | begin:"\\$\\("+e.UNDERSCORE_IDENT_RE+"\\)",contains:[e.BACKSLASH_ESCAPE]},{ 673 | begin:/\$[@%`]+/}]}]}]};return{name:"HTML, XML", 693 | aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"], 694 | case_insensitive:!0,contains:[{className:"meta",begin:"", 695 | relevance:10,contains:[a,i,t,s,{begin:"\\[",end:"\\]",contains:[{ 696 | className:"meta",begin:"",contains:[a,s,i,t]}]}] 697 | },e.COMMENT("\x3c!--","--\x3e",{relevance:10}),{begin:"<\\!\\[CDATA\\[", 698 | end:"\\]\\]>",relevance:10},n,{className:"meta",begin:/<\?xml/,end:/\?>/, 699 | relevance:10},{className:"tag",begin:")",end:">",keywords:{ 700 | name:"style"},contains:[c],starts:{end:"",returnEnd:!0, 701 | subLanguage:["css","xml"]}},{className:"tag",begin:")",end:">", 702 | keywords:{name:"script"},contains:[c],starts:{end:"<\/script>",returnEnd:!0, 703 | subLanguage:["javascript","handlebars","xml"]}},{className:"tag",begin:"",contains:[{className:"name",begin:/[^\/><\s]+/,relevance:0},c]}]}} 705 | }()); 706 | hljs.registerLanguage("markdown",function(){"use strict";return function(n){ 707 | const e={begin:"<",end:">",subLanguage:"xml",relevance:0},a={ 708 | begin:"\\[.+?\\][\\(\\[].*?[\\)\\]]",returnBegin:!0,contains:[{ 709 | className:"string",begin:"\\[",end:"\\]",excludeBegin:!0,returnEnd:!0, 710 | relevance:0},{className:"link",begin:"\\]\\(",end:"\\)",excludeBegin:!0, 711 | excludeEnd:!0},{className:"symbol",begin:"\\]\\[",end:"\\]",excludeBegin:!0, 712 | excludeEnd:!0}],relevance:10},i={className:"strong",contains:[],variants:[{ 713 | begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},s={className:"emphasis", 714 | contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{begin:/_(?!_)/,end:/_/, 715 | relevance:0}]};i.contains.push(s),s.contains.push(i);var c=[e,a] 716 | ;return i.contains=i.contains.concat(c),s.contains=s.contains.concat(c),{ 717 | name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{className:"section", 718 | variants:[{begin:"^#{1,6}",end:"$",contains:c=c.concat(i,s)},{ 719 | begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n", 720 | contains:c}]}]},e,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)", 721 | end:"\\s+",excludeEnd:!0},i,s,{className:"quote",begin:"^>\\s+",contains:c, 722 | end:"$"},{className:"code",variants:[{begin:"(`{3,})(.|\\n)*?\\1`*[ ]*"},{ 723 | begin:"(~{3,})(.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{begin:"~~~", 724 | end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",contains:[{ 725 | begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{begin:"^[-\\*]{3,}",end:"$" 726 | },a,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{className:"symbol", 727 | begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{className:"link", 728 | begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}}}()); 729 | hljs.registerLanguage("nginx",function(){"use strict";return function(e){var n={ 730 | className:"variable",variants:[{begin:/\$\d+/},{begin:/\$\{/,end:/}/},{ 731 | begin:"[\\$\\@]"+e.UNDERSCORE_IDENT_RE}]},a={endsWithParent:!0,keywords:{ 732 | $pattern:"[a-z/_]+", 733 | literal:"on off yes no true false none blocked debug info notice warn error crit select break last permanent redirect kqueue rtsig epoll poll /dev/poll" 734 | },relevance:0,illegal:"=>",contains:[e.HASH_COMMENT_MODE,{className:"string", 735 | contains:[e.BACKSLASH_ESCAPE,n],variants:[{begin:/"/,end:/"/},{begin:/'/,end:/'/ 736 | }]},{begin:"([a-z]+):/",end:"\\s",endsWithParent:!0,excludeEnd:!0,contains:[n] 737 | },{className:"regexp",contains:[e.BACKSLASH_ESCAPE,n],variants:[{begin:"\\s\\^", 738 | end:"\\s|{|;",returnEnd:!0},{begin:"~\\*?\\s+",end:"\\s|{|;",returnEnd:!0},{ 739 | begin:"\\*(\\.[a-z\\-]+)+"},{begin:"([a-z\\-]+\\.)+\\*"}]},{className:"number", 740 | begin:"\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?\\b"},{ 741 | className:"number",begin:"\\b\\d+[kKmMgGdshdwy]*\\b",relevance:0},n]};return{ 742 | name:"Nginx config",aliases:["nginxconf"],contains:[e.HASH_COMMENT_MODE,{ 743 | begin:e.UNDERSCORE_IDENT_RE+"\\s+{",returnBegin:!0,end:"{",contains:[{ 744 | className:"section",begin:e.UNDERSCORE_IDENT_RE}],relevance:0},{ 745 | begin:e.UNDERSCORE_IDENT_RE+"\\s",end:";|{",returnBegin:!0,contains:[{ 746 | className:"attribute",begin:e.UNDERSCORE_IDENT_RE,starts:a}],relevance:0}], 747 | illegal:"[^\\s\\}]"}}}()); 748 | hljs.registerLanguage("objectivec",function(){"use strict";return function(e){ 749 | var n=/[a-zA-Z@][a-zA-Z0-9_]*/,_={$pattern:n, 750 | keyword:"@interface @class @protocol @implementation"};return{ 751 | name:"Objective-C",aliases:["mm","objc","obj-c","obj-c++","objective-c++"], 752 | keywords:{$pattern:n, 753 | keyword:"int float while char export sizeof typedef const struct for union unsigned long volatile static bool mutable if do return goto void enum else break extern asm case short default double register explicit signed typename this switch continue wchar_t inline readonly assign readwrite self @synchronized id typeof nonatomic super unichar IBOutlet IBAction strong weak copy in out inout bycopy byref oneway __strong __weak __block __autoreleasing @private @protected @public @try @property @end @throw @catch @finally @autoreleasepool @synthesize @dynamic @selector @optional @required @encode @package @import @defs @compatibility_alias __bridge __bridge_transfer __bridge_retained __bridge_retain __covariant __contravariant __kindof _Nonnull _Nullable _Null_unspecified __FUNCTION__ __PRETTY_FUNCTION__ __attribute__ getter setter retain unsafe_unretained nonnull nullable null_unspecified null_resettable class instancetype NS_DESIGNATED_INITIALIZER NS_UNAVAILABLE NS_REQUIRES_SUPER NS_RETURNS_INNER_POINTER NS_INLINE NS_AVAILABLE NS_DEPRECATED NS_ENUM NS_OPTIONS NS_SWIFT_UNAVAILABLE NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_END NS_REFINED_FOR_SWIFT NS_SWIFT_NAME NS_SWIFT_NOTHROW NS_DURING NS_HANDLER NS_ENDHANDLER NS_VALUERETURN NS_VOIDRETURN", 754 | literal:"false true FALSE TRUE nil YES NO NULL", 755 | built_in:"BOOL dispatch_once_t dispatch_queue_t dispatch_sync dispatch_async dispatch_once" 756 | },illegal:"/,end:/$/, 765 | illegal:"\\n"},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{ 766 | className:"class",begin:"("+_.keyword.split(" ").join("|")+")\\b",end:"({|$)", 767 | excludeEnd:!0,keywords:_,contains:[e.UNDERSCORE_TITLE_MODE]},{ 768 | begin:"\\."+e.UNDERSCORE_IDENT_RE,relevance:0}]}}}()); 769 | hljs.registerLanguage("perl",function(){"use strict";return function(e){var n={ 770 | $pattern:/[\w.]+/, 771 | keyword:"getpwent getservent quotemeta msgrcv scalar kill dbmclose undef lc ma syswrite tr send umask sysopen shmwrite vec qx utime local oct semctl localtime readpipe do return format read sprintf dbmopen pop getpgrp not getpwnam rewinddir qq fileno qw endprotoent wait sethostent bless s|0 opendir continue each sleep endgrent shutdown dump chomp connect getsockname die socketpair close flock exists index shmget sub for endpwent redo lstat msgctl setpgrp abs exit select print ref gethostbyaddr unshift fcntl syscall goto getnetbyaddr join gmtime symlink semget splice x|0 getpeername recv log setsockopt cos last reverse gethostbyname getgrnam study formline endhostent times chop length gethostent getnetent pack getprotoent getservbyname rand mkdir pos chmod y|0 substr endnetent printf next open msgsnd readdir use unlink getsockopt getpriority rindex wantarray hex system getservbyport endservent int chr untie rmdir prototype tell listen fork shmread ucfirst setprotoent else sysseek link getgrgid shmctl waitpid unpack getnetbyname reset chdir grep split require caller lcfirst until warn while values shift telldir getpwuid my getprotobynumber delete and sort uc defined srand accept package seekdir getprotobyname semop our rename seek if q|0 chroot sysread setpwent no crypt getc chown sqrt write setnetent setpriority foreach tie sin msgget map stat getlogin unless elsif truncate exec keys glob tied closedir ioctl socket readlink eval xor readline binmode setservent eof ord bind alarm pipe atan2 getgrent exp time push setgrent gt lt or ne m|0 break given say state when" 772 | },t={className:"subst",begin:"[$@]\\{",end:"\\}",keywords:n},s={begin:"->{", 773 | end:"}"},r={variants:[{begin:/\$\d/},{ 774 | begin:/[\$%@](\^\w\b|#\w+(::\w+)*|{\w+}|\w+(::\w*)*)/},{begin:/[\$%@][^\s\w{]/, 775 | relevance:0}] 776 | },i=[e.BACKSLASH_ESCAPE,t,r],a=[r,e.HASH_COMMENT_MODE,e.COMMENT("^\\=\\w","\\=cut",{ 777 | endsWithParent:!0}),s,{className:"string",contains:i,variants:[{ 778 | begin:"q[qwxr]?\\s*\\(",end:"\\)",relevance:5},{begin:"q[qwxr]?\\s*\\[", 779 | end:"\\]",relevance:5},{begin:"q[qwxr]?\\s*\\{",end:"\\}",relevance:5},{ 780 | begin:"q[qwxr]?\\s*\\|",end:"\\|",relevance:5},{begin:"q[qwxr]?\\s*\\<", 781 | end:"\\>",relevance:5},{begin:"qw\\s+q",end:"q",relevance:5},{begin:"'",end:"'", 782 | contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"'},{begin:"`",end:"`", 783 | contains:[e.BACKSLASH_ESCAPE]},{begin:"{\\w+}",contains:[],relevance:0},{ 784 | begin:"-?\\w+\\s*\\=\\>",contains:[],relevance:0}]},{className:"number", 785 | begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b", 786 | relevance:0},{ 787 | begin:"(\\/\\/|"+e.RE_STARTERS_RE+"|\\b(split|return|print|reverse|grep)\\b)\\s*", 788 | keywords:"split return print reverse grep",relevance:0, 789 | contains:[e.HASH_COMMENT_MODE,{className:"regexp", 790 | begin:"(s|tr|y)/(\\\\.|[^/])*/(\\\\.|[^/])*/[a-z]*",relevance:10},{ 791 | className:"regexp",begin:"(m|qr)?/",end:"/[a-z]*",contains:[e.BACKSLASH_ESCAPE], 792 | relevance:0}]},{className:"function",beginKeywords:"sub", 793 | end:"(\\s*\\(.*?\\))?[;{]",excludeEnd:!0,relevance:5,contains:[e.TITLE_MODE]},{ 794 | begin:"-\\w\\b",relevance:0},{begin:"^__DATA__$",end:"^__END__$", 795 | subLanguage:"mojolicious",contains:[{begin:"^@@.*",end:"$",className:"comment"}] 796 | }];return t.contains=a,s.contains=a,{name:"Perl",aliases:["pl","pm"],keywords:n, 797 | contains:a}}}()); 798 | hljs.registerLanguage("php",function(){"use strict";return function(e){var r={ 799 | begin:"\\$+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*"},t={className:"meta", 800 | variants:[{begin:/<\?php/,relevance:10},{begin:/<\?[=]?/},{begin:/\?>/}]},a={ 801 | className:"subst",variants:[{begin:/\$\w+/},{begin:/\{\$/,end:/\}/}] 802 | },n=e.inherit(e.APOS_STRING_MODE,{illegal:null 803 | }),i=e.inherit(e.QUOTE_STRING_MODE,{illegal:null, 804 | contains:e.QUOTE_STRING_MODE.contains.concat(a)}),o=e.END_SAME_AS_BEGIN({ 805 | begin:/<<<[ \t]*(\w+)\n/,end:/[ \t]*(\w+)\b/, 806 | contains:e.QUOTE_STRING_MODE.contains.concat(a)}),l={className:"string", 807 | contains:[e.BACKSLASH_ESCAPE,t],variants:[e.inherit(n,{begin:"b'",end:"'" 808 | }),e.inherit(i,{begin:'b"',end:'"'}),i,n,o]},s={ 809 | variants:[e.BINARY_NUMBER_MODE,e.C_NUMBER_MODE]},c={ 810 | keyword:"__CLASS__ __DIR__ __FILE__ __FUNCTION__ __LINE__ __METHOD__ __NAMESPACE__ __TRAIT__ die echo exit include include_once print require require_once array abstract and as binary bool boolean break callable case catch class clone const continue declare default do double else elseif empty enddeclare endfor endforeach endif endswitch endwhile eval extends final finally float for foreach from global goto if implements instanceof insteadof int integer interface isset iterable list match new object or private protected public real return string switch throw trait try unset use var void while xor yield", 811 | literal:"false null true", 812 | built_in:"Error|0 AppendIterator ArgumentCountError ArithmeticError ArrayIterator ArrayObject AssertionError BadFunctionCallException BadMethodCallException CachingIterator CallbackFilterIterator CompileError Countable DirectoryIterator DivisionByZeroError DomainException EmptyIterator ErrorException Exception FilesystemIterator FilterIterator GlobIterator InfiniteIterator InvalidArgumentException IteratorIterator LengthException LimitIterator LogicException MultipleIterator NoRewindIterator OutOfBoundsException OutOfRangeException OuterIterator OverflowException ParentIterator ParseError RangeException RecursiveArrayIterator RecursiveCachingIterator RecursiveCallbackFilterIterator RecursiveDirectoryIterator RecursiveFilterIterator RecursiveIterator RecursiveIteratorIterator RecursiveRegexIterator RecursiveTreeIterator RegexIterator RuntimeException SeekableIterator SplDoublyLinkedList SplFileInfo SplFileObject SplFixedArray SplHeap SplMaxHeap SplMinHeap SplObjectStorage SplObserver SplObserver SplPriorityQueue SplQueue SplStack SplSubject SplSubject SplTempFileObject TypeError UnderflowException UnexpectedValueException ArrayAccess Closure Generator Iterator IteratorAggregate Serializable Throwable Traversable WeakReference Directory __PHP_Incomplete_Class parent php_user_filter self static stdClass" 813 | };return{aliases:["php","php3","php4","php5","php6","php7","php8"], 814 | case_insensitive:!0,keywords:c, 815 | contains:[e.HASH_COMMENT_MODE,e.COMMENT("//","$",{contains:[t] 816 | }),e.COMMENT("/\\*","\\*/",{contains:[{className:"doctag",begin:"@[A-Za-z]+"}] 817 | }),e.COMMENT("__halt_compiler.+?;",!1,{endsWithParent:!0, 818 | keywords:"__halt_compiler"}),t,{className:"keyword",begin:/\$this\b/},r,{ 819 | begin:/(::|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/},{className:"function", 820 | beginKeywords:"fn function",end:/[;{]/,excludeEnd:!0,illegal:"[$%\\[]", 821 | contains:[e.UNDERSCORE_TITLE_MODE,{className:"params",begin:"\\(",end:"\\)", 822 | excludeBegin:!0,excludeEnd:!0,keywords:c, 823 | contains:["self",r,e.C_BLOCK_COMMENT_MODE,l,s]}]},{className:"class", 824 | beginKeywords:"class interface",end:"{",excludeEnd:!0,illegal:/[:\(\$"]/, 825 | contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{ 826 | beginKeywords:"namespace",end:";",illegal:/[\.']/, 827 | contains:[e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"use",end:";", 828 | contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"=>"},l,s]}}}()); 829 | hljs.registerLanguage("php-template",function(){"use strict";return function(n){ 830 | return{name:"PHP template",subLanguage:"xml",contains:[{begin:/<\?(php|=)?/, 831 | end:/\?>/,subLanguage:"php",contains:[{begin:"/\\*",end:"\\*/",skip:!0},{ 832 | begin:'b"',end:'"',skip:!0},{begin:"b'",end:"'",skip:!0 833 | },n.inherit(n.APOS_STRING_MODE,{illegal:null,className:null,contains:null, 834 | skip:!0}),n.inherit(n.QUOTE_STRING_MODE,{illegal:null,className:null, 835 | contains:null,skip:!0})]}]}}}()); 836 | hljs.registerLanguage("plaintext",function(){"use strict";return function(t){ 837 | return{name:"Plain text",aliases:["text","txt"],disableAutodetect:!0}}}()); 838 | hljs.registerLanguage("properties",function(){"use strict";return function(e){ 839 | var n="[ \\t\\f]*",t="("+n+"[:=]"+n+"|[ \\t\\f]+)",a="([^\\\\\\W:= \\t\\f\\n]|\\\\.)+",s="([^\\\\:= \\t\\f\\n]|\\\\.)+",r={ 840 | end:t,relevance:0,starts:{className:"string",end:/$/,relevance:0,contains:[{ 841 | begin:"\\\\\\n"}]}};return{name:".properties",case_insensitive:!0,illegal:/\S/, 842 | contains:[e.COMMENT("^\\s*[!#]","$"),{begin:a+t,returnBegin:!0,contains:[{ 843 | className:"attr",begin:a,endsParent:!0,relevance:0}],starts:r},{begin:s+t, 844 | returnBegin:!0,relevance:0,contains:[{className:"meta",begin:s,endsParent:!0, 845 | relevance:0}],starts:r},{className:"attr",relevance:0,begin:s+n+"$"}]}}}()); 846 | hljs.registerLanguage("python",function(){"use strict";return function(e){ 847 | const n={ 848 | keyword:"and as assert async await break class continue def del elif else except finally for from global if import in is lambda nonlocal|10 not or pass raise return try while with yield", 849 | built_in:"__import__ abs all any ascii bin bool breakpoint bytearray bytes callable chr classmethod compile complex delattr dict dir divmod enumerate eval exec filter float format frozenset getattr globals hasattr hash help hex id input int isinstance issubclass iter len list locals map max memoryview min next object oct open ord pow print property range repr reversed round set setattr slice sorted staticmethod str sum super tuple type vars zip", 850 | literal:"__debug__ Ellipsis False None NotImplemented True"},a={ 851 | className:"meta",begin:/^(>>>|\.\.\.) /},s={className:"subst",begin:/\{/, 852 | end:/\}/,keywords:n,illegal:/#/},i={begin:/\{\{/,relevance:0},r={ 853 | className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{ 854 | begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/,end:/'''/, 855 | contains:[e.BACKSLASH_ESCAPE,a],relevance:10},{ 856 | begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/,end:/"""/, 857 | contains:[e.BACKSLASH_ESCAPE,a],relevance:10},{ 858 | begin:/([fF][rR]|[rR][fF]|[fF])'''/,end:/'''/, 859 | contains:[e.BACKSLASH_ESCAPE,a,i,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"""/, 860 | end:/"""/,contains:[e.BACKSLASH_ESCAPE,a,i,s]},{begin:/([uU]|[rR])'/,end:/'/, 861 | relevance:10},{begin:/([uU]|[rR])"/,end:/"/,relevance:10},{ 862 | begin:/([bB]|[bB][rR]|[rR][bB])'/,end:/'/},{begin:/([bB]|[bB][rR]|[rR][bB])"/, 863 | end:/"/},{begin:/([fF][rR]|[rR][fF]|[fF])'/,end:/'/, 864 | contains:[e.BACKSLASH_ESCAPE,i,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"/,end:/"/, 865 | contains:[e.BACKSLASH_ESCAPE,i,s]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},t={ 866 | className:"number",relevance:0,variants:[{begin:e.BINARY_NUMBER_RE+"[lLjJ]?"},{ 867 | begin:"\\b(0o[0-7]+)[lLjJ]?"},{begin:e.C_NUMBER_RE+"[lLjJ]?"}]},l={ 868 | className:"params",variants:[{begin:/\(\s*\)/,skip:!0,className:null},{ 869 | begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n, 870 | contains:["self",a,t,r,e.HASH_COMMENT_MODE]}]};return s.contains=[r,t,a],{ 871 | name:"Python",aliases:["py","gyp","ipython"],keywords:n, 872 | illegal:/(<\/|->|\?)|=>/,contains:[a,t,{beginKeywords:"if",relevance:0 873 | },r,e.HASH_COMMENT_MODE,{variants:[{className:"function",beginKeywords:"def"},{ 874 | className:"class",beginKeywords:"class"}],end:/:/,illegal:/[${=;\n,]/, 875 | contains:[e.UNDERSCORE_TITLE_MODE,l,{begin:/->/,endsWithParent:!0, 876 | keywords:"None"}]},{className:"meta",begin:/^[\t ]*@/,end:/$/},{ 877 | begin:/\b(print|exec)\(/}]}}}()); 878 | hljs.registerLanguage("python-repl",function(){"use strict";return function(n){ 879 | return{aliases:["pycon"],contains:[{className:"meta",starts:{end:/ |$/,starts:{ 880 | end:"$",subLanguage:"python"}},variants:[{begin:/^>>>(?=[ ]|$)/},{ 881 | begin:/^\.\.\.(?=[ ]|$)/}]}]}}}()); 882 | hljs.registerLanguage("ruby",function(){"use strict";return function(e){ 883 | var n="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?",a={ 884 | keyword:"and then defined module in return redo if BEGIN retry end for self when next until do begin unless END rescue else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor", 885 | literal:"true false nil"},s={className:"doctag",begin:"@[A-Za-z]+"},i={ 886 | begin:"#<",end:">"},r=[e.COMMENT("#","$",{contains:[s] 887 | }),e.COMMENT("^\\=begin","^\\=end",{contains:[s],relevance:10 888 | }),e.COMMENT("^__END__","\\n$")],c={className:"subst",begin:"#\\{",end:"}", 889 | keywords:a},t={className:"string",contains:[e.BACKSLASH_ESCAPE,c],variants:[{ 890 | begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{ 891 | begin:"%[qQwWx]?\\(",end:"\\)"},{begin:"%[qQwWx]?\\[",end:"\\]"},{ 892 | begin:"%[qQwWx]?{",end:"}"},{begin:"%[qQwWx]?<",end:">"},{begin:"%[qQwWx]?/", 893 | end:"/"},{begin:"%[qQwWx]?%",end:"%"},{begin:"%[qQwWx]?-",end:"-"},{ 894 | begin:"%[qQwWx]?\\|",end:"\\|"},{ 895 | begin:/\B\?(\\\d{1,3}|\\x[A-Fa-f0-9]{1,2}|\\u[A-Fa-f0-9]{4}|\\?\S)\b/},{ 896 | begin:/<<[-~]?'?(\w+)(?:.|\n)*?\n\s*\1\b/,returnBegin:!0,contains:[{ 897 | begin:/<<[-~]?'?/},e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/, 898 | contains:[e.BACKSLASH_ESCAPE,c]})]}]},b={className:"params",begin:"\\(", 899 | end:"\\)",endsParent:!0,keywords:a},d=[t,i,{className:"class", 900 | beginKeywords:"class module",end:"$|;",illegal:/=/, 901 | contains:[e.inherit(e.TITLE_MODE,{begin:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?"}),{ 902 | begin:"<\\s*",contains:[{begin:"("+e.IDENT_RE+"::)?"+e.IDENT_RE}]}].concat(r)},{ 903 | className:"function",beginKeywords:"def",end:"$|;", 904 | contains:[e.inherit(e.TITLE_MODE,{begin:n}),b].concat(r)},{begin:e.IDENT_RE+"::" 905 | },{className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"(\\!|\\?)?:",relevance:0},{ 906 | className:"symbol",begin:":(?!\\s)",contains:[t,{begin:n}],relevance:0},{ 907 | className:"number", 908 | begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b", 909 | relevance:0},{begin:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{className:"params", 910 | begin:/\|/,end:/\|/,keywords:a},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*", 911 | keywords:"unless",contains:[i,{className:"regexp", 912 | contains:[e.BACKSLASH_ESCAPE,c],illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*" 913 | },{begin:"%r{",end:"}[a-z]*"},{begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!", 914 | end:"![a-z]*"},{begin:"%r\\[",end:"\\][a-z]*"}]}].concat(r),relevance:0 915 | }].concat(r);c.contains=d,b.contains=d;var g=[{begin:/^\s*=>/,starts:{end:"$", 916 | contains:d}},{className:"meta", 917 | begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+>|(\\w+-)?\\d+\\.\\d+\\.\\d(p\\d+)?[^>]+>)", 918 | starts:{end:"$",contains:d}}];return{name:"Ruby", 919 | aliases:["rb","gemspec","podspec","thor","irb"],keywords:a,illegal:/\/\*/, 920 | contains:r.concat(g).concat(d)}}}()); 921 | hljs.registerLanguage("rust",function(){"use strict";return function(e){ 922 | var n="([ui](8|16|32|64|128|size)|f(32|64))?",t="drop i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize f32 f64 str char bool Box Option Result String Vec Copy Send Sized Sync Drop Fn FnMut FnOnce ToOwned Clone Debug PartialEq PartialOrd Eq Ord AsRef AsMut Into From Default Iterator Extend IntoIterator DoubleEndedIterator ExactSizeIterator SliceConcatExt ToString assert! assert_eq! bitflags! bytes! cfg! col! concat! concat_idents! debug_assert! debug_assert_eq! env! panic! file! format! format_args! include_bin! include_str! line! local_data_key! module_path! option_env! print! println! select! stringify! try! unimplemented! unreachable! vec! write! writeln! macro_rules! assert_ne! debug_assert_ne!" 923 | ;return{name:"Rust",aliases:["rs"],keywords:{$pattern:e.IDENT_RE+"!?", 924 | keyword:"abstract as async await become box break const continue crate do dyn else enum extern false final fn for if impl in let loop macro match mod move mut override priv pub ref return self Self static struct super trait true try type typeof unsafe unsized use virtual where while yield", 925 | literal:"true false Some None Ok Err",built_in:t},illegal:""}]}}}()); 942 | hljs.registerLanguage("scss",function(){"use strict";return function(e){ 943 | var t="@[a-z-]+",i={className:"variable",begin:"(\\$[a-zA-Z-][a-zA-Z0-9_-]*)\\b" 944 | },r={className:"number",begin:"#[0-9A-Fa-f]+"} 945 | ;return e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE, 946 | e.APOS_STRING_MODE,e.C_BLOCK_COMMENT_MODE,{name:"SCSS",case_insensitive:!0, 947 | illegal:"[=/|']",contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{ 948 | className:"selector-id",begin:"\\#[A-Za-z0-9_-]+",relevance:0},{ 949 | className:"selector-class",begin:"\\.[A-Za-z0-9_-]+",relevance:0},{ 950 | className:"selector-attr",begin:"\\[",end:"\\]",illegal:"$"},{ 951 | className:"selector-tag", 952 | begin:"\\b(a|abbr|acronym|address|area|article|aside|audio|b|base|big|blockquote|body|br|button|canvas|caption|cite|code|col|colgroup|command|datalist|dd|del|details|dfn|div|dl|dt|em|embed|fieldset|figcaption|figure|footer|form|frame|frameset|(h[1-6])|head|header|hgroup|hr|html|i|iframe|img|input|ins|kbd|keygen|label|legend|li|link|map|mark|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre|progress|q|rp|rt|ruby|samp|script|section|select|small|span|strike|strong|style|sub|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|tt|ul|var|video)\\b", 953 | relevance:0},{className:"selector-pseudo", 954 | begin:":(visited|valid|root|right|required|read-write|read-only|out-range|optional|only-of-type|only-child|nth-of-type|nth-last-of-type|nth-last-child|nth-child|not|link|left|last-of-type|last-child|lang|invalid|indeterminate|in-range|hover|focus|first-of-type|first-line|first-letter|first-child|first|enabled|empty|disabled|default|checked|before|after|active)" 955 | },{className:"selector-pseudo", 956 | begin:"::(after|before|choices|first-letter|first-line|repeat-index|repeat-item|selection|value)" 957 | },i,{className:"attribute", 958 | begin:"\\b(src|z-index|word-wrap|word-spacing|word-break|width|widows|white-space|visibility|vertical-align|unicode-bidi|transition-timing-function|transition-property|transition-duration|transition-delay|transition|transform-style|transform-origin|transform|top|text-underline-position|text-transform|text-shadow|text-rendering|text-overflow|text-indent|text-decoration-style|text-decoration-line|text-decoration-color|text-decoration|text-align-last|text-align|tab-size|table-layout|right|resize|quotes|position|pointer-events|perspective-origin|perspective|page-break-inside|page-break-before|page-break-after|padding-top|padding-right|padding-left|padding-bottom|padding|overflow-y|overflow-x|overflow-wrap|overflow|outline-width|outline-style|outline-offset|outline-color|outline|orphans|order|opacity|object-position|object-fit|normal|none|nav-up|nav-right|nav-left|nav-index|nav-down|min-width|min-height|max-width|max-height|mask|marks|margin-top|margin-right|margin-left|margin-bottom|margin|list-style-type|list-style-position|list-style-image|list-style|line-height|letter-spacing|left|justify-content|initial|inherit|ime-mode|image-orientation|image-resolution|image-rendering|icon|hyphens|height|font-weight|font-variant-ligatures|font-variant|font-style|font-stretch|font-size-adjust|font-size|font-language-override|font-kerning|font-feature-settings|font-family|font|float|flex-wrap|flex-shrink|flex-grow|flex-flow|flex-direction|flex-basis|flex|filter|empty-cells|display|direction|cursor|counter-reset|counter-increment|content|column-width|column-span|column-rule-width|column-rule-style|column-rule-color|column-rule|column-gap|column-fill|column-count|columns|color|clip-path|clip|clear|caption-side|break-inside|break-before|break-after|box-sizing|box-shadow|box-decoration-break|bottom|border-width|border-top-width|border-top-style|border-top-right-radius|border-top-left-radius|border-top-color|border-top|border-style|border-spacing|border-right-width|border-right-style|border-right-color|border-right|border-radius|border-left-width|border-left-style|border-left-color|border-left|border-image-width|border-image-source|border-image-slice|border-image-repeat|border-image-outset|border-image|border-color|border-collapse|border-bottom-width|border-bottom-style|border-bottom-right-radius|border-bottom-left-radius|border-bottom-color|border-bottom|border|background-size|background-repeat|background-position|background-origin|background-image|background-color|background-clip|background-attachment|background-blend-mode|background|backface-visibility|auto|animation-timing-function|animation-play-state|animation-name|animation-iteration-count|animation-fill-mode|animation-duration|animation-direction|animation-delay|animation|align-self|align-items|align-content)\\b", 959 | illegal:"[^\\s]"},{ 960 | begin:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b" 961 | },{begin:":",end:";", 962 | contains:[i,r,e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,{ 963 | className:"meta",begin:"!important"}]},{begin:"@(page|font-face)",lexemes:t, 964 | keywords:"@page @font-face"},{begin:"@",end:"[{;]",returnBegin:!0, 965 | keywords:"and or not only",contains:[{begin:t,className:"keyword" 966 | },i,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,r,e.CSS_NUMBER_MODE]}]}}}()); 967 | hljs.registerLanguage("shell",function(){"use strict";return function(s){return{ 968 | name:"Shell Session",aliases:["console"],contains:[{className:"meta", 969 | begin:"^\\s{0,3}[/\\w\\d\\[\\]()@-]*[>%$#]",starts:{end:"$",subLanguage:"bash"} 970 | }]}}}()); 971 | hljs.registerLanguage("sql",function(){"use strict";return function(e){ 972 | var t=e.COMMENT("--","$");return{name:"SQL",case_insensitive:!0, 973 | illegal:/[<>{}*]/,contains:[{ 974 | beginKeywords:"begin end start commit rollback savepoint lock alter create drop rename call delete do handler insert load replace select truncate update set show pragma grant merge describe use explain help declare prepare execute deallocate release unlock purge reset change stop analyze cache flush optimize repair kill install uninstall checksum restore check backup revoke comment values with", 975 | end:/;/,endsWithParent:!0,keywords:{$pattern:/[\w\.]+/, 976 | keyword:"as abort abs absolute acc acce accep accept access accessed accessible account acos action activate add addtime admin administer advanced advise aes_decrypt aes_encrypt after agent aggregate ali alia alias all allocate allow alter always analyze ancillary and anti any anydata anydataset anyschema anytype apply archive archived archivelog are as asc ascii asin assembly assertion associate asynchronous at atan atn2 attr attri attrib attribu attribut attribute attributes audit authenticated authentication authid authors auto autoallocate autodblink autoextend automatic availability avg backup badfile basicfile before begin beginning benchmark between bfile bfile_base big bigfile bin binary_double binary_float binlog bit_and bit_count bit_length bit_or bit_xor bitmap blob_base block blocksize body both bound bucket buffer_cache buffer_pool build bulk by byte byteordermark bytes cache caching call calling cancel capacity cascade cascaded case cast catalog category ceil ceiling chain change changed char_base char_length character_length characters characterset charindex charset charsetform charsetid check checksum checksum_agg child choose chr chunk class cleanup clear client clob clob_base clone close cluster_id cluster_probability cluster_set clustering coalesce coercibility col collate collation collect colu colum column column_value columns columns_updated comment commit compact compatibility compiled complete composite_limit compound compress compute concat concat_ws concurrent confirm conn connec connect connect_by_iscycle connect_by_isleaf connect_by_root connect_time connection consider consistent constant constraint constraints constructor container content contents context contributors controlfile conv convert convert_tz corr corr_k corr_s corresponding corruption cos cost count count_big counted covar_pop covar_samp cpu_per_call cpu_per_session crc32 create creation critical cross cube cume_dist curdate current current_date current_time current_timestamp current_user cursor curtime customdatum cycle data database databases datafile datafiles datalength date_add date_cache date_format date_sub dateadd datediff datefromparts datename datepart datetime2fromparts day day_to_second dayname dayofmonth dayofweek dayofyear days db_role_change dbtimezone ddl deallocate declare decode decompose decrement decrypt deduplicate def defa defau defaul default defaults deferred defi defin define degrees delayed delegate delete delete_all delimited demand dense_rank depth dequeue des_decrypt des_encrypt des_key_file desc descr descri describ describe descriptor deterministic diagnostics difference dimension direct_load directory disable disable_all disallow disassociate discardfile disconnect diskgroup distinct distinctrow distribute distributed div do document domain dotnet double downgrade drop dumpfile duplicate duration each edition editionable editions element ellipsis else elsif elt empty enable enable_all enclosed encode encoding encrypt end end-exec endian enforced engine engines enqueue enterprise entityescaping eomonth error errors escaped evalname evaluate event eventdata events except exception exceptions exchange exclude excluding execu execut execute exempt exists exit exp expire explain explode export export_set extended extent external external_1 external_2 externally extract failed failed_login_attempts failover failure far fast feature_set feature_value fetch field fields file file_name_convert filesystem_like_logging final finish first first_value fixed flash_cache flashback floor flush following follows for forall force foreign form forma format found found_rows freelist freelists freepools fresh from from_base64 from_days ftp full function general generated get get_format get_lock getdate getutcdate global global_name globally go goto grant grants greatest group group_concat group_id grouping grouping_id groups gtid_subtract guarantee guard handler hash hashkeys having hea head headi headin heading heap help hex hierarchy high high_priority hosts hour hours http id ident_current ident_incr ident_seed identified identity idle_time if ifnull ignore iif ilike ilm immediate import in include including increment index indexes indexing indextype indicator indices inet6_aton inet6_ntoa inet_aton inet_ntoa infile initial initialized initially initrans inmemory inner innodb input insert install instance instantiable instr interface interleaved intersect into invalidate invisible is is_free_lock is_ipv4 is_ipv4_compat is_not is_not_null is_used_lock isdate isnull isolation iterate java join json json_exists keep keep_duplicates key keys kill language large last last_day last_insert_id last_value lateral lax lcase lead leading least leaves left len lenght length less level levels library like like2 like4 likec limit lines link list listagg little ln load load_file lob lobs local localtime localtimestamp locate locator lock locked log log10 log2 logfile logfiles logging logical logical_reads_per_call logoff logon logs long loop low low_priority lower lpad lrtrim ltrim main make_set makedate maketime managed management manual map mapping mask master master_pos_wait match matched materialized max maxextents maximize maxinstances maxlen maxlogfiles maxloghistory maxlogmembers maxsize maxtrans md5 measures median medium member memcompress memory merge microsecond mid migration min minextents minimum mining minus minute minutes minvalue missing mod mode model modification modify module monitoring month months mount move movement multiset mutex name name_const names nan national native natural nav nchar nclob nested never new newline next nextval no no_write_to_binlog noarchivelog noaudit nobadfile nocheck nocompress nocopy nocycle nodelay nodiscardfile noentityescaping noguarantee nokeep nologfile nomapping nomaxvalue nominimize nominvalue nomonitoring none noneditionable nonschema noorder nopr nopro noprom nopromp noprompt norely noresetlogs noreverse normal norowdependencies noschemacheck noswitch not nothing notice notnull notrim novalidate now nowait nth_value nullif nulls num numb numbe nvarchar nvarchar2 object ocicoll ocidate ocidatetime ociduration ociinterval ociloblocator ocinumber ociref ocirefcursor ocirowid ocistring ocitype oct octet_length of off offline offset oid oidindex old on online only opaque open operations operator optimal optimize option optionally or oracle oracle_date oradata ord ordaudio orddicom orddoc order ordimage ordinality ordvideo organization orlany orlvary out outer outfile outline output over overflow overriding package pad parallel parallel_enable parameters parent parse partial partition partitions pascal passing password password_grace_time password_lock_time password_reuse_max password_reuse_time password_verify_function patch path patindex pctincrease pctthreshold pctused pctversion percent percent_rank percentile_cont percentile_disc performance period period_add period_diff permanent physical pi pipe pipelined pivot pluggable plugin policy position post_transaction pow power pragma prebuilt precedes preceding precision prediction prediction_cost prediction_details prediction_probability prediction_set prepare present preserve prior priority private private_sga privileges procedural procedure procedure_analyze processlist profiles project prompt protection public publishingservername purge quarter query quick quiesce quota quotename radians raise rand range rank raw read reads readsize rebuild record records recover recovery recursive recycle redo reduced ref reference referenced references referencing refresh regexp_like register regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy reject rekey relational relative relaylog release release_lock relies_on relocate rely rem remainder rename repair repeat replace replicate replication required reset resetlogs resize resource respect restore restricted result result_cache resumable resume retention return returning returns reuse reverse revoke right rlike role roles rollback rolling rollup round row row_count rowdependencies rowid rownum rows rtrim rules safe salt sample save savepoint sb1 sb2 sb4 scan schema schemacheck scn scope scroll sdo_georaster sdo_topo_geometry search sec_to_time second seconds section securefile security seed segment select self semi sequence sequential serializable server servererror session session_user sessions_per_user set sets settings sha sha1 sha2 share shared shared_pool short show shrink shutdown si_averagecolor si_colorhistogram si_featurelist si_positionalcolor si_stillimage si_texture siblings sid sign sin size size_t sizes skip slave sleep smalldatetimefromparts smallfile snapshot some soname sort soundex source space sparse spfile split sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_small_result sql_variant_property sqlcode sqldata sqlerror sqlname sqlstate sqrt square standalone standby start starting startup statement static statistics stats_binomial_test stats_crosstab stats_ks_test stats_mode stats_mw_test stats_one_way_anova stats_t_test_ stats_t_test_indep stats_t_test_one stats_t_test_paired stats_wsr_test status std stddev stddev_pop stddev_samp stdev stop storage store stored str str_to_date straight_join strcmp strict string struct stuff style subdate subpartition subpartitions substitutable substr substring subtime subtring_index subtype success sum suspend switch switchoffset switchover sync synchronous synonym sys sys_xmlagg sysasm sysaux sysdate sysdatetimeoffset sysdba sysoper system system_user sysutcdatetime table tables tablespace tablesample tan tdo template temporary terminated tertiary_weights test than then thread through tier ties time time_format time_zone timediff timefromparts timeout timestamp timestampadd timestampdiff timezone_abbr timezone_minute timezone_region to to_base64 to_date to_days to_seconds todatetimeoffset trace tracking transaction transactional translate translation treat trigger trigger_nestlevel triggers trim truncate try_cast try_convert try_parse type ub1 ub2 ub4 ucase unarchived unbounded uncompress under undo unhex unicode uniform uninstall union unique unix_timestamp unknown unlimited unlock unnest unpivot unrecoverable unsafe unsigned until untrusted unusable unused update updated upgrade upped upper upsert url urowid usable usage use use_stored_outlines user user_data user_resources users using utc_date utc_timestamp uuid uuid_short validate validate_password_strength validation valist value values var var_samp varcharc vari varia variab variabl variable variables variance varp varraw varrawc varray verify version versions view virtual visible void wait wallet warning warnings week weekday weekofyear wellformed when whene whenev wheneve whenever where while whitespace window with within without work wrapped xdb xml xmlagg xmlattributes xmlcast xmlcolattval xmlelement xmlexists xmlforest xmlindex xmlnamespaces xmlpi xmlquery xmlroot xmlschema xmlserialize xmltable xmltype xor year year_to_month years yearweek", 977 | literal:"true false null unknown", 978 | built_in:"array bigint binary bit blob bool boolean char character date dec decimal float int int8 integer interval number numeric real record serial serial8 smallint text time timestamp tinyint varchar varchar2 varying void" 979 | },contains:[{className:"string",begin:"'",end:"'",contains:[{begin:"''"}]},{ 980 | className:"string",begin:'"',end:'"',contains:[{begin:'""'}]},{ 981 | className:"string",begin:"`",end:"`" 982 | },e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,t,e.HASH_COMMENT_MODE] 983 | },e.C_BLOCK_COMMENT_MODE,t,e.HASH_COMMENT_MODE]}}}()); 984 | hljs.registerLanguage("swift",function(){"use strict";return function(e){var i={ 985 | keyword:"#available #colorLiteral #column #else #elseif #endif #file #fileLiteral #function #if #imageLiteral #line #selector #sourceLocation _ __COLUMN__ __FILE__ __FUNCTION__ __LINE__ Any as as! as? associatedtype associativity break case catch class continue convenience default defer deinit didSet do dynamic dynamicType else enum extension fallthrough false fileprivate final for func get guard if import in indirect infix init inout internal is lazy left let mutating nil none nonmutating open operator optional override postfix precedence prefix private protocol Protocol public repeat required rethrows return right self Self set static struct subscript super switch throw throws true try try! try? Type typealias unowned var weak where while willSet", 986 | literal:"true false nil", 987 | built_in:"abs advance alignof alignofValue anyGenerator assert assertionFailure bridgeFromObjectiveC bridgeFromObjectiveCUnconditional bridgeToObjectiveC bridgeToObjectiveCUnconditional c compactMap contains count countElements countLeadingZeros debugPrint debugPrintln distance dropFirst dropLast dump encodeBitsAsWords enumerate equal fatalError filter find getBridgedObjectiveCType getVaList indices insertionSort isBridgedToObjectiveC isBridgedVerbatimToObjectiveC isUniquelyReferenced isUniquelyReferencedNonObjC join lazy lexicographicalCompare map max maxElement min minElement numericCast overlaps partition posix precondition preconditionFailure print println quickSort readLine reduce reflect reinterpretCast reverse roundUpToAlignment sizeof sizeofValue sort split startsWith stride strideof strideofValue swap toString transcode underestimateCount unsafeAddressOf unsafeBitCast unsafeDowncast unsafeUnwrap unsafeReflect withExtendedLifetime withObjectAtPlusZero withUnsafePointer withUnsafePointerToObject withUnsafeMutablePointer withUnsafeMutablePointers withUnsafePointer withUnsafePointers withVaList zip" 988 | },n=e.COMMENT("/\\*","\\*/",{contains:["self"]}),t={className:"subst", 989 | begin:/\\\(/,end:"\\)",keywords:i,contains:[]},a={className:"string", 990 | contains:[e.BACKSLASH_ESCAPE,t],variants:[{begin:/"""/,end:/"""/},{begin:/"/, 991 | end:/"/}]},r={className:"number", 992 | begin:"\\b([\\d_]+(\\.[\\deE_]+)?|0x[a-fA-F0-9_]+(\\.[a-fA-F0-9p_]+)?|0b[01_]+|0o[0-7_]+)\\b", 993 | relevance:0};return t.contains=[r],{name:"Swift",keywords:i, 994 | contains:[a,e.C_LINE_COMMENT_MODE,n,{className:"type", 995 | begin:"\\b[A-Z][\\w\xc0-\u02b8']*[!?]"},{className:"type", 996 | begin:"\\b[A-Z][\\w\xc0-\u02b8']*",relevance:0},r,{className:"function", 997 | beginKeywords:"func",end:"{",excludeEnd:!0,contains:[e.inherit(e.TITLE_MODE,{ 998 | begin:/[A-Za-z$_][0-9A-Za-z$_]*/}),{begin://},{className:"params", 999 | begin:/\(/,end:/\)/,endsParent:!0,keywords:i, 1000 | contains:["self",r,a,e.C_BLOCK_COMMENT_MODE,{begin:":"}],illegal:/["']/}], 1001 | illegal:/\[|%/},{className:"class", 1002 | beginKeywords:"struct protocol class extension enum",keywords:i,end:"\\{", 1003 | excludeEnd:!0,contains:[e.inherit(e.TITLE_MODE,{ 1004 | begin:/[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/})]},{className:"meta", 1005 | begin:"(@discardableResult|@warn_unused_result|@exported|@lazy|@noescape|@NSCopying|@NSManaged|@objc|@objcMembers|@convention|@required|@noreturn|@IBAction|@IBDesignable|@IBInspectable|@IBOutlet|@infix|@prefix|@postfix|@autoclosure|@testable|@available|@nonobjc|@NSApplicationMain|@UIApplicationMain|@dynamicMemberLookup|@propertyWrapper)\\b" 1006 | },{beginKeywords:"import",end:/$/,contains:[e.C_LINE_COMMENT_MODE,n]}]}}}()); 1007 | hljs.registerLanguage("typescript",function(){"use strict" 1008 | ;const e="[A-Za-z$_][0-9A-Za-z$_]*",n=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],a=["true","false","null","undefined","NaN","Infinity"],s=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]) 1009 | ;function t(e){return r("(?=",e,")")}function i(e){return r("(",e,")?")} 1010 | function r(...e){return e.map((e=>{ 1011 | return(n=e)?"string"==typeof n?n:n.source:null;var n})).join("")} 1012 | return function(c){const o={$pattern:e, 1013 | keyword:n.concat(["type","namespace","typedef","interface","public","private","protected","implements","declare","abstract","readonly"]).join(" "), 1014 | literal:a.join(" "), 1015 | built_in:s.concat(["any","void","number","boolean","string","object","never","enum"]).join(" ") 1016 | },l={className:"meta",begin:"@[A-Za-z$_][0-9A-Za-z$_]*"},d=(e,n,a)=>{ 1017 | const s=e.contains.findIndex((e=>e.label===n)) 1018 | ;if(-1===s)throw Error("can not find mode to replace");e.contains.splice(s,1,a) 1019 | },g=function(c){const o=e,l={begin:/<[A-Za-z0-9\\._:-]+/, 1020 | end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(e,n)=>{ 1021 | const a=e[0].length+e.index,s=e.input[a];"<"!==s?">"===s&&(((e,{after:n})=>{ 1022 | const a=e[0].replace("<","`\\b0[${e}][${n}]([${n}_]*[${n}])?n?`,b=/[1-9]([0-9_]*\d)?/,u=/\d([0-9_]*\d)?/,E=r(/[eE][+-]?/,u),m={ 1026 | className:"number",variants:[{begin:g("bB","01")},{begin:g("oO","0-7")},{ 1027 | begin:g("xX","0-9a-fA-F")},{begin:r(/\b/,b,"n")},{begin:r(/(\b0)?\./,u,i(E))},{ 1028 | begin:r(/\b/,b,i(r(/\./,i(u))),i(E))},{begin:/\b0[\.n]?/}],relevance:0},y={ 1029 | className:"subst",begin:"\\$\\{",end:"\\}",keywords:d,contains:[]},p={ 1030 | begin:"html`",end:"",starts:{end:"`",returnEnd:!1, 1031 | contains:[c.BACKSLASH_ESCAPE,y],subLanguage:"xml"}},_={begin:"css`",end:"", 1032 | starts:{end:"`",returnEnd:!1,contains:[c.BACKSLASH_ESCAPE,y],subLanguage:"css"} 1033 | },N={className:"string",begin:"`",end:"`",contains:[c.BACKSLASH_ESCAPE,y]},f={ 1034 | className:"comment",variants:[c.COMMENT("/\\*\\*","\\*/",{relevance:0, 1035 | contains:[{className:"doctag",begin:"@[A-Za-z]+",contains:[{className:"type", 1036 | begin:"\\{",end:"\\}",relevance:0},{className:"variable", 1037 | begin:o+"(?=\\s*(-)|$)",endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/, 1038 | relevance:0}]}]}),c.C_BLOCK_COMMENT_MODE,c.C_LINE_COMMENT_MODE] 1039 | },A=[c.APOS_STRING_MODE,c.QUOTE_STRING_MODE,p,_,N,m,c.REGEXP_MODE] 1040 | ;y.contains=A.concat({begin:/{/,end:/}/,keywords:d,contains:["self"].concat(A)}) 1041 | ;const O=[].concat(f,y.contains),S=O.concat([{begin:/\(/,end:/\)/,keywords:d, 1042 | contains:["self"].concat(O)}]),T={className:"params",begin:/\(/,end:/\)/, 1043 | excludeBegin:!0,excludeEnd:!0,keywords:d,contains:S};return{name:"Javascript", 1044 | aliases:["js","jsx","mjs","cjs"],keywords:d,exports:{PARAMS_CONTAINS:S}, 1045 | illegal:/#(?![$_A-z])/,contains:[c.SHEBANG({label:"shebang",binary:"node", 1046 | relevance:5}),{label:"use_strict",className:"meta",relevance:10, 1047 | begin:/^\s*['"]use (strict|asm)['"]/ 1048 | },c.APOS_STRING_MODE,c.QUOTE_STRING_MODE,p,_,N,f,m,{ 1049 | begin:r(/[{,\n]\s*/,t(r(/(\/\/.*$)*/,/(\/\*(.|\n)*\*\/)*/,/\s*/,o+"\\s*:"))), 1050 | relevance:0,contains:[{className:"attr",begin:o+t("\\s*:"),relevance:0}]},{ 1051 | begin:"("+c.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*", 1052 | keywords:"return throw case",contains:[f,c.REGEXP_MODE,{className:"function", 1053 | begin:"(\\([^()]*(\\([^()]*(\\([^()]*\\))*[^()]*\\))*[^()]*\\)|"+c.UNDERSCORE_IDENT_RE+")\\s*=>", 1054 | returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{ 1055 | begin:c.UNDERSCORE_IDENT_RE},{className:null,begin:/\(\s*\)/,skip:!0},{ 1056 | begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:d,contains:S}]}]},{ 1057 | begin:/,/,relevance:0},{className:"",begin:/\s/,end:/\s*/,skip:!0},{variants:[{ 1058 | begin:"<>",end:""},{begin:l.begin,"on:begin":l.isTrulyOpeningTag,end:l.end}], 1059 | subLanguage:"xml",contains:[{begin:l.begin,end:l.end,skip:!0,contains:["self"]}] 1060 | }],relevance:0},{className:"function",beginKeywords:"function",end:/[{;]/, 1061 | excludeEnd:!0,keywords:d,contains:["self",c.inherit(c.TITLE_MODE,{begin:o}),T], 1062 | illegal:/%/},{className:"function", 1063 | begin:c.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\))*[^()]*\\))*[^()]*\\)\\s*{", 1064 | returnBegin:!0,contains:[T,c.inherit(c.TITLE_MODE,{begin:o})]},{variants:[{ 1065 | begin:"\\."+o},{begin:"\\$"+o}],relevance:0},{className:"class", 1066 | beginKeywords:"class",end:/[{;=]/,excludeEnd:!0,illegal:/[:"\[\]]/,contains:[{ 1067 | beginKeywords:"extends"},c.UNDERSCORE_TITLE_MODE]},{begin:/\b(?=constructor)/, 1068 | end:/[\{;]/,excludeEnd:!0,contains:[c.inherit(c.TITLE_MODE,{begin:o}),"self",T] 1069 | },{begin:"(get|set)\\s+(?="+o+"\\()",end:/{/,keywords:"get set", 1070 | contains:[c.inherit(c.TITLE_MODE,{begin:o}),{begin:/\(\)/},T]},{begin:/\$[(.]/}] 1071 | }}(c) 1072 | ;return Object.assign(g.keywords,o),g.exports.PARAMS_CONTAINS.push(l),g.contains=g.contains.concat([l,{ 1073 | beginKeywords:"namespace",end:/\{/,excludeEnd:!0},{beginKeywords:"interface", 1074 | end:/\{/,excludeEnd:!0,keywords:"interface extends" 1075 | }]),d(g,"shebang",c.SHEBANG()),d(g,"use_strict",{className:"meta",relevance:10, 1076 | begin:/^\s*['"]use strict['"]/ 1077 | }),g.contains.find((e=>"function"===e.className)).relevance=0,Object.assign(g,{ 1078 | name:"TypeScript",aliases:["ts"]}),g}}()); 1079 | hljs.registerLanguage("yaml",function(){"use strict";return function(e){ 1080 | var n="true false yes no null",a="[\\w#;/?:@&=+$,.~*\\'()[\\]]+",s={ 1081 | className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/ 1082 | },{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable", 1083 | variants:[{begin:"{{",end:"}}"},{begin:"%{",end:"}"}]}]},i=e.inherit(s,{ 1084 | variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),l={ 1085 | end:",",endsWithParent:!0,excludeEnd:!0,contains:[],keywords:n,relevance:0},t={ 1086 | begin:"{",end:"}",contains:[l],illegal:"\\n",relevance:0},g={begin:"\\[", 1087 | end:"\\]",contains:[l],illegal:"\\n",relevance:0},b=[{className:"attr", 1088 | variants:[{begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{ 1089 | begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)" 1090 | }]},{className:"meta",begin:"^---s*$",relevance:10},{className:"string", 1091 | begin:"[\\|>]([0-9]?[+-])?[ ]*\\n( *)[\\S ]+\\n(\\2[\\S ]+\\n?)*"},{ 1092 | begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0, 1093 | relevance:0},{className:"type",begin:"!\\w+!"+a},{className:"type", 1094 | begin:"!<"+a+">"},{className:"type",begin:"!"+a},{className:"type",begin:"!!"+a 1095 | },{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta", 1096 | begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"\\-(?=[ ]|$)", 1097 | relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{ 1098 | className:"number", 1099 | begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b" 1100 | },{className:"number",begin:e.C_NUMBER_RE+"\\b"},t,g,s],c=[...b];return c.pop(), 1101 | c.push(i),l.contains=c,{name:"YAML",case_insensitive:!0,aliases:["yml","YAML"], 1102 | contains:b}}}()); 1103 | 1104 | // original from https://github.com/leanprover-community/highlightjs-lean/blob/master/src/lean.js, BSD 3, (c) 2020 Patrick Massot 1105 | hljs.registerLanguage("lean", function(hljs) { 1106 | var LEAN_KEYWORDS = { 1107 | $pattern: /#?\w+/, 1108 | keyword: 1109 | 'theorem|10 def class structure instance set_option ' + 1110 | 'example inductive coinductive ' + 1111 | 'axiom constant ' + 1112 | 'partial unsafe private protected ' + 1113 | 'if then else ' + 1114 | 'universe variable ' + 1115 | 'import open export prelude renaming hiding ' + 1116 | 'calc match with do by let extends ' + 1117 | 'for in unless try catch finally mutual mut return continue break where rec ' + 1118 | 'syntax macro_rules macro deriving ' + 1119 | 'fun ' + 1120 | '#check #check_failure #eval #reduce #print ' + 1121 | 'section namespace end infix infixl infixr postfix prefix notation ', 1122 | built_in: 1123 | 'Type Prop|10 Sort rw|10 rewrite rwa erw subst substs ' + 1124 | 'simp dsimp simpa simp_intros finish using generalizing ' + 1125 | 'unfold unfold1 dunfold unfold_projs unfold_coes ' + 1126 | 'delta cc ac_rfl ' + 1127 | 'existsi|10 cases rcases intro intros introv by_cases ' + 1128 | 'refl rfl funext case focus propext exact exacts ' + 1129 | 'refine apply eapply fapply apply_with apply_instance ' + 1130 | 'induction rename assumption revert generalize specialize clear ' + 1131 | 'contradiction by_contradiction by_contra trivial exfalso ' + 1132 | 'symmetry transitivity destruct constructor econstructor ' + 1133 | 'left right split injection injections ' + 1134 | 'repeat skip swap solve1 abstract all_goals any_goals done ' + 1135 | 'fail_if_success success_if_fail guard_target guard_hyp ' + 1136 | 'have replace at suffices show from ' + 1137 | 'congr congr_n congr_arg norm_num ring ', 1138 | literal: 1139 | 'true false', 1140 | meta: 1141 | 'noncomputable|10 private protected mutual', 1142 | strong: 1143 | 'sorry admit', 1144 | }; 1145 | 1146 | var LEAN_IDENT_RE = /[A-Za-z_][\\w\u207F-\u209C\u1D62-\u1D6A\u2079\'0-9?]*/; 1147 | 1148 | var DASH_COMMENT = hljs.COMMENT('--', '$'); 1149 | var MULTI_LINE_COMMENT = hljs.COMMENT('/-[^-]', '-/'); 1150 | var DOC_COMMENT = { 1151 | className: 'doctag', 1152 | begin: '/-[-!]', 1153 | end: '-/' 1154 | }; 1155 | 1156 | var ATTRIBUTE_DECORATOR = { 1157 | className: 'meta', 1158 | begin: '@\\[', 1159 | end: '\\]' 1160 | }; 1161 | 1162 | var ATTRIBUTE_LINE = { 1163 | className: 'meta', 1164 | begin: '^attribute', 1165 | end: '$' 1166 | }; 1167 | 1168 | var LEAN_DEFINITION = { 1169 | className: 'theorem', 1170 | begin: '\\b(def|theorem|lemma|class|structure|(?