mirror of
https://github.com/MoleskiCoder/EightBitNet.git
synced 2026-10-25 05:02:14 +00:00
Fully embrace reflected method of parsing symbols
This commit is contained in:
1 parent
5d796ef669
commit
61ba72f10a
17 files changed
+266
-318
No files matched your search
@@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<T>(int key, List<T>? 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<T>(string key, List<T>? from) where T : IdentifiableSection => TakeReference(this.TakeInteger(key), from);
|
||||
|
||||
protected T? MaybeTakeReference<T>(string key, List<T>? from) where T : IdentifiableSection
|
||||
{
|
||||
var id = this.MaybeTakeInteger(key);
|
||||
return id == null ? null : TakeReference(id.Value, from);
|
||||
}
|
||||
|
||||
protected List<T> TakeReferences<T>(string key, List<T>? 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<T>(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<Module>(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<File>(key, this._container?.Files);
|
||||
var (name, type, attribute) = connection;
|
||||
|
||||
protected Type TakeTypeReference(string key = "type") => this.TakeReference<Type>(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<Segment>(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<Scope>(key, this._container?.Scopes);
|
||||
// The reference ID
|
||||
|
||||
protected Scope? MaybeTakeParentReference(string key = "parent") => this.MaybeTakeReference<Scope>(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<Symbol>(key, this._container?.Symbols);
|
||||
|
||||
protected List<Span> TakeSpanReferences(string key = "span") => this.TakeReferences<Span>(key, this._container?.Spans);
|
||||
|
||||
protected List<Line> TakeLineReferences(string key) => this.TakeReferences<Line>(key, this._container?.Lines);
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
// Now set our reference field
|
||||
Debug.Assert(referencingObject != null);
|
||||
this.SetProperty(name, referencingObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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<Span> Spans => this.TakeSpanReferences();
|
||||
public List<Span>? Spans { get; private set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+74
-159
@@ -13,123 +13,29 @@
|
||||
#region Variables, properties etc.
|
||||
|
||||
// Section -> Unique ID list of dictionary entries
|
||||
private readonly Dictionary<string, List<Dictionary<string, string>>> _parsed = [];
|
||||
|
||||
private Version? _version;
|
||||
private Information? _information;
|
||||
|
||||
private List<File>? _files;
|
||||
private List<Line>? _lines;
|
||||
private List<Module>? _modules;
|
||||
private List<Segment>? _segments;
|
||||
private List<Span>? _spans;
|
||||
private List<Scope>? _scopes;
|
||||
private List<Symbol>? _symbols;
|
||||
private List<Type>? _types;
|
||||
public Dictionary<string, List<Dictionary<string, string>>> Parsed { get; } = [];
|
||||
|
||||
public ref List<File>? Files
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._files == null)
|
||||
{
|
||||
this.ExtractFiles();
|
||||
}
|
||||
public List<Section> SectionEntries { get; } = [];
|
||||
|
||||
return ref this._files;
|
||||
}
|
||||
}
|
||||
public List<File> Files = [];
|
||||
|
||||
public ref List<Line>? Lines
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._lines == null)
|
||||
{
|
||||
this.ExtractLines();
|
||||
}
|
||||
public List<Line> Lines = [];
|
||||
|
||||
return ref this._lines;
|
||||
}
|
||||
}
|
||||
public List<Module> Modules = [];
|
||||
|
||||
public ref List<Module>? Modules
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._modules == null)
|
||||
{
|
||||
this.ExtractModules();
|
||||
}
|
||||
public List<Segment> Segments = [];
|
||||
|
||||
return ref this._modules;
|
||||
}
|
||||
}
|
||||
public List<Span> Spans = [];
|
||||
|
||||
public ref List<Segment>? Segments
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._segments == null)
|
||||
{
|
||||
this.ExtractSegments();
|
||||
}
|
||||
public List<Scope> Scopes = [];
|
||||
|
||||
return ref this._segments;
|
||||
}
|
||||
}
|
||||
public List<Symbol> Symbols = [];
|
||||
|
||||
public ref List<Span>? Spans
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._spans == null)
|
||||
{
|
||||
this.ExtractSpans();
|
||||
}
|
||||
|
||||
return ref this._spans;
|
||||
}
|
||||
}
|
||||
|
||||
public ref List<Scope>? Scopes
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._scopes == null)
|
||||
{
|
||||
this.ExtractScopes();
|
||||
}
|
||||
|
||||
return ref this._scopes;
|
||||
}
|
||||
}
|
||||
|
||||
public ref List<Symbol>? Symbols
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._symbols == null)
|
||||
{
|
||||
this.ExtractSymbols();
|
||||
}
|
||||
|
||||
return ref this._symbols;
|
||||
}
|
||||
}
|
||||
|
||||
public ref List<Type>? Types
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._types == null)
|
||||
{
|
||||
this.ExtractTypes();
|
||||
}
|
||||
|
||||
return ref this._types;
|
||||
}
|
||||
}
|
||||
public List<Type> Types = [];
|
||||
|
||||
// Symbol sub-types
|
||||
public IEnumerable<Symbol> Labels => this.SelectSymbolsByType("lab");
|
||||
@@ -160,8 +66,6 @@
|
||||
|
||||
#region Lookups
|
||||
|
||||
private static IEnumerable<T> SelectNameMatching<T>(string name, IEnumerable<T>? items) where T : NamedSection => from item in items where item.Name == name select item;
|
||||
|
||||
private static IEnumerable<T> SelectIdMatching<T>(int id, IEnumerable<T>? items) where T : IdentifiableSection => from item in items where item.ID == id select item;
|
||||
|
||||
private IEnumerable<Symbol> 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<Symbol> 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<Symbol> LookupLabelsByID(int id) => SelectIdMatching(id, this.Labels);
|
||||
|
||||
public Symbol? LookupLabelByID(int id)
|
||||
@@ -263,8 +159,9 @@
|
||||
|
||||
#region Scope evaluation
|
||||
|
||||
private static List<Scope> EvaluateScope(Scope start)
|
||||
private static List<Scope> EvaluateScope(Scope? start)
|
||||
{
|
||||
Debug.Assert(start != null);
|
||||
var returned = new List<Scope>();
|
||||
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>("file", this.Files);
|
||||
|
||||
private void ExtractLines() => this.Extract<Line>("line", this.Lines);
|
||||
|
||||
private void ExtractModules() => this.Extract<Module>("mod", this.Modules);
|
||||
|
||||
private void ExtractSegments() => this.Extract<Segment>("seg", this.Segments);
|
||||
|
||||
private void ExtractSpans() => this.Extract<Span>("span", this.Spans);
|
||||
|
||||
private void ExtractScopes() => this.Extract<Scope>("scope", this.Scopes);
|
||||
|
||||
private void ExtractSymbols() => this.Extract<Symbol>("sym", this.Symbols);
|
||||
|
||||
private void ExtractTypes() => this.Extract<Type>("type", this.Types);
|
||||
|
||||
private void Extract<T>(string key, List<T> 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>("file", ref this._files);
|
||||
|
||||
private void ExtractLines() => this.Extract<Line>("line", ref this._lines);
|
||||
|
||||
private void ExtractModules() => this.Extract<Module>("mod", ref this._modules);
|
||||
|
||||
private void ExtractSegments() => this.Extract<Segment>("seg", ref this._segments);
|
||||
|
||||
private void ExtractSpans() => this.Extract<Span>("span", ref this._spans);
|
||||
|
||||
private void ExtractScopes() => this.Extract<Scope>("scope", ref this._scopes);
|
||||
|
||||
private void ExtractSymbols() => this.Extract<Symbol>("sym", ref this._symbols);
|
||||
|
||||
private void ExtractTypes() => this.Extract<Type>("type", ref this._types);
|
||||
|
||||
private void Extract<T>(string key, ref List<T>? 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<T>(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);
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
public sealed class ReflectedSectionProperties
|
||||
{
|
||||
private readonly Dictionary<string, string> _entriesToProperties = [];
|
||||
private readonly Dictionary<string, string> _propertiesToEntries = [];
|
||||
|
||||
public HashSet<string> StringKeys { get; } = [];
|
||||
public HashSet<string> EnumerationKeys { get; } = [];
|
||||
@@ -23,8 +22,23 @@
|
||||
|
||||
public Dictionary<string, PropertyInfo> Properties { get; } = [];
|
||||
|
||||
internal SectionAttribute? ClassAttribute { get; }
|
||||
|
||||
internal Dictionary<string, Tuple<string, System.Type, SectionPropertyAttribute>> Attributes { get; } = [];
|
||||
|
||||
internal Dictionary<string, Tuple<string, System.Type, SectionReferenceAttribute>> ReferenceAttributes { get; } = [];
|
||||
|
||||
internal Dictionary<string, Tuple<string, System.Type, SectionReferencesAttribute>> 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<T>(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<string, System.Type, SectionPropertyAttribute>(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<string, System.Type, SectionReferenceAttribute>(name, originalType, referenceAttribute));
|
||||
Debug.Assert(success);
|
||||
} else if (attribute is SectionReferencesAttribute referencesAttribute)
|
||||
{
|
||||
var success = this.ReferencesAttributes.TryAdd(key, new Tuple<string, System.Type, SectionReferencesAttribute>(name, originalType, referencesAttribute));
|
||||
Debug.Assert(success);
|
||||
}
|
||||
|
||||
var multiples = attribute.Many;
|
||||
|
||||
@@ -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<Span> Spans => this.TakeSpanReferences();
|
||||
public List<Span>? Spans { get; private set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,19 +17,20 @@
|
||||
|
||||
protected readonly Parser _container;
|
||||
|
||||
protected readonly Dictionary<string, int> _integers = [];
|
||||
protected readonly Dictionary<string, List<int>> _multiples = [];
|
||||
// Needed to evaluate references on a second pass
|
||||
protected readonly Dictionary<string, int> _references = [];
|
||||
protected readonly Dictionary<string, List<int>> _multipleReferences = [];
|
||||
|
||||
protected ReflectedSectionProperties SectionProperties
|
||||
protected Dictionary<string, string>? _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<T>(string key) => this.SectionProperties.MaybeGetValue<T>(this, key);
|
||||
|
||||
public T GetValueT<T>(string key) => this.SectionProperties.GetValueT<T>(this, key);
|
||||
|
||||
public virtual void Parse(IDictionary<string, string> entries)
|
||||
public virtual void Parse(Dictionary<string, string> 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<int>? 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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Line> Definitions => this.TakeLineReferences("def"); // Guess
|
||||
public List<Line>? Definitions { get; private set; }
|
||||
|
||||
[SectionReferences("ref")]
|
||||
public List<Line> References => this.TakeLineReferences("ref"); // Guess
|
||||
public List<Line>? 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; }
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
namespace Symbols
|
||||
{
|
||||
// type id = 0, val = "800920"
|
||||
[Section("type", "Types")]
|
||||
public sealed class Type(Parser container) : IdentifiableSection(container)
|
||||
{
|
||||
[SectionProperty("val")]
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
namespace Symbols
|
||||
{
|
||||
//version major = 2, minor = 0
|
||||
[Section("version")]
|
||||
public sealed class Version(Parser container) : Section(container)
|
||||
{
|
||||
[SectionProperty("major")]
|
||||
|
||||
Reference in new issue
Block a user