Newer
Older
TheVengeance-Project-IADE-Unity2D / Assets / Ink / InkLibs / InkCompiler / InkParser / InkParser_Content.cs
  1. using Ink.Parsed;
  2. using System.Text;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. namespace Ink
  6. {
  7. public partial class InkParser
  8. {
  9. void TrimEndWhitespace(List<Parsed.Object> mixedTextAndLogicResults, bool terminateWithSpace)
  10. {
  11. // Trim whitespace from end
  12. if (mixedTextAndLogicResults.Count > 0) {
  13. var lastObjIdx = mixedTextAndLogicResults.Count - 1;
  14. var lastObj = mixedTextAndLogicResults[lastObjIdx];
  15. if (lastObj is Text) {
  16. var text = (Text)lastObj;
  17. text.text = text.text.TrimEnd (' ', '\t');
  18. if (terminateWithSpace)
  19. text.text += " ";
  20. // No content left at all? trim the whole object
  21. else if( text.text.Length == 0 ) {
  22. mixedTextAndLogicResults.RemoveAt(lastObjIdx);
  23. // Recurse in case there's more whitespace
  24. TrimEndWhitespace(mixedTextAndLogicResults, terminateWithSpace:false);
  25. }
  26. }
  27. }
  28. }
  29. protected List<Parsed.Object> LineOfMixedTextAndLogic()
  30. {
  31. // Consume any whitespace at the start of the line
  32. // (Except for escaped whitespace)
  33. Parse (Whitespace);
  34. var result = Parse(MixedTextAndLogic);
  35. if (result == null || result.Count == 0)
  36. return null;
  37. // Warn about accidentally writing "return" without "~"
  38. var firstText = result[0] as Text;
  39. if (firstText) {
  40. if (firstText.text.StartsWith ("return")) {
  41. Warning ("Do you need a '~' before 'return'? If not, perhaps use a glue: <> (since it's lowercase) or rewrite somehow?");
  42. }
  43. }
  44. if (result.Count == 0)
  45. return null;
  46. var lastObj = result [result.Count - 1];
  47. if (!(lastObj is Divert)) {
  48. TrimEndWhitespace (result, terminateWithSpace:false);
  49. }
  50. EndTagIfNecessary(result);
  51. // If the line doens't actually contain any normal text content
  52. // but is in fact entirely a tag, then let's not append
  53. // a newline, since we want the tag (or tags) to be associated
  54. // with the line below rather than being completely independent.
  55. bool lineIsPureTag = result.Count > 0 && result[0] is Parsed.Tag && ((Parsed.Tag)result[0]).isStart;
  56. if( !lineIsPureTag )
  57. result.Add (new Text ("\n"));
  58. Expect(EndOfLine, "end of line", recoveryRule: SkipToNextLine);
  59. return result;
  60. }
  61. protected List<Parsed.Object> MixedTextAndLogic()
  62. {
  63. // Check for disallowed "~" within this context
  64. var disallowedTilda = ParseObject(Spaced(String("~")));
  65. if (disallowedTilda != null)
  66. Error ("You shouldn't use a '~' here - tildas are for logic that's on its own line. To do inline logic, use { curly braces } instead");
  67. // Either, or both interleaved
  68. var results = Interleave<Parsed.Object>(Optional (ContentText), Optional (InlineLogicOrGlueOrStartTag));
  69. // Terminating divert?
  70. // (When parsing content for the text of a choice, diverts aren't allowed.
  71. // The divert on the end of the body of a choice is handled specially.)
  72. if (!_parsingChoice) {
  73. var diverts = Parse (MultiDivert);
  74. if (diverts != null) {
  75. // May not have had any results at all if there's *only* a divert!
  76. if (results == null)
  77. results = new List<Parsed.Object> ();
  78. // End previously active tag if necessary
  79. EndTagIfNecessary(results);
  80. TrimEndWhitespace (results, terminateWithSpace:true);
  81. results.AddRange (diverts);
  82. }
  83. }
  84. if (results == null)
  85. return null;
  86. return results;
  87. }
  88. protected Parsed.Text ContentText()
  89. {
  90. return ContentTextAllowingEcapeChar ();
  91. }
  92. protected Parsed.Text ContentTextAllowingEcapeChar()
  93. {
  94. StringBuilder sb = null;
  95. do {
  96. var str = Parse(ContentTextNoEscape);
  97. bool gotEscapeChar = ParseString(@"\") != null;
  98. if( gotEscapeChar || str != null ) {
  99. if( sb == null ) {
  100. sb = new StringBuilder();
  101. }
  102. if( str != null ) {
  103. sb.Append(str);
  104. }
  105. if( gotEscapeChar ) {
  106. char c = ParseSingleCharacter();
  107. sb.Append(c);
  108. }
  109. } else {
  110. break;
  111. }
  112. } while(true);
  113. if (sb != null ) {
  114. return new Parsed.Text (sb.ToString ());
  115. } else {
  116. return null;
  117. }
  118. }
  119. // Content text is an unusual parse rule compared with most since it's
  120. // less about saying "this is is the small selection of stuff that we parse"
  121. // and more "we parse ANYTHING except this small selection of stuff".
  122. protected string ContentTextNoEscape()
  123. {
  124. // Eat through text, pausing at the following characters, and
  125. // attempt to parse the nonTextRule.
  126. // "-": possible start of divert or start of gather
  127. // "<": possible start of glue
  128. if (_nonTextPauseCharacters == null) {
  129. _nonTextPauseCharacters = new CharacterSet ("-<");
  130. }
  131. // If we hit any of these characters, we stop *immediately* without bothering to even check the nonTextRule
  132. // "{" for start of logic
  133. // "|" for mid logic branch
  134. if (_nonTextEndCharacters == null) {
  135. _nonTextEndCharacters = new CharacterSet ("{}|\n\r\\#");
  136. _notTextEndCharactersChoice = new CharacterSet (_nonTextEndCharacters);
  137. _notTextEndCharactersChoice.AddCharacters ("[]");
  138. _notTextEndCharactersString = new CharacterSet (_nonTextEndCharacters);
  139. _notTextEndCharactersString.AddCharacters ("\"");
  140. }
  141. // When the ParseUntil pauses, check these rules in case they evaluate successfully
  142. ParseRule nonTextRule = () => OneOf (ParseDivertArrow, ParseThreadArrow, EndOfLine, Glue);
  143. CharacterSet endChars = null;
  144. if (parsingStringExpression) {
  145. endChars = _notTextEndCharactersString;
  146. }
  147. else if (_parsingChoice) {
  148. endChars = _notTextEndCharactersChoice;
  149. }
  150. else {
  151. endChars = _nonTextEndCharacters;
  152. }
  153. string pureTextContent = ParseUntil (nonTextRule, _nonTextPauseCharacters, endChars);
  154. if (pureTextContent != null ) {
  155. return pureTextContent;
  156. } else {
  157. return null;
  158. }
  159. }
  160. CharacterSet _nonTextPauseCharacters;
  161. CharacterSet _nonTextEndCharacters;
  162. CharacterSet _notTextEndCharactersChoice;
  163. CharacterSet _notTextEndCharactersString;
  164. }
  165. }