Parsing code elements of a narrative

Currently, I have been working on an engine called StoryDev 2, and while the engine is mostly complete, there are some parts of it that still need working. It is an interactive story engine, and I am not an expert at parsing text. I know how to use Regular expressions, but regex in this case is simply a no-no.

I will need to parse the text of a narrative, checking for code snippets along the way, character-by-character, and evaluating the results. Take the below as an example:

Saniyah : Oh, you need to go to the {{if (role == 'lore' || role == 'cleric')}}Great Library, which is three blocks to the left of me. Follow the road down, and the first door to the right is the building entrance. {{else if (role == 'monk')}}Halls of Light, which is deep in the heart of the city center. It's a large temple that's difficult to miss. {{endif}}

It’s quite obvious which part of the narrative is code and which isn’t, but ultimately I need a function that will parse this narrative (everything on the right of the colon) and return the evaluated result. Since HScript exists, I was considering taking the code that exists and parsing it into something HScript understands.

So the narrative would change this:

evaluated += "Oh, you need to go to the ";
if (role == 'lore' || role == 'cleric') {
    evaluated += "Great Library, which is three blocks to the left of me. Follow the road down, and the first door to the right is the building entrance.";
}
else if (role == 'monk') {
    evaluated += "Halls of Light, which is deep in the heart of the city center. It's a large temple that's difficult to miss.";
}

The function would then return the evaluated result.

This is my currently implemented code for doing this:

public function parseNarrative(value:String)
    {
        var result = "";
        var isCodeBlock = false;
        var openBracket = 0;
        var script = "";
        var scriptEval = "";
        var addedEval = false;
        
        _interp.variables.set("evaluated", result);
        
        for (i in 0...value.length)
        {
            if (openBracket == 2)
            {
                script += value.charAt(i);
                continue;
            }
            
            if (value.charAt(i) == '{')
            {
                if (addedEval)
                {
                    script += "\";";
                    addedEval = false;
                }
                
                openBracket += 1;
            }
            else if (value.charAt(i) == '}')
            {
                if (openBracket - 1 < 0)
                {
                    Browser.console.error('Narration parsing error at character $i : Too many close curly brackets.');
                }
                else
                {
                    openBracket -= 1;
                }
            }
            else
            {
                if (script != "" && openBracket == 2)
                {
                    script += value.charAt(i);
                }
                else if (script != "" && openBracket == 0)
                {
                    if (!addedEval)
                    {
                        addedEval = true;
                        script += "evaluated += \"" + value.charAt(i);
                    }
                    else
                    {
                        script += value.charAt(i);
                    }
                }
            }
        }
        
        
        
        return result;
    }

Now, I’ve got this far and I am already misunderstanding my own code. This is how bad I am at parsing text! Now, I could use regular expressions, because I understand that… But again, it’s knowing how to combine each of the different elements together into coherent code that HScript understands.

I have a function called executeCode which I would use later once I have parsed the narrative to acquire the result, which I then return using this function.

So ultimately, if role == 'cleric', Saniyah should say:

Oh, you need to go to the Great Library, which is three blocks to the left of me. Follow the road down, and the first door to the right is the building entrance.

Could anyone help to complete the above function? A special thank you in advance. I will also credit you if the function works perfectly in the engine. Even if it isn’t a code example, any alternative suggestions would be just as great.

Could you use a template system instead? I ask because it’s probably the thing I’ll do for this kind of feature instead of bother me to write more code…

Well, somehow I managed to get the above code to work correctly anyway…

public function parseNarrative(value:String)
    {
        var result = "";
        var openBracket = 0;
        var script = "evaluated = '';";
        var addedEval = false;
        
        for (i in 0...value.length)
        {
            if (i == value.length - 1)
            {
                script += value.charAt(i) + "\";";
                break;
            }
            
            if (value.charAt(i) == '{')
            {
                if (addedEval)
                {
                    script += "\";";
                    addedEval = false;
                }
                
                openBracket += 1;
            }
            else if (value.charAt(i) == '}')
            {
                if (openBracket - 1 < 0)
                {
                    Browser.console.error('Narration parsing error at character $i : Too many close curly brackets.');
                }
                else
                {
                    openBracket -= 1;
                }
            }
            else
            {
                if (openBracket == 2)
                {
                    script += value.charAt(i);
                    continue;
                }
                
                if (script != "" && openBracket == 2)
                {
                    script += value.charAt(i);
                }
                else if (script != "" && openBracket == 0)
                {
                    if (!addedEval)
                    {
                        addedEval = true;
                        script += "evaluated += \"" + value.charAt(i);
                    }
                    else
                    {
                        script += value.charAt(i);
                    }
                }
            }
        }
        
        executeCode(script);
        result = _interp.variables.get("evaluated");
        
        return result;
    }

I’d still consider using templates as @loudo suggested, you can do it really easily http://try.haxe.org/#83b75

It also supports iteration, sub templates and more http://haxe.org/manual/std-template.html

Oh, those templates! I completely forgot about that. When @loudo first mentioned templates, I didn’t know what the hell that was about! Because I have “Templates” in my engine, I was getting confused between the two things. But thanks for the suggestion. I’ll probably implement it soon.