Files
n8n-openai-adapter/lib/elixir/lib/kernel.ex
T

7102 lines
191 KiB
Elixir

# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: 2021 The Elixir Team
# SPDX-FileCopyrightText: 2012 Plataformatec
# Use elixir_bootstrap module to be able to bootstrap Kernel.
# The bootstrap module provides simpler implementations of the
# functions removed, simple enough to bootstrap.
import Kernel,
except: [@: 1, defmodule: 2, def: 1, def: 2, defp: 2, defmacro: 1, defmacro: 2, defmacrop: 2]
import :elixir_bootstrap
defmodule Kernel do
@moduledoc """
`Kernel` is Elixir's default environment.
It mainly consists of:
* basic language primitives, such as arithmetic operators, spawning of processes,
data type handling, and others
* macros for control-flow and defining new functionality (modules, functions, and the like)
* guard checks for augmenting pattern matching
You can invoke `Kernel` functions and macros anywhere in Elixir code
without the use of the `Kernel.` prefix since they have all been
automatically imported. For example, in IEx, you can call:
iex> is_number(13)
true
If you don't want to import a function or macro from `Kernel`, use the `:except`
option and then list the function/macro by arity:
import Kernel, except: [if: 2, is_number: 1]
See `import/2` for more information on importing.
Elixir also has special forms that are always imported and
cannot be skipped. These are described in `Kernel.SpecialForms`.
## The standard library
`Kernel` provides the basic capabilities the Elixir standard library
is built on top of. It is recommended to explore the standard library
for advanced functionality. Here are the main groups of modules in the
standard library (this list is not a complete reference, see the
documentation sidebar for all entries).
### Built-in types
The following modules handle Elixir built-in data types:
* `Atom` - literal constants with a name (`true`, `false`, and `nil` are atoms)
* `Float` - numbers with floating point precision
* `Function` - a reference to code chunk, created with the `fn/1` special form
* `Integer` - whole numbers (not fractions)
* `List` - collections of a variable number of elements (linked lists)
* `Map` - collections of key-value pairs
* `Process` - light-weight threads of execution
* `Port` - mechanisms to interact with the external world
* `Tuple` - collections of a fixed number of elements
There are two data types without an accompanying module:
* Bitstring - a sequence of bits, created with `<<>>/1`.
When the number of bits is divisible by 8, they are called binaries and can
be manipulated with Erlang's [`:binary`](`:binary`) module
* Reference - a unique value in the runtime system, created with `make_ref/0`
### Data types
Elixir also provides other data types that are built on top of the types
listed above. Some of them are:
* `Date` - `year-month-day` structs in a given calendar
* `DateTime` - date and time with time zone in a given calendar
* `Exception` - data raised from errors and unexpected scenarios
* `MapSet` - unordered collections of unique elements
* `NaiveDateTime` - date and time without time zone in a given calendar
* `Keyword` - lists of two-element tuples, often representing optional values
* `Range` - inclusive ranges between two integers
* `Regex` - regular expressions
* `String` - UTF-8 encoded binaries representing characters
* `Time` - `hour:minute:second` structs in a given calendar
* `URI` - representation of URIs that identify resources
* `Version` - representation of versions and requirements
### System modules
Modules that interface with the underlying system, such as:
* `IO` - handles input and output
* `File` - interacts with the underlying file system
* `Path` - manipulates file system paths
* `System` - reads and writes system information
### Protocols
Protocols add polymorphic dispatch to Elixir. They are contracts
implementable by data types. See `Protocol` for more information on
protocols. Elixir provides the following protocols in the standard library:
* `Collectable` - collects data into a data type
* `Enumerable` - handles collections in Elixir. The `Enum` module
provides eager functions for working with collections, the `Stream`
module provides lazy functions
* `Inspect` - converts data types into their programming language
representation
* `List.Chars` - converts data types to their outside world
representation as charlists (non-programming based)
* `String.Chars` - converts data types to their outside world
representation as strings (non-programming based)
### Process-based and application-centric functionality
The following modules build on top of processes to provide concurrency,
fault-tolerance, and more.
* `Agent` - a process that encapsulates mutable state
* `Application` - functions for starting, stopping and configuring
applications
* `GenServer` - a generic client-server API
* `Registry` - a key-value process-based storage
* `Supervisor` - a process that is responsible for starting,
supervising and shutting down other processes
* `Task` - a process that performs computations
* `Task.Supervisor` - a supervisor for managing tasks exclusively
### Supporting documents
Under the "Pages" section in sidebar you will find tutorials, guides,
and reference documents that outline Elixir semantics and behaviors
in more detail. Those are:
* [Compatibility and deprecations](compatibility-and-deprecations.md) - lists
compatibility between every Elixir version and Erlang/OTP, release schema;
lists all deprecated functions, when they were deprecated and alternatives
* [Library guidelines](library-guidelines.md) - general guidelines, anti-patterns,
and rules for those writing libraries
* [Naming conventions](naming-conventions.md) - naming conventions for Elixir code
* [Operators reference](operators.md) - lists all Elixir operators and their precedences
* [Patterns and guards](patterns-and-guards.md) - an introduction to patterns,
guards, and extensions
* [Syntax reference](syntax-reference.md) - the language syntax reference
* [Typespecs reference](typespecs.md)- types and function specifications, including list of types
* [Unicode syntax](unicode-syntax.md) - outlines Elixir support for Unicode
## Guards
This module includes the built-in guards used by Elixir developers.
They are a predefined set of functions and macros that augment pattern
matching, typically invoked after the `when` operator. For example:
def drive(%User{age: age}) when age >= 16 do
...
end
The clause above will only be invoked if the user's age is more than
or equal to 16. Guards also support joining multiple conditions with
`and` and `or`. The whole guard is true if all guard expressions will
evaluate to `true`. A more complete introduction to guards is available
in the [Patterns and guards](patterns-and-guards.md) page.
## Truthy and falsy values
Besides the booleans `true` and `false`, Elixir has the
concept of a "truthy" or "falsy" value.
* a value is truthy when it is neither `false` nor `nil`
* a value is falsy when it is either `false` or `nil`
Elixir has functions, like `and/2`, that *only* work with
booleans, but also functions that work with these
truthy/falsy values, like `&&/2` and `!/1`.
## Structural comparison
The functions in this module perform structural comparison. This allows
different data types to be compared using comparison operators:
1 < :an_atom
This is possible so Elixir developers can create collections, such as
dictionaries and ordered sets, that store a mixture of data types in them.
To understand why this matters, let's discuss the two types of comparisons
we find in software: _structural_ and _semantic_.
Structural means we are comparing the underlying data structures and we often
want those operations to be as fast as possible, because it is used to power
several algorithms and data structures in the language. A semantic comparison
worries about what each data type represents. For example, semantically
speaking, it doesn't make sense to compare `Time` with `Date`.
One example that shows the differences between structural and semantic
comparisons are strings: "alien" sorts less than "office" (`"alien" < "office"`)
but "álien" is greater than "office". This happens because `<` compares the
underlying bytes that form the string. If you were doing alphabetical listing,
you may want "álien" to also appear before "office".
This means **comparisons in Elixir are structural**, as it has the goal
of comparing data types as efficiently as possible to create flexible
and performant data structures. This distinction is specially important
for functions that provide ordering, such as `>/2`, `</2`, `>=/2`,
`<=/2`, `min/2`, and `max/2`. For example:
~D[2017-03-31] > ~D[2017-04-01]
will return `true` because structural comparison compares the `:day`
field before `:month` or `:year`. Luckily, the Elixir compiler will
detect whenever comparing structs or whenever comparing code that is
either always true or false, and emit a warning accordingly.
In order to perform semantic comparisons, the relevant data-types
provide a `compare/2` function, such as `Date.compare/2`:
iex> Date.compare(~D[2017-03-31], ~D[2017-04-01])
:lt
Alternatively, you can use the functions in the `Enum` module to
sort or compute a maximum/minimum:
iex> Enum.sort([~D[2017-03-31], ~D[2017-04-01]], Date)
[~D[2017-03-31], ~D[2017-04-01]]
iex> Enum.max([~D[2017-03-31], ~D[2017-04-01]], Date)
~D[2017-04-01]
The second argument is precisely the module to be used for semantic
comparison. Keeping this distinction is important, because if semantic
comparison was used by default for implementing data structures and
algorithms, they could become orders of magnitude slower!
Finally, note there is an overall structural sorting order, called
"Term Ordering", defined below. This order is provided for reference
purposes, it is not required for Elixir developers to know it by heart.
### Term ordering
```
number < atom < reference < function < port < pid < tuple < map < list < bitstring
```
When comparing two numbers of different types (a number being either
an integer or a float), a conversion to the type with greater precision
will always occur, unless the comparison operator used is either `===/2`
or `!==/2`. A float will be considered more precise than an integer, unless
the float is greater/less than +/-9007199254740992.0 respectively,
at which point all the significant figures of the float are to the left
of the decimal point. This behavior exists so that the comparison of large
numbers remains transitive.
The collection types are compared using the following rules:
* Tuples are compared by size, then element by element.
* Maps are compared by size, then by key-value pairs.
* Lists are compared element by element.
* Bitstrings are compared byte by byte, incomplete bytes are compared bit by bit.
* Atoms are compared using their string value, codepoint by codepoint.
### Examples
We can check the truthiness of a value by using the `!/1`
function twice.
Truthy values:
iex> !!true
true
iex> !!5
true
iex> !![1,2]
true
iex> !!"foo"
true
Falsy values (of which there are exactly two):
iex> !!false
false
iex> !!nil
false
## Inlining
Some of the functions described in this module are inlined by
the Elixir compiler into their Erlang counterparts in the
[`:erlang`](`:erlang`) module.
Those functions are called BIFs (built-in internal functions)
in Erlang-land and they exhibit interesting properties, as some
of them are allowed in guards and others are used for compiler
optimizations.
Most of the inlined functions can be seen in effect when
capturing the function:
iex> &Kernel.is_atom/1
&:erlang.is_atom/1
Those functions will be explicitly marked in their docs as
"inlined by the compiler".
"""
# We need this check only for bootstrap purposes.
# Once Kernel is loaded and we recompile, it is a no-op.
@compile {:inline, bootstrapped?: 1}
case :code.ensure_loaded(Kernel) do
{:module, _} ->
defp bootstrapped?(module), do: is_atom(module)
{:error, _} ->
defp bootstrapped?(module), do: :code.ensure_loaded(module) == {:module, module}
end
## Delegations to Erlang with inlining (macros)
@doc """
Returns an integer or float which is the arithmetical absolute value of `number`.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> abs(-3.33)
3.33
iex> abs(-3)
3
"""
@doc guard: true
@spec abs(number) :: number
def abs(number) do
:erlang.abs(number)
end
@doc """
Invokes the given anonymous function `fun` with the list of
arguments `args`.
If the number of arguments is known at compile time, prefer
`fun.(arg_1, arg_2, ..., arg_n)` as it is clearer than
`apply(fun, [arg_1, arg_2, ..., arg_n])`.
Inlined by the compiler.
## Examples
iex> apply(fn x -> x * 2 end, [2])
4
"""
@spec apply(fun, [any]) :: any
def apply(fun, args) do
:erlang.apply(fun, args)
end
@doc """
Invokes the given function from `module` with the list of
arguments `args`.
`apply/3` is used to invoke functions where the module, function
name or arguments are defined dynamically at runtime. For this
reason, you can't invoke macros using `apply/3`, only functions.
If the number of arguments and the function name are known at compile time,
prefer `module.function(arg_1, arg_2, ..., arg_n)` as it is clearer than
`apply(module, :function, [arg_1, arg_2, ..., arg_n])`.
`apply/3` cannot be used to call private functions.
Inlined by the compiler.
## Examples
iex> apply(Enum, :reverse, [[1, 2, 3]])
[3, 2, 1]
"""
@spec apply(module, function_name :: atom, [any]) :: any
def apply(module, function_name, args) do
:erlang.apply(module, function_name, args)
end
@doc """
Extracts the part of the binary at `start` with `size`.
If `start` or `size` reference in any way outside the binary,
an `ArgumentError` exception is raised.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> binary_part("foo", 1, 2)
"oo"
A negative `size` can be used to extract bytes that come *before* the byte
at `start`:
iex> binary_part("Hello", 5, -3)
"llo"
An `ArgumentError` is raised when the `size` is outside of the binary:
binary_part("Hello", 0, 10)
** (ArgumentError) argument error
"""
@doc guard: true
@spec binary_part(binary, non_neg_integer, integer) :: binary
def binary_part(binary, start, size) do
:erlang.binary_part(binary, start, size)
end
@doc """
Returns an integer which is the size in bits of `bitstring`.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> bit_size(<<433::16, 3::3>>)
19
iex> bit_size(<<1, 2, 3>>)
24
"""
@doc guard: true
@spec bit_size(bitstring) :: non_neg_integer
def bit_size(bitstring) do
:erlang.bit_size(bitstring)
end
@doc """
Returns the number of bytes needed to contain `bitstring`.
That is, if the number of bits in `bitstring` is not divisible by 8, the
resulting number of bytes will be rounded up (by excess). This operation
happens in constant time.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> byte_size(<<433::16, 3::3>>)
3
iex> byte_size(<<1, 2, 3>>)
3
"""
@doc guard: true
@spec byte_size(bitstring) :: non_neg_integer
def byte_size(bitstring) do
:erlang.byte_size(bitstring)
end
@doc """
Returns the smallest integer greater than or equal to `number`.
If you want to perform ceil operation on other decimal places,
use `Float.ceil/2` instead.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> ceil(10)
10
iex> ceil(10.1)
11
iex> ceil(-10.1)
-10
"""
@doc since: "1.8.0", guard: true
@spec ceil(number) :: integer
def ceil(number) do
:erlang.ceil(number)
end
@doc """
Performs an integer division.
Raises an `ArithmeticError` exception if one of the arguments is not an
integer, or when the `divisor` is `0`.
`div/2` performs *truncated* integer division. This means that
the result is always rounded towards zero.
If you want to perform floored integer division (rounding towards negative infinity),
use `Integer.floor_div/2` instead.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> div(5, 2)
2
iex> div(6, -4)
-1
iex> div(-99, 2)
-49
div(100, 0)
** (ArithmeticError) bad argument in arithmetic expression
"""
@doc guard: true
@spec div(integer, neg_integer | pos_integer) :: integer
def div(dividend, divisor) do
:erlang.div(dividend, divisor)
end
@doc """
Stops the execution of the calling process with the given reason.
Since evaluating this function causes the process to terminate,
it has no return value.
Inlined by the compiler.
## Examples
When a process reaches its end, by default it exits with
reason `:normal`. You can also call `exit/1` explicitly if you
want to terminate a process but not signal any failure:
exit(:normal)
In case something goes wrong, you can also use `exit/1` with
a different reason:
exit(:seems_bad)
If the exit reason is not `:normal`, all the processes linked to the process
that exited will crash (unless they are trapping exits).
## OTP exits
Exits are used by the OTP to determine if a process exited abnormally
or not. The following exits are considered "normal":
* `exit(:normal)`
* `exit(:shutdown)`
* `exit({:shutdown, term})`
Exiting with any other reason is considered abnormal and treated
as a crash. This means the default supervisor behavior kicks in,
error reports are emitted, and so forth.
This behavior is relied on in many different places. For example,
`ExUnit` uses `exit(:shutdown)` when exiting the test process to
signal linked processes, supervision trees and so on to politely
shut down too.
## CLI exits
Building on top of the exit signals mentioned above, if the
process started by the command line exits with any of the three
reasons above, its exit is considered normal and the Operating
System process will exit with status 0.
It is, however, possible to customize the operating system exit
signal by invoking:
exit({:shutdown, integer})
This will cause the operating system process to exit with the status given by
`integer` while signaling all linked Erlang processes to politely
shut down.
Any other exit reason will cause the operating system process to exit with
status `1` and linked Erlang processes to crash.
"""
@spec exit(term) :: no_return
def exit(reason) do
:erlang.exit(reason)
end
@doc """
Returns the largest integer smaller than or equal to `number`.
If you want to perform floor operation on other decimal places,
use `Float.floor/2` instead.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> floor(10)
10
iex> floor(9.7)
9
iex> floor(-9.7)
-10
"""
@doc since: "1.8.0", guard: true
@spec floor(number) :: integer
def floor(number) do
:erlang.floor(number)
end
@doc """
Returns the head of a list. Raises `ArgumentError` if the list is empty.
The head of a list is its first element.
It works with improper lists.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> hd([1, 2, 3, 4])
1
iex> hd([1 | 2])
1
Giving it an empty list raises:
hd([])
** (ArgumentError) argument error
"""
@doc guard: true
@spec hd(nonempty_maybe_improper_list(elem, term)) :: elem when elem: term
def hd(list) do
:erlang.hd(list)
end
@doc """
Returns `true` if `term` is an atom, otherwise returns `false`.
Note `true`, `false`, and `nil` are atoms in Elixir, as well as
module names. Therefore this function will return `true` to all
of those values.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> is_atom(:name)
true
iex> is_atom(false)
true
iex> is_atom(AnAtom)
true
iex> is_atom("string")
false
"""
@doc guard: true
@spec is_atom(term) :: boolean
def is_atom(term) do
:erlang.is_atom(term)
end
@doc """
Returns `true` if `term` is a binary, otherwise returns `false`.
A binary always contains a complete number of bytes.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> is_binary("foo")
true
iex> is_binary(<<1::3>>)
false
"""
@doc guard: true
@spec is_binary(term) :: boolean
def is_binary(term) do
:erlang.is_binary(term)
end
@doc """
Returns `true` if `term` is a bitstring (including a binary), otherwise returns `false`.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> is_bitstring("foo")
true
iex> is_bitstring(<<1::3>>)
true
"""
@doc guard: true
@spec is_bitstring(term) :: boolean
def is_bitstring(term) do
:erlang.is_bitstring(term)
end
@doc """
Returns `true` if `term` is either the atom `true` or the atom `false` (i.e.,
a boolean), otherwise returns `false`.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> is_boolean(false)
true
iex> is_boolean(true)
true
iex> is_boolean(:test)
false
"""
@doc guard: true
@spec is_boolean(term) :: boolean
def is_boolean(term) do
:erlang.is_boolean(term)
end
@doc """
Returns `true` if `term` is a floating-point number, otherwise returns `false`.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> is_float(2.15)
true
iex> is_float(3.45e5)
true
iex> is_float(5)
false
"""
@doc guard: true
@spec is_float(term) :: boolean
def is_float(term) do
:erlang.is_float(term)
end
@doc """
Returns `true` if `term` is a function, otherwise returns `false`.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> is_function(fn x -> x + x end)
true
iex> is_function("not a function")
false
"""
@doc guard: true
@spec is_function(term) :: boolean
def is_function(term) do
:erlang.is_function(term)
end
@doc """
Returns `true` if `term` is a function that can be applied with `arity` number of arguments;
otherwise returns `false`.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> is_function(fn x -> x * 2 end, 1)
true
iex> is_function(fn x -> x * 2 end, 2)
false
"""
@doc guard: true
@spec is_function(term, non_neg_integer) :: boolean
def is_function(term, arity) do
:erlang.is_function(term, arity)
end
@doc """
Returns `true` if `term` is an integer, otherwise returns `false`.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> is_integer(5)
true
iex> is_integer(5.0)
false
"""
@doc guard: true
@spec is_integer(term) :: boolean
def is_integer(term) do
:erlang.is_integer(term)
end
@doc """
Returns `true` if `term` is a list with zero or more elements, otherwise returns `false`.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> is_list([1, 2, 3])
true
iex> is_list(key: :sum, value: 3)
true
iex> is_list({1, 2, 3})
false
"""
@doc guard: true
@spec is_list(term) :: boolean
def is_list(term) do
:erlang.is_list(term)
end
@doc """
Returns `true` if `term` is either an integer or a floating-point number;
otherwise returns `false`.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> is_number(2.15)
true
iex> is_number(5)
true
iex> is_number(:one)
false
"""
@doc guard: true
@spec is_number(term) :: boolean
def is_number(term) do
:erlang.is_number(term)
end
@doc """
Returns `true` if `term` is a PID (process identifier), otherwise returns `false`.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> {:ok, agent_pid} = Agent.start_link(fn -> 0 end)
iex> is_pid(agent_pid)
true
iex> is_pid(self())
true
iex> is_pid(:pid)
false
"""
@doc guard: true
@spec is_pid(term) :: boolean
def is_pid(term) do
:erlang.is_pid(term)
end
@doc """
Returns `true` if `term` is a port identifier, otherwise returns `false`.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> [port | _] = Port.list()
iex> is_port(port)
true
iex> is_port(:port)
false
"""
@doc guard: true
@spec is_port(term) :: boolean
def is_port(term) do
:erlang.is_port(term)
end
@doc """
Returns `true` if `term` is a reference, otherwise returns `false`.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> ref = make_ref()
iex> is_reference(ref)
true
iex> is_reference(:ref)
false
"""
@doc guard: true
@spec is_reference(term) :: boolean
def is_reference(term) do
:erlang.is_reference(term)
end
@doc """
Returns `true` if `term` is a tuple, otherwise returns `false`.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> is_tuple({1, 2, 3})
true
iex> is_tuple({})
true
iex> is_tuple(true)
false
"""
@doc guard: true
@spec is_tuple(term) :: boolean
def is_tuple(term) do
:erlang.is_tuple(term)
end
@doc """
Returns `true` if `term` is a map, otherwise returns `false`.
Allowed in guard tests. Inlined by the compiler.
> #### Structs are maps {: .info}
>
> Structs are also maps, and many of Elixir data structures are implemented
> using structs: `Range`s, `Regex`es, `Date`s...
>
> iex> is_map(1..10)
> true
> iex> is_map(~D[2024-04-18])
> true
>
> If you mean to specifically check for non-struct maps, use
> `is_non_struct_map/1` instead.
>
> iex> is_non_struct_map(1..10)
> false
"""
@doc guard: true
@spec is_map(term) :: boolean
def is_map(term) do
:erlang.is_map(term)
end
@doc """
Returns `true` if `key` is a key in `map`, otherwise returns `false`.
It raises `BadMapError` if the first element is not a map.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> is_map_key(%{a: "foo", b: "bar"}, :a)
true
iex> is_map_key(%{a: "foo", b: "bar"}, :c)
false
"""
@doc guard: true, since: "1.10.0"
@spec is_map_key(map, term) :: boolean
def is_map_key(map, key) do
:erlang.is_map_key(key, map)
end
@doc """
Returns the length of `list`.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> length([1, 2, 3, 4, 5, 6, 7, 8, 9])
9
"""
@doc guard: true
@spec length(list) :: non_neg_integer
def length(list) do
:erlang.length(list)
end
@doc """
Returns an almost unique reference.
The returned reference will re-occur after approximately 2^82 calls;
therefore it is unique enough for practical purposes.
Inlined by the compiler.
## Examples
make_ref()
#=> #Reference<0.0.0.135>
"""
@spec make_ref() :: reference
def make_ref() do
:erlang.make_ref()
end
@doc """
Returns the size of a map.
The size of a map is the number of key-value pairs that the map contains.
This operation happens in constant time.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> map_size(%{a: "foo", b: "bar"})
2
"""
@doc guard: true
@spec map_size(map) :: non_neg_integer
def map_size(map) do
:erlang.map_size(map)
end
@doc """
Returns the biggest of the two given terms according to
their structural comparison.
If the terms compare equal, the first one is returned.
This performs a structural comparison where all Elixir
terms can be compared with each other. See the ["Structural
comparison"](#module-structural-comparison) section
for more information.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> max(1, 2)
2
iex> max("a", "b")
"b"
"""
@doc guard: true
@spec max(first, second) :: first | second when first: term, second: term
def max(first, second) do
:erlang.max(first, second)
end
@doc """
Returns the smallest of the two given terms according to
their structural comparison.
If the terms compare equal, the first one is returned.
This performs a structural comparison where all Elixir
terms can be compared with each other. See the ["Structural
comparison"](#module-structural-comparison) section
for more information.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> min(1, 2)
1
iex> min("foo", "bar")
"bar"
"""
@doc guard: true
@spec min(first, second) :: first | second when first: term, second: term
def min(first, second) do
:erlang.min(first, second)
end
@doc """
Returns an atom representing the name of the local node.
If the node is not alive, `:nonode@nohost` is returned instead.
Allowed in guard tests. Inlined by the compiler.
"""
@doc guard: true
@spec node() :: node
def node do
:erlang.node()
end
@doc """
Returns the node where the given argument is located.
The argument can be a PID, a reference, or a port.
If the local node is not alive, `:nonode@nohost` is returned.
Allowed in guard tests. Inlined by the compiler.
"""
@doc guard: true
@spec node(pid | reference | port) :: node
def node(arg) do
:erlang.node(arg)
end
@doc """
Computes the remainder of an integer division.
`rem/2` uses truncated division, which means that
the result will always have the sign of the `dividend`.
Raises an `ArithmeticError` exception if one of the arguments is not an
integer, or when the `divisor` is `0`.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> rem(5, 2)
1
iex> rem(6, -4)
2
"""
@doc guard: true
@spec rem(integer, neg_integer | pos_integer) :: integer
def rem(dividend, divisor) do
:erlang.rem(dividend, divisor)
end
@doc """
Rounds a number to the nearest integer.
If the number is equidistant to the two nearest integers, rounds away from zero.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> round(5.6)
6
iex> round(5.2)
5
iex> round(-9.9)
-10
iex> round(-9)
-9
iex> round(2.5)
3
iex> round(-2.5)
-3
"""
@doc guard: true
@spec round(number) :: integer
def round(number) do
:erlang.round(number)
end
@doc """
Sends a message to the given `dest` and returns the message.
`dest` may be a remote or local PID, a local port, a locally
registered name, or a tuple in the form of `{registered_name, node}` for a
registered name at another node.
For additional documentation, see the [`!` operator Erlang
documentation](https://www.erlang.org/doc/reference_manual/expressions#send).
Inlined by the compiler.
## Examples
iex> send(self(), :hello)
:hello
"""
@spec send(dest :: Process.dest(), message) :: message when message: any
def send(dest, message) do
:erlang.send(dest, message)
end
@doc """
Returns the PID (process identifier) of the calling process.
Allowed in guard clauses. Inlined by the compiler.
"""
@doc guard: true
@spec self() :: pid
def self() do
:erlang.self()
end
@doc """
Spawns the given function and returns its PID.
Typically developers do not use the `spawn` functions, instead they use
abstractions such as `Task`, `GenServer` and `Agent`, built on top of
`spawn`, that spawns processes with more conveniences in terms of
introspection and debugging.
Check the `Process` module for more process-related functions.
The anonymous function receives 0 arguments, and may return any value.
Inlined by the compiler.
## Examples
iex> current = self()
iex> child = spawn(fn -> send(current, {self(), 1 + 2}) end)
iex> receive do
...> {^child, 3} -> :ok
...> end
:ok
"""
@spec spawn((-> any)) :: pid
def spawn(fun) do
:erlang.spawn(fun)
end
@doc """
Spawns the given function `fun` from the given `module` passing it the given
`args` and returns its PID.
Typically developers do not use the `spawn` functions, instead they use
abstractions such as `Task`, `GenServer` and `Agent`, built on top of
`spawn`, that spawns processes with more conveniences in terms of
introspection and debugging.
Check the `Process` module for more process-related functions.
Inlined by the compiler.
## Examples
spawn(SomeModule, :function, [1, 2, 3])
"""
@spec spawn(module, atom, list) :: pid
def spawn(module, fun, args) do
:erlang.spawn(module, fun, args)
end
@doc """
Spawns the given function, links it to the current process, and returns its PID.
Typically developers do not use the `spawn` functions, instead they use
abstractions such as `Task`, `GenServer` and `Agent`, built on top of
`spawn`, that spawns processes with more conveniences in terms of
introspection and debugging.
Check the `Process` module for more process-related functions. For more
information on linking, check `Process.link/1`.
The anonymous function receives 0 arguments, and may return any value.
Inlined by the compiler.
## Examples
iex> current = self()
iex> child = spawn_link(fn -> send(current, {self(), 1 + 2}) end)
iex> receive do
...> {^child, 3} -> :ok
...> end
:ok
"""
@spec spawn_link((-> any)) :: pid
def spawn_link(fun) do
:erlang.spawn_link(fun)
end
@doc """
Spawns the given function `fun` from the given `module` passing it the given
`args`, links it to the current process, and returns its PID.
Typically developers do not use the `spawn` functions, instead they use
abstractions such as `Task`, `GenServer` and `Agent`, built on top of
`spawn`, that spawns processes with more conveniences in terms of
introspection and debugging.
Check the `Process` module for more process-related functions. For more
information on linking, check `Process.link/1`.
Inlined by the compiler.
## Examples
spawn_link(SomeModule, :function, [1, 2, 3])
"""
@spec spawn_link(module, atom, list) :: pid
def spawn_link(module, fun, args) do
:erlang.spawn_link(module, fun, args)
end
@doc """
Spawns the given function, monitors it and returns its PID
and monitoring reference.
Typically developers do not use the `spawn` functions, instead they use
abstractions such as `Task`, `GenServer` and `Agent`, built on top of
`spawn`, that spawns processes with more conveniences in terms of
introspection and debugging.
Check the `Process` module for more process-related functions.
The anonymous function receives 0 arguments, and may return any value.
Inlined by the compiler.
## Examples
iex> current = self()
iex> {child, _ref} = spawn_monitor(fn -> send(current, {self(), 1 + 2}) end)
iex> receive do
...> {^child, 3} -> :ok
...> end
:ok
"""
@spec spawn_monitor((-> any)) :: {pid, reference}
def spawn_monitor(fun) do
:erlang.spawn_monitor(fun)
end
@doc """
Spawns the given module and function passing the given args,
monitors it and returns its PID and monitoring reference.
Typically developers do not use the `spawn` functions, instead they use
abstractions such as `Task`, `GenServer` and `Agent`, built on top of
`spawn`, that spawns processes with more conveniences in terms of
introspection and debugging.
Check the `Process` module for more process-related functions.
Inlined by the compiler.
## Examples
spawn_monitor(SomeModule, :function, [1, 2, 3])
"""
@spec spawn_monitor(module, atom, list) :: {pid, reference}
def spawn_monitor(module, fun, args) do
:erlang.spawn_monitor(module, fun, args)
end
@doc """
Pipes the first argument, `value`, into the second argument, a function `fun`,
and returns `value` itself.
Useful for running synchronous side effects in a pipeline, using the `|>/2` operator.
## Examples
iex> tap(1, fn x -> x + 1 end)
1
Most commonly, this is used in pipelines, using the `|>/2` operator.
For example, let's suppose you want to inspect part of a data structure.
You could write:
%{a: 1}
|> Map.update!(:a, & &1 + 2)
|> tap(&IO.inspect(&1.a))
|> Map.update!(:a, & &1 * 2)
"""
@doc since: "1.12.0"
defmacro tap(value, fun) do
quote bind_quoted: [fun: fun, value: value] do
_ = fun.(value)
value
end
end
@doc """
A non-local return from a function.
Using `throw/1` is generally discouraged, as it allows a function
to escape from its regular execution flow, which can make the code
harder to read. Furthermore, all thrown values must be caught by
`try/catch`. See `try/1` for more information.
Inlined by the compiler.
"""
@spec throw(term) :: no_return
def throw(term) do
:erlang.throw(term)
end
@doc """
Returns the tail of a list. Raises `ArgumentError` if the list is empty.
The tail of a list is the list without its first element.
It works with improper lists.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> tl([1, 2, 3, :go])
[2, 3, :go]
iex> tl([:one])
[]
iex> tl([:a, :b | :improper_end])
[:b | :improper_end]
iex> tl([:a | %{b: 1}])
%{b: 1}
Giving it an empty list raises:
tl([])
** (ArgumentError) argument error
"""
@doc guard: true
@spec tl(nonempty_maybe_improper_list(elem, last)) :: maybe_improper_list(elem, last) | last
when elem: term, last: term
def tl(list) do
:erlang.tl(list)
end
@doc """
Returns the integer part of `number`.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> trunc(5.4)
5
iex> trunc(-5.99)
-5
iex> trunc(-5)
-5
"""
@doc guard: true
@spec trunc(number) :: integer
def trunc(number) do
:erlang.trunc(number)
end
@doc """
Returns the size of a tuple.
This operation happens in constant time.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> tuple_size({:a, :b, :c})
3
"""
@doc guard: true
@spec tuple_size(tuple) :: non_neg_integer
def tuple_size(tuple) do
:erlang.tuple_size(tuple)
end
@doc """
Arithmetic addition operator.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> 1 + 2
3
"""
@doc guard: true
@spec integer + integer :: integer
@spec float + float :: float
@spec integer + float :: float
@spec float + integer :: float
def left + right do
:erlang.+(left, right)
end
@doc """
Arithmetic subtraction operator.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> 1 - 2
-1
"""
@doc guard: true
@spec integer - integer :: integer
@spec float - float :: float
@spec integer - float :: float
@spec float - integer :: float
def left - right do
:erlang.-(left, right)
end
@doc """
Arithmetic positive unary operator.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> +1
1
"""
@doc guard: true
@spec +integer :: integer
@spec +float :: float
def +value do
:erlang.+(value)
end
@doc """
Arithmetic negative unary operator.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> -2
-2
"""
@doc guard: true
@spec -0 :: 0
@spec -pos_integer :: neg_integer
@spec -neg_integer :: pos_integer
@spec -float :: float
def -value do
:erlang.-(value)
end
@doc """
Arithmetic multiplication operator.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> 1 * 2
2
"""
@doc guard: true
@spec integer * integer :: integer
@spec float * float :: float
@spec integer * float :: float
@spec float * integer :: float
def left * right do
:erlang.*(left, right)
end
@doc """
Arithmetic division operator.
The result is always a float. Use `div/2` and `rem/2` if you want
an integer division or the remainder.
Raises `ArithmeticError` if `right` is 0 or 0.0.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> 1 / 2
0.5
iex> -3.0 / 2.0
-1.5
iex> 5 / 1
5.0
7 / 0
** (ArithmeticError) bad argument in arithmetic expression
"""
@doc guard: true
@spec number / number :: float
def left / right do
:erlang./(left, right)
end
@doc """
List concatenation operator. Concatenates a proper list and a term, returning a list.
The complexity of `a ++ b` is proportional to `length(a)`, so avoid repeatedly
appending to lists of arbitrary length, for example, `list ++ [element]`.
Instead, consider prepending via `[element | rest]` and then reversing.
If the `right` operand is not a proper list, it returns an improper list.
If the `left` operand is not a proper list, it raises `ArgumentError`.
If the `left` operand is an empty list, it returns the `right` operand.
Inlined by the compiler.
## Examples
iex> [1] ++ [2, 3]
[1, 2, 3]
iex> ~c"foo" ++ ~c"bar"
~c"foobar"
# a non-list on the right will return an improper list
# with said element at the end
iex> [1, 2] ++ 3
[1, 2 | 3]
iex> [1, 2] ++ {3, 4}
[1, 2 | {3, 4}]
# improper list on the right will return an improper list
iex> [1] ++ [2 | 3]
[1, 2 | 3]
# empty list on the left will return the right operand
iex> [] ++ 1
1
The `++/2` operator is right associative, meaning:
iex> [1, 2, 3] -- [1] ++ [2]
[3]
As it is equivalent to:
iex> [1, 2, 3] -- ([1] ++ [2])
[3]
"""
@spec [] ++ a :: a when a: term()
@spec nonempty_list() ++ term() :: maybe_improper_list()
def left ++ right do
:erlang.++(left, right)
end
@doc """
List subtraction operator. Removes the first occurrence of an element
on the left list for each element on the right.
This function is optimized so the complexity of `a -- b` is proportional
to `length(a) * log(length(b))`. See also the [Erlang efficiency
guide](https://www.erlang.org/doc/system/efficiency_guide.html).
Inlined by the compiler.
## Examples
iex> [1, 2, 3] -- [1, 2]
[3]
iex> [1, 2, 3, 2, 1] -- [1, 2, 2]
[3, 1]
The `--/2` operator is right associative, meaning:
iex> [1, 2, 3] -- [2] -- [3]
[1, 3]
As it is equivalent to:
iex> [1, 2, 3] -- ([2] -- [3])
[1, 3]
"""
@spec list -- list :: list
def left -- right do
:erlang.--(left, right)
end
@doc """
Strictly boolean "not" operator.
`value` must be a boolean; if it's not, an `ArgumentError` exception is raised.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> not false
true
"""
@doc guard: true
@spec not true :: false
@spec not false :: true
def not value do
:erlang.not(value)
end
@doc """
Less-than operator.
Returns `true` if `left` is less than `right`.
This performs a structural comparison where all Elixir
terms can be compared with each other. See the ["Structural
comparison"](#module-structural-comparison) section
for more information.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> 1 < 2
true
"""
@doc guard: true
@spec term < term :: boolean
def left < right do
:erlang.<(left, right)
end
@doc """
Greater-than operator.
Returns `true` if `left` is more than `right`.
This performs a structural comparison where all Elixir
terms can be compared with each other. See the ["Structural
comparison"](#module-structural-comparison) section
for more information.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> 1 > 2
false
"""
@doc guard: true
@spec term > term :: boolean
def left > right do
:erlang.>(left, right)
end
@doc """
Less-than or equal to operator.
Returns `true` if `left` is less than or equal to `right`.
This performs a structural comparison where all Elixir
terms can be compared with each other. See the ["Structural
comparison"](#module-structural-comparison) section
for more information.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> 1 <= 2
true
"""
@doc guard: true
@spec term <= term :: boolean
def left <= right do
:erlang."=<"(left, right)
end
@doc """
Greater-than or equal to operator.
Returns `true` if `left` is more than or equal to `right`.
This performs a structural comparison where all Elixir
terms can be compared with each other. See the ["Structural
comparison"](#module-structural-comparison) section
for more information.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> 1 >= 2
false
"""
@doc guard: true
@spec term >= term :: boolean
def left >= right do
:erlang.>=(left, right)
end
@doc """
Equal to operator. Returns `true` if the two terms are equal.
This operator considers 1 and 1.0 to be equal. For stricter
semantics, use `===/2` instead.
This performs a structural comparison where all Elixir
terms can be compared with each other. See the ["Structural
comparison"](#module-structural-comparison) section
for more information.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> 1 == 2
false
iex> 1 == 1.0
true
"""
@doc guard: true
@spec term == term :: boolean
def left == right do
:erlang.==(left, right)
end
@doc """
Not equal to operator.
Returns `true` if the two terms are not equal.
This operator considers 1 and 1.0 to be equal. For match
comparison, use `!==/2` instead.
This performs a structural comparison where all Elixir
terms can be compared with each other. See the ["Structural
comparison"](#module-structural-comparison) section
for more information.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> 1 != 2
true
iex> 1 != 1.0
false
"""
@doc guard: true
@spec term != term :: boolean
def left != right do
:erlang."/="(left, right)
end
@doc """
Strictly equal to operator.
Returns `true` if the two terms are exactly equal.
The terms are only considered to be exactly equal if they
have the same value and are of the same type. For example,
`1 == 1.0` returns `true`, but since they are of different
types, `1 === 1.0` returns `false`.
This performs a structural comparison where all Elixir
terms can be compared with each other. See the ["Structural
comparison"](#module-structural-comparison) section
for more information.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> 1 === 2
false
iex> 1 === 1.0
false
"""
@doc guard: true
@spec term === term :: boolean
def left === right do
:erlang."=:="(left, right)
end
@doc """
Strictly not equal to operator.
Returns `true` if the two terms are not exactly equal.
See `===/2` for a definition of what is considered "exactly equal".
This performs a structural comparison where all Elixir
terms can be compared with each other. See the ["Structural
comparison"](#module-structural-comparison) section
for more information.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> 1 !== 2
true
iex> 1 !== 1.0
true
"""
@doc guard: true
@spec term !== term :: boolean
def left !== right do
:erlang."=/="(left, right)
end
@doc """
Gets the element at the zero-based `index` in `tuple`.
It raises `ArgumentError` when index is negative or it is out of range of the tuple elements.
Allowed in guard tests. Inlined by the compiler.
## Examples
iex> tuple = {:foo, :bar, 3}
iex> elem(tuple, 1)
:bar
elem({}, 0)
** (ArgumentError) argument error
elem({:foo, :bar}, 2)
** (ArgumentError) argument error
"""
@doc guard: true
@spec elem(tuple, non_neg_integer) :: term
def elem(tuple, index) do
:erlang.element(index + 1, tuple)
end
@doc """
Puts `value` at the given zero-based `index` in `tuple`.
Inlined by the compiler.
## Examples
iex> tuple = {:foo, :bar, 3}
iex> put_elem(tuple, 0, :baz)
{:baz, :bar, 3}
"""
@spec put_elem(tuple, non_neg_integer, term) :: tuple
def put_elem(tuple, index, value) do
:erlang.setelement(index + 1, tuple, value)
end
## Implemented in Elixir
defp annotate_case(extra, {:case, meta, args}) do
{:case, extra ++ meta, args}
end
defp x_is_false_or_nil do
quote generated: true do
:erlang.orelse(:erlang."=:="(x, false), :erlang."=:="(x, nil))
end
end
@doc """
Strictly boolean "or" operator.
If `left` is `true`, returns `true`, otherwise returns `right`.
Requires only the `left` operand to be a boolean since it short-circuits.
If the `left` operand is not a boolean, a `BadBooleanError` exception is
raised.
Allowed in guard tests.
## Examples
iex> true or false
true
iex> false or 42
42
iex> 42 or false
** (BadBooleanError) expected a boolean on left-side of "or", got: 42
"""
@doc guard: true
defmacro left or right do
case __CALLER__.context do
nil -> build_boolean_check(:or, left, true, right)
:match -> invalid_match!(:or)
:guard -> quote(do: :erlang.orelse(unquote(left), unquote(right)))
end
end
@doc """
Strictly boolean "and" operator.
If `left` is `false`, returns `false`, otherwise returns `right`.
Requires only the `left` operand to be a boolean since it short-circuits. If
the `left` operand is not a boolean, a `BadBooleanError` exception is raised.
Allowed in guard tests.
## Examples
iex> true and false
false
iex> true and "yay!"
"yay!"
iex> "yay!" and true
** (BadBooleanError) expected a boolean on left-side of "and", got: "yay!"
"""
@doc guard: true
defmacro left and right do
case __CALLER__.context do
nil -> build_boolean_check(:and, left, right, false)
:match -> invalid_match!(:and)
:guard -> quote(do: :erlang.andalso(unquote(left), unquote(right)))
end
end
defp build_boolean_check(operator, check, true_clause, false_clause) do
bools =
quote do
false -> unquote(false_clause)
true -> unquote(true_clause)
end
error =
quote generated: true do
other -> :erlang.error({:badbool, unquote(operator), other})
end
annotate_case(
[optimize_boolean: true, type_check: :expr],
{:case, [], [check, [do: bools ++ error]]}
)
end
@doc """
Boolean "not" operator.
Receives any value (not just booleans) and returns `true` if `value`
is `false` or `nil`; returns `false` otherwise.
Not allowed in guard clauses.
## Examples
iex> !Enum.empty?([])
false
iex> !List.first([])
true
"""
defmacro !value
defmacro !{:!, _, [value]} do
assert_no_match_or_guard_scope(__CALLER__.context, "!")
annotate_case(
[optimize_boolean: true, type_check: :expr],
quote do
case unquote(value) do
x when unquote(x_is_false_or_nil()) -> false
_ -> true
end
end
)
end
defmacro !value do
assert_no_match_or_guard_scope(__CALLER__.context, "!")
annotate_case(
[optimize_boolean: true, type_check: :expr],
quote do
case unquote(value) do
x when unquote(x_is_false_or_nil()) -> true
_ -> false
end
end
)
end
@doc """
Binary concatenation operator. Concatenates two binaries.
Raises an `ArgumentError` if one of the sides aren't binaries.
## Examples
iex> "foo" <> "bar"
"foobar"
The `<>/2` operator can also be used in pattern matching (and guard clauses) as
long as the left argument is a literal binary:
iex> "foo" <> x = "foobar"
iex> x
"bar"
`x <> "bar" = "foobar"` would result in an `ArgumentError` exception.
"""
defmacro left <> right do
concats = extract_concatenations({:<>, [], [left, right]}, __CALLER__)
quote(do: <<unquote_splicing(concats)>>)
end
# Extracts concatenations in order to optimize many
# concatenations into one single clause.
defp extract_concatenations({:<>, _, [left, right]}, caller) do
[wrap_concatenation(left, :left, caller) | extract_concatenations(right, caller)]
end
defp extract_concatenations(other, caller) do
[wrap_concatenation(other, :right, caller)]
end
defp wrap_concatenation(binary, _side, _caller) when is_binary(binary) do
binary
end
defp wrap_concatenation(literal, _side, _caller)
when is_list(literal) or is_atom(literal) or is_integer(literal) or is_float(literal) do
:erlang.error(
ArgumentError.exception(
"expected binary argument in <> operator but got: #{Macro.to_string(literal)}"
)
)
end
defp wrap_concatenation(other, side, caller) do
expanded = expand_concat_argument(other, side, caller)
{:"::", [], [expanded, {:binary, [], nil}]}
end
defp expand_concat_argument(arg, :left, %{context: :match} = caller) do
expanded_arg =
case bootstrapped?(Macro) do
true -> Macro.expand(arg, caller)
false -> arg
end
case expanded_arg do
{var, _, nil} when is_atom(var) ->
invalid_concat_left_argument_error(Atom.to_string(var))
_ ->
expanded_arg
end
end
defp expand_concat_argument(arg, _, _) do
arg
end
defp invalid_concat_left_argument_error(arg) do
:erlang.error(
ArgumentError.exception(
"cannot perform prefix match because the left operand of <> has unknown size. " <>
"The left operand of <> inside a match should either be a literal binary or " <>
"an existing variable with the pin operator (such as ^some_var). Got: #{arg}"
)
)
end
@doc """
Raises an exception.
If `message` is a string, it raises a `RuntimeError` exception with it.
If `message` is an atom, it just calls `raise/2` with the atom as the first
argument and `[]` as the second one.
If `message` is an exception struct, it is raised as is.
If `message` is anything else, `raise` will fail with an `ArgumentError`
exception.
## Examples
iex> raise "oops"
** (RuntimeError) oops
try do
1 + :foo
rescue
x in [ArithmeticError] ->
IO.puts("that was expected")
raise x
end
"""
defmacro raise(message) do
# Try to figure out the type at compilation time
# to avoid dead code and make Dialyzer happy.
message =
case not is_binary(message) and bootstrapped?(Macro) do
true -> Macro.expand(message, __CALLER__)
false -> message
end
erlang_error =
fn x ->
quote do
:erlang.error(unquote(x), :none, error_info: %{module: Exception})
end
end
case message do
message when is_binary(message) ->
erlang_error.(quote do: RuntimeError.exception(unquote(message)))
{:<<>>, _, _} = message ->
erlang_error.(quote do: RuntimeError.exception(unquote(message)))
alias when is_atom(alias) ->
erlang_error.(quote do: unquote(alias).exception([]))
_ ->
erlang_error.(quote do: Kernel.Utils.raise(unquote(message)))
end
end
@doc """
Raises an exception.
Calls the `exception/1` function on the given argument (which has to be a
module name like `ArgumentError` or `RuntimeError`) passing `attributes`
in order to retrieve the exception struct.
Any module that contains a call to the `defexception/1` macro automatically
implements the `c:Exception.exception/1` callback expected by `raise/2`.
For more information, see `defexception/1`.
## Examples
iex> raise(ArgumentError, "Sample")
** (ArgumentError) Sample
"""
defmacro raise(exception, attributes) do
quote do
:erlang.error(unquote(exception).exception(unquote(attributes)))
end
end
@doc """
Raises an exception preserving a previous stacktrace.
Works like `raise/1` but does not generate a new stacktrace.
Note that `__STACKTRACE__` can be used inside catch/rescue
to retrieve the current stacktrace.
## Examples
iex> try do
...> raise "oops"
...> rescue
...> exception ->
...> reraise exception, __STACKTRACE__
...> end
** (RuntimeError) oops
"""
defmacro reraise(message, stacktrace) do
# Try to figure out the type at compilation time
# to avoid dead code and make Dialyzer happy.
case Macro.expand(message, __CALLER__) do
message when is_binary(message) ->
quote do
:erlang.raise(:error, RuntimeError.exception(unquote(message)), unquote(stacktrace))
end
{:<<>>, _, _} = message ->
quote do
:erlang.raise(:error, RuntimeError.exception(unquote(message)), unquote(stacktrace))
end
alias when is_atom(alias) ->
quote do
:erlang.raise(:error, unquote(alias).exception([]), unquote(stacktrace))
end
message ->
quote do
:erlang.raise(:error, Kernel.Utils.raise(unquote(message)), unquote(stacktrace))
end
end
end
@doc """
Raises an exception preserving a previous stacktrace.
`reraise/3` works like `reraise/2`, except it passes arguments to the
`exception/1` function as explained in `raise/2`.
## Examples
try do
raise "oops"
rescue
exception ->
reraise WrapperError, [exception: exception], __STACKTRACE__
end
"""
defmacro reraise(exception, attributes, stacktrace) do
quote do
:erlang.raise(
:error,
unquote(exception).exception(unquote(attributes)),
unquote(stacktrace)
)
end
end
@doc """
Text-based match operator. Matches the string on the `left`
against the regular expression or string on the `right`.
If `right` is a regular expression, returns `true` if `left` matches right.
If `right` is a string, returns `true` if `left` contains `right`.
## Examples
iex> "abcd" =~ ~r/c(d)/
true
iex> "abcd" =~ ~r/e/
false
iex> "abcd" =~ ~r//
true
iex> "abcd" =~ "bc"
true
iex> "abcd" =~ "ad"
false
iex> "abcd" =~ "abcd"
true
iex> "abcd" =~ ""
true
For more information about regular expressions, please check the `Regex` module.
"""
@spec String.t() =~ (String.t() | Regex.t()) :: boolean
def left =~ "" when is_binary(left), do: true
def left =~ right when is_binary(left) and is_binary(right) do
:binary.match(left, right) != :nomatch
end
def left =~ right when is_binary(left) do
Regex.match?(right, left)
end
@doc ~S"""
Inspects the given argument according to the `Inspect` protocol.
The second argument is a keyword list with options to control
inspection.
## Options
`inspect/2` accepts a list of options that are internally
translated to an `Inspect.Opts` struct. Check the docs for
`Inspect.Opts` to see the supported options.
## Examples
iex> inspect(:foo)
":foo"
iex> inspect([1, 2, 3, 4, 5], limit: 3)
"[1, 2, 3, ...]"
iex> inspect([1, 2, 3], pretty: true, width: 0)
"[1,\n 2,\n 3]"
iex> inspect("olá" <> <<0>>)
"<<111, 108, 195, 161, 0>>"
iex> inspect("olá" <> <<0>>, binaries: :as_strings)
"\"olá\\0\""
iex> inspect("olá", binaries: :as_binaries)
"<<111, 108, 195, 161>>"
iex> inspect(~c"bar")
"~c\"bar\""
iex> inspect([0 | ~c"bar"])
"[0, 98, 97, 114]"
iex> inspect(100, base: :octal)
"0o144"
iex> inspect(100, base: :hex)
"0x64"
Note that the `Inspect` protocol does not necessarily return a valid
representation of an Elixir term. In such cases, the inspected result
must start with `#`. For example, inspecting a function will return:
inspect(fn a, b -> a + b end)
#=> #Function<...>
The `Inspect` protocol can be derived to hide certain fields
from structs, so they don't show up in logs, inspects and similar.
See the "Deriving" section of the documentation of the `Inspect`
protocol for more information.
"""
@spec inspect(Inspect.t(), [Inspect.Opts.new_opt()]) :: String.t()
def inspect(term, opts \\ []) when is_list(opts) do
opts = Inspect.Opts.new(opts)
limit =
case opts.pretty do
true -> opts.width
false -> :infinity
end
doc = Inspect.Algebra.group(Inspect.Algebra.to_doc(term, opts))
IO.iodata_to_binary(Inspect.Algebra.format(doc, limit))
end
@doc """
Creates and updates a struct.
The `struct` argument may be an atom (which defines `defstruct`)
or a `struct` itself. The second argument is any `Enumerable` that
emits two-element tuples (key-value pairs) during enumeration.
Keys in the `Enumerable` that don't exist in the struct are automatically
discarded. Note that keys must be atoms, as only atoms are allowed when
defining a struct. If there are duplicate keys in the `Enumerable`, the last
entry will be taken (same behavior as `Map.new/1`).
This function is useful for dynamically creating and updating structs, as
well as for converting maps to structs; in the latter case, just inserting
the appropriate `:__struct__` field into the map may not be enough and
`struct/2` should be used instead.
## Examples
defmodule User do
defstruct name: "john"
end
struct(User)
#=> %User{name: "john"}
opts = [name: "meg"]
user = struct(User, opts)
#=> %User{name: "meg"}
struct(user, unknown: "value")
#=> %User{name: "meg"}
struct(User, %{name: "meg"})
#=> %User{name: "meg"}
# String keys are ignored
struct(User, %{"name" => "meg"})
#=> %User{name: "john"}
"""
@spec struct(module | struct, Enumerable.t()) :: struct
def struct(struct, fields \\ []) do
struct(struct, fields, fn
{:__struct__, _val}, acc ->
acc
{key, val}, acc ->
case acc do
%{^key => _} -> %{acc | key => val}
_ -> acc
end
end)
end
@doc """
Similar to `struct/2` but checks for key validity.
The function `struct!/2` emulates the compile time behavior
of structs. This means that:
* when building a struct, as in `struct!(SomeStruct, key: :value)`,
it is equivalent to `%SomeStruct{key: :value}` and therefore this
function will check if every given key-value belongs to the struct.
If the struct is enforcing any key via `@enforce_keys`, those will
be enforced as well;
* when updating a struct, as in `struct!(%SomeStruct{}, key: :value)`,
it is equivalent to `%SomeStruct{struct | key: :value}` and therefore this
function will check if every given key-value belongs to the struct.
"""
@spec struct!(module | struct, Enumerable.t()) :: struct
def struct!(struct, fields \\ [])
def struct!(struct, fields) when is_atom(struct) do
validate_struct!(struct.__struct__(fields), struct, 1)
end
def struct!(struct, fields) when is_map(struct) do
struct(struct, fields, fn
{:__struct__, _}, acc ->
acc
{key, val}, acc ->
Map.replace!(acc, key, val)
end)
end
defp struct(struct, [], _fun) when is_atom(struct) do
validate_struct!(struct.__struct__(), struct, 0)
end
defp struct(struct, fields, fun) when is_atom(struct) do
struct(validate_struct!(struct.__struct__(), struct, 0), fields, fun)
end
defp struct(%_{} = struct, [], _fun) do
struct
end
defp struct(%_{} = struct, fields, fun) do
Enum.reduce(fields, struct, fun)
end
defp validate_struct!(%{__struct__: module} = struct, module, _arity) do
struct
end
defp validate_struct!(%{__struct__: struct_name}, module, arity) when is_atom(struct_name) do
error_message =
"expected struct name returned by #{inspect(module)}.__struct__/#{arity} to be " <>
"#{inspect(module)}, got: #{inspect(struct_name)}"
:erlang.error(ArgumentError.exception(error_message))
end
defp validate_struct!(expr, module, arity) do
error_message =
"expected #{inspect(module)}.__struct__/#{arity} to return a map with a :__struct__ " <>
"key that holds the name of the struct (atom), got: #{inspect(expr)}"
:erlang.error(ArgumentError.exception(error_message))
end
@doc """
Returns `true` if `term` is a struct, otherwise returns `false`.
Allowed in guard tests.
## Examples
iex> is_struct(URI.parse("/"))
true
iex> is_struct(%{})
false
"""
@doc since: "1.10.0", guard: true
defmacro is_struct(term) do
case __CALLER__.context do
nil ->
quote do
case unquote(term) do
%_{} -> true
_ -> false
end
end
:match ->
invalid_match!(:is_struct)
:guard ->
quote do
is_map(unquote(term)) and :erlang.is_map_key(:__struct__, unquote(term)) and
is_atom(:erlang.map_get(:__struct__, unquote(term)))
end
end
end
@doc """
Returns `true` if `term` is a struct of `name`, otherwise returns `false`.
`is_struct/2` does not check that `name` exists and is a valid struct.
If you want such validations, you must pattern match on the struct
instead, such as `match?(%URI{}, arg)`.
Allowed in guard tests.
## Examples
iex> is_struct(URI.parse("/"), URI)
true
iex> is_struct(URI.parse("/"), Macro.Env)
false
"""
@doc since: "1.11.0", guard: true
defmacro is_struct(term, name) do
case __CALLER__.context do
nil ->
quote generated: true do
case unquote(name) do
name when is_atom(name) ->
case unquote(term) do
%{__struct__: ^name} -> true
_ -> false
end
_ ->
raise ArgumentError
end
end
:match ->
invalid_match!(:is_struct)
:guard ->
quote do
is_map(unquote(term)) and
(is_atom(unquote(name)) or :fail) and
:erlang.is_map_key(:__struct__, unquote(term)) and
:erlang.map_get(:__struct__, unquote(term)) == unquote(name)
end
end
end
@doc """
Returns `true` if `term` is a map that is not a struct, otherwise
returns `false`.
Allowed in guard tests.
## Examples
iex> is_non_struct_map(%{})
true
iex> is_non_struct_map(URI.parse("/"))
false
iex> is_non_struct_map(nil)
false
"""
@doc since: "1.17.0", guard: true
defmacro is_non_struct_map(term) do
case __CALLER__.context do
nil ->
quote do
case unquote(term) do
%_{} -> false
%{} -> true
_ -> false
end
end
:match ->
invalid_match!(:is_non_struct_map)
:guard ->
quote do
is_map(unquote(term)) and
not (:erlang.is_map_key(:__struct__, unquote(term)) and
is_atom(:erlang.map_get(:__struct__, unquote(term))))
end
end
end
@doc """
Returns `true` if `term` is an exception, otherwise returns `false`.
Allowed in guard tests.
## Examples
iex> is_exception(%RuntimeError{})
true
iex> is_exception(%{})
false
"""
@doc since: "1.11.0", guard: true
defmacro is_exception(term) do
case __CALLER__.context do
nil ->
quote do
case unquote(term) do
%_{__exception__: true} -> true
_ -> false
end
end
:match ->
invalid_match!(:is_exception)
:guard ->
quote do
is_map(unquote(term)) and :erlang.is_map_key(:__struct__, unquote(term)) and
is_atom(:erlang.map_get(:__struct__, unquote(term))) and
:erlang.is_map_key(:__exception__, unquote(term)) and
:erlang.map_get(:__exception__, unquote(term)) == true
end
end
end
@doc """
Returns `true` if `term` is an exception of `name`, otherwise returns `false`.
Allowed in guard tests.
## Examples
iex> is_exception(%RuntimeError{}, RuntimeError)
true
iex> is_exception(%RuntimeError{}, Macro.Env)
false
"""
@doc since: "1.11.0", guard: true
defmacro is_exception(term, name) do
case __CALLER__.context do
nil ->
quote do
case unquote(name) do
name when is_atom(name) ->
case unquote(term) do
%{__struct__: ^name, __exception__: true} -> true
_ -> false
end
_ ->
raise ArgumentError
end
end
:match ->
invalid_match!(:is_exception)
:guard ->
quote do
is_map(unquote(term)) and
(is_atom(unquote(name)) or :fail) and
:erlang.is_map_key(:__struct__, unquote(term)) and
:erlang.map_get(:__struct__, unquote(term)) == unquote(name) and
:erlang.is_map_key(:__exception__, unquote(term)) and
:erlang.map_get(:__exception__, unquote(term)) == true
end
end
end
@doc """
Pipes the first argument, `value`, into the second argument, a function `fun`,
and returns the result of calling `fun`.
In other words, it invokes the function `fun` with `value` as argument,
and returns its result.
This is most commonly used in pipelines, using the `|>/2` operator, allowing you
to pipe a value to a function outside of its first argument.
## Examples
iex> 1 |> then(fn x -> x * 2 end)
2
iex> 1 |> then(fn x -> Enum.drop(["a", "b", "c"], x) end)
["b", "c"]
"""
@doc since: "1.12.0"
defmacro then(value, fun) do
quote do
unquote(fun).(unquote(value))
end
end
@doc """
Gets a value from a nested structure with nil-safe handling.
Uses the `Access` module to traverse the structures
according to the given `keys`, unless the `key` is a
function, which is detailed in a later section.
## Examples
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_in(users, ["john", :age])
27
iex> # Equivalent to:
iex> users["john"][:age]
27
`get_in/2` can also use the accessors in the `Access` module
to traverse more complex data structures. For example, here we
use `Access.all/0` to traverse a list:
iex> users = [%{name: "john", age: 27}, %{name: "meg", age: 23}]
iex> get_in(users, [Access.all(), :age])
[27, 23]
In case any of the components returns `nil`, `nil` will be returned
and `get_in/2` won't traverse any further:
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_in(users, ["unknown", :age])
nil
iex> # Equivalent to:
iex> users["unknown"][:age]
nil
## Functions as keys
If a key given to `get_in/2` is a function, the function will be invoked
passing three arguments:
* the operation (`:get`)
* the data to be accessed
* a function to be invoked next
This means `get_in/2` can be extended to provide custom lookups.
That's precisely how the `Access.all/0` key in the previous section
behaves. For example, we can manually implement such traversal as
follows:
iex> users = [%{name: "john", age: 27}, %{name: "meg", age: 23}]
iex> all = fn :get, data, next -> Enum.map(data, next) end
iex> get_in(users, [all, :age])
[27, 23]
The `Access` module ships with many convenience accessor functions.
See `Access.all/0`, `Access.key/2`, and others as examples.
## Working with structs
By default, structs do not implement the `Access` behaviour required
by this function. Therefore, you can't do this:
get_in(some_struct, [:some_key, :nested_key])
There are two alternatives. Given structs have predefined keys,
we can use the `struct.field` notation:
some_struct.some_key.nested_key
However, the code above will fail if any of the values return `nil`.
If you also want to handle nil values, you can use `get_in/1`:
get_in(some_struct.some_key.nested_key)
Pattern-matching is another option for handling such cases,
which can be especially useful if you want to match on several
fields at once or provide custom return values:
case some_struct do
%{some_key: %{nested_key: value}} -> value
%{} -> nil
end
"""
@spec get_in(Access.t(), nonempty_list(term)) :: term
def get_in(data, keys)
def get_in(nil, [_ | _]), do: nil
def get_in(data, [h]) when is_function(h), do: h.(:get, data, & &1)
def get_in(data, [h | t]) when is_function(h), do: h.(:get, data, &get_in(&1, t))
def get_in(data, [h]), do: Access.get(data, h)
def get_in(data, [h | t]), do: get_in(Access.get(data, h), t)
@doc """
Puts a value in a nested structure.
Uses the `Access` module to traverse the structures
according to the given `keys`, unless the `key` is a
function. If the key is a function, it will be invoked
as specified in `get_and_update_in/3`.
## Examples
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> put_in(users, ["john", :age], 28)
%{"john" => %{age: 28}, "meg" => %{age: 23}}
If any of the intermediate values are nil, it will raise:
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> put_in(users, ["jane", :age], "oops")
** (ArgumentError) could not put/update key :age on a nil value
"""
@spec put_in(Access.t(), nonempty_list(term), term) :: Access.t()
def put_in(data, [_ | _] = keys, value) do
elem(get_and_update_in(data, keys, fn _ -> {nil, value} end), 1)
end
@doc """
Updates a key in a nested structure.
Uses the `Access` module to traverse the structures
according to the given `keys`, unless the `key` is a
function. If the key is a function, it will be invoked
as specified in `get_and_update_in/3`.
`data` is a nested structure (that is, a map, keyword
list, or struct that implements the `Access` behaviour).
The `fun` argument receives the value of `key` (or `nil`
if `key` is not present) and the result replaces the value
in the structure.
## Examples
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> update_in(users, ["john", :age], &(&1 + 1))
%{"john" => %{age: 28}, "meg" => %{age: 23}}
Note the current value given to the anonymous function may be `nil`.
If any of the intermediate values are nil, it will raise:
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> update_in(users, ["jane", :age], & &1 + 1)
** (ArgumentError) could not put/update key :age on a nil value
"""
@spec update_in(Access.t(), nonempty_list(term), (term -> term)) :: Access.t()
def update_in(data, [_ | _] = keys, fun) when is_function(fun) do
elem(get_and_update_in(data, keys, fn x -> {nil, fun.(x)} end), 1)
end
@doc """
Gets a value and updates a nested structure.
`data` is a nested structure (that is, a map, keyword
list, or struct that implements the `Access` behaviour).
The `fun` argument receives the value of `key` (or `nil` if `key`
is not present) and must return one of the following values:
* a two-element tuple `{current_value, new_value}`. In this case,
`current_value` is the retrieved value which can possibly be operated on before
being returned. `new_value` is the new value to be stored under `key`.
* `:pop`, which implies that the current value under `key`
should be removed from the structure and returned.
This function uses the `Access` module to traverse the structures
according to the given `keys`, unless the `key` is a function,
which is detailed in a later section.
## Examples
This function is useful when there is a need to retrieve the current
value (or something calculated in function of the current value) and
update it at the same time. For example, it could be used to read the
current age of a user while increasing it by one in one pass:
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_and_update_in(users, ["john", :age], &{&1, &1 + 1})
{27, %{"john" => %{age: 28}, "meg" => %{age: 23}}}
Note the current value given to the anonymous function may be `nil`.
If any of the intermediate values are nil, it will raise:
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_and_update_in(users, ["jane", :age], &{&1, &1 + 1})
** (ArgumentError) could not put/update key :age on a nil value
## Functions as keys
If a key is a function, the function will be invoked passing three
arguments:
* the operation (`:get_and_update`)
* the data to be accessed
* a function to be invoked next
This means `get_and_update_in/3` can be extended to provide custom
lookups. The downside is that functions cannot be stored as keys
in the accessed data structures.
When one of the keys is a function, the function is invoked.
In the example below, we use a function to get and increment all
ages inside a list:
iex> users = [%{name: "john", age: 27}, %{name: "meg", age: 23}]
iex> all = fn :get_and_update, data, next ->
...> data |> Enum.map(next) |> Enum.unzip()
...> end
iex> get_and_update_in(users, [all, :age], &{&1, &1 + 1})
{[27, 23], [%{name: "john", age: 28}, %{name: "meg", age: 24}]}
If the previous value before invoking the function is `nil`,
the function *will* receive `nil` as a value and must handle it
accordingly (be it by failing or providing a sane default).
The `Access` module ships with many convenience accessor functions,
like the `all` anonymous function defined above. See `Access.all/0`,
`Access.key/2`, and others as examples.
"""
@spec get_and_update_in(
structure,
keys,
(term | nil -> {current_value, new_value} | :pop)
) :: {current_value, new_structure :: structure}
when structure: Access.t(),
keys: nonempty_list(term),
current_value: Access.value(),
new_value: Access.value()
def get_and_update_in(data, keys, fun)
def get_and_update_in(data, [head], fun) when is_function(head, 3),
do: head.(:get_and_update, data, fun)
def get_and_update_in(data, [head | tail], fun) when is_function(head, 3),
do: head.(:get_and_update, data, &get_and_update_in(&1, tail, fun))
def get_and_update_in(data, [head], fun) when is_function(fun, 1),
do: Access.get_and_update(data, head, fun)
def get_and_update_in(data, [head | tail], fun) when is_function(fun, 1),
do: Access.get_and_update(data, head, &get_and_update_in(&1, tail, fun))
@doc """
Pops a key from the given nested structure.
Uses the `Access` protocol to traverse the structures
according to the given `keys`, unless the `key` is a
function. If the key is a function, it will be invoked
as specified in `get_and_update_in/3`.
## Examples
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> pop_in(users, ["john", :age])
{27, %{"john" => %{}, "meg" => %{age: 23}}}
In case any entry returns `nil`, its key will be removed
and the deletion will be considered a success.
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> pop_in(users, ["jane", :age])
{nil, %{"john" => %{age: 27}, "meg" => %{age: 23}}}
"""
@spec pop_in(data, nonempty_list(Access.get_and_update_fun(term, data) | term)) :: {term, data}
when data: Access.container()
def pop_in(data, keys)
def pop_in(nil, [key | _]) do
raise ArgumentError, "could not pop key #{inspect(key)} on a nil value"
end
def pop_in(data, [_ | _] = keys) do
pop_in_data(data, keys)
end
defp pop_in_data(nil, [_ | _]), do: :pop
defp pop_in_data(data, [fun]) when is_function(fun),
do: fun.(:get_and_update, data, fn _ -> :pop end)
defp pop_in_data(data, [fun | tail]) when is_function(fun),
do: fun.(:get_and_update, data, &pop_in_data(&1, tail))
defp pop_in_data(data, [key]), do: Access.pop(data, key)
defp pop_in_data(data, [key | tail]),
do: Access.get_and_update(data, key, &pop_in_data(&1, tail))
@doc """
Gets a key from the nested structure via the given `path`, with
nil-safe handling.
This is similar to `get_in/2`, except the path is extracted via
a macro rather than passing a list. For example:
get_in(opts[:foo][:bar])
Is equivalent to:
get_in(opts, [:foo, :bar])
Additionally, this macro can traverse structs:
get_in(struct.foo.bar)
In case any of the keys returns `nil`, then `nil` will be returned
and `get_in/1` won't traverse any further.
Note that in order for this macro to work, the complete path must always
be visible by this macro. For more information about the supported path
expressions, please check `get_and_update_in/2` docs.
## Examples
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_in(users["john"].age)
27
iex> get_in(users["unknown"].age)
nil
"""
@doc since: "1.17.0"
defmacro get_in(path) do
{[h | t], _} = unnest(path, [], true, "get_in/1")
nest_get_in(h, quote(do: x), t)
end
defp nest_get_in(h, _var, []) do
h
end
defp nest_get_in(h, var, [{:map, key} | tail]) do
quote generated: true do
case unquote(h) do
%{unquote(key) => unquote(var)} -> unquote(nest_get_in(var, var, tail))
nil -> nil
unquote(var) -> :erlang.error({:badkey, unquote(key), unquote(var)})
end
end
end
defp nest_get_in(h, var, [{:access, key} | tail]) do
h = quote do: Access.get(unquote(h), unquote(key))
nest_get_in(h, var, tail)
end
@doc """
Puts a value in a nested structure via the given `path`.
This is similar to `put_in/3`, except the path is extracted via
a macro rather than passing a list. For example:
put_in(opts[:foo][:bar], :baz)
Is equivalent to:
put_in(opts, [:foo, :bar], :baz)
This also works with nested structs and the `struct.path.to.value` way to specify
paths:
put_in(struct.foo.bar, :baz)
Note that in order for this macro to work, the complete path must always
be visible by this macro. For more information about the supported path
expressions, please check `get_and_update_in/2` docs.
## Examples
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> put_in(users["john"][:age], 28)
%{"john" => %{age: 28}, "meg" => %{age: 23}}
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> put_in(users["john"].age, 28)
%{"john" => %{age: 28}, "meg" => %{age: 23}}
"""
defmacro put_in(path, value) do
case unnest(path, [], true, "put_in/2") do
{[h | t], true} ->
nest_map_update_in(h, t, quote(do: fn _ -> unquote(value) end))
{[h | t], false} ->
expr = nest_get_and_update_in(h, t, quote(do: fn _ -> {nil, unquote(value)} end))
quote(do: :erlang.element(2, unquote(expr)))
end
end
@doc """
Pops a key from the nested structure via the given `path`.
This is similar to `pop_in/2`, except the path is extracted via
a macro rather than passing a list. For example:
pop_in(opts[:foo][:bar])
Is equivalent to:
pop_in(opts, [:foo, :bar])
Note that in order for this macro to work, the complete path must always
be visible by this macro. For more information about the supported path
expressions, please check `get_and_update_in/2` docs.
## Examples
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> pop_in(users["john"][:age])
{27, %{"john" => %{}, "meg" => %{age: 23}}}
iex> users = %{john: %{age: 27}, meg: %{age: 23}}
iex> pop_in(users.john[:age])
{27, %{john: %{}, meg: %{age: 23}}}
In case any entry returns `nil`, its key will be removed
and the deletion will be considered a success.
"""
defmacro pop_in(path) do
{[h | t], _} = unnest(path, [], true, "pop_in/1")
nest_pop_in(:map, h, t)
end
@doc """
Updates a nested structure via the given `path`.
This is similar to `update_in/3`, except the path is extracted via
a macro rather than passing a list. For example:
update_in(opts[:foo][:bar], &(&1 + 1))
Is equivalent to:
update_in(opts, [:foo, :bar], &(&1 + 1))
This also works with nested structs and the `struct.path.to.value` way to specify
paths:
update_in(struct.foo.bar, &(&1 + 1))
Note that in order for this macro to work, the complete path must always
be visible by this macro. For more information about the supported path
expressions, please check `get_and_update_in/2` docs.
## Examples
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> update_in(users["john"][:age], &(&1 + 1))
%{"john" => %{age: 28}, "meg" => %{age: 23}}
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> update_in(users["john"].age, &(&1 + 1))
%{"john" => %{age: 28}, "meg" => %{age: 23}}
"""
defmacro update_in(path, fun) do
case unnest(path, [], true, "update_in/2") do
{[h | t], true} ->
nest_map_update_in(h, t, fun)
{[h | t], false} ->
expr = nest_get_and_update_in(h, t, quote(do: fn x -> {nil, unquote(fun).(x)} end))
quote(do: :erlang.element(2, unquote(expr)))
end
end
@doc """
Gets a value and updates a nested data structure via the given `path`.
This is similar to `get_and_update_in/3`, except the path is extracted
via a macro rather than passing a list. For example:
get_and_update_in(opts[:foo][:bar], &{&1, &1 + 1})
Is equivalent to:
get_and_update_in(opts, [:foo, :bar], &{&1, &1 + 1})
This also works with nested structs and the `struct.path.to.value` way to specify
paths:
get_and_update_in(struct.foo.bar, &{&1, &1 + 1})
Note that in order for this macro to work, the complete path must always
be visible by this macro. See the "Paths" section below.
## Examples
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_and_update_in(users["john"].age, &{&1, &1 + 1})
{27, %{"john" => %{age: 28}, "meg" => %{age: 23}}}
## Paths
A path may start with a variable, local or remote call, and must be
followed by one or more:
* `foo[bar]` - accesses the key `bar` in `foo`; in case `foo` is nil,
`nil` is returned
* `foo.bar` - accesses a map/struct field; in case the field is not
present, an error is raised
Here are some valid paths:
users["john"][:age]
users["john"].age
User.all()["john"].age
all_users()["john"].age
Here are some invalid ones:
# Does a remote call after the initial value
users["john"].do_something(arg1, arg2)
# Does not access any key or field
users
"""
defmacro get_and_update_in(path, fun) do
{[h | t], _} = unnest(path, [], true, "get_and_update_in/2")
nest_get_and_update_in(h, t, fun)
end
defp nest_map_update_in([], fun), do: fun
defp nest_map_update_in(list, fun) do
quote do
fn x -> unquote(nest_map_update_in(quote(do: x), list, fun)) end
end
end
defp nest_map_update_in(h, [{:map, key} | t], fun) do
quote do
Map.update!(unquote(h), unquote(key), unquote(nest_map_update_in(t, fun)))
end
end
defp nest_get_and_update_in([], fun), do: fun
defp nest_get_and_update_in(list, fun) do
quote do
fn x -> unquote(nest_get_and_update_in(quote(do: x), list, fun)) end
end
end
defp nest_get_and_update_in(h, [{:access, key} | t], fun) do
quote do
Access.get_and_update(unquote(h), unquote(key), unquote(nest_get_and_update_in(t, fun)))
end
end
defp nest_get_and_update_in(h, [{:map, key} | t], fun) do
quote do
Map.get_and_update!(unquote(h), unquote(key), unquote(nest_get_and_update_in(t, fun)))
end
end
defp nest_pop_in(kind, list) do
quote do
fn x -> unquote(nest_pop_in(kind, quote(do: x), list)) end
end
end
defp nest_pop_in(:map, h, [{:access, key}]) do
quote generated: true do
case unquote(h) do
nil -> {nil, nil}
h -> Access.pop(h, unquote(key))
end
end
end
defp nest_pop_in(_, _, [{:map, key}]) do
raise ArgumentError,
"cannot use pop_in when the last segment is a map/struct field. " <>
"This would effectively remove the field #{inspect(key)} from the map/struct"
end
defp nest_pop_in(_, h, [{:map, key} | t]) do
quote do
Map.get_and_update!(unquote(h), unquote(key), unquote(nest_pop_in(:map, t)))
end
end
defp nest_pop_in(_, h, [{:access, key}]) do
quote generated: true do
case unquote(h) do
nil -> :pop
h -> Access.pop(h, unquote(key))
end
end
end
defp nest_pop_in(_, h, [{:access, key} | t]) do
quote do
Access.get_and_update(unquote(h), unquote(key), unquote(nest_pop_in(:access, t)))
end
end
defp unnest({{:., _, [Access, :get]}, _, [expr, key]}, acc, _all_map?, kind) do
unnest(expr, [{:access, key} | acc], false, kind)
end
defp unnest({{:., _, [expr, key]}, _, []}, acc, all_map?, kind)
when is_tuple(expr) and :erlang.element(1, expr) != :__aliases__ and
:erlang.element(1, expr) != :__MODULE__ do
unnest(expr, [{:map, key} | acc], all_map?, kind)
end
defp unnest(other, [], _all_map?, kind) do
raise ArgumentError,
"expected expression given to #{kind} to access at least one element, " <>
"got: #{Macro.to_string(other)}"
end
defp unnest(other, acc, all_map?, kind) do
case proper_start?(other) do
true ->
{[other | acc], all_map?}
false ->
raise ArgumentError,
"expression given to #{kind} must start with a variable, local or remote call " <>
"and be followed by an element access, got: #{Macro.to_string(other)}"
end
end
defp proper_start?({{:., _, [expr, _]}, _, _args})
when is_atom(expr)
when :erlang.element(1, expr) == :__aliases__
when :erlang.element(1, expr) == :__MODULE__,
do: true
defp proper_start?({atom, _, _args})
when is_atom(atom),
do: true
defp proper_start?(other), do: not is_tuple(other)
@doc """
Converts the argument to a string according to the
`String.Chars` protocol.
This is invoked when there is string interpolation.
## Examples
iex> to_string(:foo)
"foo"
"""
defmacro to_string(term) do
quote(do: :"Elixir.String.Chars".to_string(unquote(term)))
end
@doc """
Converts the given term to a charlist according to the `List.Chars` protocol.
## Examples
iex> to_charlist(:foo)
~c"foo"
"""
defmacro to_charlist(term) do
quote(do: :"Elixir.List.Chars".to_charlist(unquote(term)))
end
@doc """
Returns `true` if `term` is `nil`, `false` otherwise.
Allowed in guard clauses.
## Examples
iex> is_nil(1 + 2)
false
iex> is_nil(nil)
true
"""
@doc guard: true
defmacro is_nil(term) do
quote(do: unquote(term) == nil)
end
@doc """
A convenience macro that checks if the result of `expression` matches `pattern`.
## Examples
iex> match?(1, 1)
true
iex> match?({1, _}, {1, 2})
true
iex> map = %{a: 1, b: 2}
iex> match?(%{a: _}, map)
true
iex> a = 1
iex> match?(^a, 1)
true
`match?/2` is very useful when filtering or finding a value in an enumerable:
iex> list = [a: 1, b: 2, a: 3]
iex> Enum.filter(list, &match?({:a, _}, &1))
[a: 1, a: 3]
Guard clauses can also be given to the match:
iex> list = [a: 1, b: 2, a: 3]
iex> Enum.filter(list, &match?({:a, x} when x < 2, &1))
[a: 1]
Variables assigned in the match will not be available outside of the
function call (unlike regular pattern matching with the `=` operator):
iex> match?(_x, 1)
true
iex> binding()
[]
## Values vs patterns
Remember the pin operator matches _values_, not _patterns_.
Passing a variable as the pattern will always return `true` and will
result in a warning that the variable is unused. Don't do this:
pattern = %{a: :a}
match?(pattern, %{b: :b})
#=> true
Similarly, moving an expression out the pattern may no longer preserve
its semantics. For example:
iex> match?([_ | _], [1, 2, 3])
true
pattern = [_ | _]
match?(pattern, [1, 2, 3])
** (CompileError) invalid use of _. _ can only be used inside patterns to ignore values and cannot be used in expressions. Make sure you are inside a pattern or change it accordingly
Another example is that a map as a pattern performs a subset match, but not
once assigned to a variable:
iex> match?(%{x: 1}, %{x: 1, y: 2})
true
iex> attrs = %{x: 1}
iex> match?(^attrs, %{x: 1, y: 2})
false
The pin operator will check if the values are equal, using `===/2`, while
patterns have their own rules when matching maps, lists, and so forth.
Such behavior is not specific to `match?/2`. The following code also
throws an exception:
attrs = %{x: 1}
^attrs = %{x: 1, y: 2}
#=> (MatchError) no match of right hand side value: %{x: 1, y: 2}
"""
defmacro match?(pattern, expression) do
success =
quote do
unquote(pattern) -> true
end
failure =
quote generated: true do
_ -> false
end
{:case, [], [expression, [do: success ++ failure]]}
end
@doc """
Module attribute unary operator.
Reads and writes attributes in the current module.
The canonical example for attributes is annotating that a module
implements an OTP behaviour, such as `GenServer`:
defmodule MyServer do
@behaviour GenServer
# ... callbacks ...
end
By default Elixir supports all the module attributes supported by Erlang, but
custom attributes can be used as well:
defmodule MyServer do
@my_data 13
IO.inspect(@my_data)
#=> 13
end
Unlike Erlang, such attributes are not stored in the module by default since
it is common in Elixir to use custom attributes to store temporary data that
will be available at compile-time. Custom attributes may be configured to
behave closer to Erlang by using `Module.register_attribute/3`.
> #### Prefixing module attributes {: .tip}
>
> Libraries and frameworks should consider prefixing any
> module attributes that are private by underscore, such as `@_my_data`,
> so code completion tools do not show them on suggestions and prompts.
Finally, note that attributes can also be read inside functions:
defmodule MyServer do
@my_data 11
def first_data, do: @my_data
@my_data 13
def second_data, do: @my_data
end
MyServer.first_data()
#=> 11
MyServer.second_data()
#=> 13
It is important to note that reading an attribute takes a snapshot of
its current value. In other words, the value is read at compilation
time and not at runtime. Check the `Module` module for other functions
to manipulate module attributes.
## Attention! Multiple references of the same attribute
As mentioned above, every time you read a module attribute, a snapshot
of its current value is taken. Therefore, if you are storing large
values inside module attributes (for example, embedding external files
in module attributes), you should avoid referencing the same attribute
multiple times. For example, don't do this:
@files %{
example1: File.read!("lib/example1.data"),
example2: File.read!("lib/example2.data")
}
def example1, do: @files[:example1]
def example2, do: @files[:example2]
In the above, each reference to `@files` may end-up with a complete
and individual copy of the whole `@files` module attribute. Instead,
reference the module attribute once in a private function:
@files %{
example1: File.read!("lib/example1.data"),
example2: File.read!("lib/example2.data")
}
defp files(), do: @files
def example1, do: files()[:example1]
def example2, do: files()[:example2]
"""
defmacro @expr
defmacro @{:__aliases__, _meta, _args} do
raise ArgumentError, "module attributes set via @ cannot start with an uppercase letter"
end
defmacro @{name, meta, args} do
assert_module_scope(__CALLER__, :@, 1)
function? = __CALLER__.function != nil
cond do
# Check for Macro as it is compiled later than Kernel
not bootstrapped?(Macro) ->
nil
not function? and (__CALLER__.context == :match or __CALLER__.context == :guard) ->
raise ArgumentError,
"""
invalid usage of module attributes. Module attributes cannot be used inside \
pattern matching (and guards) outside of a function. If you are trying to \
define an attribute, do not do this:
@foo = :value
Instead, do this:
@foo :value
"""
# Typespecs attributes are currently special cased by the compiler
is_list(args) and typespec?(name) ->
case bootstrapped?(Kernel.Typespec) do
false ->
:ok
true ->
pos = :elixir_module.cache_env(__CALLER__)
%{line: line, file: file, module: module} = __CALLER__
quote do
Kernel.Typespec.deftypespec(
unquote(name),
unquote(Macro.escape(hd(args), unquote: true)),
unquote(line),
unquote(file),
unquote(module),
unquote(pos)
)
end
end
true ->
do_at(args, meta, name, function?, __CALLER__)
end
end
# @attribute(value)
defp do_at([arg], meta, name, function?, env) do
line =
case :lists.keymember(:context, 1, meta) do
true -> nil
false -> env.line
end
cond do
function? ->
raise ArgumentError, "cannot set attribute @#{name} inside function/macro"
name == :behavior ->
raise ArgumentError, "@behavior attribute is not supported, please use @behaviour instead"
:lists.member(name, [:moduledoc, :typedoc, :doc]) ->
arg = {env.line, arg}
quote do
Module.__put_attribute__(__MODULE__, unquote(name), unquote(arg), unquote(line), [])
end
true ->
{arg, traces} = collect_traces(name, arg, env)
quote do
Module.__put_attribute__(
__MODULE__,
unquote(name),
unquote(arg),
unquote(line),
unquote(Macro.escape(traces))
)
end
end
end
# @attribute()
defp do_at([], meta, name, function?, env) do
IO.warn(
"the @#{name}() notation (with parentheses) is deprecated, please use @#{name} (without parentheses) instead",
env
)
do_at(nil, meta, name, function?, env)
end
# @attribute
defp do_at(args, _meta, name, function?, env) when is_atom(args) do
line = env.line
doc_attr? = :lists.member(name, [:moduledoc, :typedoc, :doc])
case function? do
true ->
case Module.__get_attribute__(env.module, name, line, false) do
{_, doc} when doc_attr? ->
do_at_escape(name, doc)
value ->
do_at_escape(name, value)
end
false when doc_attr? ->
quote do
case Module.__get_attribute__(__MODULE__, unquote(name), unquote(line), false) do
{_, doc} -> doc
value -> value
end
end
false ->
quote do
Module.__get_attribute__(__MODULE__, unquote(name), unquote(line), true)
end
end
end
# Error cases
defp do_at([{call, meta, ctx_or_args}, [{:do, _} | _] = kw], _meta, name, _function?, _env) do
args =
case is_atom(ctx_or_args) do
true -> []
false -> ctx_or_args
end
code = "\n@#{name} (#{Macro.to_string({call, meta, args ++ [kw]})})"
raise ArgumentError, """
expected 0 or 1 argument for @#{name}, got 2.
It seems you are trying to use the do-syntax with @module attributes \
but the do-block binds to the attribute name. You probably want \
to wrap the argument value in parentheses, like this:
#{String.replace(code, "\n", "\n ")}
"""
end
defp do_at(args, _meta, name, _function?, _env) do
raise ArgumentError, "expected 0 or 1 argument for @#{name}, got: #{length(args)}"
end
defp do_at_escape(name, value) do
try do
# mark module attrs as shallow-generated since the ast for their representation
# might contain opaque terms
Macro.escape(value, generated: true)
rescue
ex in [ArgumentError] ->
raise ArgumentError,
"cannot inject attribute @#{name} into function/macro because " <>
Exception.message(ex)
end
end
# Those are always compile-time dependencies, so we can skip the trace.
defp collect_traces(:before_compile, arg, _env), do: {arg, []}
defp collect_traces(:after_compile, arg, _env), do: {arg, []}
defp collect_traces(:after_verify, arg, _env), do: {arg, []}
defp collect_traces(:on_definition, arg, _env), do: {arg, []}
defp collect_traces(_name, arg, %{lexical_tracker: pid} = env) when is_pid(pid) do
env = %{env | function: {:__info__, 1}}
{arg, aliases} =
Macro.expand_literals(arg, %{}, fn
{:__aliases__, _, _} = alias, acc ->
case Macro.expand(alias, env) do
atom when is_atom(atom) -> {atom, Map.put(acc, atom, [])}
_ -> {alias, acc}
end
node, acc ->
{Macro.expand(node, env), acc}
end)
case map_size(aliases) do
0 -> {arg, []}
_ -> {arg, [{env.line, env.lexical_tracker, env.tracers, :maps.keys(aliases)}]}
end
end
defp collect_traces(_name, arg, _env) do
{arg, []}
end
defp typespec?(:type), do: true
defp typespec?(:typep), do: true
defp typespec?(:opaque), do: true
defp typespec?(:spec), do: true
defp typespec?(:callback), do: true
defp typespec?(:macrocallback), do: true
defp typespec?(_), do: false
@doc """
Returns the binding for the given context as a keyword list.
In the returned result, keys are variable names and values are the
corresponding variable values.
If the given `context` is `nil` (by default it is), the binding for the
current context is returned.
## Examples
iex> x = 1
iex> binding()
[x: 1]
iex> x = 2
iex> binding()
[x: 2]
iex> binding(:foo)
[]
iex> var!(x, :foo) = 1
1
iex> binding(:foo)
[x: 1]
"""
defmacro binding(context \\ nil) do
in_match? = Macro.Env.in_match?(__CALLER__)
bindings =
for {v, c} <- Macro.Env.vars(__CALLER__), c == context do
{v, wrap_binding(in_match?, {v, [generated: true], c})}
end
:lists.usort(bindings)
end
defp wrap_binding(true, var) do
quote(do: ^unquote(var))
end
defp wrap_binding(_, var) do
var
end
@doc """
Provides an `if/2` macro.
This macro expects the first argument to be a condition and the second
argument to be a keyword list. Generally speaking, Elixir developers
prefer to use pattern matching and guards in function definitions and
`case/2`, as they are succinct and precise. However, not all conditions
can be expressed through patterns and guards, which makes `if/2` a viable
alternative.
Similar to `case/2`, any assignment in the condition will be available
on both clauses, as well as after the `if` expression.
## One-liner examples
iex> if 7 > 5, do: "yes"
"yes"
iex> if "truthy value", do: "yes"
"yes"
In the examples above, the `do` clause is evaluated and `"yes"` will be returned
because the condition evaluates to a truthy value (neither `false` nor `nil`).
Otherwise, the clause is not evaluated and `nil` will be returned:
iex> if 3 > 5, do: "yes"
nil
iex> if nil, do: IO.puts("this won't be printed")
nil
An `else` option can be given to specify the opposite:
iex> if 3 > 5, do: "yes", else: "no"
"no"
## Blocks examples
It's also possible to pass a block to the `if/2` macro. The first
example above would be translated to:
iex> if 7 > 5 do
...> "yes"
...> end
"yes"
Note that `do`-`end` become delimiters. The third example would
translate to:
iex> if 3 > 5 do
...> "yes"
...> else
...> "no"
...> end
"no"
If you find yourself nesting conditionals inside conditionals,
consider using `cond/1`.
## Variables scope
Variables set within `do`/`else` blocks do not leak to the outer context:
x = 1
if x > 0 do
x = x + 1
IO.puts(x) # prints 2
end
x # 1
Variables set in the condition are available in the outer context:
fruits = %{oranges: 3}
if count = fruits[:apples] do
# won't be evaluated
IO.puts(count + 1)
end
count # nil
"""
defmacro if(condition, clauses) do
build_if(condition, clauses)
end
defp build_if(condition, do: do_clause) do
build_if(condition, do: do_clause, else: nil)
end
defp build_if(condition, do: do_clause, else: else_clause) do
annotate_case(
[optimize_boolean: true, type_check: :expr],
quote do
case unquote(condition) do
x when unquote(x_is_false_or_nil()) -> unquote(else_clause)
_ -> unquote(do_clause)
end
end
)
end
defp build_if(_condition, _arguments) do
raise ArgumentError,
"invalid or duplicate keys for if, only \"do\" and an optional \"else\" are permitted"
end
@doc """
Provides an `unless` macro.
This macro evaluates and returns the `do` block passed in as the second
argument if `condition` evaluates to a falsy value (`false` or `nil`).
Otherwise, it returns the value of the `else` block if present or `nil` if not.
See also `if/2`.
## Examples
iex> unless(Enum.empty?([]), do: "Hello")
nil
iex> unless(Enum.empty?([1, 2, 3]), do: "Hello")
"Hello"
iex> unless Enum.sum([2, 2]) == 5 do
...> "Math still works"
...> else
...> "Math is broken"
...> end
"Math still works"
"""
# TODO: Deprecate this on Elixir v1.22.
@doc deprecated: "Use if/2 instead"
defmacro unless(condition, clauses) do
build_unless(condition, clauses)
end
defp build_unless(condition, do: do_clause) do
build_unless(condition, do: do_clause, else: nil)
end
defp build_unless(condition, do: do_clause, else: else_clause) do
quote do
if(unquote(condition), do: unquote(else_clause), else: unquote(do_clause))
end
end
defp build_unless(_condition, _arguments) do
raise ArgumentError,
"invalid or duplicate keys for unless, " <>
"only \"do\" and an optional \"else\" are permitted"
end
@doc """
Destructures two lists, assigning each term in the
right one to the matching term in the left one.
Unlike pattern matching via `=`, if the sizes of the left
and right lists don't match, destructuring simply stops
instead of raising an error.
## Examples
iex> destructure([x, y, z], [1, 2, 3, 4, 5])
iex> {x, y, z}
{1, 2, 3}
In the example above, even though the right list has more entries than the
left one, destructuring works fine. If the right list is smaller, the
remaining elements are simply set to `nil`:
iex> destructure([x, y, z], [1])
iex> {x, y, z}
{1, nil, nil}
The left-hand side supports any expression you would use
on the left-hand side of a match:
iex> x = 1
iex> destructure([^x, y, z], [1, 2, 3])
iex> {x, y, z}
{1, 2, 3}
The example above will only work if `x` matches the first value in the right
list. Otherwise, it will raise a `MatchError` (like the `=` operator would
do).
"""
defmacro destructure(left, right) when is_list(left) do
quote do
unquote(left) = Kernel.Utils.destructure(unquote(right), unquote(length(left)))
end
end
@doc """
Creates a range from `first` to `last`.
If first is less than last, the range will be increasing from
first to last. If first is equal to last, the range will contain
one element, which is the number itself.
If first is more than last, the range will be decreasing from first
to last, albeit this behavior is deprecated. Instead prefer to
explicitly list the step with `first..last//-1`.
See the `Range` module for more information.
## Examples
iex> 0 in 1..3
false
iex> 2 in 1..3
true
iex> Enum.to_list(1..3)
[1, 2, 3]
"""
defmacro first..last do
case bootstrapped?(Macro) do
true ->
first = Macro.expand(first, __CALLER__)
last = Macro.expand(last, __CALLER__)
validate_range!(first, last)
stepless_range(__CALLER__.context, first, last, __CALLER__)
false ->
stepless_range(__CALLER__.context, first, last, __CALLER__)
end
end
defp stepless_range(_context, first, last, caller)
when is_integer(first) and is_integer(last) do
step =
if first <= last do
1
else
# TODO: Always use 1 as an step in Elixir v2.0
IO.warn(
"#{first}..#{last} has a default step of -1, please write #{first}..#{last}//-1 instead",
Macro.Env.stacktrace(caller)
)
-1
end
{:%, [], [Elixir.Range, {:%{}, [], [first: first, last: last, step: step]}]}
end
defp stepless_range(nil, first, last, _caller) do
quote(do: Elixir.Range.new(unquote(first), unquote(last)))
end
defp stepless_range(:guard, first, last, caller) do
# We need to compute the step using guards. We don't have conditionals,
# but we can emulate them using a map access.
step =
quote do
:erlang.map_get(
:erlang.>(unquote(first), unquote(last)),
%{false: unquote(1), true: unquote(-1)}
)
end
# TODO: Always assume step 1 in Elixir v2.0
range = "#{Macro.to_string(first)}..#{Macro.to_string(last)}"
IO.warn(
"#{range} inside guards requires an explicit step, please write #{range}//1 or #{range}//-1 instead",
Macro.Env.stacktrace(caller)
)
{:%, [], [Elixir.Range, {:%{}, [], [first: first, last: last, step: step]}]}
end
defp stepless_range(:match, first, last, caller) do
# TODO: Make me an error in Elixir v2.0
range = "#{Macro.to_string(first)}..#{Macro.to_string(last)}"
IO.warn(
"#{range} inside match is deprecated, " <>
"you must always match on the step: #{range}//var or #{range}//_ if you want to ignore it",
Macro.Env.stacktrace(caller)
)
{:%, [], [Elixir.Range, {:%{}, [], [first: first, last: last]}]}
end
@doc """
Creates a range from `first` to `last` with `step`.
See the `Range` module for more information.
## Examples
iex> 0 in 1..3//1
false
iex> 2 in 1..3//1
true
iex> 2 in 1..3//2
false
iex> Enum.to_list(1..3//1)
[1, 2, 3]
iex> Enum.to_list(1..3//2)
[1, 3]
iex> Enum.to_list(3..1//-1)
[3, 2, 1]
iex> Enum.to_list(1..0//1)
[]
"""
@doc since: "1.12.0"
defmacro first..last//step do
case bootstrapped?(Macro) do
true ->
first = Macro.expand(first, __CALLER__)
last = Macro.expand(last, __CALLER__)
step = Macro.expand(step, __CALLER__)
validate_range!(first, last)
validate_step!(step)
range(__CALLER__.context, first, last, step)
false ->
{:%{}, [], [__struct__: Elixir.Range, first: first, last: last, step: step]}
end
end
defp range(context, first, last, step)
when is_integer(first) and is_integer(last) and is_integer(step)
when context != nil do
{:%, [], [Elixir.Range, {:%{}, [], [first: first, last: last, step: step]}]}
end
defp range(nil, first, last, step) do
quote(do: Elixir.Range.new(unquote(first), unquote(last), unquote(step)))
end
defp validate_range!(first, last)
when is_float(first) or is_float(last) or is_atom(first) or is_atom(last) or
is_binary(first) or is_binary(last) or is_list(first) or is_list(last) do
raise ArgumentError,
"ranges (first..last//step) expect both sides to be integers, " <>
"got: #{Macro.to_string({:.., [], [first, last]})}"
end
defp validate_range!(_, _), do: :ok
defp validate_step!(step)
when is_float(step) or is_atom(step) or is_binary(step) or is_list(step) or step == 0 do
raise ArgumentError,
"ranges (first..last//step) expect the step to be a non-zero integer, " <>
"got: #{Macro.to_string(step)}"
end
defp validate_step!(_), do: :ok
@doc """
Creates the full-slice range `0..-1//1`.
This macro returns a range with the following properties:
* When enumerated, it is empty
* When used as a `slice`, it returns the sliced element as is
See `..///3` and the `Range` module for more information.
## Examples
iex> Enum.to_list(..)
[]
iex> String.slice("Hello world!", ..)
"Hello world!"
"""
@doc since: "1.14.0"
defmacro (..) do
range(__CALLER__.context, 0, -1, 1)
end
@doc """
Boolean "and" operator.
Provides a short-circuit operator that evaluates and returns
the second expression only if the first one evaluates to a truthy value
(neither `false` nor `nil`). Returns the first expression
otherwise.
Not allowed in guard clauses.
## Examples
iex> Enum.empty?([]) && Enum.empty?([])
true
iex> List.first([]) && true
nil
iex> Enum.empty?([]) && List.first([1])
1
iex> false && throw(:bad)
false
Note that, unlike `and/2`, this operator accepts any expression
as the first argument, not only booleans.
"""
defmacro left && right do
assert_no_match_or_guard_scope(__CALLER__.context, "&&")
annotate_case(
[type_check: :expr],
quote do
case unquote(left) do
x when unquote(x_is_false_or_nil()) ->
x
_ ->
unquote(right)
end
end
)
end
@doc """
Boolean "or" operator.
Provides a short-circuit operator that evaluates and returns the second
expression only if the first one does not evaluate to a truthy value (that is,
it is either `nil` or `false`). Returns the first expression otherwise.
Not allowed in guard clauses.
## Examples
iex> Enum.empty?([1]) || Enum.empty?([1])
false
iex> List.first([]) || true
true
iex> Enum.empty?([1]) || 1
1
iex> Enum.empty?([]) || throw(:bad)
true
Note that, unlike `or/2`, this operator accepts any expression
as the first argument, not only booleans.
"""
defmacro left || right do
assert_no_match_or_guard_scope(__CALLER__.context, "||")
annotate_case(
[type_check: :expr],
quote do
case unquote(left) do
x when unquote(x_is_false_or_nil()) ->
unquote(right)
x ->
x
end
end
)
end
@doc """
Pipe operator.
This operator introduces the expression on the left-hand side as
the first argument to the function call on the right-hand side.
## Examples
iex> [1, [2], 3] |> List.flatten()
[1, 2, 3]
The example above is the same as calling `List.flatten([1, [2], 3])`.
The `|>/2` operator is mostly useful when there is a desire to execute a series
of operations resembling a pipeline:
iex> [1, [2], 3] |> List.flatten() |> Enum.map(fn x -> x * 2 end)
[2, 4, 6]
In the example above, the list `[1, [2], 3]` is passed as the first argument
to the `List.flatten/1` function, then the flattened list is passed as the
first argument to the `Enum.map/2` function which doubles each element of the
list.
In other words, the expression above simply translates to:
Enum.map(List.flatten([1, [2], 3]), fn x -> x * 2 end)
## Pitfalls
There are two common pitfalls when using the pipe operator.
The first one is related to operator precedence. For example,
the following expression:
String.graphemes "Hello" |> Enum.reverse
Translates to:
String.graphemes("Hello" |> Enum.reverse())
which results in an error as the `Enumerable` protocol is not defined
for binaries. Adding explicit parentheses resolves the ambiguity:
String.graphemes("Hello") |> Enum.reverse()
Or, even better:
"Hello" |> String.graphemes() |> Enum.reverse()
The second limitation is that Elixir always pipes to a function
call. Therefore, to pipe into an anonymous function, you need to
invoke it:
iex> some_fun = &Regex.replace(~r/l/, &1, "L")
iex> "Hello" |> some_fun.()
"HeLLo"
Alternatively, you can use `then/2` for the same effect:
iex> some_fun = &Regex.replace(~r/l/, &1, "L")
iex> "Hello" |> then(some_fun)
"HeLLo"
`then/2` is most commonly used when you want to pipe to a function
but the value is expected outside of the first argument, such as
above. By replacing `some_fun` by its value, we get:
iex> "Hello" |> then(&Regex.replace(~r/l/, &1, "L"))
"HeLLo"
"""
defmacro left |> right do
fun = fn {x, pos}, acc ->
Macro.pipe(acc, x, pos)
end
:lists.foldl(fun, left, Macro.unpipe(right))
end
@doc """
Returns `true` if `module` is loaded and contains a
public `function` with the given `arity`, otherwise `false`.
> ### Unloaded modules {: .warning}
>
> This function does *not* load the module in case it is not loaded
> and Elixir lazily loads modules by default (except on releases).
>
> This may lead to unexpected behaviour as the result of this function
> may depend if another code has happened to load the given module
> as argument beforehand. For example, this could manifest in `mix test`
> by having tests that fail when running in isolation or depending on the
> test seed. For those reasons, it is recommended to always check for
> `Code.ensure_loaded?/1` before `function_exported?/3`, unless you are
> certain the module has been loaded before.
>
> See `Code.ensure_loaded/1` for more information.
Inlined by the compiler.
## Examples
iex> Code.ensure_loaded?(Enum) and function_exported?(Enum, :map, 2)
true
iex> Code.ensure_loaded?(Enum) and function_exported?(Enum, :map, 10)
false
iex> Code.ensure_loaded?(List) and function_exported?(List, :to_string, 1)
true
"""
@spec function_exported?(module, atom, arity) :: boolean
def function_exported?(module, function, arity) do
:erlang.function_exported(module, function, arity)
end
@doc """
Returns `true` if `module` is loaded and contains a
public `macro` with the given `arity`, otherwise `false`.
Note that this function does not load the module in case
it is not loaded. See the notes under `function_exported?/3`
for more information.
If `module` is an Erlang module (as opposed to an Elixir module), this
function always returns `false`.
## Examples
iex> Code.ensure_loaded?(Kernel) and macro_exported?(Kernel, :use, 2)
true
iex> Code.ensure_loaded?(:erlang) and macro_exported?(:erlang, :abs, 1)
false
"""
@spec macro_exported?(module, atom, arity) :: boolean
def macro_exported?(module, macro, arity)
when is_atom(module) and is_atom(macro) and is_integer(arity) and
(arity >= 0 and arity <= 255) do
function_exported?(module, :__info__, 1) and
:lists.member({macro, arity}, module.__info__(:macros))
end
@doc """
Power operator.
It takes two numbers for input. If both are integers and the right-hand
side (the `exponent`) is also greater than or equal to 0, then the result
will also be an integer. Otherwise it returns a float.
## Examples
iex> 2 ** 2
4
iex> 2 ** -4
0.0625
iex> 2.0 ** 2
4.0
iex> 2 ** 2.0
4.0
"""
@doc since: "1.13.0"
@spec integer ** non_neg_integer :: integer
@spec integer ** neg_integer :: float
@spec float ** float :: float
@spec integer ** float :: float
@spec float ** integer :: float
def base ** exponent when is_integer(base) and is_integer(exponent) and exponent >= 0 do
integer_pow(base, 1, exponent)
end
def base ** exponent when is_number(base) and is_number(exponent) do
:math.pow(base, exponent)
end
# https://en.wikipedia.org/wiki/Exponentiation_by_squaring
defp integer_pow(_, _, 0),
do: 1
defp integer_pow(b, a, 1),
do: b * a
defp integer_pow(b, a, e) when :erlang.band(e, 1) == 0,
do: integer_pow(b * b, a, :erlang.bsr(e, 1))
defp integer_pow(b, a, e),
do: integer_pow(b * b, a * b, :erlang.bsr(e, 1))
@doc """
Membership operator.
Checks if the element on the left-hand side is a member of the
collection on the right-hand side.
## Examples
iex> x = 1
iex> x in [1, 2, 3]
true
This operator (which is a macro) simply translates to a call to
`Enum.member?/2`. The example above would translate to:
Enum.member?([1, 2, 3], x)
Elixir also supports `left not in right`, which evaluates to
`not(left in right)`:
iex> x = 1
iex> x not in [1, 2, 3]
false
## Guards
The `in/2` operator (as well as `not in`) can be used in guard clauses as
long as the right-hand side is a range or a list.
If the right-hand side is a list, Elixir will expand the operator to a valid
guard expression which needs to check each value. For example:
when x in [1, 2, 3]
translates to:
when x === 1 or x === 2 or x === 3
However, this construct will be inefficient for large lists. In such cases, it
is best to stop using guards and use a more appropriate data structure, such
as `MapSet`.
If the right-hand side is a range, a more efficient comparison check will be
done. For example:
when x in 1..1000
translates roughly to:
when x >= 1 and x <= 1000
### AST considerations
`left not in right` is parsed by the compiler into the AST:
{:not, _, [{:in, _, [left, right]}]}
This is the same AST as `not(left in right)`.
Additionally, `Macro.to_string/2` and `Code.format_string!/2`
will translate all occurrences of this AST to `left not in right`.
"""
@doc guard: true
defmacro left in right do
in_body? = __CALLER__.context == nil
expand =
case bootstrapped?(Macro) do
true -> &Macro.expand(&1, __CALLER__)
false -> & &1
end
case expand.(right) do
[] when not in_body? ->
false
[] ->
quote do
_ = unquote(left)
false
end
[head | tail] = list ->
# We only expand lists in the body if they are relatively
# short and it is made only of literal expressions.
case not in_body? or small_literal_list?(right) do
true -> in_var(in_body?, left, &in_list(&1, head, tail, expand, list, in_body?))
false -> quote(do: :lists.member(unquote(left), unquote(right)))
end
%{} = right ->
raise ArgumentError, "found unescaped value on the right side of in/2: #{inspect(right)}"
right ->
case range_fields(right) do
[first: first, last: last, step: step] ->
in_var(in_body?, left, &in_range(&1, expand.(first), expand.(last), expand.(step)))
_ when in_body? ->
quote(do: Elixir.Enum.member?(unquote(right), unquote(left)))
_ ->
raise_on_invalid_args_in_2(right)
end
end
end
defp range_fields({:%, _, [Elixir.Range, {:%{}, _, fields}]}), do: :lists.usort(fields)
defp range_fields({:%{}, _, [__struct__: Elixir.Range] ++ fields}), do: :lists.usort(fields)
defp range_fields(_), do: []
defp raise_on_invalid_args_in_2(right) do
raise ArgumentError, <<
"invalid right argument for operator \"in\", it expects a compile-time proper list ",
"or compile-time range on the right side when used in guard expressions, got: ",
Macro.to_string(right)::binary
>>
end
defp in_var(false, ast, fun), do: fun.(ast)
defp in_var(true, {atom, _, context} = var, fun) when is_atom(atom) and is_atom(context),
do: fun.(var)
defp in_var(true, var, fun) when is_atom(var) or is_binary(var) or is_number(var),
do: fun.(var)
defp in_var(true, ast, fun) do
quote do
var = unquote(ast)
unquote(fun.(quote(do: var)))
end
end
defp small_literal_list?(list) when is_list(list) and length(list) <= 32 do
:lists.all(fn x -> is_binary(x) or is_atom(x) or is_number(x) end, list)
end
defp small_literal_list?(_list), do: false
defp in_range(left, first, last, step) when is_integer(step) do
in_range_literal(left, first, last, step)
end
defp in_range(left, first, last, step) do
quoted =
quote do
unquote(generated_is_integer(left)) and unquote(generated_is_integer(first)) and
unquote(generated_is_integer(last)) and
((:erlang.>(unquote(step), 0) and
unquote(increasing_compare(left, first, last))) or
(:erlang.<(unquote(step), 0) and
unquote(decreasing_compare(left, first, last))))
end
in_range_step(quoted, left, first, step)
end
defp in_range_literal(left, first, first, _step) when is_integer(first) do
quote do: :erlang."=:="(unquote(left), unquote(first))
end
defp in_range_literal(left, first, last, step) when step > 0 do
quoted =
quote generated: true do
Kernel.and(
unquote(generated_is_integer(left)),
unquote(increasing_compare(left, first, last))
)
end
in_range_step(quoted, left, first, step)
end
defp in_range_literal(left, first, last, step) when step < 0 do
quoted =
quote generated: true do
Kernel.and(
unquote(generated_is_integer(left)),
unquote(decreasing_compare(left, first, last))
)
end
in_range_step(quoted, left, first, step)
end
defp in_range_step(quoted, _left, _first, step) when step == 1 or step == -1 do
quoted
end
defp in_range_step(quoted, left, first, step) do
quote do
Kernel.and(
unquote(quoted),
:erlang."=:="(:erlang.rem(unquote(left) - unquote(first), unquote(step)), 0)
)
end
end
defp in_list(left, head, tail, expand, right, in_body?) do
[head | tail] = :lists.map(&comp(left, &1, expand, right, in_body?), [head | tail])
:lists.foldl(&quote(do: Kernel.or(unquote(&2), unquote(&1))), head, tail)
end
defp comp(left, {:|, _, [head, tail]}, expand, right, in_body?) do
case expand.(tail) do
[] ->
quote(do: :erlang."=:="(unquote(left), unquote(head)))
[tail_head | tail] ->
quote do
Kernel.or(
:erlang."=:="(unquote(left), unquote(head)),
unquote(in_list(left, tail_head, tail, expand, right, in_body?))
)
end
tail when in_body? ->
quote do
Kernel.or(
:erlang."=:="(unquote(left), unquote(head)),
:lists.member(unquote(left), unquote(tail))
)
end
_ ->
raise_on_invalid_args_in_2(right)
end
end
defp comp(left, right, _expand, _right, _in_body?) do
quote(do: :erlang."=:="(unquote(left), unquote(right)))
end
defp generated_is_integer(arg) do
quote generated: true, do: :erlang.is_integer(unquote(arg))
end
defp increasing_compare(var, first, last) do
quote do
Kernel.and(
:erlang.>=(unquote(var), unquote(first)),
:erlang."=<"(unquote(var), unquote(last))
)
end
end
defp decreasing_compare(var, first, last) do
quote do
Kernel.and(
:erlang."=<"(unquote(var), unquote(first)),
:erlang.>=(unquote(var), unquote(last))
)
end
end
@doc """
Marks that the given variable should not be hygienized.
This macro expects a variable and it is typically invoked
inside `quote/2` to mark that a variable
should not be hygienized. See `quote/2` for more information.
## Examples
iex> Kernel.var!(example) = 1
1
iex> Kernel.var!(example)
1
"""
defmacro var!(var, context \\ nil)
defmacro var!({name, meta, atom}, context) when is_atom(name) and is_atom(atom) do
# Remove counter and force them to be vars
meta = :lists.keydelete(:counter, 1, meta)
meta = :lists.keystore(:if_undefined, 1, meta, {:if_undefined, :raise})
case Macro.expand(context, __CALLER__) do
context when is_atom(context) ->
{name, meta, context}
other ->
raise ArgumentError,
"expected var! context to expand to an atom, got: #{Macro.to_string(other)}"
end
end
defmacro var!(other, _context) do
raise ArgumentError, "expected a variable to be given to var!, got: #{Macro.to_string(other)}"
end
@doc """
When used inside quoting, marks that the given alias should not
be hygienized. This means the alias will be expanded when
the macro is expanded.
Check `quote/2` for more information.
"""
defmacro alias!(alias) when is_atom(alias) do
alias
end
defmacro alias!({:__aliases__, meta, args}) do
# Simply remove the alias metadata from the node
# so it does not affect expansion.
{:__aliases__, :lists.keydelete(:alias, 1, meta), args}
end
@doc """
Returns a binary starting at the offset `start` and of the given `size`.
This is similar to `binary_part/3` except that if `start + size`
is greater than the binary size, it automatically clips it to
the binary size instead of raising. Opposite to `binary_part/3`,
this function is not allowed in guards.
This function works with bytes. For a slicing operation that
considers characters, see `String.slice/3`.
## Examples
iex> binary_slice("elixir", 0, 6)
"elixir"
iex> binary_slice("elixir", 0, 5)
"elixi"
iex> binary_slice("elixir", 1, 4)
"lixi"
iex> binary_slice("elixir", 0, 10)
"elixir"
If `start` is negative, it is normalized against the binary
size and clamped to 0:
iex> binary_slice("elixir", -3, 10)
"xir"
iex> binary_slice("elixir", -10, 10)
"elixir"
If the `size` is zero, an empty binary is returned:
iex> binary_slice("elixir", 1, 0)
""
If `start` is greater than or equal to the binary size,
an empty binary is returned:
iex> binary_slice("elixir", 10, 10)
""
"""
@doc since: "1.14.0"
def binary_slice(binary, start, size)
when is_binary(binary) and is_integer(start) and is_integer(size) and size >= 0 do
total = byte_size(binary)
start = if start < 0, do: max(total + start, 0), else: start
case start < total do
true -> :erlang.binary_part(binary, start, min(size, total - start))
false -> ""
end
end
@doc """
Returns a binary from the offset given by the start of the
range to the offset given by the end of the range.
If the start or end of the range are negative, they are converted
into positive indices based on the binary size. For example,
`-1` means the last byte of the binary.
This is similar to `binary_part/3` except that it works with ranges
and it is not allowed in guards.
This function works with bytes. For a slicing operation that
considers characters, see `String.slice/2`.
## Examples
iex> binary_slice("elixir", 0..5)
"elixir"
iex> binary_slice("elixir", 1..3)
"lix"
iex> binary_slice("elixir", 1..10)
"lixir"
iex> binary_slice("elixir", -4..-1)
"ixir"
iex> binary_slice("elixir", -4..6)
"ixir"
iex> binary_slice("elixir", -10..10)
"elixir"
For ranges where `start > stop`, you need to explicitly
mark them as increasing:
iex> binary_slice("elixir", 2..-1//1)
"ixir"
iex> binary_slice("elixir", 1..-2//1)
"lixi"
You can use `../0` as a shortcut for `0..-1//1`, which returns
the whole binary as is:
iex> binary_slice("elixir", ..)
"elixir"
The step can be any positive number. For example, to
get every 2 characters of the binary:
iex> binary_slice("elixir", 0..-1//2)
"eii"
If the first position is after the string ends or after
the last position of the range, it returns an empty string:
iex> binary_slice("elixir", 10..3//1)
""
iex> binary_slice("elixir", -10..-7)
""
iex> binary_slice("a", 1..1500)
""
"""
@doc since: "1.14.0"
def binary_slice(binary, first..last//step)
when is_binary(binary) and step > 0 do
total = byte_size(binary)
first = if first < 0, do: max(first + total, 0), else: first
last = if last < 0, do: last + total, else: last
amount = last - first + 1
if first < total and amount > 0 do
part = binary_part(binary, first, min(amount, total - first))
if step == 1 do
part
else
<<first_byte, rest::binary>> = part
for <<_::size(^step - 1)-bytes, byte <- rest>>, into: <<first_byte>>, do: <<byte>>
end
else
""
end
end
def binary_slice(binary, _.._//_ = range) when is_binary(binary) do
raise ArgumentError,
"binary_slice/2 does not accept ranges with negative steps, got: #{inspect(range)}"
end
## Definitions implemented in Elixir
@doc ~S"""
Defines a module given by name with the given contents.
This macro defines a module with the given `alias` as its name and with the
given contents. It returns a tuple with four elements:
* `:module`
* the module name
* the binary contents of the module
* the result of evaluating the contents block
## Examples
defmodule Number do
def one, do: 1
def two, do: 2
end
#=> {:module, Number, <<70, 79, 82, ...>>, {:two, 0}}
Number.one()
#=> 1
Number.two()
#=> 2
## Module names and aliases
Module names (and aliases) must start with an ASCII uppercase character which
may be followed by any ASCII letter, number, or underscore. Elixir's
[Naming Conventions](naming-conventions.md) suggest for module names and aliases
to be written in the `CamelCase` format.
You can also use atoms as the module name, although they must only contain ASCII
characters.
## Nesting
Nesting a module inside another module affects the name of the nested module:
defmodule Foo do
defmodule Bar do
end
end
In the example above, two modules - `Foo` and `Foo.Bar` - are created.
When nesting, Elixir automatically creates an alias to the inner module,
allowing the second module `Foo.Bar` to be accessed as `Bar` in the same
lexical scope where it's defined (the `Foo` module). This only happens
if the nested module is defined via an alias.
If the `Foo.Bar` module is moved somewhere else, the references to `Bar` in
the `Foo` module need to be updated to the fully-qualified name (`Foo.Bar`) or
an alias has to be explicitly set in the `Foo` module with the help of
`alias/2`.
defmodule Foo.Bar do
# code
end
defmodule Foo do
alias Foo.Bar
# code here can refer to "Foo.Bar" as just "Bar"
end
## Dynamic names
Elixir module names can be dynamically generated. This is very
useful when working with macros. For instance, one could write:
defmodule Module.concat(["Foo", "Bar"]) do
# contents ...
end
Elixir will accept any module name as long as the expression passed as the
first argument to `defmodule/2` evaluates to an atom.
Note that, when a dynamic name is used, Elixir won't nest the name under
the current module nor automatically set up an alias.
## Reserved module names
If you attempt to define a module that already exists, you will get a
warning saying that a module has been redefined.
There are some modules that Elixir does not currently implement but it
may be implement in the future. Those modules are reserved and defining
them will result in a compilation error:
defmodule Any do
# code
end
** (CompileError) iex:1: module Any is reserved and cannot be defined
Elixir reserves the following module names: `Elixir`, `Any`, `BitString`,
`PID`, and `Reference`.
"""
defmacro defmodule(alias, do_block)
defmacro defmodule(alias, do: block) do
env = __CALLER__
assert_no_match_or_guard_scope(env.context, "defmodule/2")
expanded = expand_module_alias(alias, env)
module_meta = module_meta(alias)
{expanded, with_alias} =
case is_atom(expanded) do
true ->
{full, old, opts} = alias_defmodule(alias, expanded, env)
# Expand the module considering the current environment/nesting
meta = [defined: full] ++ module_meta
{full, {:require, meta, [old, opts]}}
false ->
{expanded, nil}
end
escaped =
case env do
%{function: nil, lexical_tracker: pid} when is_pid(pid) ->
integer = Kernel.LexicalTracker.write_cache(pid, block)
quote(do: Kernel.LexicalTracker.read_cache(unquote(pid), unquote(integer)))
%{} ->
:elixir_quote.escape(block, :escape, false)
end
versioned_vars = env.versioned_vars
prune = :erlang.is_map_key({:elixir, :prune_binding}, versioned_vars)
var_meta =
case prune do
true -> [generated: true, keep_unused: true]
false -> [generated: true]
end
module_vars = :lists.map(&module_var(&1, var_meta), :maps.keys(versioned_vars))
quote do
unquote(with_alias)
:elixir_module.compile(
unquote(module_meta),
unquote(expanded),
unquote(escaped),
unquote(module_vars),
unquote(prune),
__ENV__
)
end
end
defp module_meta({_, meta, _}), do: meta
defp module_meta(_), do: []
# We don't want to trace :alias_reference since we are defining the alias
defp expand_module_alias({:__aliases__, meta, list} = alias, env) do
case :elixir_aliases.expand_or_concat(meta, list, env, true) do
receiver when is_atom(receiver) ->
receiver
[head | tail] ->
case Macro.expand(head, env) do
head when is_atom(head) -> :elixir_aliases.concat([head | tail])
_ -> alias
end
end
end
defp expand_module_alias(other, env), do: Macro.expand(other, env)
# defmodule Elixir.Alias
defp alias_defmodule({:__aliases__, _, [:"Elixir", _ | _]}, module, _env),
do: {module, module, []}
# defmodule Alias in root
defp alias_defmodule({:__aliases__, _, _}, module, %{module: nil}), do: {module, module, []}
# defmodule Alias nested
defp alias_defmodule({:__aliases__, _, [h | t]}, _module, env) when is_atom(h) do
module = :elixir_aliases.concat([env.module, h])
alias = String.to_atom("Elixir." <> Atom.to_string(h))
opts = [as: alias, warn: false]
case t do
[] -> {module, module, opts}
_ -> {String.to_atom(Enum.join([module | t], ".")), module, opts}
end
end
# defmodule _
defp alias_defmodule(_raw, module, _env) do
{module, module, []}
end
defp module_var({name, kind}, meta) when is_atom(kind), do: {name, meta, kind}
defp module_var({name, kind}, meta), do: {name, [counter: kind] ++ meta, nil}
@doc ~S"""
Defines a public function with the given name and body.
## Examples
defmodule Foo do
def bar, do: :baz
end
Foo.bar()
#=> :baz
A function that expects arguments can be defined as follows:
defmodule Foo do
def sum(a, b) do
a + b
end
end
In the example above, a `sum/2` function is defined; this function receives
two arguments and returns their sum.
## Default arguments
`\\` is used to specify a default value for a parameter of a function. For
example:
defmodule MyMath do
def multiply_by(number, factor \\ 2) do
number * factor
end
end
MyMath.multiply_by(4, 3)
#=> 12
MyMath.multiply_by(4)
#=> 8
The compiler translates this into multiple functions with different arities,
here `MyMath.multiply_by/1` and `MyMath.multiply_by/2`, that represent cases when
arguments for parameters with default values are passed or not passed.
When defining a function with default arguments as well as multiple
explicitly declared clauses, you must write a function head that declares the
defaults. For example:
defmodule MyString do
def join(string1, string2 \\ nil, separator \\ " ")
def join(string1, nil, _separator) do
string1
end
def join(string1, string2, separator) do
string1 <> separator <> string2
end
end
Note that `\\` can't be used with anonymous functions because they
can only have a sole arity.
### Keyword lists with default arguments
Functions containing many arguments can benefit from using `Keyword`
lists to group and pass attributes as a single value.
defmodule MyConfiguration do
@default_opts [storage: "local"]
def configure(resource, opts \\ []) do
opts = Keyword.merge(@default_opts, opts)
storage = opts[:storage]
# ...
end
end
The difference between using `Map` and `Keyword` to store many
arguments is `Keyword`'s keys:
* must be atoms
* can be given more than once
* ordered, as specified by the developer
## Function names
Function and variable names in Elixir must start with an underscore or a
Unicode letter that is not in uppercase or titlecase. They may continue
using a sequence of Unicode letters, numbers, and underscores. They may
end in `?` or `!`. Elixir's [Naming Conventions](naming-conventions.md)
suggest for function and variable names to be written in the `snake_case`
format.
## `rescue`/`catch`/`after`/`else`
Function bodies support `rescue`, `catch`, `after`, and `else` as `try/1`
does (known as "implicit try"). For example, the following two functions are equivalent:
def convert(number) do
try do
String.to_integer(number)
rescue
e in ArgumentError -> {:error, e.message}
end
end
def convert(number) do
String.to_integer(number)
rescue
e in ArgumentError -> {:error, e.message}
end
"""
defmacro def(call, expr \\ nil) do
assert_no_match_or_guard_scope(__CALLER__.context, "def/2")
define(:def, call, expr, __CALLER__)
end
@doc """
Defines a private function with the given name and body.
Private functions are only accessible from within the module in which they are
defined. Trying to access a private function from outside the module it's
defined in results in an `UndefinedFunctionError` exception.
Check `def/2` for more information.
## Examples
defmodule Foo do
def bar do
sum(1, 2)
end
defp sum(a, b), do: a + b
end
Foo.bar()
#=> 3
Foo.sum(1, 2)
** (UndefinedFunctionError) undefined function Foo.sum/2
"""
defmacro defp(call, expr \\ nil) do
assert_no_match_or_guard_scope(__CALLER__.context, "defp/2")
define(:defp, call, expr, __CALLER__)
end
@doc """
Defines a public macro with the given name and body.
Macros must be defined before its usage.
Check `def/2` for rules on naming and default arguments.
## Examples
defmodule MyLogic do
defmacro unless(expr, opts) do
quote do
if !unquote(expr), unquote(opts)
end
end
end
require MyLogic
MyLogic.unless false do
IO.puts("It works")
end
"""
defmacro defmacro(call, expr \\ nil) do
assert_no_match_or_guard_scope(__CALLER__.context, "defmacro/2")
define(:defmacro, call, expr, __CALLER__)
end
@doc """
Defines a private macro with the given name and body.
Private macros are only accessible from the same module in which they are
defined.
Private macros must be defined before its usage.
Check `defmacro/2` for more information, and check `def/2` for rules on
naming and default arguments.
"""
defmacro defmacrop(call, expr \\ nil) do
assert_no_match_or_guard_scope(__CALLER__.context, "defmacrop/2")
define(:defmacrop, call, expr, __CALLER__)
end
defp define(kind, call, expr, env) do
module = assert_module_scope(env, kind, 2)
assert_no_function_scope(env, kind, 2)
unquoted_call = :elixir_quote.has_unquotes(call)
unquoted_expr = :elixir_quote.has_unquotes(expr)
store =
case unquoted_expr or unquoted_call do
true ->
:elixir_quote.escape({call, expr}, :escape, true)
false ->
key = :erlang.unique_integer()
:elixir_module.write_cache(module, key, {call, expr})
key
end
pos = :elixir_module.cache_env(env)
quote do
:elixir_def.store_definition(unquote(kind), unquote(store), unquote(pos))
end
end
@doc """
Defines a struct.
A struct is a tagged map that allows developers to provide
default values for keys, tags to be used in polymorphic
dispatches and compile time assertions.
It is only possible to define a struct per module, as the
struct is tied to the module itself.
## Examples
defmodule User do
defstruct name: nil, age: nil
end
Struct fields are evaluated at compile-time, which allows
them to be dynamic. In the example below, `10 + 11` is
evaluated at compile-time and the age field is stored
with value `21`:
defmodule User do
defstruct name: nil, age: 10 + 11
end
The `fields` argument is usually a keyword list with field names
as atom keys and default values as corresponding values. `defstruct/1`
also supports a list of atoms as its argument: in that case, the atoms
in the list will be used as the struct's field names and they will all
default to `nil`.
defmodule Post do
defstruct [:title, :content, :author]
end
Add documentation to a struct with the `@doc` attribute, like a function.
defmodule Post do
@doc "A post. The content should be valid Markdown."
defstruct [:title, :content, :author]
end
Once a struct is defined, it is possible to create them as follows:
%Post{title: "Hello world!"}
For more information on creating, updating, and pattern matching on
structs, please check `%/2`.
## Deriving
Although structs are maps, by default structs do not implement
any of the protocols implemented for maps. For example, attempting
to use a protocol with the `User` struct leads to an error:
john = %User{name: "John"}
MyProtocol.call(john)
** (Protocol.UndefinedError) protocol MyProtocol not implemented for User (a struct)
`defstruct/1`, however, allows protocol implementations to be
*derived*. This can be done by defining a `@derive` attribute as a
list before invoking `defstruct/1`:
defmodule User do
@derive MyProtocol
defstruct name: nil, age: nil
end
MyProtocol.call(john) # it works!
A common example is to `@derive` the `Inspect` protocol to hide certain fields
when the struct is printed:
defmodule User do
@derive {Inspect, only: :name}
defstruct name: nil, age: nil
end
For each protocol in `@derive`, Elixir will verify if the protocol
has implemented the `c:Protocol.__deriving__/2` callback. If so,
the callback will be invoked and it should define the implementation
module. Otherwise an implementation that simply points to the `Any`
implementation is automatically derived. For more information, see
`Protocol.derive/3`.
## Enforcing keys
When building a struct, Elixir will automatically guarantee all keys
belong to the struct:
%User{name: "john", unknown: :key}
** (KeyError) key :unknown not found in: %User{age: 21, name: nil}
Elixir also allows developers to enforce that certain keys must always be
given when building the struct:
defmodule User do
@enforce_keys [:name]
defstruct name: nil, age: 10 + 11
end
Now trying to build a struct without the name key will fail:
%User{age: 21}
** (ArgumentError) the following keys must also be given when building struct User: [:name]
Keep in mind `@enforce_keys` is a simple compile-time guarantee
to aid developers when building structs. It is not enforced on
updates and it does not provide any sort of value-validation.
## Types
It is recommended to define types for structs. By convention, such a type
is called `t`. To define a type for a struct, the struct literal syntax is
used:
defmodule User do
defstruct name: "John", age: 25
@type t :: %__MODULE__{name: String.t(), age: non_neg_integer}
end
It is recommended to only use the struct syntax when defining the struct's
type. When referring to another struct, it's better to use `User.t()` instead of
`%User{}`.
The types of the struct fields that are not included in `%User{}` default to
`term()` (see `t:term/0`).
Structs whose internal structure is private to the local module (pattern
matching them or directly accessing their fields should not be allowed) should
use the `@opaque` attribute. Structs whose internal structure is public should
use `@type`.
"""
defmacro defstruct(fields) do
quote bind_quoted: [fields: fields, bootstrapped?: bootstrapped?(Enum)] do
{struct, derive, escaped_struct, kv, body} =
Kernel.Utils.defstruct(__MODULE__, fields, bootstrapped?, __ENV__)
case derive do
[] -> :ok
_ -> Protocol.__derive__(derive, __MODULE__, __ENV__)
end
def __struct__(), do: unquote(escaped_struct)
def __struct__(unquote(kv)), do: unquote(body)
Kernel.Utils.announce_struct(__MODULE__)
struct
end
end
@doc ~S"""
Defines an exception.
Exceptions are structs backed by a module that implements
the `Exception` behaviour. The `Exception` behaviour requires
two functions to be implemented:
* [`exception/1`](`c:Exception.exception/1`) - receives the arguments given to `raise/2`
and returns the exception struct. The default implementation
accepts either a set of keyword arguments that is merged into
the struct or a string to be used as the exception's message.
* [`message/1`](`c:Exception.message/1`) - receives the exception struct and must return its
message. Most commonly exceptions have a message field which
by default is accessed by this function. However, if an exception
does not have a message field, this function must be explicitly
implemented.
Since exceptions are structs, the API supported by `defstruct/1`
is also available in `defexception/1`.
## Raising exceptions
The most common way to raise an exception is via `raise/2`:
defmodule MyAppError do
defexception [:message]
end
value = [:hello]
raise MyAppError,
message: "did not get what was expected, got: #{inspect(value)}"
In many cases it is more convenient to pass the expected value to
`raise/2` and generate the message in the `c:Exception.exception/1` callback:
defmodule MyAppError do
defexception [:message]
@impl true
def exception(value) do
msg = "did not get what was expected, got: #{inspect(value)}"
%MyAppError{message: msg}
end
end
raise MyAppError, value
The example above shows the preferred strategy for customizing
exception messages.
"""
defmacro defexception(fields) do
quote bind_quoted: [fields: fields] do
Elixir.Kernel.@(behaviour(Exception))
struct = defstruct([__exception__: true] ++ fields)
if Map.has_key?(struct, :message) do
Elixir.Kernel.@(impl(true))
def message(exception) do
exception.message
end
defoverridable message: 1
Elixir.Kernel.@(impl(true))
def exception(msg) when Kernel.is_binary(msg) do
exception(message: msg)
end
end
# Calls to Kernel functions must be fully-qualified to ensure
# reproducible builds, otherwise, this macro will generate ASTs
# with different metadata (:imports, :context) depending on if
# it is the bootstrapped version or not.
Elixir.Kernel.@(impl(true))
def exception(args) when Kernel.is_list(args) do
struct!(__MODULE__, args)
end
defoverridable exception: 1
end
end
@doc """
Defines a protocol.
See the `Protocol` module for more information.
"""
defmacro defprotocol(name, do_block)
defmacro defprotocol(name, do: block) do
Protocol.__protocol__(name, do: block)
end
@doc """
Defines an implementation for the given protocol.
See the `Protocol` module for more information.
"""
defmacro defimpl(name, opts, do_block \\ []) do
Protocol.__impl__(name, opts, do_block, __CALLER__)
end
@doc """
Makes the given definitions in the current module overridable.
If the user defines a new function or macro with the same name
and arity, then the overridable ones are discarded. Otherwise, the
original definitions are used.
It is possible for the overridden definition to have a different
visibility than the original: a public function can be overridden
by a private function and vice-versa. Macros cannot be overridden
as functions and vice-versa.
## Example
defmodule DefaultMod do
defmacro __using__(_opts) do
quote do
def test(x, y) do
x + y
end
defoverridable test: 2
end
end
end
defmodule ChildMod do
use DefaultMod
def test(x, y) do
x * y + super(x, y)
end
end
As seen as in the example above, `super` can be used to call the default
implementation.
## Example with behaviour
`defoverridable` is commonly used with behaviours. The behaviours use
`@callback` definitions to define the general module API and the
`__using__` callback is used to define default implementations of
functions, which can then be overridable.
For convenience, you can pass a behaviour to `defoverridable` and it
will mark all of the callbacks in the behaviour as overridable:
defmodule Behaviour do
@callback test(number(), number()) :: number()
end
defmodule DefaultMod do
defmacro __using__(_opts) do
quote do
@behaviour Behaviour
def test(x, y) do
x + y
end
defoverridable Behaviour
end
end
end
defmodule ChildMod do
use DefaultMod
def test(x, y) do
x * y + super(x, y)
end
end
> #### Narrow behaviours and entry points {: .tip}
>
> When defining behaviours, a general rule of thumb is to define narrow
> behaviours, with the minimum amount of callbacks, to facilitate maintenance
> over time. Fewer callbacks minimize the points of contact between different
> parts of the system and reduces the risk of breaking changes and of different
> implementations having inconsistent behaviour. However, when using `defoverridable`
> with behaviours, you may accidentally define broad interfaces as all default
> behaviour is provided via `defoverridable`. Furthermore, `defoverridable`
> necessarily relies on meta-programming, which complicates debugging. `super` is
> also hard to troubleshoot, as it by definition relies on calling an implicitly
> defined function.
>
> A possible alternative to `defoverridable` is to use optional callbacks and
> move the default implementation to the caller. Then you can check if a callback
> exists via `Code.ensure_loaded?/1` and `function_exported?/3`. For instance,
> in the example above, imagine there is a module that calls the `test/2` function.
> This module could be defined as such:
>
> defmodule CallsTest do
> def receives_module_and_calls_test(module, x, y) do
> if Code.ensure_loaded?(module) and function_exported?(module, :test, 2) do
> module.test(x, y)
> else
> x + y
> end
> end
> end
>
> The downside of the above code is that it must call `Code.ensure_loaded?/1` and
> `function_exported?/3` on every invocation of the behaviour, which may impact
> runtime performance. For this reason, this approach works best when the behaviour
> has an entry point, such as a `init` callback (as seen in `GenServer`), which you
> invoke once to guarantee the module is loaded, and from that moment, you only need
> to perform `function_exported?/3` checks.
>
> To recap:
>
> * Prefer narrow behaviours
>
> * If your behaviour has an entry point, consider using optional callbacks
> followed by `Code.ensure_loaded?/1` and `function_exported?/3` checks
>
> * If using `defoverridable`, avoid relying on `super` to trigger the default
> behaviour, suggesting users to invoke well-defined APIs instead.
>
"""
defmacro defoverridable(keywords_or_behaviour) do
quote do
Module.make_overridable(__MODULE__, unquote(keywords_or_behaviour))
end
end
@doc """
Defines a macro suitable for use in guard expressions.
It raises at compile time if the `guard` uses expressions that aren't
allowed in [guard clauses](patterns-and-guards.html#guards),
and otherwise creates a macro that can be used both inside or outside guards.
When defining your own guards, consider the
[naming conventions](naming-conventions.html#is_-prefix-is_foo)
around boolean-returning guards.
## Example
defmodule Integer.Guards do
defguard is_even(value) when is_integer(value) and rem(value, 2) == 0
end
defmodule Collatz do
@moduledoc "Tools for working with the Collatz sequence."
import Integer.Guards
@doc "Determines the number of steps `n` takes to reach `1`."
# If this function never converges, please let me know what `n` you used.
def converge(n) when n > 0, do: step(n, 0)
defp step(1, step_count) do
step_count
end
defp step(n, step_count) when is_even(n) do
step(div(n, 2), step_count + 1)
end
defp step(n, step_count) do
step(3 * n + 1, step_count + 1)
end
end
"""
@doc since: "1.6.0"
@spec defguard(Macro.t()) :: Macro.t()
defmacro defguard(guard) do
define_guard(:defmacro, guard, __CALLER__)
end
@doc """
Defines a private macro suitable for use in guard expressions.
It raises at compile time if the `guard` uses expressions that aren't
allowed in [guard clauses](patterns-and-guards.html#guards),
and otherwise creates a private macro that can be used
both inside or outside guards in the current module.
When defining your own guards, consider the
[naming conventions](naming-conventions.html#is_-prefix-is_foo)
around boolean-returning guards.
Similar to `defmacrop/2`, `defguardp/1` must be defined before its use
in the current module.
"""
@doc since: "1.6.0"
@spec defguardp(Macro.t()) :: Macro.t()
defmacro defguardp(guard) do
define_guard(:defmacrop, guard, __CALLER__)
end
defp define_guard(kind, guard, env) do
case :elixir_utils.extract_guards(guard) do
{call, [_, _ | _]} ->
raise ArgumentError,
"invalid syntax in defguard #{Macro.to_string(call)}, " <>
"only a single when clause is allowed"
{call, impls} ->
case decompose_args(call) do
:error ->
raise ArgumentError, "invalid syntax in defguard #{Macro.to_string(call)}"
args ->
validate_variable_only_args!(call, args)
macro_definition =
case impls do
[] ->
define(kind, call, nil, env)
[guard] ->
quoted =
quote do
require Kernel.Utils
Kernel.Utils.defguard(unquote(args), unquote(guard))
end
define(kind, call, [do: quoted], env)
end
quote do
Elixir.Kernel.@(doc(guard: true))
unquote(macro_definition)
end
end
end
end
defp decompose_args({name, _, args}) when is_atom(name) and is_atom(args), do: []
defp decompose_args({name, _, args}) when is_atom(name) and is_list(args), do: args
defp decompose_args({{:unquote, _, _}, _, args}) when is_atom(args), do: []
defp decompose_args({{:unquote, _, _}, _, args}) when is_list(args), do: args
defp decompose_args(_), do: :error
defp validate_variable_only_args!(call, args) do
Enum.each(args, fn
{ref, _meta, context} when is_atom(ref) and is_atom(context) ->
:ok
{:\\, _m1, [{ref, _m2, context}, _default]} when is_atom(ref) and is_atom(context) ->
:ok
_match ->
raise ArgumentError, "invalid syntax in defguard #{Macro.to_string(call)}"
end)
end
@doc """
Uses the given module in the current context.
When calling:
use MyModule, some: :options
Elixir will invoke `MyModule.__using__/1` passing the second argument of
`use` as its argument. Since `__using__/1` is typically a macro, all
the usual macro rules apply, and its return value should be quoted code
that is then inserted where `use/2` is called.
> #### Code injection {: .warning}
>
> `use MyModule` works as a **code-injection point** in the caller.
> Given the caller of `use MyModule` has little control over how the
> code is injected, `use/2` should be used with care. If you can,
> avoid use in favor of `import/2` or `alias/2` whenever possible.
## Examples
For example, to write test cases using the `ExUnit` framework provided
with Elixir, a developer should `use` the `ExUnit.Case` module:
defmodule AssertionTest do
use ExUnit.Case, async: true
test "always pass" do
assert true
end
end
In this example, Elixir will call the `__using__/1` macro in the
`ExUnit.Case` module with the keyword list `[async: true]` as its
argument.
In other words, `use/2` translates to:
defmodule AssertionTest do
require ExUnit.Case
ExUnit.Case.__using__(async: true)
test "always pass" do
assert true
end
end
where `ExUnit.Case` defines the `__using__/1` macro:
defmodule ExUnit.Case do
defmacro __using__(opts) do
# do something with opts
quote do
# return some code to inject in the caller
end
end
end
## Best practices
`__using__/1` is typically used when there is a need to set some state
(via module attributes) or callbacks (like `@before_compile`, see the
documentation for `Module` for more information) into the caller.
`__using__/1` may also be used to alias, require, or import functionality
from different modules:
defmodule MyModule do
defmacro __using__(_opts) do
quote do
import MyModule.Foo
import MyModule.Bar
import MyModule.Baz
alias MyModule.Repo
end
end
end
However, do not provide `__using__/1` if all it does is to import,
alias or require the module itself. For example, avoid this:
defmodule MyModule do
defmacro __using__(_opts) do
quote do
import MyModule
end
end
end
In such cases, developers should instead import or alias the module
directly, so that they can customize those as they wish,
without the indirection behind `use/2`. Developers must also avoid
defining functions inside `__using__/1`.
Given `use MyModule` can generate any code, it may not be easy for
developers to understand the impact of `use MyModule`.
For this reason, to provide guidance and clarity, we recommend developers
to include an admonition block in their `@moduledoc` that explains how
`use MyModule` impacts their code. As an example, the `GenServer` documentation
outlines:
> #### `use GenServer` {: .info}
>
> When you `use GenServer`, the `GenServer` module will
> set `@behaviour GenServer` and define a `child_spec/1`
> function, so your module can be used as a child
> in a supervision tree.
This provides a quick summary of how using a module impacts the user code.
Keep in mind to only list changes made to the public API of the module.
For example, if `use MyModule` sets an internal attribute called
`@_my_module_info` and this attribute is never meant to be public,
it must not be listed.
For convenience, the markup notation to generate the admonition block
above is:
```
> #### `use GenServer` {: .info}
>
> When you `use GenServer`, the GenServer module will
> set `@behaviour GenServer` and define a `child_spec/1`
> function, so your module can be used as a child
> in a supervision tree.
```
"""
defmacro use(module, opts \\ []) do
calls =
Enum.map(expand_aliases(module, __CALLER__), fn
expanded when is_atom(expanded) ->
quote do
require unquote(expanded)
unquote(expanded).__using__(unquote(opts))
end
_otherwise ->
raise ArgumentError,
"invalid arguments for use, " <>
"expected a compile time atom or alias, got: #{Macro.to_string(module)}"
end)
quote(do: (unquote_splicing(calls)))
end
defp expand_aliases({{:., _, [base, :{}]}, _, refs}, env) do
base = Macro.expand(base, env)
Enum.map(refs, fn
{:__aliases__, _, ref} ->
Module.concat([base | ref])
ref when is_atom(ref) ->
Module.concat(base, ref)
other ->
other
end)
end
defp expand_aliases(module, env) do
[Macro.expand(module, env)]
end
@doc """
Defines a function that delegates to another module.
Functions defined with `defdelegate/2` are public and can be invoked from
outside the module they're defined in, as if they were defined using `def/2`.
Therefore, `defdelegate/2` is about extending the current module's public API.
If what you want is to invoke a function defined in another module without
using its full module name, then use `alias/2` to shorten the module name or use
`import/2` to be able to invoke the function without the module name altogether.
Delegation only works with functions; delegating macros is not supported.
Check `def/2` for rules on naming and default arguments.
## Options
* `:to` - the module to dispatch to.
* `:as` - the function to call on the target given in `:to`.
This parameter is optional and defaults to the name being
delegated (`funs`).
## Examples
defmodule MyList do
defdelegate reverse(list), to: Enum
defdelegate other_reverse(list), to: Enum, as: :reverse
end
MyList.reverse([1, 2, 3])
#=> [3, 2, 1]
MyList.other_reverse([1, 2, 3])
#=> [3, 2, 1]
"""
defmacro defdelegate(funs, opts) do
funs = Macro.escape(funs, unquote: true)
opts = Macro.expand_literals(opts, %{__CALLER__ | function: {:__info__, 1}})
quote bind_quoted: [funs: funs, opts: opts] do
target = Kernel.Utils.defdelegate_all(funs, opts, __ENV__)
# TODO: Remove List.wrap when multiple funs are no longer supported
for fun <- List.wrap(funs) do
{name, args, as, as_args} = Kernel.Utils.defdelegate_each(fun, opts)
Elixir.Kernel.@(doc(delegate_to: {target, as, :erlang.length(as_args)}))
# Build the call AST by hand so it doesn't get a
# context and it warns on things like missing @impl
def unquote({name, [line: __ENV__.line], args}) do
unquote(target).unquote(as)(unquote_splicing(as_args))
end
end
end
end
@doc """
Debugs the given `code`.
`dbg/2` can be used to debug the given `code` through a configurable debug function.
It returns the result of the given code.
## Examples
Let's take this call to `dbg/2`:
dbg(Atom.to_string(:debugging))
#=> "debugging"
It returns the string `"debugging"`, which is the result of the `Atom.to_string/1` call.
Additionally, the call above prints:
[my_file.ex:10: MyMod.my_fun/0]
Atom.to_string(:debugging) #=> "debugging"
The default debugging function prints additional debugging info when dealing with
pipelines. It prints the values at every "step" of the pipeline.
"Elixir is cool!"
|> String.trim_trailing("!")
|> String.split()
|> List.first()
|> dbg()
#=> "Elixir"
The code above prints:
[my_file.ex:10: MyMod.my_fun/0]
"Elixir is cool!" #=> "Elixir is cool!"
|> String.trim_trailing("!") #=> "Elixir is cool"
|> String.split() #=> ["Elixir", "is", "cool"]
|> List.first() #=> "Elixir"
With no arguments, `dbg()` debugs information about the current binding. See `binding/1`.
## `dbg` inside IEx
You can enable IEx to replace `dbg` with its `IEx.pry/0` backend by calling:
$ iex --dbg pry
In such cases, `dbg` will start a `pry` session where you can interact with
the imports, aliases, and variables of the current environment at the location
of the `dbg` call.
If you call `dbg` at the end of a pipeline (using `|>`) within IEx, you are able
to go through each step of the pipeline one by one by entering "next" (or "n").
Note `dbg` only supports stepping for pipelines (in other words, it can only
step through the code it sees). For general stepping, you can set breakpoints
using `IEx.break!/4`.
For more information, [see IEx documentation](https://hexdocs.pm/iex/IEx.html#module-dbg-and-breakpoints).
## Configuring the debug function
One of the benefits of `dbg/2` is that its debugging logic is configurable,
allowing tools to extend `dbg` with enhanced behaviour. This is done, for
example, by `IEx` which extends `dbg` with an interactive shell where you
can directly inspect and access values.
The debug function can be configured at compile time through the `:dbg_callback`
key of the `:elixir` application. The debug function must be a
`{module, function, args}` tuple. The `function` function in `module` will be
invoked with three arguments *prepended* to `args`:
1. The AST of `code`
2. The AST of `options`
3. The `Macro.Env` environment of where `dbg/2` is invoked
The debug function is invoked at compile time and it must also return an AST.
The AST is expected to ultimately return the result of evaluating the debugged
expression.
Here's a simple example:
defmodule MyMod do
def debug_fun(code, options, caller, device) do
quote do
result = unquote(code)
IO.inspect(unquote(device), result, label: unquote(Macro.to_string(code)))
end
end
end
To configure the debug function:
# In config/config.exs
config :elixir, :dbg_callback, {MyMod, :debug_fun, [:stdio]}
### Default debug function
By default, the debug function we use is `Macro.dbg/3`. It just prints
information about the code to standard output and returns the value
returned by evaluating `code`. `options` are used to control how terms
are inspected. They are the same options accepted by `inspect/2`.
"""
@doc since: "1.14.0"
defmacro dbg(code \\ quote(do: binding()), options \\ []) do
{mod, fun, args} = Application.compile_env!(__CALLER__, :elixir, :dbg_callback)
Macro.compile_apply(mod, fun, [code, options, __CALLER__ | args], __CALLER__)
end
hour_in_ms = 1000 * 60 * 60
day_in_ms = 24 * hour_in_ms
week_in_ms = 7 * day_in_ms
@doc """
Constructs a millisecond timeout from the given components, duration, or timeout.
This function is useful for constructing timeouts to use in functions that
expect `t:timeout/0` values (such as `Process.send_after/4` and many others).
## Argument
The `duration` argument can be one of a `Duration`, a `t:timeout/0`, or a list
of components. Each of these is described below.
### Passing `Duration`s
`t:Duration.t/0` structs can be converted to timeouts. The given duration must have
`year` and `month` fields set to `0`, since those cannot be reliably converted to
milliseconds (due to the varying number of days in a month and year).
Microseconds in durations are converted to milliseconds (through `System.convert_time_unit/3`).
### Passing components
The `duration` argument can also be keyword list which can contain the following
keys, each appearing at most once with a non-negative integer value:
* `:week` - the number of weeks (a week is always 7 days)
* `:day` - the number of days (a day is always 24 hours)
* `:hour` - the number of hours
* `:minute` - the number of minutes
* `:second` - the number of seconds
* `:millisecond` - the number of milliseconds
The timeout is calculated as the sum of the components, each multiplied by
the corresponding factor.
### Passing timeouts
You can also pass timeouts directly to this functions, that is, milliseconds or
the atom `:infinity`. In this case, this function just returns the given argument.
## Examples
With a keyword list:
iex> to_timeout(hour: 1, minute: 30)
5400000
With a duration:
iex> to_timeout(%Duration{hour: 1, minute: 30})
5400000
With a timeout:
iex> to_timeout(5_400_000)
5400000
iex> to_timeout(:infinity)
:infinity
"""
@doc since: "1.17.0"
@spec to_timeout([{unit, non_neg_integer()}] | timeout() | Duration.t()) :: timeout()
when unit: :week | :day | :hour | :minute | :second | :millisecond
def to_timeout(duration)
def to_timeout(:infinity), do: :infinity
def to_timeout(timeout) when is_integer(timeout) and timeout >= 0, do: timeout
def to_timeout(%{__struct__: Duration} = duration) do
case duration do
%{year: year} when year != 0 ->
raise ArgumentError,
"duration with a non-zero year cannot be reliably converted to timeouts"
%{month: month} when month != 0 ->
raise ArgumentError,
"duration with a non-zero month cannot be reliably converted to timeouts"
_other ->
{microsecond, _precision} = duration.microsecond
millisecond = :erlang.convert_time_unit(microsecond, :microsecond, :millisecond)
duration.week * unquote(week_in_ms) +
duration.day * unquote(day_in_ms) +
duration.hour * unquote(hour_in_ms) +
duration.minute * 60_000 +
duration.second * 1000 +
millisecond
end
end
def to_timeout(components) when is_list(components) do
reducer = fn
{key, value}, {acc, seen_keys} when is_integer(value) and value >= 0 ->
case :lists.member(key, seen_keys) do
true ->
raise ArgumentError, "timeout component #{inspect(key)} is duplicated"
false ->
:ok
end
factor =
case key do
:week ->
unquote(week_in_ms)
:day ->
unquote(day_in_ms)
:hour ->
unquote(hour_in_ms)
:minute ->
60_000
:second ->
1000
:millisecond ->
1
other ->
raise ArgumentError, """
timeout component #{inspect(other)} is not a valid timeout component, valid \
values are: :week, :day, :hour, :minute, :second, :millisecond\
"""
end
{acc + value * factor, [key | seen_keys]}
{key, value}, {_acc, _seen_keys} ->
raise ArgumentError,
"timeout component #{inspect(key)} must be a non-negative " <>
"integer, got: #{inspect(value)}"
end
elem(:lists.foldl(reducer, {0, _seen_keys = []}, components), 0)
end
## Sigils
@doc ~S"""
Handles the sigil `~S` for strings.
It returns a string without interpolations and without escape
characters.
## Examples
iex> ~S(foo)
"foo"
iex> ~S(f#{o}o)
"f\#{o}o"
iex> ~S(\o/)
"\\o/"
"""
defmacro sigil_S(term, modifiers)
defmacro sigil_S({:<<>>, _, [binary]}, []) when is_binary(binary), do: binary
@doc ~S"""
Handles the sigil `~s` for strings.
It returns a string as if it was a double quoted string, unescaping characters
and replacing interpolations.
## Examples
iex> ~s(foo)
"foo"
iex> ~s(f#{:o}o)
"foo"
iex> ~s(f\#{:o}o)
"f\#{:o}o"
"""
defmacro sigil_s(term, modifiers)
defmacro sigil_s({:<<>>, _, [piece]}, []) when is_binary(piece) do
:elixir_interpolation.unescape_string(piece)
end
defmacro sigil_s({:<<>>, line, pieces}, []) do
{:<<>>, line, unescape_tokens(pieces)}
end
@doc ~S"""
Handles the sigil `~C` for charlists.
It returns a charlist without interpolations and without escape
characters.
A charlist is a list of integers where all the integers are valid code points.
The three expressions below are equivalent:
~C"foo\n"
[?f, ?o, ?o, ?\\, ?n]
[102, 111, 111, 92, 110]
In practice, charlists are mostly used in specific scenarios such as
interfacing with older Erlang libraries that do not accept binaries as arguments.
## Examples
iex> ~C(foo)
~c"foo"
iex> ~C(f#{o}o)
~c"f\#{o}o"
iex> ~C(foo\n)
~c"foo\\n"
"""
defmacro sigil_C(term, modifiers)
defmacro sigil_C({:<<>>, _meta, [string]}, []) when is_binary(string) do
String.to_charlist(string)
end
@doc ~S"""
Handles the sigil `~c` for charlists.
It returns a charlist, unescaping characters and replacing interpolations.
A charlist is a list of integers where all the integers are valid code points.
The three expressions below are equivalent:
~c"foo"
[?f, ?o, ?o]
[102, 111, 111]
In practice, charlists are mostly used in specific scenarios such as
interfacing with older Erlang libraries that do not accept binaries as arguments.
## Examples
iex> ~c(foo)
~c"foo"
iex> ~c(f#{:o}o)
~c"foo"
iex> ~c(f\#{:o}o)
~c"f\#{:o}o"
The list is only printed as a `~c` sigil if all code points are within the
ASCII range:
iex> ~c"hełło"
[104, 101, 322, 322, 111]
iex> [104, 101, 108, 108, 111]
~c"hello"
See `Inspect.Opts` for more information.
"""
defmacro sigil_c(term, modifiers)
# We can skip the runtime conversion if we are
# creating a binary made solely of series of chars.
defmacro sigil_c({:<<>>, _meta, [string]}, []) when is_binary(string) do
String.to_charlist(:elixir_interpolation.unescape_string(string))
end
defmacro sigil_c({:<<>>, _meta, pieces}, []) do
quote(do: List.to_charlist(unquote(unescape_list_tokens(pieces))))
end
@doc ~S"""
Handles the sigil `~r` for regular expressions.
It returns a regular expression pattern, unescaping characters and replacing
interpolations.
More information on regular expressions can be found in the `Regex` module.
## Examples
iex> Regex.match?(~r/foo/, "foo")
true
iex> Regex.match?(~r/a#{:b}c/, "abc")
true
While the `~r` sigil allows parens and brackets to be used as delimiters,
it is preferred to use `"` or `/` to avoid escaping conflicts with reserved
regex characters.
"""
defmacro sigil_r(term, modifiers)
defmacro sigil_r({:<<>>, _meta, [binary]}, options) when is_binary(binary) do
assert_no_match_or_guard_scope(__CALLER__.context, "the ~r sigil")
binary = :elixir_interpolation.unescape_string(binary, &regex_unescape_map/1)
compile_regex(binary, options)
end
defmacro sigil_r({:<<>>, meta, pieces}, options) do
assert_no_match_or_guard_scope(__CALLER__.context, "the ~r sigil")
tuple = {:<<>>, meta, unescape_tokens(pieces, &regex_unescape_map/1)}
compile_regex(tuple, options)
end
defp regex_unescape_map(:newline), do: true
defp regex_unescape_map(_), do: false
@doc false
defmacro sigil_R({:<<>>, _meta, [binary]}, options) when is_binary(binary) do
IO.warn(
"~R/.../ is deprecated, use ~r/.../ instead",
Macro.Env.stacktrace(__CALLER__)
)
compile_regex(binary, options)
end
defp compile_regex(binary_or_tuple, options) do
bin_opts = :binary.list_to_bin(options)
case is_binary(binary_or_tuple) do
true ->
Macro.escape(Regex.compile!(binary_or_tuple, bin_opts))
false ->
quote(do: Regex.compile!(unquote(binary_or_tuple), unquote(bin_opts)))
end
end
@doc ~S"""
Handles the sigil `~D` for dates.
By default, this sigil uses the built-in `Calendar.ISO`, which
requires dates to be written in the ISO8601 format:
~D[yyyy-mm-dd]
such as:
~D[2015-01-13]
If you are using alternative calendars, any representation can
be used as long as you follow the representation by a single space
and the calendar name:
~D[SOME-REPRESENTATION My.Alternative.Calendar]
The lower case `~d` variant does not exist as interpolation
and escape characters are not useful for date sigils.
More information on dates can be found in the `Date` module.
## Examples
iex> ~D[2015-01-13]
~D[2015-01-13]
"""
defmacro sigil_D(date_string, modifiers)
defmacro sigil_D({:<<>>, _, [string]}, []) do
{{:ok, {year, month, day}}, calendar} = parse_with_calendar!(string, :parse_date, "Date")
to_calendar_struct(Date, calendar: calendar, year: year, month: month, day: day)
end
@doc ~S"""
Handles the sigil `~T` for times.
By default, this sigil uses the built-in `Calendar.ISO`, which
requires times to be written in the ISO8601 format:
~T[hh:mm:ss]
~T[hh:mm:ss.ssssss]
such as:
~T[13:00:07]
~T[13:00:07.123]
If you are using alternative calendars, any representation can
be used as long as you follow the representation by a single space
and the calendar name:
~T[SOME-REPRESENTATION My.Alternative.Calendar]
The lower case `~t` variant does not exist as interpolation
and escape characters are not useful for time sigils.
More information on times can be found in the `Time` module.
## Examples
iex> ~T[13:00:07]
~T[13:00:07]
iex> ~T[13:00:07.001]
~T[13:00:07.001]
"""
defmacro sigil_T(time_string, modifiers)
defmacro sigil_T({:<<>>, _, [string]}, []) do
{{:ok, {hour, minute, second, microsecond}}, calendar} =
parse_with_calendar!(string, :parse_time, "Time")
to_calendar_struct(Time,
calendar: calendar,
hour: hour,
minute: minute,
second: second,
microsecond: microsecond
)
end
@doc ~S"""
Handles the sigil `~N` for naive date times.
By default, this sigil uses the built-in `Calendar.ISO`, which
requires naive date times to be written in the ISO8601 format:
~N[yyyy-mm-dd hh:mm:ss]
~N[yyyy-mm-dd hh:mm:ss.ssssss]
~N[yyyy-mm-ddThh:mm:ss.ssssss]
such as:
~N[2015-01-13 13:00:07]
~N[2015-01-13T13:00:07.123]
If you are using alternative calendars, any representation can
be used as long as you follow the representation by a single space
and the calendar name:
~N[SOME-REPRESENTATION My.Alternative.Calendar]
The lower case `~n` variant does not exist as interpolation
and escape characters are not useful for date time sigils.
More information on naive date times can be found in the
`NaiveDateTime` module.
## Examples
iex> ~N[2015-01-13 13:00:07]
~N[2015-01-13 13:00:07]
iex> ~N[2015-01-13T13:00:07.001]
~N[2015-01-13 13:00:07.001]
"""
defmacro sigil_N(naive_datetime_string, modifiers)
defmacro sigil_N({:<<>>, _, [string]}, []) do
{{:ok, {year, month, day, hour, minute, second, microsecond}}, calendar} =
parse_with_calendar!(string, :parse_naive_datetime, "NaiveDateTime")
to_calendar_struct(NaiveDateTime,
calendar: calendar,
year: year,
month: month,
day: day,
hour: hour,
minute: minute,
second: second,
microsecond: microsecond
)
end
@doc ~S"""
Handles the sigil `~U` to create a UTC `DateTime`.
By default, this sigil uses the built-in `Calendar.ISO`, which
requires UTC date times to be written in the ISO8601 format:
~U[yyyy-mm-dd hh:mm:ssZ]
~U[yyyy-mm-dd hh:mm:ss.ssssssZ]
~U[yyyy-mm-ddThh:mm:ss.ssssss+00:00]
such as:
~U[2015-01-13 13:00:07Z]
~U[2015-01-13T13:00:07.123+00:00]
If you are using alternative calendars, any representation can
be used as long as you follow the representation by a single space
and the calendar name:
~U[SOME-REPRESENTATION My.Alternative.Calendar]
The given `datetime_string` must include "Z" or "00:00" offset
which marks it as UTC, otherwise an error is raised.
The lower case `~u` variant does not exist as interpolation
and escape characters are not useful for date time sigils.
More information on date times can be found in the `DateTime` module.
## Examples
iex> ~U[2015-01-13 13:00:07Z]
~U[2015-01-13 13:00:07Z]
iex> ~U[2015-01-13T13:00:07.001+00:00]
~U[2015-01-13 13:00:07.001Z]
"""
@doc since: "1.9.0"
defmacro sigil_U(datetime_string, modifiers)
defmacro sigil_U({:<<>>, _, [string]}, []) do
{{:ok, {year, month, day, hour, minute, second, microsecond}, offset}, calendar} =
parse_with_calendar!(string, :parse_utc_datetime, "UTC DateTime")
if offset != 0 do
raise ArgumentError,
"cannot parse #{inspect(string)} as UTC DateTime for #{inspect(calendar)}, reason: :non_utc_offset"
end
to_calendar_struct(DateTime,
calendar: calendar,
year: year,
month: month,
day: day,
hour: hour,
minute: minute,
second: second,
microsecond: microsecond,
time_zone: "Etc/UTC",
zone_abbr: "UTC",
utc_offset: 0,
std_offset: 0
)
end
defp parse_with_calendar!(string, fun, context) do
{calendar, string} = extract_calendar(string)
result = apply(calendar, fun, [string])
{maybe_raise!(result, calendar, context, string), calendar}
end
defp extract_calendar(string) do
case :binary.split(string, " ", [:global]) do
[_] -> {Calendar.ISO, string}
parts -> maybe_atomize_calendar(List.last(parts), string)
end
end
defp maybe_atomize_calendar(<<alias, _::binary>> = last_part, string)
when alias >= ?A and alias <= ?Z do
string = binary_part(string, 0, byte_size(string) - byte_size(last_part) - 1)
{String.to_atom("Elixir." <> last_part), string}
end
defp maybe_atomize_calendar(_last_part, string) do
{Calendar.ISO, string}
end
defp maybe_raise!({:error, reason}, calendar, type, string) do
raise ArgumentError,
"cannot parse #{inspect(string)} as #{type} for #{inspect(calendar)}, " <>
"reason: #{inspect(reason)}"
end
defp maybe_raise!(other, _calendar, _type, _string), do: other
defp to_calendar_struct(type, fields) do
quote do
%unquote(type){unquote_splicing(fields)}
end
end
@doc ~S"""
Handles the sigil `~w` for list of words.
It returns a list of "words" split by whitespace. Character unescaping and
interpolation happens for each word.
## Modifiers
* `s`: words in the list are strings (default)
* `a`: words in the list are atoms
* `c`: words in the list are charlists
## Examples
iex> ~w(foo #{:bar} baz)
["foo", "bar", "baz"]
iex> ~w(foo #{" bar baz "})
["foo", "bar", "baz"]
iex> ~w(--source test/enum_test.exs)
["--source", "test/enum_test.exs"]
iex> ~w(foo bar baz)a
[:foo, :bar, :baz]
iex> ~w(foo bar baz)c
[~c"foo", ~c"bar", ~c"baz"]
"""
defmacro sigil_w(term, modifiers)
defmacro sigil_w({:<<>>, _meta, [string]}, modifiers) when is_binary(string) do
split_words(:elixir_interpolation.unescape_string(string), modifiers, __CALLER__)
end
defmacro sigil_w({:<<>>, meta, pieces}, modifiers) do
binary = {:<<>>, meta, unescape_tokens(pieces)}
split_words(binary, modifiers, __CALLER__)
end
@doc ~S"""
Handles the sigil `~W` for list of words.
It returns a list of "words" split by whitespace without interpolations
and without escape characters.
## Modifiers
* `s`: words in the list are strings (default)
* `a`: words in the list are atoms
* `c`: words in the list are charlists
## Examples
iex> ~W(foo #{bar} baz)
["foo", "\#{bar}", "baz"]
"""
defmacro sigil_W(term, modifiers)
defmacro sigil_W({:<<>>, _meta, [string]}, modifiers) when is_binary(string) do
split_words(string, modifiers, __CALLER__)
end
defp split_words(string, [], caller) do
split_words(string, [?s], caller)
end
defp split_words(string, [mod], caller)
when mod == ?s or mod == ?a or mod == ?c do
case is_binary(string) do
true ->
parts = String.split(string)
parts_with_trailing_comma =
:lists.filter(&(byte_size(&1) > 1 and :binary.last(&1) == ?,), parts)
if parts_with_trailing_comma != [] do
stacktrace = Macro.Env.stacktrace(caller)
IO.warn(
"the sigils ~w/~W do not allow trailing commas at the end of each word. " <>
"If the comma is necessary, define a regular list with [...], otherwise remove the comma.",
stacktrace
)
end
case mod do
?s -> parts
?a -> :lists.map(&String.to_atom/1, parts)
?c -> :lists.map(&String.to_charlist/1, parts)
end
false ->
parts = quote(do: String.split(unquote(string)))
case mod do
?s -> parts
?a -> quote(do: :lists.map(&String.to_atom/1, unquote(parts)))
?c -> quote(do: :lists.map(&String.to_charlist/1, unquote(parts)))
end
end
end
defp split_words(_string, _mods, _caller) do
raise ArgumentError, "modifier must be one of: s, a, c"
end
## Shared functions
defp assert_module_scope(env, fun, arity) do
case env.module do
nil -> raise ArgumentError, "cannot invoke #{fun}/#{arity} outside module"
mod -> mod
end
end
defp assert_no_function_scope(env, fun, arity) do
case env.function do
nil -> :ok
_ -> raise ArgumentError, "cannot invoke #{fun}/#{arity} inside function/macro"
end
end
defp assert_no_match_or_guard_scope(context, exp) do
case context do
:match ->
invalid_match!(exp)
:guard ->
raise ArgumentError,
"invalid expression in guard, #{exp} is not allowed in guards. " <>
"To learn more about guards, visit: https://hexdocs.pm/elixir/patterns-and-guards.html"
_ ->
:ok
end
end
defp invalid_match!(exp) do
raise ArgumentError,
"invalid expression in match, #{exp} is not allowed in patterns " <>
"such as function clauses, case clauses or on the left side of the = operator"
end
# Helper to handle the :ok | :error tuple returned from :elixir_interpolation.unescape_tokens
# We need to do this for bootstrapping purposes, actual code can use Macro.unescape_string.
defp unescape_tokens(tokens) do
:lists.map(
fn token ->
case is_binary(token) do
true -> :elixir_interpolation.unescape_string(token)
false -> token
end
end,
tokens
)
end
defp unescape_tokens(tokens, unescape_map) do
:lists.map(
fn token ->
case is_binary(token) do
true -> :elixir_interpolation.unescape_string(token, unescape_map)
false -> token
end
end,
tokens
)
end
defp unescape_list_tokens(tokens) do
escape = fn
{:"::", _, [expr, _]} -> expr
binary when is_binary(binary) -> :elixir_interpolation.unescape_string(binary)
end
:lists.map(escape, tokens)
end
@doc false
defmacro to_char_list(arg) do
IO.warn(
"Kernel.to_char_list/1 is deprecated, use Kernel.to_charlist/1 instead",
Macro.Env.stacktrace(__CALLER__)
)
quote(do: Kernel.to_charlist(unquote(arg)))
end
end