2014-08-09 15:18:31 -05:00
|
|
|
|
using System.Runtime.CompilerServices;
|
|
|
|
|
[assembly: InternalsVisibleTo("Ficdown.Parser.Tests")]
|
|
|
|
|
|
|
|
|
|
namespace Ficdown.Parser
|
2014-06-29 23:04:51 -05:00
|
|
|
|
{
|
2014-07-01 01:51:08 -05:00
|
|
|
|
using System;
|
2018-09-27 12:32:32 -05:00
|
|
|
|
using System.Collections.Generic;
|
2015-07-19 17:19:40 -05:00
|
|
|
|
using System.Linq;
|
2014-08-09 15:18:31 -05:00
|
|
|
|
using Model.Parser;
|
2014-07-02 23:11:36 -05:00
|
|
|
|
using Parser;
|
2014-08-09 15:18:31 -05:00
|
|
|
|
using Player;
|
2014-06-29 23:04:51 -05:00
|
|
|
|
|
|
|
|
|
public class FicdownParser
|
|
|
|
|
{
|
2019-09-21 18:52:00 -05:00
|
|
|
|
private static Logger _logger = Logger.GetLogger<FicdownParser>();
|
2018-09-27 12:32:32 -05:00
|
|
|
|
public List<FicdownException> Warnings { get; private set; }
|
|
|
|
|
|
2014-06-29 23:04:51 -05:00
|
|
|
|
private IBlockHandler _blockHandler;
|
2014-08-09 15:18:31 -05:00
|
|
|
|
internal IBlockHandler BlockHandler
|
2014-06-29 23:04:51 -05:00
|
|
|
|
{
|
2018-09-27 12:32:32 -05:00
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _blockHandler ??
|
|
|
|
|
(_blockHandler = new BlockHandler { Warnings = Warnings });
|
|
|
|
|
}
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_blockHandler = value;
|
|
|
|
|
_blockHandler.Warnings = Warnings;
|
|
|
|
|
}
|
2014-06-29 23:04:51 -05:00
|
|
|
|
}
|
|
|
|
|
|
2014-08-09 15:18:31 -05:00
|
|
|
|
private IGameTraverser _gameTraverser;
|
|
|
|
|
internal IGameTraverser GameTraverser
|
|
|
|
|
{
|
2018-09-27 12:32:32 -05:00
|
|
|
|
get { return _gameTraverser ??
|
|
|
|
|
(_gameTraverser = new GameTraverser { Warnings = Warnings }); }
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_gameTraverser = value;
|
|
|
|
|
_gameTraverser.Warnings = Warnings;
|
|
|
|
|
}
|
2014-08-09 15:18:31 -05:00
|
|
|
|
}
|
2014-06-30 11:59:56 -05:00
|
|
|
|
|
2014-08-09 15:18:31 -05:00
|
|
|
|
private IStateResolver _stateResolver;
|
|
|
|
|
internal IStateResolver StateResolver
|
2014-06-30 11:59:56 -05:00
|
|
|
|
{
|
2018-09-27 12:32:32 -05:00
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _stateResolver ??
|
|
|
|
|
(_stateResolver = new StateResolver { Warnings = Warnings });
|
|
|
|
|
}
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_stateResolver = value;
|
|
|
|
|
_stateResolver.Warnings = Warnings;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public FicdownParser()
|
|
|
|
|
{
|
|
|
|
|
Warnings = new List<FicdownException>();
|
2014-06-30 11:59:56 -05:00
|
|
|
|
}
|
|
|
|
|
|
2014-08-10 17:32:13 -05:00
|
|
|
|
public ResolvedStory ParseStory(string storyText)
|
2014-06-29 23:04:51 -05:00
|
|
|
|
{
|
2014-07-01 01:51:08 -05:00
|
|
|
|
var lines = storyText.Split(new[] {"\n", "\r\n"}, StringSplitOptions.None);
|
2019-09-21 18:52:00 -05:00
|
|
|
|
_logger.Debug($"Parsed {lines.Length} lines.");
|
2014-06-29 23:04:51 -05:00
|
|
|
|
var blocks = BlockHandler.ExtractBlocks(lines);
|
2019-09-21 18:52:00 -05:00
|
|
|
|
_logger.Debug($"Extracted {blocks.Count()} blocks.");
|
2014-08-10 11:10:21 -05:00
|
|
|
|
var story = BlockHandler.ParseBlocks(blocks);
|
2019-09-21 18:52:00 -05:00
|
|
|
|
_logger.Debug("Finished initial story breakdown.");
|
2018-09-25 16:29:53 -05:00
|
|
|
|
|
|
|
|
|
// dupe scene sanity check
|
|
|
|
|
foreach(var key in story.Scenes.Keys)
|
|
|
|
|
{
|
|
|
|
|
foreach(var scene in story.Scenes[key])
|
|
|
|
|
{
|
|
|
|
|
foreach(var otherScene in story.Scenes[key].Where(s => s != scene))
|
|
|
|
|
{
|
|
|
|
|
if((scene.Conditions == null && otherScene.Conditions == null)
|
|
|
|
|
|| (scene.Conditions != null && otherScene.Conditions != null
|
|
|
|
|
&& scene.Conditions.Count == otherScene.Conditions.Count
|
|
|
|
|
&& !scene.Conditions.Except(otherScene.Conditions).Any()))
|
2018-09-27 12:32:32 -05:00
|
|
|
|
Warnings.Add(new FicdownException(scene.Name, string.Format("Scene defined again on line {0}", otherScene.LineNumber), scene.LineNumber));
|
2018-09-25 16:29:53 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-10 11:10:21 -05:00
|
|
|
|
GameTraverser.Story = story;
|
2015-07-19 17:19:40 -05:00
|
|
|
|
var resolved = StateResolver.Resolve(GameTraverser.Enumerate(), story);
|
|
|
|
|
resolved.Orphans = GameTraverser.OrphanedScenes.Select(o => new Orphan
|
|
|
|
|
{
|
|
|
|
|
Type = "Scene",
|
|
|
|
|
Name = o.Name,
|
|
|
|
|
LineNumber = o.LineNumber
|
|
|
|
|
}).Union(GameTraverser.OrphanedActions.Select(o => new Orphan
|
|
|
|
|
{
|
|
|
|
|
Type = "Action",
|
|
|
|
|
Name = o.Toggle,
|
|
|
|
|
LineNumber = o.LineNumber
|
|
|
|
|
}));
|
|
|
|
|
return resolved;
|
2014-06-29 23:04:51 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|