cerl(3)

๐Ÿ“ฆ
version 29.0.6 ยท 3 versions
, in ubuntu stonking

๐Ÿ’– cerl โ€” Core Erlang abstract syntax trees ๐Ÿ’–

okay bestie, welcome to cerl(3), the Erlang module definition for Core Erlang abstract syntax trees. this is the Erlang compiler's inner sanctum, so buckle up ๐ŸŽ€


โœจ NAME โœจ

cerl โ€” Core Erlang abstract syntax trees. that's the whole vibe. trees of syntax. abstract ones. ๐Ÿ’…


๐ŸŒธ DESCRIPTION ๐ŸŒธ

โš ๏ธ NOTE: the public interface of the Erlang compiler lives in module compile. This module is an internal part of the compiler. Its API is not guaranteed to remain compatible between releases. so likeโ€ฆ use it, love it, but don't build your whole personality on it staying the same, fr fr ๐Ÿ˜ญ

so this module defines an abstract data type for representing Core Erlang source code as syntax trees. trees! ๐ŸŒณโœจ

if you're a first-time user, the recommended starting point is the documentation of the function type/1. that's your entry point, bestie. start there ๐Ÿซถ

โš ๏ธ NOTE: This module deals with the composition and decomposition of syntactic entities (as opposed to semantic ones). its whole purpose is to hide all direct references to the data structures used to represent these entities. With few exceptions, the functions in this module perform no semantic interpretation of their inputs, and in general, the user is assumed to pass type-correct arguments โ€” if this is not done, the effects are not defined. ๐Ÿ’€ so like, you gotta do your part okay??

Currently, the internal data structure used is the same as the record-based data structures used traditionally in the Beam compiler. The internal representations of abstract syntax trees are subject to change without notice, and should not be documented outside this module. ๐Ÿ™ˆ

Furthermore, we do not give any guarantees on how an abstract syntax tree may or may not be represented, with the following exceptions:

  • no syntax tree is represented by a single atom, such as none
  • no syntax tree is represented by a list constructor [X | Y]
  • no syntax tree is represented by the empty list []

This can be relied on when writing functions that operate on syntax trees. those three things are your safe little constants, periodt ๐Ÿ‘‘


๐Ÿฆ‹ DATA TYPES ๐Ÿฆ‹

okay so here's the whole roster. every single one. no skipping, we don't do that here ๐ŸŽ€

c_alias() :: #c_alias{}.

c_apply() :: #c_apply{}.

c_binary() :: #c_binary{}.

c_bitstr() :: #c_bitstr{}.

c_call() :: #c_call{}.

c_case() :: #c_case{}.

c_catch() :: #c_catch{}.

c_clause() :: #c_clause{}.

c_cons() :: #c_cons{}.

c_fun() :: #c_fun{}.

c_lct() :: c_literal() | c_cons() | c_tuple().

c_let() :: #c_let{}.

c_letrec() :: #c_letrec{}.

c_literal() :: #c_literal{}.

c_map() :: #c_map{}.

c_map_pair() :: #c_map_pair{}.

c_module() :: #c_module{}.

c_opaque() :: #c_opaque{}.

c_primop() :: #c_primop{}.

c_receive() :: #c_receive{}.

c_record() :: #c_record{}.

c_record_pair() :: #c_record_pair{}.

c_seq() :: #c_seq{}.

c_try() :: #c_try{}.

c_tuple() :: #c_tuple{}.

c_values() :: #c_values{}.

c_var() :: #c_var{}.

and now the big union type, the main character herself ๐ŸŒˆ:

cerl() ::
          c_alias() |
          c_apply() |
          c_binary() |
          c_bitstr() |
          c_call() |
          c_case() |
          c_catch() |
          c_clause() |
          c_cons() |
          c_fun() |
          c_let() |
          c_letrec() |
          c_literal() |
          c_map() |
          c_map_pair() |
          c_record() |
          c_record_pair() |
          c_module() |
          c_opaque() |
          c_primop() |
          c_receive() |
          c_seq() |
          c_try() |
          c_tuple() |
          c_values() |
          c_var().

the type tags, so you know what flavor of node you're holding ๐Ÿ“:

ctype() ::
          alias | apply | binary | bitstr | call | 'case' | 'catch' |
          clause | cons | 'fun' | 'let' | letrec | literal | map |
          map_pair | module | opaque | primop | 'receive' | seq |
          record | record_pair | 'try' | tuple | values | var.

data types for data types, iykyk:

dtype() :: cons | tuple | {atomic, value()}.

map_op() :: #c_literal{val :: assoc} | #c_literal{val :: exact}.

record_id() :: c_literal().

value() :: integer() | float() | atom() | [].

var_name() :: integer() | atom() | {atom(), integer()}.

๐Ÿ”ฅ FUNCTIONS ๐Ÿ”ฅ

  • abstract(Term :: term()) -> c_literal() โ€” Creates a syntax tree corresponding to an Erlang term. ๐ŸŒณ

Term must be a literal term, that is, one that can be represented as a source code literal. Thus, it may not contain a process identifier, port, reference, binary or function value as a subterm. ๐Ÿšซ

Note: This is a constant time operation. โšก

See also: ann_abstract/2, concrete/1, is_literal/1, is_literal_term/1.

  • add_ann(Annotations :: [term()], Node :: cerl()) -> cerl() โ€” Appends Annotations to the list of user annotations of Node. ๐Ÿ’…
Note: this is equivalent to set_ann(Node, Annotations ++ get_ann(Node)), but potentially more efficient. โœจ

See also: get_ann/1, set_ann/2.

  • alias_pat(Node :: c_alias()) -> cerl() โ€” Returns the pattern subtree of an abstract pattern alias. ๐ŸŽ€

See also: c_alias/2.

  • alias_var(Node :: c_alias()) -> c_var() โ€” Returns the variable subtree of an abstract pattern alias. ๐Ÿฆ‹

See also: c_alias/2.

  • ann_abstract(Annotations :: [term()], Term :: term()) -> c_literal() โ€” the annotated version, bestie.

See also: abstract/1.

  • ann_c_alias(Annotations :: [term()], Variable :: c_var(), Pattern :: cerl()) -> c_alias() โ€” annotated alias constructor.

See also: c_alias/2.

  • ann_c_apply(Annotations :: [term()], Operator :: cerl(), Arguments :: [cerl()]) -> c_apply() โ€” annotated apply constructor.

See also: c_apply/2.

  • ann_c_atom(Annotations :: [term()], Name :: atom() | string()) -> c_literal() โ€” annotated atom constructor.

See also: c_atom/1.

  • ann_c_binary(Annotations :: [term()], Segments :: [cerl()]) -> c_binary() โ€” annotated binary constructor.

See also: c_binary/1.

  • ann_c_bitstr(Annotations :: [term()], Value :: cerl(), Size :: cerl(), Type :: cerl(), Flags :: cerl()) -> c_bitstr() โ€” Equivalent to ann_c_bitstr(As, Value, Size, abstract(1), Type, Flags). ๐Ÿ’ซ
  • ann_c_bitstr(Annotations :: [term()], Value :: cerl(), Size :: cerl(), Unit :: cerl(), Type :: cerl(), Flags :: cerl()) -> c_bitstr() โ€” the six-arg glow-up version.

See also: ann_c_bitstr/5, c_bitstr/5.

  • ann_c_call(Annotations :: [term()], Module :: cerl(), Name :: cerl(), Arguments :: [cerl()]) -> c_call() โ€” annotated call constructor.

See also: c_call/3.

  • ann_c_case(Annotations :: [term()], Argument :: cerl(), Clauses :: [cerl()]) -> c_case() โ€” annotated case constructor.

See also: c_case/2.

  • ann_c_catch(Annotations :: [term()], Body :: cerl()) -> c_catch() โ€” annotated catch constructor.

See also: c_catch/1.

  • ann_c_char(Annotations :: [term()], Value :: char()) -> c_literal() โ€” annotated char constructor.

See also: c_char/1.

  • ann_c_clause(Annotations :: [term()], Patterns :: [cerl()], Body :: cerl()) -> c_clause() โ€” Equivalent to ann_c_clause(As, Patterns, c_atom(true), Body). ๐Ÿ’…

See also: c_clause/3.

  • ann_c_clause(Annotations :: [term()], Patterns :: [cerl()], Guard :: cerl(), Body :: cerl()) -> c_clause() โ€” the four-arg version, with the guard front and center.

See also: ann_c_clause/3, c_clause/3.

  • ann_c_cons(Annotations :: [term()], Head :: cerl(), Tail :: cerl()) -> c_literal() | c_cons() โ€” annotated cons constructor.

See also: c_cons/2.

  • ann_c_cons_skel(Annotations :: [term()], Head :: cerl(), Tail :: cerl()) -> c_cons() โ€” annotated cons skeleton, the skele-bones version. ๐Ÿฆด

See also: c_cons_skel/2.

  • ann_c_float(Annotations :: [term()], Value :: float()) -> c_literal() โ€” annotated float constructor.

See also: c_float/1.

  • ann_c_fname(Annotations :: [term()], Name :: atom(), Arity :: arity()) -> c_var() โ€” Equivalent to ann_c_var(As, {Atom, Arity}). โœจ

See also: c_fname/2.

  • ann_c_fun(Annotations :: [term()], Variables :: [cerl()], Body :: cerl()) -> c_fun() โ€” annotated fun constructor.

See also: c_fun/2.

  • ann_c_int(Annotations :: [term()], Value :: integer()) -> c_literal() โ€” annotated int constructor.

See also: c_int/1.

  • ann_c_let(Annotations :: [term()], Variables :: [cerl()], Argument :: cerl(), Body :: cerl()) -> c_let() โ€” annotated let constructor.

See also: c_let/3.

  • ann_c_letrec(Annotations :: [term()], Definitions :: [{cerl(), cerl()}], Body :: cerl()) -> c_letrec() โ€” annotated letrec constructor.

See also: c_letrec/2.

  • ann_c_map(Annotations :: [term()], Pairs :: [c_map_pair()]) -> c_map() | c_literal() โ€” annotated map constructor.

See also: c_map/1.

  • ann_c_map(Annotations :: [term()], Argument :: c_map() | c_literal(), Pairs :: [c_map_pair()]) -> c_map() | c_literal() โ€” the two-arg, with-argument version.

See also: c_map/2

  • ann_c_map_pair(Annotations :: [term()], Operation :: cerl(), Key :: cerl(), Value :: cerl()) -> c_map_pair() โ€” annotated map pair constructor.

See also: c_map_pair/2, c_map_pair_exact/2.

  • ann_c_map_pattern(Annotations :: [term()], Pairs :: [c_map_pair()]) -> c_map() โ€” annotated map pattern constructor.

See also: c_map_pattern/2

  • ann_c_module(Annotations :: [term()], Name :: cerl(), Exports :: [cerl()], Definitions :: [{cerl(), cerl()}]) -> c_module() โ€” annotated module constructor.

See also: ann_c_module/5, c_module/3.

  • ann_c_module(Annotations :: [term()], Name :: cerl(), Exports :: [cerl()], Attributes :: [{cerl(), cerl()}], Definitions :: [{cerl(), cerl()}]) -> c_module() โ€” the five-arg version, now with attributes ๐ŸŽ€

See also: ann_c_module/4, c_module/4.

  • ann_c_nil(Annotations :: [term()]) -> c_literal() โ€” annotated nil constructor. the fancy version of nothing. ๐Ÿ’…

See also: c_nil/0.

  • ann_c_primop(Annotations :: [term()], Name :: cerl(), Arguments :: [cerl()]) -> c_primop() โ€” annotated primop constructor.

See also: c_primop/2.

  • ann_c_receive(Annotations :: [term()], Clauses :: [cerl()]) -> c_receive() โ€” Equivalent to ann_c_receive(As, Clauses, c_atom(infinity), c_atom(true)). ๐Ÿ“จ

See also: c_atom/1, c_receive/3.


okay we're not done yet bestie, there's MORE ๐Ÿ’–

  • ann_c_receive(Annotations :: [term()], Clauses :: [cerl()], Timeout :: cerl(), Actions :: cerl()) -> c_receive() โœจ See also: ann_c_receive/2, c_receive/3.
  • ann_c_record(Annotations :: [term()], Argument :: c_var() | c_record() | c_literal(), Id :: term(), Pairs :: [c_record_pair()]) -> #c_record{} ๐Ÿ’… See also: c_record/2.
  • ann_c_record_pair(Annotations :: [term()], Key :: cerl(), Value :: cerl()) -> c_record_pair() ๐ŸŽ€ See also: c_record/2.
  • ann_c_seq(Annotations :: [term()], Argument :: cerl(), Body :: cerl()) -> c_seq() ๐ŸŒธ See also: c_seq/2.
  • ann_c_string(Annotations :: [term()], Value :: string()) -> c_literal() ๐Ÿฆ‹ See also: c_string/1.
  • ann_c_try(Annotations :: [term()], Argument :: cerl(), Variables :: [cerl()], Body :: cerl(), ExceptionVars :: [cerl()], Handler :: cerl()) -> c_try() ๐Ÿ’œ See also: c_try/5.
  • ann_c_tuple(Annotations :: [term()], Elements :: [cerl()]) -> c_tuple() | c_literal() โœจ See also: c_tuple/1.
  • ann_c_tuple_skel(Annotations :: [term()], Elements :: [cerl()]) -> c_tuple() ๐Ÿ’ซ See also: c_tuple_skel/1.
  • ann_c_values(Annotations :: [term()], Values :: [cerl()]) -> c_values() ๐ŸŒˆ See also: c_values/1.
  • ann_c_var(Annotations :: [term()], Name :: var_name()) -> c_var() ๐Ÿ‘‘ See also: c_var/1.
  • ann_make_data(Annotations :: [term()], Type :: dtype(), Elementes :: [cerl()]) -> c_lct() ๐Ÿ’Ž See also: make_data/2.
  • ann_make_data_skel(Annotations :: [term()], Type :: dtype(), Elements :: [cerl()]) -> c_lct() ๐Ÿซถ See also: make_data_skel/2.
  • ann_make_list(Annotations :: [term()], List :: [cerl()], Tail :: cerl() | none) -> cerl() ๐Ÿ’– See also: ann_make_list/2, make_list/2.
  • ann_make_tree(Annotations :: [term()], Type :: ctype(), Groups :: [[cerl()], ...]) -> cerl() โ€” Makes a syntax tree with those annotations, type, and subtrees. โœจ (Yeah, it's literally building a tree, no cap.) Peep make_tree/2 for the deets. See also: make_tree/2.
  • apply_args(Node :: c_apply()) -> [cerl()] โ€” Returns the list of argument subtrees of an abstract function application. ๐Ÿ”ฅ See also: apply_arity/1, c_apply/2.
  • apply_arity(Node :: c_apply()) -> arity() โ€” Returns the number of argument subtrees of an abstract function application. ๐Ÿงฎ
Note: this is equivalent to length(apply_args(Node)), but potentially more efficient.

See also: apply_args/1, c_apply/2.

  • apply_op(Node :: c_apply()) -> cerl() โ€” Returns the operator subtree of an abstract function application. ๐Ÿ‘‘ See also: c_apply/2.
  • atom_lit(Node :: cerl()) -> nonempty_string() โ€” Returns the literal string represented by an abstract atom. This always includes surrounding single-quote characters. ๐Ÿ“
Note that an abstract atom may have several literal representations, and that the representation yielded by this function is not fixed; for example, atom_lit(c_atom("a\012b")) could yield the string "\'a\\nb\'".

See also: c_atom/1.

  • atom_name(Node :: c_literal()) -> string() โ€” Returns the printname of an abstract atom. ๐Ÿท๏ธ See also: c_atom/1.
  • atom_val(Node :: c_literal()) -> atom() โ€” Returns the value represented by an abstract atom. ๐Ÿ’Ž See also: c_atom/1.
  • binary_segments(Node :: c_binary()) -> [cerl()] โ€” Returns the list of segment subtrees of an abstract binary-template. ๐Ÿงฉ See also: c_binary/1, c_bitstr/5.
  • bitstr_bitsize(Node :: c_bitstr()) -> all | any | utf | non_neg_integer() โ€” Returns the total size in bits of an abstract bit-string template. ๐Ÿ“ If the size field is an integer literal, the result is the product of the size and unit values; if the size field is the atom literal all, the atom all is returned. If the size is not a literal, the atom any is returned. If the type of the bit-string segment is one of utf8, utf16 or utf32, the atom utf is returned. See also: c_bitstr/5.
  • bitstr_flags(Node :: c_bitstr()) -> cerl() โ€” Returns the flags subtree of an abstract bit-string template. ๐Ÿšฉ See also: c_bitstr/5.
  • bitstr_size(Node :: c_bitstr()) -> cerl() โ€” Returns the size subtree of an abstract bit-string template. ๐Ÿ“ See also: c_bitstr/5.
  • bitstr_type(Node :: c_bitstr()) -> cerl() โ€” Returns the type subtree of an abstract bit-string template. ๐Ÿท๏ธ See also: c_bitstr/5.
  • bitstr_unit(Node :: c_bitstr()) -> cerl() โ€” Returns the unit subtree of an abstract bit-string template. ๐Ÿ“ See also: c_bitstr/5.
  • bitstr_val(Node :: c_bitstr()) -> cerl() โ€” Returns the value subtree of an abstract bit-string template. ๐Ÿ’Ž See also: c_bitstr/5.
  • c_alias(Variable :: c_var(), Pattern :: cerl()) -> c_alias() โ€” Creates an abstract pattern alias. ๐Ÿ”— The result represents "Variable = Pattern". See also: alias_pat/1, alias_var/1, ann_c_alias/3, c_clause/3, is_c_alias/1, update_c_alias/3.
  • c_apply(Operator :: cerl(), Arguments :: [cerl()]) -> c_apply() โ€” Creates an abstract function application. ๐Ÿš€ If Arguments is [A1, ..., An], the result represents "apply Operator(A1, ..., An)". See also: ann_c_apply/3, apply_args/1, apply_arity/1, apply_op/1, c_call/3, c_primop/2, is_c_apply/1, update_c_apply/3.
  • c_atom(Name :: atom() | string()) -> c_literal() โ€” Creates an abstract atom literal. โš›๏ธ The print name of the atom is the character sequence represented by Name.
Note: passing a string as argument to this function causes a corresponding atom to be created for the internal representation.

See also: ann_c_atom/2, atom_lit/1, atom_name/1, atom_val/1, is_c_atom/1.

  • c_binary(Segments :: [cerl()]) -> c_binary() โ€” Creates an abstract binary-template. ๐Ÿงฌ A binary object is in this context is a sequence of an arbitrary number of bits. (The number of bits used to be evenly divisible by 8, but after the introduction of bit strings in the Erlang language, the choice was made to use the binary template for all bit strings.) It is specified by zero or more bit-string template segments of arbitrary lengths (in number of bits). If Segments is [S1, ..., Sn], the result represents "#{S1, ..., Sn}#". All the Si must have type bitstr. See also: ann_c_binary/2, binary_segments/1, c_bitstr/5, is_c_binary/1, update_c_binary/2.
  • c_bitstr(Value :: cerl(), Type :: cerl(), Flags :: cerl()) -> c_bitstr() โ€” Equivalent to c_bitstr(Value, abstract(all), abstract(1), Type, Flags). โœจ
  • c_bitstr(Value :: cerl(), Size :: cerl(), Unit :: cerl(), Type :: cerl(), Flags :: cerl()) -> c_bitstr() โ€” Creates an abstract bit-string template. ๐Ÿงต These can only occur as components of an abstract binary-template (see c_binary/1). The result represents "#<Value>(Size, Unit, Type, Flags)", where Unit must represent a positive integer constant, Type must represent a constant atom (one of 'integer', 'float', 'binary', 'utf8', 'utf16' or 'utf32'), and Flags must represent a constant list "[F1, ..., Fn]" where all the Fi are atoms. See also: ann_c_bitstr/6, bitstr_flags/1, bitstr_size/1, bitstr_type/1, bitstr_unit/1, bitstr_val/1, c_binary/1, is_c_bitstr/1, update_c_bitstr/6.
  • c_call(Module :: cerl(), Name :: cerl(), Arguments :: [cerl()]) -> c_call() โ€” Creates an abstract inter-module call. ๐Ÿ“ž If Arguments is [A1, ..., An], the result represents "call Module:Name(A1, ..., An)". See also: ann_c_call/4, c_apply/2, c_primop/2, call_args/1, call_arity/1, call_module/1, call_name/1, is_c_call/1, update_c_call/4.
  • c_case(Argument :: cerl(), Clauses :: [cerl()]) -> c_case() โ€” Creates an abstract case-expression. ๐ŸŽญ If Clauses is [C1, ..., Cn], the result represents "case Argument of C1 ... Cn end". Clauses must not be empty. See also: ann_c_case/3, c_clause/3, case_arg/1, case_arity/1, case_clauses/1, is_c_case/1, update_c_case/3.
  • c_catch(Body :: cerl()) -> c_catch() โ€” Creates an abstract catch-expression. ๐Ÿฅ… The result represents "catch Body".
Note: catch-expressions can be rewritten as try-expressions, and will eventually be removed from Core Erlang.

See also: ann_c_catch/2, c_try/5, catch_body/1, is_c_catch/1, update_c_catch/2.

  • c_char(Value :: non_neg_integer()) -> c_literal() โ€” Creates an abstract character literal. ๐Ÿ”ค If the local implementation of Erlang defines char/0 as a subset of integer/0, this function is equivalent to c_int/1. Otherwise, if the given value is an integer, it will be converted to the character with the corresponding code. The lexical representation of a character is "$Char", where Char is a single printing character or an escape sequence. See also: ann_c_char/2, c_int/1, c_string/1, char_lit/1, char_val/1, is_c_char/1, is_print_char/1.
  • c_clause(Patterns :: [cerl()], Body :: cerl()) -> c_clause() โ€” Equivalent to c_clause(Patterns, c_atom(true), Body). โœจ See also: c_atom/1.
  • c_clause(Patterns :: [cerl()], Guard :: cerl(), Body :: cerl()) -> c_clause() โ€” Creates an abstract clause. ๐Ÿ“œ If Patterns is [P1, ..., Pn], the result represents "<P1, ..., Pn> when Guard -> Body".

See also: ann_c_clause/4, c_case/2, c_clause/2, c_receive/3, clause_arity/1, clause_body/1, clause_guard/1, clause_pats/1, clause_vars/1, is_c_clause/1, update_c_clause/4.


๐ŸŽ€ c_cons/2 ๐ŸŽ€

c_cons(Head :: cerl(), Tail :: cerl()) -> c_literal() | c_cons().

Makes u an abstract list constructor, bestie. The result is giving [Head | Tail] energy. Heads up though: if both Head and Tail have type literal, then the result is also type literal, and the annotations on Head and Tail get yeeted into the void โ€” gone, lost, no cap.

And remember what we learned in Erlang class: the tail element of a list constructor is not necessarily a list. The way that's just how it works. ๐Ÿฆ‹

See also: ann_c_cons/3, c_cons_skel/2, c_nil/0, cons_hd/1, cons_tl/1, is_c_cons/1, is_c_list/1, list_elements/1, list_length/1, make_list/2, update_c_cons/3.


๐Ÿ’… c_cons_skel/2 ๐Ÿ’…

c_cons_skel(Head :: cerl(), Tail :: cerl()) -> c_cons().

Creates an abstract list constructor skeleton, and this one is so different from c_cons/2, iykyk. It does not fold constant literals โ€” like, ever. The result always has type cons, and it represents [Head | Tail]. Periodt.

So when is this iconic? Occasionally when u genuinely need annotations on the subnodes of a list constructor node, even when those subnodes are constant literals. Very niche, very main character.

โš ๏ธ But bestie, listen: is_literal/1 will yield false and concrete/1 will fail if u pass it the result from this function. Not a vibe. If u need to go back, fold_literal/1 can revert a node to the normal-form representation. ๐Ÿซถ

See also: ann_c_cons_skel/3, c_cons/2, c_nil/0, concrete/1, fold_literal/1, is_c_cons/1, is_c_list/1, is_literal/1, update_c_cons_skel/3.


โœจ c_float/1 โœจ

c_float(Value :: float()) -> c_literal().

Makes an abstract floating-point literal. The lexical representation is just the decimal floating-point numeral of Value. Slay, decimals. ๐Ÿ”ฅ

See also: ann_c_float/2, float_lit/1, float_val/1, is_c_float/1.


๐ŸŒธ c_fname/2 ๐ŸŒธ

c_fname(Name :: atom(), Arity :: arity()) -> c_var().

Literally the same as calling c_var({Name, Arity}). That's it, that's the whole function. ๐Ÿ’–

See also: ann_c_fname/3, fname_arity/1, fname_id/1, is_c_fname/1, update_c_fname/3.


๐Ÿงš c_fun/2 ๐Ÿงš

c_fun(Variables :: [cerl()], Body :: cerl()) -> c_fun().

Creates an abstract fun-expression. If Variables is [V1, ..., Vn], the result represents fun (V1, ..., Vn) -> Body. And all the Vi must have type var โ€” like, mandatory, no exceptions. ๐ŸŒˆ

See also: ann_c_fun/3, fun_arity/1, fun_body/1, fun_vars/1, is_c_fun/1, update_c_fun/3.


โญ c_int/1 โญ

c_int(Value :: integer()) -> c_literal().

Creates an abstract integer literal. The lexical representation is the canonical decimal numeral of Value. Canonical, bestie โ€” we don't do messy numerals here. ๐Ÿ‘‘

See also: ann_c_int/2, c_char/1, int_lit/1, int_val/1, is_c_int/1.


๐ŸŽ€ c_let/3 ๐ŸŽ€

c_let(Variables :: [cerl()], Argument :: cerl(), Body :: cerl()) ->
                c_let().

Creates an abstract let-expression. If Variables is [V1, ..., Vn], the result represents let <V1, ..., Vn> = Argument in Body. All the Vi must have type var. Yes all of them. Every single one. ๐Ÿ’…

See also: ann_c_let/4, is_c_let/1, let_arg/1, let_arity/1, let_body/1, let_vars/1, update_c_let/4.


๐Ÿฆ‹ c_letrec/2 ๐Ÿฆ‹

c_letrec(Definitions :: [{cerl(), cerl()}], Body :: cerl()) ->
                   c_letrec().

Creates an abstract letrec-expression. If Definitions is [{V1, F1}, ..., {Vn, Fn}], the result represents letrec V1 = F1 ... Vn = Fn in Body. Rules of the house: all the Vi must have type var and represent function names, and all the Fi must have type 'fun'. Recursion but make it abstract. ๐Ÿ”

See also: ann_c_letrec/3, is_c_letrec/1, letrec_body/1, letrec_defs/1, letrec_vars/1, update_c_letrec/3.


๐Ÿ’œ c_map/1 ๐Ÿ’œ

c_map(Pairs :: [c_map_pair()]) -> c_map().

Creates an abstract map constructor. If Pairs is [E1, ..., EN], the result represents "~{E1, ..., EN}~" โ€” that's the creating a new map flavour, obvs. ๐Ÿ—บ๏ธ

Important tea: if all pairs in Pairs have type literal for both the key and the value, or if Pairs is empty, then the result will also have type literal and the annotations on nodes in Pairs are lost forever. ๐Ÿ˜ญ

All Ei must be abstract pairs constructed by c_map_pair/2. Don't try anything cute.

See also: ann_c_map/2, is_c_map/1, is_c_map_empty/1, is_c_map_pattern/1, map_es/1, c_map_pair/2, c_map_pair_exact/2.


๐Ÿ”ฅ c_map/2 ๐Ÿ”ฅ

c_map(Argument :: cerl(), Pairs :: [c_map_pair()]) -> c_map().

Creates an abstract map update expression, the sequel to c_map/1. If Pairs is [E1, ..., EN], the result represents "~{E1, ..., EN | Argument}~" โ€” updating an existing map, periodt.

Same warning energy: if Argument is a literal and all pairs in Pairs have type literal for both key and value, or if Pairs is empty, then the result will also have type literal and annotations on nodes in Pairs are gone. ๐Ÿ’€

All Ei must be abstract pairs constructed by either c_map_pair/2 or c_map_pair_exact/2. Both are welcome here.

See also: ann_c_map/2, is_c_map/1, is_c_map_empty/1, is_c_map_pattern/1, map_es/1, c_map_pair/2, c_map_pair_exact/2.


๐Ÿ“ c_map_pair/2 ๐Ÿ“

c_map_pair(Key :: cerl(), Value :: cerl()) -> c_map_pair().

Creates an abstract map pair using the assoc operator. These can only occur as components of an abstract map creation expression or an abstract update expression (peep c_map/1 and c_map/2). The result represents Key => Value. Classic. ๐Ÿ˜Œ

See also: map_pair_key/1, map_pair_op/1, map_pair_val/1.


๐Ÿงš c_map_pair_exact/2 ๐Ÿงš

c_map_pair_exact(Key :: cerl(), Value :: cerl()) -> c_map_pair().

Creates an abstract map pair using the exact operator. These can only occur as components of an abstract map update expression or an abstract map pattern (peep c_map/1 and c_map_pattern/1). The result represents Key := Value.

Note the difference bestie: exact operator = :=, assoc = =>. They are not interchangeable, and I need u to know that. โœจ

See also: map_pair_key/1, map_pair_op/1, map_pair_val/1.


๐ŸŒˆ c_map_pattern/1 ๐ŸŒˆ

c_map_pattern(Pairs :: [c_map_pair()]) -> c_map().

Creates an abstract map pattern. If Pairs is [E1, ..., EN], the result represents "~{E1, ..., EN}~". Yes it looks the same as c_map/1 but bestie it is not the same โ€” trust.

All Ei must be abstract pairs constructed by c_map_pair_exact/2. Exact only. I don't make the rules. ๐ŸŽ€

See also: ann_c_map/2, is_c_map/1, is_c_map_empty/1, is_c_map_pattern/1, map_es/1, c_map_pair_exact/2.


๐Ÿ‘‘ c_module/4 ๐Ÿ‘‘

c_module(Name :: cerl(),
                Exports :: [cerl()],
                Attributes :: [{cerl(), cerl()}],
                Definitions :: [{cerl(), cerl()}]) ->
                   c_module().

Creates an abstract module definition. The result represents

module Name [E1, ..., Ek]
  attributes [K1 = T1, ...,
              Km = Tm]
  V1 = F1
  ...
  Vn = Fn
end

if Exports = [E1, ..., Ek], Attributes = [{K1, T1}, ..., {Km, Tm}], and Definitions = [{V1, F1}, ..., {Vn, Fn}].

Now the rules, and there are a lot of them, so lock in ๐Ÿ”’:

  • Name and all the Ki must be atom literals.
  • All the Ti must be constant literals.
  • All the Vi and Ei must have type var and represent function names.
  • All the Fi must have type 'fun'.

Get all of those right and ur module is serving. Get them wrong and... well. ๐Ÿ™ˆ

See also: ann_c_module/4, ann_c_module/5, c_atom/1, c_fun/2, c_module/3, c_var/1, is_literal/1, module_attrs/1, module_defs/1, module_exports/1, module_name/1, module_vars/1, update_c_module/5.


๐Ÿซถ c_nil/0 ๐Ÿซถ

c_nil() -> c_literal().

Creates an abstract empty list. The result represents []. Fun fact: the empty list is traditionally called nil. The more u know. ๐Ÿ’ซ

See also: ann_c_nil/1, c_cons/2, is_c_list/1.


โญ c_primop/2 โญ

c_primop(Name :: cerl(), Arguments :: [cerl()]) -> c_primop().

Creates an abstract primitive operation call. If Arguments is [A1, ..., An], the result represents primop Name(A1, ..., An). And Name must be an atom literal โ€” no negotiation. ๐Ÿ”ฅ

See also: ann_c_primop/3, c_apply/2, c_call/3, is_c_primop/1, primop_args/1, primop_arity/1, primop_name/1, update_c_primop/3.


๐ŸŽ€ c_receive/1 ๐ŸŽ€

c_receive(Clauses :: [cerl()]) -> c_receive().

Literally just c_receive(Clauses, c_atom(infinity), c_atom(true)). A shortcut, a little treat for u. ๐Ÿ“

See also: c_atom/1.


๐Ÿ’… c_receive/3 ๐Ÿ’…

c_receive(Clauses :: [cerl()],
                 Timeout :: cerl(),
                 Action :: cerl()) ->
                    c_receive().

Creates an abstract receive-expression. If Clauses is [C1, ..., Cn], the result represents receive C1 ... Cn after Timeout -> Action end. The full three-arg main character version. โœจ

See also: ann_c_receive/4, c_receive/1, is_c_receive/1, receive_action/1, receive_clauses/1, receive_timeout/1, update_c_receive/4.


๐ŸŽ c_record/2 ๐ŸŽ

c_record(Argument :: record_id(), Pairs :: [c_record_pair()]) ->
                   #c_record{}.

Creates an abstract record constructor. Notice the return type is literally written as #c_record{} in the spec โ€” that's not a typo, that's just how it is, and we respect it. ๐Ÿซก

See also: ann_c_record/3, is_c_record/1, record_id/1, record_es/1, c_record_pair/2, update_c_record/4.


๐ŸŒธ c_record_pair/2 ๐ŸŒธ

c_record_pair(Key :: c_literal(), Value :: cerl()) ->
                        c_record_pair().

Creates an abstract record pair. These can only occur as components of an abstract record creation expression or an abstract update expression (peep c_record/2). The result represents Key = Value. Key is a c_literal(), no substitutes. ๐Ÿ’–

See also: ann_c_record_pair/3, record_pair_key/1, record_pair_val/1.


๐Ÿ’œ c_seq/2 ๐Ÿ’œ

c_seq(Argument :: cerl(), Body :: cerl()) -> c_seq().

Creates an abstract sequencing expression. The result represents do Argument Body. One thing, then the next thing. That's the sequence, bestie. โžก๏ธ

See also: ann_c_seq/3, is_c_seq/1, seq_arg/1, seq_body/1, update_c_seq/3.


๐Ÿฆ‹ c_string/1 ๐Ÿฆ‹

c_string(Value :: string()) -> c_literal().

Creates an abstract string literal. It's equivalent to creating an abstract list of the corresponding character literals (cf. is_c_string/1) โ€” but this is typically more efficient, so like, do this one. โšก

The lexical representation of a string is ""Chars"", where Chars is a sequence of printing characters or spaces.

See also: ann_c_string/2, c_char/1, is_c_string/1, is_print_string/1, string_lit/1, string_val/1.


๐ŸŒˆ c_try/5 ๐ŸŒˆ

c_try(Argument :: cerl(),
             Variables :: [cerl()],
             Body :: cerl(),
             ExceptionVars :: [cerl()],
             Handler :: cerl()) ->
                c_try().

Creates an abstract try-expression. If Variables is [V1, ..., Vn] and ExceptionVars is [X1, ..., Xm], the result represents try Argument of <V1, ..., Vn> -> Body catch <X1, ..., Xm> -> Handler.

Both sets matter: all the Vi and all the Xi must have type var. Try it, catch it, love it. ๐Ÿ’…

See also: ann_c_try/6, c_catch/1, is_c_try/1, try_arg/1, try_body/1, try_vars/1, update_c_try/6.


๐Ÿ’– c_tuple/1 ๐Ÿ’–

c_tuple(Elements :: [cerl()]) -> c_tuple() | c_literal().

Creates an abstract tuple. If Elements is [E1, ..., En], the result represents {E1, ..., En}.

And here's the tea again ๐Ÿซ–: if all nodes in Elements have type literal, or if Elements is empty, then the result will also have type literal and the annotations on nodes in Elements are lost. Same energy as c_cons/2, same heartbreak. ๐Ÿ˜ญ

See also: ann_c_tuple/2, is_c_tuple/1, tuple_arity/1, tuple_es/1, update_c_tuple/3.


See also: ann_c_tuple/2, c_tuple/1, is_c_tuple/1, tuple_arity/1, tuple_es/1, update_c_tuple/3.

Recall that Erlang has distinct 1-tuples, that is, {X} is always distinct from X itself. Yeah, it's a whole thing. ๐Ÿ’…

See also: ann_c_tuple/2, c_tuple_skel/1, is_c_tuple/1, tuple_arity/1, tuple_es/1, update_c_tuple/2.

c_tuple_skel(Elements :: [cerl()]) -> c_tuple(). โœจ

Creates an abstract tuple skeleton.

No cap, it does not fold constant literals, that is, the result always has type tuple, representing "{E1, ..., En}", if Elements is [E1, ..., En].

This function is occasionally useful when it is necessary to have annotations on the subnodes of a tuple node, even when all the subnodes are constant literals. However, note that is_literal/1 will yield false and concrete/1 will fail if passed the result from this function.

fold_literal/1 can be used to revert a node to the normal-form representation.

See also: ann_c_tuple_skel/2, c_tuple/1, concrete/1, fold_literal/1, is_c_tuple/1, is_literal/1, tuple_es/1, update_c_tuple_skel/2.

c_values(Elements :: [cerl()]) -> c_values(). ๐ŸŒˆ

Creates an abstract value list.

If Elements is [E1, ..., En], the result represents "<E1, ..., En>".

See also: ann_c_values/2, is_c_values/1, update_c_values/2, values_arity/1, values_es/1.

c_var(Name :: var_name()) -> c_var(). ๐Ÿ’–

Creates an abstract variable.

A variable is identified by its name, given by the Name parameter.

If a name is given by a single atom, it should either be a "simple" atom which does not need to be single-quoted in Erlang, or otherwise its print name should correspond to a proper Erlang variable, that is, begin with an uppercase character or an underscore. Names of the form {A, N} represent function name variables "A/N"; these are special variables which may be bound only in the function definitions of a module or a letrec. They may not be bound in let expressions and cannot occur in clause patterns. The atom A in a function name may be any atom; the integer N must be nonnegative. The functions c_fname/2 etc. are utilities for handling function name variables.

When printing variable names, they must have the form of proper Core Erlang variables and function names. E.g., a name represented by an integer such as 42 could be formatted as "_42", an atom 'Xxx' simply as "Xxx", and an atom foo as "_foo". However, one must assure that any two valid distinct names are never mapped to the same strings. Tuples such as {foo, 2} representing function names can simply be formatted as "'foo'/2", with no risk of conflicts.

See also: ann_c_var/2, c_fname/2, c_letrec/2, c_module/4, is_c_var/1, update_c_var/2, var_name/1.

call_args(Node :: c_call()) -> [cerl()]. ๐Ÿฆ‹

Returns the list of argument subtrees of an abstract inter-module call.

See also: c_call/3, call_arity/1.

call_arity(Node :: c_call()) -> arity(). ๐ŸŽ€

Returns the number of argument subtrees of an abstract inter-module call.

Note: this is equivalent to length(call_args(Node)), but potentially more efficient.
See also: c_call/3, call_args/1.

call_module(Node :: c_call()) -> cerl(). ๐ŸŒธ

Returns the module subtree of an abstract inter-module call.

See also: c_call/3.

call_name(Node :: c_call()) -> cerl(). ๐Ÿ’œ

Returns the name subtree of an abstract inter-module call.

See also: c_call/3.

case_arg(Node :: c_case()) -> cerl(). ๐Ÿงš

Returns the argument subtree of an abstract case-expression.

See also: c_case/2.

case_arity(Node :: c_case()) -> non_neg_integer(). ๐Ÿ”ฅ

Equivalent to clause_arity(hd(case_clauses(Node))), but potentially more efficient.

See also: c_case/2, case_clauses/1, clause_arity/1.

case_clauses(Node :: c_case()) -> [cerl()]. ๐Ÿ‘‘

Returns the list of clause subtrees of an abstract case-expression.

See also: c_case/2, case_arity/1.

catch_body(Node :: c_catch()) -> cerl(). ๐Ÿซถ

Returns the body subtree of an abstract catch-expression.

See also: c_catch/1.

char_lit(Node :: c_literal()) -> nonempty_string(). ๐Ÿ“

Returns the literal string represented by an abstract character. This includes a leading $ character.

Currently, all characters that are not in the set of ISO 8859-1 (Latin-1) "printing" characters will be escaped.

See also: c_char/1.

char_val(Node :: c_literal()) -> char(). ๐Ÿ’€

Returns the value represented by an abstract character literal.

See also: c_char/1.

clause_arity(Node :: c_clause()) -> non_neg_integer(). โญ

Returns the number of pattern subtrees of an abstract clause.

Note: this is equivalent to length(clause_pats(Node)), but potentially more efficient.
See also: c_clause/3, clause_pats/1.

clause_body(Node :: c_clause()) -> cerl(). ๐ŸŒˆ

Returns the body subtree of an abstract clause.

See also: c_clause/3.

clause_guard(Node :: c_clause()) -> cerl(). ๐Ÿ’–

Returns the guard subtree of an abstract clause.

See also: c_clause/3.

clause_pats(Node :: c_clause()) -> [cerl()]. โœจ

Returns the list of pattern subtrees of an abstract clause.

See also: c_clause/3, clause_arity/1.

clause_vars(Node :: c_clause()) -> [cerl()]. ๐Ÿฆ‹

Returns the list of all abstract variables in the patterns of an abstract clause.

The order of listing is not defined.

See also: c_clause/3, pat_list_vars/1.

concrete(Node :: c_literal()) -> term(). ๐ŸŽ€

Returns the Erlang term represented by a syntax tree.

An exception is thrown if Node does not represent a literal term.

Note: This is a constant time operation.
See also: abstract/1, is_literal/1.

cons_hd(Node :: c_cons() | c_literal()) -> cerl(). ๐ŸŒธ

Returns the head subtree of an abstract list constructor.

See also: c_cons/2.

cons_tl(Node :: c_cons() | c_literal()) -> cerl(). ๐Ÿ’œ

Returns the tail subtree of an abstract list constructor.

Recall that the tail does not necessarily represent a proper list.

See also: c_cons/2.

copy_ann(Source :: cerl(), Target :: cerl()) -> cerl(). ๐Ÿงš

Copies the list of user annotations from Source to Target.

Note: this is equivalent to set_ann(Target, get_ann(Source)), but potentially more efficient.
See also: get_ann/1, set_ann/2.

data_arity(Node :: c_lct()) -> non_neg_integer(). ๐Ÿ”ฅ

Returns the number of subtrees of a data constructor node.

This is equivalent to length(data_es(Node)), but potentially more efficient.

See also: data_es/1, is_data/1.

data_es(Node :: c_lct()) -> [cerl()]. ๐Ÿ‘‘

Returns the list of subtrees of a data constructor node.

If the arity of the constructor is zero, the result is the empty list.

Note: if data_type(Node) is cons, the number of subtrees is exactly two. If data_type(Node) is {atomic, Value}, the number of subtrees is zero.
See also: data_arity/1, data_type/1, is_data/1, make_data/2.

data_type(Node :: c_lct()) -> dtype(). ๐Ÿซถ

Returns a type descriptor for a data constructor node. (Cf. is_data/1.)

This is mainly useful for comparing types and for constructing new nodes of the same type (cf. make_data/2). If Node represents an integer, floating-point number, atom or empty list, the result is {atomic, Value}, where Value is the value of concrete(Node), otherwise the result is either cons or tuple.

Type descriptors can be compared for equality or order (in the Erlang term order), but remember that floating-point values should in general never be tested for equality.

See also: concrete/1, is_data/1, make_data/2, type/1.

float_lit(Node :: c_literal()) -> string(). ๐Ÿ“

Returns the numeral string represented by a floating-point literal node.

See also: c_float/1.

float_val(Node :: c_literal()) -> float(). ๐Ÿ’€

Returns the value represented by a floating-point literal node.

See also: c_float/1.

fname_arity(Node :: c_var()) -> arity(). โญ

Returns the arity part of an abstract function name variable.

See also: c_fname/2, fname_id/1.

fname_id(Node :: c_var()) -> atom(). ๐ŸŒˆ

Returns the identifier part of an abstract function name variable.

See also: c_fname/2, fname_arity/1.

fold_literal(Node :: cerl()) -> cerl(). ๐Ÿ’–

Ensures that literals have a compact representation.

This is occasionally useful if c_cons_skel/2, c_tuple_skel/1 or unfold_literal/1 were used in the construction of Node, and you want to revert to the normal "folded" representation of literals. If Node represents a tuple or list constructor, its elements are rewritten recursively, and the node is reconstructed using c_cons/2 or c_tuple/1, respectively; otherwise, Node is not changed.

See also: c_cons/2, c_cons_skel/2, c_tuple/1, c_tuple_skel/1, is_literal/1, unfold_literal/1.

from_records(Node :: cerl()) -> cerl(). โœจ

Translates an explicit record representation to a corresponding abstract syntax tree.

The records are defined in the file "core_parse.hrl".

See also: to_records/1, type/1.

fun_arity(Node :: c_fun()) -> arity(). ๐Ÿฆ‹

Returns the number of parameter subtrees of an abstract fun-expression.

Note: this is equivalent to length(fun_vars(Node)), but potentially more efficient.
See also: c_fun/2, fun_vars/1.

fun_body(Node :: c_fun()) -> cerl(). ๐ŸŽ€

Returns the body subtree of an abstract fun-expression.

See also: c_fun/2.

fun_vars(Node :: c_fun()) -> [cerl()]. ๐ŸŒธ

Returns the list of parameter subtrees of an abstract fun-expression.

See also: c_fun/2, fun_arity/1.

get_ann(Node :: cerl()) -> [term()]. ๐Ÿ’œ

Returns the list of user annotations associated with a syntax tree node.

For a newly created node, this is the empty list. The annotations may be any terms.

See also: set_ann/2.

int_lit(Node :: c_literal()) -> string(). ๐Ÿงš

Returns the numeral string represented by an integer literal node.

See also: c_int/1.

int_val(Node :: c_literal()) -> integer(). ๐Ÿ”ฅ

Returns the value represented by an integer literal node.

See also: c_int/1.

okay bestie we're picking right back up in the โœจ predicate section โœจ and this is the era of the is_* girlies โ€” every single one is a vibe check that hands you back true or false and absolutely nothing else. no cap. ๐ŸŽ€


is_c_alias(Node :: cerl()) -> boolean().

Vibe check: does Node represent an abstract pattern alias? true if so, false if not. ๐Ÿ’…

See also: c_alias/2.


is_c_apply(Node :: cerl()) -> boolean().

Returns true if Node is an abstract function application, otherwise false. ๐Ÿ”ฅ

See also: c_apply/2.


is_c_atom(Node :: cerl()) -> boolean().

Returns true if Node represents an atom literal, otherwise false. โœจ

See also: c_atom/1.


is_c_binary(Node :: cerl()) -> boolean().

Returns true if Node is an abstract binary-template, otherwise false. ๐Ÿฆ‹

See also: c_binary/1.


is_c_bitstr(Node :: cerl()) -> boolean().

Returns true if Node is an abstract bit-string template, otherwise false. ๐Ÿ’œ

See also: c_bitstr/5.


is_c_call(Node :: cerl()) -> boolean().

Returns true if Node is an abstract inter-module call expression, otherwise false. ๐ŸŒˆ

See also: c_call/3.


is_c_case(Node :: cerl()) -> boolean().

Returns true if Node is an abstract case-expression, otherwise false. ๐ŸŽ€

See also: c_case/2.


is_c_catch(Node :: cerl()) -> boolean().

Returns true if Node is an abstract catch-expression, otherwise false. ๐Ÿซถ

See also: c_catch/1.


is_c_char(Node :: c_literal()) -> boolean().

Returns true if Node may represent a character literal, otherwise false.

Heads up bestie: if your local Erlang implementation defines char/0 as a subset of integer/0, then is_c_int(Node) will also hand you true. so yeah, overlap is real. โœจ

See also: c_char/1, is_print_char/1.


is_c_clause(Node :: cerl()) -> boolean().

Returns true if Node is an abstract clause, otherwise false. ๐Ÿ’ซ

See also: c_clause/3.


is_c_cons(Node :: cerl()) -> boolean().

Returns true if Node is an abstract list constructor, otherwise false. ๐Ÿ“


is_c_float(Node :: cerl()) -> boolean().

Returns true if Node represents a floating-point literal, otherwise false. ๐Ÿ’…

See also: c_float/1.


is_c_fname(Node :: cerl()) -> boolean().

Returns true if Node is an abstract function name variable, otherwise false. ๐Ÿ‘‘

See also: c_fname/2, c_var/1, var_name/1.


is_c_fun(Node :: cerl()) -> boolean().

Returns true if Node is an abstract fun-expression, otherwise false. ๐ŸŽ€

See also: c_fun/2.


is_c_int(Node :: cerl()) -> boolean().

Returns true if Node represents an integer literal, otherwise false. ๐Ÿ”ขโœจ

See also: c_int/1.


is_c_let(Node :: cerl()) -> boolean().

Returns true if Node is an abstract let-expression, otherwise false. ๐ŸŒธ

See also: c_let/3.


is_c_letrec(Node :: cerl()) -> boolean().

Returns true if Node is an abstract letrec-expression, otherwise false. ๐ŸŒ€

See also: c_letrec/2.


is_c_list(Node :: cerl()) -> boolean().

Returns true if Node represents a proper list, otherwise false.

A "proper list" is either the empty list [], or a cons cell [Head | Tail] where, recursively, Tail is also a proper list. iconic structural recursion, we love to see it. ๐Ÿ’–

ok so listen โ€” Node is a syntax tree, which means the actual run-time values behind its subtrees are often partially or totally unknown. so if Node represents like "[... | Ns]" where Ns is a variable? this function says false, because nobody knows if Ns will be bound to a list at run-time. but if Node represents something like "[1, 2, 3]" or "[A | []]", you get true. bestie it cannot know what it cannot know. ๐Ÿ˜ญ

See also: c_cons/2, c_nil/0, list_elements/1, list_length/1.


is_c_map(Node :: cerl()) -> boolean().

Returns true if Node is any kind of abstract map โ€” constructing, updating, or matching โ€” otherwise false. ๐Ÿ—บ๏ธโœจ

See also: ann_c_map/3, c_map/1, c_map_pattern/1.


is_c_map_empty(Node :: c_map() | c_literal()) -> boolean().

Returns true if Node represents an empty abstract map, otherwise false. ๐Ÿซ™

See also: c_map/1, c_map_pattern/1.


is_c_map_pattern(Node :: c_map()) -> boolean().

Returns true if Node is an abstract map pattern, otherwise false. ๐Ÿงฉ

See also: c_map/1, c_map_pattern/1.


is_c_module(Node :: cerl()) -> boolean().

Returns true if Node is an abstract module definition, otherwise false. ๐Ÿ›๏ธ

See also: type/1.


is_c_nil(Node :: cerl()) -> boolean().

Returns true if Node is an abstract empty list, otherwise false. ๐Ÿ•ณ๏ธ


is_c_primop(Node :: cerl()) -> boolean().

Returns true if Node is an abstract primitive operation call, otherwise false. โšก

See also: c_primop/2.


is_c_receive(Node :: cerl()) -> boolean().

Returns true if Node is an abstract receive-expression, otherwise false. ๐Ÿ“ฌ

See also: c_receive/3.


is_c_record(Node :: cerl()) -> boolean().

Returns true if Node is an abstract record, otherwise false. ๐Ÿ“€

See also: c_record/2.


is_c_seq(Node :: cerl()) -> boolean().

Returns true if Node is an abstract sequencing expression, otherwise false. ๐Ÿชœ

See also: c_seq/2.


is_c_string(Node :: cerl()) -> boolean().

Returns true if Node may represent a string literal, otherwise false.

Strings are defined as lists of characters โ€” peep is_c_char/1 for all the deets. ๐Ÿ”ค

See also: c_string/1, is_c_char/1, is_print_string/1.


is_c_try(Node :: cerl()) -> boolean().

Returns true if Node is an abstract try-expression, otherwise false. ๐Ÿ›Ÿ

See also: c_try/5.


is_c_tuple(Node :: cerl()) -> boolean().

Returns true if Node is an abstract tuple, otherwise false. ๐Ÿ“ฆ

See also: c_tuple/1.


is_c_values(Node :: cerl()) -> boolean().

Returns true if Node is an abstract value list, otherwise false. ๐Ÿ’ž

See also: c_values/1.


is_c_var(Node :: cerl()) -> boolean().

Returns true if Node is an abstract variable, otherwise false. ๐Ÿท๏ธ

See also: c_var/1.


is_data(Node :: cerl()) -> boolean().

Returns true if Node represents a data constructor, otherwise false.

Data constructors are: cons cells, tuples, and atomic literals. the whole data squad, no impostors. ๐Ÿ‘‘

See also: data_arity/1, data_es/1, data_type/1.


is_leaf(Node :: cerl()) -> boolean().

Returns true if Node is a leaf node, otherwise false.

The current leaf node types are literal and var. ๐Ÿƒ

note note note: all literals (cf. is_literal/1) are leaf nodes โ€” even when they represent structured (constant) values like {foo, [bar, baz]}. and also note that variables are leaf nodes but they are not literals. two different things bestie, don't get it twisted. ๐Ÿ’€

See also: is_literal/1, type/1.


is_literal(Node :: cerl()) -> boolean().

Returns true if Node represents a literal term, otherwise false.

This gives you true if and only if the value of concrete(Node) is defined. ๐Ÿ”ฎ

and here's the slay: this is a constant time operation. O(1) girlies rise. โœจ

See also: abstract/1, concrete/1, fold_literal/1.


is_literal_term(Term :: term()) -> boolean().

Returns true if Term can be represented as a literal, otherwise false.

Heads up though โ€” this one takes time proportional to the size of Term. so not the freebie that its cousin above is. ๐ŸŒ

See also: abstract/1.


is_print_char(Node :: cerl()) -> boolean().

Returns true if Node may represent a "printing" character, otherwise false. (Cf. is_c_char/1.) ๐Ÿ–จ๏ธ

A "printing" character is one that either has a given graphical representation, or a "named" escape sequence like "\n". Currently, only ISO 8859-1 (Latin-1) character values are recognized. ๐ŸŒˆ

See also: c_char/1, is_c_char/1.


is_print_string(Node :: cerl()) -> boolean().

Returns true if Node may represent a string literal containing only "printing" characters, otherwise false.

Go read is_c_string/1 and is_print_char/1 for the full lore. Currently, only ISO 8859-1 (Latin-1) character values are recognized. ๐Ÿ’œ

See also: c_string/1, is_c_string/1, is_print_char/1.


okay now we're leaving the is_* era and entering the โœจ accessor girlies โœจ โ€” these ones actually hand you back parts of a node instead of a true/false. obsessed. ๐Ÿ’…


let_arg(Node :: c_let()) -> cerl().

Hands you back the argument subtree of an abstract let-expression. ๐ŸŽ

See also: c_let/3.


let_arity(Node :: c_let()) -> non_neg_integer().

Hands you back the number of left-hand side variables of an abstract let-expression. ๐Ÿ”ข

note: this is equivalent to length(let_vars(Node)), but potentially more efficient. same answer, less work. ๐Ÿ’…

See also: c_let/3, let_vars/1.


let_body(Node :: c_let()) -> cerl().

Hands you back the body subtree of an abstract let-expression. ๐Ÿซ€

See also: c_let/3.


let_vars(Node :: c_let()) -> [cerl()].

Hands you back the list of left-hand side variables of an abstract let-expression. ๐Ÿ“‹

See also: c_let/3, let_arity/1.


letrec_body(Node :: c_letrec()) -> cerl().

Hands you back the body subtree of an abstract letrec-expression. ๐Ÿซ€

See also: c_letrec/2.


letrec_defs(Node :: c_letrec()) -> [{cerl(), cerl()}].

Hands you back the list of definitions of an abstract letrec-expression. ๐Ÿ“ฆ

If Node represents "letrec V1 = F1 ... Vn = Fn in Body", then what you get back is [{V1, F1}, ..., {Vn, Fn}]. ๐ŸŽ€

See also: c_letrec/2.


letrec_vars(Node :: c_letrec()) -> [cerl()].

Hands you back the list of left-hand side function variable subtrees of a letrec-expression. ๐Ÿท๏ธ

If Node represents "letrec V1 = F1 ... Vn = Fn in Body", then what you get back is [V1, ..., Vn]. โœจ

See also: c_letrec/2.


list_elements(Node :: c_cons() | c_literal()) -> [cerl()].

Hands you back the list of element subtrees of an abstract list. ๐Ÿ“œ

Node must represent a proper list. for example, if Node represents "[X1, X2 | [X3, X4 | []]", then list_elements(Node) yields the list [X1, X2, X3, X4]. ๐Ÿ’–

See also: c_cons/2, c_nil/0, is_c_list/1, list_length/1, make_list/2.


list_length(Node :: c_cons() | c_literal()) -> non_neg_integer().

Hands you back the number of element subtrees of an abstract list. ๐Ÿ”ข

Node must represent a proper list. for example, if Node represents "[X1 | [X2, X3 | [X4, X5, X6]]]", then list_length(Node) returns the integer 6. ๐ŸŽ‰

note: this is equivalent to length(list_elements(Node)), but potentially more efficient. bestie it just counts without building the whole list first. ๐Ÿ’…

See also: c_cons/2, c_nil/0, is_c_list/1, list_elements/1.


make_data(Type :: dtype(), Elements :: [cerl()]) -> c_lct().

Builds you a data constructor node with the type and subtrees you specify. (Cf. data_type/1.) ๐Ÿ—๏ธโœจ

An exception gets thrown if the length of Elements is invalid for the given Type โ€” check data_es/1 for the arity constraints on constructor types, bestie. ๐Ÿ‘‘

See also: ann_make_data/3, data_es/1, data_type/1, make_data_skel/2, update_data/3.

make_data_skel</p> ๐Ÿ’…

make_data_skel(Type :: dtype(), Elements :: [cerl()]) -> c_lct().

Basically make_data/2, but it's the skeleton-sibling of c_tuple_skel/1 and c_cons_skel/2. Same energy, different paperwork. โœจ

See also: ann_make_data_skel/3, c_cons_skel/2, c_tuple_skel/1, make_data/2, update_data_skel/3.

make_list ๐ŸŽ€

make_list(List :: [cerl()], Tail :: cerl() | none) -> cerl().

Builds an abstract list out of the elements in List plus the optional Tail. ๐ŸŒธ

If Tail is none, you get a nil-terminated list, no cap. Otherwise it's giving "[... | Tail]" โ€” tail and all, iconic. ๐Ÿฆ‹

See also: ann_make_list/3, c_cons/2, c_nil/0, list_elements/1, update_list/3.

make_tree ๐ŸŒˆ

make_tree(Type :: ctype(), Groups :: [[cerl()], ...]) -> cerl().

Makes a syntax tree with the type and subtrees you hand it. ๐ŸŒฑ

Type has to be a node type name (peep type/1) that is not a leaf node type (peep is_leaf/1).

Groups has to be a nonempty list of groups of syntax trees โ€” those are the subtrees of a node of the given type, in left-to-right order exactly like they'd show up in the printed program text, grouped by category the way subtrees/1 does it. ๐Ÿ“š

The result of ann_make_tree(get_ann(Node), type(Node), subtrees(Node)) (cf. update_tree/2) represents the same source code text as the original Node, assuming subtrees(Node) gives you a nonempty list. But heads up โ€” it does not necessarily have the exact same data representation as Node. Close cousin, not clone. ๐Ÿ™ˆ

See also: ann_make_tree/3, is_leaf/1, subtrees/1, type/1, update_tree/2.

map_arg

map_arg(Node :: c_map() | c_literal()) -> c_map() | c_literal().

Hands you the argument subtree of an abstract map. ๐Ÿ—บ๏ธ

See also: c_map/2.

map_es

map_es(Node :: c_map() | c_literal()) -> [c_map_pair()].

Returns the list of map pair subtrees of an abstract map. โœจ

See also: c_map/1.

map_pair_key

map_pair_key(Node :: c_map_pair()) -> cerl().

The key subtree of an abstract map pair. ๐Ÿ”‘

See also: c_map_pair/2, c_map_pair_exact/2.

map_pair_op

map_pair_op(Node :: c_map_pair()) -> map_op().

The operation subtree of an abstract map pair. โš™๏ธ

See also: c_map_pair/2, c_map_pair_exact/2.

map_pair_val

map_pair_val(Node :: c_map_pair()) -> cerl().

The value subtree of an abstract map pair. ๐Ÿ’–

See also: c_map_pair/2, c_map_pair_exact/2.

meta ๐Ÿ‘‘

meta(Tree :: cerl()) -> cerl().

Creates a meta-representation of a syntax tree. This one is a whole vibe, so let's go slow. ๐Ÿงš

The result represents an Erlang expression "MetaTree" which, if you evaluate it, yields a new syntax tree representing the same source code text as Tree โ€” although the actual data representation may be different, fr fr. And get this: the expression represented by MetaTree is implementation independent with regard to the data structures used by the abstract syntax tree implementation. That's the slay part. ๐Ÿ’…

Now, any node in Tree whose node type is var (cf. type/1) and whose list of annotations (cf. get_ann/1) contains the atom meta_var will stay unchanged in the resulting tree โ€” except that exactly one occurrence of meta_var is removed from its annotation list. Exactly one. Not zero, not two. ๐ŸŽฏ

So what's the point? Main use of meta/1 is turning a data structure Tree, which represents a piece of program code, into a form that's representation independent when printed. For example: suppose Tree represents a variable named "V". Then (assuming a function print/1 for printing syntax trees), evaluating print(abstract(Tree)) โ€” just using abstract/1 to map the actual data structure onto a syntax tree representation โ€” would output a string that might look something like "{var, ..., 'V'}", which is obviously dependent on the implementation of the abstract syntax trees. Cataloging that could be useful for caching a syntax tree in a file, sure. But sometimes โ€” like in a program generator generator (yes, two "generator", that's not a typo ๐Ÿ˜ญ) โ€” it may be unacceptable. So use print(meta(Tree)) instead and you'd output a representation-independent syntax tree generating expression; in the case above, something like "cerl:c_var('V')". Chef's kiss. ๐Ÿ“

The implementation tries to generate compact code with respect to literals and lists. โœจ

See also: abstract/1, get_ann/1, type/1.

module_attrs

module_attrs(Node :: c_module()) -> [{cerl(), cerl()}].

Returns the list of pairs of attribute key/value subtrees of an abstract module definition. ๐Ÿ“ฆ

See also: c_module/4.

module_defs

module_defs(Node :: c_module()) -> [{cerl(), cerl()}].

Returns the list of function definitions of an abstract module definition. ๐Ÿ› ๏ธ

See also: c_module/4.

module_exports

module_exports(Node :: c_module()) -> [cerl()].

Returns the list of exports subtrees of an abstract module definition. ๐Ÿš€

See also: c_module/4.

module_name

module_name(Node :: c_module()) -> cerl().

Returns the name subtree of an abstract module definition. ๐Ÿท๏ธ

See also: c_module/4.

module_vars

module_vars(Node :: c_module()) -> [cerl()].

Returns the list of left-hand side function variable subtrees of an abstract module definition. ๐Ÿซถ

See also: c_module/4.

pat_list_vars

pat_list_vars(Patterns :: [cerl()]) -> [cerl()].

Returns the list of all abstract variables in the given patterns. ๐Ÿ”

An exception gets thrown if some element in Patterns doesn't represent a well-formed Core Erlang clause pattern โ€” so behave. And ngl, the order of listing is not defined. Don't @ me. ๐Ÿ’€

See also: clause_vars/1, pat_vars/1.

pat_vars

pat_vars(Node :: cerl()) -> [cerl()].

Returns the list of all abstract variables in a pattern.

An exception gets thrown if Node doesn't represent a well-formed Core Erlang clause pattern. And again: the order of listing is not defined. ๐Ÿ™ƒ

See also: clause_vars/1, pat_list_vars/1.

primop_args

primop_args(Node :: c_primop()) -> [cerl()].

Returns the list of argument subtrees of an abstract primitive operation call. โšก

See also: c_primop/2, primop_arity/1.

primop_arity

primop_arity(Node :: c_primop()) -> arity().

Returns the number of argument subtrees of an abstract primitive operation call. ๐Ÿงฎ

Note: this is equivalent to length(primop_args(Node)), but potentially more efficient. Fancy like that. ๐Ÿ’…

See also: c_primop/2, primop_args/1.

primop_name

primop_name(Node :: c_primop()) -> cerl().

Returns the name subtree of an abstract primitive operation call. โœ๏ธ

See also: c_primop/2.

receive_action

receive_action(Node :: c_receive()) -> cerl().

Returns the action subtree of an abstract receive-expression. ๐Ÿ“จ

See also: c_receive/3.

receive_clauses

receive_clauses(Node :: c_receive()) -> [cerl()].

Returns the list of clause subtrees of an abstract receive-expression. ๐Ÿ“ฌ

See also: c_receive/3.

receive_timeout

receive_timeout(Node :: c_receive()) -> cerl().

Returns the timeout subtree of an abstract receive-expression. โณ

See also: c_receive/3.

record_arg

record_arg(Node :: c_record()) -> c_var() | c_literal().

Returns the argument subtree of an abstract record. ๐Ÿ’พ

See also: c_record/2.

record_es

record_es(Node :: c_record()) -> [c_record_pair()].

Returns the list of native record pair subtrees of an abstract record. ๐ŸŽ

See also: c_record/2.

record_id

record_id(Node :: c_record()) -> record_id().

Returns the identifier of of an abstract record. Yes, of of. ๐Ÿ™ˆ We do not talk about it, we simply relay the facts, bestie.

See also: c_record/2.

record_pair_key

record_pair_key(Node :: c_record_pair()) -> c_literal().

Returns the key subtree of an abstract record pair. ๐Ÿ”‘

See also: c_record_pair/2.

record_pair_val

record_pair_val(Node :: c_record_pair()) -> cerl().

Returns the value subtree of an abstract record pair. ๐Ÿ’œ

See also: c_record_pair/2.

seq_arg

seq_arg(Node :: c_seq()) -> cerl().

Returns the argument subtree of an abstract sequencing expression. โžก๏ธ

See also: c_seq/2.

seq_body

seq_body(Node :: c_seq()) -> cerl().

Returns the body subtree of an abstract sequencing expression. ๐Ÿงต

See also: c_seq/2.

set_ann

set_ann(Node :: cerl(), Annotations :: [term()]) -> cerl().

Sets the list of user annotations of Node to Annotations. Rewrites the whole annotation list, no takebacks. โœ๏ธ

See also: add_ann/2, copy_ann/2, get_ann/1.

string_lit ๐ŸŽ€

string_lit(Node :: c_literal()) -> nonempty_string().

Returns the literal string represented by an abstract string. This includes the surrounding double-quote characters "..." โ€” quotes stay, they're part of the fit. ๐Ÿ’–

Currently, characters that are not in the set of ISO 8859-1 (Latin-1) "printing" characters will be escaped, except for spaces. Spaces stay cute and unescaped. โœจ

See also: c_string/1.

string_val ๐ŸŽ€

string_val(Node :: c_literal()) -> string().

Returns the value represented by an abstract string literal. ๐ŸŒธ

See also: c_string/1.

subtrees ๐ŸŒˆ๐Ÿ‘‘

subtrees(Node :: cerl()) -> [[cerl()]].

Returns the grouped list of all subtrees of a node. Big one, stay with me. ๐Ÿฆ‹

If Node is a leaf node (cf. is_leaf/1), this is the empty list. Otherwise the result is always a nonempty list, containing the lists of subtrees of Node, in left-to-right order as they occur in the printed program text, and grouped by category. Often, each group contains only a single subtree. Packed light. ๐ŸŽ’

Depending on the type of Node, the size of some groups may be variable โ€” for example, the group consisting of all the elements of a tuple โ€” while others always contain the same number of elements, usually exactly one (for example, the group containing the argument expression of a case-expression). But note: the exact structure of the returned list (for a given node type) should in general not be depended upon, since it might be subject to change without notice. Do not build your whole personality on it, okay? ๐Ÿ˜ญ

The function subtrees/1 and the constructor functions make_tree/2 and update_tree/2 can be a great help if you want to traverse a syntax tree, visiting all its subtrees, but treat nodes of the tree in a uniform way in most or all cases. Using these functions makes this simple, and also assures that your code is not overly sensitive to extensions of the syntax tree data type โ€” because any node types not explicitly handled by your code can be left to a default case. Future-proof, lowkey iconic. ๐Ÿ‘‘

For example:

postorder(F, Tree) ->
    F(case subtrees(Tree) of
        [] -> Tree;
        List -> update_tree(Tree,
                            [[postorder(F, Subtree)
                              || Subtree <- Group]
                             || Group <- List])
      end).

okay so what this does ๐Ÿ’… it maps the function F onto Tree and all its subtrees, doing a post-order traversal of the syntax tree. (And bestie, notice the lil flex: it uses update_tree/2 to preserve annotations ๐ŸŽ€ โ€” do not lose the annotations, they are the moment.)

For a simple function like:

f(Node) ->
    case type(Node) of
        atom -> atom("a_" ++ atom_name(Node));
        _ -> Node
    end.

the call postorder(fun f/1, Tree) will yield a new representation of Tree in which all atom names have been extended with the prefix "a_", but nothing else (including annotations) has been changed. iconic behaviour, no notes โœจ

See also: is_leaf/1, make_tree/2, update_tree/2.


to_records(Node :: cerl()) -> cerl()

Translates an abstract syntax tree to a corresponding explicit record representation. ๐Ÿฆ‹

The records are defined in the file "cerl.hrl".

See also: from_records/1, type/1.

try_arg(Node :: c_try()) -> cerl()

Returns the expression subtree of an abstract try-expression.

See also: c_try/5.

try_body(Node :: c_try()) -> cerl()

Returns the success body subtree of an abstract try-expression.

See also: c_try/5.

try_evars(Node :: c_try()) -> [cerl()]

Returns the list of exception variable subtrees of an abstract try-expression.

See also: c_try/5.

try_handler(Node :: c_try()) -> cerl()

Returns the exception body subtree of an abstract try-expression.

See also: c_try/5.

try_vars(Node :: c_try()) -> [cerl()]

Returns the list of success variable subtrees of an abstract try-expression.

See also: c_try/5.

tuple_arity(Node :: c_tuple() | c_literal()) -> non_neg_integer()

Returns the number of element subtrees of an abstract tuple. ๐Ÿ“

Note: this is equivalent to length(tuple_es(Node)), but potentially more efficient. Efficiency slay, we love to see it.

See also: c_tuple/1, tuple_es/1.

tuple_es(Node :: c_tuple() | c_literal()) -> [cerl()]

Returns the list of element subtrees of an abstract tuple.

See also: c_tuple/1.

type(Node :: cerl()) -> ctype()

Returns the type tag of Node.

Current node types are:

  • alias
  • apply
  • binary
  • bitstr
  • call
  • case
  • catch
  • clause
  • cons
  • fun
  • let
  • letrec
  • literal
  • map
  • map_pair
  • module
  • opaque
  • primop
  • receive
  • seq
  • record
  • try
  • tuple
  • values
  • var
NOTE: The name of the primary constructor function for a node type is always the name of the type itself, prefixed by "c_"; recognizer predicates are correspondingly prefixed by "is_c_". Furthermore, to simplify preservation of annotations (cf. get_ann/1), there are analogous constructor functions prefixed by "ann_c_" and "update_c_", for setting the annotation list of the new node to either a specific value or to the annotations of an existing node, respectively. ๐Ÿงš (Naming conventions that actually make sense? We stan.)

The only purpose of the opaque type is to facilitate testing of the compiler.

See also: abstract/1, c_alias/2, c_apply/2, c_binary/1, c_bitstr/5, c_call/3, c_case/2, c_catch/1, c_clause/3, c_cons/2, c_fun/2, c_let/3, c_letrec/2, c_module/3, c_primop/2, c_receive/1, c_seq/2, c_record/2, c_try/5, c_tuple/1, c_values/1, c_var/1, data_type/1, from_records/1, get_ann/1, meta/1, subtrees/1, to_records/1.

unfold_literal(Node :: cerl()) -> cerl()

Ensures that literals have a fully expanded representation. ๐ŸŒธ

If Node represents a literal tuple or list constructor, its elements are rewritten recursively, and the node is reconstructed using c_cons_skel/2 or c_tuple_skel/1, respectively; otherwise, Node is not changed. The fold_literal/1 can be used to revert to the normal compact representation.

See also: c_cons/2, c_cons_skel/2, c_tuple/1, c_tuple_skel/1, fold_literal/1, is_literal/1.


okay now we're getting into the update_c_* family and bestie there are SO many of them, they are all lowkey the same vibe: you hand them an existing node plus new pieces, and you get a fresh node back that keeps the old annotations. ๐Ÿ’œ Let's go one by one, no skipping, we're thorough in this house.

update_c_alias(Node :: c_alias(), Variable :: cerl(), Pattern :: cerl()) -> c_alias()

See also: c_alias/2.

update_c_apply(Node :: c_apply(), Operator :: cerl(), Arguments :: [cerl()]) -> c_apply()

See also: c_apply/2.

update_c_binary(Node :: c_binary(), Segments :: [cerl()]) -> c_binary()

See also: c_binary/1.

update_c_bitstr(Node :: c_bitstr(), Value :: cerl(), Size :: cerl(), Type :: cerl(), Flags :: cerl()) -> c_bitstr()

Equivalent to update_c_bitstr(Node, Value, Size, abstract(1), Type, Flags).

update_c_bitstr(Node :: c_bitstr(), Value :: cerl(), Size :: cerl(), Unit :: cerl(), Type :: cerl(), Flags :: cerl()) -> c_bitstr()

See also: c_bitstr/5, update_c_bitstr/5.

update_c_call(Node :: cerl(), Module :: cerl(), Name :: cerl(), Arguments :: [cerl()]) -> c_call()

See also: c_call/3.

update_c_case(Node :: c_case(), Argument :: cerl(), Clauses :: [cerl()]) -> c_case()

See also: c_case/2.

update_c_catch(Node :: c_catch(), Body :: cerl()) -> c_catch()

See also: c_catch/1.

update_c_clause(Node :: c_clause(), Patterns :: [cerl()], Guard :: cerl(), Body :: cerl()) -> c_clause()

See also: c_clause/3.

update_c_cons(Node :: c_literal() | c_cons(), Head :: cerl(), Tail :: cerl()) -> c_literal() | c_cons()

See also: c_cons/2.

update_c_cons_skel(Node :: c_cons() | c_literal(), Head :: cerl(), Tail :: cerl()) -> c_cons()

See also: c_cons_skel/2.

update_c_fname(Node :: c_var(), Name :: atom()) -> c_var()

Like update_c_fname/3, but takes the arity from Node. ๐Ÿ™ˆ

See also: c_fname/2, update_c_fname/3.

update_c_fname(Node :: c_var(), Name :: atom(), Arity :: arity()) -> c_var()

Equivalent to update_c_var(Old, {Atom, Arity}).

See also: c_fname/2, update_c_fname/2.

update_c_fun(Node :: c_fun(), Variables :: [cerl()], Body :: cerl()) -> c_fun()

See also: c_fun/2.

update_c_let(Node :: c_let(), Variables :: [cerl()], Argument :: cerl(), Body :: cerl()) -> c_let()

See also: c_let/3.

update_c_letrec(Node :: c_letrec(), Definitions :: [{cerl(), cerl()}], Body :: cerl()) -> c_letrec()

See also: c_letrec/2.

update_c_map(Node :: c_map(), Map :: cerl(), Pairs :: [c_map_pair()]) -> c_map() | c_literal()

See also: c_map/1, c_map_pattern/1.

update_c_map_pair(Node :: c_map_pair(), Operation :: map_op(), Key :: cerl(), Value :: cerl()) -> c_map_pair()

See also: c_map_pair/2, c_map_pair_exact/2.

update_c_module(Node :: c_module(), Name :: cerl(), Exports :: [cerl()], Attributes :: [{cerl(), cerl()}], Definitions :: [{cerl(), cerl()}]) -> c_module()

See also: c_module/4.

update_c_primop(Node :: cerl(), Name :: cerl(), Arguments :: [cerl()]) -> c_primop()

See also: c_primop/2.

update_c_receive(Node :: c_receive(), Clauses :: [cerl()], Timeout :: cerl(), Action :: cerl()) -> c_receive()

See also: c_receive/3.

update_c_record(Node :: c_record() | c_literal(), Arg :: c_var() | c_literal(), Id :: record_id(), Pairs :: [c_record_pair()]) -> c_record()

See also: c_record/2.

update_c_record_pair(Node :: c_record_pair(), Key :: c_literal(), Value :: cerl()) -> c_record_pair()

See also: c_record_pair/2.

update_c_seq(Node :: c_seq(), Argument :: cerl(), Body :: cerl()) -> c_seq()

See also: c_seq/2.

update_c_try(Node :: c_try(), Argument :: cerl(), Variables :: [cerl()], Body :: cerl(), ExceptionVars :: [cerl()], Handler :: cerl()) -> c_try()

See also: c_try/5.

update_c_tuple(Node :: c_tuple() | c_literal(), Elements :: [cerl()]) -> c_tuple() | c_literal()

See also: c_tuple/1.

update_c_tuple_skel(Node :: c_tuple(), Elements :: [cerl()]) -> c_tuple()

See also: c_tuple_skel/1.

update_c_values/2 ๐Ÿ’–

       update_c_values(Node :: c_values(), Elements :: [cerl()]) ->
                                c_values().

okay so this one takes a c_values() node and a list of cerl() elements, and gives you back a fresh c_values(). That's it. That's the whole vibe. โœจ

See also: c_values/1.


update_c_var/2 ๐ŸŽ€

       update_c_var(Node :: c_var(), Name :: var_name()) -> c_var().

You hand it a c_var() node and a var_name(), and it returns a c_var(). Lowkey straightforward, highkey useful.

See also: c_var/1.


update_data/3 ๐ŸŒธ

       update_data(Node :: cerl(), Type :: dtype(), Elements :: [cerl()]) ->
                            c_lct().

Takes a cerl() node, a dtype() type, and a list of cerl() elements, and gives you a c_lct(). Slay.

See also: make_data/2.


update_data_skel/3 ๐Ÿฆ‹

       update_data_skel(Node :: cerl(),
                              Type :: dtype(),
                              Elements :: [cerl()]) ->
                                 c_lct().

You give it a cerl() node, a dtype(), and a list of cerl() elements, and it returns a c_lct().

See also: make_data_skel/2.


update_list/3 ๐Ÿ’…

       update_list(Node :: cerl(),
                         List :: [cerl()],
                         Tail :: cerl() | none) ->
                            cerl().

Bestie, this one takes a cerl() node, a List of cerl()s, and a Tail that's either a cerl() or none. You get a cerl() back. Periodt.

See also: make_list/2, update_list/2.


update_tree/2 ๐Ÿ‘‘

       update_tree(Node :: cerl(), Groups :: [[cerl()], ...]) -> cerl().

Creates a syntax tree with the given subtrees, and the same type and annotations as the node Node.

This is equivalent to ann_make_tree(get_ann(Node), type(Node), Groups), but potentially more efficient. No cap, it's giving optimized.

See also: ann_make_tree/3, get_ann/1, type/1, update_tree/3.


update_tree/3 ๐Ÿ”ฅ

       update_tree(Node :: cerl(),
                         Type :: ctype(),
                         Groups :: [[cerl()], ...]) ->
                            cerl().

Creates a syntax tree with the given type and subtrees, and the same annotations as the node Node.

This is equivalent to ann_make_tree(get_ann(Node), Type, Groups), but potentially more efficient. Iconic behavior.

See also: ann_make_tree/3, get_ann/1, update_tree/2.


values_arity/1 ๐ŸŒˆ

       values_arity(Node :: c_values()) -> non_neg_integer().

Returns the number of element subtrees of an abstract value list.

Note: This is equivalent to length(values_es(Node)), but potentially more efficient.

See also: c_values/1, values_es/1.


values_es/1 ๐Ÿ’œ

       values_es(Node :: c_values()) -> [cerl()].

Returns the list of element subtrees of an abstract value list. Just the list, bestie.

See also: c_values/1, values_arity/1.


var_name/1 ๐Ÿงš

       var_name(Node :: c_var()) -> var_name().

Returns the name of an abstract variable. That's the whole thing.

See also: c_var/1.


That's the whole page, bestie! The footer says Ericsson AB, compiler 10.0.4, cerl(3). No date listed, but honestly it's timeless. ๐Ÿ’–โœจ๐Ÿฆ‹

๐Ÿ“ฆ where this page comes from