Fork of daniellemaywood.uk/gleam — Wasm codegen work
2

Configure Feed

Select the types of activity you want to include in your feed.

Split try-gleam into own repo

https://github.com/gleam-lang/try-gleam

-1801
-23
try-gleam/.github/workflows/test.yml
··· 1 - name: test 2 - 3 - on: 4 - push: 5 - branches: 6 - - master 7 - - main 8 - pull_request: 9 - 10 - jobs: 11 - test: 12 - runs-on: ubuntu-latest 13 - steps: 14 - - uses: actions/checkout@v3 15 - - uses: erlef/setup-beam@v1 16 - with: 17 - otp-version: "26.0.2" 18 - gleam-version: "0.32.4" 19 - rebar3-version: "3" 20 - # elixir-version: "1.15.4" 21 - - run: gleam deps download 22 - - run: gleam test 23 - - run: gleam format --check src test
-5
try-gleam/.gitignore
··· 1 - *.beam 2 - *.ez 3 - build 4 - erl_crash.dump 5 - public
-22
try-gleam/README.md
··· 1 - # playground 2 - 3 - [![Package Version](https://img.shields.io/hexpm/v/playground)](https://hex.pm/packages/playground) 4 - [![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/playground/) 5 - 6 - ## Quick start 7 - 8 - ```sh 9 - gleam run # Run the project 10 - gleam test # Run the tests 11 - gleam shell # Run an Erlang shell 12 - ``` 13 - 14 - ## Installation 15 - 16 - If available on Hex this package can be added to your Gleam project: 17 - 18 - ```sh 19 - gleam add playground 20 - ``` 21 - 22 - and its documentation can be found at <https://hexdocs.pm/playground>.
-20
try-gleam/gleam.toml
··· 1 - name = "try_gleam" 2 - version = "1.0.0" 3 - target = "javascript" 4 - 5 - # Fill out these fields if you intend to generate HTML documentation or publish 6 - # your project to the Hex package manager. 7 - # 8 - # description = "" 9 - # licences = ["Apache-2.0"] 10 - # repository = { type = "github", user = "username", repo = "project" } 11 - # links = [{ title = "Website", href = "https://gleam.run" }] 12 - 13 - [dependencies] 14 - gleam_stdlib = "~> 0.32" 15 - simplifile = "~> 1.0" 16 - snag = "~> 0.2" 17 - htmb = "~> 1.1" 18 - 19 - [dev-dependencies] 20 - gleeunit = "~> 1.0"
-22
try-gleam/lessons/README.md
··· 1 - # lessons 2 - 3 - [![Package Version](https://img.shields.io/hexpm/v/lessons)](https://hex.pm/packages/lessons) 4 - [![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/lessons/) 5 - 6 - ## Quick start 7 - 8 - ```sh 9 - gleam run # Run the project 10 - gleam test # Run the tests 11 - gleam shell # Run an Erlang shell 12 - ``` 13 - 14 - ## Installation 15 - 16 - If available on Hex this package can be added to your Gleam project: 17 - 18 - ```sh 19 - gleam add lessons 20 - ``` 21 - 22 - and its documentation can be found at <https://hexdocs.pm/lessons>.
-9
try-gleam/lessons/gleam.toml
··· 1 - name = "lessons" 2 - version = "1.0.0" 3 - target = "javascript" 4 - 5 - [dependencies] 6 - gleam_stdlib = "~> 0.32" 7 - 8 - [dev-dependencies] 9 - gleeunit = "~> 1.0"
-11
try-gleam/lessons/manifest.toml
··· 1 - # This file was generated by Gleam 2 - # You typically do not need to edit this file 3 - 4 - packages = [ 5 - { name = "gleam_stdlib", version = "0.33.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "539E37A2AA5EBE8E75F4B74755E4CC604BD957C3000AC8D705A2024886A2738B" }, 6 - { name = "gleeunit", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D3682ED8C5F9CAE1C928F2506DE91625588CC752495988CBE0F5653A42A6F334" }, 7 - ] 8 - 9 - [requirements] 10 - gleam_stdlib = { version = "~> 0.32" } 11 - gleeunit = { version = "~> 1.0" }
-5
try-gleam/lessons/src/lesson000_hello_world/code.gleam
··· 1 - import gleam/io 2 - 3 - pub fn main() { 4 - io.println("Hello, Joe!") 5 - }
-26
try-gleam/lessons/src/lesson000_hello_world/text.html
··· 1 - <h2>Hello, friend 💫</h2> 2 - <p> 3 - Welcome to Try Gleam! An interactive tour of the Gleam programming language. 4 - </p> 5 - <p> 6 - It covers all aspects of the Gleam language, and assuming you have some 7 - prior programming experience should teach you everything you need to write 8 - real programs in Gleam. 9 - </p> 10 - <p> 11 - The tour is interactive! The code shown is editable and will be compiled and 12 - evaluated as you type. Anything you print using <code>io.println</code> or 13 - <code>io.debug</code> will be shown in the bottom section, along with any 14 - compile errors and warnings. To evaluate Gleam code the tour compiles Gleam to 15 - JavaScript and runs it, all entirely within your browser window. 16 - </p> 17 - <p> 18 - If at any point you get stuck or have a question do not hesitate to ask in 19 - <a href="https://discord.gg/Fm8Pwmy">the Gleam Discord server</a>. We're here 20 - to help, and if you find something confusing then it's likely others will too, 21 - and we want to know about it so we can improve the tour. 22 - </p> 23 - <p> 24 - OK, let's go. Click "Next" to get started, or click "Index" to jump to a 25 - specific topic. 26 - </p>
-7
try-gleam/lessons/src/lesson001_basics/code.gleam
··· 1 - // Import a Gleam module from the standard library 2 - import gleam/io 3 - 4 - pub fn main() { 5 - // Print to the console 6 - io.println("Hello, Joe!") 7 - }
-17
try-gleam/lessons/src/lesson001_basics/text.html
··· 1 - <p> 2 - Here is a program that prints out the text "Hello, Joe!". 3 - </p> 4 - <p> 5 - It does this by using the `println` function which has been imported from the 6 - <a href="https://hexdocs.pm/gleam_stdlib/gleam/io.html"><code>gleam/io</code></a> 7 - module, which is part of the Gleam standard library. 8 - </p> 9 - <p> 10 - In a normal Gleam program this program would be run use the command 11 - <code>gleam run</code> on the command line, but here in this tutorial the 12 - program is automatically compiled and run as the code is edited. 13 - </p> 14 - <p> 15 - Try changing the text being printed to <code>Hello, Mike!</code> and see what 16 - happens. 17 - </p>
-10
try-gleam/lessons/src/lesson002_unqualified_imports/code.gleam
··· 1 - // Import the module and one of its functions 2 - import gleam/io.{println} 3 - 4 - pub fn main() { 5 - // Use the function in a qualified fashion 6 - io.println("This is qualified") 7 - 8 - // Or an unqualified fashion 9 - println("This is unqualified") 10 - }
-15
try-gleam/lessons/src/lesson002_unqualified_imports/text.html
··· 1 - <p> 2 - Normally functions from other modules are used in a qualified fashion, with 3 - the module qualifier before function name. For example, 4 - <code>io.println("Hello!")</code>. 5 - </p> 6 - <p> 7 - It is also possible to specify a list of functions to import from a module in 8 - an unqualified fashion, such as the <code>println</code> function in the code 9 - editor. Because it has been imported like this it can be referred to as just 10 - <code>println</code>. 11 - </p> 12 - <p> 13 - Generally it is best to use qualified imports, as this makes it clear where 14 - the function is defined, making the code easier to read. 15 - </p>
-7
try-gleam/lessons/src/lesson003_type_checking/code.gleam
··· 1 - import gleam/io 2 - 3 - pub fn main() { 4 - io.println("My lucky number is:") 5 - // io.println(4) 6 - // 👆️ Uncomment this line 7 - }
-19
try-gleam/lessons/src/lesson003_type_checking/text.html
··· 1 - <p> 2 - Gleam has a robust static type system that is help you as you write and edit 3 - code, catching mistakes and showing you where to make changes. 4 - </p> 5 - <p> 6 - Uncomment the line <code>io.println(4)</code> and see how a compile time error 7 - is reported as the <code>io.println</code> function only works with strings, 8 - not ints. 9 - </p> 10 - <p> 11 - To fix the code change the code to call the <code>io.debug</code> 12 - function instead, as it will print a value of any type. 13 - </p> 14 - <p> 15 - Gleam has no <code>null</code>, no implicit conversions, no exceptions, and 16 - always performs full type checking. If the code compiles you can be reasonably 17 - confident it does not have any inconsistencies that may cause bugs or 18 - crashes. 19 - </p>
-21
try-gleam/lessons/src/lesson004_ints/code.gleam
··· 1 - import gleam/io 2 - import gleam/int 3 - 4 - pub fn main() { 5 - // Int arithmetic 6 - io.debug(1 + 1) 7 - io.debug(5 - 1) 8 - io.debug(5 / 2) 9 - io.debug(3 * 3) 10 - io.debug(5 % 2) 11 - 12 - // Int comparisons 13 - io.debug(2 > 1) 14 - io.debug(2 < 1) 15 - io.debug(2 >= 1) 16 - io.debug(2 <= 1) 17 - 18 - // Standard library int functions 19 - io.debug(int.max(42, 77)) 20 - io.debug(int.clamp(5, 10, 20)) 21 - }
-15
try-gleam/lessons/src/lesson004_ints/text.html
··· 1 - <p> 2 - Gleam's <code>Int</code> type represents whole numbers. 3 - </p> 4 - <p> 5 - There are arithmetic and comparison operators for ints. 6 - </p> 7 - <p> 8 - When running on the Erlang virtual machine ints have no maximum and minimum 9 - size. When running on JavaScript runtimes ints are represented using 10 - JavaScript's 64 bit floating point numbers, 11 - </p> 12 - <p> 13 - The <a href="https://hexdocs.pm/gleam_stdlib/gleam/int.html"><code>gleam/int</code></a> 14 - standard library module contains functions for working with ints. 15 - </p>
-20
try-gleam/lessons/src/lesson005_floats/code.gleam
··· 1 - import gleam/io 2 - import gleam/float 3 - 4 - pub fn main() { 5 - // Float arithmetic 6 - io.debug(1.0 +. 1.5) 7 - io.debug(5.0 -. 1.5) 8 - io.debug(5.0 /. 2.5) 9 - io.debug(3.0 *. 3.5) 10 - 11 - // Float comparisons 12 - io.debug(2.2 >. 1.3) 13 - io.debug(2.2 <. 1.3) 14 - io.debug(2.2 >=. 1.3) 15 - io.debug(2.2 <=. 1.3) 16 - 17 - // Standard library float functions 18 - io.debug(float.max(2.0, 9.5)) 19 - io.debug(float.ceiling(5.4)) 20 - }
-19
try-gleam/lessons/src/lesson005_floats/text.html
··· 1 - <p> 2 - Gleam's <code>Float</code> type represents numbers that are not integers. 3 - </p> 4 - <p> 5 - Unlike many languages Gleam does not have a `NaN` or `Infinity` float value. 6 - </p> 7 - <p> 8 - Gleam's numerical operators are not overloaded, so there are dedictated 9 - operators for working with floats. 10 - </p> 11 - <p> 12 - Floats are represented as 64 bit floating point numbers on both Erlang and 13 - JavaScript runtimes. 14 - </p> 15 - <p> 16 - The <a href="https://hexdocs.pm/gleam_stdlib/gleam/float.html"><code>gleam/float</code></a> 17 - standard library module contains functions for working with floats. 18 - </p> 19 -
-16
try-gleam/lessons/src/lesson006_number_formats/code.gleam
··· 1 - import gleam/io 2 - 3 - pub fn main() { 4 - // Underscores 5 - io.debug(1_000_000) 6 - io.debug(10_000.01) 7 - 8 - // Binary, octal, and hex Int literals 9 - io.debug(0b00001111) 10 - io.debug(0o17) 11 - io.debug(0xF) 12 - 13 - // Scientific notation Float literals 14 - io.debug(7.0e7) 15 - io.debug(3.0e-4) 16 - }
-13
try-gleam/lessons/src/lesson006_number_formats/text.html
··· 1 - <p> 2 - Underscores can be added to numbers for clarity. For example, 3 - <code>1000000</code> can be tricky to read quickly, while 4 - <code>1_000_000</code> can be easier. 5 - </p> 6 - <p> 7 - Ints can be written in binary, octal, or hexadecimal formats using the 8 - <code>0b</code>, <code>0o</code>, and <code>0x</code> prefixes respectively. 9 - </p> 10 - <p> 11 - Floats can be written in a scientific notation. 12 - </p> 13 -
-20
try-gleam/lessons/src/lesson007_strings/code.gleam
··· 1 - import gleam/io 2 - import gleam/string 3 - 4 - pub fn main() { 5 - // String literals 6 - io.debug("👩‍💻 こんにちは Gleam 🏳️‍🌈") 7 - io.debug( 8 - "multi 9 - line 10 - string", 11 - ) 12 - io.debug("\u{1F600}") 13 - 14 - // String concatenation 15 - io.debug("One " <> "Two") 16 - 17 - // String functions 18 - io.debug(string.reverse("1 2 3 4 5")) 19 - io.debug(string.append("abc", "def")) 20 - }
-23
try-gleam/lessons/src/lesson007_strings/text.html
··· 1 - <p> 2 - In Gleam Strings are written as text surrounded by double quotes, and 3 - can span multiple lines and contain unicode characters. 4 - </p> 5 - <p> 6 - The <code>&lt;&gt;</code> operator can be used to concatenate strings. 7 - </p> 8 - <p> 9 - Several escape sequences are supported: 10 - </p> 11 - <ul> 12 - <li><code>\"</code> - double quote</li> 13 - <li><code>\\</code> - backslash</li> 14 - <li><code>\f</code> - form feed</li> 15 - <li><code>\n</code> - newline</li> 16 - <li><code>\r</code> - carriage return</li> 17 - <li><code>\t</code> - tab</li> 18 - <li><code>\u{xxxxxx}</code> - unicode codepoint</li> 19 - </ul> 20 - <p> 21 - The <a href="https://hexdocs.pm/gleam_stdlib/gleam/string.html"><code>gleam/string</code></a> 22 - standard library module contains functions for working with strings. 23 - </p>
-14
try-gleam/lessons/src/lesson008_bools/code.gleam
··· 1 - import gleam/io 2 - import gleam/bool 3 - 4 - pub fn main() { 5 - // Bool operators 6 - io.debug(True && False) 7 - io.debug(True && True) 8 - io.debug(False || False) 9 - io.debug(False || True) 10 - 11 - // Bool functions 12 - io.debug(bool.to_string(True)) 13 - io.debug(bool.to_int(False)) 14 - }
-17
try-gleam/lessons/src/lesson008_bools/text.html
··· 1 - <p> 2 - A <code>Bool</code> is a either <code>True</code> or <code>False</code>. 3 - </p> 4 - <p> 5 - The <code>||</code>, <code>&&</code>, and <code>!</code> operators can be used 6 - to manipulate bools. 7 - </p> 8 - <p> 9 - The <code>||</code> and <code>&&</code> operators are short-circuiting, 10 - meaning that if the left hand side of the operator is <code>True</code> for 11 - <code>||</code> or <code>False</code> for <code>&&</code> then the right hand 12 - side of the operator will not be evaluated. 13 - </p> 14 - <p> 15 - The <a href="https://hexdocs.pm/gleam_stdlib/gleam/bool.html"><code>gleam/bool</code></a> 16 - standard library module contains functions for working with bools. 17 - </p>
-17
try-gleam/lessons/src/lesson009_assignments/code.gleam
··· 1 - import gleam/io 2 - 3 - pub fn main() { 4 - let x = "Original" 5 - io.debug(x) 6 - 7 - // Assign `y` to the value of `x` 8 - let y = x 9 - io.debug(y) 10 - 11 - // Assign `x` to a new value 12 - let x = "New" 13 - io.debug(x) 14 - 15 - // The `y` still refers to the original value 16 - io.debug(y) 17 - }
-8
try-gleam/lessons/src/lesson009_assignments/text.html
··· 1 - <p> 2 - A value can be assigned to a variable using <code>let</code>. 3 - </p> 4 - <p> 5 - Variable names can be reused by later let bindings, but the values they 6 - reference are immutable, so the values themselves are not changed or mutated 7 - in any way. 8 - </p>
-4
try-gleam/lessons/src/lesson010_discard_patterns/code.gleam
··· 1 - pub fn main() { 2 - // This variable is never used 3 - let _score = 1000 4 - }
-10
try-gleam/lessons/src/lesson010_discard_patterns/text.html
··· 1 - <p> 2 - If a variable is assigned but not used then Gleam will emit a warning. 3 - </p> 4 - <p> 5 - If a variable is intended not to be use then the name can be prefixed with an 6 - underscore, silencing the warning. 7 - </p> 8 - <p> 9 - Try changing the variable name to <code>score</code> to see the warning. 10 - </p>
-7
try-gleam/lessons/src/lesson011_type_annotations/code.gleam
··· 1 - pub fn main() { 2 - let _name: String = "Gleam" 3 - 4 - let _is_cool: Bool = True 5 - 6 - let _version: Int = 1 7 - }
-15
try-gleam/lessons/src/lesson011_type_annotations/text.html
··· 1 - <p> 2 - Let assignments can be written with a type annotation after the name. 3 - </p> 4 - <p> 5 - Type annotations may be useful for documentation purposes, but they do not 6 - change how Gleam type checks the code beyond ensuring that the annotation is 7 - correct. 8 - </p> 9 - <p> 10 - Typically Gleam code will not have type annotations for assignments. 11 - </p> 12 - <p> 13 - Try changing a type annotation to something incorrect to see the compile 14 - error. 15 - </p>
-13
try-gleam/lessons/src/lesson012_blocks/code.gleam
··· 1 - import gleam/io 2 - 3 - pub fn main() { 4 - let fahrenheit = { 5 - let degrees = 64 6 - degrees 7 - } 8 - // io.debug(degrees) // <- This will not compile 9 - 10 - // Changing order of evaluation 11 - let celsius = { fahrenheit - 32 } * 5 / 9 12 - io.debug(celsius) 13 - }
-23
try-gleam/lessons/src/lesson012_blocks/text.html
··· 1 - <p> 2 - Blocks are one or more expressions grouped together with curly braces. Each 3 - expression is evaluated in order and the value of the last expression is 4 - returned. 5 - </p> 6 - <p> 7 - Any variables assigned within the block can only be used within the block. 8 - </p> 9 - <p> 10 - Try uncommenting <code>io.debug(degrees)</code> to see the compile error from 11 - trying to use a variable that is not in scope. 12 - </p> 13 - <p> 14 - Blocks can also be used to change the order of evaluation of binary operators 15 - expressions. 16 - </p> 17 - <p> 18 - <code>*</code> binds more tightly than <code>+</code> so the expression 19 - <code>1 + 2 * 3</code> evaluates to 7. If the <code>1 + 2</code> should be 20 - evaluated first to make the expression evaluate to 9 then the expression can be 21 - wrapped in a block: <code>{ 1 + 2 } * 3</code>. This is similar to grouping 22 - with parentheses in some other languages. 23 - </p>
-13
try-gleam/lessons/src/lesson013_functions/code.gleam
··· 1 - import gleam/io 2 - 3 - pub fn main() { 4 - io.debug(double(10)) 5 - } 6 - 7 - fn double(a: Int) -> Int { 8 - multiply(a, 2) 9 - } 10 - 11 - fn multiply(a: Int, b: Int) -> Int { 12 - a * b 13 - }
-14
try-gleam/lessons/src/lesson013_functions/text.html
··· 1 - <p> 2 - The <code>fn</code> keyword is used to define new functions. 3 - </p> 4 - <p> 5 - The <code>double</code> and <code>multiply</code> functions are defined 6 - without the <code>pub</code> keyword. This makes them <em>private</em> 7 - functions, they can only be used within this module. If another module 8 - attempted to use them it would result in a compiler error. 9 - </p> 10 - <p> 11 - Like with assignments, type annotations are optional for function arguments 12 - and return values. It is considered good practice to use type annotations for 13 - functions, for clarity and to encourage intentional and thoughtful design. 14 - </p>
-18
try-gleam/lessons/src/lesson014_higher_order_functions/code.gleam
··· 1 - import gleam/io 2 - 3 - pub fn main() { 4 - // Call a function with another function 5 - io.debug(twice(1, add_one)) 6 - 7 - // Functions can be assigned to variables 8 - let function = add_one 9 - io.debug(function(100)) 10 - } 11 - 12 - fn twice(argument: Int, function: fn(Int) -> Int) -> Int { 13 - function(function(argument)) 14 - } 15 - 16 - fn add_one(argument: Int) -> Int { 17 - argument + 1 18 - }
-12
try-gleam/lessons/src/lesson014_higher_order_functions/text.html
··· 1 - <p> 2 - In Gleam functions are values. They can be assigned to variables, passed to 3 - other functions, and anything else you can do with values. 4 - </p> 5 - <p> 6 - Here the function <code>add_one</code> is being passed as an argument to the 7 - <code>twice</code> function. 8 - </p> 9 - <p> 10 - Notice the <code>fn</code> keyword is also used to describe the type of the 11 - function that <code>twice</code> takes as its second argument. 12 - </p>
-14
try-gleam/lessons/src/lesson015_anonymous_functions/code.gleam
··· 1 - import gleam/io 2 - 3 - pub fn main() { 4 - // Assign an anonymous function to a variable 5 - let add_one = fn(a) { a + 1 } 6 - io.debug(twice(1, add_one)) 7 - 8 - // Pass an anonymous function as an argument 9 - io.debug(twice(1, fn(a) { a * 2 })) 10 - } 11 - 12 - fn twice(argument: Int, function: fn(Int) -> Int) -> Int { 13 - function(function(argument)) 14 - }
-7
try-gleam/lessons/src/lesson015_anonymous_functions/text.html
··· 1 - <p> 2 - As well as module-level named functions, Gleam has anonymous function 3 - literals. 4 - </p> 5 - <p> 6 - Anonymous functions can be used interchangeably with named functions. 7 - </p>
-14
try-gleam/lessons/src/lesson016_function_captures/code.gleam
··· 1 - import gleam/io 2 - 3 - pub fn main() { 4 - // These two statements are equivalent 5 - let add_one_v1 = fn(x) { add(1, x) } 6 - let add_one_v2 = add(1, _) 7 - 8 - io.debug(add_one_v1(10)) 9 - io.debug(add_one_v2(10)) 10 - } 11 - 12 - fn add(a: Int, b: Int) -> Int { 13 - a + b 14 - }
-11
try-gleam/lessons/src/lesson016_function_captures/text.html
··· 1 - <p> 2 - Gleam has a shorthand syntax for creating anonymous functions that take one 3 - argument and immediately call another function with that argument: the 4 - function capture syntax. 5 - </p> 6 - <p> 7 - The anonymous function <code>fn(a) { some_function(..., a, ...) }</code> can 8 - be written as <code>some_function(..., _, ...)</code>, with any number of 9 - other arguments passed to the inner function. The underscore <code>_</code> is 10 - a placeholder for the final argument. 11 - </p>
-19
try-gleam/lessons/src/lesson017_generic_functions/code.gleam
··· 1 - import gleam/io 2 - 3 - pub fn main() { 4 - let add_one = fn(x) { x + 1 } 5 - let exclaim = fn(x) { x <> "!" } 6 - 7 - // Invalid, Int and String are not the same type 8 - // twice(10, exclaim) 9 - 10 - // Here the type variable is replaced by the type Int 11 - io.debug(twice(10, add_one)) 12 - 13 - // Here the type variable is replaced by the type String 14 - io.debug(twice("Hello", exclaim)) 15 - } 16 - 17 - fn twice(argument: value, function: fn(value) -> value) -> value { 18 - function(function(argument)) 19 - }
-25
try-gleam/lessons/src/lesson017_generic_functions/text.html
··· 1 - <p> 2 - Up until now each function has accepted precisely one type for each of its 3 - arguments. 4 - </p> 5 - <p> 6 - The <code>twice</code> function for example only worked with functions that 7 - would take and return ints. This is overly restrictive, it should be possible 8 - to use this function with any type, so long as the function and the initial 9 - value are compatible. 10 - </p> 11 - <p> 12 - To enable this Gleam support <em>generics</em>, also known as <em>parametric 13 - polymorphism</em>. 14 - </p> 15 - <p> 16 - This works by instead of specifying a concrete type, a type variable is used 17 - which stands in for whatever specific type is being used when the function is 18 - called. These type variable are written with a lowercase name. 19 - </p> 20 - <p> 21 - Type variables are not like an <code>any</code> type, they get replaced with a 22 - specific type each time the function is called. Try uncommenting 23 - <code>twice(10, exclaim)</code> to see the compiler error from trying to use a 24 - type variable as an int and a string at the same time. 25 - </p>
-19
try-gleam/lessons/src/lesson018_pipelines/code.gleam
··· 1 - import gleam/io 2 - import gleam/string 3 - 4 - pub fn main() { 5 - // Without the pipe operator 6 - io.debug(string.drop_left(string.drop_right("Hello, Joe!", 1), 7)) 7 - 8 - // With the pipe operator 9 - "Hello, Mike!" 10 - |> string.drop_right(1) 11 - |> string.drop_left(7) 12 - |> io.debug 13 - 14 - // Changing order with function capturing 15 - "1" 16 - |> string.append("2") 17 - |> string.append("3", _) 18 - |> io.debug 19 - }
-25
try-gleam/lessons/src/lesson018_pipelines/text.html
··· 1 - <p> 2 - It's common to want to call a series of functions, passing the result of one 3 - to the next. With the regular function call syntax this can be a little 4 - difficult to read as you have to read the code from the inside out. 5 - </p> 6 - <p> 7 - Gleam's pipe operator <code>|></code> helps with this problem by allowing you 8 - to write code top-to-bottom. 9 - </p> 10 - <p> 11 - The pipe operator takes the result of the expression on its left and passes it 12 - as an argument to the function on its right. 13 - </p> 14 - <p> 15 - It will first check to see if the left-hand value could be used as the first 16 - argument to the call. For example, <code>a |> b(1, 2)</code> would become 17 - <code>b(a, 1, 2)</code>. If not, it falls back to calling the result of the 18 - right-hand side as a function, e.g., <code>b(1, 2)(a)</code> 19 - </p> 20 - <p> 21 - Gleam code is typically written with the "subject" of the function as the 22 - first argument, to make it easier to pipe. If you wish to pipe to a different 23 - position then a function capture can be used to insert the argument to the 24 - desired position. 25 - </p>
-16
try-gleam/lessons/src/lesson019_labelled_arguments/code.gleam
··· 1 - import gleam/io 2 - 3 - pub fn main() { 4 - // Without using labels 5 - io.debug(calculate(1, 2, 3)) 6 - 7 - // Using the labels 8 - io.debug(calculate(1, add: 2, multiply: 3)) 9 - 10 - // Using the labels in a different order 11 - io.debug(calculate(1, multiply: 3, add: 2)) 12 - } 13 - 14 - fn calculate(value: Int, add addend: Int, multiply multiplier: Int) { 15 - value * multiplier + addend 16 - }
-23
try-gleam/lessons/src/lesson019_labelled_arguments/text.html
··· 1 - <p> 2 - When functions take several arguments it can be difficult to remember what the 3 - arguments are, and what order they are expected in. 4 - </p> 5 - <p> 6 - To help with this Gleam supports labelled arguments, where function arguments 7 - are given an external label in addition to their internal name. These labels 8 - are written before the argument name in the function definition. 9 - </p> 10 - <p> 11 - When labelled arguments are used the order of the arguments does not matter, 12 - but all unlabelled arguments must come before labelled arguments. 13 - </p> 14 - <p> 15 - There is no performance cost to using labelled arguments, it does not allocate 16 - a dictionary or perform any other runtime work. 17 - </p> 18 - <p> 19 - Labels are optional when calling a function, it is up to the programmer to 20 - decide what is clearest in their code. 21 - </p> 22 - 23 -
-16
try-gleam/lessons/src/lesson020_lists/code.gleam
··· 1 - import gleam/io 2 - 3 - pub fn main() { 4 - let ints = [1, 2, 3] 5 - 6 - io.debug(ints) 7 - 8 - // Immutably prepend 9 - io.debug([-1, 0, ..ints]) 10 - 11 - // Uncomment this to see the error 12 - // io.debug(["zero", ..ints]) 13 - 14 - // The original lists are unchanged 15 - io.debug(ints) 16 - }
-19
try-gleam/lessons/src/lesson020_lists/text.html
··· 1 - <p> 2 - Lists are ordered collections of values. 3 - </p> 4 - <p> 5 - <code>List</code> is a generic type, having a type parameter 6 - for the type of values it contains. A list of ints has the type 7 - <code>List(Int)</code>, and a list of strings has the type 8 - <code>List(String)</code>. 9 - </p> 10 - <p> 11 - Lists are immutable single-linked lists, meaning they are very efficient to 12 - add and remove elements from the front of the list. 13 - </p> 14 - <p> 15 - Counting the length of a list or getting elements from other positions in the 16 - list is expensive and rarely done. It is rare to write algorithms that index 17 - into sequences in Gleam, but but when they are written a list is not the right 18 - choice of data structure. 19 - </p>
-15
try-gleam/lessons/src/lesson021_list_functions/code.gleam
··· 1 - import gleam/io 2 - import gleam/list 3 - 4 - pub fn main() { 5 - let ints = [0, 1, 2, 3, 4, 5] 6 - 7 - let doubled = list.map(ints, fn(x) { x * 2 }) 8 - io.debug(doubled) 9 - 10 - let even = list.filter(ints, fn(x) { x % 2 == 0 }) 11 - io.debug(even) 12 - 13 - let total = list.fold(ints, from: 0, with: fn(count, e) { count + e }) 14 - io.debug(total) 15 - }
-25
try-gleam/lessons/src/lesson021_list_functions/text.html
··· 1 - <p> 2 - The <a href="https://hexdocs.pm/gleam_stdlib/gleam/list.html"><code>gleam/list</code></a> 3 - standard library module contains functions for working with lists. A Gleam 4 - program will likely make heavy use of this module. 5 - </p> 6 - 7 - <p> 8 - <a href="https://hexdocs.pm/gleam_stdlib/gleam/list.html#map"><code>map</code></a> 9 - makes a new list by running a function on each element in a list. 10 - </p> 11 - <p> 12 - <a href="https://hexdocs.pm/gleam_stdlib/gleam/list.html#filter"><code>filter</code></a> 13 - makes a new list containing only the elements for which a function returns 14 - true. 15 - </p> 16 - <p> 17 - <a href="https://hexdocs.pm/gleam_stdlib/gleam/list.html#fold"><code>fold</code></a> 18 - combines all the elements in a list into a single value by running a function 19 - left-to-right on each element, passing the result of the previous call to the 20 - next call. 21 - </p> 22 - <p> 23 - It's worth getting familiar with all the functions in this module when writing 24 - Gleam code. 25 - </p>
-10
try-gleam/lessons/src/lesson022_case_expressions/code.gleam
··· 1 - import gleam/io 2 - import gleam/int 3 - 4 - pub fn main() { 5 - let result = case int.random(0, 5) { 6 - 0 -> "It's zero!" 7 - other -> "It's " <> int.to_string(other) 8 - } 9 - io.debug(result) 10 - }
-7
try-gleam/lessons/src/lesson022_case_expressions/text.html
··· 1 - <p> 2 - Patterns in case expressions can also assign variables. 3 - </p> 4 - <p> 5 - When a variable name is used in a pattern the value that is matched against is 6 - assigned to that name, and can be used in the body of that clause. 7 - </p>
-16
try-gleam/lessons/src/lesson023_variable_patterns/code.gleam
··· 1 - import gleam/io 2 - import gleam/int 3 - 4 - pub fn main() { 5 - let x = int.random(0, 5) 6 - io.debug(x) 7 - 8 - let result = case x { 9 - // Match specific values 10 - 0 -> "Zero" 11 - 1 -> "One" 12 - // Match any other value 13 - _ -> "Other" 14 - } 15 - io.debug(result) 16 - }
-17
try-gleam/lessons/src/lesson023_variable_patterns/text.html
··· 1 - <p> 2 - The case expression is the most common kind of flow control in Gleam code. It 3 - is similar to `switch` in some other languages, but more powerful than most. 4 - </p> 5 - <p> 6 - It allows the programmer to say "if the data has this shape then run this 7 - code", a process called called <em>pattern matching</em>. 8 - </p> 9 - <p> 10 - Gleam performs <em>exhaustiveness checking</em> to ensure that the patterns in 11 - a case expression cover all possible values. With this you can have confidence 12 - that your logic is up-to-date for the design of the data you are working with. 13 - </p> 14 - <p> 15 - Try commenting out patterns or adding new redundant ones, and see what 16 - problems the compiler reports. 17 - </p>
-14
try-gleam/lessons/src/lesson024_string_patterns/code.gleam
··· 1 - import gleam/io 2 - 3 - pub fn main() { 4 - io.debug(get_name("Hello, Joe")) 5 - io.debug(get_name("Hello, Mike")) 6 - io.debug(get_name("System still working?")) 7 - } 8 - 9 - fn get_name(x: String) -> String { 10 - case x { 11 - "Hello, " <> name -> name 12 - _ -> "Unknown" 13 - } 14 - }
-9
try-gleam/lessons/src/lesson024_string_patterns/text.html
··· 1 - <p> 2 - When pattern matching on strings the <code>&lt;&gt;</code> operator can be 3 - used to match on strings with a specific prefix. 4 - </p> 5 - <p> 6 - The pattern <code>"hello " <> name</code> matches any string that starts with 7 - <code>"hello "</code> and asigns the rest of the string to the variable 8 - <code>name</code>. 9 - </p>
-17
try-gleam/lessons/src/lesson025_list_patterns/code.gleam
··· 1 - import gleam/io 2 - import gleam/int 3 - import gleam/list 4 - 5 - pub fn main() { 6 - let x = list.repeat(int.random(0, 5), times: int.random(0, 3)) 7 - io.debug(x) 8 - 9 - let result = case x { 10 - [] -> "Empty list" 11 - [1] -> "List of just 1" 12 - [4, ..] -> "List starting with 4" 13 - [_, _] -> "List of 2 elements" 14 - _ -> "Some other list" 15 - } 16 - io.debug(result) 17 - }
-15
try-gleam/lessons/src/lesson025_list_patterns/text.html
··· 1 - <p> 2 - Lists and the values they contain can be pattern matched on in case 3 - expressions. 4 - </p> 5 - <p> 6 - List patterns match on specific lengths of lists. The pattern <code>[]</code> 7 - matches an empty list, and the pattern <code>[_]</code> matches a list with 8 - one element. They will not match on lists with other lengths. 9 - </p> 10 - <p> 11 - The spread pattern <code>..</code> can be used to match the rest of the list. 12 - The pattern <code>[1, ..]</code> matches any list that starts with 13 - <code>1</code>. The pattern <code>[_, _, ..]</code> matches any list that has 14 - at least two elements. 15 - </p>
-13
try-gleam/lessons/src/lesson026_list_recursion/code.gleam
··· 1 - import gleam/io 2 - 3 - pub fn main() { 4 - let sum = sum_list([18, 56, 35, 85, 91], 0) 5 - io.debug(sum) 6 - } 7 - 8 - fn sum_list(list: List(Int), total: Int) -> Int { 9 - case list { 10 - [first, ..rest] -> sum_list(rest, total + first) 11 - [] -> total 12 - } 13 - }
-22
try-gleam/lessons/src/lesson026_list_recursion/text.html
··· 1 - <p> 2 - Most commonly functions in the 3 - <a href="https://hexdocs.pm/gleam_stdlib/gleam/list.html"><code>gleam/list</code></a> 4 - module are used to iterate across a list, but at times you may prefer 5 - to work with the list directly. 6 - </p> 7 - <p> 8 - Gleam doesn't have a looping syntax, instead iteration is done through 9 - recursion and pattern matching. 10 - </p> 11 - <p> 12 - The <code>[first, ..rest]</code> pattern matches on a list with at least one 13 - element, assigning the first element to the variable <code>first</code> and 14 - the rest of the list to the variable <code>rest</code>. 15 - By using this pattern and a pattern for the empty list <code>[]</code> a 16 - function can run code on each element of a list until the end is reached. 17 - </p> 18 - <p> 19 - This code sums a list by recursing over the list and adding each int to a 20 - <code>total</code> argument, returning it when the end is reached. 21 - </p> 22 -
-19
try-gleam/lessons/src/lesson099_documentation_comments/code.gleam
··· 1 - //// A module containing some unusual functions and types. 2 - 3 - /// A type where the value can never be constructed. 4 - /// Can you work out why? 5 - pub type Never { 6 - Never(Never) 7 - } 8 - 9 - /// Call a function twice with an initial value. 10 - /// 11 - pub fn twice(argument: value, function: fn(value) -> value) -> value { 12 - function(function(argument)) 13 - } 14 - 15 - /// Call a function three times with an initial value. 16 - /// 17 - pub fn thrice(argument: value, function: fn(value) -> value) -> value { 18 - function(function(function(argument))) 19 - }
-16
try-gleam/lessons/src/lesson099_documentation_comments/text.html
··· 1 - <p> 2 - Documentation and comments are important tools for making your code easier to 3 - work with and understand. 4 - </p> 5 - <p> 6 - As well as regular <code>//</code> comments Gleam has <code>///</code> and 7 - <code>////</code> comments which are used for attaching documentation to code. 8 - </p> 9 - <p> 10 - <code>///</code> is used for documenting types and functions, and should be 11 - placed immediately before the type or function it is documenting. 12 - </p> 13 - <p> 14 - <code>////</code> is used for documenting modules, and should be placed 15 - at the top of the module. 16 - </p>
-12
try-gleam/lessons/test/lessons_test.gleam
··· 1 - import gleeunit 2 - import gleeunit/should 3 - 4 - pub fn main() { 5 - gleeunit.main() 6 - } 7 - 8 - // gleeunit test functions end in `_test` 9 - pub fn hello_world_test() { 10 - 1 11 - |> should.equal(1) 12 - }
-17
try-gleam/manifest.toml
··· 1 - # This file was generated by Gleam 2 - # You typically do not need to edit this file 3 - 4 - packages = [ 5 - { name = "gleam_stdlib", version = "0.33.1", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "3CEAD7B153D896499C78390B22CC968620C27500C922AED3A5DD7B536F922B25" }, 6 - { name = "gleeunit", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D3682ED8C5F9CAE1C928F2506DE91625588CC752495988CBE0F5653A42A6F334" }, 7 - { name = "htmb", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "htmb", source = "hex", outer_checksum = "30D448F0E15DFCF7283AAAC2F351D77B9D54E318219C9FDDB1877572B67C27B7" }, 8 - { name = "simplifile", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "0BD6F0E7DA1A7E11D18B8AD48453225CAFCA4C8CFB4513D217B372D2866C501C" }, 9 - { name = "snag", version = "0.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "8FD70D8FB3728E08AC425283BB509BB0F012BE1AE218424A597CDE001B0EE589" }, 10 - ] 11 - 12 - [requirements] 13 - gleam_stdlib = { version = "~> 0.32" } 14 - gleeunit = { version = "~> 1.0" } 15 - htmb = { version = "~> 1.1" } 16 - simplifile = { version = "~> 1.0" } 17 - snag = { version = "~> 0.2" }
-397
try-gleam/src/try_gleam.gleam
··· 1 - import gleam/io 2 - import gleam/list 3 - import htmb.{h, text} 4 - import gleam/string_builder 5 - import gleam/option.{type Option, None, Some} 6 - import gleam/pair 7 - import gleam/string 8 - import gleam/result 9 - import simplifile 10 - import snag 11 - 12 - const static = "static" 13 - 14 - const public = "public" 15 - 16 - const public_precompiled = "public/precompiled" 17 - 18 - const prelude = "../compiler-core/templates/prelude.mjs" 19 - 20 - const stdlib_compiled = "build/dev/javascript/gleam_stdlib/gleam" 21 - 22 - const stdlib_sources = "build/packages/gleam_stdlib/src/gleam" 23 - 24 - const stdlib_external = "build/packages/gleam_stdlib/src" 25 - 26 - const compiler_wasm = "../compiler-wasm/pkg" 27 - 28 - const lessons_src = "lessons/src" 29 - 30 - const hello_joe = "import gleam/io 31 - 32 - pub fn main() { 33 - io.println(\"Hello, Joe!\") 34 - } 35 - " 36 - 37 - // Don't include deprecated stdlib modules 38 - const skipped_stdlib_modules = [ 39 - "bit_string.gleam", "bit_builder.gleam", "map.gleam", 40 - ] 41 - 42 - pub fn main() { 43 - let result = { 44 - use _ <- result.try(reset_output()) 45 - use _ <- result.try(make_prelude_available()) 46 - use _ <- result.try(make_stdlib_available()) 47 - use _ <- result.try(copy_wasm_compiler()) 48 - use p <- result.try(load_pages()) 49 - use _ <- result.try(write_pages(p)) 50 - Ok(Nil) 51 - } 52 - 53 - case result { 54 - Ok(_) -> Nil 55 - Error(snag) -> { 56 - io.println(snag.pretty_print(snag)) 57 - panic 58 - } 59 - } 60 - } 61 - 62 - type Page { 63 - Page( 64 - name: String, 65 - text: String, 66 - code: String, 67 - path: String, 68 - previous: Option(String), 69 - next: Option(String), 70 - ) 71 - } 72 - 73 - fn load_pages() -> snag.Result(List(Page)) { 74 - use lessons <- result.try( 75 - simplifile.read_directory(lessons_src) 76 - |> file_error("Failed to read lessons directory"), 77 - ) 78 - 79 - let lessons = 80 - lessons 81 - |> list.sort(by: string.compare) 82 - |> list.index_map(pair.new) 83 - 84 - use pages <- result.try(list.try_map(lessons, fn(pair) { 85 - let #(index, lesson) = pair 86 - let path = lessons_src <> "/" <> lesson 87 - let name = 88 - lesson 89 - |> string.split("_") 90 - |> list.drop(1) 91 - |> string.join("-") 92 - 93 - use code <- result.try( 94 - simplifile.read(path <> "/code.gleam") 95 - |> file_error("Failed to read code.gleam"), 96 - ) 97 - 98 - use text <- result.try( 99 - simplifile.read(path <> "/text.html") 100 - |> file_error("Failed to read text.html"), 101 - ) 102 - 103 - let path = case index { 104 - 0 -> "/" 105 - _ -> "/" <> name 106 - } 107 - 108 - Ok( 109 - Page( 110 - name: name, 111 - text: text, 112 - code: code, 113 - path: path, 114 - previous: None, 115 - next: None, 116 - ), 117 - ) 118 - })) 119 - 120 - Ok(add_previous_next(pages, [], None)) 121 - } 122 - 123 - fn write_pages(pages: List(Page)) -> snag.Result(Nil) { 124 - use _ <- result.try(list.try_each(pages, write_page)) 125 - 126 - let render = fn(h) { string_builder.to_string(htmb.render(h)) } 127 - let html = 128 - string.concat([ 129 - render(h("h2", [], [text("Table of contents")])), 130 - render(h("ul", [], list.map(pages, fn(page) { 131 - h("li", [], [ 132 - h("a", [#("href", page.path)], [ 133 - page.name 134 - |> string.replace("-", " ") 135 - |> string.capitalise 136 - |> text, 137 - ]), 138 - ]) 139 - }))), 140 - ]) 141 - 142 - let page = 143 - Page( 144 - name: "Index", 145 - text: html, 146 - code: hello_joe, 147 - path: "/index", 148 - previous: None, 149 - next: None, 150 - ) 151 - write_page(page) 152 - } 153 - 154 - fn write_page(page: Page) -> snag.Result(Nil) { 155 - let path = public <> page.path 156 - use _ <- result.try( 157 - simplifile.create_directory_all(path) 158 - |> file_error("Failed to make " <> path), 159 - ) 160 - 161 - let path = path <> "/index.html" 162 - simplifile.write(to: path, contents: page_html(page)) 163 - |> file_error("Failed to write page " <> path) 164 - } 165 - 166 - fn add_previous_next( 167 - rest: List(Page), 168 - acc: List(Page), 169 - previous: Option(String), 170 - ) -> List(Page) { 171 - case rest { 172 - [] -> list.reverse(acc) 173 - [page, next, ..rest] -> { 174 - let page = Page(..page, previous: previous, next: Some(next.path)) 175 - add_previous_next([next, ..rest], [page, ..acc], Some(page.path)) 176 - } 177 - [page, ..rest] -> { 178 - let page = Page(..page, previous: previous, next: None) 179 - add_previous_next(rest, [page, ..acc], Some(page.path)) 180 - } 181 - } 182 - } 183 - 184 - fn copy_wasm_compiler() -> snag.Result(Nil) { 185 - use <- require( 186 - simplifile.is_directory(compiler_wasm), 187 - "compiler-wasm/pkg must have been compiled", 188 - ) 189 - 190 - simplifile.copy_directory(compiler_wasm, public <> "/compiler") 191 - |> file_error("Failed to copy compiler-wasm") 192 - } 193 - 194 - fn make_prelude_available() -> snag.Result(Nil) { 195 - use _ <- result.try( 196 - simplifile.create_directory_all(public_precompiled) 197 - |> file_error("Failed to make " <> public_precompiled), 198 - ) 199 - 200 - simplifile.copy_file(prelude, public_precompiled <> "/gleam.mjs") 201 - |> file_error("Failed to copy prelude.mjs") 202 - } 203 - 204 - fn make_stdlib_available() -> snag.Result(Nil) { 205 - use files <- result.try( 206 - simplifile.read_directory(stdlib_sources) 207 - |> file_error("Failed to read stdlib directory"), 208 - ) 209 - 210 - let modules = 211 - files 212 - |> list.filter(fn(file) { string.ends_with(file, ".gleam") }) 213 - |> list.filter(fn(file) { !list.contains(skipped_stdlib_modules, file) }) 214 - |> list.map(string.replace(_, ".gleam", "")) 215 - 216 - use _ <- result.try( 217 - generate_stdlib_bundle(modules) 218 - |> snag.context("Failed to generate stdlib.js bundle"), 219 - ) 220 - 221 - use _ <- result.try( 222 - copy_compiled_stdlib(modules) 223 - |> snag.context("Failed to copy precompiled stdlib modules"), 224 - ) 225 - 226 - use _ <- result.try( 227 - copy_stdlib_externals() 228 - |> snag.context("Failed to copy stdlib external files"), 229 - ) 230 - 231 - Ok(Nil) 232 - } 233 - 234 - fn copy_stdlib_externals() -> snag.Result(Nil) { 235 - use files <- result.try( 236 - simplifile.read_directory(stdlib_external) 237 - |> file_error("Failed to read stdlib external directory"), 238 - ) 239 - let files = list.filter(files, string.ends_with(_, ".mjs")) 240 - 241 - list.try_each(files, fn(file) { 242 - let from = stdlib_external <> "/" <> file 243 - let to = public_precompiled <> "/" <> file 244 - simplifile.copy_file(from, to) 245 - |> file_error("Failed to copy stdlib external file " <> from) 246 - }) 247 - } 248 - 249 - fn copy_compiled_stdlib(modules: List(String)) -> snag.Result(Nil) { 250 - use <- require( 251 - simplifile.is_directory(stdlib_compiled), 252 - "Project must have been compiled for JavaScript", 253 - ) 254 - 255 - let dest = public_precompiled <> "/gleam" 256 - use _ <- result.try( 257 - simplifile.create_directory_all(dest) 258 - |> file_error("Failed to make " <> dest), 259 - ) 260 - 261 - use _ <- result.try(list.try_each(modules, fn(name) { 262 - let from = stdlib_compiled <> "/" <> name <> ".mjs" 263 - let to = dest <> "/" <> name <> ".mjs" 264 - simplifile.copy_file(from, to) 265 - |> file_error("Failed to copy stdlib module " <> from) 266 - })) 267 - 268 - Ok(Nil) 269 - } 270 - 271 - fn generate_stdlib_bundle(modules: List(String)) -> snag.Result(Nil) { 272 - use entries <- result.try(list.try_map(modules, fn(name) { 273 - let path = stdlib_sources <> "/" <> name <> ".gleam" 274 - use code <- result.try( 275 - simplifile.read(path) 276 - |> file_error("Failed to read stdlib module " <> path), 277 - ) 278 - let name = string.replace(name, ".gleam", "") 279 - let code = 280 - code 281 - |> string.replace("\\", "\\\\") 282 - |> string.replace("`", "\\`") 283 - |> string.split("\n") 284 - |> list.filter(fn(line) { !string.starts_with(string.trim(line), "//") }) 285 - |> list.filter(fn(line) { !string.starts_with(line, "@external(erlang") }) 286 - |> list.filter(fn(line) { line != "" }) 287 - |> string.join("\n") 288 - 289 - Ok(" \"gleam/" <> name <> "\": `" <> code <> "`") 290 - })) 291 - 292 - entries 293 - |> string.join(",\n") 294 - |> string.append("export default {\n", _) 295 - |> string.append("\n}\n") 296 - |> simplifile.write(public <> "/stdlib.js", _) 297 - |> file_error("Failed to write stdlib.js") 298 - } 299 - 300 - fn reset_output() -> snag.Result(Nil) { 301 - use _ <- result.try( 302 - simplifile.create_directory_all(public) 303 - |> file_error("Failed to delete public directory"), 304 - ) 305 - 306 - use files <- result.try( 307 - simplifile.read_directory(public) 308 - |> file_error("Failed to read public directory"), 309 - ) 310 - 311 - use _ <- result.try( 312 - files 313 - |> list.map(string.append(public <> "/", _)) 314 - |> simplifile.delete_all 315 - |> file_error("Failed to delete public directory"), 316 - ) 317 - 318 - simplifile.copy_directory(static, public) 319 - |> file_error("Failed to copy static directory") 320 - } 321 - 322 - fn require( 323 - that condition: Bool, 324 - because reason: String, 325 - then next: fn() -> snag.Result(t), 326 - ) -> snag.Result(t) { 327 - case condition { 328 - True -> next() 329 - False -> Error(snag.new(reason)) 330 - } 331 - } 332 - 333 - fn file_error( 334 - result: Result(t, simplifile.FileError), 335 - context: String, 336 - ) -> snag.Result(t) { 337 - case result { 338 - Ok(value) -> Ok(value) 339 - Error(error) -> 340 - snag.error("File error: " <> string.inspect(error)) 341 - |> snag.context(context) 342 - } 343 - } 344 - 345 - fn page_html(page: Page) -> String { 346 - let navlink = fn(name, link) { 347 - case link { 348 - None -> h("span", [], [text(name)]) 349 - Some(path) -> h("a", [#("href", path)], [text(name)]) 350 - } 351 - } 352 - 353 - h("html", [#("lang", "en-gb")], [ 354 - h("head", [], [ 355 - h("meta", [#("charset", "utf-8")], []), 356 - h( 357 - "meta", 358 - [ 359 - #("name", "viewport"), 360 - #("content", "width=device-width, initial-scale=1"), 361 - ], 362 - [], 363 - ), 364 - h("title", [], [text("Try Gleam")]), 365 - h("link", [#("rel", "stylesheet"), #("href", "/style.css")], []), 366 - ]), 367 - h("body", [], [ 368 - h("nav", [#("class", "navbar")], [ 369 - h("a", [#("href", "/")], [text("Try Gleam")]), 370 - ]), 371 - h("article", [#("class", "playground")], [ 372 - h("section", [#("id", "text")], [ 373 - htmb.dangerous_unescaped_fragment( 374 - string_builder.from_string(page.text), 375 - ), 376 - h("nav", [#("class", "prev-next")], [ 377 - navlink("Back", page.previous), 378 - text(" — "), 379 - h("a", [#("href", "/index")], [text("Index")]), 380 - text(" — "), 381 - navlink("Next", page.next), 382 - ]), 383 - ]), 384 - h("section", [#("id", "editor")], [ 385 - h("div", [#("id", "editor-target")], []), 386 - ]), 387 - h("aside", [#("id", "output")], []), 388 - ]), 389 - h("script", [#("type", "gleam"), #("id", "code")], [ 390 - htmb.dangerous_unescaped_fragment(string_builder.from_string(page.code)), 391 - ]), 392 - h("script", [#("type", "module"), #("src", "/index.js")], []), 393 - ]), 394 - ]) 395 - |> htmb.render_page("html") 396 - |> string_builder.to_string 397 - }
-90
try-gleam/static/compiler.js
··· 1 - let compiler; 2 - 3 - export default async function initGleamCompiler() { 4 - const wasm = await import("/compiler/gleam_wasm.js"); 5 - await wasm.default(); 6 - wasm.initialise_panic_hook(); 7 - if (!compiler) { 8 - compiler = new Compiler(wasm); 9 - } 10 - return compiler; 11 - } 12 - 13 - class Compiler { 14 - #wasm; 15 - #nextId = 0; 16 - #projects = new Map(); 17 - 18 - constructor(wasm) { 19 - this.#wasm = wasm; 20 - } 21 - 22 - get wasm() { 23 - return this.#wasm; 24 - } 25 - 26 - newProject() { 27 - const id = this.#nextId++; 28 - const project = new Project(id); 29 - this.#projects.set(id, new WeakRef(project)); 30 - return project; 31 - } 32 - 33 - garbageCollectProjects() { 34 - const gone = []; 35 - for (const [id, project] of this.#projects) { 36 - if (!project.deref()) gone.push(id); 37 - } 38 - for (const id of gone) { 39 - this.#projects.delete(id); 40 - this.#wasm.delete_project(id); 41 - } 42 - } 43 - } 44 - 45 - class Project { 46 - #id; 47 - 48 - constructor(id) { 49 - this.#id = id; 50 - } 51 - 52 - get projectId() { 53 - return this.#id; 54 - } 55 - 56 - writeModule(moduleName, code) { 57 - compiler.wasm.write_module(this.#id, moduleName, code); 58 - } 59 - 60 - compilePackage(target) { 61 - compiler.garbageCollectProjects(); 62 - compiler.wasm.reset_warnings(this.#id); 63 - compiler.wasm.compile_package(this.#id, target); 64 - } 65 - 66 - readCompiledJavaScript(moduleName) { 67 - return compiler.wasm.read_compiled_javascript(this.#id, moduleName); 68 - } 69 - 70 - readCompiledErlang(moduleName) { 71 - return compiler.wasm.read_compiled_erlang(this.#id, moduleName); 72 - } 73 - 74 - resetFilesystem() { 75 - compiler.wasm.reset_filesystem(this.#id); 76 - } 77 - 78 - delete() { 79 - compiler.wasm.delete_project(this.#id); 80 - } 81 - 82 - takeWarnings() { 83 - const warnings = []; 84 - while (true) { 85 - const warning = compiler.wasm.pop_warning(this.#id); 86 - if (!warning) return warnings; 87 - warnings.push(warning.trimStart()); 88 - } 89 - } 90 - }
-126
try-gleam/static/index.js
··· 1 - import CodeFlask from "https://cdn.jsdelivr.net/npm/codeflask@1.4.1/+esm"; 2 - import initGleamCompiler from "./compiler.js"; 3 - import stdlib from "./stdlib.js"; 4 - 5 - const output = document.querySelector("#output"); 6 - const initialCode = document.querySelector("#code").innerHTML; 7 - 8 - const prismGrammar = { 9 - comment: { 10 - pattern: /\/\/.*/, 11 - greedy: true, 12 - }, 13 - function: /([a-z_][a-z0-9_]+)(?=\()/, 14 - keyword: 15 - /\b(use|case|if|external|fn|import|let|assert|try|pub|type|opaque|const|todo|as)\b/, 16 - symbol: { 17 - pattern: /([A-Z][A-Za-z0-9_]+)/, 18 - greedy: true, 19 - }, 20 - operator: { 21 - pattern: 22 - /(<<|>>|<-|->|\|>|<>|\.\.|<=\.?|>=\.?|==\.?|!=\.?|<\.?|>\.?|&&|\|\||\+\.?|-\.?|\/\.?|\*\.?|%\.?|=)/, 23 - greedy: true, 24 - }, 25 - string: { 26 - pattern: /"(?:\\(?:\r\n|[\s\S])|(?!")[^\\\r\n])*"/, 27 - greedy: true, 28 - }, 29 - module: { 30 - pattern: /([a-z][a-z0-9_]*)\./, 31 - inside: { 32 - punctuation: /\./, 33 - }, 34 - alias: "keyword", 35 - }, 36 - punctuation: /[.\\:,{}()]/, 37 - number: 38 - /\b(?:0b[0-1]+|0o[0-7]+|[[:digit:]][[:digit:]_]*(\\.[[:digit:]]*)?|0x[[:xdigit:]]+)\b/, 39 - }; 40 - 41 - // Monkey patch console.log to keep a copy of the output 42 - let logged = ""; 43 - const log = console.log; 44 - console.log = (...args) => { 45 - log(...args); 46 - logged += args.map((e) => `${e}`).join(" ") + "\n"; 47 - }; 48 - 49 - function resetLogCapture() { 50 - logged = ""; 51 - } 52 - 53 - async function compileEval(project, code) { 54 - try { 55 - project.writeModule("main", code); 56 - project.compilePackage("javascript"); 57 - const js = project.readCompiledJavaScript("main"); 58 - const main = await loadProgram(js); 59 - resetLogCapture(); 60 - if (main) main(); 61 - replaceOutput(logged, "log"); 62 - } catch (error) { 63 - console.error(error); 64 - replaceOutput(error.toString(), "error"); 65 - } 66 - for (const warning of project.takeWarnings()) { 67 - appendOutput(warning, "warning"); 68 - } 69 - } 70 - 71 - async function loadProgram(js) { 72 - const url = new URL(import.meta.url); 73 - url.pathname = ""; 74 - url.hash = ""; 75 - url.search = ""; 76 - const href = url.toString(); 77 - const js1 = js.replaceAll( 78 - /from\s+"\.\/(.+)"/g, 79 - `from "${href}precompiled/$1"` 80 - ); 81 - const js2 = btoa(unescape(encodeURIComponent(js1))); 82 - const module = await import("data:text/javascript;base64," + js2); 83 - return module.main; 84 - } 85 - 86 - function clearOutput() { 87 - while (output.firstChild) { 88 - output.removeChild(output.firstChild); 89 - } 90 - } 91 - 92 - function replaceOutput(content, className) { 93 - clearOutput(); 94 - appendOutput(content, className); 95 - } 96 - 97 - function appendOutput(content, className) { 98 - if (!content) return; 99 - const element = document.createElement("pre"); 100 - element.textContent = content; 101 - element.className = className; 102 - output.appendChild(element); 103 - } 104 - 105 - const editor = new CodeFlask("#editor-target", { 106 - language: "gleam", 107 - }); 108 - editor.addLanguage("gleam", prismGrammar); 109 - editor.updateCode(initialCode); 110 - 111 - const compiler = await initGleamCompiler(); 112 - const project = compiler.newProject(); 113 - for (const [name, code] of Object.entries(stdlib)) { 114 - project.writeModule(name, code); 115 - } 116 - 117 - function debounce(fn, delay) { 118 - let timer = null; 119 - return (...args) => { 120 - clearTimeout(timer); 121 - timer = setTimeout(() => fn(...args), delay); 122 - }; 123 - } 124 - 125 - editor.onUpdate(debounce((code) => compileEval(project, code), 200)); 126 - compileEval(project, initialCode);
-174
try-gleam/static/style.css
··· 1 - @font-face { 2 - font-family: "Lexend"; 3 - font-display: swap; 4 - font-weight: 400; 5 - src: url("https://gleam.run/fonts/Lexend.woff2") format("woff2"); 6 - } 7 - 8 - @font-face { 9 - font-family: "Lexend"; 10 - font-display: swap; 11 - font-weight: 700; 12 - src: url("https://gleam.run/fonts/Lexend-700.woff2") format("woff2"); 13 - } 14 - 15 - @font-face { 16 - font-family: "Outfit"; 17 - font-display: swap; 18 - src: url("https://gleam.run/fonts/Outfit.woff") format("woff"); 19 - } 20 - 21 - :root { 22 - --font-family-normal: "Outfit", sans-serif; 23 - --font-family-title: "Lexend", sans-serif; 24 - 25 - --color-pink: #ffaff3; 26 - --color-red: #ff6262; 27 - --color-orange: #ffd596; 28 - --color-green: #c8ffa7; 29 - --gap: 12px; 30 - } 31 - 32 - * { 33 - box-sizing: border-box; 34 - } 35 - 36 - body { 37 - margin: 0; 38 - padding: 0; 39 - height: 100vh; 40 - display: flex; 41 - flex-direction: column; 42 - font-family: var(--font-family-normal); 43 - letter-spacing: 0.01em; 44 - line-height: 1.3; 45 - } 46 - 47 - codeflask__textarea, 48 - pre, 49 - code { 50 - font-weight: normal; 51 - letter-spacing: initial; 52 - } 53 - 54 - p code { 55 - padding: 1px 2px; 56 - background-color: #f5f5f5; 57 - } 58 - 59 - h1, 60 - h2, 61 - h3, 62 - h4, 63 - h5, 64 - h6 { 65 - font-family: var(--font-family-title); 66 - font-weight: normal; 67 - } 68 - 69 - .navbar { 70 - display: flex; 71 - justify-content: space-between; 72 - align-items: center; 73 - padding: var(--gap); 74 - background-color: var(--color-pink); 75 - } 76 - 77 - .navbar a:visited, 78 - .navbar a { 79 - text-decoration: none; 80 - color: #000; 81 - } 82 - 83 - .playground { 84 - display: flex; 85 - flex-direction: column; 86 - flex-wrap: wrap; 87 - flex: auto; 88 - max-width: 100vw; 89 - } 90 - 91 - #text { 92 - flex: 1; 93 - } 94 - 95 - #text > :first-child { 96 - margin-top: 0; 97 - } 98 - 99 - #editor { 100 - flex: 1; 101 - position: relative; 102 - } 103 - 104 - #output { 105 - flex: 1; 106 - } 107 - 108 - @media (min-width: 600px) { 109 - #text, 110 - #output, 111 - #editor { 112 - width: 50vw; 113 - } 114 - #text { 115 - flex-basis: 100%; 116 - border-right: 2px solid var(--color-pink); 117 - } 118 - #editor { 119 - flex: 1.62; 120 - } 121 - #output, 122 - #editor { 123 - max-height: 50vh; 124 - } 125 - } 126 - 127 - #text, 128 - #output > *, 129 - #editor .codeflask__flatten { 130 - padding: var(--gap); 131 - } 132 - 133 - #text, 134 - #output, 135 - #editor { 136 - min-width: 50%; 137 - max-width: 100%; 138 - overflow-y: auto; 139 - border-bottom: 2px solid var(--color-pink); 140 - margin: 0; 141 - overflow-wrap: break-word; 142 - } 143 - 144 - #output > * { 145 - margin: 0; 146 - white-space: pre-wrap; 147 - } 148 - 149 - .error, 150 - .warning { 151 - border: var(--gap) solid var(--border-color); 152 - border-top: 0; 153 - border-bottom: 0; 154 - } 155 - 156 - .error { 157 - --border-color: var(--color-red); 158 - } 159 - 160 - .warning { 161 - --border-color: var(--color-orange); 162 - } 163 - 164 - .prev-next { 165 - display: flex; 166 - justify-content: center; 167 - align-items: center; 168 - padding: 0 var(--gap); 169 - gap: 0.5em; 170 - } 171 - 172 - .prev-next span { 173 - opacity: 0.5; 174 - }
-12
try-gleam/test/playground_test.gleam
··· 1 - import gleeunit 2 - import gleeunit/should 3 - 4 - pub fn main() { 5 - gleeunit.main() 6 - } 7 - 8 - // gleeunit test functions end in `_test` 9 - pub fn hello_world_test() { 10 - 1 11 - |> should.equal(1) 12 - }