From 61ba72f10a81694f3299850244f82cc4ebc24e6e Mon Sep 17 00:00:00 2001 From: Adrian Conlon <98398945+AdrianConlon@users.noreply.github.com> Date: Tue, 24 Sep 2024 21:40:43 +0100 Subject: [PATCH] Fully embrace reflected method of parsing symbols --- M6502/M6502.Symbols/File.cs | 3 +- M6502/M6502.Symbols/IdentifiableSection.cs | 112 +++++---- M6502/M6502.Symbols/Information.cs | 1 + M6502/M6502.Symbols/Line.cs | 7 +- M6502/M6502.Symbols/Module.cs | 3 +- M6502/M6502.Symbols/Parser.cs | 233 ++++++------------ .../ReflectedSectionProperties.cs | 60 +++-- M6502/M6502.Symbols/Scope.cs | 27 +- M6502/M6502.Symbols/Section.cs | 99 ++++---- M6502/M6502.Symbols/SectionAttribute.cs | 16 ++ .../M6502.Symbols/SectionPropertyAttribute.cs | 4 +- .../SectionReferenceAttribute.cs | 2 +- M6502/M6502.Symbols/Segment.cs | 1 + M6502/M6502.Symbols/Span.cs | 5 +- M6502/M6502.Symbols/Symbol.cs | 9 +- M6502/M6502.Symbols/Type.cs | 1 + M6502/M6502.Symbols/Version.cs | 1 + 17 files changed, 266 insertions(+), 318 deletions(-) create mode 100644 M6502/M6502.Symbols/SectionAttribute.cs diff --git a/M6502/M6502.Symbols/File.cs b/M6502/M6502.Symbols/File.cs index 4de63be..4977bed 100644 --- a/M6502/M6502.Symbols/File.cs +++ b/M6502/M6502.Symbols/File.cs @@ -5,6 +5,7 @@ namespace Symbols { // file id=0,name="sudoku.s",size=9141,mtime=0x6027C7F0,mod=0 + [Section("file", "Files")] public sealed class File(Parser container) : NamedSection(container) { [SectionProperty("size")] @@ -14,7 +15,7 @@ public DateTime ModificationTime { get; private set; } [SectionReference("mod")] - public Symbols.Module Module => this.TakeModuleReference(); + public Symbols.Module? Module { get; private set; } } } } diff --git a/M6502/M6502.Symbols/IdentifiableSection.cs b/M6502/M6502.Symbols/IdentifiableSection.cs index 602a729..d526d77 100644 --- a/M6502/M6502.Symbols/IdentifiableSection.cs +++ b/M6502/M6502.Symbols/IdentifiableSection.cs @@ -4,7 +4,8 @@ { namespace Symbols { - using System.Collections.Generic; + using System.Collections; + using System.Diagnostics; public class IdentifiableSection : Section { @@ -15,67 +16,80 @@ : base(container) {} - #region Foreign key constraints - - #region Generic FK access - - protected static T TakeReference(int key, List? from) where T : IdentifiableSection + private bool MaybeExtractFromParsed(string key, out string value) { - ArgumentNullException.ThrowIfNull(from); - var identifiable = from[key]; - ArgumentOutOfRangeException.ThrowIfNotEqual(identifiable.ID, key, nameof(key)); - return identifiable; - } - - protected T TakeReference(string key, List? from) where T : IdentifiableSection => TakeReference(this.TakeInteger(key), from); - - protected T? MaybeTakeReference(string key, List? from) where T : IdentifiableSection - { - var id = this.MaybeTakeInteger(key); - return id == null ? null : TakeReference(id.Value, from); - } - - protected List TakeReferences(string key, List? from) where T : IdentifiableSection - { - ArgumentNullException.ThrowIfNull(from); - var ids = this.MaybeTakeMultiple(key); - if (ids != null) + Debug.Assert(this._parsed != null); + var found = this._parsed.TryGetValue(key, out var extracted); + if (found) { - var returned = new List(ids.Count); - foreach (var id in ids) - { - returned.Add(from[id]); - } - return returned; + Debug.Assert(extracted != null); + value = extracted; } - return []; + else + { + value = string.Empty; + } + return found; } - #endregion + private bool MaybeExtractIntegerFromParsed(string key, out int value) + { + var available = this.MaybeExtractFromParsed(key, out var extracted); + if (!available) + { + value = 0; + return false; + } + value = ExtractInteger(extracted); + return available; + } - #region Specific FK access + private void SetProperty(string name, object obj) + { + var type = this.GetType(); + var property = type.GetProperty(name); + Debug.Assert(property != null); + property.SetValue(this, obj); + } - protected Module TakeModuleReference(string key = "mod") => this.TakeReference(key, this._container?.Modules); + public void ExtractReferences() + { + var sectionProperties = this.SectionProperties; + foreach (var (entryName, connection) in sectionProperties.ReferenceAttributes) + { + var hasID = this.MaybeExtractIntegerFromParsed(entryName, out var id); + if (!hasID) + { + continue; + } - protected File TakeFileReference(string key = "file") => this.TakeReference(key, this._container?.Files); + var (name, type, attribute) = connection; - protected Type TakeTypeReference(string key = "type") => this.TakeReference(key, this._container?.Types); + // The reference container in the parent class + var referenceSectionProperties = GetSectionProperties(type); + var referenceClassAttribute = referenceSectionProperties.ClassAttribute; + Debug.Assert(referenceClassAttribute != null); + var referencingContainer = referenceClassAttribute.Referencing; - protected Segment TakeSegmentReference(string key = "seg") => this.TakeReference(key, this._container?.Segments); + // Get the parent container field + var containerType = this._container.GetType(); + Debug.Assert(referencingContainer != null); + var containerField = containerType.GetField(referencingContainer); + Debug.Assert(containerField != null); + var fieldValue = containerField.GetValue(this._container); + var fieldList = fieldValue as IList; - protected Scope TakeScopeReference(string key = "scope") => this.TakeReference(key, this._container?.Scopes); + // The reference ID - protected Scope? MaybeTakeParentReference(string key = "parent") => this.MaybeTakeReference(key, this._container?.Scopes); + // Now get the referenced object from the parent container field (via ID as an index) + Debug.Assert(fieldList != null); + var referencingObject = fieldList[id]; - protected Symbol? MaybeTakeSymbolReference(string key = "sym") => this.MaybeTakeReference(key, this._container?.Symbols); - - protected List TakeSpanReferences(string key = "span") => this.TakeReferences(key, this._container?.Spans); - - protected List TakeLineReferences(string key) => this.TakeReferences(key, this._container?.Lines); - - #endregion - - #endregion + // Now set our reference field + Debug.Assert(referencingObject != null); + this.SetProperty(name, referencingObject); + } + } } } } diff --git a/M6502/M6502.Symbols/Information.cs b/M6502/M6502.Symbols/Information.cs index 52aeff6..965be62 100644 --- a/M6502/M6502.Symbols/Information.cs +++ b/M6502/M6502.Symbols/Information.cs @@ -5,6 +5,7 @@ namespace Symbols { //info csym = 0, file = 3, lib = 0, line = 380, mod = 1, scope = 12, seg = 8, span = 356, sym = 61, type = 3 + [Section("info")] public sealed class Information(Parser container) : Section(container) { [SectionProperty("csym")] diff --git a/M6502/M6502.Symbols/Line.cs b/M6502/M6502.Symbols/Line.cs index 3d86f0b..c012f1b 100644 --- a/M6502/M6502.Symbols/Line.cs +++ b/M6502/M6502.Symbols/Line.cs @@ -5,22 +5,23 @@ namespace Symbols { // line id = 268, file = 1, line = 60, type = 2, count = 1, span = 286 + 195 + [Section("line", "Lines")] public sealed class Line(Parser container) : IdentifiableSection(container) { [SectionReference("file")] - public Symbols.File File => this.TakeFileReference(); + public Symbols.File? File { get; private set; } [SectionProperty("line")] public int LineNumber { get; private set; } [SectionReference("type")] - public Symbols.Type Type => this.TakeTypeReference(); + public Symbols.Type? Type { get; private set; } [SectionProperty("count")] public int? Count { get; private set; } [SectionReferences("span")] - public List Spans => this.TakeSpanReferences(); + public List? Spans { get; private set; } } } } diff --git a/M6502/M6502.Symbols/Module.cs b/M6502/M6502.Symbols/Module.cs index 86f4796..f3a3be2 100644 --- a/M6502/M6502.Symbols/Module.cs +++ b/M6502/M6502.Symbols/Module.cs @@ -5,10 +5,11 @@ namespace Symbols { // mod id=0,name="sudoku.o",file=0 + [Section("mod", "Modules")] public sealed class Module(Parser container) : NamedSection(container) { [SectionReference("file")] - public Symbols.File File => this.TakeFileReference(); + public Symbols.File? File { get; private set; } } } } diff --git a/M6502/M6502.Symbols/Parser.cs b/M6502/M6502.Symbols/Parser.cs index f53049f..459c80d 100644 --- a/M6502/M6502.Symbols/Parser.cs +++ b/M6502/M6502.Symbols/Parser.cs @@ -13,123 +13,29 @@ #region Variables, properties etc. // Section -> Unique ID list of dictionary entries - private readonly Dictionary>> _parsed = []; private Version? _version; private Information? _information; - private List? _files; - private List? _lines; - private List? _modules; - private List? _segments; - private List? _spans; - private List? _scopes; - private List? _symbols; - private List? _types; + public Dictionary>> Parsed { get; } = []; - public ref List? Files - { - get - { - if (this._files == null) - { - this.ExtractFiles(); - } + public List
SectionEntries { get; } = []; - return ref this._files; - } - } + public List Files = []; - public ref List? Lines - { - get - { - if (this._lines == null) - { - this.ExtractLines(); - } + public List Lines = []; - return ref this._lines; - } - } + public List Modules = []; - public ref List? Modules - { - get - { - if (this._modules == null) - { - this.ExtractModules(); - } + public List Segments = []; - return ref this._modules; - } - } + public List Spans = []; - public ref List? Segments - { - get - { - if (this._segments == null) - { - this.ExtractSegments(); - } + public List Scopes = []; - return ref this._segments; - } - } + public List Symbols = []; - public ref List? Spans - { - get - { - if (this._spans == null) - { - this.ExtractSpans(); - } - - return ref this._spans; - } - } - - public ref List? Scopes - { - get - { - if (this._scopes == null) - { - this.ExtractScopes(); - } - - return ref this._scopes; - } - } - - public ref List? Symbols - { - get - { - if (this._symbols == null) - { - this.ExtractSymbols(); - } - - return ref this._symbols; - } - } - - public ref List? Types - { - get - { - if (this._types == null) - { - this.ExtractTypes(); - } - - return ref this._types; - } - } + public List Types = []; // Symbol sub-types public IEnumerable Labels => this.SelectSymbolsByType("lab"); @@ -160,8 +66,6 @@ #region Lookups - private static IEnumerable SelectNameMatching(string name, IEnumerable? items) where T : NamedSection => from item in items where item.Name == name select item; - private static IEnumerable SelectIdMatching(int id, IEnumerable? items) where T : IdentifiableSection => from item in items where item.ID == id select item; private IEnumerable SelectSymbolsByType(string type) => from symbol in this.Symbols where symbol.Type == type select symbol; @@ -176,14 +80,6 @@ return labels.Count > 0 ? labels[0] : null; } - private IEnumerable LookupLabelsByName(string name) => SelectNameMatching(name, this.Labels); - - public Symbol? LookupLabelByName(string name) - { - var labels = this.LookupLabelsByName(name).ToList(); - return labels.Count > 0 ? labels[0] : null; - } - private IEnumerable LookupLabelsByID(int id) => SelectIdMatching(id, this.Labels); public Symbol? LookupLabelByID(int id) @@ -263,8 +159,9 @@ #region Scope evaluation - private static List EvaluateScope(Scope start) + private static List EvaluateScope(Scope? start) { + Debug.Assert(start != null); var returned = new List(); for (var current = start; current.Parent != null; current = current.Parent) { @@ -334,7 +231,57 @@ #endregion - #region Metadata lookup + #region Section extractors + + private void ExtractSections() + { + this.ExtractFiles(); + this.ExtractLines(); + this.ExtractModules(); + this.ExtractSegments(); + this.ExtractSpans(); + this.ExtractScopes(); + this.ExtractSymbols(); + this.ExtractTypes(); + } + + private void ExtractFiles() => this.Extract("file", this.Files); + + private void ExtractLines() => this.Extract("line", this.Lines); + + private void ExtractModules() => this.Extract("mod", this.Modules); + + private void ExtractSegments() => this.Extract("seg", this.Segments); + + private void ExtractSpans() => this.Extract("span", this.Spans); + + private void ExtractScopes() => this.Extract("scope", this.Scopes); + + private void ExtractSymbols() => this.Extract("sym", this.Symbols); + + private void ExtractTypes() => this.Extract("type", this.Types); + + private void Extract(string key, List into) where T : IdentifiableSection + { + if (!this.Parsed.TryGetValue(key, out var parsed)) + { + throw new ArgumentOutOfRangeException(nameof(key), key, "Debugging section is unavailable"); + } + + into.Capacity = parsed.Count; + for (var id = 0; id < parsed.Count; ++id) + { + Debug.Assert(into.Count == id); + var entry = (T?)Activator.CreateInstance(typeof(T), this); + Debug.Assert(entry != null); + var information = parsed[id]; + entry.Parse(information); + into.Add(entry); + } + Debug.Assert(into.Count == parsed.Count); + + this.VerifyInformationCount(key, into.Count); + } private void VerifyInformationCount(string key, int actual) { @@ -348,50 +295,15 @@ #endregion - #region Section extractors + #region Reference extractors - private void ExtractFiles() => this.Extract("file", ref this._files); - - private void ExtractLines() => this.Extract("line", ref this._lines); - - private void ExtractModules() => this.Extract("mod", ref this._modules); - - private void ExtractSegments() => this.Extract("seg", ref this._segments); - - private void ExtractSpans() => this.Extract("span", ref this._spans); - - private void ExtractScopes() => this.Extract("scope", ref this._scopes); - - private void ExtractSymbols() => this.Extract("sym", ref this._symbols); - - private void ExtractTypes() => this.Extract("type", ref this._types); - - private void Extract(string key, ref List? into) where T : IdentifiableSection + private void ExtractReferences() { - if (this._parsed.Count == 0) + foreach (var entry in this.SectionEntries) { - into = []; - return; + var identifiableEntry = entry as IdentifiableSection; + identifiableEntry?.ExtractReferences(); } - - if (!this._parsed.TryGetValue(key, out var parsed)) - { - throw new ArgumentOutOfRangeException(nameof(key), key, "Debugging section is unavailable"); - } - - into = new List(parsed.Count); - for (var id = 0; id < parsed.Count; ++id) - { - Debug.Assert(into.Count == id); - var entry = (T?)Activator.CreateInstance(typeof(T), this); - Debug.Assert(entry != null); - var information = parsed[id]; - entry.Parse(information); - into.Add(entry); - } - Debug.Assert(into.Count == parsed.Count); - - this.VerifyInformationCount(key, into.Count); } #endregion @@ -407,6 +319,9 @@ using var reader = new StreamReader(path); await this.ParseAsync(reader); + + this.ExtractSections(); + this.ExtractReferences(); } private async Task ParseAsync(StreamReader reader) @@ -458,10 +373,10 @@ private void Parse(string key, string[] parts) { - if (!this._parsed.TryGetValue(key, out var section)) + if (!this.Parsed.TryGetValue(key, out var section)) { - this._parsed[key] = []; - section = this._parsed[key]; + this.Parsed[key] = []; + section = this.Parsed[key]; } var dictionary = BuildDictionary(parts); diff --git a/M6502/M6502.Symbols/ReflectedSectionProperties.cs b/M6502/M6502.Symbols/ReflectedSectionProperties.cs index 8f9cd99..ebe3553 100644 --- a/M6502/M6502.Symbols/ReflectedSectionProperties.cs +++ b/M6502/M6502.Symbols/ReflectedSectionProperties.cs @@ -10,7 +10,6 @@ public sealed class ReflectedSectionProperties { private readonly Dictionary _entriesToProperties = []; - private readonly Dictionary _propertiesToEntries = []; public HashSet StringKeys { get; } = []; public HashSet EnumerationKeys { get; } = []; @@ -23,8 +22,23 @@ public Dictionary Properties { get; } = []; + internal SectionAttribute? ClassAttribute { get; } + + internal Dictionary> Attributes { get; } = []; + + internal Dictionary> ReferenceAttributes { get; } = []; + + internal Dictionary> ReferencesAttributes { get; } = []; + public ReflectedSectionProperties(System.Type type) { + var sectionAttributes = type.GetCustomAttributes(typeof(SectionAttribute), true); + Debug.Assert(sectionAttributes != null, "No section attributes available"); + Debug.Assert(sectionAttributes.Length == 1, "Must be a single section attribute available"); + var sectionAttribute = sectionAttributes[0]; + Debug.Assert(sectionAttribute != null, "Section attribute cannot be null"); + this.ClassAttribute = (SectionAttribute)sectionAttribute; + foreach (var property in type.GetProperties()) { this.ProcessPropertyAttributes(property); @@ -42,29 +56,27 @@ return propertyName; } - public string GetEntryNameFromPropertyName(string name) - { - var found = this._propertiesToEntries.TryGetValue(name, out var entryName); - if (!found) - { - throw new ArgumentOutOfRangeException(nameof(name), name, "Missing entry mapping"); - } - Debug.Assert(entryName != null); - return entryName; - } - - public object? GetValue(object? obj, string key) + private PropertyInfo GetPropertyFromEntryName(string key) { var propertyName = this.GetPropertyNameFromEntryName(key); var propertyAvailable = this.Properties.TryGetValue(propertyName, out var property); Debug.Assert(propertyAvailable); - Debug.Assert(property != null); - var readable = property?.CanRead; - Debug.Assert(readable != null); - Debug.Assert(readable.Value); + return property; + } - return property?.GetValue(obj); + public object? GetValue(object? obj, string key) + { + var property = this.GetPropertyFromEntryName(key); + Debug.Assert(property.CanRead); + return property.GetValue(obj); + } + + public void SetValue(object? obj, string key, object? value) + { + var property = this.GetPropertyFromEntryName(key); + Debug.Assert(property.CanWrite); + property.SetValue(obj, value); ; } public T? MaybeGetValue(object? obj, string key) => (T?)this.GetValue(obj, key); @@ -150,9 +162,17 @@ throw new InvalidOperationException($"Entry {key} from attribute has already been added"); } - if (!_propertiesToEntries.TryAdd(name, key)) + this.Attributes.Add(key, new Tuple(name, originalType, attribute)); + Debug.Assert(this.Attributes.Count == this.Properties.Count); + + if (attribute is SectionReferenceAttribute referenceAttribute) { - throw new ArgumentOutOfRangeException(nameof(name), name, "Property has already been added"); + var success = this.ReferenceAttributes.TryAdd(key, new Tuple(name, originalType, referenceAttribute)); + Debug.Assert(success); + } else if (attribute is SectionReferencesAttribute referencesAttribute) + { + var success = this.ReferencesAttributes.TryAdd(key, new Tuple(name, originalType, referencesAttribute)); + Debug.Assert(success); } var multiples = attribute.Many; diff --git a/M6502/M6502.Symbols/Scope.cs b/M6502/M6502.Symbols/Scope.cs index 93d79f5..285934f 100644 --- a/M6502/M6502.Symbols/Scope.cs +++ b/M6502/M6502.Symbols/Scope.cs @@ -7,10 +7,11 @@ //scope id = 0, name = "", mod = 0, size = 1137, span = 355 + 354 //scope id = 1, name = "stack", mod = 0, type = scope, size = 7, parent = 0, span = 15 //scope id = 7, name = "print_box_break_vertical", mod = 0, type = scope, size = 6, parent = 0, sym = 33, span = 72 + [Section("scope", "Scopes")] public sealed class Scope(Parser container) : NamedSection(container) { [SectionReference("mod")] - public Symbols.Module Module => this.TakeModuleReference(); + public Symbols.Module? Module { get; private set; } [SectionProperty("type")] public string? Type { get; private set; } @@ -18,28 +19,14 @@ [SectionProperty("size")] public int Size { get; private set; } - [SectionReference("parent")] - public Scope? Parent => this.MaybeTakeParentReference(); + [SectionReference("parent", optional: true)] + public Scope? Parent { get; private set; } - private bool _symbolAvailable; - private Symbols.Symbol? _symbol; - - [SectionReference("sym")] - public Symbols.Symbol? Symbol - { - get - { - if (!this._symbolAvailable) - { - this._symbol = this.MaybeTakeSymbolReference(); - this._symbolAvailable = true; - } - return this._symbol; - } - } + [SectionReference("sym", optional: true)] + public Symbols.Symbol? Symbol { get; private set; } [SectionReferences("span")] - public List Spans => this.TakeSpanReferences(); + public List? Spans { get; private set; } } } } diff --git a/M6502/M6502.Symbols/Section.cs b/M6502/M6502.Symbols/Section.cs index 6d0f557..fec0cca 100644 --- a/M6502/M6502.Symbols/Section.cs +++ b/M6502/M6502.Symbols/Section.cs @@ -17,19 +17,20 @@ protected readonly Parser _container; - protected readonly Dictionary _integers = []; - protected readonly Dictionary> _multiples = []; + // Needed to evaluate references on a second pass + protected readonly Dictionary _references = []; + protected readonly Dictionary> _multipleReferences = []; - protected ReflectedSectionProperties SectionProperties + protected Dictionary? _parsed; + + protected ReflectedSectionProperties SectionProperties => GetSectionProperties(this.GetType()); + + protected static ReflectedSectionProperties GetSectionProperties(System.Type type) { - get - { - var type = this.GetType(); - var obtained = _sectionPropertiesCache.TryGetValue(type, out var properties); - Debug.Assert(obtained, $"Section properties for {type.Name} have not been built"); - Debug.Assert(properties != null); - return properties; - } + var obtained = _sectionPropertiesCache.TryGetValue(type, out var properties); + Debug.Assert(obtained, $"Section properties for {type.Name} have not been built"); + Debug.Assert(properties != null); + return properties; } protected Section(Parser container) => this._container = container; @@ -44,14 +45,12 @@ } } - public object? GetValue(string key) => this.SectionProperties.GetValue(this, key); - - public T? MaybeGetValue(string key) => this.SectionProperties.MaybeGetValue(this, key); - public T GetValueT(string key) => this.SectionProperties.GetValueT(this, key); - public virtual void Parse(IDictionary entries) + public virtual void Parse(Dictionary entries) { + this._parsed = entries; + this._container.SectionEntries.Add(this); this.ProcessAttributesOfProperties(); foreach (var entry in entries) { @@ -63,9 +62,8 @@ private void Parse(string key, string value) { - var sectionProperties = this.SectionProperties; - var propertyName = sectionProperties.GetPropertyNameFromEntryName(key); - var propertyAvailable = sectionProperties.Properties.TryGetValue(propertyName, out var property); + var propertyName = this.SectionProperties.GetPropertyNameFromEntryName(key); + var propertyAvailable = this.SectionProperties.Properties.TryGetValue(propertyName, out var property); if (!propertyAvailable) { throw new InvalidOperationException($"Unable to locate property name {propertyName} using reflection"); @@ -76,64 +74,56 @@ private void Parse(PropertyInfo property, string key, string value) { - if (property.CanWrite) - { - this.ParseValueProperty(property, key, value); } - else - { - this.ParseReferenceProperty(key, value); - } - } + var reference = this.SectionProperties.ReferenceAttributes.ContainsKey(key); + var references = this.SectionProperties.ReferencesAttributes.ContainsKey(key); + var lazy = reference || references; - private void ParseReferenceProperty(string key, string value) - { - var sectionProperties = this.SectionProperties; - if (sectionProperties.IntegerKeys.Contains(key)) + if (lazy) { - this._integers.Add(key, ExtractInteger(value)); + if (reference) + { + this._references[key] = ExtractInteger(value); + } + else if (references) + { + this._multipleReferences[key] = ExtractCompoundInteger(value); + } + else + { + throw new InvalidOperationException("Getting here should be impossible! Lazy, but not a reference"); + } + return; } - else if (sectionProperties.MultipleKeys.Contains(key)) - { - this._multiples.Add(key, ExtractCompoundInteger(value)); - } - else - { - throw new InvalidOperationException($"Doesn't appear to be a valid reference type: {key}"); - } - } - private void ParseValueProperty(PropertyInfo property, string key, string value) - { - var sectionProperties = this.SectionProperties; - if (sectionProperties.StringKeys.Contains(key)) + if (this.SectionProperties.StringKeys.Contains(key)) { property?.SetValue(this, ExtractString(value)); } - else if (sectionProperties.EnumerationKeys.Contains(key)) + else if (this.SectionProperties.EnumerationKeys.Contains(key)) { property?.SetValue(this, ExtractEnumeration(value)); } - else if (sectionProperties.IntegerKeys.Contains(key)) + else if (this.SectionProperties.IntegerKeys.Contains(key)) { property?.SetValue(this, ExtractInteger(value)); } - else if (sectionProperties.HexIntegerKeys.Contains(key)) + else if (this.SectionProperties.HexIntegerKeys.Contains(key)) { property?.SetValue(this, ExtractHexInteger(value)); } - else if (sectionProperties.LongKeys.Contains(key)) + else if (this.SectionProperties.LongKeys.Contains(key)) { property?.SetValue(this, ExtractLong(value)); } - else if (sectionProperties.HexLongKeys.Contains(key)) + else if (this.SectionProperties.HexLongKeys.Contains(key)) { property?.SetValue(this, ExtractHexLong(value)); } - else if (sectionProperties.DateTimeKeys.Contains(key)) + else if (this.SectionProperties.DateTimeKeys.Contains(key)) { property?.SetValue(this, ExtractDateTime(value)); } - else if (sectionProperties.MultipleKeys.Contains(key)) + else if (this.SectionProperties.MultipleKeys.Contains(key)) { property?.SetValue(this, ExtractCompoundInteger(value)); } @@ -143,11 +133,6 @@ } } - protected int? MaybeTakeInteger(string key) => this._integers.TryGetValue(key, out var value) ? value : null; - protected List? MaybeTakeMultiple(string key) => this._multiples.TryGetValue(key, out var value) ? value : null; - - protected int TakeInteger(string key) => this.MaybeTakeInteger(key) ?? throw new ArgumentOutOfRangeException(nameof(key), key, "Missing integer entry in section"); - protected static string ExtractString(string value) => value.Trim('"'); protected static string ExtractEnumeration(string value) => value; diff --git a/M6502/M6502.Symbols/SectionAttribute.cs b/M6502/M6502.Symbols/SectionAttribute.cs new file mode 100644 index 0000000..1ced0c4 --- /dev/null +++ b/M6502/M6502.Symbols/SectionAttribute.cs @@ -0,0 +1,16 @@ +namespace EightBit +{ + namespace Files + { + namespace Symbols + { + [AttributeUsage(AttributeTargets.Class)] + internal class SectionAttribute(string key, string? referencing = null) : Attribute + { + public string Key { get; private set; } = key; + + public string? Referencing { get; private set; } = referencing; + } + } + } +} diff --git a/M6502/M6502.Symbols/SectionPropertyAttribute.cs b/M6502/M6502.Symbols/SectionPropertyAttribute.cs index 64488d7..4edba6a 100644 --- a/M6502/M6502.Symbols/SectionPropertyAttribute.cs +++ b/M6502/M6502.Symbols/SectionPropertyAttribute.cs @@ -5,7 +5,7 @@ namespace Symbols { [AttributeUsage(AttributeTargets.Property)] - internal class SectionPropertyAttribute(string key, System.Type? type = null, bool enumeration = false, bool hexadecimal = false, bool many = false) : Attribute + internal class SectionPropertyAttribute(string key, System.Type? type = null, bool enumeration = false, bool hexadecimal = false, bool optional = false, bool many = false) : Attribute { public string Key { get; private set; } = key; @@ -15,6 +15,8 @@ public bool Hexadecimal { get; private set; } = hexadecimal; + public bool Optional { get; private set; } = optional; + public bool Many { get; private set; } = many; } } diff --git a/M6502/M6502.Symbols/SectionReferenceAttribute.cs b/M6502/M6502.Symbols/SectionReferenceAttribute.cs index 72f8e2e..fa33b52 100644 --- a/M6502/M6502.Symbols/SectionReferenceAttribute.cs +++ b/M6502/M6502.Symbols/SectionReferenceAttribute.cs @@ -5,7 +5,7 @@ namespace Symbols { [AttributeUsage(AttributeTargets.Property)] - internal sealed class SectionReferenceAttribute(string key) : SectionPropertyAttribute(key, type: typeof(int)) + internal sealed class SectionReferenceAttribute(string key, bool optional = false) : SectionPropertyAttribute(key, type: typeof(int), optional: optional) { } } diff --git a/M6502/M6502.Symbols/Segment.cs b/M6502/M6502.Symbols/Segment.cs index 754705b..efa2dc4 100644 --- a/M6502/M6502.Symbols/Segment.cs +++ b/M6502/M6502.Symbols/Segment.cs @@ -5,6 +5,7 @@ namespace Symbols { // seg id=1,name="RODATA",start=0x00F471,size=0x0000,addrsize=absolute,type=ro,oname="sudoku.65b",ooffs=1137 + [Section("seg", "Segments")] public sealed class Segment(Parser container) : NamedSection(container) { [SectionProperty("start", hexadecimal: true)] diff --git a/M6502/M6502.Symbols/Span.cs b/M6502/M6502.Symbols/Span.cs index 84b4fdc..667edc2 100644 --- a/M6502/M6502.Symbols/Span.cs +++ b/M6502/M6502.Symbols/Span.cs @@ -5,10 +5,11 @@ namespace Symbols { //span id = 351, seg = 7, start = 0, size = 2, type = 2 + [Section("span", "Spans")] public sealed class Span(Parser container) : IdentifiableSection(container) { [SectionReference("seg")] - public Symbols.Segment Segment => this.TakeSegmentReference(); + public Symbols.Segment? Segment { get; private set; } [SectionProperty("start")] public int Start { get; private set; } @@ -17,7 +18,7 @@ public int Size { get; private set; } [SectionReference("type")] - public Symbols.Type Type => this.TakeTypeReference(); + public Symbols.Type? Type { get; private set; } } } } diff --git a/M6502/M6502.Symbols/Symbol.cs b/M6502/M6502.Symbols/Symbol.cs index ea4df28..9523c0e 100644 --- a/M6502/M6502.Symbols/Symbol.cs +++ b/M6502/M6502.Symbols/Symbol.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; // sym id = 16, name = "solve", addrsize = absolute, size = 274, scope = 0, def = 94,ref=144+17+351,val=0xF314,seg=6,type=lab + [Section("symbol", "Symbols")] public sealed class Symbol(Parser container) : NamedSection(container) { [SectionEnumeration("addrsize")] @@ -16,19 +17,19 @@ public int? Size { get; private set; } [SectionReference("scope")] - public Symbols.Scope Scope => this.TakeScopeReference(); + public Symbols.Scope? Scope { get; private set; } [SectionReferences("def")] - public List Definitions => this.TakeLineReferences("def"); // Guess + public List? Definitions { get; private set; } [SectionReferences("ref")] - public List References => this.TakeLineReferences("ref"); // Guess + public List? References { get; private set; } [SectionProperty("val", hexadecimal: true)] public int Value { get; private set; } [SectionReference("seg")] - public Symbols.Segment Segment => this.TakeSegmentReference(); + public Symbols.Segment? Segment { get; private set; } [SectionEnumeration("type")] public string? Type { get; private set; } diff --git a/M6502/M6502.Symbols/Type.cs b/M6502/M6502.Symbols/Type.cs index 9dd38fd..7bc5759 100644 --- a/M6502/M6502.Symbols/Type.cs +++ b/M6502/M6502.Symbols/Type.cs @@ -5,6 +5,7 @@ namespace Symbols { // type id = 0, val = "800920" + [Section("type", "Types")] public sealed class Type(Parser container) : IdentifiableSection(container) { [SectionProperty("val")] diff --git a/M6502/M6502.Symbols/Version.cs b/M6502/M6502.Symbols/Version.cs index 107a7a0..1dbacaf 100644 --- a/M6502/M6502.Symbols/Version.cs +++ b/M6502/M6502.Symbols/Version.cs @@ -5,6 +5,7 @@ namespace Symbols { //version major = 2, minor = 0 + [Section("version")] public sealed class Version(Parser container) : Section(container) { [SectionProperty("major")]