| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/env python |
| 2 | 2 |
| 3 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 3 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 4 # for details. All rights reserved. Use of this source code is governed by a | 4 # for details. All rights reserved. Use of this source code is governed by a |
| 5 # BSD-style license that can be found in the LICENSE file. | 5 # BSD-style license that can be found in the LICENSE file. |
| 6 # | 6 # |
| 7 | 7 |
| 8 """ | 8 """ |
| 9 Frogpad is used to compile .dart files to javascript. | 9 Frogpad is used to compile .dart files to javascript. |
| 10 | 10 |
| 11 This is accomplished by first creating an html file (usually called | 11 This is accomplished by first creating an html file (usually called |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 45 | 45 |
| 46 | 46 |
| 47 class CommandFailedException(Exception): | 47 class CommandFailedException(Exception): |
| 48 def __init__(self, message): | 48 def __init__(self, message): |
| 49 self._message = message | 49 self._message = message |
| 50 | 50 |
| 51 def GetMessage(self): | 51 def GetMessage(self): |
| 52 return self._message | 52 return self._message |
| 53 | 53 |
| 54 | 54 |
| 55 # This file is produced by compiling frogpad.dart to javascript. To do this | |
| 56 # we run frogc.dart on the dart vm. | |
| 57 # | |
| 58 # Note, we use ".frogc.js" as the extension (instead of simply ".js"), | |
| 59 # because this file is generated by frogc and not by frogpad. | |
| 60 # | |
| 61 # (For testing, it's useful to be able to distinguish files that are generated | |
| 62 # by frogc from files that are generated by frogpad.) | |
| 63 # | |
| 64 FROGPAD_JS = "frogpad.dart.frogc.js" | |
| 65 | |
| 66 # Template for the html page we're going to generate. | 55 # Template for the html page we're going to generate. |
| 67 HTML = """<html> | 56 HTML = """<!DOCTYPE html> |
| 57 <html> |
| 68 <head> | 58 <head> |
| 69 <style type="text/css"> | 59 <style type="text/css"> |
| 70 textarea { | 60 textarea { |
| 71 width: 100%; | 61 width: 100%; |
| 72 height: 200px; | 62 height: 200px; |
| 73 } | 63 } |
| 74 .label { | 64 .label { |
| 75 margin-top: 5px; | 65 margin-top: 5px; |
| 76 } | 66 } |
| 77 pre { | 67 pre { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 100 </script> | 90 </script> |
| 101 </body> | 91 </body> |
| 102 </html> | 92 </html> |
| 103 """ | 93 """ |
| 104 | 94 |
| 105 # This finds everything after the word "Output:" in the html page. | 95 # This finds everything after the word "Output:" in the html page. |
| 106 # (Note, because the javascript we're fishing out spans multiple lines | 96 # (Note, because the javascript we're fishing out spans multiple lines |
| 107 # we need to use the DOTALL switch here.) | 97 # we need to use the DOTALL switch here.) |
| 108 OUTPUT_JAVASCRIPT_REGEX = re.compile(".*\nOutput:(.*)#EOF", re.DOTALL) | 98 OUTPUT_JAVASCRIPT_REGEX = re.compile(".*\nOutput:(.*)#EOF", re.DOTALL) |
| 109 | 99 |
| 100 # If the frogpad.dart encounters a compilation error, the generated |
| 101 # javascript will start with the word 'throw'. |
| 102 COMPILATION_ERROR_REGEX = re.compile(".*frogpad compilation error.*", re.DOTALL) |
| 103 |
| 110 # We use "application/inert" here to make the browser ignore the | 104 # We use "application/inert" here to make the browser ignore the |
| 111 # these script tags. (frogpad.dart will fish out the contents as needed.) | 105 # these script tags. (frogpad.dart will fish out the contents as needed.) |
| 112 # | 106 # |
| 113 SCRIPT_TAG = """<script type="application/inert" id="{{id}}"> | 107 SCRIPT_TAG = """<script type="application/inert" id="{{id}}"> |
| 114 {{contents}} | 108 {{contents}} |
| 115 </script> | 109 </script> |
| 116 """ | 110 """ |
| 117 | 111 |
| 118 # Regex that finds #import, #source and #native directives in .dart files. | 112 # Regex that finds #import, #source and #native directives in .dart files. |
| 119 # match.group(1) = "import", "source" or "native" | 113 # match.group(1) = "import", "source" or "native" |
| 120 # match.group(2) = url of file being imported | 114 # match.group(2) = url of file being imported |
| 121 DIRECTIVE_RE = re.compile(r"^#(import|source|native)\([\"']([^\"']*)[\"']") | 115 DIRECTIVE_RE = re.compile(r"^#(import|source|native)\([\"']([^\"']*)[\"']") |
| 122 | 116 |
| 123 # id of script tag that holds name of the top dart file to be compiled, | 117 # id of script tag that holds name of the top dart file to be compiled, |
| 124 # (This file name passed will be passed to the frog compiler by frogpad.dart.) | 118 # (This file name passed will be passed to the frog compiler by frogpad.dart.) |
| 125 MAIN_ID = "main_id" | 119 MAIN_ID = "main_id" |
| 126 | 120 |
| 127 DART_LIBRARIES = { | 121 DART_LIBRARIES = { |
| 128 "core": "lib/corelib.dart", | 122 "core": "lib/corelib.dart", |
| 129 "coreimpl": "lib/corelib_impl.dart", | 123 "coreimpl": "lib/corelib_impl.dart", |
| 130 "dom": "../client/dom/frog/dom_frog.dart", | 124 "dom": "../client/dom/frog/dom_frog.dart", |
| 131 "html": "../client/html/frog/html_frog.dart", | 125 "html": "../client/html/frog/html_frog.dart", |
| 126 "isolate": "../lib/isolate/isolate_frog.dart", |
| 132 "json": "../lib/json/json_frog.dart" | 127 "json": "../lib/json/json_frog.dart" |
| 133 } | 128 } |
| 134 | 129 |
| 135 | |
| 136 class Pad(object): | 130 class Pad(object): |
| 137 """ | 131 """ |
| 138 Accumulates all source files that are needed to compile a dart program, | 132 Accumulates all source files that are needed to compile a dart program, |
| 139 and places them in <script> tags on an html page. | 133 and places them in <script> tags on an html page. |
| 140 """ | 134 """ |
| 141 | 135 |
| 142 def __init__(self, argv): | 136 def __init__(self, argv): |
| 143 parser = optparse.OptionParser(usage= | 137 parser = optparse.OptionParser(usage= |
| 144 "%prog [options] file_to_compile.dart" | 138 "%prog [options] file_to_compile.dart" |
| 145 ) | 139 ) |
| 146 parser.add_option("-r", "--rebuild", action="store_true", | 140 parser.add_option("-f", "--frogpad_js", |
| 147 help="forces rebuild of the frogpad javascript") | 141 help="location of frogpad.js file") |
| 148 parser.add_option("-o", "--out", | 142 parser.add_option("-o", "--out", |
| 149 help="name of javascript output file") | 143 help="name of javascript output file") |
| 150 parser.add_option("-v", "--verbose", action="store_true", | 144 parser.add_option("-v", "--verbose", action="store_true", |
| 151 help="more verbose logging") | 145 help="more verbose logging") |
| 152 (options, args) = parser.parse_args(argv) | 146 (options, args) = parser.parse_args(argv) |
| 153 | 147 |
| 154 log_level = logging.INFO | 148 log_level = logging.INFO |
| 155 if options.verbose: | 149 if options.verbose: |
| 156 log_level = logging.DEBUG | 150 log_level = logging.DEBUG |
| 157 logging.basicConfig(level=log_level) | 151 logging.basicConfig(level=log_level) |
| (...skipping 11 matching lines...) Expand all Loading... |
| 169 self.dart_dir = os.path.dirname(os.path.dirname(os.path.dirname( | 163 self.dart_dir = os.path.dirname(os.path.dirname(os.path.dirname( |
| 170 self.frogpad_dir))) | 164 self.frogpad_dir))) |
| 171 | 165 |
| 172 # directory of frog compiler source code | 166 # directory of frog compiler source code |
| 173 self.frog_dir = os.path.join(self.dart_dir, "frog") | 167 self.frog_dir = os.path.join(self.dart_dir, "frog") |
| 174 | 168 |
| 175 logging.debug("dartdir_dir: '%s'" % self.dart_dir) | 169 logging.debug("dartdir_dir: '%s'" % self.dart_dir) |
| 176 logging.debug("frog_dir: '%s'" % self.frog_dir) | 170 logging.debug("frog_dir: '%s'" % self.frog_dir) |
| 177 logging.debug("frogpad_dir: '%s'" % self.frogpad_dir) | 171 logging.debug("frogpad_dir: '%s'" % self.frogpad_dir) |
| 178 | 172 |
| 179 # name of frogpad_js file | 173 # location of frogpad.js |
| 180 self.frogpad_js = os.path.join(self.frogpad_dir, FROGPAD_JS) | 174 # (frogpad.js is generated by running frogsh_bootstrap_wrapper.py) |
| 175 if not options.frogpad_js: |
| 176 raise Exception("--frogpad_js is required") |
| 177 |
| 178 if not os.path.exists(options.frogpad_js): |
| 179 raise FileNotFoundException(options.frogpad_js) |
| 180 |
| 181 self.frogpad_js = options.frogpad_js |
| 181 | 182 |
| 182 if options.out: | 183 if options.out: |
| 183 # user has specified an output file | 184 # user has specified an output file name |
| 184 self.js_file = os.path.abspath(options.out) | 185 self.js_file = os.path.abspath(options.out) |
| 185 else: | 186 else: |
| 186 # user didn't specify an output file, so base the name on the | 187 # User didn't specify an output file, so use the input |
| 187 # input file | 188 # file name as the base of the output file name. |
| 188 self.js_file = self.main_file + ".frogpad.js" | 189 self.js_file = self.main_file + ".frogpad.js" |
| 189 | 190 |
| 190 logging.debug("js_file: '%s" % self.js_file) | 191 logging.debug("js_file: '%s" % self.js_file) |
| 191 | 192 |
| 192 # this is the html file that we pass to DumpRenderTree | 193 # this is the html file that we pass to DumpRenderTree |
| 193 self.html_file = self.js_file + ".frogpad.html" | 194 self.html_file = self.js_file + ".frogpad.html" |
| 194 logging.debug("html_file: '%s'" % self.html_file) | 195 logging.debug("html_file: '%s'" % self.html_file) |
| 195 | 196 |
| 196 # map from file name to File object (contains entries for all corelib | 197 # map from file name to File object (contains entries for all corelib |
| 197 # and all other dart files needed to compile main_file) | 198 # and all other dart files needed to compile main_file) |
| 198 self.name_to_file = {} | 199 self.name_to_file = {} |
| 199 | 200 |
| 200 # map from script tag id to File object | 201 # map from script tag id to File object |
| 201 self.id_to_file = {} | 202 self.id_to_file = {} |
| 202 | 203 |
| 203 if not os.path.exists(self.frogpad_js): | |
| 204 options.rebuild = True | |
| 205 | |
| 206 if options.rebuild: | |
| 207 self.build_frogpad_js() | |
| 208 | |
| 209 self.load_libraries() | 204 self.load_libraries() |
| 210 self.load_file(self.main_file) | 205 self.load_file(self.main_file) |
| 211 | 206 |
| 212 html = self.generate_html() | 207 html = self.generate_html() |
| 213 write_file(self.html_file, html) | 208 write_file(self.html_file, html) |
| 214 | 209 |
| 215 js = self.generate_js() | 210 js = self.generate_js() |
| 216 write_file(self.js_file, js) | 211 write_file(self.js_file, js) |
| 217 | 212 |
| 218 line_count = len(js.splitlines()) | 213 line_count = len(js.splitlines()) |
| 219 logging.info("generated '%s' (%d lines)", self.js_file, line_count) | 214 logging.debug("generated '%s' (%d lines)", self.js_file, line_count) |
| 220 | 215 |
| 221 def build_frogpad_js(self): | 216 match = COMPILATION_ERROR_REGEX.match(js) |
| 222 dart_vm = os.path.join(self.dart_dir, "out/Release_ia32/dart") | 217 if match: |
| 223 check_exists(dart_vm) | 218 sys.exit(1) |
| 224 | |
| 225 frogc_dart = os.path.join(self.frog_dir, "frogc.dart") | |
| 226 frogpad_dart = os.path.join(self.frogpad_dir, "frogpad.dart") | |
| 227 check_exists(frogc_dart) | |
| 228 check_exists(frogpad_dart) | |
| 229 | |
| 230 args = [] | |
| 231 args.append(dart_vm) | |
| 232 | |
| 233 # command line arguments for the dart vm | |
| 234 | |
| 235 # We leave out --enable_type_checks here for speed. | |
| 236 # args.append("--enable_type_checks") | |
| 237 | |
| 238 args.append("--enable_asserts") | |
| 239 | |
| 240 # The dart program we're going to run on the dart vm. | |
| 241 args.append(frogc_dart) | |
| 242 | |
| 243 # Command line arguments for frogc.dart | |
| 244 args.append("--libdir=%s/lib" % self.frog_dir) | |
| 245 args.append("--compile-only") | |
| 246 args.append("--enable_type_checks") | |
| 247 args.append("--enable_asserts") | |
| 248 args.append("--out=%s" % self.frogpad_js) | |
| 249 | |
| 250 # The dart program that we want frogc.dart to compile. | |
| 251 args.append(frogpad_dart) | |
| 252 logging.info("generating '%s'" % self.frogpad_js) | |
| 253 | |
| 254 run_command(args) | |
| 255 check_exists(self.frogpad_js) | |
| 256 | 219 |
| 257 def generate_html(self): | 220 def generate_html(self): |
| 258 tags = [] | 221 tags = [] |
| 259 for f in self.id_to_file.values(): | 222 for f in self.id_to_file.values(): |
| 260 tags.append(self._create_tag(f.id, f.contents)) | 223 tags.append(self._create_tag(f.id, f.contents)) |
| 261 tags.append(self._create_tag(MAIN_ID, self.main_file)) | 224 tags.append(self._create_tag(MAIN_ID, self.main_file)) |
| 262 html = HTML.replace("{{script_tags}}", "".join(tags)) | 225 html = HTML.replace("{{script_tags}}", "".join(tags)) |
| 263 html = html.replace("{{FROGPAD_JS}}", read_file(self.frogpad_js)) | 226 html = html.replace("{{FROGPAD_JS}}", read_file(self.frogpad_js)) |
| 264 return html | 227 return html |
| 265 | 228 |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 391 raise CommandFailedException(msg) | 354 raise CommandFailedException(msg) |
| 392 logging.debug("SUCCEEDED (%d bytes)" % len(stdout)) | 355 logging.debug("SUCCEEDED (%d bytes)" % len(stdout)) |
| 393 return stdout | 356 return stdout |
| 394 | 357 |
| 395 | 358 |
| 396 def main(argv): | 359 def main(argv): |
| 397 Pad(argv) | 360 Pad(argv) |
| 398 | 361 |
| 399 if __name__ == "__main__": | 362 if __name__ == "__main__": |
| 400 sys.exit(main(sys.argv)) | 363 sys.exit(main(sys.argv)) |
| OLD | NEW |