FlowQL is a compiler pipeline:
Source Text → Lexer → Parser → AST → Sema → Plan → Lower → FlowNet → Execute
Defines token kinds (keywords, operators, literals, identifiers) and helper functions. 42 token kinds total.
Hand-written scanner that produces tokens from source text. Tracks line/column for error reporting. Supports # line comments. Provides Next() and Peek().
AST node types for pipelines:
Pipeline= Source + Stage[] + SinkStagevariants: Filter, Map, Project, ParseJson, ParseCsv, ParseTsv, ParseKv, Lines, Count, CountBy, Batch, WindowHeaderMode: Default, Header, Noheader — controls CSV/TSV header behaviorExprtree: BinOp, UnaryOp, FieldRef, literals- Heap-allocated expression nodes via
NewExpr()/FreeExpr()
Recursive-descent parser producing an AST Pipeline. Expression parsing uses precedence climbing with levels: or → and → comparison → addition → multiplication → primary.
Semantic validation:
- Source/sink presence
- No duplicate parse stages
- Parse stages cannot follow aggregation
- Batch/window size limits (FlowNet max 64)
- Filter requires expression, map/project require fields
Runtime value type with 5 variants: Int, Real, Bool, Str, Null. Supports comparison, truthiness, and string formatting.
Runtime event — a dictionary of up to 32 named fields, each holding a Value. Supports field get/set, existence check, and JSON formatting.
Tree-walk expression evaluator. Evaluates AST expressions against an Event to produce a Value. Supports arithmetic, comparison, boolean logic with short-circuit evaluation, and field references.
Prints the execution plan in two modes:
- Default (
PrintPlan): pipeline graph with logical stage names and[stage N]annotations, channel topology with capacity and endpoint names, FlowNet mapping with kind tags (standard/expr-eval/aggregate), and a one-line summary (threads, channels, lowering strategy). - Verbose (
PrintPlanVerbose, viaplan -v): adds per-node detail — context types (SourceCtx, MapCtx, FilterCtx, etc.), userData record types, callback procedure names, source/sink config values, channel type tags (ADDRESS -> Event*), and origin annotations distinguishing builtin FlowNet nodes from FlowQL runtime wrappers.
Includes an expression printer that renders filter predicates and map computed fields in human-readable form (e.g. Filter(status >= 500 and latency_ms > 100), Map{path, slow = latency_ms > 1000}). Map/project stages with more than 3 fields are formatted multi-line for readability.
Compiles a validated AST pipeline into FlowNet Pipe.Stage() calls. Each FlowQL stage becomes a FlowNet node with appropriate context and callback. Manages node lifecycle (open/close sources and sinks).
FlowQL-specific FlowNet callbacks:
SourceGen— reads lines from file/stdinParseJsonTransform— parses JSON lines into EventsParseCsvTransform— parses CSV lines with header detectionParseTsvTransform— parses TSV lines with header detectionParseKvTransform— parses key=value log linesLinesTransform— renames_linetolineFilterPred— evaluates filter expressionMapTransform— evaluates map/project field expressionsCountReduce/CountByReduce— counting aggregationSinkConsume— formats and outputs Events as JSON
All pipelines are linear → compiled via Pipe.Stage():
| FlowQL Stage | FlowNet Node | Callback |
|---|---|---|
| source | SourceRun | GenProc (SourceGen) |
| parse_json | MapRun | TransformProc (ParseJsonTransform) |
| parse_csv | MapRun | TransformProc (ParseCsvTransform) |
| parse_tsv | MapRun | TransformProc (ParseTsvTransform) |
| parse_kv | MapRun | TransformProc (ParseKvTransform) |
| lines | MapRun | TransformProc (LinesTransform) |
| filter | FilterRun | PredicateProc (FilterPred) |
| map/project | MapRun | TransformProc (MapTransform) |
| count | ReduceRun | ReduceProc (CountReduce) |
| count by | ReduceRun | ReduceProc (CountByReduce) |
| batch | BatchRun | BatchProc (BatchPassthrough) |
| sink | SinkRun | ConsumeProc (SinkConsume) |
- Source reads lines, wraps each in an Event with
_linefield - Parse stages transform
_lineinto structured fields - Filter/map/project operate on structured Events
- Aggregation reduces the stream
- Sink formats Events as JSON lines
All Events flow as heap-allocated ADDRESS pointers through FlowNet's bounded FIFO channels.
Each pipeline stage runs in its own OS thread (FlowNet model). Backpressure is automatic via bounded channels. Graceful shutdown cascades when the source exhausts.
- No static type system — all types checked at runtime
- Expression evaluation is interpreted (tree-walk), not compiled
- No optimizer — direct AST-to-FlowNet lowering
- Linear pipelines only — no fan-out, fan-in, or joins
- JSON parser is a simplified line-oriented parser (not full RFC 8259)