import { AgencyComment, AgencyMultiLineComment, AgencyNode, AgencyProgram, Assignment, Comprehension, DebuggerStatement, Hole, InterruptStatement, Literal, NewLine, ObjectTypeTrivia, ParallelBlock, Scope, SeqBlock, TypeAlias, VariableType } from "../types.js"; import { AccessChainElement, ValueAccess } from "../types/access.js"; import { CodeLiteral } from "../types/codeLiteral.js"; import { BlockArgument } from "../types/blockArgument.js"; import { AgencyArray, AgencyObject, Trivia } from "../types/dataStructures.js"; import { FunctionCall, FunctionDefinition } from "../types/function.js"; import { GraphNodeDefinition } from "../types/graphNode.js"; import { IfElse } from "../types/ifElse.js"; import { ImportNameType, ImportNodeStatement, ImportStatement } from "../types/importStatement.js"; import { ExportFromStatement } from "../types/exportFromStatement.js"; import { EffectDeclaration } from "../types/effectDeclaration.js"; import { MatchBlock } from "../types/matchBlock.js"; import { ReturnStatement } from "../types/returnStatement.js"; import { GotoStatement } from "../types/gotoStatement.js"; import { ForLoop } from "../types/forLoop.js"; import { WhileLoop } from "../types/whileLoop.js"; import { AgencyConfig } from "../config.js"; import { MessageThread } from "../types/messageThread.js"; import { Skill } from "../types/skill.js"; import { BinOpArgument, BinOpExpression, Operator } from "../types/binop.js"; import { Keyword } from "../types/keyword.js"; import { HandleBlock } from "../types/handleBlock.js"; import { FinalizeBlock } from "../types/finalizeBlock.js"; import { GuardBlock } from "../types/guardBlock.js"; import { Tag } from "../types/tag.js"; import { NewExpression } from "../types/newExpression.js"; import { BindingPattern, MatchPattern } from "../types/pattern.js"; export declare function escapeStringText(s: string, delim: '"' | "'" | "`"): string; export declare class AgencyGenerator { protected graphNodes: GraphNodeDefinition[]; protected generatedStatements: string[]; protected generatedTypeAliases: string[]; protected typeAliases: Record; protected functionsUsed: Set; protected importNodes: ImportStatement[]; protected importedNodes: ImportNodeStatement[]; /** Comments / blank lines at the very top of the file that must stay * above the (sorted) imports block — e.g. file-level `// @tc-nocheck`, * shebangs, module docstrings. Populated by `partitionImports()`. */ protected importHeaderNodes: AgencyNode[]; /** Comments attached to each import statement (no blank line between * them and the import). Travel with the import when imports get * sorted, so `// @tc-ignore` above an import keeps suppressing it. */ protected importAttachedComments: Map; protected functionDefinitions: Record; protected currentScope: Scope[]; protected program: AgencyProgram | null; protected agencyConfig: AgencyConfig; private indentLevel; private indentSize; private debug; /** * When true, imports render in-place (in their original source position) * rather than being hoisted to the top of the file and sorted. Used by * `agency literate weave`, which needs to render the file in source * order so the prose / code alternation matches what the author wrote. */ protected preserveOrder: boolean; constructor(args?: { config?: AgencyConfig; preserveOrder?: boolean; }); protected trace(methodName: string, result: string): string; configDefaults(): Partial; generate(program: AgencyProgram): { output: string; }; /** * Split the node stream into three pieces: * * 1. `importHeaderNodes` — contiguous comments/blank lines at the * very top of the file (before any code or any import-attached * comment). These render unchanged above the sorted imports block. * 2. Imports + comments attached to each one — tracked in * `importAttachedComments`. A comment is "attached" iff it sits * directly above its import with no blank line between them. This * keeps `// @tc-ignore` above an import even when the import is * moved by sorting. * 3. Everything else — returned as the new node stream for the * remaining passes to process normally. * * Imports themselves are kept in `program.nodes` (returned here) so the * existing collection pass for `importNodes` / `importedNodes` still * sees them. The render path skips them because `processNode` for an * import returns "". */ private partitionImports; /** * Render the top-of-file header (comments + blank lines that sit above * the imports block). Returns an empty string when there are none. */ private renderImportHeader; addIfNonEmpty(str: string, lines: string[]): void; protected preprocessAST(): void; protected generateBuiltins(): string; protected generateImports(): string; protected preprocess(): string; protected postprocess(): string; protected collectFunctionSignature(node: FunctionDefinition): void; protected processGraphNodeName(node: GraphNodeDefinition): void; processNode(node: AgencyNode): string; private processNodeInner; protected formatHole(node: Hole): string; protected processInterruptStatement(node: InterruptStatement): string; protected needsParensLeft(child: BinOpArgument, parentOp: Operator): boolean; protected needsParensRight(child: BinOpArgument, parentOp: Operator): boolean; protected startScope(scope: Scope): void; protected endScope(): void; protected getCurrentScope(): Scope; protected isAgencyFunction(functionName: string, context: "valueAccess" | "functionArg" | "topLevelStatement"): boolean; private indent; private increaseIndent; private decreaseIndent; private indentStr; private wrapList; private renderParams; private stringifyProp; protected emitTriviaAt(trivia: (ObjectTypeTrivia | Trivia)[] | undefined, anchorIndex: number, lines: string[]): void; protected aliasedTypeToString(aliasedType: VariableType): string; protected processEffectDeclaration(node: EffectDeclaration): string; protected processTypeAlias(node: TypeAlias): string; /** * Format the `` chunk of a generic alias declaration. * Returns an empty string when there are no type params. */ private formatTypeParams; /** * Format the `(low: number, high: number = 10)` chunk of a * value-parameterized alias declaration. Returns an empty string when * there are no value params. */ private formatValueParams; protected processAssignment(node: Assignment): string; /** * Format a pattern AST node back into Agency pattern syntax. Used by the * formatter (it sees the un-lowered AST). Handles binding patterns and * match patterns; for match patterns, literal sub-nodes are formatted via * the existing literal/expression code paths. */ protected formatPattern(pattern: BindingPattern | MatchPattern): string; /** * The right side of the `is` operator. A test-only type pattern prints as * the bare type here, because the operator is already on the page — * `x is string`, not `x is _: string`. */ private formatIsRhs; /** * An arm's left side. Type patterns print differently here than after the * `is` operator: the test-only form needs the `is` keyword written out * (`is string =>`), and since `is Type` and `_: Type` parse to the same * node, `_: Type` intentionally normalizes to `is Type`. */ private formatArmCaseValue; private formatObjectPattern; private formatArrayPattern; protected generateLiteral(literal: Literal): string; private generateStringLiteral; /** * Render a docstring body for re-emission under the formatter's * current indent level. Strips the common leading indentation * ("dedent") rather than every line's leading whitespace, so inner * structure — ```code fences```, indented bullet sub-items, sample * snippets — survives a round-trip. The caller wraps the returned * lines in `"""` ... `"""` and re-indents. */ private formatDocStringLines; private generateMultiLineStringLiteral; protected effectSetTypeToString(type: VariableType): string; protected formatRaisesClause(raises: VariableType | undefined): string; /** Build the signature line(s) for a `def`/`node` — the given `prefix`, * wrapped params, return type, and `raises` clause — with `opener` * appended (`" {"` for a full definition, `""` for a signature-only * render). The params wrap onto their own lines via `wrapList` when they * don't fit. */ private buildSignature; /** The signature of a `def`/`node`/`type` with no export keyword, no * markers, no docs, and no body — used by `agency doc` and by * `std::agency`'s `describe`. For defs/nodes this is * `name(params): ReturnType raises <...>` (params wrap the way the * formatter wraps source); for type aliases it is the declaration line * `type Name<...> = ...`, produced here rather than by printing the * node and stripping keywords, so all three kinds share one canonical * signature path. */ signatureOf(node: FunctionDefinition | GraphNodeDefinition | TypeAlias): string; protected processFunctionDefinition(node: FunctionDefinition): string; protected processFunctionCall(node: FunctionCall): string; protected renderArgs(args: FunctionCall["arguments"], block?: BlockArgument): string[]; protected renderArgList(args: FunctionCall["arguments"], block?: BlockArgument): string; protected generateFunctionCallExpression(node: FunctionCall, context: "valueAccess" | "functionArg" | "topLevelStatement"): string; protected processAgencyArray(node: AgencyArray): string; protected processAgencyObject(node: AgencyObject): string; private addQuotesToKey; protected processValueAccess(node: ValueAccess): string; /** Print `[| ... |]`. An expr-kind body that fits one line prints * inline; everything else prints multi-line with the body one indent * level deeper and `|]` aligned with the statement. The body text is * the SHARED canonical print (printCodeLiteralBody), so what fmt * shows and what codegen embeds are the same text — and yes, fmt * REFORMATS bodies deliberately: a literal body is held to the same * standard a template file is. */ protected processCodeLiteral(node: CodeLiteral): string; protected asyncAwaitPrefix(code: string, async?: boolean): string; protected processMatchBlock(node: MatchBlock): string; protected processForLoop(node: ForLoop): string; protected processWhileLoop(node: WhileLoop): string; protected processIfElse(node: IfElse): string; protected processReturnStatement(node: ReturnStatement): string; /** Print an `if ... then ... else` expression (an `ifElse` in value position) * as its single-line surface form so it round-trips through the parser. */ protected formatIfExpression(node: IfElse): string; protected processGotoStatement(node: GotoStatement): string; protected processDebuggerStatement(node: DebuggerStatement): string; protected processComment(node: AgencyComment): string; protected processMultiLineComment(node: AgencyMultiLineComment): string; protected formatDocComment(node: { docComment?: AgencyMultiLineComment; }): string; protected processImportStatement(node: ImportStatement): string; protected processImportNameType(node: ImportNameType): string; /** Render an imported/re-exported name with its `destructive` or * `idempotent` prefix. A name carries at most one marker. */ private prefixMarkedName; protected processImportNodeStatement(node: ImportNodeStatement): string; protected processExportFromStatement(node: ExportFromStatement): string; private sortAndRenderImports; protected processGraphNode(node: GraphNodeDefinition): string; protected processNewExpression(node: NewExpression): string; protected processTool(node: FunctionDefinition): string; protected processNewLine(_node: NewLine): string; protected renderBody(body: AgencyNode[]): string; protected processMessageThread(node: MessageThread): string; protected processParallelBlock(node: ParallelBlock): string; protected processSeqBlock(node: SeqBlock): string; protected processHandleBlock(node: HandleBlock): string; /** Canonical form: no parens, and the binder prints through the same * param renderer blocks use. A stray `as` with no binder (the shared * grammar's no-param form) canonicalizes away — printing IS the * migration, like guard's legacy `as`. */ protected processFinalizeBlock(node: FinalizeBlock): string; /** Canonical form: the head prints through the same argument * renderer function calls use (source order for free), parens * always present, never a legacy `as` — printing old syntax through * the generator IS the `as`-removal migration. */ protected processGuardBlock(node: GuardBlock): string; protected processComprehension(node: Comprehension): string; protected processSkill(node: Skill): string; protected processBinOpExpression(node: BinOpExpression, assigned?: boolean): string; private flattenPipeChain; protected processAccessChainElement(node: AccessChainElement): string; protected formatTag(tag: Tag): string; protected formatAttachedTags(node: { tags?: Tag[]; }): string; protected processKeyword(node: Keyword): string; } /** The canonical printed body of a code literal, WITHOUT the brackets. * Shared by the formatter (which wraps it in `[| |]`) and codegen * (which embeds it for runtime reconstruction), so what fmt shows and * what the generated program reconstructs are the same text. */ export declare function printCodeLiteralBody(node: CodeLiteral): string; export declare function generateAgency(program: AgencyProgram, opts?: { preserveOrder?: boolean; }): string; /** * Formatter-exact source rendering of a single expression — the same * renderer interpolations use, so string quotes and escapes are preserved. * NOT `expressionToString` (lib/utils/node.ts), which drops string quotes. */ export declare function generateExpression(expr: AgencyNode): string;