libshit

Just some random shit
git clone https://git.neptards.moe/neptards/libshit.git
Log | Files | Refs | Submodules | README | LICENSE

util.rb (4477B)


      1 # frozen_string_literal: true
      2 
      3 require 'set'
      4 
      5 module Util
      6   extend self
      7 
      8   def print_fancy fun, str, c
      9     to_print = String.new
     10     if c
     11       loc = c.location
     12       to_print = "#{loc.file}:#{loc.line}:#{c.spelling}: "
     13     end
     14     to_print << (str.respond_to?(:full_message) ? str.full_message : str)
     15     CI.send fun, to_print
     16   end
     17 
     18   @success = true
     19   def success? = @success
     20   def fail!; @success = false; end
     21   def print_error str, c = nil
     22     @success = false
     23     print_fancy :eerror, str, c
     24   end
     25 
     26   def print_warning str, c = nil
     27     print_fancy :ewarn, str, c
     28   end
     29 
     30   def remove_anon_ns str
     31     str.gsub '::(anonymous namespace)', ''
     32   end
     33 
     34   def fun_qualified_name c
     35     res = [ c.spelling ]
     36     x = c.semantic_parent
     37     while x&.kind == :namespace
     38       res << x.spelling
     39       x = x.semantic_parent
     40     end
     41     res.reverse.join '::'
     42   end
     43 
     44   # get template types
     45   TEMPLATE_TYPES = Set.new %i(
     46     template_type_parameter non_type_template_parameter
     47     template_template_parameter
     48   )
     49   IGNORE_TYPES = Set.new %i(
     50     parm_decl type_ref annotate_attr namespace_ref compound_stmt
     51   )
     52   def collect_template_args c
     53     res = []
     54     c.visit_children do |c, par|
     55       kind = c.kind
     56       if TEMPLATE_TYPES.member? kind
     57         res << c
     58       elsif !IGNORE_TYPES.member? kind
     59         Util.print_warning "Unhandled arg type #{kind}", c
     60       end
     61       :continue
     62     end
     63     res
     64   end
     65 
     66   def collect_args c
     67     res = []
     68     c.visit_children do |c, par|
     69       res << c if c.kind == :parm_decl
     70       :continue
     71     end
     72     res
     73   end
     74 
     75   def has_annotation? c
     76     if block_given?
     77       c.visit_children do |c2|
     78         return true if c2.kind == :annotate_attr && yield(c2.spelling)
     79         :continue
     80       end
     81     else
     82       c.visit_children do |c2|
     83         return true if c2.kind == :annotate_attr
     84         :continue
     85       end
     86     end
     87     false
     88   end
     89 
     90   def collect_annotations c
     91     res = []
     92     if block_given?
     93       c.visit_children do |c2|
     94         if c2.kind == :annotate_attr && (mapped = yield(c2.spelling))
     95           res << mapped
     96         end
     97         :continue
     98       end
     99     else
    100       c.visit_children do |c2|
    101         res << c2 if c2.kind == :annotate_attr
    102         :continue
    103       end
    104     end
    105     res
    106   end
    107 
    108   def map_annotation cls, key, ann, env = {}
    109     return unless ann =~ /\A#{key}{(.*)}\z/
    110     # binding fuckery: simply calling instance_eval from this function would
    111     # mean that the parameters and the local variables here would end up in the
    112     # scope of the annotation value eval
    113     b = TOPLEVEL_BINDING.dup
    114     b.local_variable_set '__eval_obj__', OpenStruct.new(env)
    115     b.local_variable_set '__eval_cls__', cls
    116     b.local_variable_set '__eval_str__', "__eval_cls__.new(#$1).freeze"
    117     b.eval '__eval_obj__.instance_eval __eval_str__', __FILE__, __LINE__
    118   end
    119 
    120   CPP_ESCAPES = {
    121     '\\' => '\\\\',
    122     "\a" => '\\a',
    123     "\b" => '\\b',
    124     "\t" => '\\t',
    125     "\n" => '\\n',
    126     "\v" => '\\v',
    127     "\f" => '\\f',
    128     "\r" => '\\r',
    129   }.transform_keys!(&:ord).freeze
    130   def cpp_inspect s
    131     return s.to_s unless s.is_a? String
    132     esc = s.each_byte.map do |b|
    133       next CPP_ESCAPES[b] if CPP_ESCAPES[b]
    134       next b.chr if (32..127) === b
    135       # octal is max 3 chars, hex can be any length, so use octal
    136       '\\%03o' % b
    137     end.join.gsub /(\\x[0-9a-f]{2})([0-9a-f])/, '\1""\2'
    138     "\"#{esc}\""
    139   end
    140 end
    141 
    142 module RecursiveClassDiscovery
    143   def class_migrate_inheritable mod, ref; end
    144   def get_class_info c, ann; ann; end
    145 
    146   def class? type
    147     @rec_class_cache ||= {}
    148     type = type.canonical
    149     name = type.spelling
    150     return @rec_class_cache[name] unless @rec_class_cache[name].nil?
    151 
    152     ann_cls = self.class.const_get :ClassAnnotation
    153     ann_key = self.class.const_get :CLASS_ANNOTATION_KEY
    154     ret = nil
    155     tmp = nil
    156     type.declaration.visit_children do |c, par|
    157       case c.kind
    158       when :cxx_base_specifier
    159         if base_class = class?(c.type)
    160           ret = true if ret.nil?
    161           tmp ||= base_class.dup
    162           class_migrate_inheritable tmp, base_class
    163         end
    164 
    165       when :annotate_attr
    166         if at = Util.map_annotation(ann_cls, ann_key, c.spelling, c:)
    167           ret = get_class_info par, at
    168         end
    169       end
    170       :continue
    171     end
    172 
    173     ret = get_class_info type.declaration, ann_cls.new if ret == true
    174     class_migrate_inheritable ret, tmp if tmp
    175     @rec_class_cache[name] = ret
    176     ret
    177   end
    178 
    179   def class_by_name name
    180     @rec_class_cache[name] or fail "Unknown class #{name.inspect}"
    181   end
    182 end