curry.icurry.analysis package

class curry.icurry.analysis.CaseBody(body, params, locals, frees, scrutinee, branches)[source]

Bases: object

A body that is one case on a parameter: the parameters it binds, the locals before the case, its free variables, the variable and the parameter index of the scrutinee, and the branches by the full name of their constructor. size is the largest branch.

class curry.icurry.analysis.ExpressionBody(body, params, locals, frees, result)[source]

Bases: object

A body that returns an expression: the parameters it binds (variable to parameter index), the locals it binds, in order (variable and expression), its free variables, and the result. size counts the nodes it builds, uses the occurrences of each variable.

class curry.icurry.analysis.Inliner(modules, budget, depth=MAX_DEPTH)[source]

Bases: object

Rewrites the body of one function at a time, in place: every saturated call of a known function is replaced by its body under the rules of this module, and every apply whose head is known is saturated (partials.saturate), to a fixpoint bounded by depth. budget is the largest expression body inlined, in nodes built; 0 turns both rules off. symbols collects the symbol names that the copied bodies name, so the caller can join the imports of the module.

bind(sigma, vids, expr, uses, pending, depth, rewrite=False)[source]

Maps the variables vids of the body, which name one argument, to expr under the sharing rule: a variable, a literal, or a static string as it is; an expression used once as it is; one used more through a fresh variable of the caller’s block, so that it is built once; one not used is dropped. uses counts the occurrences of all the variables together. A local that gets a variable is rewritten first (rewrite); an argument was rewritten already.

bind_frees(sigma, frees, pending)[source]
bind_locals(sigma, locals, uses, pending, depth)[source]
block(block)[source]
expr(expr, pending, depth)[source]

Rewrites expr from the inside out. The result of a rule is rewritten again, one level deeper, until no rule applies or the depth is reached. The walk over the arguments runs on the trampoline; the rewrite of a result (rules) runs a walk of its own, at most depth deep.

fresh()[source]
instantiate(shape, args, pending, depth)[source]

The expression body shape on the arguments args.

instantiate_case(shape, branch, args, pending, depth)[source]

The branch branch of the single-case body shape on the arguments args, whose scrutinee is a constructor of the branch.

rewrite(ifun)[source]

Rewrites the body of ifun. Returns the number of calls and applies replaced. The shape of the function is taken first, so that a caller reached later sees the body as it was.

rules(expr, pending, depth)[source]

The rewrite of the call expr, or None when no rule applies.

curry.icurry.analysis.alias_target(ifun)[source]

The full name of the function that ifun is an alias of, or None. The answer comes from the metadata when it is there (a module loaded from its compiled form), else from the body.

curry.icurry.analysis.alias_target_of_body(ifun)[source]

The full name of the function that ifun is an alias of, read from its body, or None. A function without a Curry body (built-in, external, or loaded from its compiled form) is never an alias by this test.

curry.icurry.analysis.body_shape(body, arity)[source]

The ExpressionBody or CaseBody of the IFuncBody body of a function of arity parameters, or None when the body has another shape: no block (a built-in, an external, or a function loaded from its compiled form), a recursive let, a case whose branches all have a case or an exempt, a variable the body does not bind, or a path the inliner does not follow.

curry.icurry.analysis.find_static_strings(iobj)[source]

A static string is a sequence of ICCall nodes constructing a list of characters.

curry.icurry.analysis.inline_body_text(body)[source]

The ICurry-JSON text of a function body, for the metadata.

curry.icurry.analysis.inline_shape(ifun)[source]

The shape of the body that a call of ifun is replaced by, or None. The shape is built once per function, over a copy of the body as it is when first asked for (before the pass rewrites the function), or over the body the metadata records (INLINE_KEY: a module loaded from its compiled form has no bodies). A text that does not read back makes the function unknown; it does not stop the import.

curry.icurry.analysis.is_apply(expr, modules)[source]

Tells whether expr is a saturated call of apply: an IFCall with two arguments of Prelude.apply, or of Prelude.$ while the loaded Prelude defines it as an alias of apply (resolve_alias). modules maps module names to Curry modules and packages, as Interpreter.modules does.

A user alias of apply (app f x = f x) is not an apply here, though inline_aliases turns a call of it into one afterwards: the source wrote the indirection, and a program may need it to hand a known function value to the apply of the runtime, which the optimizer would otherwise fold away (a let of a bare function value does not survive the front end).

curry.icurry.analysis.is_recursive(ifun, modules)[source]

Whether ifun lies on a cycle of the call graph of its module. A function whose module is not among modules counts as recursive: the inliner leaves it alone.

curry.icurry.analysis.lookup_constructor(symbolname, modules)[source]

Finds the IConstructor named by the full name symbolname among the loaded modules, as lookup_function finds a function. Returns None when the module is not loaded or has no such constructor.

curry.icurry.analysis.lookup_function(symbolname, modules)[source]

Finds the IFunction named by the full name symbolname among the loaded modules. modules maps module names to Curry modules and packages, as Interpreter.modules does. Returns None when the module is not loaded or has no such function.

curry.icurry.analysis.lookup_module(modulename, modules)[source]

Finds the IModule named modulename among the loaded modules, as lookup_function finds a function, or None.

curry.icurry.analysis.lookup_symbol(symbolname, modules)[source]

The IFunction or IConstructor named by symbolname, or None.

curry.icurry.analysis.node_count(expr)[source]

The nodes that expr builds: a call, a partial application, a constructor, a choice, or a literal is one node plus its arguments; a variable is a reference and counts nothing.

curry.icurry.analysis.nullary_body(ifun)[source]

The expression that the nullary function ifun returns, when its body is one return statement without declarations, or None. A function with parameters, a local variable, a free variable, or a case is never unfolded. Neither is a function without a Curry body (built-in, external, or loaded from its compiled form).

curry.icurry.analysis.partial_head(expr, modules, depth=MAX_UNFOLDING_DEPTH)[source]

The partial application that the head expression expr denotes, as a fresh IFPCall or ICPCall, or None when the head is not known.

expr is known when it is a partial application; an IFCall without arguments of a nullary function that unfolds to one (unfolding); or an apply whose head is known and whose call is a partial application (saturate), through at most depth nullary functions and applies. modules maps module names to Curry modules and packages, as Interpreter.modules does. The partial must agree with the symbol table: the function or constructor is loaded, and its arity is the number of arguments plus the missing count, which is at least one. So a call built from the answer has the arity of its symbol.

curry.icurry.analysis.recordable(ifun, modules)[source]

Whether the body of ifun is one that a module records for its importers: it has a shape, it is not recursive, and it is within the limit (RECORD_LIMIT for an expression body, CASE_LIMIT for the largest branch of a single-case body).

curry.icurry.analysis.recorded_functions(imodule, modules)[source]

The full names of the functions of imodule whose bodies the module records under INLINE_KEY, as a frozenset: every public function that is recordable, and every private function that a recorded body names, in a saturated call or in a partial application, so that an importer can follow the chain (the lambda behind . sits in a partial application of the body of .). Computed once per module and cached on it.

curry.icurry.analysis.recursive_functions(imodule)[source]

The full names of the functions of imodule that lie on a cycle of its call graph, as a frozenset: a function that calls itself, or two or more that call each other, through saturated calls (IFCall). A partial application is a value and makes no edge. Computed once per module, from the bodies as they are when first asked for, and cached on the module. A function without a body has no edges.

curry.icurry.analysis.resolve_alias(symbolname, modules, nargs)[source]

Follows aliases from the function named symbolname, called with nargs arguments, to the function that does the work. Returns the full name of that function: symbolname itself when it is not an alias, when its module is not loaded, or when the call is not saturated. A chain stops before a target that is not loaded or that has another arity. A chain that closes on itself (aliases of each other) leaves the call alone.

curry.icurry.analysis.saturate(iapply, modules, depth=MAX_UNFOLDING_DEPTH)[source]

The call that the apply node iapply builds when its head is known (partial_head), or None. When the partial misses one argument, the call is the saturated call (IFCall, or ICCall of a constructor); when it misses more, the call is the longer partial application. A saturated call that is itself an apply (ap = apply, then ap f x) is saturated again, to the bound depth. The head is a fresh copy, so the call shares nothing with the body of a nullary function; the argument is the one of iapply.

curry.icurry.analysis.set_monadic_metadata(ifun, modules)[source]

Determines whether an ICurry function is monadic.

The result is stored in the ‘all.monadic’ metadata and also in ‘all.flags’ by OR-ing with F_MONADIC. This apparent redundancy is needed because ‘all.monadic’ is actually a tristate: True or False indicates the monadic check has been performed, while its absense indicates the check needs to be performed.

To determine whether a function is monadic, its call graph is walked. If the function calls any monadic function, then it is determined to be monadic.

curry.icurry.analysis.unfolding(ifun, modules, depth=MAX_UNFOLDING_DEPTH)[source]

The partial application that the nullary function ifun unfolds to, as a fresh expression, or None. The answer comes from the metadata when it is there (a module loaded from its compiled form), else from the body, which may itself be a call of another nullary function or an apply chain (see partial_head). A text in the metadata that does not read back as a partial application makes the function unknown; it does not stop the import.

curry.icurry.analysis.unfolding_text(partial)[source]

The ICurry-JSON text of a partial application, for the metadata.

curry.icurry.analysis.varinfo(iobj)[source]

Captures information about ICurry variables.

Submodules