@@ -4,18 +4,18 @@ FlowScript {
44 Line = BlankLine | RelationshipExpression | Element
55
66 Element = Modifier* Content
7- Content = State | Insight | Question | Completion | Alternative | Block | Statement
7+ Content = State | Insight | Question | Completion | Alternative | fixpointExpression | Block | Statement
88
99 BlankLine = space* "\n"
10- Statement = ~Modifier (~("\n" | "{" | "}") any)+ "\n"?
10+ Statement = ~Modifier ~"@fix" (~("\n" | "{" | "}") any)+ "\n"?
1111
1212 // Blocks (thought blocks / atomic processing units)
1313 Block = "{" ws BlockContent? ws "}"
1414 BlockContent = BlockLine (separator? BlockLine)* separator?
1515 BlockLine = ws (ContinuationRel | RelationshipExpression | BlockElement)
1616 BlockElement = Modifier* BlockContent_inner
17- BlockContent_inner = State | Insight | Question | Completion | Alternative | Block | BlockStatement
18- BlockStatement = ~Modifier (~("\n" | "{" | "}" | ";") any)+
17+ BlockContent_inner = State | Insight | Question | Completion | Alternative | fixpointExpression | Block | BlockStatement
18+ BlockStatement = ~Modifier ~"@fix" (~("\n" | "{" | "}" | ";") any)+
1919 separator = (space | "\n" | ";")+
2020 ws = (space | "\n")*
2121
@@ -127,6 +127,107 @@ FlowScript {
127127
128128 identifier = letter (letter | digit | "_" | "-")*
129129
130+ // =========================================================================
131+ // Fixpoint Expressions (@fix operator)
132+ // All @fix rules are LEXICAL (lowercase) for explicit whitespace control.
133+ // Syntactic rules auto-insert spaces which conflicts with @fix's
134+ // multi-line block structure. Lexical rules give full control.
135+ // =========================================================================
136+
137+ // @fix name? { clauses }
138+ fixpointExpression = fixpointExpression_named | fixpointExpression_anon
139+ fixpointExpression_named = "@fix" space+ fixName ws "{" ws fixpointClauses ws "}"
140+ fixpointExpression_anon = "@fix" ws "{" ws fixpointClauses ws "}"
141+
142+ fixName = letter (letter | digit | "_")*
143+
144+ fixpointClauses = fixpointClause (ws fixpointClause)*
145+ fixpointClause = fixMatchClause | fixYieldClause | fixUntilClause | fixConstraintClause
146+
147+ fixMatchClause = "match" ws ":" ws fixMatchBody
148+ fixYieldClause = "yield" ws ":" ws fixYieldBody
149+ fixUntilClause = "until" ws ":" ws fixTerminationCondition
150+ fixConstraintClause = "constraint" ws ":" ws constraintLevel
151+
152+ constraintLevel = "L2" | "L1"
153+
154+ // --- Match patterns ---
155+ fixMatchBody = fixMatchBody_braced | fixMatchBody_query
156+ fixMatchBody_braced = "{" ws fixPatternList ws "}"
157+ fixMatchBody_query = fixQueryRef
158+ fixPatternList = fixPatternElement (ws "," ws fixPatternElement)*
159+ fixPatternElement = fixNegationPattern | fixPathPattern | fixNodePattern
160+
161+ // Path pattern: A: node -> trusts -> B: node
162+ fixPathPattern = fixNodePattern (ws "->" ws fixEdgeLabel ws "->" ws fixNodePattern)+
163+ fixEdgeLabel = letter (letter | digit | "_")*
164+
165+ // Node pattern: A: node or A: thought(predicate1, predicate2)
166+ fixNodePattern = fixVariable ws ":" ws fixNodeType fixMatchCondition?
167+ fixMatchCondition = "(" ws fixPredicateList ws ")"
168+ fixPredicateList = fixPredicate (ws "," ws fixPredicate)*
169+ fixPredicate = fixPredicateName "(" ws fixArgList? ws ")"
170+ fixPredicateName = letter (letter | digit | "_")*
171+
172+ // Negation: not node_pattern | not query_ref
173+ fixNegationPattern = fixNegationPattern_node | fixNegationPattern_query
174+ fixNegationPattern_node = "not" space+ fixNodePattern
175+ fixNegationPattern_query = "not" space+ fixQueryRef
176+
177+ // Query references: tensions(), blocked(), etc.
178+ fixQueryRef = fixQueryName "(" ws fixArgList? ws ")"
179+ fixQueryName = "tensions" | "blocked" | "alternatives" | "why" | "what_if"
180+ fixArgList = fixArg (ws "," ws fixArg)*
181+ fixArg = fixVariable | string
182+
183+ // --- Yield productions ---
184+ fixYieldBody = fixYieldBody_braced | fixYieldBody_nested | fixYieldBody_builtin
185+ fixYieldBody_braced = "{" ws fixYieldList ws "}"
186+ fixYieldBody_nested = fixpointExpression
187+ fixYieldBody_builtin = fixBuiltinAction
188+ fixYieldList = fixYieldElement (ws "," ws fixYieldElement)*
189+ fixYieldElement = fixNodeRelProduction | fixNodeProduction | fixBuiltinAction | fixRelProduction | fixStateProduction | fixpointExpression
190+
191+ // new hypothesis(X) -> resolves -> X | source: abductive (combined create + connect)
192+ fixNodeRelProduction = "new" space+ fixNodeKind "(" ws fixArgList? ws ")" ws "->" ws fixEdgeLabel ws "->" ws fixVariable fixAnnotation*
193+
194+ // new hypothesis(X) | source: abductive (create only)
195+ fixNodeProduction = "new" space+ fixNodeKind "(" ws fixArgList? ws ")" fixAnnotation*
196+ fixNodeKind = letter (letter | digit | "_")*
197+
198+ // A -> believes -> P | confidence: derived
199+ fixRelProduction = fixVariable ws "->" ws fixEdgeLabel ws "->" ws fixVariable fixAnnotation*
200+
201+ // resolve(X) | annotate(X)
202+ fixStateProduction = fixStateAction "(" ws fixVariable ws ")" fixAnnotation*
203+ fixStateAction = "resolve" | "annotate"
204+
205+ // resolve(matched) — builtin action on query results
206+ fixBuiltinAction = "resolve" "(" ws "matched" ws ")" fixAnnotation*
207+
208+ // Annotations: | key: value
209+ fixAnnotation = ws "|" ws fixAnnotationKey ws ":" ws fixAnnotationValue
210+ fixAnnotationKey = letter (letter | digit | "_")*
211+ fixAnnotationValue = string | fixInteger | fixAnnotationIdent
212+ fixAnnotationIdent = letter (letter | digit | "_")*
213+
214+ // --- Termination conditions ---
215+ fixTerminationCondition = fixSimpleTermCondition (ws "or" ws fixSimpleTermCondition)*
216+ fixSimpleTermCondition = fixIterationBound | fixTimeoutBound | fixMeasureBound | fixStableCondition
217+ fixStableCondition = "stable"
218+ fixIterationBound = "max_iterations" ws ":" ws fixInteger
219+ fixTimeoutBound = "timeout" ws ":" ws fixInteger fixTimeUnit
220+ fixTimeUnit = "ms" | "s" | "m"
221+ fixMeasureBound = "measure" ws ":" ws fixMeasureName
222+ fixMeasureName = letter (letter | digit | "_")*
223+
224+ // Fixpoint lexical primitives
225+ fixVariable = upper (letter | digit | "_")*
226+ fixInteger = digit+
227+ fixNodeType = "fixpoint" | "thought" | "question" | "decision" | "blocker" | "action"
228+ | "statement" | "insight" | "completion" | "alternative"
229+ | "exploring" | "parking" | "block" | "node"
230+
130231 // Lexical rules (whitespace handling)
131232 space := " " | "\t" | "\r"
132233}
0 commit comments