Caps on how much work an expression may cause.
Expressions can be hostile or simply mistaken: for i in 1..1000000000 return i
would otherwise try to build a billion-element list. Limits are checked in the
shared runtime, so every backend enforces them. A limit is a non-negative
integer or :infinity.
The defaults are provisional and need tuning against real workloads.
Fields
:max_source_bytes- the size of the source text. Checked when parsing.:max_nesting_depth- how deeply expressions may nest. Checked when parsing. The nesting of a type counts with the expression it is in:list<list<number>>, the member types of acontext<>, the parameters and the result of afunction<>(D-154).:max_name_tokens- how many tokens a name that the expression itself gives may have: the name of a parameter of a function, of the variable of afor,someorevery, and a key of a context written as a name (first nameis two tokens,a-bthree). Checked when parsing, with the code:name_too_long. The names of the:scopeare the host's and are not limited, and nor is a key written as a string, which is a key whatever its length and can be read as a name if it is not longer than this (D-154).:max_narrowing_facts- how many facts the conditions of an expression may compose about one subject (a name, a local, a path from one) that cannot be answered from what is known of the type the subject is read at, and have to be applied to it at each read (x > 1 and 1 / x > 0 and x > 2 …, withxread in an operation): the work for a subject is the square of the number. The facts that are answered cost no more for the next and are not counted, so a thousandx = "a" or x = "b" or …is within any limit. Checked when analyzing, with the code:too_many_facts(D-154).:max_generated_statements- how many statements the BEAM backend may generate for one expression (the statements of all the functions of the module, therun_1,run_2, … that a long body is cut into among them). The Erlang compiler takes about 20 000 reductions and 6 to 28 KB of memory for each, whatever the expression is: 10 000 of them are about 200 million reductions and 60 to 280 MB at the peak, and the 100 000 bytes that:max_source_byteslets in can make 50 000 (x + x + …: 1.4 GB). The interpreter makes none, and ignores this. Checked when preparing withbackend: :beam, with the code:too_large_to_compile(D-154).:max_list_length- the length of any list a run builds. Aforis held to it as it makes its list, and ends at the first result over it (D-154), and so is a built-in function whose list can be as long as the product of the sizes of its arguments (flatten,concatenate,union,split,extract,get entries): it is refused when the items counted pass it, and the list is not made. Any other list is checked when it is made. Lists nested in the returned value are also checked, including folded constants and host bindings.:max_string_length- the byte size of any string a run builds. A built-in function whose string can be as long as the product of the sizes of its arguments (string join,replace,stringandto jsonof a list or a context) is refused when the bytes counted pass it, and the string is not made. Any other string is checked when it is made. Strings nested in the returned value are checked as well.:max_iterations- the total number of elements that the iterators offor,someandeverytake in one run, across all of them and the ones inside them; a rangefrom..tois walked and not made, so it counts as it goes (D-86).:regex_match_limit- the backtracking budget handed to the regular-expression engine formatches,replace, andsplit.:max_call_depth- how many calls of a function value may be inside one another (D-82).:max_calls- the total number of calls of a function of FEEL in one run, nested or not (D-154). The depth does not bound it: a function that calls itself twice at each level makes about 2ⁿ calls at a depth ofn. The default leaves room forsortof the longest list a run can build with a function of FEEL as its order (about 1.5 million comparisons).:max_diagnostics- how many diagnostics a run may report, warnings and infos with the errors (D-154). A run that reports one in every turn of a loop or call of a function makes as many as it has turns, each about 300 bytes, andmax_iterationsandmax_callsdo not bound them. The run that would report one more ends, in either mode, with the diagnostics it has in the error. A strict run ends at its first error whatever this is. A deadline or process heap cap is not part of this struct. PublicFeelcalls supply these by default throughFeel.Worker, with shared binaries included at garbage collection. Early per-value construction checks remain active with either sandbox setting. There is no cumulative allocation quota; a process heap policy is not a complete VM memory bound. See the security model for worker ownership, nested policies and host responsibilities.
Summary
Types
@type limit() :: non_neg_integer() | :infinity
A non-negative integer, or :infinity for no limit.
@type t() :: %Feel.Limits{ max_call_depth: limit(), max_calls: limit(), max_diagnostics: limit(), max_generated_statements: limit(), max_iterations: limit(), max_list_length: limit(), max_name_tokens: limit(), max_narrowing_facts: limit(), max_nesting_depth: limit(), max_source_bytes: limit(), max_string_length: limit(), regex_match_limit: limit() }
Functions
@spec default() :: t()
Returns the default limits.
iex> Feel.Limits.default().max_nesting_depth
100
Builds limits from the defaults, overriding the given fields.
Raises ArgumentError for an unknown field or for a value that is neither a
non-negative integer nor :infinity.
iex> Feel.Limits.new(max_list_length: 10, max_iterations: :infinity).max_list_length
10
Whether a value is a limits struct with valid fields, including structs built without new/1.