# Ava R2 This document specifies the second revision of the Ava programming language, started 2024-07-18. ## Table of Contents - [Names](#names) - [Reserved Keywords](#reserved-keywords) - [Reserved Symbols and Operators](#reserved-symbols-and-operators) - [Namespaces](#namespaces) - [Imports](#imports) - [Definitions](#definitions) - [Comments](#comments) - [Constants](#constants) ## Names _Names_ in Ava source code are user-defined strings that provide some form of identifier to some component that may be named. All names in Ava follow the same rules. ### Name Rules - Names are UTF-8 strings. - Names may **not** be a reserved keyword. - Names may **not** be a reserved symbol/operator. - Names may **not** include whitespace characters. - Names may **not** include `.` - Names may **not** include `"` - Names may **not** include `'` - Names may **not** include `,` - Names may **not** include `:` - Names may **not** include `\` - Names may **not** include `(` - Names may **not** include `)` - Names may **not** begin with a number. - Two definitions may **not** share the same name in scope. - This implies that names may **not** reuse the name of any standard type that is always considered in scope, such as `Int32` or `Boolean`. ### Name Targets The following items may be named in Ava: - [Namespaces](#namespaces) - [Definitions](#definitions) - [Variables](#variables) - [Function Arguments](#function-arguments) - [Record Fields](#record-fields) - [Destructured Fields](#destructured-fields) ### Name Examples - `foo` - `foo-bar` - `foo_bar` - `<=` - `>` - `==` - `%` - `f1` - `_foo` - `&&` - `||` ## Reserved Keywords ### `namespace` Used to specify the [Namespace](#namespaces) of a file. ### `import` Used to declare an [Import](#imports) within a file. ### `private` Used to mark a [Definition](#definitions) as [Private](#private-accessibility). ### `internal` Used to mark a [Definition](#definitions) as [Internal](#internal-accessibility). ### `let` Declares an immutable [Variable](#variables) binding. ### `mut` Declares a mutable [Variable](#variables) binding. ### `const` Declares a [Constant](#constants) definition. ### `given` Used to define [type constructors](#type-constructors) within the scope of some definition. ### `fn` Indicates a [function](#functions) definition. Each function may or may not be implemented. ### `class` Indicates a [type class](#type-classes) definition. ### `instance` Indicates the definition of a specific [type class instance](#type-class-instances). ### `match` Keyword that identifies a [match expression](#match-expressions). ### `λ` Alias for the [case](#case) keyword. ### `case` Defines a [pattern matching](#pattern-matching) case within some pattern matching context (either a function implementation or a match expression). ### `end` Used to indicate the end of some block. ### `type` Declare a [type definition](#type-definitions). ### `opaque` Declare an [opaque type](#opaque-types). ### `record` Define a [record](#records) (immutable data structure). ### `enum` Define a new [enumeration](#enumerations) (sum type). ### `as` Used to rename a specific [import](#imports). ### `if` Denotes an [if/then/else expression](#if-then-else-expressions). ### `then` Required after the predicate of an [if/then/else expression](#if-then-else-expressions). ### `else` Required after the first block of an [if/then/else expression](#if-then-else-expressions). ### `true` The Boolean value `true`. ### `false` The Boolean value `false`. ### `object` Define a [singleton object](#singleton-objects). ### MISSING SOME VALUES TODO: Things like `do`/`return`, `infix`, `const` TODO: Consider `abstract` to be used for abstract type class functions. ## Reserved Symbols and Operators ### `.` (Access Operator) ### `=` (Assignment Operator) ### `:` (Type Assignment Operator) ### `::` (Type Class Membership Operator) ### `(` (Open Parenthesis) ### `)` (Close Parenthesis) ### `,` (Comma) ### `=>` (Case Implementation Operator) ### `->` (Type Function Operator) ### `_` (Anonymous Value Binding) ### `|` (Type Union Operator) ### `--` (Comment Prefix) ## Namespaces The primary organizational concept in Ava is the _namespace_. Namespaces must be explicitly declared in _every_ Ava file. ### Rules - Every Ava source file _must_ begin with a `namespace` declaration. - The first non-comment code in any Ava source file _must_ be a `namespace` declaration. - Namespaces must contain at least one [name](#names). - Namespaces may concatenate names using the `.` character. - Multiple files may share the same namespace. - Namespaces are **public** by default. This means that if any [definition](#definition) is not marked [private](#definition-accessibility) or [internal](#definition-accessibility), all definitions will be exported. ### Syntax Specification ``` namespace [.]* ``` ### Syntax Examples ``` namespace foo namespace foo.bar namespace foo.bar.baz_buzz namespace foo.bar.v0 ``` ## Imports An `import` can be used to pull other namespaces, or [definitions](#definitions) from other namespaces, into the current scope. ### Rules - Imports **must** follow the [namespace](#namespaces) declaration. - Imports may **not** be placed after any definition. - Glob imports may **not** use `as` to rename (since they have no specific target to rename). ### Syntax Specification ``` import [.]*[.\* | as ] ``` ### Syntax Examples ``` -- import a namespace, which can be referenced by name import foo.bar -- import everything within some namespace import foo.bar.baz.* -- import a specific definition from within a namespace import foo.bar.SomeDef -- import and rename a namespace import baz.buzz as bb -- import and rename a specific definition from within a namespace import baz.buzz.FooBar as Foo ``` ## Definitions A "definition" is something that might be _defined_ at the top level of any Ava source file. These include: - [Constants](#constants) - [Functions](#functions) - [Infix Functions](#infix-functions) - [Type Classes](#type-classes) - [Type Class Instances](#type-class-instances) - [Enumerations](#enumerations) - [Records](#records) - [Type Definitions](#type-definitions) - [Opaque Types](#opaque-types) ### Definition Accessibility All definitions are **public** by default. All definitions **may** be modified to be either [internal](#internal-accessibility) or [private](#private-accessibility). ### Internal Accessibility `internal` definitions are only accessible _within their namespace_. This means that they are shared across files that share a namespace. ``` internal fn foo: Int32 -> Int32 λ x => x + 1 end fn ``` Unused `internal` definitions are considered errors. ### Private Accessibility `private` definitions are only accessible _within their file_. Even if another file shares a namespace, `private` definitions are invisible to that file. ``` private fn foo: Int32 -> Int32 λ x => x + 1 end fn ``` Unused `private` definitions are considered errors. ## Comments _Comments_ are sections of code that are not parsed as code. They are used to add in-code documentation. ### Rules - All comments begin with `--`. This is a _prefix_, `--` tells the parser to ignore any following content on sight. - Multi-line comments are **not** supported. - Names may _not_ include the comment designator. ### Standard Comment Syntax Comments start with `--`. If that string is detected, the comment initializer to the end of the line will be completely ignored. ### Docstring Comment Syntax Docstrings start with `---` and must precede a _definition_ at the top level of some source file. Docstrings _may_ be parsed in a separate process to produce a documentation artifact. ### Examples ``` --- This is a docstring for the function definition. fn foo: String -> String -- This is a regular comment. --- This is a regular comment, because it is not at the definition level. λ x => x + x end fn ``` ## Constants _Constants_ are top-level [definitions](#definitions) in Ava. They are named, concrete values with a concrete type. ### Rules - Constants must be defined at the top level of Ava source files. - Constants must have an explicit type (they may not infer). - Constants must have a concrete type. - Constants must have a literal value. - Constants _may_ reference the value of another constant. - Constants _may_ be a record, itself defined in terms of literal values or constant values. Note that these rules exist to permit constant definitions that are not limited to literal values. ### Syntax Constants are defined using the [const](#const) keyword. ``` const : = ``` ### Examples ``` const foo: String = "foo" const bar: Int32 = 12 record Foo x: String, y: Int32, end record const baz: Foo = Foo(foo, bar) ``` ## Functions _Functions_ are top-level [definitions](#definitions) in Ava, values in Ava, and are the heart of programming in Ava. In general, functions have type `A -> B`, where input of type `A` produces a result of type `B`. ### Functions Without Arguments Technically, there are _no_ functions without arguments in Ava. All functions are pure, and thus a function without arguments is just a value. The `Unit` type can be used as a "nothing" argument, as it's a singleton object. ``` given A record IO thunk: Unit -> A end record given A fn io_new: (Unit -> A) -> IO A λ thunk => IO(thunk = thunk) end fn fn demonstrate: Unit -> IO Int32 λ () => block let foo: Int32 = 10 let bar: IO Int32 = io_new λ () => foo bar end block end fn ``` ### Functions With Multiple Arguments Arguments should be chained with `->` in Ava: ``` import ava.string fn example: String -> Int32 -> Int32 λ x y => (string.length x) + y end fn ``` Technically, this represents a curried function with left associativity: ``` A -> B -> C -> D == ((A -> B) -> C) -> D ``` This means that Ava naturally supports curried functions with partial application: ``` fn example: Int32 -> Int32 -> Int32 -> Int32 λ x y z => x + y + z end fn let add1: Int32 -> Int32 -> Int32 = example 1 -- Result: 6 let result = add1 2 3 ``` In this case, `example 1` invokes `example` with an input of literal value `1`, which results in a partial application of example that looks like: ``` fn partial: Int32 -> Int32 -> Int32 λ y z => 1 + y + z end fn ```