diff --git a/BeefProj.toml b/BeefProj.toml index 0d15fdc..ddfd45a 100644 --- a/BeefProj.toml +++ b/BeefProj.toml @@ -2,5 +2,4 @@ FileVersion = 1 [Project] Name = "Bofa" -TargetType = "BeefLib" StartupObject = "Bofa.Program" diff --git a/src/Bofa.bf b/src/Bofa.bf index 55ae41b..324cd46 100644 --- a/src/Bofa.bf +++ b/src/Bofa.bf @@ -5,7 +5,18 @@ using System.Collections; class Bofa { - private String _line = null; //The actual line + private String __line = null; //The actual line + private String _line + { + get + { + return __line; + } + set + { + __line = value; + } + } private Bofa _lastObject = null; //If we are a container we keep track of the last container inside of us public StringView Name; @@ -136,11 +147,13 @@ class Bofa { if(_line != null) delete _line; + if(Type == .Text) delete Value.Text; } } + public ~this() { if(_line != null) @@ -183,4 +196,55 @@ class Bofa Value.Object[view] = value; } } + + public ref Bofa this[int view] + { + [Checked] + get + { + Runtime.Assert(Type == .Array); + Runtime.Assert(Value.Array.Count > view); + return ref Value.Array[view]; + } + + [Unchecked, Inline] + get + { + return ref Value.Array[view]; + } + + [Checked] + set + { + Runtime.Assert(Type == .Array); + Runtime.Assert(Value.Array.Count > view); + Value.Array[view] = value; + } + + [Unchecked, Inline] + set + { + Value.Array[view] = value; + } + } + + ///Get the value if the object is a container + public Result Get(StringView pKey) + { + if(Type != .Object) + return .Err; + if(!Value.Object.ContainsKey(pKey)) + return .Err; + return Value.Object[pKey]; + } + + ///Get the value if the object is a container + public Result Get(int pIndex) + { + if(Type != .Array) + return .Err; + if(!(Value.Array.Count > pIndex)) + return .Err; + return Value.Array[pIndex]; + } } \ No newline at end of file diff --git a/src/BofaParser.bf b/src/BofaParser.bf index b8b7593..3517bf9 100644 --- a/src/BofaParser.bf +++ b/src/BofaParser.bf @@ -32,31 +32,32 @@ class BofaParser 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 = new .(); + if (reader.ReadLine(l) case .Err) { //Despite data being here, we cannot read it delete l; pErrors.Add(-2); return; } - + var entry = ParseLine(l, line); - if(!(entry.Type == .Bofa || entry.Type == .Text)) + if (!(entry.Type == .Bofa || entry.Type == .Text)) delete l; //In these cases we have no useable data - if(entry.Type == .Empty) + if (entry.Type == .Empty) { line++; continue; } - if(entry.Type == .Error) + if (entry.Type == .Error) { pErrors.Add(line); continue; } //If we are on the lowest level we can just add them here - if(entry.Depth == 0 && entry.Type ==.Bofa) + if (entry.Depth == 0 && entry.Type == .Bofa) { - if(!pResult.ContainsKey(entry.Data.Bofa.Name)) + if (!pResult.ContainsKey(entry.Data.Bofa.Name)) { last = entry.Data.Bofa; pResult.Add(entry.Data.Bofa.Name, entry.Data.Bofa); @@ -67,27 +68,27 @@ class BofaParser delete entry.Data.Bofa; } } - else if(entry.Depth == 1 && entry.Type == .Text) + else if (entry.Depth == 1 && entry.Type == .Text) { - if(last.Type == .Text) + if (last.Type == .Text) last.Value.Text.Append(scope $"\n{entry.Data.Text}"); else - pErrors.Add(entry.Line); //Bad text error + pErrors.Add(entry.Line); //Bad text error + delete l; } else { entry.Depth--; - if(last.[Friend]_Insert(&entry) case .Err) + if (last.[Friend]_Insert(&entry) case .Err) { pErrors.Add(line); delete entry.Data.Bofa; } + else if (entry.Type == .Text) + delete l; } - if(entry.Type == .Text) - delete l; line++; } - return; //Being done normally } @@ -139,42 +140,41 @@ class BofaParser 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: + case "c": + let tnameres = NextPart(line); + if (tnameres.0 == "") + { //Its of type custom but ends after the custom toReturn.Type = .Error; - return toReturn; //Unsupported 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 @@ -215,77 +215,77 @@ class BofaParser { 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 + 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 diff --git a/src/Extension.bf b/src/Extension.bf index d0898b5..bacdd8c 100644 --- a/src/Extension.bf +++ b/src/Extension.bf @@ -1,3 +1,5 @@ +using Bofa.Serialization; + namespace System { static @@ -7,4 +9,23 @@ namespace System *(T*)(void*)&v } } + + extension Int : IBofaParseable + { + public bool Serialize(Bofa.Bofa pTarget) + { + pTarget.Type = .Integer; + pTarget.Typename = "Integer"; + pTarget.Value.Integer = (.)this; + return true; + } + + public bool Deserialize(Bofa.Bofa pInput) mut + { + if(pInput.Type != .Integer) + return false; + this = (.)pInput.Value.Integer; + return true; + } + } } \ No newline at end of file diff --git a/src/Program.bf b/src/Program.bf new file mode 100644 index 0000000..33ef40b --- /dev/null +++ b/src/Program.bf @@ -0,0 +1,20 @@ +namespace Bofa; + +using System; +using System.Collections; + +class Program +{ + + public static void Main() + { + + Bofa.Testing.Profiling.Profiling_Depth_Testing(); + Bofa.Testing.Profiling.Profiling_Depth_Testing_Medium(); + Bofa.Testing.Profiling.Profiling_Normal(); + Bofa.Testing.Profiling.Profiling_Normal_Medium(); + Bofa.Testing.Profiling.Profiling_Normal_Large(); + Bofa.Testing.Profiling.Profiling_Texts(); + Bofa.Testing.Profiling.Profiling_Texts_Large(); + } +} \ No newline at end of file diff --git a/src/Serialization/BofaIncludeAttribute.bf b/src/Serialization/BofaIncludeAttribute.bf new file mode 100644 index 0000000..515a068 --- /dev/null +++ b/src/Serialization/BofaIncludeAttribute.bf @@ -0,0 +1,13 @@ +namespace Bofa.Serialization; + +using System; + +struct BofaIncludeAttribute : Attribute +{ + public StringView Name; + + public this(StringView pName) + { + Name = pName; + } +} \ No newline at end of file diff --git a/src/Serialization/BofaSerializeAttribute.bf b/src/Serialization/BofaSerializeAttribute.bf new file mode 100644 index 0000000..c3a17f6 --- /dev/null +++ b/src/Serialization/BofaSerializeAttribute.bf @@ -0,0 +1,112 @@ +namespace Bofa.Serialization; + +using System; +using System.Reflection; + +using Bofa; + +[AttributeUsage(.Struct | .Class)] +struct BofaSerializeAttribute : Attribute, IOnTypeInit +{ + [Comptime] + public void OnTypeInit(Type type, Self* prev) + { + String serializeString = scope .("public bool Serialize(Bofa b)\n{\n"); + String deserializeString = scope .("public bool Deserialize(Bofa b)\n{\n"); + + serializeString.Append(""" + b.Type = .Object; + b.Value.Object = new .(); + b.Typename = "Object"; + Bofa toAdd; + + """); + + deserializeString.Append(""" + if(b.Type != .Object) + return false; + + """); + + + var fields = type.GetFields(); + for(var f in fields) + { + if(!f.IsPublic && !f.HasCustomAttribute()) + continue; + + bool hasIFace = false; + for(var i in f.FieldType.Interfaces) + if(i == typeof(IBofaParseable)) + hasIFace = true; + + //Hardcoded stuff + if(f.FieldType == typeof(int)) + hasIFace = true; + else if(f.FieldType == typeof(int8)) + hasIFace = true; + else if(f.FieldType == typeof(int16)) + hasIFace = true; + else if(f.FieldType == typeof(int32)) + hasIFace = true; + else if(f.FieldType == typeof(int64)) + hasIFace = true; + else if(f.FieldType == typeof(uint)) + hasIFace = true; + else if(f.FieldType == typeof(uint8)) + hasIFace = true; + else if(f.FieldType == typeof(uint16)) + hasIFace = true; + else if(f.FieldType == typeof(uint32)) + hasIFace = true; + else if(f.FieldType == typeof(uint64)) + hasIFace = true; + else if(f.FieldType == typeof(char8)) + hasIFace = true; + else if(f.FieldType == typeof(char16)) + hasIFace = true; + else if(f.FieldType == typeof(char32)) + hasIFace = true; + else if(f.FieldType == typeof(float)) + hasIFace = true; + else if(f.FieldType == typeof(double)) + hasIFace = true; + + if(!hasIFace) + continue; + + + StringView name; + name = f.Name; + if(f.HasCustomAttribute() && f.GetCustomAttribute() case .Ok(let attr)) + name = attr.Name; + + serializeString.Append(scope $""" + toAdd = new .(); + toAdd.Name = "{name}"; + if(!{f.Name}.Serialize(toAdd)) + \{ + delete toAdd; + return false; + \} + else + b.Value.Object.Add("{name}", toAdd); + """); + + deserializeString.Append(scope $""" + if(!b.Value.Object.ContainsKey("{name}")) + return false; + if(!{f.Name}.Deserialize(b.Value.Object["{name}"])) + return false; + """); + + } + + + serializeString.Append("\n\treturn true;\n}\n"); + deserializeString.Append("\n\treturn true;\n}\n"); + Compiler.EmitTypeBody(type, serializeString); + Compiler.EmitTypeBody(type, deserializeString); + Compiler.EmitAddInterface(type, typeof(IBofaParseable)); + } +} \ No newline at end of file diff --git a/src/Serialization/IBofaParseable.bf b/src/Serialization/IBofaParseable.bf new file mode 100644 index 0000000..9cd8314 --- /dev/null +++ b/src/Serialization/IBofaParseable.bf @@ -0,0 +1,11 @@ +namespace Bofa.Serialization; + +using System; + +interface IBofaParseable +{ + ///Serializes the current state of a bofa object, may allocate subobjects to fill + public bool Serialize(Bofa pTarget) mut; + ///Attempt to restore an object from the bofa input state + public bool Deserialize(Bofa pInput) mut; +} \ No newline at end of file diff --git a/src/Testing/Fuzzing.bf b/src/Testing/Fuzzing.bf index 4374964..08ddd0a 100644 --- a/src/Testing/Fuzzing.bf +++ b/src/Testing/Fuzzing.bf @@ -7,7 +7,7 @@ using System.Collections; class Fuzzing { - [Test(Name = "Fuzzing - 10 * 1000000 random characters")] + //[Test(Name = "Fuzzing - 10 * 1000000 random characters")] public static void Fuzzin_Random() { for (int i < 10) @@ -25,7 +25,7 @@ class Fuzzing } } - [Test(Name = "Fuzzing - 10 * 10000000 random characters")] + //[Test(Name = "Fuzzing - 10 * 10000000 random characters")] public static void Fuzzin_Random_Large() { for (int i < 10) diff --git a/src/Testing/Serialization.bf b/src/Testing/Serialization.bf new file mode 100644 index 0000000..6baaa0a --- /dev/null +++ b/src/Testing/Serialization.bf @@ -0,0 +1,25 @@ +namespace Bofa.Testing; + +using System; + +using Bofa; +using Bofa.Serialization; + +[BofaSerialize] +class Serialization +{ + public int anInteger = (.)1; + + [Test] + public static void Test() + { + Serialization s = scope .(); + Bofa b = scope .(); + b.Name = "s"; + s.Serialize(b); + + Console.WriteLine(b.ToString(.. scope .())); + //Console.Read(); + } + +} \ No newline at end of file