| #!/usr/bin/env ruby |
| |
| # Copyright (C) 2013 Apple Inc. All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions |
| # are met: |
| # 1. Redistributions of source code must retain the above copyright |
| # notice, this list of conditions and the following disclaimer. |
| # 2. Redistributions in binary form must reproduce the above copyright |
| # notice, this list of conditions and the following disclaimer in the |
| # documentation and/or other materials provided with the distribution. |
| # |
| # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| # THE POSSIBILITY OF SUCH DAMAGE. |
| |
| class Reference |
| attr_reader :kind, :number |
| |
| def initialize(kind, number) |
| @kind = kind |
| @number = number |
| end |
| |
| def resolve(hashTable, bangTable) |
| case @kind |
| when "#" |
| result = hashTable[@number] |
| when "!" |
| result = bangTable[@number] |
| else |
| raise |
| end |
| raise unless result |
| result |
| end |
| end |
| |
| def parse(string) |
| result = [] |
| until string.empty? |
| before, match, string = string.partition(/[!#]([0-9]+)/) |
| result << before |
| if match.empty? |
| result << string |
| break |
| end |
| result << Reference.new(match[0..0], match[1..-1].to_i) |
| end |
| result |
| end |
| |
| class MetaData |
| attr_reader :index, :name, :parent, :val |
| |
| def initialize(index, name, parent, val) |
| @index = index |
| @name = name |
| @parent = parent |
| @val = val |
| end |
| end |
| |
| $definitions = [] |
| $declarations = {} |
| $attributes = [] |
| $metaData = {} |
| $attributesBackMap = {} |
| $count = 0 |
| |
| loop { |
| line = $stdin.readline |
| if line =~ /^; NOTE: THIS IS A COMBINED MODULE/ |
| puts line |
| puts $stdin.read |
| exit 0 |
| end |
| break if line =~ /^define/ |
| } |
| |
| puts "; NOTE: THIS IS A COMBINED MODULE" |
| |
| # Loop over all definitions. |
| shouldContinue = true |
| while shouldContinue |
| # We're starting a new definition. |
| body = "" |
| loop { |
| line = $stdin.readline |
| break if line.chomp == "}" |
| body += line |
| } |
| |
| body = parse(body) |
| |
| declarations=[] |
| metaDataMap=[] |
| attributeMap = [] |
| unresolvedMetaData = [] |
| |
| loop { |
| line = $stdin.gets |
| |
| if not line |
| shouldContinue = false |
| break |
| elsif line =~ /^define/ |
| break |
| elsif line =~ /^declare/ |
| declarations << parse(line) |
| elsif line =~ /!([0-9]+) = metadata !{metadata !\"([a-zA-Z0-9_]+)\"}/ |
| index = $1.to_i |
| name = $2 |
| unless $metaData[name] |
| $metaData[name] = MetaData.new($metaData.size, name, nil, nil) |
| end |
| metaDataMap[index] = $metaData[$2].index |
| elsif line =~ /!([0-9]+) = metadata !{metadata !\"([a-zA-Z0-9_]+)\", metadata !([0-9]+)/ |
| metaData = MetaData.new($1.to_i, $2, $3.to_i, nil) |
| unresolvedMetaData << metaData |
| elsif line =~ /!([0-9]+) = metadata !{metadata !\"branch_weights\"/ |
| index = $1.to_i |
| arr1 = line.split(','); |
| arr1.shift |
| arr2 = Array.new |
| name = "branch_weights" |
| arr1.each { |a| |
| a =~ /i32 ([0-9]+)/ |
| name.concat($1) |
| arr2.push($1) |
| } |
| unless $metaData[name] |
| $metaData[name] = MetaData.new($metaData.size, "branch_weights", nil, arr2) |
| end |
| metaDataMap[index] = $metaData[name].index |
| elsif line =~ /!([0-9]+) = metadata !{i32 ([-+0-9]+), i32 ([-+0-9]+)}/ |
| index = $1.to_i |
| name = "#$2#$3" |
| unless $metaData[name] |
| $metaData[name] = MetaData.new($metaData.size, nil, nil, [$2, $3]) |
| end |
| metaDataMap[index] = $metaData[name].index |
| elsif line =~ /attributes #([0-9]+) = / |
| attributeNumber = $1.to_i |
| attributeBody = $~.post_match |
| if $attributesBackMap[attributeBody] |
| attributeMap[attributeNumber] = $attributesBackMap[attributeBody] |
| else |
| attributeMap[attributeNumber] = $attributes.size |
| $attributesBackMap[attributeBody] = $attributes.size |
| $attributes << attributeBody |
| end |
| end |
| } |
| |
| # Iteratively resolve meta-data references |
| until unresolvedMetaData.empty? |
| index = 0 |
| while index < unresolvedMetaData.size |
| metaData = unresolvedMetaData[index] |
| if $metaData[metaData.name] |
| metaDataMap[metaData.index] = $metaData[metaData.name].index |
| unresolvedMetaData[index] = unresolvedMetaData[-1] |
| unresolvedMetaData.pop |
| elsif metaDataMap[metaData.parent] |
| metaDataMap[metaData.index] = $metaData.size |
| $metaData[metaData.name] = MetaData.new($metaData.size, metaData.name, metaDataMap[metaData.parent], nil) |
| unresolvedMetaData[index] = unresolvedMetaData[-1] |
| unresolvedMetaData.pop |
| else |
| index += 1 |
| end |
| end |
| end |
| |
| # Output the body with all of the things remapped. |
| puts "define i64 @jsBody_#{$count += 1}() {" |
| body.each { |
| | thing | |
| if thing.is_a? Reference |
| print(thing.kind + thing.resolve(attributeMap, metaDataMap).to_s) |
| else |
| print(thing) |
| end |
| } |
| puts "}" |
| |
| # Figure out what to do with declarations. |
| declarations.each { |
| | declaration | |
| declaration = declaration.map { |
| | thing | |
| if thing.is_a? Reference |
| thing.kind + thing.resolve(attributeMap, metaDataMap).to_s |
| else |
| thing |
| end |
| } |
| declaration = declaration.join('') |
| |
| next if $declarations[declaration] |
| |
| $declarations[declaration] = true |
| } |
| end |
| |
| $declarations.each_key { |
| | declaration | |
| puts declaration |
| } |
| |
| $attributes.each_with_index { |
| | attribute, index | |
| puts "attributes ##{index} = #{attribute}" |
| } |
| |
| $metaData.each_value { |
| | metaData | |
| print "!#{metaData.index} = metadata !{" |
| if metaData.name |
| print "metadata !\"#{metaData.name}\"" |
| end |
| if metaData.parent |
| print ", metadata !#{metaData.parent}" |
| end |
| if (metaData.val) |
| index = 0 |
| if metaData.name |
| index = 1 |
| end |
| metaData.val.each { |a| |
| if (index == 0) |
| print "i32 #{a}" |
| else |
| print ", i32 #{a}" |
| end |
| index += 1 |
| } |
| end |
| puts "}" |
| } |
| |