10 files changed, 254 insertions(+), 220 deletions(-)
CHANGELOG.md+1| ... | @@ -7,6 +7,7 @@ | ... | @@ -7,6 +7,7 @@ |
| 7 | - feat(transform): parse string escapes properly | 7 | - feat(transform): parse string escapes properly |
| 8 | - feat(link): print string escapes properly | 8 | - feat(link): print string escapes properly |
| 9 | - feat: implement the `comptime` keyword (many comptime ops are not implemented) | 9 | - feat: implement the `comptime` keyword (many comptime ops are not implemented) |
| 10 | - feat: add `@jsNew` to create JavaScript `new` expressions | ||
| 10 | - fix(sema): properly coerce assignments | 11 | - fix(sema): properly coerce assignments |
| 11 | - fix(transform): empty block generated in top level code tripped sema assertion | 12 | - fix(transform): empty block generated in top level code tripped sema assertion |
| 12 | - fix(link): emit parenthesis to preserve operator precedence | 13 | - fix(link): emit parenthesis to preserve operator precedence |
build.zig+4-4| ... | @@ -58,7 +58,7 @@ pub fn build(b: *std.Build) void { | ... | @@ -58,7 +58,7 @@ pub fn build(b: *std.Build) void { |
| 58 | test_all.dependOn(run_step); | 58 | test_all.dependOn(run_step); |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | // Language Server | 61 | // Language Reference Generator |
| 62 | const langref_generator = b.addExecutable(.{ | 62 | const langref_generator = b.addExecutable(.{ |
| 63 | .name = "generate-langref", | 63 | .name = "generate-langref", |
| 64 | .root_source_file = b.path("src/langref/generate-langref.zig"), | 64 | .root_source_file = b.path("src/langref/generate-langref.zig"), |
| ... | @@ -70,10 +70,10 @@ pub fn build(b: *std.Build) void { | ... | @@ -70,10 +70,10 @@ pub fn build(b: *std.Build) void { |
| 70 | langref_generator.root_module.addImport("core", native_debug.core); | 70 | langref_generator.root_module.addImport("core", native_debug.core); |
| 71 | const langref_run = b.addRunArtifact(langref_generator); | 71 | const langref_run = b.addRunArtifact(langref_generator); |
| 72 | langref_run.addFileArg(native_debug.compiler.getEmittedBin()); | 72 | langref_run.addFileArg(native_debug.compiler.getEmittedBin()); |
| 73 | langref_run.addFileArg(b.path("doc/langref.md")); | 73 | langref_run.addFileArg(b.path("doc/language-reference.md")); |
| 74 | langref_run.addFileArg(b.path("src/langref/langref.template.html")); | 74 | langref_run.addFileArg(b.path("src/langref/template.html")); |
| 75 | const langref_out = langref_run.addOutputFileArg("language-reference.html"); | 75 | const langref_out = langref_run.addOutputFileArg("language-reference.html"); |
| 76 | const install_langref = b.addInstallFile(langref_out, "doc/langref.html"); | 76 | const install_langref = b.addInstallFile(langref_out, "doc/README.html"); |
| 77 | b.step("langref", "build language reference").dependOn(&install_langref.step); | 77 | b.step("langref", "build language reference").dependOn(&install_langref.step); |
| 78 | 78 | ||
| 79 | // const wasm_api = b.addExecutable(.{ | 79 | // const wasm_api = b.addExecutable(.{ |
doc/architecture.md created+7| ... | @@ -0,0 +1,7 @@ | ||
| 1 | # compiler architecture | ||
| 2 | |||
| 3 | This document will outline the code structure of the language's SDK as well as the compilation pipeline architecture. The major components of the language are: | ||
| 4 | |||
| 5 | - [**Core**][core] | ||
| 6 | - [**Standard Library**][std] | ||
| 7 | - [**Language Server**][lsp] | ||
doc/langref.md deleted-137| ... | @@ -1,137 +0,0 @@ | ||
| 1 | # New Language Project | ||
| 2 | |||
| 3 | This is a high-level, general purpose programming language. It is a mix of Rust, Zig, and JavaScript's great points. | ||
| 4 | |||
| 5 | - **Rust** - Expressive control flow that is easy to write. | ||
| 6 | - **Zig** - Execute any code at compile time, everything is an expression. | ||
| 7 | - **JavaScript** - Garbage collected values with a versitile type system. | ||
| 8 | |||
| 9 | Key goals of this project are: | ||
| 10 | |||
| 11 | - **Ease of Use**: Use of type inference keeps code concise and easy to read and write. | ||
| 12 | - **Fast Iteration**: The compiler is designed for quick incremental compilation and hot module reloading. | ||
| 13 | - TODO: some more | ||
| 14 | |||
| 15 | ## Standard Library | ||
| 16 | |||
| 17 | Currently, there is no standard library. One will be introduced later. | ||
| 18 | |||
| 19 | ## Hello World | ||
| 20 | |||
| 21 | ```lang:run | ||
| 22 | let print = @js("console").log; | ||
| 23 | print("Hello, world!"); | ||
| 24 | ``` | ||
| 25 | |||
| 26 | The `print` function is implemented by getting an external reference to the `console` JavaScript global, and then retriving the `log` property from it. | ||
| 27 | |||
| 28 | ## Primative Data Types | ||
| 29 | |||
| 30 | | name | ts equivilent | description | | ||
| 31 | | ---------- | --------------------- | ---------------------------------------------- | | ||
| 32 | | `int` | `number` | a number in signed 32-bit range | | ||
| 33 | | `float` | `number` | a 64-bit floating point number | | ||
| 34 | | `bool` | `boolean` | either `true` or `false` | | ||
| 35 | | `string` | `string` | a sequence of text characters | | ||
| 36 | | `void` | `undefined` or `null` | detectable lack of a value | | ||
| 37 | | `noreturn` | `never` | control flow prevents this value from existing | | ||
| 38 | |||
| 39 | > **note**: `bigint` is planned but not added | ||
| 40 | |||
| 41 | ## Built-in Constants | ||
| 42 | |||
| 43 | In addition to the above types being built-in constants, the following are available. | ||
| 44 | |||
| 45 | | name | description | | ||
| 46 | | ------- | ------------------------------------- | | ||
| 47 | | `true` | boolean true (result of `1 == 1`) | | ||
| 48 | | `false` | boolean false (result of `1 == 2`) | | ||
| 49 | | `std` | handle to the standard library module | | ||
| 50 | |||
| 51 | These constants are reserved names, and it is an error to re-declare them. | ||
| 52 | |||
| 53 | ```lang:build | ||
| 54 | let true = 1 == 0; | ||
| 55 | ``` | ||
| 56 | |||
| 57 | ## Variables | ||
| 58 | |||
| 59 | There are two types of variables, `let` and `var`. | ||
| 60 | |||
| 61 | `let` bindings cannot be overridden, and should be thought of as aliases of the expression within. Referring to these identifiers is equivilent to inlining it's where it was used, aside from side effect duplication. | ||
| 62 | |||
| 63 | ```lang:run | ||
| 64 | let hello: int = 1; | ||
| 65 | let world = hello + 2; | ||
| 66 | let hello = hello * world; | ||
| 67 | |||
| 68 | @js("console").log(hello); | ||
| 69 | ``` | ||
| 70 | |||
| 71 | `var` bindings create mutable memory locations at runtime. This means they can be re-assigned to: | ||
| 72 | |||
| 73 | ```lang:run | ||
| 74 | var message = "first message"; | ||
| 75 | |||
| 76 | if @js("Math").random() > 0.5 { | ||
| 77 | message = "second message" | ||
| 78 | } | ||
| 79 | |||
| 80 | @js("console").log(message); | ||
| 81 | ``` | ||
| 82 | |||
| 83 | Using `let` is preferred whenever possible, as it will lead to more readable code, and the compiler is able to optimize it better. The above can be rewritten as: | ||
| 84 | |||
| 85 | ```lang:run | ||
| 86 | let message = if @js("Math").random() > 0.5 { | ||
| 87 | "second message" | ||
| 88 | } else { | ||
| 89 | "first message" | ||
| 90 | }; | ||
| 91 | |||
| 92 | @js("console").log(message); | ||
| 93 | ``` | ||
| 94 | |||
| 95 | It should be noted that numeric literals are a comptime-only data type, meaning it cannot be assigned to a `var` without an explicit type annotation. Since `int` is a strict subset of valid `float`s, the coersion will implicitly be a float, but a compiler warning will be emitted. | ||
| 96 | |||
| 97 | ```lang | ||
| 98 | var number = 0; // `number` is a `float`, but not explicit | ||
| 99 | var number: int = 0; // `number` is `int` | ||
| 100 | var number: float = 0; // `number` is `float` | ||
| 101 | ``` | ||
| 102 | |||
| 103 | ## Functions | ||
| 104 | |||
| 105 | Functions are declared with the `fn` keyword. Parameter types must be annotated. The function body is a block, which may use implicit return to return. | ||
| 106 | |||
| 107 | ```lang:run | ||
| 108 | fn add(a: int, b: int) -> int { | ||
| 109 | a + b | ||
| 110 | } | ||
| 111 | |||
| 112 | let print = @js("console").log; | ||
| 113 | //print("Sum of 2 and 7" + add(2, 7)); | ||
| 114 | print(add(2, 7)); | ||
| 115 | ``` | ||
| 116 | |||
| 117 | > **Bug**: Return types are currently required. Omitting the `-> type` syntax currently makes the return type `void`, but this will be changed in the future to be an inferred return type. | ||
| 118 | |||
| 119 | The `return` expression can be used within functions to return early. | ||
| 120 | |||
| 121 | ```lang | ||
| 122 | fn something(a: int) -> bool { | ||
| 123 | if a == 0 { | ||
| 124 | return false; | ||
| 125 | } | ||
| 126 | |||
| 127 | a > 100 | ||
| 128 | } | ||
| 129 | ``` | ||
| 130 | |||
| 131 | ## Number Literals | ||
| 132 | |||
| 133 | TODO | ||
| 134 | |||
| 135 | ## String Literals | ||
| 136 | |||
| 137 | TODO | ||
doc/language-reference.md created+154| ... | @@ -0,0 +1,154 @@ | ||
| 1 | # New Language Project | ||
| 2 | |||
| 3 | This is a high-level, general purpose programming language. It is a mix of Rust, Zig, and JavaScript's great points. | ||
| 4 | |||
| 5 | - **Rust** - Expressive control flow that is easy to write. | ||
| 6 | - **Zig** - Execute any code at compile time, everything is an expression. | ||
| 7 | - **JavaScript** - Garbage collected values with a versitile type system. | ||
| 8 | |||
| 9 | Key goals of this project are: | ||
| 10 | |||
| 11 | - **Ease of Use**: Use of type inference keeps code concise and easy to read and write. | ||
| 12 | - **Fast Iteration**: The compiler is designed for quick incremental compilation and hot module reloading. | ||
| 13 | - TODO: some more | ||
| 14 | |||
| 15 | ## Standard Library | ||
| 16 | |||
| 17 | Currently, there is no standard library. One will be introduced later. | ||
| 18 | |||
| 19 | ## Hello World | ||
| 20 | |||
| 21 | ```lang:run | ||
| 22 | let print = @js("console").log; | ||
| 23 | print("Hello, world!"); | ||
| 24 | ``` | ||
| 25 | |||
| 26 | The `print` function is implemented by getting an external reference to the `console` JavaScript global, and then retriving the `log` property from it. | ||
| 27 | |||
| 28 | ## Primative Data Types | ||
| 29 | |||
| 30 | | name | ts equivilent | description | | ||
| 31 | | ---------- | --------------------- | ---------------------------------------------- | | ||
| 32 | | `int` | `number` | a number in signed 32-bit range | | ||
| 33 | | `float` | `number` | a 64-bit floating point number | | ||
| 34 | | `bool` | `boolean` | either `true` or `false` | | ||
| 35 | | `string` | `string` | a sequence of text characters | | ||
| 36 | | `void` | `undefined` or `null` | detectable lack of a value | | ||
| 37 | | `noreturn` | `never` | control flow prevents this value from existing | | ||
| 38 | |||
| 39 | > **note**: `bigint` is planned but not added | ||
| 40 | |||
| 41 | ## Built-in Constants | ||
| 42 | |||
| 43 | In addition to the above types being built-in constants, the following are available. | ||
| 44 | |||
| 45 | | name | description | | ||
| 46 | | ------- | ------------------------------------- | | ||
| 47 | | `true` | boolean true (result of `1 == 1`) | | ||
| 48 | | `false` | boolean false (result of `1 == 2`) | | ||
| 49 | | `std` | handle to the standard library module | | ||
| 50 | |||
| 51 | These constants are reserved names, and it is an error to re-declare them. | ||
| 52 | |||
| 53 | ```lang:build | ||
| 54 | let true = 1 == 0; | ||
| 55 | ``` | ||
| 56 | |||
| 57 | ## Variables | ||
| 58 | |||
| 59 | There are two types of variables, `let` and `var`. | ||
| 60 | |||
| 61 | `let` bindings cannot be overridden, and should be thought of as aliases of the expression within. Referring to these identifiers is equivilent to inlining it's where it was used, aside from side effect duplication. | ||
| 62 | |||
| 63 | ```lang:run | ||
| 64 | let hello: int = 1; | ||
| 65 | let world = hello + 2; | ||
| 66 | let hello = hello * world; | ||
| 67 | |||
| 68 | @js("console").log(hello); | ||
| 69 | ``` | ||
| 70 | |||
| 71 | `var` bindings create mutable memory locations at runtime. This means they can be re-assigned to: | ||
| 72 | |||
| 73 | ```lang:run | ||
| 74 | var message = "first message"; | ||
| 75 | |||
| 76 | if @js("Math").random() > 0.5 { | ||
| 77 | message = "second message" | ||
| 78 | } | ||
| 79 | |||
| 80 | @js("console").log(message); | ||
| 81 | ``` | ||
| 82 | |||
| 83 | Using `let` is preferred whenever possible, as it will lead to more readable code, and the compiler is able to optimize it better. The above can be rewritten as: | ||
| 84 | |||
| 85 | ```lang:run | ||
| 86 | let message = if @js("Math").random() > 0.5 { | ||
| 87 | "second message" | ||
| 88 | } else { | ||
| 89 | "first message" | ||
| 90 | }; | ||
| 91 | |||
| 92 | @js("console").log(message); | ||
| 93 | ``` | ||
| 94 | |||
| 95 | It should be noted that numeric literals are a comptime-only data type, meaning it cannot be assigned to a `var` without an explicit type annotation. Since `int` is a strict subset of valid `float`s, the coersion will implicitly be a float, but a compiler warning will be emitted. | ||
| 96 | |||
| 97 | ```lang | ||
| 98 | var number = 0; // `number` is a `float`, but not explicit | ||
| 99 | var number: int = 0; // `number` is `int` | ||
| 100 | var number: float = 0; // `number` is `float` | ||
| 101 | ``` | ||
| 102 | |||
| 103 | ## Functions | ||
| 104 | |||
| 105 | Functions are declared with the `fn` keyword. Parameter types must be annotated. The function body is a block, which may use implicit return to return. | ||
| 106 | |||
| 107 | ```lang:run | ||
| 108 | fn add(a: int, b: int) -> int { | ||
| 109 | a + b | ||
| 110 | } | ||
| 111 | |||
| 112 | let print = @js("console").log; | ||
| 113 | //print("Sum of 2 and 7" + add(2, 7)); | ||
| 114 | print(add(2, 7)); | ||
| 115 | ``` | ||
| 116 | |||
| 117 | > **Bug**: Return types are currently required. Omitting the `-> type` syntax currently makes the return type `void`, but this will be changed in the future to be an inferred return type. | ||
| 118 | |||
| 119 | The `return` expression can be used within functions to return early. | ||
| 120 | |||
| 121 | ```lang | ||
| 122 | fn something(a: int) -> bool { | ||
| 123 | if a == 0 { | ||
| 124 | return false; | ||
| 125 | } | ||
| 126 | |||
| 127 | a > 100 | ||
| 128 | } | ||
| 129 | ``` | ||
| 130 | |||
| 131 | ## Number Literals | ||
| 132 | |||
| 133 | TODO | ||
| 134 | |||
| 135 | ## String Literals | ||
| 136 | |||
| 137 | TODO | ||
| 138 | |||
| 139 | ## JavaScript Interop | ||
| 140 | |||
| 141 | A global variable handle can be retrived with `@js`. We've seen this in the hello world. The plan is to eventually replace this construct with something else, but implementing a function like this is extremely trivial for the compiler. | ||
| 142 | |||
| 143 | Many JS-exclusive actions are exposed via built-in functions, such as using `@jsNew` for calling constructors. | ||
| 144 | |||
| 145 | ```lang:run | ||
| 146 | let date_constructor = @js("Date"); | ||
| 147 | let print = @js("console").log; | ||
| 148 | |||
| 149 | fn currentYear() -> int { | ||
| 150 | @jsNew(date_constructor).getFullYear() | ||
| 151 | } | ||
| 152 | |||
| 153 | print(currentYear()); | ||
| 154 | ``` | ||
src/cli.zig created+6| ... | @@ -0,0 +1,6 @@ | ||
| 1 | //! This is the `lang` command line interface. It combines all components | ||
| 2 | //! of the software development kit into one. For development, it may | ||
| 3 | //! be more reasonable to hack on individual components, which each | ||
| 4 | //! expose their own CLIs | ||
| 5 | |||
| 6 | pub fn main() !void {} | ||
src/core/Transform.zig+2| ... | @@ -565,6 +565,7 @@ fn transformParamDecl(t: *Transform, decl: BlockContext, param: NodeIndex) Alloc | ... | @@ -565,6 +565,7 @@ fn transformParamDecl(t: *Transform, decl: BlockContext, param: NodeIndex) Alloc |
| 565 | 565 | ||
| 566 | pub const Builtin = enum { | 566 | pub const Builtin = enum { |
| 567 | js, | 567 | js, |
| 568 | js_new, | ||
| 568 | import, | 569 | import, |
| 569 | fetch, | 570 | fetch, |
| 570 | compile_error, | 571 | compile_error, |
| ... | @@ -576,6 +577,7 @@ pub const Builtin = enum { | ... | @@ -576,6 +577,7 @@ pub const Builtin = enum { |
| 576 | .{ "fetch", .fetch }, | 577 | .{ "fetch", .fetch }, |
| 577 | .{ "import", .import }, | 578 | .{ "import", .import }, |
| 578 | .{ "js", .js }, | 579 | .{ "js", .js }, |
| 580 | .{ "jsNew", .js_new }, | ||
| 579 | .{ "typeOf", .type_of }, | 581 | .{ "typeOf", .type_of }, |
| 580 | // sort-lines: end | 582 | // sort-lines: end |
| 581 | }); | 583 | }); |
src/langref/generate-langref.zig+2-1| ... | @@ -9,7 +9,8 @@ const ArrayList = std.ArrayList; | ... | @@ -9,7 +9,8 @@ const ArrayList = std.ArrayList; |
| 9 | 9 | ||
| 10 | pub fn main() !void { | 10 | pub fn main() !void { |
| 11 | comptime std.debug.assert(@import("builtin").mode == .Debug); | 11 | comptime std.debug.assert(@import("builtin").mode == .Debug); |
| 12 | const gpa = std.heap.c_allocator; | 12 | var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); |
| 13 | const gpa = arena.allocator(); | ||
| 13 | 14 | ||
| 14 | var args = try std.process.argsWithAllocator(gpa); | 15 | var args = try std.process.argsWithAllocator(gpa); |
| 15 | _ = args.next().?; | 16 | _ = args.next().?; |
src/langref/langref.template.html deleted-78| ... | @@ -1,78 +0,0 @@ | ||
| 1 | <!doctype html> | ||
| 2 | <html lang="en"> | ||
| 3 | <head> | ||
| 4 | <meta charset="UTF-8"> | ||
| 5 | <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
| 6 | <title>Language Reference</title> | ||
| 7 | <style> | ||
| 8 | * { margin: 0; padding: 0; box-sizing: border-box; } | ||
| 9 | body { | ||
| 10 | background-color: #fefefe; | ||
| 11 | font-family: sans-serif; | ||
| 12 | max-width: 45rem; | ||
| 13 | padding: 1rem; | ||
| 14 | margin: auto; | ||
| 15 | } | ||
| 16 | h1,h2,h3,h4,h5,h6,p,ul,pre,blockquote { | ||
| 17 | margin-bottom: 1rem; | ||
| 18 | } | ||
| 19 | ul { | ||
| 20 | padding-left: 2rem; | ||
| 21 | } | ||
| 22 | li { | ||
| 23 | margin-bottom: 0.25rem; | ||
| 24 | } | ||
| 25 | blockquote { | ||
| 26 | background-color: #ddd; | ||
| 27 | border-left: 4px solid black; | ||
| 28 | padding-left: 16px; | ||
| 29 | padding-top: 8px; | ||
| 30 | padding-bottom: 8px; | ||
| 31 | } | ||
| 32 | pre { | ||
| 33 | padding: 0.5rem; | ||
| 34 | } | ||
| 35 | pre > code { | ||
| 36 | border: none; | ||
| 37 | padding: 0; | ||
| 38 | background-color: transparent; | ||
| 39 | } | ||
| 40 | code, pre { | ||
| 41 | border: 1px solid #999; | ||
| 42 | background-color: #eeeeee; | ||
| 43 | border-radius: 4px; | ||
| 44 | padding: 2px 4px; | ||
| 45 | } | ||
| 46 | .term { | ||
| 47 | border: 1px solid #333; | ||
| 48 | background-color: #222; | ||
| 49 | color:white; | ||
| 50 | } | ||
| 51 | .ansi-1 { | ||
| 52 | font-weight: bold; | ||
| 53 | } | ||
| 54 | .ansi-31 { | ||
| 55 | color:rgb(255, 68, 68); | ||
| 56 | } | ||
| 57 | .ansi-2 { | ||
| 58 | color:#aaa; | ||
| 59 | } | ||
| 60 | |||
| 61 | .kw { | ||
| 62 | color: mediumpurple; | ||
| 63 | font-weight: bold; | ||
| 64 | } | ||
| 65 | .tok-string { | ||
| 66 | color: green; | ||
| 67 | } | ||
| 68 | .tok-number_int, .tok-number_float { | ||
| 69 | color: orangered; | ||
| 70 | } | ||
| 71 | </style> | ||
| 72 | </head> | ||
| 73 | <body> | ||
| 74 | <main> | ||
| 75 | {contents} | ||
| 76 | </main> | ||
| 77 | </body> | ||
| 78 | </html> | ||
src/langref/template.html created+78| ... | @@ -0,0 +1,78 @@ | ||
| 1 | <!doctype html> | ||
| 2 | <html lang="en"> | ||
| 3 | <head> | ||
| 4 | <meta charset="UTF-8"> | ||
| 5 | <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
| 6 | <title>Language Reference</title> | ||
| 7 | <style> | ||
| 8 | * { margin: 0; padding: 0; box-sizing: border-box; } | ||
| 9 | body { | ||
| 10 | background-color: #fefefe; | ||
| 11 | font-family: sans-serif; | ||
| 12 | max-width: 45rem; | ||
| 13 | padding: 1rem; | ||
| 14 | margin: auto; | ||
| 15 | } | ||
| 16 | h1,h2,h3,h4,h5,h6,p,ul,pre,blockquote { | ||
| 17 | margin-bottom: 1rem; | ||
| 18 | } | ||
| 19 | ul { | ||
| 20 | padding-left: 2rem; | ||
| 21 | } | ||
| 22 | li { | ||
| 23 | margin-bottom: 0.25rem; | ||
| 24 | } | ||
| 25 | blockquote { | ||
| 26 | background-color: #ddd; | ||
| 27 | border-left: 4px solid black; | ||
| 28 | padding-left: 16px; | ||
| 29 | padding-top: 8px; | ||
| 30 | padding-bottom: 8px; | ||
| 31 | } | ||
| 32 | pre { | ||
| 33 | padding: 0.5rem; | ||
| 34 | } | ||
| 35 | pre > code { | ||
| 36 | border: none; | ||
| 37 | padding: 0; | ||
| 38 | background-color: transparent; | ||
| 39 | } | ||
| 40 | code, pre { | ||
| 41 | border: 1px solid #999; | ||
| 42 | background-color: #eeeeee; | ||
| 43 | border-radius: 4px; | ||
| 44 | padding: 2px 4px; | ||
| 45 | } | ||
| 46 | .term { | ||
| 47 | border: 1px solid #333; | ||
| 48 | background-color: #222; | ||
| 49 | color:white; | ||
| 50 | } | ||
| 51 | .ansi-1 { | ||
| 52 | font-weight: bold; | ||
| 53 | } | ||
| 54 | .ansi-31 { | ||
| 55 | color:rgb(255, 68, 68); | ||
| 56 | } | ||
| 57 | .ansi-2 { | ||
| 58 | color:#aaa; | ||
| 59 | } | ||
| 60 | |||
| 61 | .kw { | ||
| 62 | color: mediumpurple; | ||
| 63 | font-weight: bold; | ||
| 64 | } | ||
| 65 | .tok-string { | ||
| 66 | color: green; | ||
| 67 | } | ||
| 68 | .tok-number_int, .tok-number_float { | ||
| 69 | color: orangered; | ||
| 70 | } | ||
| 71 | </style> | ||
| 72 | </head> | ||
| 73 | <body> | ||
| 74 | <main> | ||
| 75 | {contents} | ||
| 76 | </main> | ||
| 77 | </body> | ||
| 78 | </html> | ||