|
|
|
@ -6,14 +6,14 @@ import { |
|
|
|
|
MarkdownOutput, |
|
|
|
|
MeteredResource, |
|
|
|
|
NumberSign, |
|
|
|
|
Operands, |
|
|
|
|
Operands, OperandsFrom, |
|
|
|
|
ParseContext, |
|
|
|
|
Resource, |
|
|
|
|
Resource, Source, Target, |
|
|
|
|
UnmeteredResource, |
|
|
|
|
} from "../model/Messages"; |
|
|
|
|
import {IterationNode, Node, NonterminalNode, TerminalNode} from "ohm-js"; |
|
|
|
|
import {Iter, IterationNode, Node, NonterminalNode, TerminalNode} from "ohm-js"; |
|
|
|
|
import {CharacterPrivacy, CharacterSide} from "../model/Character"; |
|
|
|
|
import {ClockMode} from "../model/GameState"; |
|
|
|
|
import {ClockMode, TimerDirection} from "../model/GameState"; |
|
|
|
|
|
|
|
|
|
export const parser = grammar.createSemantics() |
|
|
|
|
|
|
|
|
@ -24,25 +24,28 @@ export interface ParserNode extends Node { |
|
|
|
|
numberValue: number |
|
|
|
|
identifier: string |
|
|
|
|
resource: Resource|null |
|
|
|
|
|
|
|
|
|
// TODO: Implement all of the things listed below.
|
|
|
|
|
operands: Operands |
|
|
|
|
blockTargets: Operands |
|
|
|
|
blockSources: Operands |
|
|
|
|
currentValue: number|null |
|
|
|
|
maxValue: number|null |
|
|
|
|
textValue: string |
|
|
|
|
silenced: boolean |
|
|
|
|
currentValue: number |
|
|
|
|
maxValue: number |
|
|
|
|
|
|
|
|
|
// TODO: Implement all of the things listed below.
|
|
|
|
|
textValue: string |
|
|
|
|
failReason: unknown // TODO: create an enum for this
|
|
|
|
|
// TODO: create rules for these to describe clocks/timers/items/statuses/characters and implement them
|
|
|
|
|
nameText: string |
|
|
|
|
descriptionText: string |
|
|
|
|
// TODO: use for portraits, status icons, backdrops, BGM, and SFX
|
|
|
|
|
url: string |
|
|
|
|
side: CharacterSide |
|
|
|
|
privacy: CharacterPrivacy |
|
|
|
|
clockMode: ClockMode |
|
|
|
|
timerDirection: unknown // TODO: create an enum for this
|
|
|
|
|
timerDirection: TimerDirection |
|
|
|
|
timerDurationMs: number |
|
|
|
|
|
|
|
|
|
// TODO: add backdrop and music change and sfx commands
|
|
|
|
|
// TODO: make sure that FP and UP spent gets saved in the appropriate counters
|
|
|
|
|
evaluate(ctx: ParseContext): ParseContext |
|
|
|
|
renderMarkdown(ctx: MarkdownContext): MarkdownOutput |
|
|
|
@ -98,7 +101,7 @@ parser.addAttribute<ElementalType|null>("element", { |
|
|
|
|
DeltaOperationAlternate2(operands: NonterminalNode, colon: NonterminalNode, resource: NonterminalNode, delta: NonterminalNode, affinity: IterationNode, elementalType: IterationNode): ElementalType | null { |
|
|
|
|
return (elementalType as ParserNode).element |
|
|
|
|
}, |
|
|
|
|
_iter(...children: Node[]): ElementalType|null { |
|
|
|
|
_iter(...children: readonly Node[]): ElementalType|null { |
|
|
|
|
if (this.isOptional() && children.length === 0) { |
|
|
|
|
return null |
|
|
|
|
} else if (this.isOptional() && children.length === 1) { |
|
|
|
@ -143,7 +146,7 @@ parser.addAttribute<Affinity>("affinity", { |
|
|
|
|
DeltaOperationAlternate2(operands: NonterminalNode, colon: NonterminalNode, resource: NonterminalNode, delta: NonterminalNode, affinity: IterationNode, elementalType: IterationNode): Affinity { |
|
|
|
|
return (affinity as ParserNode).affinity |
|
|
|
|
}, |
|
|
|
|
_iter(...children: Node[]): Affinity { |
|
|
|
|
_iter(...children: readonly Node[]): Affinity { |
|
|
|
|
if (this.isOptional() && children.length === 0) { |
|
|
|
|
return Affinity.Normal |
|
|
|
|
} else if (this.isOptional() && children.length === 1) { |
|
|
|
@ -455,7 +458,7 @@ parser.addAttribute<Resource|null>("resource", { |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
_iter(...children: Node[]): Resource|null { |
|
|
|
|
_iter(...children: readonly Node[]): Resource|null { |
|
|
|
|
if (this.isOptional() && children.length === 0) { |
|
|
|
|
return null |
|
|
|
|
} else if (this.isOptional() && children.length === 1) { |
|
|
|
@ -464,6 +467,12 @@ parser.addAttribute<Resource|null>("resource", { |
|
|
|
|
throw Error(`No idea what to say ${this.ctorName} iteration node's resource is when there are multiple children`) |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
_nonterminal(): never { |
|
|
|
|
throw Error(`No idea what to say ${this.ctorName} nonterminal node's resource value is`) |
|
|
|
|
}, |
|
|
|
|
_terminal(): never { |
|
|
|
|
throw Error(`No idea what to say ${this.ctorName} terminal node's resource value is`) |
|
|
|
|
}, |
|
|
|
|
SetMeteredOperation(operands: NonterminalNode, space: NonterminalNode, resource: NonterminalNode, colon: NonterminalNode, value: NonterminalNode): MeteredResource { |
|
|
|
|
const r = (resource as ParserNode).resource; |
|
|
|
|
switch (r) { |
|
|
|
@ -533,4 +542,244 @@ parser.addAttribute<Resource|null>("resource", { |
|
|
|
|
} |
|
|
|
|
return r |
|
|
|
|
}, |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
parser.addAttribute<Operands>("operands", { |
|
|
|
|
CompleteOperation(silence: IterationNode, operation: NonterminalNode, terminator: NonterminalNode): Operands { |
|
|
|
|
return (operation as ParserNode).operands |
|
|
|
|
}, |
|
|
|
|
Operation(operation: NonterminalNode): Operands { |
|
|
|
|
return (operation as ParserNode).operands |
|
|
|
|
}, |
|
|
|
|
ClearOperation(operands: NonterminalNode, space: NonterminalNode, resource: NonterminalNode, colon: NonterminalNode, nul: NonterminalNode): Operands { |
|
|
|
|
return (operands as ParserNode).operands |
|
|
|
|
}, |
|
|
|
|
ClearOperationAlternate(operands: NonterminalNode, colon: NonterminalNode, nul: NonterminalNode, resource: NonterminalNode): Operands { |
|
|
|
|
return (operands as ParserNode).operands |
|
|
|
|
}, |
|
|
|
|
ClearOperationAlternate2(operands: NonterminalNode, colon: NonterminalNode, resource: NonterminalNode, nul: NonterminalNode): Operands { |
|
|
|
|
return (operands as ParserNode).operands; |
|
|
|
|
}, |
|
|
|
|
DeltaOperation(operands: NonterminalNode, space: NonterminalNode, resource: NonterminalNode, colon: NonterminalNode, delta: NonterminalNode, affinity: IterationNode, element: IterationNode): Operands { |
|
|
|
|
return (operands as ParserNode).operands; |
|
|
|
|
}, |
|
|
|
|
DeltaOperationAlternate(operands: NonterminalNode, colon: NonterminalNode, delta: NonterminalNode, affinity: IterationNode, resource: IterationNode, element: IterationNode): Operands { |
|
|
|
|
return (operands as ParserNode).operands; |
|
|
|
|
}, |
|
|
|
|
DeltaOperationAlternate2(operands: NonterminalNode, colon: NonterminalNode, resource: NonterminalNode, delta: NonterminalNode, affinity: IterationNode, element: IterationNode): Operands { |
|
|
|
|
return (operands as ParserNode).operands; |
|
|
|
|
}, |
|
|
|
|
FailOperation(operands: NonterminalNode, colon: NonterminalNode, fail: NonterminalNode): Operands { |
|
|
|
|
return (operands as ParserNode).operands; |
|
|
|
|
}, |
|
|
|
|
PrintOperation(): Set<never> { |
|
|
|
|
return Operands<never>() |
|
|
|
|
}, |
|
|
|
|
SetMaxOperation(operands: NonterminalNode, space: NonterminalNode, resource: NonterminalNode, colon: NonterminalNode, max: NonterminalNode): Operands { |
|
|
|
|
return (operands as ParserNode).operands |
|
|
|
|
}, |
|
|
|
|
SetMaxOperationAlternate(operands: NonterminalNode, colon: NonterminalNode, max: NonterminalNode, resource: NonterminalNode): Operands { |
|
|
|
|
return (operands as ParserNode).operands |
|
|
|
|
}, |
|
|
|
|
SetMaxOperationAlternate2(operands: NonterminalNode, colon: NonterminalNode, resource: NonterminalNode, max: NonterminalNode): Operands { |
|
|
|
|
return (operands as ParserNode).operands |
|
|
|
|
}, |
|
|
|
|
SetMeteredOperation(operands: NonterminalNode, space: NonterminalNode, resource: NonterminalNode, colon: NonterminalNode, meter: NonterminalNode): Operands { |
|
|
|
|
return (operands as ParserNode).operands |
|
|
|
|
}, |
|
|
|
|
SetMeteredOperationAlternate(operands: NonterminalNode, colon: NonterminalNode, meter: NonterminalNode, resource: NonterminalNode): Operands { |
|
|
|
|
return (operands as ParserNode).operands |
|
|
|
|
}, |
|
|
|
|
SetMeteredOperationAlternate2(operands: NonterminalNode, colon: NonterminalNode, resource: NonterminalNode, meter: NonterminalNode): Operands { |
|
|
|
|
return (operands as ParserNode).operands |
|
|
|
|
}, |
|
|
|
|
SetSourceOperation(source: NonterminalNode, operands: NonterminalNode): Operands { |
|
|
|
|
return (operands as ParserNode).operands |
|
|
|
|
}, |
|
|
|
|
SetTargetOperation(target: NonterminalNode, operands: NonterminalNode): Operands { |
|
|
|
|
return (operands as ParserNode).operands |
|
|
|
|
}, |
|
|
|
|
SetValueOperation(operands: NonterminalNode, space: NonterminalNode, resource: NonterminalNode, colon: NonterminalNode, value: NonterminalNode): Operands { |
|
|
|
|
return (operands as ParserNode).operands |
|
|
|
|
}, |
|
|
|
|
SetValueOperationAlternate(operands: NonterminalNode, colon: NonterminalNode, value: NonterminalNode, resource: NonterminalNode): Operands { |
|
|
|
|
return (operands as ParserNode).operands |
|
|
|
|
}, |
|
|
|
|
SetValueOperationAlternate2(operands: NonterminalNode, colon: NonterminalNode, resource: NonterminalNode, value: NonterminalNode): Operands { |
|
|
|
|
return (operands as ParserNode).operands |
|
|
|
|
}, |
|
|
|
|
StatusOrItemCounterDeltaOperation(operands: NonterminalNode, colon: NonterminalNode, statusOrItem: NonterminalNode, delta: NonterminalNode): Operands { |
|
|
|
|
return (operands as ParserNode).operands |
|
|
|
|
}, |
|
|
|
|
StatusOrItemCounterSetOperation(operands: NonterminalNode, colon: NonterminalNode, statusOrItem: NonterminalNode, value: NonterminalNode): Operands { |
|
|
|
|
return (operands as ParserNode).operands |
|
|
|
|
}, |
|
|
|
|
StatusOrItemDeltaOperation(operands: NonterminalNode, colon: NonterminalNode, delta: NonterminalNode, statusOrItem: NonterminalNode, counter: IterationNode): Operands { |
|
|
|
|
return (operands as ParserNode).operands |
|
|
|
|
}, |
|
|
|
|
Operands(arg0: NonterminalNode): Operands { |
|
|
|
|
return (arg0.asIteration() as ParserNode).operands |
|
|
|
|
}, |
|
|
|
|
_iter(...children: readonly Node[]): Operands { |
|
|
|
|
return OperandsFrom(children.map((child) => (child as ParserNode).operands)) |
|
|
|
|
}, |
|
|
|
|
operand(oper: NonterminalNode): Operands { |
|
|
|
|
return (oper as ParserNode).operands |
|
|
|
|
}, |
|
|
|
|
identifier(): Set<string> { |
|
|
|
|
return Operands((this as ParserNode).identifier) |
|
|
|
|
}, |
|
|
|
|
target(): Set<typeof Target> { |
|
|
|
|
return Operands(Target) |
|
|
|
|
}, |
|
|
|
|
source(): Set<typeof Source> { |
|
|
|
|
return Operands(Source); |
|
|
|
|
}, |
|
|
|
|
["null"](): Set<never> { |
|
|
|
|
return Operands() |
|
|
|
|
}, |
|
|
|
|
_nonterminal(): never { |
|
|
|
|
throw Error(`No idea what to say ${this.ctorName} nonterminal node's operands value is`) |
|
|
|
|
}, |
|
|
|
|
_terminal(): never { |
|
|
|
|
throw Error(`No idea what to say ${this.ctorName} terminal node's operands value is`) |
|
|
|
|
}, |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
parser.addAttribute<Operands>("blockTargets", { |
|
|
|
|
Block(start: NonterminalNode, terminator: NonterminalNode, code: NonterminalNode, end: NonterminalNode, terminator2: NonterminalNode): Operands { |
|
|
|
|
return (start as ParserNode).blockTargets |
|
|
|
|
}, |
|
|
|
|
BlockStart(silenced: IterationNode, begin: NonterminalNode, source: IterationNode, target: IterationNode, colon: NonterminalNode, text: NonterminalNode): Operands { |
|
|
|
|
return (target as ParserNode).operands |
|
|
|
|
}, |
|
|
|
|
_iter(): Operands { |
|
|
|
|
throw Error(`No idea what to say ${this.ctorName} iteration node's block targets value is`) |
|
|
|
|
}, |
|
|
|
|
_nonterminal(): never { |
|
|
|
|
throw Error(`No idea what to say ${this.ctorName} nonterminal node's block targets value is`) |
|
|
|
|
}, |
|
|
|
|
_terminal(): never { |
|
|
|
|
throw Error(`No idea what to say ${this.ctorName} terminal node's block targets value is`) |
|
|
|
|
}, |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
parser.addAttribute<Operands>("blockSources", { |
|
|
|
|
Block(start: NonterminalNode, terminator: NonterminalNode, code: NonterminalNode, end: NonterminalNode, terminator2: NonterminalNode): Operands { |
|
|
|
|
return (start as ParserNode).blockSources |
|
|
|
|
}, |
|
|
|
|
BlockStart(silenced: IterationNode, begin: NonterminalNode, source: IterationNode, target: IterationNode, colon: NonterminalNode, text: NonterminalNode): Operands { |
|
|
|
|
return (source as ParserNode).operands |
|
|
|
|
}, |
|
|
|
|
_iter(): Operands { |
|
|
|
|
throw Error(`No idea what to say ${this.ctorName} iteration node's block sources value is`) |
|
|
|
|
}, |
|
|
|
|
_nonterminal(): never { |
|
|
|
|
throw Error(`No idea what to say ${this.ctorName} nonterminal node's block sources value is`) |
|
|
|
|
}, |
|
|
|
|
_terminal(): never { |
|
|
|
|
throw Error(`No idea what to say ${this.ctorName} terminal node's block sources value is`) |
|
|
|
|
}, |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
parser.addAttribute<boolean>("silenced", { |
|
|
|
|
Block(start: NonterminalNode, terminator: NonterminalNode, code: NonterminalNode, end: NonterminalNode, terminator2: NonterminalNode): boolean { |
|
|
|
|
return (start as ParserNode).silenced |
|
|
|
|
}, |
|
|
|
|
BlockStart(silenced: IterationNode, begin: NonterminalNode, source: IterationNode, target: IterationNode, colon: NonterminalNode, text: NonterminalNode): boolean { |
|
|
|
|
return (target as ParserNode).silenced |
|
|
|
|
}, |
|
|
|
|
CompleteOperation(silenced: IterationNode, operation: NonterminalNode, terminator: NonterminalNode): boolean { |
|
|
|
|
return (silenced as ParserNode).silenced |
|
|
|
|
}, |
|
|
|
|
silentOperator(): boolean { |
|
|
|
|
return true |
|
|
|
|
}, |
|
|
|
|
_iter(): boolean { |
|
|
|
|
if (this.isOptional() && this.children.length === 0) { |
|
|
|
|
return false |
|
|
|
|
} else if (this.isOptional() && this.children.length === 1) { |
|
|
|
|
return (this.children[0] as ParserNode).silenced |
|
|
|
|
} else { |
|
|
|
|
throw Error(`No idea what to say ${this.ctorName} iteration node's element is when there are multiple children`) |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
_nonterminal(): never { |
|
|
|
|
throw Error(`No idea what to say ${this.ctorName} nonterminal node's silenced status is`) |
|
|
|
|
}, |
|
|
|
|
_terminal(): never { |
|
|
|
|
throw Error(`No idea what to say ${this.ctorName} terminal node's silenced status is`) |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
parser.addAttribute<number>("currentValue", { |
|
|
|
|
SetValueOperation(operands: NonterminalNode, space: NonterminalNode, resource: NonterminalNode, colon: NonterminalNode, integer: NonterminalNode): number { |
|
|
|
|
return (integer as ParserNode).numberValue; |
|
|
|
|
}, |
|
|
|
|
SetValueOperationAlternate(operands: NonterminalNode, colon: NonterminalNode, integer: NonterminalNode, resource: NonterminalNode): number { |
|
|
|
|
return (integer as ParserNode).numberValue; |
|
|
|
|
}, |
|
|
|
|
SetValueOperationAlternate2(operands: NonterminalNode, colon: NonterminalNode, resource: NonterminalNode, integer: NonterminalNode): number { |
|
|
|
|
return (integer as ParserNode).numberValue; |
|
|
|
|
}, |
|
|
|
|
MeteredValue(current: NonterminalNode, max: NonterminalNode): number { |
|
|
|
|
return (current as ParserNode).numberValue |
|
|
|
|
}, |
|
|
|
|
SetMeteredOperation(operands: NonterminalNode, space: NonterminalNode, resource: NonterminalNode, colon: NonterminalNode, value: NonterminalNode): number { |
|
|
|
|
return (value as ParserNode).currentValue; |
|
|
|
|
}, |
|
|
|
|
SetMeteredOperationAlternate(operands: NonterminalNode, colon: NonterminalNode, value: NonterminalNode, resource: NonterminalNode): number { |
|
|
|
|
return (value as ParserNode).currentValue; |
|
|
|
|
}, |
|
|
|
|
SetMeteredOperationAlternate2(operands: NonterminalNode, colon: NonterminalNode, resource: NonterminalNode, value: NonterminalNode): number { |
|
|
|
|
return (value as ParserNode).currentValue; |
|
|
|
|
}, |
|
|
|
|
StatusOrItemDeltaOperation(operands: NonterminalNode, colon: NonterminalNode, deltaOperator: NonterminalNode, identifier: NonterminalNode, counter: NonterminalNode): number { |
|
|
|
|
return (counter as ParserNode).numberValue |
|
|
|
|
}, |
|
|
|
|
StatusOrItemCounterSetOperation(operands: NonterminalNode, colon: NonterminalNode, identifier: NonterminalNode, counter: NonterminalNode): number { |
|
|
|
|
return (counter as ParserNode).numberValue |
|
|
|
|
}, |
|
|
|
|
_iter(): never { |
|
|
|
|
throw Error(`No idea what to say ${this.ctorName} iteration node's current value is`) |
|
|
|
|
}, |
|
|
|
|
_nonterminal(): never { |
|
|
|
|
throw Error(`No idea what to say ${this.ctorName} nonterminal node's current value is`) |
|
|
|
|
}, |
|
|
|
|
_terminal(): never { |
|
|
|
|
throw Error(`No idea what to say ${this.ctorName} terminal node's current value is`) |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
parser.addAttribute<number>("maxValue", { |
|
|
|
|
SetMaxOperation(operands: NonterminalNode, space: NonterminalNode, resource: NonterminalNode, colon: NonterminalNode, maxvalue: NonterminalNode): number { |
|
|
|
|
return (maxvalue as ParserNode).numberValue; |
|
|
|
|
}, |
|
|
|
|
SetMaxOperationAlternate(operands: NonterminalNode, colon: NonterminalNode, maxvalue: NonterminalNode, resource: NonterminalNode): number { |
|
|
|
|
return (maxvalue as ParserNode).numberValue; |
|
|
|
|
}, |
|
|
|
|
SetMaxOperationAlternate2(operands: NonterminalNode, colon: NonterminalNode, resource: NonterminalNode, maxvalue: NonterminalNode): number { |
|
|
|
|
return (maxvalue as ParserNode).numberValue; |
|
|
|
|
}, |
|
|
|
|
MeteredValue(current: NonterminalNode, max: NonterminalNode): number { |
|
|
|
|
return (max as ParserNode).numberValue |
|
|
|
|
}, |
|
|
|
|
SetMeteredOperation(operands: NonterminalNode, space: NonterminalNode, resource: NonterminalNode, colon: NonterminalNode, value: NonterminalNode): number { |
|
|
|
|
return (value as ParserNode).maxValue; |
|
|
|
|
}, |
|
|
|
|
SetMeteredOperationAlternate(operands: NonterminalNode, colon: NonterminalNode, value: NonterminalNode, resource: NonterminalNode): number { |
|
|
|
|
return (value as ParserNode).maxValue; |
|
|
|
|
}, |
|
|
|
|
SetMeteredOperationAlternate2(operands: NonterminalNode, colon: NonterminalNode, resource: NonterminalNode, value: NonterminalNode): number { |
|
|
|
|
return (value as ParserNode).maxValue; |
|
|
|
|
}, |
|
|
|
|
_iter(): never { |
|
|
|
|
throw Error(`No idea what to say ${this.ctorName} iteration node's max value is`) |
|
|
|
|
}, |
|
|
|
|
_nonterminal(): never { |
|
|
|
|
throw Error(`No idea what to say ${this.ctorName} nonterminal node's max value is`) |
|
|
|
|
}, |
|
|
|
|
_terminal(): never { |
|
|
|
|
throw Error(`No idea what to say ${this.ctorName} terminal node's max value is`) |
|
|
|
|
} |
|
|
|
|
}) |