1 // 2 // Copyright (c) 2010-2023 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System; 8 using System.Collections.Generic; 9 using System.Linq; 10 using Antmicro.Renode.Logging; 11 12 namespace Antmicro.Renode.PlatformDescription.Syntax 13 { 14 public static class SyntaxTreeHelpers 15 { ScanFor(object objectToScan, IWithPosition objectToFind)16 public static bool ScanFor(object objectToScan, IWithPosition objectToFind) 17 { 18 var found = false; 19 VisitSyntaxTree<IWithPosition>(objectToScan, x => 20 { 21 found |= objectToFind.Equals(x); 22 }); 23 return found; 24 } 25 26 public static void VisitSyntaxTree<TValue>(object root, Action<TValue> visitorAction) where TValue : class 27 { VisitSyntaxTreeInner(root, visitorAction, null)28 VisitSyntaxTreeInner<TValue>(root, visitorAction, null); 29 } 30 31 public static void VisitSyntaxTree<TValue>(object root, Action<TValue> visitorAction, Func<object, bool, bool> filter) where TValue : class 32 { VisitSyntaxTreeInner(root, visitorAction, filter)33 VisitSyntaxTreeInner(root, visitorAction, filter); 34 } 35 36 private static void VisitSyntaxTreeInner<TValue>(object objectToVisit, Action<TValue> visitorAction, Func<object, bool, bool> filter) where TValue : class 37 { 38 var objectAsValue = objectToVisit as TValue; 39 if(objectAsValue != null) 40 { 41 visitorAction(objectAsValue); 42 } 43 44 var objectIsEntry = objectToVisit.GetType() == typeof(Antmicro.Renode.PlatformDescription.Syntax.Entry); 45 46 var objectAsVisitable = objectToVisit as IVisitable; 47 if(objectAsVisitable != null) 48 { 49 foreach(var element in objectAsVisitable.Visit()) 50 { 51 if(element != null && ApplyFilter(element, objectIsEntry, filter)) 52 { 53 VisitSyntaxTreeInner(element, visitorAction, filter); 54 } 55 } 56 return; 57 } 58 59 var objectType = objectToVisit.GetType(); 60 var publicProperties = objectType.GetProperties(); 61 foreach(var property in publicProperties.Where(x => x.CanRead)) 62 { 63 var propertyValue = property.GetGetMethod().Invoke(objectToVisit, new object[0]); 64 if(propertyValue != null) 65 { 66 var typeOfValue = propertyValue.GetType(); 67 if(typeOfValue.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IEnumerable<>) && 68 x.GetGenericArguments()[0].Namespace.StartsWith(OurNamespace, StringComparison.InvariantCulture))) 69 { 70 foreach(var element in ((System.Collections.IEnumerable)propertyValue)) 71 { 72 if(ApplyFilter(element, objectIsEntry, filter)) 73 { 74 VisitSyntaxTreeInner(element, visitorAction, filter); 75 } 76 } 77 } 78 else if(typeOfValue.Namespace.StartsWith(OurNamespace, StringComparison.InvariantCulture)) 79 { 80 if(ApplyFilter(propertyValue, objectIsEntry, filter)) 81 { 82 VisitSyntaxTreeInner(propertyValue, visitorAction, filter); 83 } 84 } 85 } 86 } 87 } 88 ApplyFilter(object obj, bool isEntryChild, Func<object, bool, bool> filter)89 private static bool ApplyFilter(object obj, bool isEntryChild, Func<object, bool, bool> filter) 90 { 91 return filter == null ? true : filter(obj, isEntryChild); 92 } 93 94 private static readonly string OurNamespace = typeof(SyntaxTreeHelpers).Namespace; 95 } 96 } 97