# Copyright (C) 2014 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from collections                      import namedtuple
from common.immutables                import ImmutableDict
from common.logger                    import Logger
from file_format.c1visualizer.struct  import C1visualizerFile, C1visualizerPass
from file_format.checker.struct       import CheckerFile, TestCase, TestAssertion
from match.line                       import MatchLines, EvaluateLine

MatchScope = namedtuple("MatchScope", ["start", "end"])
MatchInfo = namedtuple("MatchInfo", ["scope", "variables"])

class MatchFailedException(Exception):
  def __init__(self, assertion, lineNo):
    self.assertion = assertion
    self.lineNo = lineNo

def splitIntoGroups(assertions):
  """ Breaks up a list of assertions, grouping instructions which should be
      tested in the same scope (consecutive DAG and NOT instructions).
   """
  splitAssertions = []
  lastVariant = None
  for assertion in assertions:
    if (assertion.variant == lastVariant and
        assertion.variant in [TestAssertion.Variant.DAG, TestAssertion.Variant.Not]):
      splitAssertions[-1].append(assertion)
    else:
      splitAssertions.append([assertion])
      lastVariant = assertion.variant
  return splitAssertions

def findMatchingLine(assertion, c1Pass, scope, variables, excludeLines=[]):
  """ Finds the first line in `c1Pass` which matches `assertion`.

  Scan only lines numbered between `scope.start` and `scope.end` and not on the
  `excludeLines` list.

  Returns the index of the `c1Pass` line matching the assertion and variables
  values after the match.

  Raises MatchFailedException if no such `c1Pass` line can be found.
  """
  for i in range(scope.start, scope.end):
    if i in excludeLines: continue
    newVariables = MatchLines(assertion, c1Pass.body[i], variables)
    if newVariables is not None:
      return MatchInfo(MatchScope(i, i), newVariables)
  raise MatchFailedException(assertion, scope.start)

def matchDagGroup(assertions, c1Pass, scope, variables):
  """ Attempts to find matching `c1Pass` lines for a group of DAG assertions.

  Assertions are matched in the list order and variable values propagated. Only
  lines in `scope` are scanned and each line can only match one assertion.

  Returns the range of `c1Pass` lines covered by this group (min/max of matching
  line numbers) and the variable values after the match of the last assertion.

  Raises MatchFailedException when an assertion cannot be satisfied.
  """
  matchedLines = []
  for assertion in assertions:
    assert assertion.variant == TestAssertion.Variant.DAG
    match = findMatchingLine(assertion, c1Pass, scope, variables, matchedLines)
    variables = match.variables
    assert match.scope.start == match.scope.end
    assert match.scope.start not in matchedLines
    matchedLines.append(match.scope.start)
  return MatchInfo(MatchScope(min(matchedLines), max(matchedLines)), variables)

def testNotGroup(assertions, c1Pass, scope, variables):
  """ Verifies that none of the given NOT assertions matches a line inside
      the given `scope` of `c1Pass` lines.

  Raises MatchFailedException if an assertion matches a line in the scope.
  """
  for i in range(scope.start, scope.end):
    line = c1Pass.body[i]
    for assertion in assertions:
      assert assertion.variant == TestAssertion.Variant.Not
      if MatchLines(assertion, line, variables) is not None:
        raise MatchFailedException(assertion, i)

def testEvalGroup(assertions, scope, variables):
  for assertion in assertions:
    if not EvaluateLine(assertion, variables):
      raise MatchFailedException(assertion, scope.start)

def MatchTestCase(testCase, c1Pass):
  """ Runs a test case against a C1visualizer graph dump.

  Raises MatchFailedException when an assertion cannot be satisfied.
  """
  assert testCase.name == c1Pass.name

  matchFrom = 0
  variables = ImmutableDict()
  c1Length = len(c1Pass.body)

  # NOT assertions are verified retrospectively, once the scope is known.
  pendingNotAssertions = None

  # Prepare assertions by grouping those that are verified in the same scope.
  # We also add None as an EOF assertion that will set scope for NOTs.
  assertionGroups = splitIntoGroups(testCase.assertions)
  assertionGroups.append(None)

  for assertionGroup in assertionGroups:
    if assertionGroup is None:
      # EOF marker always matches the last+1 line of c1Pass.
      match = MatchInfo(MatchScope(c1Length, c1Length), None)
    elif assertionGroup[0].variant == TestAssertion.Variant.Not:
      # NOT assertions will be tested together with the next group.
      assert not pendingNotAssertions
      pendingNotAssertions = assertionGroup
      continue
    elif assertionGroup[0].variant == TestAssertion.Variant.InOrder:
      # Single in-order assertion. Find the first line that matches.
      assert len(assertionGroup) == 1
      scope = MatchScope(matchFrom, c1Length)
      match = findMatchingLine(assertionGroup[0], c1Pass, scope, variables)
    elif assertionGroup[0].variant == TestAssertion.Variant.NextLine:
      # Single next-line assertion. Test if the current line matches.
      assert len(assertionGroup) == 1
      scope = MatchScope(matchFrom, matchFrom + 1)
      match = findMatchingLine(assertionGroup[0], c1Pass, scope, variables)
    elif assertionGroup[0].variant == TestAssertion.Variant.DAG:
      # A group of DAG assertions. Match them all starting from the same point.
      scope = MatchScope(matchFrom, c1Length)
      match = matchDagGroup(assertionGroup, c1Pass, scope, variables)
    else:
      assert assertionGroup[0].variant == TestAssertion.Variant.Eval
      scope = MatchScope(matchFrom, c1Length)
      testEvalGroup(assertionGroup, scope, variables)
      continue

    if pendingNotAssertions:
      # Previous group were NOT assertions. Make sure they don't match any lines
      # in the [matchFrom, match.start) scope.
      scope = MatchScope(matchFrom, match.scope.start)
      testNotGroup(pendingNotAssertions, c1Pass, scope, variables)
      pendingNotAssertions = None

    # Update state.
    assert matchFrom <= match.scope.end
    matchFrom = match.scope.end + 1
    variables = match.variables

def MatchFiles(checkerFile, c1File, targetArch):
  for testCase in checkerFile.testCases:
    if testCase.testArch not in [None, targetArch]:
      continue
    # TODO: Currently does not handle multiple occurrences of the same group
    # name, e.g. when a pass is run multiple times. It will always try to
    # match a check group against the first output group of the same name.
    c1Pass = c1File.findPass(testCase.name)
    if c1Pass is None:
      Logger.fail("Test case \"{}\" not found in the CFG file".format(testCase.name),
                  testCase.fileName, testCase.startLineNo)

    Logger.startTest(testCase.name)
    try:
      MatchTestCase(testCase, c1Pass)
      Logger.testPassed()
    except MatchFailedException as e:
      lineNo = c1Pass.startLineNo + e.lineNo
      if e.assertion.variant == TestAssertion.Variant.Not:
        Logger.testFailed("NOT assertion matched line {}".format(lineNo),
                          e.assertion.fileName, e.assertion.lineNo)
      else:
        Logger.testFailed("Assertion could not be matched starting from line {}".format(lineNo),
                          e.assertion.fileName, e.assertion.lineNo)
