Skip to content

Commit

Permalink
Convert Text to just be LiteralString
Browse files Browse the repository at this point in the history
  • Loading branch information
joethephish committed Mar 25, 2016
1 parent 2bb5ce3 commit 4973a9a
Show file tree
Hide file tree
Showing 10 changed files with 78 additions and 113 deletions.
68 changes: 31 additions & 37 deletions Documentation/ink_JSON_runtime_format.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,40 @@ Examples:
* `["$test", {"subContainer": [5, 6, null], "#f": 3}]`

A container with the text object "test", flags 1 and 2, and a nested container named "subContainer" that resembles the first example.

## Text

The main text content within the story flow is represented by a JSON string, with a leading `$` to distinguish it from many other object types which are represented with special string names. The only exception is a newline, which can be simply written as `"\n"`.
## Literals

Examples:
*(TODO: Consider renaming to "Values"?)*

Literals are the main content objects. The most useful is the string literal, which is used for all the main text within the story flow.

String literals are represented in JSON by preceded the text in quotes by a leading `^` to distinguish it from many other object types which have special names (for example, control commands and native functions). The only exception is a newline, which can be simply written as `"\n"`.

Literals may also be used in logic/calculations, for example with the `int` and `float` types.

Supported types:

* **string**: Represented with a leading `^` to differentiate from other string-based objects. e.g. `"^Hello world"` is used in JSON to represent the text `Hello world`, and `"^^ up there ^"` would be the text `^ up there ^`. No `^` is needed for a newline, so it's just `"\n"`.
* **int** and **float**: these are represented using their standard JSON counterparts. e.g. `5`, `5.6`.
* **divert target**: represents a variable divert target, for example as used in the following ink:

VAR x = -> somewhere
Represented in runtime JSON as an object of the form: `{"^->": "path.to.target"}`

* **variable pointer**: used for references to variables, for example when declaring a function with the following ink:

== function myFunction(ref x) ==
Represented in runtime JSON as an object of the form: `{"^var": "varname", "ci": 0}`. Where `ci` is "context index", with the following possible values:

* **-1** - default value, context yet to be determined.
* **0** - Variable is a global
* **1 or more** - variable is a local/temporary in the callstack element with the given index.

* `"$Hello world"` - The string `Hello world`
* `"$$9.99` - The string `$9.99`.
* `"\n"` - A newline.
## Void

Represented by `"void"`, this is used to place an object on the evaluation stack when a function returns without a value.

## Control commands

Expand Down Expand Up @@ -76,36 +100,6 @@ These are mathematical and logical functions that pop 1 or 2 arguments from the

Booleans are supported only in the C-style - i.e. as integers where non-zero is treated as "true" and zero as "false". The true result of a boolean operation is pushed to the evaluation stack as `1`.

## Literals

*(TODO: Consider renaming to "Values"?)*

Logical values that can be used in conjunction with various logical constructs such as functions and native functions.

Supported types:

* **int** and **float**: these are represented using their standard JSON counterparts. e.g. `5`, `5.6`.
* **string**: Represented with a leading `^` to differentiate from other string-based objects. e.g. `^Hello world`. TODO: consider merging with Text objects.
* **divert target**: represents a variable divert target, for example as used in the following ink:

VAR x = -> somewhere
Represented in runtime JSON as an object of the form: `{"^->": "path.to.target"}`

* **variable pointer**: used for references to variables, for example when declaring a function with the following ink:

== function myFunction(ref x) ==
Represented in runtime JSON as an object of the form: `{"^var": "varname", "ci": 0}`. Where `ci` is "context index", with the following possible values:

* **-1** - default value, context yet to be determined.
* **0** - Variable is a global
* **1 or more** - variable is a local/temporary in the callstack element with the given index.

## Void

Represented by `"void"`, this is used to place an object on the evaluation stack when a function returns without a value.

## Divert

Diverts can take the following forms:
Expand Down
2 changes: 1 addition & 1 deletion ink-engine-runtime/Container.cs
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ public void BuildStringOfHierarchy(StringBuilder sb, int indentation, Runtime.Ob

} else {
appendIndentation ();
if (obj is Text) {
if (obj is LiteralString) {
sb.Append ("\"");
sb.Append (obj.ToString ().Replace ("\n", "\\n"));
sb.Append ("\"");
Expand Down
24 changes: 8 additions & 16 deletions ink-engine-runtime/JsonSerialisation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,12 +142,8 @@ public static Runtime.Object JTokenToRuntimeObject(JToken token)
char firstChar = str[0];
if (firstChar == '^')
return new LiteralString (str.Substring (1));

// Runtime text
if (firstChar == '$')
return new Runtime.Text (str.Substring (1));
if (firstChar == '\n' && str.Length == 1)
return new Runtime.Text ("\n");
else if( firstChar == '\n' && str.Length == 1)
return new LiteralString ("\n");

// Glue
if (str == "<>")
Expand Down Expand Up @@ -361,8 +357,12 @@ public static JToken RuntimeObjectToJToken(Runtime.Object obj)
return litFloat.value;

var litStr = obj as LiteralString;
if (litStr)
return "^" + litStr.value;
if (litStr) {
if (litStr.isNewline)
return "\n";
else
return "^" + litStr.value;
}

var litDivTarget = obj as LiteralDivertTarget;
if (litDivTarget)
Expand All @@ -377,14 +377,6 @@ public static JToken RuntimeObjectToJToken(Runtime.Object obj)
new JProperty("ci", litVarPtr.contextIndex)
);

var text = obj as Runtime.Text;
if (text) {
if (text.isNewline)
return "\n";
else
return "$" + text.text;
}

var glue = obj as Runtime.Glue;
if (glue) {
if (glue.isBi)
Expand Down
17 changes: 17 additions & 0 deletions ink-engine-runtime/Literal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,25 @@ internal class LiteralString : Literal<string>
public override LiteralType literalType { get { return LiteralType.String; } }
public override bool isTruthy { get { return value.Length > 0; } }

public bool isNewline { get; private set; }
public bool isInlineWhitespace { get; private set; }
public bool isNonWhitespace {
get {
return !isNewline && !isInlineWhitespace;
}
}

public LiteralString(string literalVal) : base(literalVal)
{
// Classify whitespace status
isNewline = value == "\n";
isInlineWhitespace = true;
foreach (var c in value) {
if (c != ' ' && c != '\t') {
isInlineWhitespace = false;
break;
}
}
}

public LiteralString() : this("") {}
Expand Down
4 changes: 2 additions & 2 deletions ink-engine-runtime/Story.cs
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ bool PerformLogicAndFlowControl(Runtime.Object contentObj)
// TODO: Should we really always blanket convert to string?
// It would be okay to have numbers in the output stream the
// only problem is when exporting text for viewing, it skips over numbers etc.
var text = new Text (output.ToString ());
var text = new LiteralString (output.ToString ());

state.PushToOutputStream (text);
}
Expand Down Expand Up @@ -707,7 +707,7 @@ bool PerformLogicAndFlowControl(Runtime.Object contentObj)
break;
}

if( obj is Text )
if( obj is LiteralString )
contentStackForString.Push (obj);
}

Expand Down
34 changes: 17 additions & 17 deletions ink-engine-runtime/StoryState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,9 @@ internal string currentText
var sb = new StringBuilder ();

foreach (var outputObj in _outputStream) {
var textContent = outputObj as Text;
var textContent = outputObj as LiteralString;
if (textContent != null) {
sb.Append(textContent.text);
sb.Append(textContent.value);
}
}

Expand Down Expand Up @@ -298,7 +298,7 @@ internal void ResetOutput()
// in dealing with them later.
internal void PushToOutputStream(Runtime.Object obj)
{
var text = obj as Text;
var text = obj as LiteralString;
if (text) {
var listText = TrySplittingHeadTailWhitespace (text);
if (listText != null) {
Expand All @@ -324,9 +324,9 @@ internal void PushToOutputStream(Runtime.Object obj)
//
// - If no splitting is necessary, null is returned.
// - A newline on its own is returned in an list for consistency.
List<Runtime.Text> TrySplittingHeadTailWhitespace(Runtime.Text single)
List<Runtime.LiteralString> TrySplittingHeadTailWhitespace(Runtime.LiteralString single)
{
string str = single.text;
string str = single.value;

int headFirstNewlineIdx = -1;
int headLastNewlineIdx = -1;
Expand Down Expand Up @@ -362,16 +362,16 @@ internal void PushToOutputStream(Runtime.Object obj)
if (headFirstNewlineIdx == -1 && tailLastNewlineIdx == -1)
return null;

var listTexts = new List<Runtime.Text> ();
var listTexts = new List<Runtime.LiteralString> ();
int innerStrStart = 0;
int innerStrEnd = str.Length;

if (headFirstNewlineIdx != -1) {
if (headFirstNewlineIdx > 0) {
var leadingSpaces = new Text (str.Substring (0, headFirstNewlineIdx));
var leadingSpaces = new LiteralString (str.Substring (0, headFirstNewlineIdx));
listTexts.Add(leadingSpaces);
}
listTexts.Add (new Text ("\n"));
listTexts.Add (new LiteralString ("\n"));
innerStrStart = headLastNewlineIdx + 1;
}

Expand All @@ -381,14 +381,14 @@ internal void PushToOutputStream(Runtime.Object obj)

if (innerStrEnd > innerStrStart) {
var innerStrText = str.Substring (innerStrStart, innerStrEnd - innerStrStart);
listTexts.Add (new Text (innerStrText));
listTexts.Add (new LiteralString (innerStrText));
}

if (tailLastNewlineIdx != -1 && tailFirstNewlineIdx > headLastNewlineIdx) {
listTexts.Add (new Text ("\n"));
listTexts.Add (new LiteralString ("\n"));
if (tailLastNewlineIdx < str.Length - 1) {
int numSpaces = (str.Length - tailLastNewlineIdx) - 1;
var trailingSpaces = new Text (str.Substring (tailLastNewlineIdx + 1, numSpaces));
var trailingSpaces = new LiteralString (str.Substring (tailLastNewlineIdx + 1, numSpaces));
listTexts.Add(trailingSpaces);
}
}
Expand All @@ -399,7 +399,7 @@ internal void PushToOutputStream(Runtime.Object obj)
void PushToOutputStreamIndividual(Runtime.Object obj)
{
var glue = obj as Runtime.Glue;
var text = obj as Runtime.Text;
var text = obj as Runtime.LiteralString;

bool includeInOutput = true;

Expand Down Expand Up @@ -469,7 +469,7 @@ void TrimNewlinesFromOutputStream(bool stopAndRemoveRightGlue)
while (i >= 0) {
var obj = _outputStream [i];
var cmd = obj as ControlCommand;
var txt = obj as Text;
var txt = obj as LiteralString;
var glue = obj as Glue;

if (cmd || (txt && txt.isNonWhitespace)) {
Expand All @@ -489,7 +489,7 @@ void TrimNewlinesFromOutputStream(bool stopAndRemoveRightGlue)
if (removeWhitespaceFrom >= 0) {
i=removeWhitespaceFrom;
while(i < _outputStream.Count) {
var text = _outputStream [i] as Text;
var text = _outputStream [i] as LiteralString;
if (text) {
_outputStream.RemoveAt (i);
} else {
Expand All @@ -508,7 +508,7 @@ void TrimFromExistingGlue()
{
int i = currentGlueIndex;
while (i < _outputStream.Count) {
var txt = _outputStream [i] as Text;
var txt = _outputStream [i] as LiteralString;
if (txt && !txt.isNonWhitespace)
_outputStream.RemoveAt (i);
else
Expand Down Expand Up @@ -552,7 +552,7 @@ internal bool outputStreamEndsInNewline {
var obj = _outputStream [i];
if (obj is ControlCommand) // e.g. BeginString
break;
var text = _outputStream [i] as Text;
var text = _outputStream [i] as LiteralString;
if (text) {
if (text.isNewline)
return true;
Expand All @@ -569,7 +569,7 @@ internal bool outputStreamEndsInNewline {
internal bool outputStreamContainsContent {
get {
foreach (var content in _outputStream) {
if (content is Text)
if (content is LiteralString)
return true;
}
return false;
Expand Down
37 changes: 0 additions & 37 deletions ink-engine-runtime/Text.cs

This file was deleted.

1 change: 0 additions & 1 deletion ink-engine-runtime/ink-engine-runtime.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
<Compile Include="$(MSBuildThisFileDirectory)Story.cs" />
<Compile Include="$(MSBuildThisFileDirectory)StoryException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)StringJoinExtension.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Text.cs" />
<Compile Include="$(MSBuildThisFileDirectory)VariableAssignment.cs" />
<Compile Include="$(MSBuildThisFileDirectory)VariableReference.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Void.cs" />
Expand Down
2 changes: 1 addition & 1 deletion inklecate/ParsedHierarchy/Choice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ public override Runtime.Object GenerateRuntimeObject ()

// Fully parsed choice will be a full line, so it needs to be terminated
if (startContent || innerContent) {
_innerContentContainer.AddContent(new Runtime.Text("\n"));
_innerContentContainer.AddContent(new Runtime.LiteralString("\n"));
}

// Use "c" as the destination name within the choice's outer container
Expand Down
2 changes: 1 addition & 1 deletion inklecate/ParsedHierarchy/Text.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public Text (string str)

public override Runtime.Object GenerateRuntimeObject ()
{
return new Runtime.Text(this.text);
return new Runtime.LiteralString(this.text);
}

public override string ToString ()
Expand Down

0 comments on commit 4973a9a

Please sign in to comment.