# Awsum — full reference for writing programs Awsum is a correctness-first, statically-typed functional language in the ML / Haskell family. One source file compiles to five backends — Native (LLVM), JVM, CLR, WASM, and JS — and produces **identical** stdout on every one. That cross-target identity is a compiler invariant, verified across all five backends on every commit, not a best-effort goal. This file is self-contained: reading it is enough to understand the language and write a program that compiles. Where prose examples and the bundled prelude could disagree, the prelude (`stdlib/Prelude.aww`, linked at the end) and the complete tested program near the bottom of this file are authoritative. Status: version 0.0.6, pre-1.0. Program type `cli` only so far (browser and library are planned). Targets: LLVM, JVM, CLR, WASM, JS. ## What the language guarantees 1. **Identical results on every target.** The same program produces the same stdout on LLVM, JVM, CLR, WASM, and JS. 2. **Stack safety for any recursion shape.** Self, mutual, tail, and non-tail recursion are all normalized by the compiler into a bounded-stack loop on every backend — including JVM and JS, which have no native cross-method tail calls. No annotations, no `tailRecM`, no manual CPS. Write the recursion that expresses the algorithm. 3. **Errors are values.** Integer overflow, underflow, precision loss, division by zero, string-too-long, and parse failure are returned as `Either` with a typed error. Effects carry their failure type explicitly in `IO e a`. No exceptions, no `NaN`, no `null` / `nil` / `undefined`, no silent wraparound or saturation. 4. **Effects are platform-aware data.** An `IO e a` value *describes* an effect; constructing it performs nothing. Only the `IO` returned from `main` is run, by a small per-target runtime walker. Using an effect a target does not support is a compile error. 5. **No invisible decisions.** No defaulting of integer literals (ambiguity is rejected). No shadowing (a compile error). No catch-all `_ ->` in `case`. A `_`-prefixed binding cannot be read. When guarantees conflict, the compiler prefers, in order: correctness, runtime performance, compilation speed, syntactic convenience. ## Install and run The compiler is a single binary. Install it, then install only the runtimes for the targets you plan to use. ### Install the compiler (per OS) macOS (Apple Silicon): ```sh mkdir -p ~/.local/bin curl -fsSL https://github.com/awsum-lang/awsum/releases/download/v0.0.6/awsum-0.0.6-macos-aarch64.tar.gz \ | tar -xzC ~/.local/bin awsum --version # verify; ~/.local/bin must be on PATH ``` Linux (x86_64): ```sh mkdir -p ~/.local/bin curl -fsSL https://github.com/awsum-lang/awsum/releases/download/v0.0.6/awsum-0.0.6-linux-x86_64-gnu.tar.gz \ | tar -xzC ~/.local/bin awsum --version ``` Linux (aarch64): ```sh mkdir -p ~/.local/bin curl -fsSL https://github.com/awsum-lang/awsum/releases/download/v0.0.6/awsum-0.0.6-linux-aarch64-gnu.tar.gz \ | tar -xzC ~/.local/bin awsum --version ``` Windows (x86_64, PowerShell) — installs into `%LOCALAPPDATA%\Microsoft\WindowsApps`, on PATH by default since Windows 10: ```powershell $Url = "https://github.com/awsum-lang/awsum/releases/download/v0.0.6/awsum-0.0.6-windows-x86_64.zip" $Dest = "$env:LOCALAPPDATA\Microsoft\WindowsApps" Invoke-WebRequest -Uri $Url -OutFile "$env:TEMP\awsum.zip" Expand-Archive -Path "$env:TEMP\awsum.zip" -DestinationPath $Dest -Force awsum --version ``` Other platforms (musl Linux, x86 macOS, BSD): build from source — see https://github.com/awsum-lang/awsum/blob/main/CONTRIBUTING.md#development-setup . The version pinned above is 0.0.6; check the releases page for the current tag. ### Install target runtimes (per OS) Install only the runtimes for targets you'll actually use. macOS (Homebrew): ```sh brew install llvm@15 # LLVM target — clang 15+ (opaque pointers) brew install openjdk # JVM target — Java 11+ brew install dotnet # CLR target — .NET 9+ brew install wasmtime # WASM target — wasmtime (WASI) brew install node # JS target — Node 22+ ``` Linux (x86_64 and aarch64, apt): ```sh sudo apt-get install -y clang-15 # LLVM (clang 15+) sudo apt-get install -y default-jre # JVM (Java 11+) sudo apt-get install -y dotnet-sdk-9.0 # CLR (.NET 9+; Ubuntu 24.04+, else add Microsoft's APT repo) curl https://wasmtime.dev/install.sh -sSf | bash # WASM (wasmtime) curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - # JS (Node 22+; apt's default is older) sudo apt-get install -y nodejs ``` Windows (PowerShell + winget): ```powershell # LLVM target — clang 15.0.7 (16+ has known issues with our codegen on Windows) $Url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-15.0.7/LLVM-15.0.7-win64.exe" Invoke-WebRequest -Uri $Url -OutFile "$env:TEMP\llvm-installer.exe" Start-Process -Wait "$env:TEMP\llvm-installer.exe" -ArgumentList "/S" winget install EclipseAdoptium.Temurin.21.JDK # JVM (Java 11+) winget install Microsoft.DotNet.SDK.9 # CLR (.NET 9+) winget install BytecodeAlliance.Wasmtime # WASM winget install OpenJS.NodeJS # JS (Node 22+) ``` ### Editor extensions LSP-based tooling (diagnostics, formatting, quick fixes, outline, workspace symbols): - VSCode — Visual Studio Marketplace (`awsum-lang.awsum-vscode`) or Open VSX. - IntelliJ IDEA (and other JetBrains IDEs) — JetBrains Marketplace (plugin "awsum"). - Zed, Neovim (0.12+), Emacs (29.1+) — install from their repos (linked at the end of this file). ### CLI usage ```sh # Compile for a target; -o writes a file, omit it for stdout. awsum build --program-type cli -t llvm|jvm|clr|wasm|js [-o OUT] Main.aww # Compile and run in one step. argv goes after --, read via IO.Args.getArgs. # stdin is inherited, so a pipe or < file reaches IO.Stdin.readAllString / readAllBytes. awsum run --program-type cli -t llvm Main.aww -- arg1 arg2 echo "input" | awsum run --program-type cli -t jvm Main.aww # Typecheck only. --json for editor integrations; --strict makes warnings fail CI. awsum check --program-type cli [--json] [--strict] Main.aww # Format in place (-i) or to stdout. awsum format [-i] Main.aww ``` `--program-type cli` is mandatory on any command that typechecks. It picks which platform effects are available; an explicit choice rather than a silent default. ## Hello world ```awsum import IO.Stdout main : IO Never Unit main = IO.Stdout.print "Hello, world!" ``` - Every program's entry point is `main : IO Never Unit`. `Never` is the uninhabited type; in an error row it means "cannot fail". `Unit` is the one-value type. - `IO.Stdout.print : String -> IO Never Unit` is a CLI platform effect; it requires both `import IO.Stdout` and `--program-type cli`. - The prelude is implicit: `Maybe`, `Either`, `Bool`, `List`, arithmetic, `showInt32`, and friends are in scope with no import. ## Language reference ### Top-level signatures are mandatory Every top-level definition needs an explicit type signature. Local inference still runs inside a body; the compiler only refuses to infer a *top-level* type. This caps the blast radius of a type error at one definition. ```awsum square : Int32 -> Int32 square n = n -- placeholder body; real arithmetic returns Either (see below) ``` ### Primitives and literals Built-in: `String`, `Int32` (signed 32-bit), `UInt8` (0..255), `UInt32` (0..2^32−1). There is **no defaulting**: a bare integer literal has no type until context fixes it, and an out-of-range literal is a compile error. ```awsum answer : Int32 answer = 42 -- ok: signature fixes the type -- ambiguous = 42 -- error: no context to fix the literal's type -- tooBig : UInt8 -- tooBig = 300 -- error: out of range for UInt8 ``` Integer literals may use `_` as a digit separator (`1_000_000`). Strings: escapes `\n \t \r \" \\ \0`; a source string literal is capped at 21845 UTF-16 code units; a string built at runtime is capped at 2^27 code units (operations that would exceed it return `Left StringTooLong`). Awsum strings are strict UTF-16 — lone surrogates are not representable. ### Sum types and pattern matching ```awsum type Bool = True | False type Maybe a = Nothing | Just a type Either a b = Left a | Right b type Tree a = Leaf | Node (Tree a) a (Tree a) -- recursive ``` Match with `case`. Arms must be **exhaustive**, and there is **no catch-all** (`_ -> ...`) over a sum's constructors. When a type gains a constructor, every `case` over it stops compiling until the new constructor is handled — that is by design. ```awsum describe : Maybe Int32 -> String describe x = case x of Nothing -> "nothing" Just n -> showInt32 n ``` A `type X` with zero constructors is uninhabited. `empty type Never` is the special uninhabited "row identity" used in `IO Never a`. ### Polymorphism Lowercase identifiers in a signature are universally-quantified type variables. ```awsum identity : a -> a identity x = x const : a -> b -> a const x _y = x ``` ### Functions, lambdas, closures Arrows are right-associative; application is curried. A destructuring parameter must be parenthesized (so it is not read as several bare parameters): ```awsum addPair : Tuple2 Int32 Int32 -> Int32 addPair (Tuple2 a b) = a -- placeholder apply : (a -> b) -> a -> b apply f x = f x ``` Lambdas are `\x y -> body`; they may close over outer parameters. Constructors are first-class (passable to higher-order functions, partially applicable). No backend has a closure runtime — the compiler defunctionalizes every function value at compile time, so this is free at runtime. ### Pipe `|>` `x |> f` is syntax for `f x` (left-associative, lowest precedence). It is a pure rewrite with zero runtime cost; `(|>)` is **not** a referenceable name. ```awsum greet : String -> IO Never Unit greet name = name |> IO.Stdout.print -- same as IO.Stdout.print name ``` ### Structural sums (row types) A value can be the union of several types, written with `|` inside parens. Match with type-ascription patterns `(x : T)`, which bind `x` to that alternative. Rows are commutative, idempotent, associative. A value of type `A` flows into a position expecting `(A | B)` with no explicit wrapper (implicit injection). No catch-all here either — every alternative is covered or it is a compile error. ```awsum describe : (Int32 | String) -> String describe x = case x of (n : Int32) -> showInt32 n (s : String) -> s ``` The pipe in types binds looser than `->`: `A | B -> C` parses as `A | (B -> C)`. Wrap unions in parens. ### Type ascription `(e : T)` pins the type of an expression (e.g. a literal flowing into a polymorphic slot: `identity (42 : Int32)`). In a pattern, `(p : T)` matches alternative `T` and binds `p`. Both forms require the parens. ### Errors as values: `Either` and `do` The prelude's `Either a b = Left a | Right b` is the error type; `Left` is failure, `Right` is success. Composition unions the error rows: ```awsum bindEither : Either e1 a -> (a -> Either e2 b) -> Either (e1 | e2) b ``` `do`-notation desugars to `bindEither` / `pureEither` and currently types **only** against `Either`: ```awsum type ErrA = ErrA type ErrB = ErrB f : Either (ErrA | ErrB) Int32 f = do a <- op1 -- op1 : Either ErrA Int32 b <- op2 a -- op2 : Int32 -> Either ErrB Int32 pureEither b ``` `<-` binds the success value; a bound name is visible in later statements. The final statement is an expression of type `Either e a` (use `pureEither x` to lift a plain value). `let n = e` (no `in`) introduces a non-monadic binding inside a `do` block. The LHS of `<-` and of `let` may be a destructuring pattern. ### `let` `let n = e in body` is an expression. No defaulting on the RHS (annotate with `let n : T = e` if synthesis can't pin it). Destructuring LHS allowed; ascribing a destructuring let is rejected — ascribe the RHS. No shadowing. The RHS is evaluated once. ### IO `IO e a` is lazy data declared in the prelude. Compose it with the prelude functions, which mirror the `Either` family: ```awsum pureIO : a -> IO e a failIO : e -> IO e a bindIO : IO e1 a -> (a -> IO e2 b) -> IO (e1 | e2) b andThenIO : (a -> IO e2 b) -> IO e1 a -> IO (e1 | e2) b mapIO : IO e a -> (a -> b) -> IO e b mapIOError : IO e1 a -> (e1 -> e2) -> IO e2 a handleErrorIO : (e1 -> IO e2 a) -> IO e1 a -> IO e2 a ``` `do`-notation does **not** work for `IO` — sequence with `andThenIO` / `bindIO`. `main` must reduce its error row to `Never` (handle every failure, typically `|> handleErrorIO h` at the tail). CLI platform effects (each needs `--program-type cli` plus its import): ```awsum IO.Stdout.print : String -> IO Never Unit -- import IO.Stdout IO.Args.getArgs : IO (StringTooLong | UnpairedUtf16Surrogate) (List String) -- import IO.Args IO.Stdin.readAllString : IO (StringTooLong | InvalidUtf8) String -- import IO.Stdin IO.Stdin.readAllBytes : IO Never (List UInt8) -- import IO.Stdin ``` `IO.Args.getArgs` reads all command-line arguments as a `List String` (there is no `main` parameter for argv). `IO.Stdin.readAllString` consumes stdin to EOF and decodes it as strict UTF-8, with `Left InvalidUtf8` on any malformed byte sequence; `IO.Stdin.readAllBytes` returns the raw bytes undecoded, so it cannot fail. Both `getArgs` and `readAllString` fail all-or-nothing — one element that can't decode fails the whole call. Sequencing two prints: ```awsum main : IO Never Unit main = IO.Stdout.print "a" |> andThenIO (\_u -> IO.Stdout.print "b") -- prints "ab" ``` ### No shadowing; the underscore convention A new binding may not reuse a name visible in any enclosing scope of the same module — shadowing is a compile error (the prelude is a separate module, so user names never clash with it). A leading `_` marks a binding intentionally unused; referencing any `_`-prefixed name anywhere is an error. A bare `_` is a wildcard that binds nothing. An unused non-`_` binding is a warning (`awsum check --strict` escalates it). ### Comments and docstrings `--` to end of line; `{- ... -}` blocks (which nest). A comment with no blank line before a top-level declaration becomes that declaration's docstring (rendered as markdown in editor hover). A blank line detaches it. ## Prelude API (in scope in every program, no import) Exact signatures from the bundled prelude. Note that string concatenation and all fallible arithmetic return `Either` with a typed error — they do not return bare values. Types: `Unit`, `Never`, `Bool = True | False`, `Maybe a = Nothing | Just a`, `Either a b = Left a | Right b`, `List a = Nil | Cons a (List a)`, `Tuple2 a b = Tuple2 a b`, `Tuple3 a b c = Tuple3 a b c`, `IO e a`. Error types (each nullary): `UnderflowError`, `OverflowError`, `StringTooLong`, `UnpairedUtf16Surrogate`, `InvalidUtf8`, `ParseError`, `BrokenPipe`. ```awsum -- String (note: concatenation can fail with StringTooLong) (++) : String -> String -> Either StringTooLong String splitOnFirst : String -> String -> Maybe (Tuple2 String String) lengthCodePoints : String -> UInt32 -- Unicode code points lengthUtf16CodeUnits : String -> UInt32 -- UTF-16 code units lengthUtf8Bytes : String -> UInt32 -- bytes when UTF-8 encoded eqString : String -> String -> Bool showUnit : Unit -> String -- Bool not : Bool -> Bool and : Bool -> Bool -> Bool -- no short-circuit; both args evaluated or : Bool -> Bool -> Bool showBool : Bool -> String -- Either / general bindEither : Either e1 a -> (a -> Either e2 b) -> Either (e1 | e2) b andThenEither : (a -> Either e2 b) -> Either e1 a -> Either (e1 | e2) b pureEither : a -> Either e a mapRight : Either e a -> (a -> b) -> Either e b mapLeft : Either e1 a -> (e1 -> e2) -> Either e2 a nothingAsLeft : e -> Maybe a -> Either e a -- bridge Maybe into an Either do-block const : a -> b -> a -- Maybe / List headList : List a -> Maybe a tailList : List a -> Maybe (List a) -- IO (see the IO section above) pureIO / failIO / bindIO / andThenIO / mapIO / mapIOError / handleErrorIO eitherToIO : Either e a -> IO e a -- lift an Either into IO, preserving the error row -- Int32 (arithmetic returns Either with a typed error; no wraparound) minInt32 : Int32 -- -2_147_483_648 maxInt32 : Int32 -- 2_147_483_647 eqInt32 : Int32 -> Int32 -> Bool showInt32 : Int32 -> String predInt32 : Int32 -> Either UnderflowError Int32 succInt32 : Int32 -> Either OverflowError Int32 addInt32 : Int32 -> Int32 -> Either (UnderflowError | OverflowError) Int32 subInt32 : Int32 -> Int32 -> Either (UnderflowError | OverflowError) Int32 mulInt32 : Int32 -> Int32 -> Either (UnderflowError | OverflowError) Int32 negInt32 : Int32 -> Either OverflowError Int32 parseInt32 : String -> Either ParseError Int32 -- UInt8 (0..255) and UInt32 (0..4_294_967_295): same shape minUInt8 / maxUInt8 / eqUInt8 / showUInt8 / predUInt8 / succUInt8 / addUInt8 / subUInt8 / mulUInt8 / parseUInt8 minUInt32 / maxUInt32 / eqUInt32 / showUInt32 / predUInt32 / succUInt32 / addUInt32 / subUInt32 / mulUInt32 / parseUInt32 -- unsigned add/mul return Either OverflowError; unsigned sub returns Either UnderflowError -- Bytes to hex (lowercase, zero-padded, no 0x prefix) byteToHexStringNoPrefix : UInt8 -> String -- 0 -> "00", 255 -> "ff" bytesToHexStringNoPrefix : List UInt8 -> Either StringTooLong String -- Left only past the string cap -- Error rendering showUnderflowError / showOverflowError / showStringTooLong / showUnpairedUtf16Surrogate / showInvalidUtf8 / showParseError / showBrokenPipe : -> String ``` There is no `[1,2,3]` list syntax and no `::` operator — build lists with `Cons h t` and `Nil`. There is no polymorphic `show` yet (type classes are on the roadmap); use the per-type `show*` helpers. ## A complete program: greeting from a command-line argument A real tested program showing the argv flow end to end: read arguments, run a fallible `do` block over `Either`, lift the result into `IO`, print it, and handle every failure in the error row before `main` returns `IO Never Unit`. ```awsum import IO.Stdout import IO.Args type NoArg = NoArg main : IO Never Unit main = IO.Args.getArgs |> andThenIO (\args -> eitherToIO (greet args)) |> andThenIO IO.Stdout.print |> handleErrorIO printError greet : List String -> Either (NoArg | StringTooLong) String greet args = do name <- headList args |> nothingAsLeft NoArg hello <- "Hello, " ++ name hello ++ "!" printError : (StringTooLong | UnpairedUtf16Surrogate | NoArg) -> IO Never Unit printError e = case e of StringTooLong -> IO.Stdout.print "STRING_TOO_LONG" UnpairedUtf16Surrogate -> IO.Stdout.print "UNPAIRED_UTF16_SURROGATE" NoArg -> IO.Stdout.print "NO_ARG" ``` Things to read off it: `headList args |> nothingAsLeft NoArg` bridges a `Maybe` into the `do`-block's `Either`; `++` returns `Either StringTooLong String`, so each step is a `<-`; `eitherToIO` lifts the `Either` into the IO chain, where its error row joins `getArgs`'s `(StringTooLong | UnpairedUtf16Surrogate)`; `handleErrorIO printError` consumes the full union `(StringTooLong | UnpairedUtf16Surrogate | NoArg)` so `main`'s row collapses to `Never`. Run it with `awsum run --program-type cli -t llvm Main.aww -- world`. ## A complete, tested program This is a real program from the project's proofs, compiled and run on all five backends with identical stdout. It builds an immutable tree of depth 100 000, mirrors it 500 times under heavy allocation, and reads the deepest left value — exercising tail, non-tail, and three-way mutual recursion at once. None of it needs an annotation to be stack-safe. ```awsum {- This demo program builds an immutable tree of depth 100_000, mirrors it 500 times (causing heavy allocation pressure), and displays the deepest value on the left path. Every recursion shape is stack-safe on every target, including JVM and JS where native cross-method TCO doesn't exist. JVM, CLR, and JS targets use their GCs. LLVM and WASM targets use static lifetimes — no GC, no explicit lifetime annotations. -} import IO.Stdout type Tree a = Leaf | Node (Tree a) a (Tree a) main : IO Never Unit main = case runDemo of Left e -> showUnderflowError e |> IO.Stdout.print Right n -> showInt32 n |> IO.Stdout.print runDemo : Either UnderflowError Int32 runDemo = do tree <- buildTree 100_000 mirrored <- mirrorN 500 tree Right (deepestLeftA 0 mirrored) buildTree : Int32 -> Either UnderflowError (Tree Int32) buildTree depth = do l <- buildLeft depth Leaf r <- buildRight depth Leaf Right (Node l 0 r) buildLeft : Int32 -> Tree Int32 -> Either UnderflowError (Tree Int32) buildLeft depth acc = case eqInt32 depth 0 of True -> Right acc False -> do d <- predInt32 depth buildLeft d (Node acc depth Leaf) -- tail recursion buildRight : Int32 -> Tree Int32 -> Either UnderflowError (Tree Int32) buildRight depth acc = case eqInt32 depth 0 of True -> Right acc False -> do d <- predInt32 depth buildRight d (Node Leaf depth acc) -- tail recursion mirror : Tree a -> Tree a mirror t = case t of Leaf -> Leaf Node l v r -> Node (mirror r) v (mirror l) -- multi-child non-tail recursion mirrorN : Int32 -> Tree a -> Either UnderflowError (Tree a) mirrorN times t = case eqInt32 times 0 of True -> Right t False -> do m <- predInt32 times mirrorN m (mirror t) -- heavy allocation pressure deepestLeftA : a -> Tree a -> a deepestLeftA lastV t = case t of Leaf -> lastV Node l v _r -> deepestLeftB v l -- 3-node mutual tail recursion deepestLeftB : a -> Tree a -> a deepestLeftB lastV t = case t of Leaf -> lastV Node l v _r -> deepestLeftC v l -- 3-node mutual tail recursion deepestLeftC : a -> Tree a -> a deepestLeftC lastV t = case t of Leaf -> lastV Node l v _r -> deepestLeftA v l -- 3-node mutual tail recursion ``` Things to read off it: `main : IO Never Unit`; `do` over `Either` with `<-`; `predInt32` returning `Either UnderflowError Int32` (honest arithmetic); `|>`; exhaustive `case` with no catch-all; `_r` marking an unused binder; and recursion written naturally in every shape. ## What you can rely on without thinking about it - **Stack safety.** Any recursion you write runs in bounded stack on every backend. No `tailRecM`, no manual accumulator gymnastics required for correctness. - **Memory.** Every heap cell is reclaimed when unreachable — host GC on JVM/CLR/JS, compiler-emitted reference counting on LLVM/WASM. You write no `free`, no `Rc::clone`, no GC hints. - **Cross-target identity.** The same source produces identical stdout on LLVM, JVM, CLR, WASM, and JS, checked on every commit by snapshot tests and by property tests that compare each backend against an independent oracle. ## Full design docs (raw markdown, one fetch each) - principles: https://raw.githubusercontent.com/awsum-lang/awsum/main/docs/principles.md - type-system: https://raw.githubusercontent.com/awsum-lang/awsum/main/docs/type-system.md - prelude: https://raw.githubusercontent.com/awsum-lang/awsum/main/docs/prelude.md - recursion: https://raw.githubusercontent.com/awsum-lang/awsum/main/docs/recursion.md - memory-management: https://raw.githubusercontent.com/awsum-lang/awsum/main/docs/memory-management.md - targets: https://raw.githubusercontent.com/awsum-lang/awsum/main/docs/targets.md - pipeline: https://raw.githubusercontent.com/awsum-lang/awsum/main/docs/pipeline.md - compatibility: https://raw.githubusercontent.com/awsum-lang/awsum/main/docs/compatibility.md - platform-version-policy: https://raw.githubusercontent.com/awsum-lang/awsum/main/docs/platform-version-policy.md - testing: https://raw.githubusercontent.com/awsum-lang/awsum/main/docs/testing.md - grammar.ebnf: https://raw.githubusercontent.com/awsum-lang/awsum/main/docs/spec/grammar.ebnf - roadmap: https://raw.githubusercontent.com/awsum-lang/awsum/main/docs/roadmap.md - Prelude.aww (authoritative API surface): https://raw.githubusercontent.com/awsum-lang/awsum/main/stdlib/Prelude.aww ## Repositories - compiler: https://github.com/awsum-lang/awsum - examples: https://github.com/awsum-lang/awsum-examples - VSCode: https://github.com/awsum-lang/awsum-vscode - Zed: https://github.com/awsum-lang/awsum-zed - IntelliJ: https://github.com/awsum-lang/awsum-intellij - Neovim: https://github.com/awsum-lang/awsum-nvim - Emacs: https://github.com/awsum-lang/awsum-emacs - Tree-sitter grammar: https://github.com/awsum-lang/tree-sitter-awsum - website: https://github.com/awsum-lang/awsum-lang.org