snale wants to see
This commit is contained in:
parent
ac15bde327
commit
1405bc0495
135
Syntax.fs
135
Syntax.fs
@ -1,46 +1,145 @@
|
||||
/// AST definition for VijiN declarative markup.
|
||||
///
|
||||
/// VijiN scene files are inspired by stage play manuscripts.
|
||||
/// Most of a scene is "spoken" text, written as a speaker name followed by a colon.
|
||||
/// Directives in square brackets indicate how the content should be presented,
|
||||
/// rather than defining the content itself.
|
||||
///
|
||||
/// The syntax includes some formatting indicators.
|
||||
/// Text between forward slashes is emphasized, with the expectation that it
|
||||
/// will be rendered in italics.
|
||||
/// Double asterisks indicate yelled text, to be rendered in bold or large font.
|
||||
/// Underscores mark whispered text.
|
||||
///
|
||||
/// Almost all syntactic constraints can be escaped by quoting text in backticks.
|
||||
/// The exception is that backtick-quoted text cannot contain backticks or newlines.
|
||||
module VijiN.Syntax
|
||||
|
||||
/// Name of a variable to expand.
|
||||
///
|
||||
/// A variable name may contain any text that doesn't have other syntactic meaning,
|
||||
/// including whitespace. It may be quoted in backticks.
|
||||
type Variable = Variable of string
|
||||
|
||||
/// A single term of text, as an element of a spoken line, directive argument,
|
||||
/// character name, &c.
|
||||
type Term = TextTerm of string | VarTerm of Variable
|
||||
|
||||
type Character = Character of Term
|
||||
// TODO: Character should probably have more, like selecting portrait outfit/style
|
||||
|
||||
type DirectivePrefix = string
|
||||
type DirectiveInfix = string
|
||||
type DirectiveOperator = DirectivePrefix * DirectiveInfix
|
||||
type DirectiveSuffix = string
|
||||
/// Fixed, syntactic components of a directive. May be interspersed with arguments.
|
||||
/// Directives in a directive line may be separated with either dots or commas;
|
||||
/// in the former case, the variant is DirectiveOperator, and in the latter
|
||||
/// case, the variant is ContinueDirective with the implication that the prefix
|
||||
/// is the same as that of the previous operator in the block.
|
||||
type DirectiveOperator =
|
||||
| DirectiveOperator of DirectivePrefix * DirectiveInfix option * DirectiveSuffix option
|
||||
| ContinueDirective of DirectiveInfix option * DirectiveSuffix option
|
||||
|
||||
/// A single argument to a directive.
|
||||
type DirectiveArg = Arg of Term list
|
||||
type Directive = DirectiveOperator * DirectiveArg list list // TODO: non-empty list
|
||||
type Directives = Directive list // TODO: non-empty list
|
||||
|
||||
type ChoiceText = ChoiceText of Term list
|
||||
type ChoiceValue = ChoiceValue of Term list
|
||||
type ChoiceOption = ChoiceText * ChoiceValue option
|
||||
type Choice = Variable * ChoiceOption list // TODO: non-empty list
|
||||
type DirectivePrefixArg = DirectiveArg
|
||||
type DirectiveInfixArg = DirectiveArg
|
||||
type DirectiveSuffixArg = DirectiveArg
|
||||
type DirectiveListArg = DirectiveArg
|
||||
/// A directive instance, the composition of an operator with any arguments.
|
||||
/// An argument may be absent even if a later argument is provided.
|
||||
type Directive = DirectiveOperator * DirectivePrefixArg * DirectiveInfixArg * DirectiveSuffixArg
|
||||
/// A directive block. Either a single directive with a possibly empty list of
|
||||
/// arguments, or a list of directives
|
||||
type DirectiveBlock =
|
||||
| SingleDirective of Directive * DirectiveListArg list
|
||||
| DirectiveList of Directive list
|
||||
|
||||
/// The speaker of a spoken line.
|
||||
/// The narrator is syntactically indicated by an empty name, i.e. a line
|
||||
/// beginning with a colon. Narrated lines may also be given as lines spoken
|
||||
/// by "Narrator" when there is no defined character named the same, but that
|
||||
/// is resolved semantically rather than syntactically.
|
||||
type Speaker =
|
||||
| Narrator
|
||||
| Speaker of Term list
|
||||
/// An inline directive appearing between a speaker name and their line.
|
||||
type InlineDirective = Directive
|
||||
/// The text of a spoken line.
|
||||
type SpokenText =
|
||||
/// Plain spoken or narrated text.
|
||||
| Plain of Term list
|
||||
/// Emphasized text written between slashes. Intended to be rendered in italics.
|
||||
| Emphasis of Term list
|
||||
/// Yelled text written between double asterisks. Intended to be rendered
|
||||
/// in bold or large text.
|
||||
| Yell of Term list
|
||||
/// Whispered text written between underscores. Intended to be rendered
|
||||
/// in small text.
|
||||
| Whisper of Term list
|
||||
type Spoken = Character option * InlineDirective list * SpokenText list // TODO: non-empty list
|
||||
/// A spoken line. The character is absent for narrated lines.
|
||||
type Spoken = Speaker * InlineDirective list * SpokenText list // TODO: non-empty list
|
||||
|
||||
/// A comment. Text between both square and round brackets, without nesting.
|
||||
type Comment = Comment of string
|
||||
|
||||
/// A line of script.
|
||||
type Line =
|
||||
| SpokenLine of Spoken
|
||||
| DirectiveLine of Directives
|
||||
| DirectiveLine of DirectiveBlock
|
||||
| CommentLine of Comment
|
||||
| ChoiceLine of Choice
|
||||
|
||||
type LineNumber = LineNo of int // TODO: >= 1
|
||||
type PageNumber = PageNo of int // TODO: >= 1
|
||||
type LineNumber = LineNo of int
|
||||
type PageNumber = PageNo of int
|
||||
/// A complete line of script along with metadata.
|
||||
type ScriptLine = LineNumber * PageNumber * Line
|
||||
// TODO: other diffing metadata
|
||||
|
||||
type SceneName = SceneName of string
|
||||
/// An entire parsed scene.
|
||||
type Scene = ScriptLine list
|
||||
|
||||
type Scene = SceneName * Character list * ScriptLine list
|
||||
|
||||
module private Parse =
|
||||
open FParsec
|
||||
|
||||
type UserState = {
|
||||
/// The list of all available parsers.
|
||||
/// Never changes within a parsing unit.
|
||||
directiveParsers: seq<Parser<DirectivePrefix, UserState> * Parser<DirectiveInfix option, UserState> * Parser<DirectiveSuffix option, UserState>>
|
||||
}
|
||||
type Parser<'t> = Parser<'t, UserState>
|
||||
|
||||
let ws = unicodeSpaces
|
||||
|
||||
/// Unquoted terms may contain most characters, including whitespace, but
|
||||
/// not those characters used elsewhere in the syntax: square brackets,
|
||||
/// curly brackets, stops, commas, or colons.
|
||||
let unquotedTerm: Parser<_> = noneOf "[]{}.,:`" |> manyChars
|
||||
|
||||
/// Quoted terms can be used to escape from syntactic requirements almost
|
||||
/// anywhere, including inside variable names, character names, directive
|
||||
/// arguments, &c.
|
||||
///
|
||||
/// A quoted term is expressed as arbitrary text between backticks (`).
|
||||
/// They cannot themselves contain backticks or newlines.
|
||||
let quotedTerm: Parser<_> = noneOf "`\n" |> manyChars |> between (pchar '`') (pchar '`')
|
||||
|
||||
/// Text is the concatenation of quoted and unquoted terms.
|
||||
let text: Parser<_> = quotedTerm <|> unquotedTerm |> manyStrings
|
||||
|
||||
/// A variable use is text between curly brackets.
|
||||
let variable: Parser<_> = text |> between (pchar '{') (pchar '}') |>> Variable
|
||||
|
||||
/// A term is either a variable or text, possibly quoted.
|
||||
let term: Parser<_> = (variable |>> VarTerm) <|> (text |>> TextTerm)
|
||||
|
||||
/// A dot-ended directive contains a fixed-prefix directive instance and
|
||||
/// zero or more continued directives separated by commas.
|
||||
let dotDirective prefix infix suffix: Parser<Directive> =
|
||||
// TODO: continued directives
|
||||
pipe4
|
||||
(prefix .>> ws)
|
||||
(((preturn [] .>>. infix) <|> (many term .>>. infix)) .>> ws)
|
||||
(((preturn [] .>>. suffix) <|> (many term .>>. suffix)) .>> ws)
|
||||
(many term .>> ws .>> skipChar '.' .>> ws)
|
||||
(fun pfx (parg, ifx) (iarg, sfx) sarg -> (DirectiveOperator (pfx, ifx, sfx), Arg parg, Arg iarg, Arg sarg))
|
||||
|
||||
/// Parse the speaker of a spoken line, through the colon.
|
||||
let speaker = ws >>. ((skipChar ':' >>% Narrator) <|> (many1 term |>> Speaker .>> ws .>> skipChar ':')) <?> "speaker"
|
||||
|
@ -7,4 +7,7 @@
|
||||
<Compile Include="Syntax.fs" />
|
||||
<Compile Include="Program.fs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FParsec" Version="2.0.0-beta2" />
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
Reference in New Issue
Block a user