# Copyright (C) 2011 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.

require "config"
require "ast"
require "backends"
require "parser"
require "transform"

#
# computeSettingsCombinations(ast) -> settingsCombiations
#
# Computes an array of settings maps, where a settings map constitutes
# a configuration for the assembly code being generated. The map
# contains key value pairs where keys are settings names (strings) and
# the values are booleans (true for enabled, false for disabled).
#

def computeSettingsCombinations(ast)
    settingsCombinations = []
    
    def settingsCombinator(settingsCombinations, mapSoFar, remaining)
        if remaining.empty?
            settingsCombinations << mapSoFar
            return
        end
        
        newMap = mapSoFar.dup
        newMap[remaining[0]] = true
        settingsCombinator(settingsCombinations, newMap, remaining[1..-1])
        
        newMap = mapSoFar.dup
        newMap[remaining[0]] = false
        settingsCombinator(settingsCombinations, newMap, remaining[1..-1])
    end
    
    nonBackendSettings = ast.filter(Setting).uniq.collect{ |v| v.name }
    nonBackendSettings.delete_if {
        | setting |
        isBackend? setting
    }
    
    allBackendsFalse = {}
    BACKENDS.each {
        | backend |
        allBackendsFalse[backend] = false
    }
    
    # This will create entries for invalid backends. That's fine. It's necessary
    # because it ensures that generate_offsets_extractor (which knows about valid
    # backends) has settings indices that are compatible with what asm will see
    # (asm doesn't know about valid backends).
    BACKENDS.each {
        | backend |
        map = allBackendsFalse.clone
        map[backend] = true
        settingsCombinator(settingsCombinations, map, nonBackendSettings)
    }
    
    settingsCombinations
end

#
# forSettings(concreteSettings, ast) {
#     | concreteSettings, lowLevelAST, backend | ... }
#
# Determines if the settings combination is valid, and if so, calls
# the block with the information you need to generate code.
#

def forSettings(concreteSettings, ast)
    # Check which architectures this combinator claims to support.
    selectedBackend = nil
    BACKENDS.each {
        | backend |
        if concreteSettings[backend]
            raise if selectedBackend
            selectedBackend = backend
        end
    }
    
    return unless isValidBackend? selectedBackend
    
    # Resolve the AST down to a low-level form (no macros or conditionals).
    lowLevelAST = ast.resolveSettings(concreteSettings)
    
    yield concreteSettings, lowLevelAST, selectedBackend
end

#
# forEachValidSettingsCombination(ast) {
#     | concreteSettings, ast, backend, index | ... }
#
# forEachValidSettingsCombination(ast, settingsCombinations) {
#     | concreteSettings, ast, backend, index | ... }
#
# Executes the given block for each valid settings combination in the
# settings map. The ast passed into the block is resolved
# (ast.resolve) against the settings.
#
# The first form will call computeSettingsCombinations(ast) for you.
#

def forEachValidSettingsCombination(ast, *optionalSettingsCombinations)
    raise if optionalSettingsCombinations.size > 1
    
    if optionalSettingsCombinations.empty?
        settingsCombinations = computeSettingsCombinations(ast)
    else
        settingsCombinations = optionalSettingsCombiations[0]
    end
    
    settingsCombinations.each_with_index {
        | concreteSettings, index |
        forSettings(concreteSettings, ast) {
            | concreteSettings_, lowLevelAST, backend |
            yield concreteSettings, lowLevelAST, backend, index
        }
    }
end

#
# cppSettingsTest(concreteSettings)
#
# Returns the C++ code used to test if we are in a configuration that
# corresponds to the given concrete settings.
#

def cppSettingsTest(concreteSettings)
    "#if " + concreteSettings.to_a.collect{
        | pair |
        (if pair[1]
             ""
         else
             "!"
         end) + "OFFLINE_ASM_" + pair[0]
    }.join(" && ")
end

#
# isASTErroneous(ast)
#
# Tests to see if the AST claims that there is an error - i.e. if the
# user's code, after settings resolution, has Error nodes.
#

def isASTErroneous(ast)
    not ast.demacroify({}).filter(Error).empty?
end

#
# assertConfiguration(concreteSettings)
#
# Emits a check that asserts that we're using the given configuration.
#

def assertConfiguration(concreteSettings)
    $output.puts cppSettingsTest(concreteSettings)
    $output.puts "#else"
    $output.puts "#error \"Configuration mismatch.\""
    $output.puts "#endif"
end

#
# emitCodeInConfiguration(concreteSettings, ast, backend) {
#     | concreteSettings, ast, backend | ... }
#
# Emits all relevant guards to see if the configuration holds and
# calls the block if the configuration is not erroneous.
#

def emitCodeInConfiguration(concreteSettings, ast, backend)
    Label.resetReferenced

    if !$emitWinAsm
        $output.puts cppSettingsTest(concreteSettings)
    else
        if backend == "X86_WIN"
            $output.puts ".MODEL FLAT, C"
        end
        $output.puts "INCLUDE #{File.basename($output.path)}.sym"
        $output.puts "_TEXT SEGMENT"
    end
    
    if isASTErroneous(ast)
        $output.puts "#error \"Invalid configuration. Error at: #{ast.filter(Error)[0].codeOrigin}\""
    elsif not WORKING_BACKENDS.include? backend
        $output.puts "#error \"This backend is not supported yet.\""
    else
        yield concreteSettings, ast, backend
    end
    
    if !$emitWinAsm
        $output.puts "#endif"
    else
        $output.puts "_TEXT ENDS"
        $output.puts "END"

        # Write symbols needed by MASM
        File.open("#{File.basename($output.path)}.sym", "w") {
            | outp |
            Label.forReferencedExtern {
                | name |
                outp.puts "EXTERN #{name[1..-1]} : near"
            }
        }
    end
end

#
# emitCodeInAllConfigurations(ast) {
#     | concreteSettings, ast, backend, index | ... }
#
# Emits guard codes for all valid configurations, and calls the block
# for those configurations that are valid and not erroneous.
#

def emitCodeInAllConfigurations(ast)
    forEachValidSettingsCombination(ast) {
        | concreteSettings, lowLevelAST, backend, index |
        $output.puts cppSettingsTest(concreteSettings)
        yield concreteSettings, lowLevelAST, backend, index
        $output.puts "#endif"
    }
end



