1#!/usr/bin/perl -w
2
3# Copyright (C) 2011 Adam Barth <abarth@webkit.org>
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions
7# are met:
8# 1. Redistributions of source code must retain the above copyright
9#    notice, this list of conditions and the following disclaimer.
10# 2. Redistributions in binary form must reproduce the above copyright
11#    notice, this list of conditions and the following disclaimer in the
12#    documentation and/or other materials provided with the distribution.
13#
14# THIS SOFTWARE IS PROVIDED BY GOOGLE, INC. ``AS IS'' AND ANY
15# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25#
26
27use strict;
28
29use Config;
30use Getopt::Long;
31use File::Path;
32use File::Spec;
33use IO::File;
34use InFilesParser;
35
36require Config;
37
38package InFilesCompiler;
39
40my $inputFile = "";
41my $outputDir = ".";
42my $defaultItemFactory;
43
44my %parsedItems;
45my %parsedParameters;
46
47sub itemHandler($$$)
48{
49    my ($itemName, $property, $value) = @_;
50
51    $parsedItems{$itemName} = { &$defaultItemFactory($itemName) } if !defined($parsedItems{$itemName});
52
53    return unless $property;
54
55    die "Unknown property $property for $itemName\n" if !defined($parsedItems{$itemName}{$property});
56    $parsedItems{$itemName}{$property} = $value;
57}
58
59sub parameterHandler($$)
60{
61    my ($parameter, $value) = @_;
62
63    die "Unknown parameter $parameter\n" if !defined($parsedParameters{$parameter});
64    $parsedParameters{$parameter} = $value;
65}
66
67sub new()
68{
69    my $object = shift;
70    my $reference = { };
71
72    my $defaultParametersRef = shift;
73    %parsedParameters = %{ $defaultParametersRef };
74    $defaultItemFactory = shift;
75
76    %parsedItems = ();
77
78    bless($reference, $object);
79    return $reference;
80}
81
82sub initializeFromCommandLine()
83{
84    ::GetOptions(
85        'input=s' => \$inputFile,
86        'outputDir=s' => \$outputDir,
87    );
88
89    die "You must specify --input <file>" unless length($inputFile);
90
91    ::mkpath($outputDir);
92
93    # FIXME: Should we provide outputDir via an accessor?
94    return $outputDir;
95}
96
97sub compile()
98{
99    my $object = shift;
100    my $generateCode = shift;
101
102    my $file = new IO::File;
103    open($file, $inputFile) or die "Failed to open file: $!";
104
105    my $InParser = InFilesParser->new();
106    $InParser->parse($file, \&parameterHandler, \&itemHandler);
107
108    close($file);
109    die "Failed to read from file: $inputFile" if (keys %parsedItems == 0);
110
111    &$generateCode(\%parsedParameters, \%parsedItems);
112}
113
114sub license()
115{
116    return "/*
117 * THIS FILE WAS AUTOMATICALLY GENERATED, DO NOT EDIT.
118 *
119 * Copyright (C) 2011 Google Inc.  All rights reserved.
120 *
121 * Redistribution and use in source and binary forms, with or without
122 * modification, are permitted provided that the following conditions
123 * are met:
124 * 1. Redistributions of source code must retain the above copyright
125 *    notice, this list of conditions and the following disclaimer.
126 * 2. Redistributions in binary form must reproduce the above copyright
127 *    notice, this list of conditions and the following disclaimer in the
128 *    documentation and/or other materials provided with the distribution.
129 *
130 * THIS SOFTWARE IS PROVIDED BY GOOGLE, INC. ``AS IS'' AND ANY
131 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
132 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
133 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
134 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
135 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
136 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
137 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
138 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
139 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
140 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
141 */
142
143";
144}
145
146sub interfaceForItem($)
147{
148    my $object = shift;
149    my $itemName = shift;
150
151    my $interfaceName = $parsedItems{$itemName}{"interfaceName"};
152    $interfaceName = $itemName unless $interfaceName;
153
154    return $interfaceName;
155}
156
157sub toMacroStyle($$)
158{
159    my $object = shift;
160    my $camelCase = shift;
161
162    return "EVENT" if $camelCase eq "Event";
163    return "EVENT_TARGET" if $camelCase eq "EventTarget";
164    return "EXCEPTION" if $camelCase eq "Exception";
165
166    die "Ok, you got me. This script is really just a giant hack. (\$camelCase=${camelCase})";
167}
168
169sub preferredConditional()
170{
171    my $object = shift;
172    my $conditional = shift;
173
174    my @conditionals = split('\\|', $conditional);
175    return $conditionals[0];
176}
177
178sub conditionalStringFromAttributeValue()
179{
180    my $object = shift;
181    my $conditional = shift;
182
183    return "ENABLE(" . join(') || ENABLE(', split('\\|', $conditional)) . ")";
184}
185
186sub generateInterfacesHeader()
187{
188    my $object = shift;
189
190    my $F;
191    my $namespace = $parsedParameters{"namespace"};
192    my $outputFile = "$outputDir/${namespace}Interfaces.h";
193
194    open F, ">$outputFile" or die "Failed to open file: $!";
195
196    print F license();
197
198    print F "#ifndef ${namespace}Interfaces_h\n";
199    print F "#define ${namespace}Interfaces_h\n";
200    print F "\n";
201
202    my %unconditionalInterfaces = ();
203    my %interfacesByConditional = ();
204
205    for my $itemName (sort keys %parsedItems) {
206        my $conditional = $parsedItems{$itemName}{"conditional"};
207        my $interfaceName = $object->interfaceForItem($itemName);
208
209        if ($conditional) {
210            if (!defined($interfacesByConditional{$conditional})) {
211                $interfacesByConditional{$conditional} = ();
212            }
213            $interfacesByConditional{$conditional}{$interfaceName} = 1;
214        } else {
215            $unconditionalInterfaces{$interfaceName} = 1
216        }
217    }
218
219    my $macroStyledNamespace = $object->toMacroStyle($namespace);
220
221    for my $conditional (sort keys %interfacesByConditional) {
222        my $preferredConditional = $object->preferredConditional($conditional);
223        print F "#if " . $object->conditionalStringFromAttributeValue($conditional) . "\n";
224        print F "#define DOM_${macroStyledNamespace}_INTERFACES_FOR_EACH_$preferredConditional(macro) \\\n";
225
226        for my $interface (sort keys %{ $interfacesByConditional{$conditional} }) {
227            next if defined($unconditionalInterfaces{$interface});
228            print F "    macro($interface) \\\n";
229        }
230
231        print F "// End of DOM_${macroStyledNamespace}_INTERFACES_FOR_EACH_$preferredConditional\n";
232        print F "#else\n";
233        print F "#define DOM_${macroStyledNamespace}_INTERFACES_FOR_EACH_$preferredConditional(macro)\n";
234        print F "#endif\n";
235        print F "\n";
236    }
237
238    print F "#define DOM_${macroStyledNamespace}_INTERFACES_FOR_EACH(macro) \\\n";
239    print F "    \\\n";
240    for my $interface (sort keys %unconditionalInterfaces) {
241            print F "    macro($interface) \\\n";
242    }
243    print F "    \\\n";
244    for my $conditional (sort keys %interfacesByConditional) {
245        my $preferredConditional = $object->preferredConditional($conditional);
246        print F "    DOM_${macroStyledNamespace}_INTERFACES_FOR_EACH_$preferredConditional(macro) \\\n";
247    }
248
249    print F "\n";
250    print F "#endif // ${namespace}Interfaces_h\n";
251
252    close F;
253}
254
255sub generateHeadersHeader()
256{
257    my $object = shift;
258
259    my $F;
260    my $namespace = $parsedParameters{"namespace"};
261    my $outputFile = "$outputDir/${namespace}Headers.h";
262
263    open F, ">$outputFile" or die "Failed to open file: $!";
264
265    print F license();
266
267    print F "#ifndef ${namespace}Headers_h\n";
268    print F "#define ${namespace}Headers_h\n";
269    print F "\n";
270
271    my %includedInterfaces = ();
272
273    for my $itemName (sort keys %parsedItems) {
274        my $conditional = $parsedItems{$itemName}{"conditional"};
275        my $interfaceName = $object->interfaceForItem($itemName);
276
277        next if defined($includedInterfaces{$interfaceName});
278        $includedInterfaces{$interfaceName} = 1;
279
280        print F "#if " . $object->conditionalStringFromAttributeValue($conditional) . "\n" if $conditional;
281        print F "#include \"$interfaceName.h\"\n";
282        print F "#include \"JS$interfaceName.h\"\n";
283        print F "#endif\n" if $conditional;
284    }
285
286    print F "\n";
287    print F "#endif // ${namespace}Headers_h\n";
288
289    close F;
290}
291
2921;
293