using System.Collections.Generic; using System.Text; namespace SteamLanguageParser { interface ICodeGen { void EmitNamespace(StringBuilder sb, bool end, string nspace); void EmitSerialBase(StringBuilder sb, int level, bool supportsGC); void EmitNode(Node n, StringBuilder sb, int level); bool SupportsNamespace(); bool SupportsUnsignedTypes(); } class CodeGenerator { private class TypeInfo { public int Size { get; private set; } public bool Signed { get; private set; } public string SignedType { get; private set; } public TypeInfo(int size, string unsigned) { Size = size; Signed = false; SignedType = unsigned; } public TypeInfo(int size) { Size = size; Signed = true; } } private static readonly string defaultType = "uint"; private static readonly Dictionary weakTypeMap = new() { {"byte", new TypeInfo(1)}, {"short", new TypeInfo(2)}, {"ushort", new TypeInfo(2, "short")}, {"int", new TypeInfo(4)}, {"uint", new TypeInfo(4, "int")}, {"long", new TypeInfo(8)}, {"ulong", new TypeInfo(8, "long")}, }; public static string GetUnsignedType(string type) { if (weakTypeMap.TryGetValue(type, out var value) && !value.Signed) { return value.SignedType; } return type; } public static string GetTypeOfSize(int size, bool unsigned) { foreach (string key in weakTypeMap.Keys) { if (weakTypeMap[key].Size == size) { if (unsigned && weakTypeMap[key].Signed == false) { return key; } else if (weakTypeMap[key].Signed) { return key; } else if (!weakTypeMap[key].Signed) { return weakTypeMap[key].SignedType; } } } return "bad"; } public static int GetTypeSize(PropNode prop) { Symbol sym = prop.Type; // no static size for proto if (prop.Flags != null && prop.Flags == "proto") { return 0; } if (sym is WeakSymbol) { WeakSymbol wsym = sym as WeakSymbol; string key = wsym.Identifier; if (!weakTypeMap.ContainsKey(key)) { key = defaultType; } if (!string.IsNullOrEmpty(prop.FlagsOpt)) { return int.Parse(prop.FlagsOpt); } return weakTypeMap[key].Size; } else if (sym is StrongSymbol) { StrongSymbol ssym = sym as StrongSymbol; if (ssym.Class is EnumNode) { EnumNode enode = ssym.Class as EnumNode; if (enode.Type is WeakSymbol weakSymbol) { return weakTypeMap[weakSymbol.Identifier].Size; } else { return weakTypeMap[defaultType].Size; } } } return 0; } public static void EmitCode(Node root, ICodeGen gen, StringBuilder sb, string nspace, bool supportsGC, bool internalFile) { gen.EmitNamespace(sb, false, nspace); int level = 0; if (gen.SupportsNamespace()) { level = 1; } if (internalFile) { gen.EmitSerialBase(sb, level, supportsGC); } foreach (Node n in root.ChildNodes) { gen.EmitNode(n, sb, level); } gen.EmitNamespace(sb, true, nspace); } } }