File: make_css_value_keywords.py

package info (click to toggle)
chromium-browser 41.0.2272.118-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie-kfreebsd
  • size: 2,189,132 kB
  • sloc: cpp: 9,691,462; ansic: 3,341,451; python: 712,689; asm: 518,779; xml: 208,926; java: 169,820; sh: 119,353; perl: 68,907; makefile: 28,311; yacc: 13,305; objc: 11,385; tcl: 3,186; cs: 2,225; sql: 2,217; lex: 2,215; lisp: 1,349; pascal: 1,256; awk: 407; ruby: 155; sed: 53; php: 14; exp: 11
file content (174 lines) | stat: -rwxr-xr-x 5,819 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#!/usr/bin/env python

import os.path
import re
import subprocess
import sys

from in_file import InFile
import in_generator
import license


HEADER_TEMPLATE = """
%(license)s

#ifndef %(class_name)s_h
#define %(class_name)s_h

#include "core/css/parser/CSSParserMode.h"
#include <string.h>

namespace blink {

enum CSSValueID {
%(value_keyword_enums)s
};

const int numCSSValueKeywords = %(value_keywords_count)d;
const size_t maxCSSValueKeywordLength = %(max_value_keyword_length)d;

const char* getValueName(unsigned short id);
bool isValueAllowedInMode(unsigned short id, CSSParserMode mode);

} // namespace blink

#endif // %(class_name)s_h
"""

GPERF_TEMPLATE = """
%%{
%(license)s

#include "config.h"
#include "%(class_name)s.h"
#include "core/css/HashTools.h"
#include <string.h>

namespace blink {
static const char valueListStringPool[] = {
"\\0"
%(value_keyword_strings)s
};

static const unsigned short valueListStringOffsets[] = {
%(value_keyword_offsets)s
};

%%}
%%struct-type
struct Value;
%%omit-struct-type
%%language=C++
%%readonly-tables
%%compare-strncmp
%%define class-name %(class_name)sHash
%%define lookup-function-name findValueImpl
%%define hash-function-name value_hash_function
%%define slot-name nameOffset
%%define word-array-name value_word_list
%%pic
%%enum
%%%%
%(value_keyword_to_enum_map)s
%%%%
const Value* findValue(register const char* str, register unsigned int len)
{
    return CSSValueKeywordsHash::findValueImpl(str, len);
}

const char* getValueName(unsigned short id)
{
    if (id >= numCSSValueKeywords || id <= 0)
        return 0;
    return valueListStringPool + valueListStringOffsets[id];
}

bool isValueAllowedInMode(unsigned short id, CSSParserMode mode)
{
    switch (id) {
        %(ua_sheet_mode_values_keywords)s
            return isUASheetBehavior(mode);
        %(quirks_mode_or_ua_sheet_mode_values_keywords)s
            return isUASheetBehavior(mode) || isQuirksModeBehavior(mode);
        default:
            return true;
    }
}

} // namespace blink
"""


class CSSValueKeywordsWriter(in_generator.Writer):
    class_name = "CSSValueKeywords"
    defaults = {
        'mode': None,
    }

    def __init__(self, file_paths):
        in_generator.Writer.__init__(self, file_paths)
        self._outputs = {(self.class_name + ".h"): self.generate_header,
                         (self.class_name + ".cpp"): self.generate_implementation,
                        }

        self._value_keywords = self.in_file.name_dictionaries
        first_property_id = 1
        for offset, property in enumerate(self._value_keywords):
            property['name'] = property['name'].lower()
            property['enum_name'] = self._enum_name_from_value_keyword(property['name'])
            property['enum_value'] = first_property_id + offset
            if property['name'].startswith('-internal-'):
                assert property['mode'] is None, 'Can\'t specify mode for value keywords with the prefix "-internal-".'
                property['mode'] = 'UASheet'
            else:
                assert property['mode'] != 'UASheet', 'UASheet mode only value keywords should have the prefix "-internal-".'

    def _enum_name_from_value_keyword(self, value_keyword):
        return "CSSValue" + "".join(w.capitalize() for w in value_keyword.split("-"))

    def _enum_declaration(self, property):
        return "    %(enum_name)s = %(enum_value)s," % property

    def _case_value_keyword(self, property):
        return "case %(enum_name)s:" % property

    def generate_header(self):
        enum_enties = map(self._enum_declaration, [{'enum_name': 'CSSValueInvalid', 'enum_value': 0}] + self._value_keywords)
        return HEADER_TEMPLATE % {
            'license': license.license_for_generated_cpp(),
            'class_name': self.class_name,
            'value_keyword_enums': "\n".join(enum_enties),
            'value_keywords_count': len(enum_enties),
            'max_value_keyword_length': reduce(max, map(len, map(lambda property: property['name'], self._value_keywords))),
        }

    def _value_keywords_with_mode(self, mode):
        return filter(lambda property: property['mode'] == mode, self._value_keywords)

    def generate_implementation(self):
        keyword_offsets = [0]
        current_offset = 1
        for keyword in self._value_keywords:
            keyword_offsets.append(current_offset)
            current_offset += len(keyword["name"]) + 1

        gperf_input = GPERF_TEMPLATE % {
            'license': license.license_for_generated_cpp(),
            'class_name': self.class_name,
            'value_keyword_strings': '\n'.join(map(lambda property: '    "%(name)s\\0"' % property, self._value_keywords)),
            'value_keyword_offsets': '\n'.join(map(lambda offset: '  %d,' % offset, keyword_offsets)),
            'value_keyword_to_enum_map': '\n'.join(map(lambda property: '%(name)s, %(enum_name)s' % property, self._value_keywords)),
            'ua_sheet_mode_values_keywords': '\n        '.join(map(self._case_value_keyword, self._value_keywords_with_mode('UASheet'))),
            'quirks_mode_or_ua_sheet_mode_values_keywords': '\n    '.join(map(self._case_value_keyword, self._value_keywords_with_mode('QuirksOrUASheet'))),
        }
        # FIXME: If we could depend on Python 2.7, we would use subprocess.check_output
        gperf_args = [self.gperf_path, '--key-positions=*', '-P', '-n']
        gperf_args.extend(['-m', '50'])  # Pick best of 50 attempts.
        gperf_args.append('-D')  # Allow duplicate hashes -> More compact code.
        gperf = subprocess.Popen(gperf_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True)
        return gperf.communicate(gperf_input)[0]


if __name__ == "__main__":
    in_generator.Maker(CSSValueKeywordsWriter).main(sys.argv)