grammar InkBlotAntlrGrammar; import InkBlotAntlrLexer; /* * STORY */ story: topLevelStatements ; /* * STATEMENTS FOR THE VARIOUS LEVELS */ topLevelStatements: topLevelStatement+ ; topLevelStatement: multiDivert | contentText ; knotLevelStatements: (contentText | multiDivert )+ ; stitchLevelStatements: (contentText | multiDivert )+ ; innerBlockLevelStatements: (contentText | multiDivert )+ ; /* * STATEMENTS */ contentText: CONTENT_TEXT_NO_ESCAPE_SIMPLE ; mixedTextAndLogic: // TODO: ~ is not allowed as first symbol of this (see InkParser_Content => MixedTextAndLog), let's implement it in the C# side? // like in innerInlineSequenceObjects, a bit of a chaos to avoid having completely empty entries contentText? (inlineLogicOrGlueOrTagStart? contentText | inlineLogicOrGlueOrTagStart contentText?)+ // TODO: this is valid only when not parsing a choice, see above for the code where this logic is implemented multiDivert // TODO: management of tag ftw O_O ; inlineLogicOrGlueOrTagStart: inlineLogic // TODO: glue, tag start ; inlineLogic: INLINE_LOGIC_START WS? innerLogic // TODO: += and -= are disabled here (don't know why, maybe because they're statements?) WS? INLINE_LOGIC_END // TODO: tags ftw ; innerLogic: WS? sequenceTypeAnnotation innerSequenceObjects // TODO: the rest of InkParser_Logic => InnerLogic ; multiDivert: WS? multiDivert_withoutWS ; multiDivert_withoutWS: THREAD_ARROW divertIdentifierWithArguments # MultiDivertThread // here be dragons: trying to express the various "Possible patterns" of InkParser_Divert => MultiDivert // syntax in the original ink parser is overly concessive: https://discord.com/channels/329929050866843648/329929390358265857/1342130940981284945 | (DIVERT_ARROW divertIdentifierWithArguments)* multiDivertArrows_tail # MultiDivertArrows // TODO: a single DIVERT_ARROW above is only valid in default choices ( https://github.com/inkle/ink/blob/master/Documentation/WritingWithInk.md#fallback-choices ) // TODO: tags ftw ; multiDivertArrows_tail: DIVERT_ARROW # MultiDivertArrows_tailDefaultChoice | DIVERT_ARROW divertIdentifierWithArguments # MultiDivertArrows_tailDivert | TUNNEL_ARROW divertIdentifierWithArguments # MultiDivertArrows_tailTunnelWithReplacement | TUNNEL_ARROW # MultiDivertArrows_tailTunnel ; divertIdentifierWithArguments: WS? divertIdentifierWithArguments_name WS? ( '(' expression (',' WS? expression)* ')' )? WS? ; divertIdentifierWithArguments_name: WS? identifier WS? ('.' WS? identifier WS? )* ; divertIdentifierWithArguments_arguments: '(' expression (',' WS? expression)* ')' ; identifier: // TODO: reject numbers-only identifier - see InkParser_Logic => Identifier IDENTIFIER ; expression: // TODO: temporary stuff here IDENTIFIER ; // all possible symbols or word(s) for sequencing sequenceTypeAnnotation: op=SEQUENCE_TYPE_SYMBOL_ANNOTATION | ONCE | CYCLE | SHUFFLE | STOPPING | SHUFFLE_ONCE | SHUFFLE_STOPPING ; /* a list of sequence objects, either compressed in a single line (e.g.: {a|b|c}) or expanded in multiple lines (e.g.: {\n- a\n- b\n- c} */ innerSequenceObjects: NL innerMultilineSequenceObjects | innerInlineSequenceObjects ; innerMultilineSequenceObjects: singleMultilineSequenceElement+ ; singleMultilineSequenceElement: WS? /* TODO: how to express this? and why is it here? InkParser_Sequences => SingleMultilineSequenceElement if (ParseString ("->") != null) return null; */ '-' WS? ( innerBlockLevelStatements | MULTILINE_WS ) ; innerInlineSequenceObjects: // it's a bit chaotic, in order to allow for empty mixedTextAndLogic, but always require at least one entry (mixedTextAndLogic ('|' mixedTextAndLogic?)*) | ('|' mixedTextAndLogic?)+ ;