# Syntax https://tour.gleam.run/everything/ ## Comments - `//` - [Documentation](https://tour.gleam.run/functions/documentation-comments/) - `///` is for documenting types and functions and comes before the subject - `////` is for documenting modules and comes at the top of the module ## `import` https://tour.gleam.run/basics/unqualified-imports/ - `import <path>` - Unqualified imports are done via `import <path>.{<stuff>}` - Need to use `type` for any types that are imported (this does not apply to variants of types!) - Put one's own code in a [`<packagename>.gleam` and/or `src/<packagename>/` directory](https://gleam.run/writing-gleam/) - Can import from each other as appropriate - [For anything not meant for public consumption but needs to be public for testing](https://gleam.run/writing-gleam/), put in a `src/<packagename>/internal` directory ## Equality https://tour.gleam.run/basics/equality/ - `==` - `!=` ## `Int` https://tour.gleam.run/basics/ints/ ### Arithmetic - `+` - `-` - `/` - `*` - `%` ### Comparisons - `>` - `<` - `>=` - `<=` ### Format Can use `_` as a separator. #### Prefixes - `0b` - `0o` - `0x` ## `Float` https://tour.gleam.run/basics/floats/ ### Arithmetic - `+.` - `-.` - `/.` - `*.` ### Comparisons - `>.` - `<.` - `>=.` - `<=.` ### Format Can use `_` as a separator. Scientific notation via `<base>e<power>` ## `String` https://tour.gleam.run/basics/strings/ ### Operators - `<>` for concatenation ### Format - `"<content>"` - `\"` - `\\` - `\f` - `\n` - `\r` - `\t` - `\us{<codepoint>}` ## `Bool` https://tour.gleam.run/basics/bools/ ### Format - `True` - `False` ### Operators - `||` (short-circuits) - `&&` (short-circuits) - `!` ## Assignment https://tour.gleam.run/basics/assignments/ - `let <snake_case> = <assign>` (immutable) - `_<name>` for discarding - `let <snake_case>: <type> = <assign>` for explicit type annotation - Destructuring in the assignment is allowed - You can rebind to the same name - `let assert <pattern> = <expression>` will [crash the program if the pattern doesn't match](https://tour.gleam.run/advanced-features/let-assert/) ## Blocks https://tour.gleam.run/basics/blocks/ - `{expressions}` creates a new scope and are evaluated earlier than operators (i.e. used over parentheses as in other languages) ## `List` https://tour.gleam.run/basics/lists/ - `[<items>]` separated by commas (a trailing comma is okay) - `[<items>, ..<variable>]` to (immutably) prepend - Single-linked list ## `const` https://tour.gleam.run/basics/constants/ - `const <literal>` at the module scope ## `fn` https://tour.gleam.run/functions/functions/ - `fn <name>(<param>: <type>) -> <return type> { <body> }`; type annotations on parameters and the return type are optional - The last expression is the return value - Prefix `pub` to make a function public - `fn(<params>)` is for declaring [anonymous functions](https://tour.gleam.run/functions/anonymous-functions/); syntax is otherwise the same as named functions - Typing functions is the same as the anonymous function syntax - `<name>(<params>, _, <params>)` is for [function captures](https://tour.gleam.run/functions/function-captures/) - Shorthand for `fn(a) {<name>(<params>, a, <params>)}` - Only works for a single argument to the capture - [Generics](https://tour.gleam.run/functions/generic-functions/) is supported by using a lowercase name for a type annotation, e.g. `fn spam(x: type_, y: type_) -> type_ { ... }` - [Pipelining](https://tour.gleam.run/functions/pipelines/) is done with `<subject> |> <target>` - If the subject can be used as the first argument to the target then it will be used that way, e.g. the `a |> b()` becomes `b(a)` - Otherwise it translates to an argument to whatever the target returns, e.g. `a |> b()` becomes `b()(a)` - Use function captures if the subject needs to be passed to a parameter other than the first one - To make it easier to pipeline with a function, the "subject" of a function call is specified first - [Labelled arguments](https://tour.gleam.run/functions/labelled-arguments/) allows passing a parameter by name w/ the syntax `<name>: <param>` - Using the names is optional - You can use the same name for both the outer and inner name - Unnamed parameters must come first - There is no performance impact - Shorthand -- as of 1.4 -- is `<var>:` to use the variable of the same name as the label ## `@deprecated` https://tour.gleam.run/functions/deprecations ```gleam @deprecated(<reason>) fn ... ``` ## `case` https://tour.gleam.run/flow-control/case-expressions/ ```gleam case <expression> { <pattern> -> <expression> _ -> <expression> } ``` - Can use [variable patterns](https://tour.gleam.run/flow-control/variable-patterns/) to assign in the pattern itself; `<variable> -> <expression>` - `<pattern> as <variable>` specifies a [pattern alias](https://tour.gleam.run/flow-control/pattern-aliases/) - [String patterns](https://tour.gleam.run/flow-control/string-patterns/) allow for matching by prefix; `<prefix> <> <variable>` - [List patterns](https://tour.gleam.run/flow-control/list-patterns/) - `[]` is empty - Use `_` to represent any item, e.g. `[_, _]` is a list of two items - You can use literals in any position - The spread pattern `..` matches the rest of a list - You can have [multiple subjects](https://tour.gleam.run/flow-control/multiple-subjects/), separated by commas: `case <subject 1>, <subject 2 { <match subject 1>, <match subject 2> -> <expression> }` - `|` for [alternative patterns](https://tour.gleam.run/flow-control/alternative-patterns/) - If variable names are used then they must be the same name in all alternatives - You can't nest an alternative pattern - `<pattern> if <clause>` for a [guard](https://tour.gleam.run/flow-control/guards/) ## Tuples https://tour.gleam.run/data-types/tuples/ - `#(<items>)` for creating - `<variable>.<index>` to access elements ## `type` ### Type Aliases https://tour.gleam.run/basics/type-aliases/ - `type <CapWords>` - `pub type <CapWords>` for a public name - To [[#`import` |import]] a type unqualified, the name needs to be prefixed with `type`, e.g. `import gleam/option.{type Option}` - Variants of types must be imported as normal, e.g., `gleam/option.{Some}` ### Custom types https://tour.gleam.run/data-types/custom-types/ - `type <Name> { <Variants> }` - Enum-like, i.e. defining constructor for a variant - Name and variants are CapWords - Variant names are **not** scoped, and so are exposed as a top-level name - The type name is just that: a name of the type - While the variants are like defining unique names that happen to a type in common - If there's only a single variant then you can reuse the type name for the variant #### Records - Define a [record](https://tour.gleam.run/data-types/records/) variant by listing the fields, e.g. `<Name>(<fields>)` - If you specify a field name then it acts as an argument label - Label shorthand works - Otherwise just specify the type - If you define the same argument label on all variants with the same type, then you can use a [record accessor](https://tour.gleam.run/data-types/record-accessors/) via `<var>.<name>` - [Record updates](https://tour.gleam.run/data-types/record-updates/) create a copy of a record with different values via `..<var>` as the first argument to the constructor, i.e. `<Name>(..<record>, <items>)` - Must come **first** in the list of arguments to the constructor - Custom types can be [generic](https://tour.gleam.run/data-types/generic-custom-types/) by specifying the type variable by the name, i.e. `<Name>(<TypeVars>) { <variants> }` - An [external type](https://tour.gleam.run/advanced-features/externals/) has no constructor (i.e. body), making the shape private/hidden/unknown for use with [[#`@external`]] ## `Nil` https://tour.gleam.run/data-types/nil/ - Both a type and value - Returned by functions that return nothing - Because it is a type it cannot be used as a value with any other type ## `Result` https://tour.gleam.run/data-types/results/ ```gleam pub type Result(ok, error) { Ok(ok) Error(error) } ``` - Due to the lack of inheritance or interfaces, the error type is completely generic - It is universally used as a function return type even when [`gleam/option.{type Option}`](https://hexdocs.pm/gleam_stdlib/gleam/option.html#Option) makes sense - "[The Option type should only be used for taking optional values as function arguments, or for storing them in other data structures.](https://hexdocs.pm/gleam_stdlib/gleam/option.html)" - Use `Nil` as the error condition (thanks to to the error type being generic) ## `BitArray` https://tour.gleam.run/data-types/bit-arrays/ - `<<>>` surrounds the segments (there can be 0 or more) - Each segment can have options - Specified via `:<option>` after the value - Possible options are: - `size` - `unit` - `bits` - `bytes` - `float` - `int` - `big` - `little` - `native` - `signed` - `unsigned` - `utf8` - `utf16` - `utf32` - `utf8_codepoint` - `utf16_codepoint` - `utf32_codepoint` ## `use` https://tour.gleam.run/advanced-features/use/ ```gleam use <argument names> = <function>(<args>) <callback> ``` [translates to](https://tour.gleam.run/advanced-features/use-sugar/) `<function>(<args>, fn(<argument names>) {<callback})` - Can chain them when you are nesting calls with callbacks - Somewhat like pipelining but for callbacks as the last argument to the function call and outside-in instead of inside-out ## `todo` https://tour.gleam.run/advanced-features/todo/ - `todo` has the compiler warn and the runtime raise an error - `todo as "<message>"` includes the message in the warning/error ## `panic` https://tour.gleam.run/advanced-features/panic/ - `panic` to error out the program - `panic as "<message>"` ## `@external` https://tour.gleam.run/advanced-features/externals/ ```gleam @external(<language>, <file path>, <function name>) fn <function name>(<args>) -> <return type> ``` - The return type needs to be an external [[#`type` |type]] - You can specify [multiple targets](https://tour.gleam.run/advanced-features/multi-target-externals/) to implement the function - A [fallback](https://tour.gleam.run/advanced-features/external-gleam-fallbacks/) written in Gleam can be provided by implementing a function body # JavaScript There's support for [JS as an FFI](https://gleam.run/book/tour/external-functions.html) along with a [prelude](https://github.com/gleam-lang/gleam/blob/main/compiler-core/templates/prelude.mjs) (available as `gleam.mjs` in your project; might need to [export it](https://gleam.run/writing-gleam/command-line-reference/)). [gleam_javascript](https://hexdocs.pm/gleam_javascript/) can be used to "work with JavaScript types and values in Gleam" and as example code for how to wrap things. # Appendix ## Tokens [Parser](https://github.com/gleam-lang/gleam/blob/7eaad191566107784495ba41a4550f1bdf618311/compiler-core/src/parse/token.rs) after the [1.0 announcement](https://gleam.run/news/gleam-version-1/). ```Rust use std::fmt; use ecow::EcoString; #[derive(Clone, Debug, PartialEq, Eq)] pub enum Token { Name { name: EcoString }, UpName { name: EcoString }, DiscardName { name: EcoString }, Int { value: EcoString }, Float { value: EcoString }, String { value: EcoString }, CommentDoc { content: String }, // Groupings LeftParen, // ( RightParen, // ) LeftSquare, // [ RightSquare, // } LeftBrace, // { RightBrace, // } // Int Operators Plus, Minus, Star, Slash, Less, Greater, LessEqual, GreaterEqual, Percent, // Float Operators PlusDot, // '+.' MinusDot, // '-.' StarDot, // '*.' SlashDot, // '/.' LessDot, // '<.' GreaterDot, // '>.' LessEqualDot, // '<=.' GreaterEqualDot, // '>=.' // String Operators LtGt, // '<>' // Other Punctuation Colon, Comma, Hash, // '#' Bang, // '!' Equal, EqualEqual, // '==' NotEqual, // '!=' Vbar, // '|' VbarVbar, // '||' AmperAmper, // '&&' LtLt, // '<<' GtGt, // '>>' Pipe, // '|>' Dot, // '.' RArrow, // '->' LArrow, // '<-' DotDot, // '..' At, // '@' EndOfFile, // Extra CommentNormal, CommentModule, EmptyLine, // Keywords (alphabetically): As, Assert, Auto, Case, Const, Delegate, Derive, Echo, Else, Fn, If, Implement, Import, Let, Macro, Opaque, Panic, Pub, Test, Todo, Type, Use, } impl Token { pub fn guard_precedence(&self) -> Option<u8> { match self { Self::VbarVbar => Some(1), Self::AmperAmper => Some(2), Self::EqualEqual | Self::NotEqual => Some(3), Self::Less | Self::LessEqual | Self::LessDot | Self::LessEqualDot | Self::GreaterEqual | Self::Greater | Self::GreaterEqualDot | Self::GreaterDot => Some(4), _ => None, } } } impl fmt::Display for Token { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = match self { Token::Name { name } | Token::UpName { name } | Token::DiscardName { name } => { name.as_str() } Token::Int { value } | Token::Float { value } | Token::String { value } => { value.as_str() } Token::AmperAmper => "&&", Token::As => "as", Token::Assert => "assert", Token::At => "@", Token::Auto => "auto", Token::Bang => "!", Token::Case => "case", Token::Colon => ":", Token::Comma => ",", Token::CommentDoc { .. } => "///", Token::CommentModule => "////", Token::CommentNormal => "//", Token::Const => "const", Token::Delegate => "delegate", Token::Derive => "derive", Token::Dot => ".", Token::DotDot => "..", Token::Echo => "echo", Token::Else => "else", Token::EmptyLine => "EMPTYLINE", Token::EndOfFile => "EOF", Token::Equal => "=", Token::EqualEqual => "==", Token::Fn => "fn", Token::Greater => ">", Token::GreaterDot => ">.", Token::GreaterEqual => ">=", Token::GreaterEqualDot => ">=.", Token::GtGt => ">>", Token::Hash => "#", Token::If => "if", Token::Implement => "implement", Token::Import => "import", Token::LArrow => "<-", Token::LeftBrace => "{", Token::LeftParen => "(", Token::LeftSquare => "[", Token::Less => "<", Token::LessDot => "<.", Token::LessEqual => "<=", Token::LessEqualDot => "<=.", Token::Let => "let", Token::LtGt => "<>", Token::LtLt => "<<", Token::Macro => "macro", Token::Minus => "-", Token::MinusDot => "-.", Token::NotEqual => "!=", Token::Opaque => "opaque", Token::Panic => "panic", Token::Percent => "%", Token::Pipe => "|>", Token::Plus => "+", Token::PlusDot => "+.", Token::Pub => "pub", Token::RArrow => "->", Token::RightBrace => "}", Token::RightParen => ")", Token::RightSquare => "]", Token::Slash => "/", Token::SlashDot => "/.", Token::Star => "*", Token::StarDot => "*.", Token::Test => "test", Token::Todo => "todo", Token::Type => "type", Token::Use => "use", Token::Vbar => "|", Token::VbarVbar => "||", }; write!(f, "\"{s}\"") } } ```