A11 (C++ runtime)
Native C++ implementation of the A11 streaming action runtime
Loading...
Searching...
No Matches
a11::flow Namespace Reference

Namespaces

namespace  catalogue
 What the language knows about the world it runs in.
 
namespace  discover
 Finding the actions a project declares, by reading its source.
 
namespace  graph
 
namespace  internal
 
namespace  interpreter
 
namespace  pattern
 
namespace  syntax
 
namespace  tool
 
namespace  vocabulary
 The words the language gives meaning to, and what each one may be given.
 

Classes

struct  CodeInfo
 What a diagnostic code means, for documentation and for a11 flow codes. More...
 
struct  CoerceContext
 What coercion needs besides the value and the type. More...
 
class  CompiledProgram
 One flow file, compiled: the plans, the graphs, and the tree they borrow. More...
 
struct  CompleteResult
 What may be written at an offset, and the word already typed there. More...
 
struct  Description
 What is at one offset, described. More...
 
struct  Diagnostic
 One problem found in a flow. More...
 
struct  DocumentSymbol
 One thing a document declares, and the things declared inside it. More...
 
struct  DtoPlan
 One compiled struct: a shape a port may be typed with. More...
 
struct  Edit
 One replacement of a span of source. An empty text is a deletion. More...
 
struct  EvalContext
 What an expression is evaluated against. More...
 
struct  FieldPlan
 One field of a struct, resolved. More...
 
struct  Fix
 An edit, or set of edits, that would fix a diagnostic. More...
 
struct  FlowPlan
 One compiled flow: what a caller sees, and what the runtime will do. More...
 
struct  FormatOptions
 What the formatter is allowed to decide. More...
 
struct  FormatResult
 The formatted text, and what it took to get there. More...
 
struct  HeaderPlan
 One declared header. More...
 
class  HostBridge
 What the process running a flow knows and the language does not. More...
 
class  HostObject
 A value only the host knows what to do with. More...
 
struct  LexOptions
 What to keep while lexing. More...
 
struct  LexResult
 Tokens, and what could not be read. More...
 
class  LineIndex
 Line and column lookup over one source text. More...
 
struct  ParseResult
 The flows a file declares, and everything wrong with it. More...
 
struct  PortPlan
 One declared port of a flow, resolved. More...
 
struct  Position
 One place in the source: the byte offset, and the line and column at it. More...
 
struct  Program
 Every flow and shape one source file declares. More...
 
struct  Proposal
 One thing that may be written at an offset. More...
 
struct  Range
 Half-open span of source, [start, end). More...
 
struct  ResolvedFlow
 One flow, resolved: its plan, its names, and what is wrong with it. More...
 
struct  ResolveResult
 A whole file, resolved. More...
 
struct  RunOptions
 What a run needs besides the program. More...
 
struct  SchemaImport
 The shapes a JSON Schema describes, and what would not fit. More...
 
struct  SemanticToken
 One token, and what it means. More...
 
struct  StepPlan
 One resolved statement, as the plan format describes it. More...
 
struct  Symbol
 One name, what it is, and what became of it. More...
 
class  TextIndex
 A document, and the offset arithmetic every editor protocol needs over it. More...
 
struct  Token
 One token: what it is, where it is, and what it holds. More...
 
class  Value
 One Flow value. More...
 

Enumerations

enum class  ProposalKind {
  kStatement , kDeclaration , kModifier , kStage ,
  kFunction , kType , kStatusCode , kLogLevel ,
  kConstant , kPortModifier , kFlow , kPort ,
  kNode , kNodeMap , kCall , kBarrier ,
  kVariable , kHeader , kField
}
 What a proposal is, which is what an editor turns into an icon. More...
 
enum class  Severity { kError , kWarning , kWeakWarning , kInformation }
 How much a diagnostic matters. More...
 
enum class  Family {
  kSyntax , kForm , kName , kSequence ,
  kBarrier , kUnused
}
 The kind of problem, which is the grouping a reader thinks in. More...
 
enum class  SyntaxTarget { kSublime , kPygments , kVsCode , kVsCodeInjection }
 An editor definition the language can write for itself. More...
 
enum class  SemanticKind {
  kComment , kString , kNumber , kDuration ,
  kDeclarationKeyword , kStatementKeyword , kModifierKeyword , kStage ,
  kBuiltin , kType , kStatusCode , kLogLevel ,
  kConstant , kWordOperator , kFlowName , kActionName ,
  kNodeMapName , kMember , kPortName , kIdentifier ,
  kFlowOperator , kOperator , kBrace , kParenthesis ,
  kBracket , kPunctuation , kBad
}
 What a token means where it stands, which is what a reader colours by. More...
 
enum class  SymbolClass {
  kFlow , kDto , kField , kPort ,
  kHeader , kNodeMap , kNode , kCall ,
  kBarrier , kVariable , kExternal
}
 Moving around a document: what is under the caret, what the file declares, and where a name was bound. More...
 
enum class  OffsetBasis { kBytes , kUtf16 }
 Which basis the offsets in a request and its answer are counted in. More...
 
enum class  SymbolKind {
  kInputPort , kOutputPort , kHeader , kCall ,
  kNode , kNodeMap , kBarrier , kLoopVariable ,
  kCarry , kValue
}
 What a name means inside a flow. More...
 
enum class  TokenKind {
  kNewline , kComment , kString , kNumber ,
  kDuration , kWord , kDot , kRange ,
  kSpread , kArrow , kCarry , kEqual ,
  kEqualEqual , kBangEqual , kLess , kLessEqual ,
  kGreater , kGreaterEqual , kPlus , kMinus ,
  kPipe , kColon , kComma , kLeftBrace ,
  kRightBrace , kLeftParen , kRightParen , kLeftBracket ,
  kRightBracket , kBad , kEnd
}
 What kind of thing a token is. More...
 

Functions

CompleteResult CompleteAt (std::string_view source, size_t offset, const catalogue::Catalogue &known=catalogue::Catalogue::Builtin())
 What may be written at offset in source.
 
std::string_view ProposalKindName (ProposalKind kind)
 The name of a proposal kind in the output format, in kebab case.
 
std::string_view SeverityName (Severity severity)
 The spelling of a severity in the output formats.
 
std::string_view FamilyName (Family family)
 The spelling of a family in the output formats.
 
Severity SeverityFromName (std::string_view name)
 Severity for a name from the output formats, or kError if unknown.
 
Family FamilyFromName (std::string_view name)
 Family for a name from the output formats, or kSyntax if unknown.
 
const Diagnostic *absl_nullable FirstError (absl::Span< const Diagnostic > diagnostics)
 The first error in diagnostics, or nullptr if none is an error.
 
absl::Span< const CodeInfo > KnownCodes ()
 Every diagnostic code the language can produce, sorted by code.
 
const CodeInfo *absl_nullable FindCode (std::string_view code)
 The entry for a code, or nullptr if nothing publishes it.
 
void SortDiagnostics (std::vector< Diagnostic > &diagnostics)
 Sorts diagnostics into the order every frontend presents them in: by position, then by code, so two runs over the same file agree byte for byte.
 
nlohmann::json DiagnosticToJsonValue (const Diagnostic &diagnostic)
 One diagnostic, as it appears in the envelope.
 
Diagnostic DiagnosticFromJsonValue (const nlohmann::json &value)
 A diagnostic read back from its JSON, for frontends that consume the envelope rather than the library – the IntelliJ plugin, a CI script.
 
nlohmann::json DiagnosticsToJsonValue (std::string_view source, absl::Span< const Diagnostic > diagnostics)
 The full flow.diagnostics/v1 envelope.
 
std::string DiagnosticsToJson (std::string_view source, absl::Span< const Diagnostic > diagnostics)
 The envelope, serialised with a trailing newline and two-space indent.
 
nlohmann::json CodesToJsonValue ()
 The published code table, as flow.codes/v1.
 
nlohmann::json VocabularyToJsonValue ()
 Every word set the language gives meaning to, as flow.vocabulary/v1.
 
nlohmann::json DiagnosticsToSarifValue (std::string_view source, absl::Span< const Diagnostic > diagnostics)
 A SARIF 2.1.0 log for one file's diagnostics.
 
std::string DiagnosticsToSarif (std::string_view source, absl::Span< const Diagnostic > diagnostics)
 The SARIF log, serialised with a trailing newline.
 
nlohmann::json ConstantToJsonValue (const syntax::Constant &constant)
 A constant as the syntax format writes it.
 
nlohmann::json NodeToJsonValue (const syntax::Node &node)
 One syntax node, and everything under it.
 
nlohmann::json SyntaxToJsonValue (std::string_view source, const ParseResult &result)
 The full flow.syntax/v1 envelope: the flows a file declares, and what is wrong with it.
 
std::string SyntaxToJson (std::string_view source, const ParseResult &result)
 The envelope, serialised with a trailing newline and two-space indent.
 
nlohmann::json TokensToJsonValue (std::string_view source_name, std::string_view source)
 The flow.tokens/v1 envelope: every token, and what it means where it is.
 
std::string TokensToJson (std::string_view source_name, std::string_view source)
 The envelope, serialised with a trailing newline and two-space indent.
 
nlohmann::json FormatToJsonValue (const FormatResult &result)
 The flow.format/v1 envelope: the formatted text, and what it took.
 
nlohmann::json CompletionsToJsonValue (const CompleteResult &result)
 The flow.completions/v1 envelope: what may be written at an offset.
 
nlohmann::json PlanToJsonValue (std::string_view source_name, const Program &program)
 The flow.plan/v1 envelope: what each flow of a file resolved to.
 
nlohmann::json DtoToJsonValue (const DtoPlan &dto, const Program *absl_nullable program=nullptr)
 One resolved shape, as the structs of a plan writes it.
 
std::string PlanToJson (std::string_view source_name, const Program &program)
 The envelope, serialised with a trailing newline and two-space indent.
 
std::string DiagnosticToText (std::string_view source, const Diagnostic &diagnostic)
 One diagnostic on one line, in the shape editors and compilers have used for decades: path:line:column: severity: message [code].
 
FormatResult Format (std::string_view source, FormatOptions options={})
 Format Flow source.
 
absl::Span< const SyntaxTarget > SyntaxTargets ()
 Every target, for a command that offers a choice of them.
 
std::string_view SyntaxTargetName (SyntaxTarget target)
 The name a target is asked for by: sublime.
 
bool SyntaxTargetFromName (std::string_view name, SyntaxTarget &target)
 A target from its name, or nullopt.
 
std::string_view SyntaxTargetPath (SyntaxTarget target)
 Where the generated file belongs, relative to the repository root.
 
std::string GenerateSyntax (SyntaxTarget target)
 The whole definition, generated.
 
std::string_view SemanticKindName (SemanticKind kind)
 The name of a semantic kind in the output formats, in kebab case.
 
SemanticKind SemanticKindFromName (std::string_view name)
 The kind a name refers to, or kIdentifier if it is not one.
 
std::vector< SemanticToken > Highlight (absl::Span< const Token > tokens)
 Classify a token stream.
 
void RefinePorts (std::string_view source, std::vector< SemanticToken > &semantic)
 Mark the identifiers that are ports of the flow they stand in.
 
std::vector< Diagnostic > Inspect (std::string_view source, const ParseResult &parsed, const ResolveResult &resolved)
 Everything a flow does that it probably did not mean to.
 
LexResult Lex (std::string_view source, LexOptions options={})
 Turn Flow source into tokens, ending with a single end token.
 
std::string WordMarkdown (std::string_view name, vocabulary::WordRole role)
 One word or mark of the language, written out as reference: what it does, what it takes, how it behaves, and a line of Flow using it.
 
std::string StageMarkdown (std::string_view name)
 A pipeline stage, written out as reference.
 
std::string BuiltinMarkdown (std::string_view name)
 A built-in function, the same way.
 
std::string ActionMarkdown (const catalogue::ActionInfo &action)
 An action, written out as the Markdown a reader wants to see: what it does, then every port it has.
 
std::string PortMarkdown (std::string_view name, std::string_view type, bool required, bool unary, std::string_view description)
 One port, written out as the Markdown a reader wants beside its name.
 
std::string FlowMarkdown (const FlowPlan &flow)
 A flow of the document, written out the same way: what it does, then its ports and which direction each runs.
 
std::string ShapeMarkdown (const DtoPlan &shape)
 A struct, written out the same way: how many fields, then each of them.
 
std::string_view SymbolClassName (SymbolClass kind)
 
Range Widened (const LineIndex &lines, const Range &range, const Range &selection)
 The whole construct a declaration opens: its first token through the } that closes its block.
 
Range ConstructRange (const LineIndex &lines, absl::Span< const Token > tokens, const syntax::Location &opened, const Range &selection)
 
std::vector< DocumentSymbol > Symbols (std::string_view source)
 Every symbol a document declares, nested as it is written.
 
Description Describe (std::string_view source, size_t offset, const catalogue::Catalogue &known=catalogue::Catalogue::Builtin())
 What is at offset, and where it came from.
 
bool OffsetBasisFromName (std::string_view name, OffsetBasis &basis)
 The basis a request named, or kBytes when it named none.
 
std::string_view OffsetBasisName (OffsetBasis basis)
 The name of a basis, for a message and for the JSON.
 
void RebaseToUtf16 (nlohmann::json &answer, const TextIndex &index)
 Rewrite every document offset in an answer from bytes into UTF-16 units.
 
ParseResult Parse (std::string_view source)
 Parse Flow source.
 
ParseResult ParseTokens (std::string_view source, absl::Span< const Token > tokens, std::vector< Diagnostic > diagnostics)
 Parse an already-lexed stream, sharing the lex diagnostics.
 
std::string_view SymbolKindName (SymbolKind kind)
 The name of a symbol kind, for a message and for the JSON.
 
ResolveResult Resolve (std::string_view source, const ParseResult &parsed, bool build_graph=false)
 Resolve a parsed program: names, ports, scopes, node maps and types.
 
absl::StatusOr< actions::ActionSchema > FlowSchema (const FlowPlan &plan)
 The [actions::ActionSchema] a flow presents.
 
absl::StatusOr< actions::ActionHandler > MakeHandler (std::shared_ptr< const CompiledProgram > program, std::string_view flow, RunOptions options={})
 The action handler that runs one flow of program.
 
absl::StatusOr< actions::ActionHandler > MakeEntryHandler (std::shared_ptr< const CompiledProgram > program, RunOptions options={})
 The action handler that runs the program's entry flow.
 
nlohmann::json DtoToJsonSchema (const DtoPlan &dto, const Program &program)
 The JSON Schema a struct describes.
 
SchemaImport JsonSchemaToDtos (const nlohmann::json &schema, std::string_view name)
 The shapes schema describes, named name where it does not name itself.
 
std::string DtoToFlow (const DtoPlan &dto)
 One shape as the Flow text that declares it.
 
absl::Span< const std::string_view > Methods ()
 Every method [Handle] knows, in the order --help lists them.
 
std::string_view MethodSummary (std::string_view method)
 What a method takes and gives back, one line, for --help.
 
nlohmann::json Handle (const nlohmann::json &request)
 One question about one document, answered.
 
std::string_view KindName (TokenKind kind)
 The name of a kind, as a11.flow.lexer spells it.
 
TokenKind KindFromName (std::string_view name)
 The kind a name from [KindName] refers to, or kBad if it is not one.
 
bool operator== (const Value &left, const Value &right)
 
std::unique_ptr< HostBridge > NativeHostBridge ()
 A bridge over A11's own C++ serialisation registry.
 
Value Lookup (const Value &value, const Value &key)
 Take key out of value: a mapping key, an index, or a field.
 
bool Truthy (const Value &value)
 Whether value counts as true, as an if and a where decide it.
 
std::string AsText (const Value &value)
 value as text, the way the text stage and builtin render it.
 
Value AsNumber (const Value &value)
 value as a number, or zero when there is nothing to read.
 
double AsDouble (const Value &value)
 AsNumber as a double, for the places that only want the magnitude.
 
Value AsHole (pattern::HoleType type, std::string_view text)
 One hole's text, read as the hole said to read it.
 
absl::StatusOr< Value > MatchPattern (std::string_view pattern, std::string_view subject)
 The fields a pattern pulls out of subject, or null where it does not fit.
 
Value MatchCompiled (const pattern::Pattern &pattern, std::string_view subject)
 The same, against a pattern already compiled.
 
Value AsJson (const Value &value)
 Text parsed as JSON; anything already decoded is left alone.
 
Value Truncate (const Value &value, std::int64_t size)
 The first size of a value: characters, bytes, elements or pairs.
 
std::string JsonText (const Value &value)
 A value's own JSON text, as json.dumps(sort_keys=True) writes it.
 
double DurationSeconds (absl::Duration value)
 A duration as a number of seconds, for every duration there is.
 
absl::Duration SecondsDuration (double total)
 A duration of total seconds, negative ones included.
 
std::optional< absl::Duration > ParseDuration (std::string_view text)
 A duration from the way the language writes one, or nullopt.
 
absl::Duration AsDuration (const Value &value)
 A duration from a duration, from written text, or from seconds.
 
std::optional< absl::Time > ParseTime (std::string_view text)
 An instant from RFC 3339 text, as TimeText writes it.
 
absl::Time AsTime (const Value &value)
 An instant from an instant, from RFC 3339 text, or from epoch seconds.
 
std::string DurationText (absl::Duration value, std::string_view spec={})
 A duration as text: 1m30s by default, or one unit when spec names one.
 
std::string TimeText (absl::Time value, std::string_view spec={})
 An instant as text: RFC 3339 in UTC, a strftime pattern, or epoch.
 
std::string Strformat (const Value &format, absl::Span< const Value > arguments)
 format with each % conversion replaced by one of arguments.
 
absl::StatusOr< Value > CallBuiltin (std::string_view name, absl::Span< const Value > arguments, HostBridge *absl_nullable bridge)
 Call one of the language's fixed functions.
 
absl::StatusOr< Value > CoerceShape (const DtoPlan &shape, const Value &value, const CoerceContext &context)
 Make value a value of shape: fill its defaults, check its bounds, and coerce every field to the type the shape gives it.
 
absl::StatusOr< Value > Coerce (const Value &value, const syntax::TypeExpression &type, const CoerceContext &context)
 Make value a value of the type type names.
 
int Order (const Value &left, const Value &right)
 Where two values sit relative to one another: -1, 0 or 1.
 
absl::StatusOr< Value > Add (const Value &left, const Value &right)
 left + right, as an expression means it.
 
absl::StatusOr< Value > Evaluate (const syntax::Node &node, const EvalContext &context)
 Evaluate one expression.
 
Value StatusRecord (const absl::Status &status)
 A status as the record a flow sees when it looks at an outcome.
 
std::optional< absl::StatusCode > StatusCodeOf (const Value &value)
 The canonical code value names, by name or by number, or nullopt.
 
absl::Status StatusOfRecord (const Value &record)
 The status a record like the one above describes.
 

Variables

constexpr std::string_view kCompletionsFormat = "flow.completions/v1"
 The format field of the completions envelope.
 
constexpr std::string_view kDiagnosticsFormat = "flow.diagnostics/v1"
 The format field of each envelope: what a reader checks before parsing.
 
constexpr std::string_view kCodesFormat = "flow.codes/v1"
 
constexpr std::string_view kSyntaxFormat = "flow.syntax/v1"
 
constexpr std::string_view kTokensFormat = "flow.tokens/v1"
 
constexpr std::string_view kVocabularyFormat = "flow.vocabulary/v1"
 
constexpr std::string_view kFormatFormat = "flow.format/v1"
 
constexpr std::string_view kSymbolsFormat = "flow.symbols/v1"
 The format field of the symbols envelope.
 
constexpr std::string_view kHoverFormat = "flow.hover/v1"
 The format field of the hover envelope.
 
constexpr std::string_view kDefinitionFormat = "flow.definition/v1"
 The format field of the definition envelope.
 
constexpr std::string_view kPlanFormat = "flow.plan/v1"
 The format field of the plan envelope.
 
constexpr size_t kQueueDepth = 8
 How many values a pipe may run ahead of its reader.
 
constexpr std::string_view kSchemaFormat = "flow.schema/v1"
 The format field of the schema envelope.
 
constexpr std::string_view kFlowTypeKey = "x-a11-type"
 The extension key that says which Flow type a string really is.
 
constexpr std::string_view kFlowOrderKey = "x-a11-order"
 The extension key holding a shape's fields in declaration order.
 

Enumeration Type Documentation

◆ Family

enum class a11::flow::Family
strong

The kind of problem, which is the grouping a reader thinks in.

An editor turns each of these into one switchable inspection, and a CI job can gate on some and not others – which is why the family is part of the output contract rather than something a frontend infers from the code.

Enumerator
kSyntax 

The text is not a flow: something is missing or in the wrong place.

kForm 

A form the language does not have, or does not have there.

kName 

A name that cannot be resolved, or is used as the wrong thing.

kSequence 

A sequence of operations that cannot do what it appears to.

kBarrier 

A barrier, loop tail or ordering that cannot hold.

kUnused 

A status, wait or declaration nothing uses.

◆ OffsetBasis

enum class a11::flow::OffsetBasis
strong

Which basis the offsets in a request and its answer are counted in.

Enumerator
kBytes 

Bytes from the start of the file: the language's own, and the default.

kUtf16 

UTF-16 code units from the start of the file: what a JVM or JavaScript editor host indexes its document buffer with.

◆ ProposalKind

enum class a11::flow::ProposalKind
strong

What a proposal is, which is what an editor turns into an icon.

Finer than "keyword or not": a reader choosing between a port and a stage is making a different decision than one choosing between two ports, and the icons are how an editor says which list they are looking at. These names are part of the flow.completions/v1 contract.

Enumerator
kStatement 

A word that opens a statement: run, wait, for.

kDeclaration 

A word that declares something: in, header, describe.

kModifier 

A word that follows a call: tee, timeout, forward headers.

kStage 

A pipeline stage, offered after a |.

kFunction 

One of the fixed functions.

kType 

A port type.

kStatusCode 

A canonical status code, as fail names one.

kLogLevel 

A log level, as log and logf name one.

kConstant 

true, false, null, it.

kPortModifier 

What a port says about itself: stream, required.

kFlow 

A flow of this file, offered as a call target.

kPort 

A port of this flow, or of a call.

kNode 

A node of the flow's own.

kNodeMap 

A node map.

kCall 

A bound run/call step.

kBarrier 

A bound wait/drain.

kVariable 

A loop variable, the index a loop binds, or what a repeat carries.

kHeader 

A header, under its alias.

kField 

A field of something: a status's code, a node's id.

◆ SemanticKind

enum class a11::flow::SemanticKind
strong

What a token means where it stands, which is what a reader colours by.

Finer-grained than the grammar needs: a word is significant or not to a parser, but a reader wants to tell a port type from a pipeline stage from a status code, because that is the distinction they are making. These are the names the output format uses and the names an editor maps to its own palette, so they are part of the contract.

Enumerator
kComment 
kString 
kNumber 
kDuration 
kDeclarationKeyword 

flow, in, out, header, node, nodes, as, default.

kStatementKeyword 

run, call, try, wait, for, if, fail, and the rest.

kModifierKeyword 

tee, via, timeout, after, with, id, forward headers.

kStage 

A stage, after a | or as a bare then/where.

kBuiltin 

One of the fixed functions, where it is being called.

kType 

A port type: string, list, a11.sdk.AudioBuffer.

kStatusCode 

A canonical status code: not_found, NOT_FOUND.

kLogLevel 

A log level a log or logf named: warning, DEBUG.

kConstant 

true, false, null, it.

kWordOperator 

and, or, not.

kFlowName 

The name a flow declaration gives.

kActionName 

The action a run/call names.

kNodeMapName 

The name a nodes declaration, or a via, gives a node map.

kMember 

What follows a .: a port, a field, a node's id.

kPortName 

A port of the flow: its declaration, and every mention of it.

Told apart from every other name a flow binds because a port is the one thing that crosses the flow's boundary – it is the interface, and a reader following where data comes from and goes wants to see which names are the outside world and which are local plumbing. Deciding it needs the resolver, so it is [RefinePorts] rather than [Highlight] that says so.

kIdentifier 

Any other word: a node, a step, a loop variable, a let value.

kFlowOperator 

->, <-, |: where a stream is going.

kOperator 

=, ==, <, +, and the rest.

kBrace 
kParenthesis 
kBracket 
kPunctuation 

., :, ,.

kBad 

Something the language has no meaning for.

◆ Severity

enum class a11::flow::Severity
strong

How much a diagnostic matters.

The distinction that earns its keep is between "this cannot work" and "this does nothing": the first stops a flow from compiling, the second is the greyed-out unused symbol every editor already knows how to show.

Enumerator
kError 

The compiler refuses the flow. a11 flow check exits non-zero.

kWarning 

The flow compiles and does something other than what it says.

kWeakWarning 

The flow works, and part of it is doing nothing.

kInformation 

Non-blocking information.

◆ SymbolClass

enum class a11::flow::SymbolClass
strong

Moving around a document: what is under the caret, what the file declares, and where a name was bound.

Navigation uses the parser and resolver so hover, completion, diagnostics, and editor integrations assign the same role and binding to each name. What a thing is, which is what an editor turns into an icon.

Serialized in flow.symbols/v1 and flow.hover/v1.

Enumerator
kFlow 
kDto 
kField 
kPort 
kHeader 
kNodeMap 
kNode 
kCall 
kBarrier 
kVariable 
kExternal 

Something the language knows about but the document did not declare: an action, a registered type, a stage, a built-in.

◆ SymbolKind

enum class a11::flow::SymbolKind
strong

What a name means inside a flow.

Enumerator
kInputPort 

An in port: read, never written.

kOutputPort 

An out port: written, never read... except by this flow, which may read back what it wrote to one only when it is a node of its own.

See Symbol::readable.

kHeader 

A header, under its alias.

kCall 

A run/call step, bound to a name.

kNode 

A node of the flow's own, from node().

kNodeMap 

A node map, from nodes.

kBarrier 

A bound wait or drain: a barrier that also reads as its outcome.

kLoopVariable 

A for variable, or the index every loop binds.

kCarry 

What a repeat carries.

kValue 

One value, read from a stream and given a name by let.

Read as a value wherever an expression is accepted. It is never a write target.

◆ SyntaxTarget

enum class a11::flow::SyntaxTarget
strong

An editor definition the language can write for itself.

Enumerator
kSublime 

editors/sublime-text/A11 Flow.sublime-syntax: a Sublime/TextMate-family YAML grammar, which is also what Zed and a few others read.

kPygments 

editors/pygments/a11flow_lexer.py: a Pygments lexer, which is what colours a fenced flow in A11's own documentation and in anything else built on Pygments (MkDocs, Sphinx, pygmentize).

kVsCode 

editors/vscode/a11flow.tmLanguage.json: a TextMate grammar in the JSON dialect VSCode reads.

The fallback rather than the whole story, and generated for the same reason the others are. A VSCode extension with a language server gets its real colours from semantic tokens, which are the language's own judgement about every token; this is what colours a .flow before the server has answered, and what colours one with no server at all. So it is a grammar of words, strings and marks, and it does not try to be a parser.

kVsCodeInjection 

editors/vscode/a11flow-injection.tmLanguage.json: the same words, as an injection into the string literals of a host language.

Where most flows actually live. A separate file because VSCode injects by injectTo on a grammar of its own rather than by a rule inside another one, and because the two answer different questions: this one has to decide whether a string is a flow before colouring any of it.

◆ TokenKind

enum class a11::flow::TokenKind
strong

What kind of thing a token is.

The same set a11.flow.lexer produces, under the same names – [KindName] returns exactly the strings the Python lexer uses – with one addition: a comment is a token here. The Python lexer drops comments because a parser has no use for them; a highlighter and a formatter do, and one lexer that keeps them serves all three.

Enumerator
kNewline 

The end of a statement. One per run of blank lines, never leading.

kComment 

# to the end of the line.

kString 

A quoted string. string_value holds it with escapes resolved.

kNumber 

A number, integral or not. number holds it.

kDuration 

A number with a duration unit: 250ms. duration holds it.

kWord 

A bare word. What it means is the grammar's business, not the lexer's.

kDot 
kRange 

.. – the range between two bounds, either of which may be left out.

kSpread 

... or ... – everything the thing after it holds, spread in here.

kArrow 
kCarry 
kEqual 
kEqualEqual 
kBangEqual 
kLess 
kLessEqual 
kGreater 
kGreaterEqual 
kPlus 
kMinus 
kPipe 
kColon 
kComma 
kLeftBrace 
kRightBrace 
kLeftParen 
kRightParen 
kLeftBracket 
kRightBracket 
kBad 

A character the language has no meaning for.

Carried rather than thrown so the rest of the file is still read.

kEnd 

One past the last token, so lookahead never runs off the end.

Function Documentation

◆ ActionMarkdown()

std::string a11::flow::ActionMarkdown ( const catalogue::ActionInfo &  action)

An action, written out as the Markdown a reader wants to see: what it does, then every port it has.

Shared by hover and completion.

◆ Add()

absl::StatusOr< Value > a11::flow::Add ( const Value &  left,
const Value &  right 
)

left + right, as an expression means it.

For | sum, | avg and | fold, which add values the way + does: numbers as numbers, durations as durations, an instant and a duration as the shifted instant, and text as text.

◆ AsDouble()

double a11::flow::AsDouble ( const Value &  value)

AsNumber as a double, for the places that only want the magnitude.

◆ AsDuration()

absl::Duration a11::flow::AsDuration ( const Value &  value)

A duration from a duration, from written text, or from seconds.

◆ AsHole()

Value a11::flow::AsHole ( pattern::HoleType  type,
std::string_view  text 
)

One hole's text, read as the hole said to read it.

◆ AsJson()

Value a11::flow::AsJson ( const Value &  value)

Text parsed as JSON; anything already decoded is left alone.

◆ AsNumber()

Value a11::flow::AsNumber ( const Value &  value)

value as a number, or zero when there is nothing to read.

Integral where the value was integral, so d of a count is the count.

◆ AsText()

std::string a11::flow::AsText ( const Value &  value)

value as text, the way the text stage and builtin render it.

◆ AsTime()

absl::Time a11::flow::AsTime ( const Value &  value)

An instant from an instant, from RFC 3339 text, or from epoch seconds.

◆ BuiltinMarkdown()

std::string a11::flow::BuiltinMarkdown ( std::string_view  name)

A built-in function, the same way.

◆ CallBuiltin()

absl::StatusOr< Value > a11::flow::CallBuiltin ( std::string_view  name,
absl::Span< const Value >  arguments,
HostBridge *absl_nullable  bridge 
)

Call one of the language's fixed functions.

Public because the strformat stage is the one-value shorthand for the builtin and must not become a second implementation of it.

◆ CodesToJsonValue()

nlohmann::json a11::flow::CodesToJsonValue ( )

The published code table, as flow.codes/v1.

◆ Coerce()

absl::StatusOr< Value > a11::flow::Coerce ( const Value &  value,
const syntax::TypeExpression &  type,
const CoerceContext &  context 
)

Make value a value of the type type names.

A built-in name coerces the way the matching builtin does; a shape the program declared is validated against, field by field; a tag or a mimetype goes to the host, which is the only place that knows what has been registered.

◆ CoerceShape()

absl::StatusOr< Value > a11::flow::CoerceShape ( const DtoPlan &  shape,
const Value &  value,
const CoerceContext &  context 
)

Make value a value of shape: fill its defaults, check its bounds, and coerce every field to the type the shape gives it.

The one implementation of what a shape means. The resolver checks what it can before anything runs – a key the shape does not have, a constant of the wrong kind – and this checks the rest, when a value actually arrives. A failure names the field it was about, by path (parent.tags[2]), because a flow's data comes from somewhere else and "invalid" without a path is a message nobody can act on.

A key the shape does not have is dropped, not refused: extra data is how {...it, ..} is useful, and a producer that sends more than a reader declared has done nothing wrong. Writing such a key out by hand is a different thing and the resolver says so.

◆ CompleteAt()

CompleteResult a11::flow::CompleteAt ( std::string_view  source,
size_t  offset,
const catalogue::Catalogue &  known = catalogue::Catalogue::Builtin() 
)

What may be written at offset in source.

The one implementation of the judgement. After a | only a stage can follow; past a port's : only a type; after a -> only somewhere writable; after x. only what x actually has. Each of those is a fact about the grammar and the names in scope, and a frontend that worked it out for itself would be a second, worse copy of the language – which is what the plugin's Kotlin completion was.

It never fails and never throws. The document is being typed: the statement the caret is in is usually half-written and the braces are usually unbalanced. Parsing recovers, resolution recovers, and what cannot be established simply narrows the list – an unknown call target offers status and no ports rather than nothing at all.

A source that declares no flow is completed as though it were a flow body, which is what an injected fragment in a Python string is.

known is what the world outside the document contains – the actions that may be called and the types that may be named. It defaults to the snapshot embedded in the language, so a standalone tool offers make_http_request's ports without being configured; a frontend that has a live registry passes its own instead, which is the case an IDE tracking what an inline flow is attached to wants.

◆ CompletionsToJsonValue()

nlohmann::json a11::flow::CompletionsToJsonValue ( const CompleteResult &  result)

The flow.completions/v1 envelope: what may be written at an offset.

◆ ConstantToJsonValue()

nlohmann::json a11::flow::ConstantToJsonValue ( const syntax::Constant &  constant)

A constant as the syntax format writes it.

◆ ConstructRange()

Range a11::flow::ConstructRange ( const LineIndex &  lines,
absl::Span< const Token >  tokens,
const syntax::Location &  opened,
const Range &  selection 
)

◆ Describe()

Description a11::flow::Describe ( std::string_view  source,
size_t  offset,
const catalogue::Catalogue &  known 
)

What is at offset, and where it came from.

◆ DiagnosticFromJsonValue()

Diagnostic a11::flow::DiagnosticFromJsonValue ( const nlohmann::json &  value)

A diagnostic read back from its JSON, for frontends that consume the envelope rather than the library – the IntelliJ plugin, a CI script.

Unknown fields are ignored and missing ones take their defaults, so a newer producer never breaks an older reader.

◆ DiagnosticsToJson()

std::string a11::flow::DiagnosticsToJson ( std::string_view  source,
absl::Span< const Diagnostic >  diagnostics 
)

The envelope, serialised with a trailing newline and two-space indent.

◆ DiagnosticsToJsonValue()

nlohmann::json a11::flow::DiagnosticsToJsonValue ( std::string_view  source,
absl::Span< const Diagnostic >  diagnostics 
)

The full flow.diagnostics/v1 envelope.

source is whatever names the input – a path, - for standard input – and is echoed so a batch of these can be concatenated and still say what each was about. counts is there so a gate can be written without walking the list.

◆ DiagnosticsToSarif()

std::string a11::flow::DiagnosticsToSarif ( std::string_view  source,
absl::Span< const Diagnostic >  diagnostics 
)

The SARIF log, serialised with a trailing newline.

◆ DiagnosticsToSarifValue()

nlohmann::json a11::flow::DiagnosticsToSarifValue ( std::string_view  source,
absl::Span< const Diagnostic >  diagnostics 
)

A SARIF 2.1.0 log for one file's diagnostics.

SARIF is what code-scanning services and CI annotators already read, so emitting it means a flow's problems show up in a pull request without anybody writing a converter. The rule metadata comes from [KnownCodes], so every rule in the log is documented by construction.

◆ DiagnosticToJsonValue()

nlohmann::json a11::flow::DiagnosticToJsonValue ( const Diagnostic &  diagnostic)

One diagnostic, as it appears in the envelope.

◆ DiagnosticToText()

std::string a11::flow::DiagnosticToText ( std::string_view  source,
const Diagnostic &  diagnostic 
)

One diagnostic on one line, in the shape editors and compilers have used for decades: path:line:column: severity: message [code].

source may be empty, which drops the leading path:.

◆ DtoToFlow()

std::string a11::flow::DtoToFlow ( const DtoPlan &  dto)

One shape as the Flow text that declares it.

What makes an import useful: the answer is source, so it can be pasted into a file, read, edited and checked in. Written the way the formatter would write it, so a11 flow fmt over the result changes nothing.

◆ DtoToJsonSchema()

nlohmann::json a11::flow::DtoToJsonSchema ( const DtoPlan &  dto,
const Program &  program 
)

The JSON Schema a struct describes.

Why both directions exist. A shape is the same idea as a JSON Schema object, so a flow that declares one should be able to hand it to anything that speaks schemas – a model's tool definition, an OpenAPI document, a validator somewhere else – and should be able to accept one back. Neither direction is the "real" one: a shape is what the language reads and a schema is what the world outside it reads, and this is the translation.

Draft 2020-12, because that is the draft JSON Schema settled on and the one a model's structured-output mode expects. Every shape struct reaches, directly or through another, goes into $defs, and a field naming one is a $ref – so a shape that names itself round-trips, which a schema inlined by substitution could not.

The three types JSON has no word for. bytes, time and duration go out as strings, with the encoding or format that says how to read them and a x-a11-type beside it. The format alone is what another reader wants; the extension is what makes coming back lossless, since {"type": "string", "format": "date-time"} is also a perfectly good way to say string.

◆ DtoToJsonValue()

nlohmann::json a11::flow::DtoToJsonValue ( const DtoPlan &  dto,
const Program *absl_nullable  program = nullptr 
)

One resolved shape, as the structs of a plan writes it.

Exposed on its own because a shape travels without its program: it is what a JSONSchema is made from, what a tool is handed as a type description, and what an editor shows on hover.

With a program, the shapes this one names travel with it under nested, innermost last – a shape is not much use to a reader that has to build a type from it without the types its fields refer to. Self-reference is fine: a shape naming itself appears once, in struct.

◆ DurationSeconds()

double a11::flow::DurationSeconds ( absl::Duration  value)

A duration as a number of seconds, for every duration there is.

Infinite ones answer an infinity rather than failing: a timeout that never fires is a duration a flow can hold, and so is the negative one two instants subtracted the wrong way round give.

◆ DurationText()

std::string a11::flow::DurationText ( absl::Duration  value,
std::string_view  spec 
)

A duration as text: 1m30s by default, or one unit when spec names one.

◆ Evaluate()

absl::StatusOr< Value > a11::flow::Evaluate ( const syntax::Node &  node,
const EvalContext &  context 
)

Evaluate one expression.

Fails for unsupported operations such as an unknown type or adding two instants. Other invalid values use the language defaults: incompatible comparisons use text, a missing key is null, and an unreadable number is zero.

◆ FamilyFromName()

Family a11::flow::FamilyFromName ( std::string_view  name)

Family for a name from the output formats, or kSyntax if unknown.

◆ FamilyName()

std::string_view a11::flow::FamilyName ( Family  family)

The spelling of a family in the output formats.

◆ FindCode()

const CodeInfo *absl_nullable a11::flow::FindCode ( std::string_view  code)

The entry for a code, or nullptr if nothing publishes it.

◆ FirstError()

const Diagnostic *absl_nullable a11::flow::FirstError ( absl::Span< const Diagnostic >  diagnostics)

The first error in diagnostics, or nullptr if none is an error.

What every strict entry point turns into its one raised failure, so that "the first thing wrong with this file" means the same in each of them.

◆ FlowMarkdown()

std::string a11::flow::FlowMarkdown ( const FlowPlan &  flow)

A flow of the document, written out the same way: what it does, then its ports and which direction each runs.

◆ FlowSchema()

absl::StatusOr< actions::ActionSchema > a11::flow::FlowSchema ( const FlowPlan &  plan)

The [actions::ActionSchema] a flow presents.

A flow is an action: it has ports, headers and a name, so anything that can dispatch an action can dispatch a composition without being told it is one.

◆ Format()

FormatResult a11::flow::Format ( std::string_view  source,
FormatOptions  options = {} 
)

Format Flow source.

What it decides: indentation, the spaces between tokens, how far a continued line is indented, how many blank lines are allowed and where, the columns of a run of port declarations, trailing whitespace, and the newline at the end of the file.

What it leaves to the author: where the lines break. Whether a pipeline is written across four lines or one, whether a list literal is split a value per

line, and where the comments are, is a judgement about what the flow <em>means</em>

which values belong together, which stage is the interesting one – and a formatter that overruled it would make every flow in the repository worse. So a break the author wrote is kept and indented properly, and a break they did not write is not invented.

It refuses a file it cannot read. With an error diagnostic, formatted is the input and diagnostics says why: half-formatting a file somebody is in the middle of typing is how a formatter loses somebody's work.

Two invariants, both tested over every flow in the repository:

  • Idempotent. Formatting formatted text changes nothing.
  • Token-preserving. The formatted text lexes to the same tokens as the input, comments included – the only difference being trailing whitespace trimmed from inside a comment. Whitespace is all it may touch, and this is what says so rather than promising it.

◆ FormatToJsonValue()

nlohmann::json a11::flow::FormatToJsonValue ( const FormatResult &  result)

The flow.format/v1 envelope: the formatted text, and what it took.

◆ GenerateSyntax()

std::string a11::flow::GenerateSyntax ( SyntaxTarget  target)

The whole definition, generated.

Why generate it. A static grammar file is a copy of the language's word lists, and a copy is a thing that falls behind: then added as a stage is a stage the editor does not colour until somebody remembers this file. So the structure – which contexts there are, what pushes what – is written here once, and every list of words in it comes from vocabulary. A word added to the language reaches the editor by running the generator, and CI notices when nobody has.

The output ends with a newline and is byte-stable: the same vocabulary generates the same file, which is what makes --check a diff rather than a judgement.

◆ Handle()

nlohmann::json a11::flow::Handle ( const nlohmann::json &  request)

One question about one document, answered.

The whole of what a frontend needs from the language, behind one function: a method name, a document, and whatever that method takes. Every surface is an adapter over this – a11-flow serve --protocol json passes requests through almost unchanged, the LSP adapter translates positions and wraps the answers in what an editor expects, and a11.flow.request hands the same dict across the Python boundary – so a capability added here is available in all of them without any adapter knowing what it is.

A request is

{"id": 1, "method": "check", "source": "flow t { }", "path": "t.flow"}

and the answer is {"id": 1, "ok": true, "result": {...}} with the envelope the method produces, or {"id": 1, "ok": false, "error": {"message": "..."}} when the request itself made no sense. A flow that makes no sense is not an error; syntax problems are returned as diagnostics.

id is echoed if it is there and omitted if it is not, so a client that does not correlate need not invent one.

◆ Highlight()

std::vector< SemanticToken > a11::flow::Highlight ( absl::Span< const Token >  tokens)

Classify a token stream.

The rules are the ones the grammar itself uses, which is why this reads a stream rather than one token at a time: a word is only a stage directly after a |, only a function where it is called, only a type past a port's :, and whatever follows a . is a member however it is spelled. Two of them need a look ahead rather than behind – a bare then/where is a stage only with an operand after it, and node is the keyword only where its parentheses open – and having the whole stream is what makes those cheap and exact.

The tokens are expected to include comments (LexOptions::keep_comments), and the result is one entry per input token except the final end.

◆ Inspect()

std::vector< Diagnostic > a11::flow::Inspect ( std::string_view  source,
const ParseResult &  parsed,
const ResolveResult &  resolved 
)

Everything a flow does that it probably did not mean to.

Not errors: every one of these compiles and runs. They are the things a reader would point at – a try whose failure nothing looks at, a | drop 3 after a | collect that left one value to drop from, an out port nothing writes, a header declared under an alias nobody uses. Each is one of the published codes, so an editor can switch one off and a CI job can gate on some and not others.

The findings and the families are the ones the IntelliJ plugin's Kotlin analysis works out today; this is where they come from now, so there is one implementation of the judgement rather than one per editor.

Takes the resolved program because that is where the facts are: the resolver walked every reference and counted what read what, and re-deriving that here would be a second name resolver. The parse result is for the sequences, which are a property of the text rather than of the names.

◆ JsonSchemaToDtos()

SchemaImport a11::flow::JsonSchemaToDtos ( const nlohmann::json &  schema,
std::string_view  name 
)

The shapes schema describes, named name where it does not name itself.

The reverse of [DtoToJsonSchema], and lossless for what that writes. Anything else is a best effort: a keyword with no Flow spelling is reported and the field keeps the type it could be read as.

◆ JsonText()

std::string a11::flow::JsonText ( const Value &  value)

A value's own JSON text, as json.dumps(sort_keys=True) writes it.

The Python reference rendered a container with json.dumps, and a flow's output can be a rendered object, so the spelling is part of the contract: sorted keys, ", " and ": " between things, non-ASCII escaped.

◆ KindFromName()

TokenKind a11::flow::KindFromName ( std::string_view  name)

The kind a name from [KindName] refers to, or kBad if it is not one.

◆ KindName()

std::string_view a11::flow::KindName ( TokenKind  kind)

The name of a kind, as a11.flow.lexer spells it.

Punctuation is named by itself ("->", "{"), which is what makes a token dump comparable between the two implementations token for token.

◆ KnownCodes()

absl::Span< const CodeInfo > a11::flow::KnownCodes ( )

Every diagnostic code the language can produce, sorted by code.

◆ Lex()

LexResult a11::flow::Lex ( std::string_view  source,
LexOptions  options = {} 
)

Turn Flow source into tokens, ending with a single end token.

The rules are a11/flow/lexer.py's: # to the end of the line is a comment, a string cannot span a line, a number may carry a duration unit, and a dash continues a name only between word characters – which is what keeps -3 a number, starts-with one name, and a -> b a pipe. A line break is a token, because the grammar is one statement per line; a run of them is one token, and a leading one is none.

This never fails. The Python lexer raises on the first unterminated string or unknown character, because a program that cannot be read cannot run. An editor is looking at a file somebody is in the middle of typing, so a problem here becomes a diagnostic and lexing carries on: an unterminated string ends at its line, an unknown character is one kBad token, and the tokens after it are still there. Compile in parser.h is where a first error becomes a refusal.

◆ Lookup()

Value a11::flow::Lookup ( const Value &  value,
const Value &  key 
)

Take key out of value: a mapping key, an index, or a field.

Answers null when it is not there, because a flow reading a field a producer did not send should be able to say if not thing.field rather than fall over.

◆ MakeEntryHandler()

absl::StatusOr< actions::ActionHandler > a11::flow::MakeEntryHandler ( std::shared_ptr< const CompiledProgram >  program,
RunOptions  options = {} 
)

The action handler that runs the program's entry flow.

A separate function rather than MakeHandler(program, ""), because the entry flow is reached by being the entry flow and not by having an empty name – the same reason Program::Entry() exists. What an interpreter calls.

◆ MakeHandler()

absl::StatusOr< actions::ActionHandler > a11::flow::MakeHandler ( std::shared_ptr< const CompiledProgram >  program,
std::string_view  flow,
RunOptions  options = {} 
)

The action handler that runs one flow of program.

Registering this makes the composition an action like any other: a peer can dispatch it, another flow can call it, and a model can be offered it as a tool, without any of them knowing it is a composition.

◆ MatchCompiled()

Value a11::flow::MatchCompiled ( const pattern::Pattern &  pattern,
std::string_view  subject 
)

The same, against a pattern already compiled.

What a stage uses: the pattern is written once in the source and the stream may be ten thousand values, so compiling it per value would be paying for the same scan over and over.

◆ MatchPattern()

absl::StatusOr< Value > a11::flow::MatchPattern ( std::string_view  pattern,
std::string_view  subject 
)

The fields a pattern pulls out of subject, or null where it does not fit.

One implementation for both senses of match: the stage drops a value this answers null for, and the function hands the null on. A record when every hole is named, and a list when they are not – {} is read by position, so it[0] is what a positional pattern gives.

See [pattern::Compile] for the language. A pattern that does not compile is an invalid_argument naming what is wrong with it, because a pattern is a literal almost every time and a silent no-match would hide a typo in it.

◆ Methods()

absl::Span< const std::string_view > a11::flow::Methods ( )

Every method [Handle] knows, in the order --help lists them.

◆ MethodSummary()

std::string_view a11::flow::MethodSummary ( std::string_view  method)

What a method takes and gives back, one line, for --help.

◆ NativeHostBridge()

std::unique_ptr< HostBridge > a11::flow::NativeHostBridge ( )

A bridge over A11's own C++ serialisation registry.

What the standalone tool and the C++ tests run with. A tag the C++ registry does not know is an error in the same words the Python reference used, which reports the type as unavailable because its defining module is not loaded.

◆ NodeToJsonValue()

nlohmann::json a11::flow::NodeToJsonValue ( const syntax::Node &  node)

One syntax node, and everything under it.

The field names are the ones a11/flow/syntax.py gives them, so the tree the two implementations produce can be compared field for field while the Python one is still the reference. Every node carries kind and its location; the rest is what that kind holds. A duration is {"$duration": seconds} rather than a bare number, so a reader can tell one from a count, and the position lives under at rather than beside those fields, because a repeat has a start of its own.

◆ OffsetBasisFromName()

bool a11::flow::OffsetBasisFromName ( std::string_view  name,
OffsetBasis &  basis 
)

The basis a request named, or kBytes when it named none.

false when the name is not one of the two, so a client with a typo is told rather than quietly served the wrong arithmetic.

◆ OffsetBasisName()

std::string_view a11::flow::OffsetBasisName ( OffsetBasis  basis)

The name of a basis, for a message and for the JSON.

◆ operator==()

bool a11::flow::operator== ( const Value &  left,
const Value &  right 
)

◆ Order()

int a11::flow::Order ( const Value &  left,
const Value &  right 
)

Where two values sit relative to one another: -1, 0 or 1.

What < and > mean in an expression, and so what | sort means: two instants or two durations compare as themselves, a number as a number, and everything else as text, so nothing dies on "3" < 5.

◆ Parse()

ParseResult a11::flow::Parse ( std::string_view  source)

Parse Flow source.

The grammar is a11/flow/parser.py's, one for one: recursive descent, one token of lookahead, and no reserved words – a word means skip or for only where it opens a statement and is not immediately followed by something that makes it a name.

Never throws and always returns a tree. Problems become diagnostics, and recovery skips to the statement end or inserts a syntax::ErrorNode where a value was required. This supports partial input in formatters and editors.

◆ ParseDuration()

std::optional< absl::Duration > a11::flow::ParseDuration ( std::string_view  text)

A duration from the way the language writes one, or nullopt.

The source's spelling and the formatter's, both ways round: 30s, 250ms, 1m30s, forever, and a bare number of seconds. A duration a flow put on a port comes back as text often enough – through a header, a JSON field, a model's answer – that reading it back has to be as ordinary as writing it.

◆ ParseTime()

std::optional< absl::Time > a11::flow::ParseTime ( std::string_view  text)

An instant from RFC 3339 text, as TimeText writes it.

◆ ParseTokens()

ParseResult a11::flow::ParseTokens ( std::string_view  source,
absl::Span< const Token >  tokens,
std::vector< Diagnostic >  diagnostics 
)

Parse an already-lexed stream, sharing the lex diagnostics.

For a frontend that has the tokens in hand – a formatter, a highlighter that then wants a tree – so one file is lexed once. Comment tokens are stepped over here, which is what lets the same stream serve both.

◆ PlanToJson()

std::string a11::flow::PlanToJson ( std::string_view  source_name,
const Program &  program 
)

The envelope, serialised with a trailing newline and two-space indent.

◆ PlanToJsonValue()

nlohmann::json a11::flow::PlanToJsonValue ( std::string_view  source_name,
const Program &  program 
)

The flow.plan/v1 envelope: what each flow of a file resolved to.

The keys are a11.flow.plan's describe(), so the plan a reader diffs to see whether a change to a flow changed what it does reads the same whichever implementation produced it.

◆ PortMarkdown()

std::string a11::flow::PortMarkdown ( std::string_view  name,
std::string_view  type,
bool  required,
bool  unary,
std::string_view  description 
)

One port, written out as the Markdown a reader wants beside its name.

Used by hover and completion to show the same full port description.

◆ ProposalKindName()

std::string_view a11::flow::ProposalKindName ( ProposalKind  kind)

The name of a proposal kind in the output format, in kebab case.

◆ RebaseToUtf16()

void a11::flow::RebaseToUtf16 ( nlohmann::json &  answer,
const TextIndex &  index 
)

Rewrite every document offset in an answer from bytes into UTF-16 units.

The rule, and it is the whole rule: a numeric field named start, end, offset or prefix_start is a byte offset into the document, at any depth. That is true of every flow.* envelope by construction – those four names are not used for anything else in any of them – so this converts exactly the right set and needs no table of shapes to fall out of step with the emitters.

Two near matches are left unchanged. range.start and range.end are objects, and the offset inside each is the offset field this does convert. A proposal's caret counts into the text that proposal inserts, not into the document, so a document-basis conversion of it would be wrong.

◆ RefinePorts()

void a11::flow::RefinePorts ( std::string_view  source,
std::vector< SemanticToken > &  semantic 
)

Mark the identifiers that are ports of the flow they stand in.

The second pass, and it is a second pass because it is the only part of classification that needs name resolution: whether sources is a port or a node of the flow's own is not a fact about the token stream, and no amount of looking at neighbouring words will settle it. [Highlight] stays lexical – it is what an editor's lexer runs on every keystroke – and this is applied on top by the surfaces that publish meanings.

Only kIdentifier tokens are touched, so a member after a ., a string that happens to spell a port's name, and a keyword all stay as they were.

One flow's span, and the names its ports have.

◆ Resolve()

ResolveResult a11::flow::Resolve ( std::string_view  source,
const ParseResult &  parsed,
bool  build_graph = false 
)

Resolve a parsed program: names, ports, scopes, node maps and types.

What this is. The semantic pass: it decides what every name in a flow means, checks that a call's ports exist on the flow it names, that a type is a type, that a <- has a repeat to carry into, and produces the [Program] that a11 flow describe prints. Its errors are a11/flow/plan.py's, in the same words, so the two agree about what compiles.

With build_graph it also builds the executable graph for every flow – the refs, steps and bodies the runtime walks – beside the description. That is off by default because an editor, a11 flow check and CI want none of it, and a graph borrows the parse tree it was built from: whoever asks for one owns both for as long as a flow is registered.

Like the parser, it never throws and always returns: a flow with an unresolvable name in it is still resolved as far as it goes, because an editor wants every problem in the file rather than the first.

◆ SecondsDuration()

absl::Duration a11::flow::SecondsDuration ( double  total)

A duration of total seconds, negative ones included.

absl::Seconds is fine with a negative, but A11's own Duration.seconds reads one as infinite, and this is the language's spelling: a number beside a duration is a length, so -30 is thirty seconds the other way.

◆ SemanticKindFromName()

SemanticKind a11::flow::SemanticKindFromName ( std::string_view  name)

The kind a name refers to, or kIdentifier if it is not one.

◆ SemanticKindName()

std::string_view a11::flow::SemanticKindName ( SemanticKind  kind)

The name of a semantic kind in the output formats, in kebab case.

◆ SeverityFromName()

Severity a11::flow::SeverityFromName ( std::string_view  name)

Severity for a name from the output formats, or kError if unknown.

◆ SeverityName()

std::string_view a11::flow::SeverityName ( Severity  severity)

The spelling of a severity in the output formats.

◆ ShapeMarkdown()

std::string a11::flow::ShapeMarkdown ( const DtoPlan &  shape)

A struct, written out the same way: how many fields, then each of them.

◆ SortDiagnostics()

void a11::flow::SortDiagnostics ( std::vector< Diagnostic > &  diagnostics)

Sorts diagnostics into the order every frontend presents them in: by position, then by code, so two runs over the same file agree byte for byte.

◆ StageMarkdown()

std::string a11::flow::StageMarkdown ( std::string_view  name)

A pipeline stage, written out as reference.

Uses the stage role when a word also has a built-in function meaning.

◆ StatusCodeOf()

std::optional< absl::StatusCode > a11::flow::StatusCodeOf ( const Value &  value)

The canonical code value names, by name or by number, or nullopt.

Either case of a canonical name, and any number Abseil defines a code for, which is what lets a flow re-raise a status it was handed without knowing how it was spelled.

◆ StatusOfRecord()

absl::Status a11::flow::StatusOfRecord ( const Value &  record)

The status a record like the one above describes.

◆ StatusRecord()

Value a11::flow::StatusRecord ( const absl::Status &  status)

A status as the record a flow sees when it looks at an outcome.

{"ok": .., "code": "NOT_FOUND", "number": 5, "message": ..} – data, so a flow can branch on it, put it on an output, or raise it again, without any of the language knowing what a status is.

◆ Strformat()

std::string a11::flow::Strformat ( const Value &  format,
absl::Span< const Value >  arguments 
)

format with each % conversion replaced by one of arguments.

printf's syntax, because a format string is a thing people already know how to read, and because it is only a format string: no attribute access, no indexing, nothing a template can reach through. A flow's templates can come from a model, so that matters more here than the convenience of a richer template language would.

%(SPEC)s applies a spec to the value first – a duration unit, a strftime pattern, epoch – and a conversion with no value behind it is left as it was written, because a visible %3$s in the output is easier to diagnose than a flow that died formatting a log line.

◆ SymbolClassName()

std::string_view a11::flow::SymbolClassName ( SymbolClass  kind)

◆ SymbolKindName()

std::string_view a11::flow::SymbolKindName ( SymbolKind  kind)

The name of a symbol kind, for a message and for the JSON.

◆ Symbols()

std::vector< DocumentSymbol > a11::flow::Symbols ( std::string_view  source)

Every symbol a document declares, nested as it is written.

Top-level flows and shapes contain their ports, fields, and local bindings.

◆ SyntaxTargetFromName()

bool a11::flow::SyntaxTargetFromName ( std::string_view  name,
SyntaxTarget &  target 
)

A target from its name, or nullopt.

◆ SyntaxTargetName()

std::string_view a11::flow::SyntaxTargetName ( SyntaxTarget  target)

The name a target is asked for by: sublime.

◆ SyntaxTargetPath()

std::string_view a11::flow::SyntaxTargetPath ( SyntaxTarget  target)

Where the generated file belongs, relative to the repository root.

◆ SyntaxTargets()

absl::Span< const SyntaxTarget > a11::flow::SyntaxTargets ( )

Every target, for a command that offers a choice of them.

◆ SyntaxToJson()

std::string a11::flow::SyntaxToJson ( std::string_view  source,
const ParseResult &  result 
)

The envelope, serialised with a trailing newline and two-space indent.

◆ SyntaxToJsonValue()

nlohmann::json a11::flow::SyntaxToJsonValue ( std::string_view  source,
const ParseResult &  result 
)

The full flow.syntax/v1 envelope: the flows a file declares, and what is wrong with it.

Both, always: a tree with a mistake in it is still a tree, and preserving the partial tree produced by the recovering parser.

◆ TimeText()

std::string a11::flow::TimeText ( absl::Time  value,
std::string_view  spec 
)

An instant as text: RFC 3339 in UTC, a strftime pattern, or epoch.

◆ TokensToJson()

std::string a11::flow::TokensToJson ( std::string_view  source_name,
std::string_view  source 
)

The envelope, serialised with a trailing newline and two-space indent.

◆ TokensToJsonValue()

nlohmann::json a11::flow::TokensToJsonValue ( std::string_view  source_name,
std::string_view  source 
)

The flow.tokens/v1 envelope: every token, and what it means where it is.

Lexes and classifies in one pass, so the two halves of a token – what it is (word, ->) and what it means (stage, type) – cannot disagree about its extent. A client colouring a document needs the second; one driving a lexer of its own – an IDE that insists on tokenising every character – needs the first, and the offsets tile the source so the gaps between them are whitespace by construction.

◆ Truncate()

Value a11::flow::Truncate ( const Value &  value,
std::int64_t  size 
)

The first size of a value: characters, bytes, elements or pairs.

◆ Truthy()

bool a11::flow::Truthy ( const Value &  value)

Whether value counts as true, as an if and a where decide it.

◆ VocabularyToJsonValue()

nlohmann::json a11::flow::VocabularyToJsonValue ( )

Every word set the language gives meaning to, as flow.vocabulary/v1.

What anything generating a static grammar file reads instead of keeping a list of its own, and what a11 flow syntax holds an editor definition to. One producer, so the table the Python API sees and the table the standalone tool prints cannot differ.

◆ Widened()

Range a11::flow::Widened ( const LineIndex &  lines,
const Range &  range,
const Range &  selection 
)

The whole construct a declaration opens: its first token through the } that closes its block.

Why this is worked out here. The parser records where a node started – the token it began at, which is what flow.syntax/v1 documents at as – and that is the wrong extent for a symbol. A flow's name is the token after the keyword, so a range of the keyword alone does not contain the name, and a document symbol whose selection is outside its range is a protocol violation: LSP refuses the whole answer with "selectionRange must be contained in fullRange", so one bad entry cost the document its entire outline.

It is also what the format promises: range is the whole construct, so "select symbol" takes the block. range, widened to hold selection.

The invariant every document symbol has to satisfy, applied where a construct has no block to match braces around: a port, a field, a bound step. Their range and selection are usually the same token, and this is what makes "usually" into "always".

◆ WordMarkdown()

std::string a11::flow::WordMarkdown ( std::string_view  name,
vocabulary::WordRole  role 
)

One word or mark of the language, written out as reference: what it does, what it takes, how it behaves, and a line of Flow using it.

Empty where nothing documents the name. role says which position the name was read in, since a word can mean two things; where that role's table has no entry the other tables are asked, because a word set may list a word that a neighbouring set documents (vocabulary::AnyDocumentation).

The name may be written in either case, as the language allows: TRUNCATE is documented and shown as written.

Variable Documentation

◆ kCodesFormat

constexpr std::string_view a11::flow::kCodesFormat = "flow.codes/v1"
inlineconstexpr

◆ kCompletionsFormat

constexpr std::string_view a11::flow::kCompletionsFormat = "flow.completions/v1"
inlineconstexpr

The format field of the completions envelope.

◆ kDefinitionFormat

constexpr std::string_view a11::flow::kDefinitionFormat = "flow.definition/v1"
inlineconstexpr

The format field of the definition envelope.

◆ kDiagnosticsFormat

constexpr std::string_view a11::flow::kDiagnosticsFormat = "flow.diagnostics/v1"
inlineconstexpr

The format field of each envelope: what a reader checks before parsing.

A version is bumped when a field changes meaning or disappears. Adding a field is not a version change, so a consumer must ignore fields it does not know – which is the contract these strings stand for.

◆ kFlowOrderKey

constexpr std::string_view a11::flow::kFlowOrderKey = "x-a11-order"
inlineconstexpr

The extension key holding a shape's fields in declaration order.

A JSON object's keys have no order a reader may rely on, and a shape's fields have one – it is what a reader of the source sees and what [DtoToFlow] writes back. Without this the round trip would quietly alphabetise every shape it touched.

◆ kFlowTypeKey

constexpr std::string_view a11::flow::kFlowTypeKey = "x-a11-type"
inlineconstexpr

The extension key that says which Flow type a string really is.

◆ kFormatFormat

constexpr std::string_view a11::flow::kFormatFormat = "flow.format/v1"
inlineconstexpr

◆ kHoverFormat

constexpr std::string_view a11::flow::kHoverFormat = "flow.hover/v1"
inlineconstexpr

The format field of the hover envelope.

◆ kPlanFormat

constexpr std::string_view a11::flow::kPlanFormat = "flow.plan/v1"
inlineconstexpr

The format field of the plan envelope.

◆ kQueueDepth

constexpr size_t a11::flow::kQueueDepth = 8
inlineconstexpr

How many values a pipe may run ahead of its reader.

Small on purpose: A11's own stores are the buffer, and a flow should not become a second one.

◆ kSchemaFormat

constexpr std::string_view a11::flow::kSchemaFormat = "flow.schema/v1"
inlineconstexpr

The format field of the schema envelope.

◆ kSymbolsFormat

constexpr std::string_view a11::flow::kSymbolsFormat = "flow.symbols/v1"
inlineconstexpr

The format field of the symbols envelope.

◆ kSyntaxFormat

constexpr std::string_view a11::flow::kSyntaxFormat = "flow.syntax/v1"
inlineconstexpr

◆ kTokensFormat

constexpr std::string_view a11::flow::kTokensFormat = "flow.tokens/v1"
inlineconstexpr

◆ kVocabularyFormat

constexpr std::string_view a11::flow::kVocabularyFormat = "flow.vocabulary/v1"
inlineconstexpr