Rewrite #2
6 changed files with 345 additions and 28 deletions
15
src/Bofa.bf
15
src/Bofa.bf
|
@ -4,8 +4,23 @@ using System;
|
|||
|
||||
class Bofa
|
||||
{
|
||||
private String _line = null; //The actual line
|
||||
private Bofa _lastObject = null; //If we are a container we keep track of the last container inside of us
|
||||
|
||||
public StringView Name;
|
||||
public EBofaType Type;
|
||||
public StringView Typename;
|
||||
public BofaValue Value;
|
||||
|
||||
public ~this()
|
||||
{
|
||||
if(_line != null)
|
||||
delete _line;
|
||||
if(Type == .Text)
|
||||
delete Value.Text;
|
||||
else if(Type == .Object)
|
||||
DeleteDictionaryAndValues!(Value.Object);
|
||||
else if(Type == .Array)
|
||||
DeleteContainerAndItems!(Value.Array);
|
||||
}
|
||||
}
|
|
@ -8,41 +8,283 @@ using Bofa.Parser;
|
|||
|
||||
class BofaParser
|
||||
{
|
||||
|
||||
public static Result<void, int64> Parse(StringView pToParse, List<Bofa> pResult)
|
||||
public static void Parse(StringView pToParse, List<Bofa> pResult, List<int64> pErrors)
|
||||
{
|
||||
StringStream stream = new .(pToParse, .Reference);
|
||||
defer delete stream;
|
||||
return Parse(stream, pResult);
|
||||
Parse(stream, pResult, pErrors);
|
||||
}
|
||||
|
||||
public static Result<void, int64> Parse(Stream pToParse, List<Bofa> pResult)
|
||||
public static void Parse(Stream pToParse, List<Bofa> pResult, List<int64> pErrors)
|
||||
{
|
||||
if(pToParse == null || pResult == null)
|
||||
return .Err(-1);
|
||||
if (pToParse == null || pResult == null)
|
||||
{ //Cannot parse what doesnt exist
|
||||
pErrors.Add(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
StreamReader reader = new .(pToParse);
|
||||
defer delete reader;
|
||||
|
||||
int64 line = 1;
|
||||
while(reader.Peek() case .Ok) //This might technically cause an issue when there is data added to the stream while we where busy processing, but if you hook this up to a network stream you deserve this happening to you
|
||||
while (reader.Peek() case .Ok) //This might technically cause an issue when there is data added to the stream while we where busy processing, but if you hook this up to a network stream you deserve this happening to you
|
||||
{
|
||||
String l = scope .();
|
||||
if(reader.ReadLine(l) case .Err)
|
||||
return .Err(-2);
|
||||
String l = new .();
|
||||
if (reader.ReadLine(l) case .Err)
|
||||
{ //Despite data being here, we cannot read it
|
||||
pErrors.Add(-2);
|
||||
return;
|
||||
}
|
||||
|
||||
var entry = ParseLine(l, line);
|
||||
if(!(entry.Type == .Bofa || entry.Type == .Text))
|
||||
delete l; //In these cases we have no useable data
|
||||
if(entry.Type == .Error)
|
||||
pErrors.Add(line);
|
||||
|
||||
//If we are on the lowest level we can just add them here
|
||||
if(entry.Depth == 0 && entry.Type ==.Bofa)
|
||||
{
|
||||
if(pResult.FindIndex(scope (x) => { return x.Name == entry.Data.Bofa.Name;}) < 0)
|
||||
pResult.Add(entry.Data.Bofa);
|
||||
else
|
||||
pErrors.Add(entry.Line); //Dublicate name error
|
||||
}
|
||||
else if(entry.Depth == 1 && entry.Type == .Text)
|
||||
{
|
||||
if(pResult[pResult.Count-1].Type == .Text)
|
||||
pResult[pResult.Count-1].Value.Text.Append(entry.Data.Text);
|
||||
else
|
||||
pErrors.Add(entry.Line); //Bad text error
|
||||
}
|
||||
|
||||
//if(pResult[pResult.Count-1].[Friend]_Insert(&entry) case .Err)
|
||||
//pErrors.Add(line);
|
||||
line++;
|
||||
}
|
||||
|
||||
return .Ok;
|
||||
return; //Being done normally
|
||||
}
|
||||
|
||||
private static ParserEntry ParseLine(StringView pLine, int64 pLineNumber)
|
||||
private static ParserEntry ParseLine(String pLine, int64 pLineNumber)
|
||||
{
|
||||
StringView line = pLine;
|
||||
ParserEntry toReturn = .();
|
||||
|
||||
uint32 depth;
|
||||
return .();
|
||||
toReturn.Line = pLineNumber;
|
||||
|
||||
#region Depth
|
||||
uint32 depth = 0;
|
||||
var hasContent = false; //In order to check wether it just ran out, or wether we actually have content
|
||||
for (var c in line)
|
||||
{
|
||||
if (c == ' ' || c == ' ')
|
||||
{
|
||||
depth++;
|
||||
continue;
|
||||
}
|
||||
else if (c == '#')
|
||||
{
|
||||
toReturn.Type = .Empty;
|
||||
return toReturn; //Comment
|
||||
}
|
||||
hasContent = true;
|
||||
break;
|
||||
}
|
||||
if (!hasContent)
|
||||
{
|
||||
toReturn.Type = .Empty;
|
||||
return toReturn; //Is empty
|
||||
}
|
||||
line = .(line, depth);
|
||||
toReturn.Depth = depth;
|
||||
#endregion
|
||||
|
||||
#region Type
|
||||
//Get the type of the line
|
||||
let type = NextPart(line);
|
||||
line = type.1;
|
||||
if (type.0 == "") //This should never be reached
|
||||
{
|
||||
Runtime.FatalError("Unreachable code reached");
|
||||
toReturn.Type = .Error;
|
||||
return toReturn;
|
||||
}
|
||||
else if (type.0 == "-")
|
||||
{
|
||||
toReturn.Type = .Text;
|
||||
toReturn.Data.Text = line;
|
||||
toReturn.Depth = depth + 1;
|
||||
return toReturn;
|
||||
|
||||
}
|
||||
//We have now assured, that the object we are handling is seemingly a normal one
|
||||
StringView typeName;
|
||||
switch (type.0)
|
||||
{
|
||||
case "c":
|
||||
let tnameres = NextPart(line);
|
||||
if (tnameres.0 == "")
|
||||
{ //Its of type custom but ends after the custom
|
||||
toReturn.Type = .Error;
|
||||
return toReturn;
|
||||
}
|
||||
line = tnameres.1;
|
||||
typeName = tnameres.0;
|
||||
case "n":
|
||||
typeName = "Number";
|
||||
case "b":
|
||||
typeName = "Boolean";
|
||||
case "l":
|
||||
typeName = "Line";
|
||||
case "bn":
|
||||
typeName = "BigNumber";
|
||||
case "i":
|
||||
typeName = "Integer";
|
||||
case "bi":
|
||||
typeName = "BigInteger";
|
||||
case "t":
|
||||
typeName = "Text";
|
||||
case "a":
|
||||
typeName = "Array";
|
||||
case "o":
|
||||
typeName = "Object";
|
||||
default:
|
||||
toReturn.Type = .Error;
|
||||
return toReturn; //Unsupported type error
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Name
|
||||
//Get the name and return if its a array or object
|
||||
let nameres = NextPart(line);
|
||||
line = nameres.1;
|
||||
if (nameres.0 == "")
|
||||
{
|
||||
toReturn.Type = .Error;
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
if (type.0 == "o" || type.0 == "a")
|
||||
{
|
||||
Bofa bofaRes = new Bofa();
|
||||
bofaRes.Name = nameres.0;
|
||||
bofaRes.Typename = typeName;
|
||||
if (type.0 == "o")
|
||||
{
|
||||
bofaRes.Type = .Object;
|
||||
bofaRes.Value.Object = new .();
|
||||
toReturn.Type = .Bofa;
|
||||
toReturn.Data.Bofa = bofaRes;
|
||||
return toReturn;
|
||||
}
|
||||
bofaRes.Type = .Array;
|
||||
bofaRes.Value.Array = new .();
|
||||
toReturn.Type = .Bofa;
|
||||
toReturn.Data.Bofa = bofaRes;
|
||||
return toReturn;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Value
|
||||
if (line == "")
|
||||
{
|
||||
toReturn.Type = .Error;
|
||||
return toReturn;
|
||||
}
|
||||
Bofa bofaRes = new .();
|
||||
bofaRes.Name = nameres.0;
|
||||
bofaRes.Typename = typeName;
|
||||
switch (type.0)
|
||||
{
|
||||
case "n":
|
||||
bofaRes.Type = .Number;
|
||||
var result = float.Parse(line);
|
||||
if (result case .Err)
|
||||
{
|
||||
delete bofaRes;
|
||||
toReturn.Type = .Error;
|
||||
return toReturn;
|
||||
}
|
||||
bofaRes.Value.Number = result.Value;
|
||||
case "b":
|
||||
if (line == "true")
|
||||
bofaRes.Value.Boolean = true;
|
||||
else if (line == "false")
|
||||
bofaRes.Value.Boolean = false;
|
||||
else
|
||||
{
|
||||
delete bofaRes;
|
||||
toReturn.Type = .Error;
|
||||
return toReturn;
|
||||
}
|
||||
bofaRes.Type = .Boolean;
|
||||
case "l":
|
||||
bofaRes.Value.Line = line;
|
||||
bofaRes.Type = .Line;
|
||||
case "bn":
|
||||
bofaRes.Type = .BigNumber;
|
||||
var result = double.Parse(line);
|
||||
if (result case .Err)
|
||||
{
|
||||
delete bofaRes;
|
||||
toReturn.Type = .Error;
|
||||
return toReturn;
|
||||
}
|
||||
bofaRes.Value.BigNumber = result.Value;
|
||||
case "i":
|
||||
bofaRes.Type = .Integer;
|
||||
var result = int32.Parse(line);
|
||||
if (result case .Err)
|
||||
{
|
||||
delete bofaRes;
|
||||
toReturn.Type = .Error;
|
||||
return toReturn;
|
||||
}
|
||||
bofaRes.Value.Integer = result.Value;
|
||||
case "bi":
|
||||
bofaRes.Type = .BigInteger;
|
||||
var result = int64.Parse(line);
|
||||
if (result case .Err)
|
||||
{
|
||||
delete bofaRes;
|
||||
toReturn.Type = .Error;
|
||||
return toReturn;
|
||||
}
|
||||
bofaRes.Value.BigInteger = result.Value;
|
||||
case "t":
|
||||
bofaRes.Value.Text = new String(line);
|
||||
bofaRes.Type = .Text;
|
||||
case "c":
|
||||
bofaRes.Value.Custom = line;
|
||||
bofaRes.Type = .Custom;
|
||||
default: //Unknown type
|
||||
delete bofaRes;
|
||||
toReturn.Type = .Error;
|
||||
return toReturn;
|
||||
}
|
||||
#endregion
|
||||
//If this ever returns something went wrong
|
||||
bofaRes.[Friend]_line = pLine;
|
||||
toReturn.Type = .Bofa;
|
||||
toReturn.Data.Bofa = bofaRes;
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
private static (StringView, StringView) NextPart(StringView pLine)
|
||||
{
|
||||
int i = 0;
|
||||
for (var c in pLine)
|
||||
{
|
||||
if (c == ' ')
|
||||
{
|
||||
if (@c.GetNext() case .Ok(let val))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return (.(pLine, 0, (i < pLine.Length) ? i - 1 : i), .(pLine, i));
|
||||
}
|
||||
}
|
|
@ -6,14 +6,14 @@ using System.Collections;
|
|||
[Union]
|
||||
struct BofaValue
|
||||
{
|
||||
StringView Line;
|
||||
StringView Text;
|
||||
float Number;
|
||||
double BigNumber;
|
||||
int32 Integer;
|
||||
int64 BigInteger;
|
||||
bool Boolean;
|
||||
String Custom;
|
||||
Bofa Object;
|
||||
Bofa Array;
|
||||
public StringView Line;
|
||||
public String Text;
|
||||
public float Number;
|
||||
public double BigNumber;
|
||||
public int32 Integer;
|
||||
public int64 BigInteger;
|
||||
public bool Boolean;
|
||||
public StringView Custom;
|
||||
public Dictionary<StringView, Bofa> Object;
|
||||
public List<Bofa> Array;
|
||||
}
|
42
src/Parser/BofaParserInsert.bf
Normal file
42
src/Parser/BofaParserInsert.bf
Normal file
|
@ -0,0 +1,42 @@
|
|||
namespace Bofa;
|
||||
|
||||
using Bofa.Parser;
|
||||
|
||||
using System;
|
||||
|
||||
extension Bofa
|
||||
{
|
||||
private Result<void> _Insert(ParserEntry* pToAdd)
|
||||
{
|
||||
//See if we can insert and do so
|
||||
if(pToAdd.Depth == 0 || (pToAdd.Type == .Text && pToAdd.Depth == 1))
|
||||
{
|
||||
if(pToAdd.Type == .Text && _lastObject.Type == .Text)
|
||||
{
|
||||
_lastObject.Value.Text.Append(pToAdd.Data.Text);
|
||||
return .Ok;
|
||||
}
|
||||
else if(_lastObject.Type == .Object)
|
||||
{
|
||||
_lastObject.Value.Object.Add(pToAdd.Data.Bofa.Name, pToAdd.Data.Bofa);
|
||||
_lastObject._lastObject = pToAdd.Data.Bofa;
|
||||
return .Ok;
|
||||
|
||||
}
|
||||
else if(_lastObject.Type == .Array)
|
||||
{
|
||||
_lastObject.Value.Array.Add(pToAdd.Data.Bofa);
|
||||
_lastObject._lastObject = pToAdd.Data.Bofa;
|
||||
return .Ok;
|
||||
}
|
||||
return .Err; //Cannot insert here
|
||||
}
|
||||
|
||||
//Can we even go deeper
|
||||
if(!(_lastObject.Type == .Object || _lastObject.Type == .Array))
|
||||
return .Err;
|
||||
|
||||
pToAdd.Depth--;
|
||||
return _lastObject._Insert(pToAdd);
|
||||
}
|
||||
}
|
|
@ -4,5 +4,6 @@ enum EParserEntryType
|
|||
{
|
||||
Bofa,
|
||||
Text,
|
||||
Empty
|
||||
Empty,
|
||||
Error
|
||||
}
|
|
@ -2,13 +2,30 @@ namespace Bofa.Testing;
|
|||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections;
|
||||
|
||||
class Default
|
||||
{
|
||||
[Test]
|
||||
public static void Default_Test_1()
|
||||
{
|
||||
BofaParser.Parse("Without an ending", scope .()).IgnoreError();
|
||||
|
||||
String content = """
|
||||
t text goes here
|
||||
- Text addendum
|
||||
""";
|
||||
List<Bofa> output = new .();
|
||||
List<int64> errors = new .();
|
||||
BofaParser.Parse(content, output, errors);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
DeleteContainerAndItems!(output);
|
||||
delete errors;
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue