/* * Copyright 2019 faddenSoft * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Diagnostics; namespace SourceGen { /// /// Subclass of Symbol used for symbols defined in the platform or project. /// /// Instances are immutable, except for the Xrefs field. /// /// /// The Xrefs field isn't really part of the object. It's just convenient to reference /// them from here. /// public class DefSymbol : Symbol { // width to use when width doesn't matter; use 1 to try to get a prefab object public const int NO_WIDTH = 1; public const int MIN_WIDTH = 1; public const int MAX_WIDTH = 4; /// /// Data format descriptor. /// public FormatDescriptor DataDescriptor { get; private set; } /// /// User-supplied comment. /// public string Comment { get; private set; } /// /// Platform symbols only: tag used to organize symbols into groups. Used by /// extension scripts. /// /// /// This is not included in DefSymbol serialization because symbols with tags are /// not stored in the project file. It's only set when symbols are parsed out of /// platform symbol files. /// public string Tag { get; private set; } /// /// Cross-reference data, generated by the analyzer. /// /// /// This is just a convenient place to reference some data generated at run-time. It's /// not serialized, and not included in the test for equality. /// public XrefSet Xrefs { get; private set; } // NOTE: might be nice to identify the symbol's origin, e.g. which platform // symbol file it was defined in. This could then be stored in a // DisplayList line, for benefit of the Info panel. /// /// Internal base-object constructor, called by other constructors. /// private DefSymbol(string label, int value, Source source, Type type) : base(label, value, source, type) { Debug.Assert(source == Source.Platform || source == Source.Project || source == Source.Variable); Debug.Assert(type == Type.ExternalAddr || type == Type.Constant); Xrefs = new XrefSet(); } /// /// Constructor. /// /// Symbol's label. /// Symbol's value. /// Symbol source (general point of origin). /// Symbol type. /// Format descriptor sub-type, so we know how the /// user wants the value to be displayed. /// End-of-line comment. /// Symbol tag, used for grouping platform symbols. public DefSymbol(string label, int value, Source source, Type type, FormatDescriptor.SubType formatSubType, string comment, string tag) : this(label, value, source, type, formatSubType, comment, tag, NO_WIDTH) { } /// /// Constructor. Used for local variables, which have a meaningful width. /// /// Symbol's label. /// Symbol's value. /// Symbol source (general point of origin). /// Symbol type. /// Format descriptor sub-type, so we know how the /// user wants the value to be displayed. /// End-of-line comment. /// Symbol tag, used for grouping platform symbols. /// Variable width. public DefSymbol(string label, int value, Source source, Type type, FormatDescriptor.SubType formatSubType, string comment, string tag, int width) : this(label, value, source, type) { Debug.Assert(comment != null); Debug.Assert(tag != null); DataDescriptor = FormatDescriptor.Create(width, FormatDescriptor.Type.NumericLE, formatSubType); Comment = comment; Tag = tag; } /// /// Constructs a DefSymbol from a Symbol and a format descriptor. This is used /// for project symbols. /// /// Base symbol. /// Format descriptor. /// End-of-line comment. public DefSymbol(Symbol sym, FormatDescriptor dfd, string comment) : this(sym.Label, sym.Value, sym.SymbolSource, sym.SymbolType) { Debug.Assert(comment != null); DataDescriptor = dfd; Comment = comment; Tag = string.Empty; } /// /// Determines whether a symbol overlaps with a region. Useful for variables. /// /// Symbol to check. /// Address. /// Symbol width. /// Symbol type to check against. /// True if the symbols overlap. public static bool CheckOverlap(DefSymbol a, int value, int width, Type type) { if (a.DataDescriptor.Length <= 0 || width <= 0) { return false; } if (a.Value < 0 || value < 0) { return false; } if (a.SymbolType != type) { return false; } int maxStart = Math.Max(a.Value, value); int minEnd = Math.Min(a.Value + a.DataDescriptor.Length - 1, value + width - 1); return (maxStart <= minEnd); } public static bool operator ==(DefSymbol a, DefSymbol b) { if (ReferenceEquals(a, b)) { return true; // same object, or both null } if (ReferenceEquals(a, null) || ReferenceEquals(b, null)) { return false; // one is null } return a.Equals(b); } public static bool operator !=(DefSymbol a, DefSymbol b) { return !(a == b); } public override bool Equals(object obj) { if (!(obj is DefSymbol)) { return false; } // Do base-class equality comparison and the ReferenceEquals check. if (!base.Equals(obj)) { return false; } // All fields must be equal, except Xrefs. DefSymbol other = (DefSymbol)obj; if (DataDescriptor != other.DataDescriptor || Comment != other.Comment || Tag != other.Tag) { return false; } return true; } public override int GetHashCode() { return base.GetHashCode() ^ DataDescriptor.GetHashCode() ^ Comment.GetHashCode() ^ Tag.GetHashCode(); } public override string ToString() { return base.ToString() + ":" + DataDescriptor + ";" + Comment + (string.IsNullOrEmpty(Tag) ? "" : " [" + Tag + "]"); } } }