Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Divert targets allow knots to be called as functions #296

Open
joningold opened this issue Mar 31, 2017 · 7 comments
Open

Divert targets allow knots to be called as functions #296

joningold opened this issue Mar 31, 2017 · 7 comments

Comments

@joningold
Copy link
Member

... and hell breaks loose if you do. (Well, the game crashes)

~ temp x = -> knot 

* { x() } The choice. 
    -> END 

=== knot 
    *   More choices 
    *   Even more choices!
    -   
    *   And then we slept. 
        -> DONE     
@clembu
Copy link

clembu commented May 30, 2019

Additional info

In Inky ( v0.10.0 ; ink v0.8.2 ; inkjs v1.7.1 with hotfix ), choices appear.
When choosing any one, crash happens, with this stacktrace:

System.Exception: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index (Internal story path: 0.4.9) ---> System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
   at System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)
   at System.Collections.Generic.List`1.get_Item(Int32 index)
   at Ink.Runtime.StoryState.PopEvaluationStack()
   at Ink.Runtime.Story.ProcessChoice(ChoicePoint choicePoint)
   at Ink.Runtime.Story.Step()
   at Ink.Runtime.Story.ContinueSingleStep()
   at Ink.Runtime.Story.ContinueInternal(Single millisecsLimitAsync)
   at Ink.Runtime.Story.ContinueAsync(Single millisecsLimitAsync)
   at Ink.Runtime.Story.Continue()
   at Ink.CommandLinePlayer.EvaluateStory()
   at Ink.CommandLinePlayer.Begin()
   at Ink.CommandLineTool..ctor(String[] args)
   --- End of inner exception stack trace ---
   at Ink.CommandLineTool..ctor(String[] args)
   at Ink.CommandLineTool.Main(String[] args)

@joningold
Copy link
Member Author

joningold commented May 31, 2019 via email

@clembu
Copy link

clembu commented May 31, 2019

I'll have a look at the generated runtime json tree once I get home. Looks to me that the function call "pops" a value that is never pushed (no "void" is pushed on the stack in knot?)

Do you want to allow calling divert targets as functions? It'd be nice if you want dynamic delegate switching, but in that case maybe there should be an explicit check at runtime that the target points to a function and not any "gotoable" point.

@joningold
Copy link
Member Author

joningold commented May 31, 2019 via email

@clembu
Copy link

clembu commented May 31, 2019

indeed there is no static way to know that a container corresponds to a function, right now. The runtime assumes that the compiler did its thing and that a function call means the target is a function.

The least effort fix doable right now would be to check if the stack is poppable before popping, to avoid an exception and throw a custom runtime error with a message that would like "tried to get a non-existing value, have you called a function that was actually not a function?" or something like that, but it would be better anyway to be able to make sure that a function call points to an actual function, directly or indirectly. Adding a flag in the #f field of the container metadata object wouldn't add that much of an overhead in the json, and would correspond to a bool in the c# object that could also be used in other dynamic checks.

@clembu
Copy link

clembu commented Jun 1, 2019

I looked at the JSON, and indeed, this choice

* { x() } The choice.

Generates the following json object (minus all the text evaluation)

                {
                    "*": "0.c-0",
                    "flg": 19
                }

which sets it to check for a condition before doing anything (flag 1 is set),
so it pops from the eval stack, but the function call x() never pushed on the stack, so as I had assumed, the runtime tries to pop from an empty stack.
This is a decently error to catch in StoryState.PopEvaluationStack (which currently does a straight count - 1 access, which fails when count is 0. Same thing for PeekEvaluationStack. Checking for empty stacks there would already help prevent crashes, and instead generate nice errors.)

@joningold
Copy link
Member Author

joningold commented Jun 1, 2019 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants