Inheritance: Parsed.Object
Ejemplo n.º 1
0
        protected Parsed.Object LogicLine()
        {
            Whitespace ();

            if (ParseString ("~") == null) {
                return null;
            }

            Whitespace ();

            // Some example lines we need to be able to distinguish between:
            // ~ temp x = 5  -- var decl + assign
            // ~ temp x      -- var decl
            // ~ x = 5       -- var assign
            // ~ x           -- expr (not var decl or assign)
            // ~ f()         -- expr
            // We don't treat variable decl/assign as an expression since we don't want an assignment
            // to have a return value, or to be used in compound expressions.
            ParseRule afterTilda = () => OneOf (ReturnStatement, TempDeclarationOrAssignment, Expression);

            var result = Expect(afterTilda, "expression after '~'", recoveryRule: SkipToNextLine) as Parsed.Object;

            // Parse all expressions, but tell the writer off if they did something useless like:
            //  ~ 5 + 4
            // And even:
            //  ~ false && myFunction()
            // ...since it's bad practice, and won't do what they expect if
            // they're expecting C's lazy evaluation.
            if (result is Expression && !(result is FunctionCall || result is IncDecExpression) ) {

                // TODO: Remove this specific error message when it has expired in usefulness
                var varRef = result as VariableReference;
                if (varRef && varRef.name == "include") {
                    Error ("'~ include' is no longer the correct syntax - please use 'INCLUDE your_filename.ink', without the tilda, and in block capitals.");
                } 

                else {
                    Error ("Logic following a '~' can't be that type of expression. It can only be something like:\n\t~ return\n\t~ var x = blah\n\t~ x++\n\t~ myFunction()");
                }
            }

            // A function call on its own line could result in a text side effect, in which case
            // it needs a newline on the end. e.g.
            //  ~ printMyName()
            // If no text gets printed, then the extra newline will have to be culled later.
            if (result is FunctionCall) {

                // Add extra pop to make sure we tidy up after ourselves - we no longer need anything on the evaluation stack.
                var funCall = result as FunctionCall;
                funCall.shouldPopReturnedValue = true;

                result = new ContentList (funCall, new Parsed.Text ("\n"));
            }

            Expect(EndOfLine, "end of line", recoveryRule: SkipToNextLine);

            return result as Parsed.Object;
        }
Ejemplo n.º 2
0
        public Choice(ContentList startContent, ContentList choiceOnlyContent, ContentList innerContent, Divert divert)
        {
            this.startContent = startContent;
            this.choiceOnlyContent = choiceOnlyContent;
            this.innerContent = innerContent;
            this.indentationDepth = 1;

            if (startContent)
                AddContent (this.startContent);

            if (choiceOnlyContent)
                AddContent (this.choiceOnlyContent);

            if( innerContent )
                AddContent (this.innerContent);

            this.onceOnly = true; // default

            if (divert) {
                terminatingDivert = divert;
                AddContent (terminatingDivert);
            }
        }
Ejemplo n.º 3
0
        public Choice(ContentList startContent, ContentList choiceOnlyContent, ContentList innerContent)
        {
            this.startContent      = startContent;
            this.choiceOnlyContent = choiceOnlyContent;
            this.innerContent      = innerContent;
            this.indentationDepth  = 1;

            if (startContent)
            {
                AddContent(this.startContent);
            }

            if (choiceOnlyContent)
            {
                AddContent(this.choiceOnlyContent);
            }

            if (innerContent)
            {
                AddContent(this.innerContent);
            }

            this.onceOnly = true; // default
        }
Ejemplo n.º 4
0
        protected Parsed.Object InlineLogic()
        {
            if ( ParseString ("{") == null) {
                return null;
            }

            Whitespace ();

            var logic = (Parsed.Object) Expect(InnerLogic, "some kind of logic, conditional or sequence within braces: { ... }");
            if (logic == null)
                return null;

            ContentList contentList = logic as ContentList;
            if (!contentList) {
                contentList = new ContentList (logic);
            }

            // Create left-glue. Like normal glue, except it only absorbs newlines to
            // the left, ensuring that the logic is inline, but without having the side effect
            // of possibly absorbing desired newlines that come after.
            var rightGlue = new Parsed.Wrap<Runtime.Glue>(new Runtime.Glue (Runtime.GlueType.Right));
            var leftGlue = new Parsed.Wrap<Runtime.Glue>(new Runtime.Glue (Runtime.GlueType.Left));
            contentList.InsertContent (0, rightGlue);
            contentList.AddContent (leftGlue);

            Whitespace ();

            Expect (String("}"), "closing brace '}' for inline logic");

            return contentList;
        }
Ejemplo n.º 5
0
		protected Choice Choice()
		{
            bool onceOnlyChoice = true;
            var bullets = Interleave <string>(OptionalExclude(Whitespace), String("*") );
            if (bullets == null) {

                bullets = Interleave <string>(OptionalExclude(Whitespace), String("+") );
                if (bullets == null) {
                    return null;
                }

                onceOnlyChoice = false;
            }
                
            // Optional name for the choice
            string optionalName = Parse(BracketedName);

            Whitespace ();

            // Optional condition for whether the choice should be shown to the player
            Expression conditionExpr = Parse(ChoiceCondition);

            Whitespace ();

            // Ordinarily we avoid parser state variables like these, since
            // nesting would require us to store them in a stack. But since you should
            // never be able to nest choices within choice content, it's fine here.
            Debug.Assert(_parsingChoice == false, "Already parsing a choice - shouldn't have nested choices");
            _parsingChoice = true;
                
            ContentList startContent = null;
            var startTextAndLogic = Parse (MixedTextAndLogic);
            if (startTextAndLogic != null)
                startContent = new ContentList (startTextAndLogic);


            ContentList optionOnlyContent = null;
            ContentList innerContent = null;

            // Check for a the weave style format:
            //   * "Hello[."]," he said.
            bool hasWeaveStyleInlineBrackets = ParseString("[") != null;
            if (hasWeaveStyleInlineBrackets) {

                var optionOnlyTextAndLogic = Parse (MixedTextAndLogic);
                if (optionOnlyTextAndLogic != null)
                    optionOnlyContent = new ContentList (optionOnlyTextAndLogic);
                

                Expect (String("]"), "closing ']' for weave-style option");

                var innerTextAndLogic = Parse (MixedTextAndLogic);
                if( innerTextAndLogic != null )
                    innerContent = new ContentList (innerTextAndLogic);
            }

            _parsingChoice = false;
             
            // Trim
            if( innerContent )
                TrimChoiceContent (ref innerContent);
            else if( optionOnlyContent )
                TrimChoiceContent (ref optionOnlyContent);
            else 
                TrimChoiceContent (ref startContent);

            if (innerContent != null) {
                innerContent.AddContent (new Text ("\n"));
            }

            bool isDefaultChoice = startContent == null && optionOnlyContent == null;
                
			Whitespace ();

            var divert =  Parse(SingleDivert);

            Whitespace ();

            // Completely empty choice?
            if (!startContent && !optionOnlyContent && !innerContent && !divert) {
                Warning ("Choice is completely empty. Interpretting as a default fallback choice. Add a divert arrow to remove this warning: * ->");
            }

            var tags = Parse (Tags);
            if (tags != null) {
                if (hasWeaveStyleInlineBrackets) {
                    if (!innerContent)
                        innerContent = new ContentList();
                    innerContent.AddContent(tags);
                } else {
                    startContent.AddContent (tags);
                }
            }

            var choice = new Choice (startContent, optionOnlyContent, innerContent, divert);
            choice.name = optionalName;
            choice.indentationDepth = bullets.Count;
            choice.hasWeaveStyleInlineBrackets = hasWeaveStyleInlineBrackets;
            choice.condition = conditionExpr;
            choice.onceOnly = onceOnlyChoice;
            choice.isInvisibleDefault = isDefaultChoice;

            return choice;

		}
Ejemplo n.º 6
0
 void TrimChoiceContent(ref ContentList content)
 {
     if (content != null) {
         content.TrimTrailingWhitespace ();
         if (content.content.Count == 0) {
             content = null;
         }
     }
 }