diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index fa156757..23c0b4e6 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -7,33 +7,41 @@ assignees: '' --- - + **What version of `bat` are you using?** -[paste the output of `bat --version` here] + + + **Describe the bug you encountered:** + ... **What did you expect to happen instead?** + ... + **How did you install `bat`?** + --- -[paste the output of `info.sh` here] +**Evironment** + + diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml index 7a141412..66fb7c76 100644 --- a/.github/workflows/CICD.yml +++ b/.github/workflows/CICD.yml @@ -27,7 +27,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: clippy - args: --all-targets --all-features + args: --all-targets --all-features -- --allow clippy::style - name: Test uses: actions-rs/cargo@v1 with: diff --git a/.gitmodules b/.gitmodules index 09ccaed3..99364ba6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -207,3 +207,9 @@ path = assets/themes/gruvbox url = https://github.com/subnut/gruvbox-tmTheme.git branch = bat-source +[submodule "assets/syntaxes/02_Extra/Lean"] + path = assets/syntaxes/02_Extra/Lean + url = https://github.com/leanprover/vscode-lean.git +[submodule "assets/syntaxes/02_Extra/Zig"] + path = assets/syntaxes/02_Extra/Zig + url = https://github.com/ziglang/sublime-zig-language.git diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e88378d..b4356bc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,10 @@ ## Syntaxes +- Added Zig syntax, see #1470 (@paulsmith) +- Added Lean syntax, see #1446 (@Julian) +- Added `.resource` extension for Robot Framework files, see #1386 + ## New themes - `ansi` replaces `ansi-dark` and `ansi-light`, see #1104 and #1412 (@mk12) diff --git a/Cargo.lock b/Cargo.lock index 16a991e3..074d8c9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -253,9 +253,9 @@ dependencies = [ [[package]] name = "console" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a50aab2529019abfabfa93f1e6c41ef392f91fbf179b347a7e96abb524884a08" +checksum = "7cc80946b3480f421c2f17ed1cb841753a371c7c5104f51d507e13f532c856aa" dependencies = [ "encode_unicode", "lazy_static", @@ -264,7 +264,6 @@ dependencies = [ "terminal_size", "unicode-width", "winapi", - "winapi-util", ] [[package]] @@ -499,9 +498,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.13.12" +version = "0.13.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6f1a0238d7f8f8fd5ee642f4ebac4dbc03e03d1f78fbe7a3ede35dcf7e2224" +checksum = "44f267c9da8a4de3c615b59e23606c75f164f84896e97f4dd6c15a4294de4359" dependencies = [ "bitflags", "libc", @@ -609,9 +608,9 @@ checksum = "aa7087f49d294270db4e1928fc110c976cd4b9e5a16348e0a1df09afa99e6c98" [[package]] name = "libgit2-sys" -version = "0.12.14+1.1.0" +version = "0.12.17+1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f25af58e6495f7caf2919d08f212de550cfa3ed2f5e744988938ea292b9f549" +checksum = "f4ebdf65ca745126df8824688637aa0535a88900b83362d8ca63893bcf4e8841" dependencies = [ "cc", "libc", @@ -850,9 +849,9 @@ dependencies = [ [[package]] name = "predicates" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bfead12e90dccead362d62bb2c90a5f6fc4584963645bc7f71a735e0b0735a" +checksum = "73dd9b7b200044694dfede9edf907c1ca19630908443e9447e624993700c6932" dependencies = [ "difference", "float-cmp", @@ -951,9 +950,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.3.9" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" +checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c" dependencies = [ "aho-corasick", "memchr", @@ -963,9 +962,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.18" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" +checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" [[package]] name = "remove_dir_all" @@ -1036,18 +1035,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.117" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a" +checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.117" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e" +checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" dependencies = [ "proc-macro2", "quote", @@ -1148,9 +1147,9 @@ dependencies = [ [[package]] name = "syntect" -version = "4.4.0" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3978df05b5850c839a6b352d3c35ce0478944a4be689be826b53cf75363e88" +checksum = "2bfac2b23b4d049dc9a89353b4e06bbc85a8f42020cccbe5409a115cf19031e5" dependencies = [ "bincode", "bitflags", @@ -1191,9 +1190,9 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.1.13" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a14cd9f8c72704232f0bfc8455c0e861f0ad4eb60cc9ec8a170e231414c1e13" +checksum = "4bd2d183bd3fac5f5fe38ddbeb4dc9aec4a39a9d7d59e7491d900302da01cbe1" dependencies = [ "libc", "winapi", diff --git a/Cargo.toml b/Cargo.toml index 63664537..70db2509 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ regex-fancy = ["syntect/regex-fancy"] # Use the rust-only "fancy-regex" engine atty = { version = "0.2.14", optional = true } ansi_term = "^0.12.1" ansi_colours = "^1.0" -console = "0.13.0" +console = "0.14.0" dirs = { version = "3.0", optional = true } lazy_static = { version = "1.4", optional = true } wild = { version = "2.0", optional = true } @@ -57,7 +57,7 @@ optional = true default-features = false [dependencies.syntect] -version = "4.4.0" +version = "4.5.0" default-features = false features = ["parsing", "yaml-load", "dump-load", "dump-create"] @@ -75,7 +75,7 @@ default-features = false tempdir = "0.3" assert_cmd = "1.0.2" serial_test = "0.5.1" -predicates = "1.0.5" +predicates = "1.0.6" [build-dependencies] clap = { version = "2.33", optional = true } diff --git a/README.md b/README.md index cbd83731..9a31db62 100644 --- a/README.md +++ b/README.md @@ -180,7 +180,7 @@ The [`prettybat`](https://github.com/eth-p/bat-extras/blob/master/doc/prettybat. ## Installation -[![Packaging status](https://repology.org/badge/vertical-allrepos/bat.svg)](https://repology.org/project/bat/versions) +[![Packaging status](https://repology.org/badge/vertical-allrepos/bat-cat.svg)](https://repology.org/project/bat-cat/versions) ### On Ubuntu (using `apt`) *... and other Debian-based Linux distributions.* diff --git a/assets/syntaxes/02_Extra/Julia b/assets/syntaxes/02_Extra/Julia index 6c0d770f..e2b1cb54 160000 --- a/assets/syntaxes/02_Extra/Julia +++ b/assets/syntaxes/02_Extra/Julia @@ -1 +1 @@ -Subproject commit 6c0d770fc74e6bc037c70cae1f94fe113b60fd95 +Subproject commit e2b1cb549d57368b7b22e79430a1d5f47555e802 diff --git a/assets/syntaxes/02_Extra/Lean b/assets/syntaxes/02_Extra/Lean new file mode 160000 index 00000000..7e99440b --- /dev/null +++ b/assets/syntaxes/02_Extra/Lean @@ -0,0 +1 @@ +Subproject commit 7e99440b33c834b11deda67144a6a7ce5a666f0e diff --git a/assets/syntaxes/02_Extra/Lean.sublime-syntax b/assets/syntaxes/02_Extra/Lean.sublime-syntax new file mode 100644 index 00000000..55e47cdd --- /dev/null +++ b/assets/syntaxes/02_Extra/Lean.sublime-syntax @@ -0,0 +1,125 @@ +%YAML 1.2 +--- +# http://www.sublimetext.com/docs/3/syntax.html +name: Lean +file_extensions: + - lean +scope: source.lean +contexts: + main: + - include: comments + - match: '\b(?])' + pop: true + - include: comments + - include: definitionName + - match: "," + - match: \b(Prop|Type|Sort)\b + scope: storage.type.lean + - match: '\battribute\b\s*\[[^\]]*\]' + scope: storage.modifier.lean + - match: '@\[[^\]]*\]' + scope: storage.modifier.lean + - match: \b(? added `.hgrc`, `hgrc`, and `desktop` file types and support for comments after section headers * `Org mode.sublime-syntax` => removed `task` file type. * `SML.sublime_syntax` => removed `ml` file type. -* `Robot.sublime_syntax` => changed name to "Robot Framework" +* `Robot.sublime_syntax` => changed name to "Robot Framework", added `.resource` extension ### Non-submodule additions @@ -59,3 +94,4 @@ The following files have been manually modified after converting from a `.tmLang https://github.com/seanjames777/SML-Language-Definition/blob/master/sml.tmLanguage * `Cabal.sublime_syntax` has been added manually from https://github.com/SublimeHaskell/SublimeHaskell/ - we don't want to include the whole submodule because it includes other syntaxes ("Haskell improved") as well. +* `Lean.sublime-syntax` has been added manually from https://github.com/leanprover/vscode-lean/blob/master/syntaxes/lean.json via conversion. diff --git a/tests/benchmarks/run-benchmarks.sh b/tests/benchmarks/run-benchmarks.sh index f74bdf24..86f4bf68 100755 --- a/tests/benchmarks/run-benchmarks.sh +++ b/tests/benchmarks/run-benchmarks.sh @@ -1,28 +1,72 @@ #!/usr/bin/env bash - cd "$(dirname "${BASH_SOURCE[0]}")" || exit +# Check that Hyperfine is installed. if ! command -v hyperfine > /dev/null 2>&1; then echo "'hyperfine' does not seem to be installed." echo "You can get it here: https://github.com/sharkdp/hyperfine" exit 1 fi +# Determine the target directories. +get_target_dir() { + if [[ -f "$HOME/.cargo/config" ]]; then + grep 'target-dir[[:space:]]*=' "$HOME/.cargo/config" \ + | sed 's/^[[:space:]]*target-dir[[:space:]]*=//; s/^[[:space:]]*"//; s/"[[:space:]]*$//' \ + && return 0 + fi + + echo "../../target" +} + +TARGET_DIR="$(get_target_dir)" +TARGET_DEBUG="${TARGET_DIR}/debug/bat" +TARGET_RELEASE="${TARGET_DIR}/release/bat" + +# Determine which target to benchmark. +BAT='' +for arg in "$@"; do + case "$arg" in + --system) BAT="bat" ;; + --debug) BAT="$TARGET_DEBUG" ;; + --release) BAT="$TARGET_RELEASE" ;; + --bat=*) BAT="${arg:6}" ;; + esac +done + +if [[ -z "$BAT" ]]; then + echo "A build of 'bat' must be specified for benchmarking." + echo "You can use '--system', '--debug', or '--release'." + exit 1 +fi + +# Ensure that the target is built. +if ! command -v "$BAT" &>/dev/null; then + echo "Could not find the build of bat to benchmark." + case "$BAT" in + "bat") echo "Make you sure to symlink 'batcat' as 'bat'." ;; + "$TARGET_DEBUG") echo "Make you sure to 'cargo build' first." ;; + "$TARGET_RELEASE") echo "Make you sure to 'cargo build --release' first." ;; + esac + exit 1 +fi + +# Run the benchmark. echo "### Startup time" echo -hyperfine --warmup 3 bat +hyperfine --warmup 3 "$BAT" echo echo "### Plain text" echo -hyperfine --warmup 3 "bat --language txt --paging=never 'test-src/jquery-3.3.1.js'" +hyperfine --warmup 3 "$(printf "%q" "$BAT") --language txt --paging=never 'test-src/jquery-3.3.1.js'" echo echo "### Time to syntax-highlight large files" echo for SRC in test-src/*; do - hyperfine --warmup 3 "bat --style=full --color=always --paging=never '$SRC'" + hyperfine --warmup 3 "$(printf "%q" "$BAT") --style=full --color=always --paging=never $(printf "%q" "$SRC")" done diff --git a/tests/syntax-tests/highlighted/Lean/test.lean b/tests/syntax-tests/highlighted/Lean/test.lean new file mode 100644 index 00000000..51918c6a --- /dev/null +++ b/tests/syntax-tests/highlighted/Lean/test.lean @@ -0,0 +1,68 @@ +import data.matrix.notation +import data.vector2 + +/-! + +Helpers that don't currently fit elsewhere... + +-/ + +lemma split_eq {m n : Type*} (x : m × n) (p p' : m × n) : + p = x ∨ p' = x ∨ (x ≠ p ∧ x ≠ p') := by tauto + +-- For `playfield`s, the piece type and/or piece index type. +variables (X : Type*) +variables [has_repr X] + +namespace chess.utils + +section repr + +/-- +An auxiliary wrapper for `option X` that allows for overriding the `has_repr` instance +for `option`, and rather, output just the value in the `some` and a custom provided +`string` for `none`. +-/ +structure option_wrapper := +(val : option X) +(none_s : string) + +instance wrapped_option_repr : has_repr (option_wrapper X) := +⟨λ ⟨val, s⟩, (option.map has_repr.repr val).get_or_else s⟩ + +variables {X} +/-- +Construct an `option_wrapper` term from a provided `option X` and the `string` +that will override the `has_repr.repr` for `none`. +-/ +def option_wrap (val : option X) (none_s : string) : option_wrapper X := ⟨val, none_s⟩ + +-- The size of the "vectors" for a `fin n' → X`, for `has_repr` definitions +variables {m' n' : ℕ} + +/-- +For a "vector" `X^n'` represented by the type `Π n' : ℕ, fin n' → X`, where +the `X` has a `has_repr` instance itself, we can provide a `has_repr` for the "vector". +This definition is used for displaying rows of the playfield, when it is defined +via a `matrix`, likely through notation. +-/ +def vec_repr : Π {n' : ℕ}, (fin n' → X) → string := +λ _ v, string.intercalate ", " ((vector.of_fn v).to_list.map repr) + +instance vec_repr_instance : has_repr (fin n' → X) := ⟨vec_repr⟩ + +/-- +For a `matrix` `X^(m' × n')` where the `X` has a `has_repr` instance itself, +we can provide a `has_repr` for the matrix, using `vec_repr` for each of the rows of the matrix. +This definition is used for displaying the playfield, when it is defined +via a `matrix`, likely through notation. +-/ +def matrix_repr : Π {m' n'}, matrix (fin m') (fin n') X → string := +λ _ _ M, string.intercalate ";\n" ((vector.of_fn M).to_list.map repr) + +instance matrix_repr_instance : + has_repr (matrix (fin n') (fin m') X) := ⟨matrix_repr⟩ + +end repr + +end chess.utils diff --git a/tests/syntax-tests/highlighted/Zig/example.zig b/tests/syntax-tests/highlighted/Zig/example.zig new file mode 100644 index 00000000..7153dbfc --- /dev/null +++ b/tests/syntax-tests/highlighted/Zig/example.zig @@ -0,0 +1,107 @@ +//! this is a top level doc, starts with "//!" + +const std = @import("std"); + +pub fn main() anyerror!void { + const stdout = std.io.getStdOut().writer(); + try stdout.print("Hello, {}!\n", .{"world"}); +} + +const expect = std.testing.expect; + +test "comments" { + // comments start with "//" until newline + // foo bar baz + const x = true; // another comment + expect(x); +} + +/// a doc comment starts with "///" +/// multiple lines are merged together +const Timestamp = struct { + /// number of seconds since epoch + seconds: i64, + + /// number of nanoseconds past the second + nano: u32, + + const Self = @This(); + + pub fn unixEpoch() Self { + return Self{ + .seconds = 0, + .nanos = 0, + }; + } +}; + +const my_val = switch (std.Target.current.os.tag) { + .linux => "Linux", + else => "not Linux", +}; + +const Book = enum { + paperback, + hardcover, + ebook, + pdf, +}; + +const TokenType = union(enum) { + int: isize, + float: f64, + string: []const u8, +}; + +const array_lit: [4]u8 = .{ 11, 22, 33, 44 }; +const sentinal_lit = [_:0]u8{ 1, 2, 3, 4 }; + +test "address of syntax" { + // Get the address of a variable: + const x: i32 = 1234; + const x_ptr = &x; + + // Dereference a pointer: + expect(x_ptr.* == 1234); + + // When you get the address of a const variable, you get a const pointer to a single item. + expect(@TypeOf(x_ptr) == *const i32); + + // If you want to mutate the value, you'd need an address of a mutable variable: + var y: i32 = 5678; + const y_ptr = &y; + expect(@TypeOf(y_ptr) == *i32); + y_ptr.* += 1; + expect(y_ptr.* == 5679); +} + +// integer literals +const decimal_int = 98222; +const hex_int = 0xff; +const another_hex_int = 0xFF; +const octal_int = 0o755; +const binary_int = 0b11110000; + +// underscores may be placed between two digits as a visual separator +const one_billion = 1_000_000_000; +const binary_mask = 0b1_1111_1111; +const permissions = 0o7_5_5; +const big_address = 0xFF80_0000_0000_0000; + +// float literals +const floating_point = 123.0E+77; +const another_float = 123.0; +const yet_another = 123.0e+77; + +const hex_floating_point = 0x103.70p-5; +const another_hex_float = 0x103.70; +const yet_another_hex_float = 0x103.70P-5; + +// underscores may be placed between two digits as a visual separator +const lightspeed = 299_792_458.000_000; +const nanosecond = 0.000_000_001; +const more_hex = 0x1234_5678.9ABC_CDEFp-10; + +fn max(comptime T: type, a: T, b: T) T { + return if (a > b) a else b; +} diff --git a/tests/syntax-tests/source/DotENV/.env b/tests/syntax-tests/source/DotENV/.env index 474f6f14..42a024ab 100644 --- a/tests/syntax-tests/source/DotENV/.env +++ b/tests/syntax-tests/source/DotENV/.env @@ -54,4 +54,4 @@ TEST_ESCAPE="escaped characters \n \t \r \" \' \$ or maybe a backslash \\..." TEST_DOUBLE="Lorem {$VAR1} ${VAR2} $VAR3 ipsum dolor sit amet\n\r\t\\" # Single Quotes -TEST_SINGLE='Lorem {$VAR1} ${VAR2} $VAR3 ipsum dolor sit amet\n\r\t\\' \ No newline at end of file +TEST_SINGLE='Lorem {$VAR1} ${VAR2} $VAR3 ipsum dolor sit amet\n\r\t\\' diff --git a/tests/syntax-tests/source/Lean/test.lean b/tests/syntax-tests/source/Lean/test.lean new file mode 100644 index 00000000..eddf316c --- /dev/null +++ b/tests/syntax-tests/source/Lean/test.lean @@ -0,0 +1,68 @@ +import data.matrix.notation +import data.vector2 + +/-! + +Helpers that don't currently fit elsewhere... + +-/ + +lemma split_eq {m n : Type*} (x : m × n) (p p' : m × n) : + p = x ∨ p' = x ∨ (x ≠ p ∧ x ≠ p') := by tauto + +-- For `playfield`s, the piece type and/or piece index type. +variables (X : Type*) +variables [has_repr X] + +namespace chess.utils + +section repr + +/-- +An auxiliary wrapper for `option X` that allows for overriding the `has_repr` instance +for `option`, and rather, output just the value in the `some` and a custom provided +`string` for `none`. +-/ +structure option_wrapper := +(val : option X) +(none_s : string) + +instance wrapped_option_repr : has_repr (option_wrapper X) := +⟨λ ⟨val, s⟩, (option.map has_repr.repr val).get_or_else s⟩ + +variables {X} +/-- +Construct an `option_wrapper` term from a provided `option X` and the `string` +that will override the `has_repr.repr` for `none`. +-/ +def option_wrap (val : option X) (none_s : string) : option_wrapper X := ⟨val, none_s⟩ + +-- The size of the "vectors" for a `fin n' → X`, for `has_repr` definitions +variables {m' n' : ℕ} + +/-- +For a "vector" `X^n'` represented by the type `Π n' : ℕ, fin n' → X`, where +the `X` has a `has_repr` instance itself, we can provide a `has_repr` for the "vector". +This definition is used for displaying rows of the playfield, when it is defined +via a `matrix`, likely through notation. +-/ +def vec_repr : Π {n' : ℕ}, (fin n' → X) → string := +λ _ v, string.intercalate ", " ((vector.of_fn v).to_list.map repr) + +instance vec_repr_instance : has_repr (fin n' → X) := ⟨vec_repr⟩ + +/-- +For a `matrix` `X^(m' × n')` where the `X` has a `has_repr` instance itself, +we can provide a `has_repr` for the matrix, using `vec_repr` for each of the rows of the matrix. +This definition is used for displaying the playfield, when it is defined +via a `matrix`, likely through notation. +-/ +def matrix_repr : Π {m' n'}, matrix (fin m') (fin n') X → string := +λ _ _ M, string.intercalate ";\n" ((vector.of_fn M).to_list.map repr) + +instance matrix_repr_instance : + has_repr (matrix (fin n') (fin m') X) := ⟨matrix_repr⟩ + +end repr + +end chess.utils diff --git a/tests/syntax-tests/source/Svelte/LICENSE b/tests/syntax-tests/source/Svelte/LICENSE.md similarity index 100% rename from tests/syntax-tests/source/Svelte/LICENSE rename to tests/syntax-tests/source/Svelte/LICENSE.md diff --git a/tests/syntax-tests/source/Zig/example.zig b/tests/syntax-tests/source/Zig/example.zig new file mode 100644 index 00000000..a128f25c --- /dev/null +++ b/tests/syntax-tests/source/Zig/example.zig @@ -0,0 +1,107 @@ +//! this is a top level doc, starts with "//!" + +const std = @import("std"); + +pub fn main() anyerror!void { + const stdout = std.io.getStdOut().writer(); + try stdout.print("Hello, {}!\n", .{"world"}); +} + +const expect = std.testing.expect; + +test "comments" { + // comments start with "//" until newline + // foo bar baz + const x = true; // another comment + expect(x); +} + +/// a doc comment starts with "///" +/// multiple lines are merged together +const Timestamp = struct { + /// number of seconds since epoch + seconds: i64, + + /// number of nanoseconds past the second + nano: u32, + + const Self = @This(); + + pub fn unixEpoch() Self { + return Self{ + .seconds = 0, + .nanos = 0, + }; + } +}; + +const my_val = switch (std.Target.current.os.tag) { + .linux => "Linux", + else => "not Linux", +}; + +const Book = enum { + paperback, + hardcover, + ebook, + pdf, +}; + +const TokenType = union(enum) { + int: isize, + float: f64, + string: []const u8, +}; + +const array_lit: [4]u8 = .{ 11, 22, 33, 44 }; +const sentinal_lit = [_:0]u8{ 1, 2, 3, 4 }; + +test "address of syntax" { + // Get the address of a variable: + const x: i32 = 1234; + const x_ptr = &x; + + // Dereference a pointer: + expect(x_ptr.* == 1234); + + // When you get the address of a const variable, you get a const pointer to a single item. + expect(@TypeOf(x_ptr) == *const i32); + + // If you want to mutate the value, you'd need an address of a mutable variable: + var y: i32 = 5678; + const y_ptr = &y; + expect(@TypeOf(y_ptr) == *i32); + y_ptr.* += 1; + expect(y_ptr.* == 5679); +} + +// integer literals +const decimal_int = 98222; +const hex_int = 0xff; +const another_hex_int = 0xFF; +const octal_int = 0o755; +const binary_int = 0b11110000; + +// underscores may be placed between two digits as a visual separator +const one_billion = 1_000_000_000; +const binary_mask = 0b1_1111_1111; +const permissions = 0o7_5_5; +const big_address = 0xFF80_0000_0000_0000; + +// float literals +const floating_point = 123.0E+77; +const another_float = 123.0; +const yet_another = 123.0e+77; + +const hex_floating_point = 0x103.70p-5; +const another_hex_float = 0x103.70; +const yet_another_hex_float = 0x103.70P-5; + +// underscores may be placed between two digits as a visual separator +const lightspeed = 299_792_458.000_000; +const nanosecond = 0.000_000_001; +const more_hex = 0x1234_5678.9ABC_CDEFp-10; + +fn max(comptime T: type, a: T, b: T) T { + return if (a > b) a else b; +}