flowlog.c)This document summarizes the main internal components of the Flowlog
engine in flowlog.c.
pl_program containing:
op/3) stored as
pl_op_overridesThe parser supports ISO term syntax, quoted atoms, lists, operators,
and the ISO read_term/3 / write_term/3 option
set used by tests.
Operator parsing follows a small disambiguation rule that matters for some control constructs:
Op(...) (no whitespace) is parsed as a functor
call.Op (...) (with whitespace) is parsed as a
prefix operator applied to a grouped term/goal.For example, \+ (A -> B) parses as negation of an
if-then goal, while \+(A -> B) is treated as a functor
call and requires extra parentheses around A -> B.
Program loading is deterministic:
pl_program.Flowlog represents terms as a tagged union:
Bindings live in a persistent environment structure
(pl_env) with parent links (copy-on-write style) so
backtracking can cheaply fork environments.
To keep variable dereferencing fast even with parent-linked environments, each clause-instantiation frame records the “introduced scope”, and variable lookup stops once that scope is reached (older frames cannot contain bindings for a scope that did not yet exist). The unifier also opportunistically caches deep ancestor bindings into the current env frame to reduce repeated parent-chain scans in pure recursive workloads.
Flowlog also maintains a small amount of call metadata (predicate indicator, depth, flags) used for:
occurs_check flag).bagof/3 / setof/3 groupingFlowlog provides three execution engines that share the same parser,
program representation, built-ins, error model, and indexing. The
default engine is wamvm.
interp /
tree)The interpreter is a direct solver (closer to a “tree-walking” engine than a compilation pipeline):
pl_program containing
predicates and their clauses (plus operator overrides and flags).This engine supports the full feature set, including:
assert*/1,
retract/1, …)wam)The WAM-lite engine is a fast fallback/alternative engine and is intended to reduce per-goal overhead for common pure/static ISO code.
In broad terms it:
The interpreter remains available as a reference engine and for debugging, but the WAM-lite engine aims to execute the full feature set directly (including dynamic database predicates, tabling, and occurs-check).
To detect what engine actually ran a query from within Prolog, use:
?- current_prolog_flag(flowlog_engine_active, Engine).wamvm)wamvm is the default engine mode and runs user-defined
clause bodies on a small bytecode VM (see WAM_ROADMAP.md).
In broad terms:
CALL and PROCEED).;/2, multi-clause predicates, and a few key
generators such as select1/3).wam.Performance notes:
wamvm keeps
select1/3 nondeterminism inside the VM (as a choicepoint)
in the non-OR-par path, avoiding per-alternative continuation
reconstruction.select1/3 chunks are executed via
an internal generator goal ($select1_range/5) so each chunk
runs as a single VM invocation, and chunk jobs reuse the
already-compiled WAMVM program code (no per-chunk rebuild).Fallbacks:
flowlog_engine=wamvm, Flowlog first checks whether
the loaded program/query is supported by the VM.FLOWLOG_WAMVM_REQUIRE_VM=1 is set,
in which case it errors instead). This includes tabling
(:- table/1) and any goals not yet supported by the VM’s
conservative support check.FLOWLOG_PROFILE_WAMVM=1 to print snapshot/call counters at
the end of a query.Conformance note:
FLOWLOG_WAMVM_REQUIRE_VM=1). A dedicated target exists to
keep this true: make test-inria-wamvm-vmonly.Flowlog uses multiple indexing layers:
Indexing is designed to be safe under dynamic database updates by using epoching and snapshots.
Indexing is a performance feature, not a semantic one:
ISO database predicates (including asserta/1,
assertz/1, retract/1, abolish/1,
clause/2) are implemented with:
Flowlog supports call-by-variant tabling for declared predicates:
:- table(path/2).Internally, each tabled predicate maintains:
Tabling runs under both engines. While tabling is active, OR-parallelism is currently disabled to keep the table state single-threaded. Tabled predicates are also treated as AND-par unsafe (they can create observable search/answer effects).
OR-parallelism runs independent alternative ranges concurrently:
Cancellation:
I/O:
AND-parallelism is used for limited “safe” cases:
Flowlog performs a conservative analysis and only parallelizes when it can preserve ISO-visible semantics.
The REPL is implemented directly in flowlog.c:
termios raw mode.~/.flowlog_history by default
(configurable via FLOWLOG_HISTORY_FILE).SIGINFO).