Home | History | Annotate | Download | only in scripts
      1 #!/usr/bin/env python
      2 
      3 import os.path
      4 import re
      5 import subprocess
      6 import sys
      7 
      8 from in_file import InFile
      9 import in_generator
     10 import license
     11 
     12 
     13 HEADER_TEMPLATE = """
     14 %(license)s
     15 
     16 #ifndef %(class_name)s_h
     17 #define %(class_name)s_h
     18 
     19 #include "core/css/CSSParserMode.h"
     20 #include <string.h>
     21 
     22 namespace WebCore {
     23 
     24 enum CSSValueID {
     25 %(value_keyword_enums)s
     26 };
     27 
     28 const int numCSSValueKeywords = %(value_keywords_count)d;
     29 const size_t maxCSSValueKeywordLength = %(max_value_keyword_length)d;
     30 
     31 const char* getValueName(unsigned short id);
     32 bool isValueAllowedInMode(unsigned short id, CSSParserMode mode);
     33 
     34 } // namespace WebCore
     35 
     36 #endif // %(class_name)s_h
     37 """
     38 
     39 GPERF_TEMPLATE = """
     40 %%{
     41 %(license)s
     42 
     43 #include "config.h"
     44 #include "%(class_name)s.h"
     45 #include "core/platform/HashTools.h"
     46 #include <string.h>
     47 
     48 namespace WebCore {
     49 static const char valueListStringPool[] = {
     50 "\\0"
     51 %(value_keyword_strings)s
     52 };
     53 
     54 static const unsigned short valueListStringOffsets[] = {
     55 %(value_keyword_offsets)s
     56 };
     57 
     58 %%}
     59 %%struct-type
     60 struct Value;
     61 %%omit-struct-type
     62 %%language=C++
     63 %%readonly-tables
     64 %%compare-strncmp
     65 %%define class-name %(class_name)sHash
     66 %%define lookup-function-name findValueImpl
     67 %%define hash-function-name value_hash_function
     68 %%define slot-name nameOffset
     69 %%define word-array-name value_word_list
     70 %%pic
     71 %%enum
     72 %%%%
     73 %(value_keyword_to_enum_map)s
     74 %%%%
     75 const Value* findValue(register const char* str, register unsigned int len)
     76 {
     77     return CSSValueKeywordsHash::findValueImpl(str, len);
     78 }
     79 
     80 const char* getValueName(unsigned short id)
     81 {
     82     if (id >= numCSSValueKeywords || id <= 0)
     83         return 0;
     84     return valueListStringPool + valueListStringOffsets[id];
     85 }
     86 
     87 bool isValueAllowedInMode(unsigned short id, CSSParserMode mode)
     88 {
     89     switch (id) {
     90         %(ua_sheet_mode_values_keywords)s
     91             return mode == UASheetMode;
     92         %(quirks_mode_values_keywords)s
     93             return mode == CSSQuirksMode;
     94         %(quirks_mode_or_ua_sheet_mode_values_keywords)s
     95             return mode == UASheetMode || mode == CSSQuirksMode;
     96         default:
     97             return true;
     98     }
     99 }
    100 
    101 } // namespace WebCore
    102 """
    103 
    104 
    105 class CSSValueKeywordsWriter(in_generator.Writer):
    106     class_name = "CSSValueKeywords"
    107     defaults = {
    108         'condition': None,
    109         'mode': None,
    110     }
    111 
    112     def __init__(self, file_paths, enabled_conditions):
    113         in_generator.Writer.__init__(self, file_paths, enabled_conditions)
    114         self._outputs = {(self.class_name + ".h"): self.generate_header,
    115                          (self.class_name + ".cpp"): self.generate_implementation,
    116                         }
    117 
    118         all_properties = self.in_file.name_dictionaries
    119         self._value_keywords = filter(lambda property: not property['condition'] or property['condition'] in self._enabled_conditions, all_properties)
    120         first_property_id = 1
    121         for offset, property in enumerate(self._value_keywords):
    122             property['name'] = property['name'].lower()
    123             property['enum_name'] = self._enum_name_from_value_keyword(property['name'])
    124             property['enum_value'] = first_property_id + offset
    125             if property['name'].startswith('-internal-'):
    126                 assert property['mode'] is None, 'Can\'t specify mode for value keywords with the prefix "-internal-".'
    127                 property['mode'] = 'UASheet'
    128             else:
    129                 assert property['mode'] != 'UASheet', 'UASheet mode only value keywords should have the prefix "-internal-".'
    130 
    131     def _enum_name_from_value_keyword(self, value_keyword):
    132         return "CSSValue" + "".join(w.capitalize() for w in value_keyword.split("-"))
    133 
    134     def _enum_declaration(self, property):
    135         return "    %(enum_name)s = %(enum_value)s," % property
    136 
    137     def _case_value_keyword(self, property):
    138         return "case %(enum_name)s:" % property
    139 
    140     def generate_header(self):
    141         enum_enties = map(self._enum_declaration, [{'enum_name': 'CSSValueInvalid', 'enum_value': 0}] + self._value_keywords)
    142         return HEADER_TEMPLATE % {
    143             'license': license.license_for_generated_cpp(),
    144             'class_name': self.class_name,
    145             'value_keyword_enums': "\n".join(enum_enties),
    146             'value_keywords_count': len(enum_enties),
    147             'max_value_keyword_length': reduce(max, map(len, map(lambda property: property['name'], self._value_keywords))),
    148         }
    149 
    150     def _value_keywords_with_mode(self, mode):
    151         return filter(lambda property: property['mode'] == mode, self._value_keywords)
    152 
    153     def generate_implementation(self):
    154         keyword_offsets = [0]
    155         current_offset = 1
    156         for keyword in self._value_keywords:
    157             keyword_offsets.append(current_offset)
    158             current_offset += len(keyword["name"]) + 1
    159 
    160         gperf_input = GPERF_TEMPLATE % {
    161             'license': license.license_for_generated_cpp(),
    162             'class_name': self.class_name,
    163             'value_keyword_strings': '\n'.join(map(lambda property: '    "%(name)s\\0"' % property, self._value_keywords)),
    164             'value_keyword_offsets': '\n'.join(map(lambda offset: '  %d,' % offset, keyword_offsets)),
    165             'value_keyword_to_enum_map': '\n'.join(map(lambda property: '%(name)s, %(enum_name)s' % property, self._value_keywords)),
    166             'ua_sheet_mode_values_keywords': '\n        '.join(map(self._case_value_keyword, self._value_keywords_with_mode('UASheet'))),
    167             'quirks_mode_values_keywords': '\n        '.join(map(self._case_value_keyword, self._value_keywords_with_mode('Quirks'))),
    168             'quirks_mode_or_ua_sheet_mode_values_keywords': '\n    '.join(map(self._case_value_keyword, self._value_keywords_with_mode('QuirksOrUASheet'))),
    169         }
    170         # FIXME: If we could depend on Python 2.7, we would use subprocess.check_output
    171         gperf_args = ['gperf', '--key-positions=*', '-D', '-n', '-s', '2']
    172         gperf = subprocess.Popen(gperf_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    173         return gperf.communicate(gperf_input)[0]
    174 
    175 
    176 if __name__ == "__main__":
    177     in_generator.Maker(CSSValueKeywordsWriter).main(sys.argv)
    178