Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions lib/eex/lib/eex.ex
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,15 @@ defmodule EEx do
| {:expr | :start_expr | :middle_expr | :end_expr, marker, charlist, metadata}
| {:eof, metadata}

@type tokenize_opt ::
{:file, binary()}
| {:line, line}
| {:column, column}
| {:indentation, non_neg_integer}
| {:trim, boolean()}

@type compile_opt :: tokenize_opt | {:engine, module()} | {:parser_options, Code.parser_opts()}

@doc """
Generates a function definition from the given string.

Expand Down Expand Up @@ -220,7 +229,7 @@ defmodule EEx do
"3"

"""
@spec compile_string(String.t(), keyword) :: Macro.t()
@spec compile_string(String.t(), [compile_opt]) :: Macro.t()
def compile_string(source, options \\ []) when is_binary(source) and is_list(options) do
case tokenize(source, options) do
{:ok, tokens} ->
Expand Down Expand Up @@ -259,7 +268,7 @@ defmodule EEx do
#=> "3"

"""
@spec compile_file(Path.t(), keyword) :: Macro.t()
@spec compile_file(Path.t(), [compile_opt]) :: Macro.t()
def compile_file(filename, options \\ []) when is_list(options) do
filename = IO.chardata_to_string(filename)
options = Keyword.merge([file: filename, line: 1], options)
Expand All @@ -277,7 +286,7 @@ defmodule EEx do
"foo baz"

"""
@spec eval_string(String.t(), keyword, keyword) :: String.t()
@spec eval_string(String.t(), keyword, [compile_opt]) :: String.t()
def eval_string(source, bindings \\ [], options \\ [])
when is_binary(source) and is_list(bindings) and is_list(options) do
compiled = compile_string(source, options)
Expand All @@ -299,7 +308,7 @@ defmodule EEx do
#=> "foo baz"

"""
@spec eval_file(Path.t(), keyword, keyword) :: String.t()
@spec eval_file(Path.t(), keyword, [compile_opt]) :: String.t()
def eval_file(filename, bindings \\ [], options \\ [])
when is_list(bindings) and is_list(options) do
filename = IO.chardata_to_string(filename)
Expand Down Expand Up @@ -339,7 +348,7 @@ defmodule EEx do
Note new tokens may be added in the future.
"""
@doc since: "1.14.0"
@spec tokenize([char()] | String.t(), opts :: keyword) ::
@spec tokenize([char()] | String.t(), [tokenize_opt]) ::
{:ok, [token()]} | {:error, String.t(), metadata()}
def tokenize(contents, opts \\ []) do
EEx.Compiler.tokenize(contents, opts)
Expand Down
18 changes: 17 additions & 1 deletion lib/eex/lib/eex/compiler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,22 @@ defmodule EEx.Compiler do
@h_spaces [?\s, ?\t]
@all_spaces [?\s, ?\t, ?\n, ?\r]

@typedoc """
Options for EEx compilation functions.

These options control various aspects of EEx template compilation including
file information, parsing behavior, and the template engine to use.
"""
@type compile_opts :: [
file: String.t(),
line: pos_integer(),
column: pos_integer(),
indentation: non_neg_integer(),
trim: boolean(),
parser_options: Code.parser_opts(),
engine: module()
]

@doc """
Tokenize EEx contents.
"""
Expand Down Expand Up @@ -290,7 +306,7 @@ defmodule EEx.Compiler do
and the engine together by handling the tokens and invoking
the engine every time a full expression or text is received.
"""
@spec compile([EEx.token()], String.t(), keyword) :: Macro.t()
@spec compile([EEx.token()], String.t(), compile_opts) :: Macro.t()
def compile(tokens, source, opts) do
file = opts[:file] || "nofile"
line = opts[:line] || 1
Expand Down
19 changes: 18 additions & 1 deletion lib/eex/lib/eex/engine.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,29 @@ defmodule EEx.Engine do

@type state :: term

@typedoc """
Options passed to engine initialization.

These are the same options passed to `EEx.Compiler.compile/3`,
allowing engines to access compilation settings and customize
their behavior accordingly.
"""
@type init_opts :: [
file: String.t(),
line: pos_integer(),
column: pos_integer(),
indentation: non_neg_integer(),
trim: boolean(),
parser_options: Code.parser_opts(),
engine: module()
]

@doc """
Called at the beginning of every template.

It must return the initial state.
"""
@callback init(opts :: keyword) :: state
@callback init(opts :: init_opts) :: state

@doc """
Called at the end of every template.
Expand Down
18 changes: 17 additions & 1 deletion lib/elixir/lib/calendar.ex
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,22 @@ defmodule Calendar do
"""
@type time_zone_database :: module()

@typedoc """
Options for formatting dates and times with `strftime/3`.
"""
@type strftime_opts :: [
preferred_datetime: String.t(),
preferred_date: String.t(),
preferred_time: String.t(),
am_pm_names: (:am | :pm -> String.t()) | (:am | :pm, map() -> String.t()),
month_names: (pos_integer() -> String.t()) | (pos_integer(), map() -> String.t()),
abbreviated_month_names:
(pos_integer() -> String.t()) | (pos_integer(), map() -> String.t()),
day_of_week_names: (pos_integer() -> String.t()) | (pos_integer(), map() -> String.t()),
abbreviated_day_of_week_names:
(pos_integer() -> String.t()) | (pos_integer(), map() -> String.t())
]

@doc """
Returns how many days there are in the given month of the given year.
"""
Expand Down Expand Up @@ -617,7 +633,7 @@ defmodule Calendar do

"""
@doc since: "1.11.0"
@spec strftime(map(), String.t(), keyword()) :: String.t()
@spec strftime(map(), String.t(), strftime_opts()) :: String.t()
def strftime(date_or_time_or_datetime, string_format, user_options \\ [])
when is_map(date_or_time_or_datetime) and is_binary(string_format) do
parse(
Expand Down
17 changes: 17 additions & 0 deletions lib/elixir/lib/calendar/duration.ex
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,22 @@ defmodule Duration do
"""
@type duration :: t | [unit_pair]

@typedoc """
Options for `Duration.to_string/2`.
"""
@type to_string_opts :: [
units: [
year: String.t(),
month: String.t(),
week: String.t(),
day: String.t(),
hour: String.t(),
minute: String.t(),
second: String.t()
],
separator: String.t()
]

@microseconds_per_second 1_000_000

@doc """
Expand Down Expand Up @@ -436,6 +452,7 @@ defmodule Duration do
"""
@doc since: "1.18.0"
@spec to_string(t, to_string_opts) :: String.t()
def to_string(%Duration{} = duration, opts \\ []) do
units = Keyword.get(opts, :units, [])
separator = Keyword.get(opts, :separator, " ")
Expand Down
97 changes: 72 additions & 25 deletions lib/elixir/lib/code.ex
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,49 @@ defmodule Code do
"""
@type position() :: line() | {line :: pos_integer(), column :: pos_integer()}

@typedoc """
Options for code formatting functions.
"""
@type format_opts :: [
file: binary(),
line: pos_integer(),
line_length: pos_integer(),
locals_without_parens: keyword(),
force_do_end_blocks: boolean(),
migrate: boolean(),
migrate_bitstring_modifiers: boolean(),
migrate_call_parens_on_pipe: boolean(),
migrate_charlists_as_sigils: boolean(),
migrate_unless: boolean()
]

@typedoc """
Options for parsing functions that convert strings to quoted expressions.
"""
@type parser_opts :: [
file: binary(),
line: pos_integer(),
column: pos_integer(),
indentation: non_neg_integer(),
columns: boolean(),
unescape: boolean(),
existing_atoms_only: boolean(),
token_metadata: boolean(),
literal_encoder: (term(), Macro.metadata() -> term()),
static_atoms_encoder: (atom() -> term()),
emit_warnings: boolean()
]

@typedoc """
Options for environment evaluation functions like eval_string/3 and eval_quoted/3.
"""
@type env_eval_opts :: [
file: binary(),
line: pos_integer(),
module: module(),
prune_binding: boolean()
]

@boolean_compiler_options [
:docs,
:debug_info,
Expand Down Expand Up @@ -560,7 +603,7 @@ defmodule Code do
[a: 1, b: 2]

"""
@spec eval_string(List.Chars.t(), binding, Macro.Env.t() | keyword) :: {term, binding}
@spec eval_string(List.Chars.t(), binding, Macro.Env.t() | env_eval_opts) :: {term, binding}
def eval_string(string, binding \\ [], opts \\ [])

def eval_string(string, binding, %Macro.Env{} = env) do
Expand Down Expand Up @@ -615,7 +658,8 @@ defmodule Code do

"""
@doc since: "1.15.0"
@spec with_diagnostics(keyword(), (-> result)) :: {result, [diagnostic(:warning | :error)]}
@spec with_diagnostics([log: boolean()], (-> result)) ::
{result, [diagnostic(:warning | :error)]}
when result: term()
def with_diagnostics(opts \\ [], fun) do
value = :erlang.get(:elixir_code_diagnostics)
Expand Down Expand Up @@ -648,7 +692,7 @@ defmodule Code do
Defaults to `true`.
"""
@doc since: "1.15.0"
@spec print_diagnostic(diagnostic(:warning | :error), keyword()) :: :ok
@spec print_diagnostic(diagnostic(:warning | :error), snippet: boolean()) :: :ok
def print_diagnostic(diagnostic, opts \\ []) do
read_snippet? = Keyword.get(opts, :snippet, true)
:elixir_errors.print_diagnostic(diagnostic, read_snippet?)
Expand Down Expand Up @@ -1035,7 +1079,7 @@ defmodule Code do
address the deprecation warnings.
"""
@doc since: "1.6.0"
@spec format_string!(binary, keyword) :: iodata
@spec format_string!(binary, format_opts) :: iodata
def format_string!(string, opts \\ []) when is_binary(string) and is_list(opts) do
line_length = Keyword.get(opts, :line_length, 98)

Expand All @@ -1060,7 +1104,7 @@ defmodule Code do
available options.
"""
@doc since: "1.6.0"
@spec format_file!(binary, keyword) :: iodata
@spec format_file!(binary, format_opts) :: iodata
def format_file!(file, opts \\ []) when is_binary(file) and is_list(opts) do
string = File.read!(file)
formatted = format_string!(string, [file: file, line: 1] ++ opts)
Expand Down Expand Up @@ -1098,7 +1142,7 @@ defmodule Code do
[a: 1, b: 2]

"""
@spec eval_quoted(Macro.t(), binding, Macro.Env.t() | keyword) :: {term, binding}
@spec eval_quoted(Macro.t(), binding, Macro.Env.t() | env_eval_opts) :: {term, binding}
def eval_quoted(quoted, binding \\ [], env_or_opts \\ []) do
{value, binding, _env} =
eval_verify(:eval_quoted, [quoted, binding, env_for_eval(env_or_opts)])
Expand Down Expand Up @@ -1129,8 +1173,15 @@ defmodule Code do
* `:line` - the line on which the script starts

* `:module` - the module to run the environment on

* `:prune_binding` - (since v1.14.2) prune binding to keep only
variables read or written by the evaluated code. Note that
variables used by modules are always pruned, even if later used
by the modules. You can submit to the `:on_module` tracer event
and access the variables used by the module from its environment.
"""
@doc since: "1.14.0"
@spec env_for_eval(Macro.Env.t() | env_eval_opts) :: Macro.Env.t()
def env_for_eval(env_or_opts), do: :elixir.env_for_eval(env_or_opts)

@doc """
Expand All @@ -1144,15 +1195,11 @@ defmodule Code do

## Options

* `:prune_binding` - (since v1.14.2) prune binding to keep only
variables read or written by the evaluated code. Note that
variables used by modules are always pruned, even if later used
by the modules. You can submit to the `:on_module` tracer event
and access the variables used by the module from its environment.
It accepts the same options as `env_for_eval/1`.

"""
@doc since: "1.14.0"
@spec eval_quoted_with_env(Macro.t(), binding, Macro.Env.t(), keyword) ::
@spec eval_quoted_with_env(Macro.t(), binding, Macro.Env.t(), env_eval_opts) ::
{term, binding, Macro.Env.t()}
def eval_quoted_with_env(quoted, binding, %Macro.Env{} = env, opts \\ [])
when is_list(binding) do
Expand Down Expand Up @@ -1263,7 +1310,7 @@ defmodule Code do
{:error, {[line: 1, column: 4], "syntax error before: ", "\"3\""}}

"""
@spec string_to_quoted(List.Chars.t(), keyword) ::
@spec string_to_quoted(List.Chars.t(), parser_opts) ::
{:ok, Macro.t()} | {:error, {location :: keyword, binary | {binary, binary}, binary}}
def string_to_quoted(string, opts \\ []) when is_list(opts) do
file = Keyword.get(opts, :file, "nofile")
Expand All @@ -1290,7 +1337,7 @@ defmodule Code do

Check `string_to_quoted/2` for options information.
"""
@spec string_to_quoted!(List.Chars.t(), keyword) :: Macro.t()
@spec string_to_quoted!(List.Chars.t(), parser_opts) :: Macro.t()
def string_to_quoted!(string, opts \\ []) when is_list(opts) do
file = Keyword.get(opts, :file, "nofile")
line = Keyword.get(opts, :line, 1)
Expand Down Expand Up @@ -1341,7 +1388,7 @@ defmodule Code do

"""
@doc since: "1.13.0"
@spec string_to_quoted_with_comments(List.Chars.t(), keyword) ::
@spec string_to_quoted_with_comments(List.Chars.t(), parser_opts) ::
{:ok, Macro.t(), list(map())} | {:error, {location :: keyword, term, term}}
def string_to_quoted_with_comments(string, opts \\ []) when is_list(opts) do
charlist = to_charlist(string)
Expand Down Expand Up @@ -1371,7 +1418,7 @@ defmodule Code do
Check `string_to_quoted/2` for options information.
"""
@doc since: "1.13.0"
@spec string_to_quoted_with_comments!(List.Chars.t(), keyword) :: {Macro.t(), list(map())}
@spec string_to_quoted_with_comments!(List.Chars.t(), parser_opts) :: {Macro.t(), list(map())}
def string_to_quoted_with_comments!(string, opts \\ []) do
charlist = to_charlist(string)

Expand Down Expand Up @@ -1456,6 +1503,9 @@ defmodule Code do

## Options

This function accepts all options supported by `format_string!/2` for controlling
code formatting, plus these additional options:

* `:comments` - the list of comments associated with the quoted expression.
Defaults to `[]`. It is recommended that both `:token_metadata` and
`:literal_encoder` options are given to `string_to_quoted_with_comments/2`
Expand All @@ -1466,17 +1516,14 @@ defmodule Code do
`string_to_quoted/2`, setting this option to `false` will prevent it from
escaping the sequences twice. Defaults to `true`.

* `:locals_without_parens` - a keyword list of name and arity
pairs that should be kept without parens whenever possible.
The arity may be the atom `:*`, which implies all arities of
that name. The formatter already includes a list of functions
and this option augments this list.

* `:syntax_colors` - a keyword list of colors the output is colorized.
See `Inspect.Opts` for more information.
See `format_string!/2` for the full list of formatting options including
`:file`, `:line`, `:line_length`, `:locals_without_parens`, `:force_do_end_blocks`,
`:syntax_colors`, and all migration options like `:migrate_charlists_as_sigils`.
"""
@doc since: "1.13.0"
@spec quoted_to_algebra(Macro.t(), keyword) :: Inspect.Algebra.t()
@spec quoted_to_algebra(Macro.t(), [
Code.Formatter.to_algebra_opt() | Code.Normalizer.normalize_opt()
]) :: Inspect.Algebra.t()
def quoted_to_algebra(quoted, opts \\ []) do
quoted
|> Code.Normalizer.normalize(opts)
Expand Down
Loading
Loading