/**************************************************************************/
/*                                                                        */
/*  This file is part of Frama-Clang                                      */
/*                                                                        */
/*  Copyright (C) 2012-2022                                               */
/*    CEA (Commissariat à l'énergie atomique et aux énergies              */
/*         alternatives)                                                  */
/*                                                                        */
/*  you can redistribute it and/or modify it under the terms of the GNU   */
/*  Lesser General Public License as published by the Free Software       */
/*  Foundation, version 2.1.                                              */
/*                                                                        */
/*  It is distributed in the hope that it will be useful,                 */
/*  but WITHOUT ANY WARRANTY; without even the implied warranty of        */
/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
/*  GNU Lesser General Public License for more details.                   */
/*                                                                        */
/*  See the GNU Lesser General Public License version 2.1                 */
/*  for more details (enclosed in the file LICENSE).                      */
/*                                                                        */
/**************************************************************************/

//
// Description:
//   Implementation of the ACSL function contracts.
//

#include "ACSLComponent.h"

namespace Acsl {

using namespace DLexer;

#if defined(__clang__) || defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-label"
#endif

const std::string default_behavior_name("default!");

Parser::ReadResult
FunctionContract::error_empty_behavior(Parser::Arguments& arguments) {
  DefineAddError (
    strcat(strdup("Empty behavior "), ((behavior)
       _spec->behavior->element.container)->beh_name))
  return RRNeedChars;
}

Parser::ReadResult
FunctionContract::check_bhv_position(Parser::Arguments& arguments) {
  switch (_state) {
    case BHV:
      return error_empty_behavior(arguments);
    case COMPLETE:
      DefineAddError ("behavior after complete/disjoint clauses")
      return RRNeedChars;
    default:
      return RRNeedChars;
  }
}

Parser::ReadResult
FunctionContract::check_terminates_position(Parser::Arguments& arguments) {
  switch (_state) {
    case BHV:
      DefineAddError("terminates clause in behavior")
      return RRNeedChars;
    case ASSUMES:
      DefineAddError("terminates clause after assumes")
      return RRNeedChars;
    case POST_COND:
      DefineAddError("terminates clause after post-condition")
      return RRNeedChars;
    case TERMINATES:
      DefineAddError("at most one terminates clause is allowed")
      return RRNeedChars;
    case VARIANT:
      DefineAddError("terminates clause after decreases clause")
      return RRNeedChars;
    case COMPLETE:
      DefineAddError("terminates clause after complete/disjoint clause")
      return RRNeedChars;
    case REQUIRES:
      if (_spec->behavior &&  strcmp( ((behavior) ((list)_spec->behavior)->element.plain )->beh_name, default_behavior_name.c_str()) != 0) {
        DefineAddError("terminates clause in behavior")
      }
      return RRNeedChars;
    default:
      return RRNeedChars;
  }
}

Parser::ReadResult
FunctionContract::check_variant_position(Parser::Arguments& arguments) {
  switch (_state) {
    case BHV:
      DefineAddError("decreases in behavior")
      return RRNeedChars;
    case ASSUMES:
      DefineAddError("decreases after assumes")
      return RRNeedChars;
    case POST_COND:
      DefineAddError("decreases after post-condition")
      return RRNeedChars;
    case VARIANT:
      DefineAddError("at most one decreases clause is allowed")
      return RRNeedChars;
    case COMPLETE:
      DefineAddError("decreases after complete/disjoint clause")
      return RRNeedChars;
    case REQUIRES:
      if (_spec->behavior) {
        DefineAddError("decreases in behavior")
      }
      return RRNeedChars;
    default: return RRNeedChars;
  }
}

Parser::ReadResult
FunctionContract::check_assumes_position(Parser::Arguments& arguments) {
  switch(_state) {
    case START:
    case VARIANT:
    case TERMINATES:
      DefineAddError("assumes clause in default behavior")
      return RRNeedChars;
    case REQUIRES:
      DefineAddError("assumes clause after requires clause")
      return RRNeedChars;
    case POST_COND:
      DefineAddError("assumes clause after post-condition")
      return RRNeedChars;
    case COMPLETE:
      DefineAddError("assumes clause after complete/disjoint clauses")
      return RRNeedChars;
    default:
      return RRNeedChars;
  }
}

Parser::ReadResult
FunctionContract::check_requires_position(Parser::Arguments& arguments) {
  switch(_state) {
    case TERMINATES:
      DefineAddError("requires clause after terminates")
      return RRNeedChars;
    case POST_COND:
      DefineAddError("requires clause after post-condition")
      return RRNeedChars;
    case VARIANT:
      DefineAddError("requires clause after variant")
      return RRNeedChars;
    case COMPLETE:
      DefineAddError("requires clause after complete/disjoint clauses")
      return RRNeedChars;
    default:
      return RRNeedChars;
  }
}

Parser::ReadResult
FunctionContract::check_post_cond_position(Parser::Arguments& arguments) {
  switch(_state) {
    case COMPLETE:
      DefineAddError("post-condition after complete/disjoint clause")
      return RRNeedChars;
    default:
      return RRNeedChars;
  }
}

Parser::ReadResult
FunctionContract::check_complete_position(Parser::Arguments& arguments) {
  switch(_state) {
    case BHV:
      return error_empty_behavior (arguments);
    default:
      return RRNeedChars;
  }
}

void
FunctionContract::add_behavior(const std::string& name) {
  behavior bhv = behavior_cons(copy_string(name),NULL,NULL,NULL,
      assigns_WritesAny(), allocation_FreeAllocAny(), NULL);
  _currentBehavior.insertContainer(bhv);
  _currentRequires = bhv->requires;
  _currentAssumes = bhv->assumes;
  _currentPostCond = bhv->post_cond;
  _currentAssigns = ForwardList();
  _currentFrees = ForwardList ();
  _currentAllocates = ForwardList ();
}

Parser::ReadResult
FunctionContract::parseSemiColumn(Parser::Arguments& arguments,
    const std::string& msg) {
  AbstractToken token = arguments.queryToken();
  if (token.getType() == AbstractToken::TOperatorPunctuator) {
    OperatorPunctuatorToken::Type type = 
      ((const OperatorPunctuatorToken&) token).getType();
    if (type == OperatorPunctuatorToken::TSemiColon)
      return RRNeedChars;
    else
      DefineAddError(std::string("Expecting ';' after ").append(msg))
  }
  else
    DefineAddError(std::string("Expecting ';' after ").append(msg))
  return RRContinueParsing;
}

Parser::ReadResult
FunctionContract::readToken(Parser::State& state, Parser::Arguments& arguments)
{ ReadResult result = RRNeedChars;
  enum Delimiters
  { DBegin, DBehaviorName, DBehavior, DRequires, DRequiresEnd, DTerminates,
    DTerminatesEnd, DDecreases, DDecreasesFor, DDecreasesForIdent,
    DAssumes, DAssumesEnd, DPostCond, DPostCondEnd, DAssigns, DAssignsEnd,
    DComplete, DCompleteBehavior, DAfterComplete, DDisjoint, DDisjointBehavior,
    DAfterDisjoint, DBeforeSemiColon, DAllocatesFrees, DAllocatesFreesEnd
  };

  switch (state.point()) {
    DefineParseCase(Begin)
      arguments.setFunSpecContext();
      // Logic label Pre, Here and Old are always present,
      // Post only exists in post-condition, assigns and allocates
      arguments.addLogicLabel("Here");
      arguments.addLogicLabel("Pre");
      arguments.addLogicLabel("Old");
      { AbstractToken token = arguments.queryToken();
      std::string s = token.str();
        if (token.getType() == AbstractToken::TKeyword) {
          KeywordToken::Type type = ((const KeywordToken&) token).getType();
          switch(type) {
            case KeywordToken::TBehavior:
              { result = check_bhv_position (arguments);
                if (result == RRFinished) return result;
                DefineGotoCase(BehaviorName)
              }
            case KeywordToken::TRequires:
              { result = check_requires_position(arguments);
                if(result == RRFinished) return result;
                DefineGotoCase(Requires)
              }
            case KeywordToken::TTerminates:
              { result = check_terminates_position(arguments);
                if(result == RRFinished) return result;
                DefineGotoCase(Terminates)
              }
            case KeywordToken::TDecreases:
              { result = check_variant_position(arguments);
                if(result == RRFinished) return result;
                DefineGotoCase(Decreases)
              }
            case KeywordToken::TAssumes:
              { result = check_assumes_position(arguments);
                if(result == RRFinished) return result;
                DefineGotoCase(Assumes)
              }
            case KeywordToken::TEnsures:
              { result = check_post_cond_position(arguments);
                if(result == RRFinished) return result;
                _postCondKind = NORMAL;
                arguments.set_result_context(!_isStatementContract);
                DefineGotoCase(PostCond)
              }
            case KeywordToken::TAssigns:
              { result = check_post_cond_position(arguments);
                if (result == RRFinished) return result;
                arguments.set_result_context(!_isStatementContract);
                DefineGotoCase(Assigns)
              }
            case KeywordToken::TAllocates:
            case KeywordToken::TFrees:
              {
                result = check_post_cond_position(arguments);
                if (result == RRFinished) return result;
                arguments.set_result_context(
                  !_isStatementContract && (type == KeywordToken::TAllocates));
                _allocClauseKind =
                  type==KeywordToken::TAllocates?ALLOCATES:FREES;
                DefineGotoCase(AllocatesFrees);
              }
            case KeywordToken::TExits:
              { result = check_post_cond_position(arguments);
                if(result == RRFinished) return result;
                _postCondKind = EXITS;
                DefineGotoCase(PostCond)
              }
            case KeywordToken::TDisjoint:
              DefineGotoCase(Disjoint)
            case KeywordToken::TComplete:
              DefineGotoCase(Complete)
            default:
              arguments.resetAnnotContext();
              DefineAddErrorAndParse(std::string("unexpected keyword ")
                  .append(token.str()).append(" in function spec"))
          }
        }
        else {
          arguments.resetAnnotContext();
          DefineAddErrorAndParse("expecting function spec")
        }
      }
    DefineParseCase(BehaviorName)
      { AbstractToken token = arguments.queryToken();
        if (token.getType() == AbstractToken::TKeyword) {
          // Allow keywords as behavior names, converting them to strings
          _behaviorName = arguments.getContentToken().text();
          DefineGotoCase(Behavior)
        }
        if (token.getType() == AbstractToken::TIdentifier) {
          _behaviorName = ((const IdentifierToken&)arguments.getContentToken())
              .content();
          DefineGotoCase(Behavior)
        };
        arguments.lexer().assumeContentToken();
        arguments.resetAnnotContext();
        DefineAddError(std::string("unexpected token '")
            .append(arguments.getContentToken().str())
            .append("' expecting name of behavior"));
        DefineReduce;
      }
    DefineParseCase(Behavior)
      { AbstractToken token = arguments.queryToken();
        token = arguments.queryToken();
        if (token.getType() != AbstractToken::TOperatorPunctuator
              || ((const OperatorPunctuatorToken&) token).getType ()
            != OperatorPunctuatorToken::TColon) {
          arguments.lexer().assumeContentToken();
          arguments.resetAnnotContext();
          DefineAddError(std::string("':' expected after behavior name, got '")
              .append(arguments.getContentToken().str())
              .append("'"));
          DefineReduce;
        }
        add_behavior(_behaviorName);
        _behaviorName = "";
        _state = BHV;
        DefineGotoCase(Begin);
      }
    DefineParseCase(Requires) {
       logic_type thisRecordType = arguments.queryThisType();
       if (thisRecordType)
        arguments.addLogicFormal("this", thisRecordType);
      TermOrPredicate* pred = new TermOrPredicate;
      state.absorbRuleResult(&pred->setPredicate());
      DefineShiftAndParse(RequiresEnd,*pred,&TermOrPredicate::readToken);
    }
    DefineParseCase(RequiresEnd)
      { Parser::State::RuleAccess::TCastFromRule<TermOrPredicate>
          node(state.getRuleResult());
        predicate_named pred = node->extractPredicate(arguments);
        state.freeRuleResult();
        if (!pred) {
          arguments.resetAnnotContext();
          DefineAddError("expecting a predicate");
          DefineGotoCaseAndParse(BeforeSemiColon)
        };
        result = parseSemiColumn(arguments, "requires clause");
        if (result == RRFinished)
          return result;
        if (result == RRContinueParsing) {
          result = RRNeedChars;
          DefineGotoCaseAndParse(BeforeSemiColon)
        };
        if (!_spec->behavior) {
          // Adding new default behavior
          add_behavior(default_behavior_name);
        }
        _currentRequires.insertContainer(pred);
        _state = REQUIRES;
        DefineGotoCase(Begin)
      }
    DefineParseCase(Terminates) {
       logic_type thisRecordType = arguments.queryThisType();
       if (thisRecordType)
        arguments.addLogicFormal("this", thisRecordType);
      TermOrPredicate* pred = new TermOrPredicate;
      state.absorbRuleResult(&pred->setPredicate());
      DefineShiftAndParse(TerminatesEnd,*pred,&TermOrPredicate::readToken);
    }
    DefineParseCase(TerminatesEnd)
      { Parser::State::RuleAccess::TCastFromRule<TermOrPredicate>
          node(state.getRuleResult());
        predicate_named pred = node->extractPredicate(arguments);
        state.freeRuleResult();
        if (!pred) {
          arguments.resetAnnotContext();
          DefineAddError("expecting a predicate");
          DefineGotoCaseAndParse(BeforeSemiColon)
        };
        result = parseSemiColumn(arguments, "terminates clause");
        if (result == RRFinished)
          return result;
        if (_spec->terminates->is_some) {
          free_predicate_named(pred);
          pred = NULL;
          arguments.resetAnnotContext();
          DefineAddError("a contract can only have one `terminates' clause");
          DefineGotoCaseAndParse(BeforeSemiColon)
        };
        free(_spec->terminates);
        _spec->terminates = opt_some_container(pred);
        if (result == RRContinueParsing) {
          result = RRNeedChars;
          DefineGotoCaseAndParse(BeforeSemiColon)
        };
        _state = TERMINATES;
        DefineGotoCase(Begin)
      }
    DefineParseCase(Decreases) {
       logic_type thisRecordType = arguments.queryThisType();
       if (thisRecordType)
        arguments.addLogicFormal("this", thisRecordType);
      TermOrPredicate* decreaseTerm = new TermOrPredicate;
      state.absorbRuleResult(&decreaseTerm->setTerm());
      DefineShiftAndParse(DecreasesFor, *decreaseTerm,
          &TermOrPredicate::readToken);
    }
    DefineParseCase(DecreasesFor)
      { Parser::State::RuleAccess::TCastFromRule<TermOrPredicate>
          node(state.getRuleResult());
        term decreaseTerm = node->extractTerm(arguments);
        state.freeRuleResult();
        if (!decreaseTerm) {
          arguments.resetAnnotContext();
          DefineAddError("expecting a term");
          DefineGotoCaseAndParse(BeforeSemiColon)
        };
        if (_spec->variant->is_some) {
          free_term(decreaseTerm);
          decreaseTerm = NULL;
          arguments.resetAnnotContext();
          DefineAddError("a contract can only have one `decreases' clause");
          DefineGotoCaseAndParse(BeforeSemiColon)
        };
        free(_spec->variant);
        _spec->variant = opt_some_container(variant_cons(decreaseTerm,
            opt_none()));
        AbstractToken token = arguments.queryToken();
        if (token.getType() == AbstractToken::TOperatorPunctuator) {
          if (((const OperatorPunctuatorToken&) token).getType()
              == OperatorPunctuatorToken::TSemiColon) {
            _state = TERMINATES;
            DefineGotoCase(Begin)
          };
          arguments.resetAnnotContext();
          DefineAddError("Expecting ';' after decreases clause");
        }
        else if (token.getType() == AbstractToken::TKeyword) {
          if (((const KeywordToken&) token).getType() == KeywordToken::TFor) {
            _state = TERMINATES;
            DefineGotoCase(DecreasesForIdent)
          };
          arguments.resetAnnotContext();
          DefineAddError("Expecting \"for\" after decreases clause");
        };
        DefineGotoCaseAndParse(BeforeSemiColon)
      }
    DefineParseCase(DecreasesForIdent)
      if (arguments.queryToken().getType() == AbstractToken::TIdentifier) {
        variant decreases = (variant) _spec->variant->content.container;
        assert(!decreases->vname->is_some);
        free(decreases->vname);
        decreases->vname = opt_some_container(strdup(((const IdentifierToken&)
            arguments.getContentToken()).content().c_str()));
        DefineGotoCase(BeforeSemiColon)
      }
      arguments.resetAnnotContext();
      DefineAddError("Expecting an identifier after decreases-for clause");
      DefineGotoCaseAndParse(BeforeSemiColon)
    DefineParseCase(Assumes)
      { logic_type thisRecordType = arguments.queryThisType();
        if (thisRecordType)
          arguments.addLogicFormal("this", thisRecordType);
        TermOrPredicate* pred = new TermOrPredicate;
        state.absorbRuleResult(&pred->setPredicate());
        DefineShiftAndParse(AssumesEnd,*pred,&TermOrPredicate::readToken)
      }
    DefineParseCase(AssumesEnd)
      { Parser::State::RuleAccess::TCastFromRule<TermOrPredicate>
          node(state.getRuleResult());
        predicate_named pred = node->extractPredicate(arguments);
        state.freeRuleResult();
        if (!pred) {
          DefineAddError("expecting a predicate");
          DefineReduceAndParse
        };
        result = parseSemiColumn(arguments, "assumes clause");
        if (result == RRFinished) return result;
        if (!_spec->behavior) {
          // Adding new default behavior
          add_behavior(default_behavior_name);
        }
        _currentAssumes.insertContainer(pred);
        _state = ASSUMES;
        DefineGotoCase(Begin)
      }
    DefineParseCase(PostCond)
      { logic_type thisRecordType = arguments.queryThisType();
        if (thisRecordType)
          arguments.addLogicFormal("this", thisRecordType);
        TermOrPredicate* pred = new TermOrPredicate;
        state.absorbRuleResult(&pred->setPredicate());
        arguments.addLogicLabel("Post");
        DefineShiftAndParse(PostCondEnd,*pred,&TermOrPredicate::readToken)
      }
    DefineParseCase(PostCondEnd)
      { Parser::State::RuleAccess::TCastFromRule<TermOrPredicate>
          node(state.getRuleResult());
        predicate_named pred = node->extractPredicate(arguments);
        state.freeRuleResult();
        if (!pred) {
          arguments.resetAnnotContext();
          DefineAddError("the body of the post-condition is not a predicate");
          _additionalMsg = "postcondition";
          DefineGotoCaseAndParse(BeforeSemiColon);
        };
        arguments.set_result_context(false);
        arguments.removeLogicLabel("Post");
        result = parseSemiColumn(arguments, "post-condition");
        if (result == RRFinished) return result;
        if (!_spec->behavior) {
          // Adding new default behavior
          add_behavior(default_behavior_name);
        }
        post_condition post = post_condition_cons(_postCondKind,pred);
        _currentPostCond.insertContainer(post);
        _state = POST_COND;
        DefineGotoCase(Begin)
      }
    DefineParseCase(Assigns)
      { 
        logic_type thisRecordType = arguments.queryThisType();
        if (thisRecordType)
          arguments.addLogicFormal("this", thisRecordType);
        AssignsClause* assigns
          = new AssignsClause(arguments.newTokenLocation());
        state.absorbRuleResult(assigns);
        arguments.addLogicLabel("Post");
        DefineShiftAndParse(AssignsEnd,*assigns,&AssignsClause::readToken);
      }
    DefineParseCase(AssignsEnd)
      { Parser::State::RuleAccess::TCastFromRule<AssignsClause>
          node(state.getRuleResult());
        ForwardList assigns = node->getResult();
        state.freeRuleResult();
        result = parseSemiColumn(arguments, "assigns");
        if (result == RRFinished) return result;
        if (!_spec->behavior) add_behavior(default_behavior_name);
        _currentAssigns.append(assigns);
        list current = _spec->behavior;
        while (current->next) current = current->next;
        behavior bhv = (behavior)current->element.container;
        if (bhv->assignements) free(bhv->assignements);
        bhv->assignements = assigns_Writes(_currentAssigns.getFront());
        DefineGotoCase(Begin)
      }
    DefineParseCase(AllocatesFrees)
    {
        logic_type thisRecordType = arguments.queryThisType();
        if (thisRecordType)
          arguments.addLogicFormal("this", thisRecordType);
        AllocFreeClause* allocFree
          = new AllocFreeClause(arguments.newTokenLocation());
        state.absorbRuleResult(allocFree);
        arguments.addLogicLabel("Post");
        DefineShiftAndParse(AllocatesFreesEnd,*allocFree,
                            &AllocFreeClause::readToken);
    }
    DefineParseCase(AllocatesFreesEnd)
    {
      Parser::State::RuleAccess::TCastFromRule<AllocFreeClause>
          node(state.getRuleResult());
      ForwardList allocFrees = node->getResult();
      state.freeRuleResult();
      result =
        parseSemiColumn(
          arguments,
          _allocClauseKind == ALLOCATES ? "allocates" : "frees");
      if (result == RRFinished) return result;
      if (!_spec->behavior) add_behavior(default_behavior_name);
      if (_allocClauseKind == ALLOCATES) {
        _currentAllocates.append(allocFrees);
      } else {
        _currentFrees.append(allocFrees);
      }
      list current = _spec->behavior;
      while (current->next) current = current->next;
      behavior bhv = (behavior)current->element.container;
      if (bhv->alloc) free(bhv->alloc);
      bhv->alloc =
        allocation_FreeAlloc(
          _currentFrees.getFront(), _currentAllocates.getFront());
      DefineGotoCase(Begin)
    }
    DefineParseCase(Complete)
    DefineParseCase(Disjoint)
      { AbstractToken token = arguments.queryToken();
        if (token.getType() == AbstractToken::TKeyword) {
          if (((const KeywordToken&) token).getType() 
              == KeywordToken::TBehaviors) {
            set_of_behaviors behaviorsSet = set_of_behaviors_cons(NULL);
            if (state.point() == DComplete)
              _complete.insertContainer(behaviorsSet);
            else
              _disjoint.insertContainer(behaviorsSet);
            _currentSetOfBehaviors
                = ForwardReferenceList(behaviorsSet->behaviors);
            DefineGotoCaseWithIncrement(DCompleteBehavior-DComplete,
              LCompleteBehavior);
          };
        };
        arguments.resetAnnotContext();
        if (state.point() == DComplete)
          DefineAddError("Expecting \"behaviors\" after complete construct")
        else
          DefineAddError("Expecting \"behaviors\" after disjoint construct")
        DefineGotoCaseAndParse(BeforeSemiColon)
      }
    DefineParseCase(CompleteBehavior)
    DefineParseCase(DisjointBehavior)
      { AbstractToken token = arguments.queryToken();
        if (token.getType() == AbstractToken::TIdentifier) {
          _currentSetOfBehaviors.insertContainer(
            strdup(((const IdentifierToken&) arguments.getContentToken())
                   .content().c_str()));
          DefineGotoCaseWithIncrement(DAfterComplete-DCompleteBehavior,
                                      LAfterComplete);
        };
        if (token.getType() == AbstractToken::TKeyword) {
          std::string name = arguments.getContentToken().text();
          _currentSetOfBehaviors.insertContainer(strdup(name.c_str()));
          DefineGotoCaseWithIncrement(DAfterComplete-DCompleteBehavior,
                                      LAfterComplete);
        };
        // Allow for empty lists: if no identifier has been added, we
        // accept a ';' and start parsing a new clause
        if (!_currentSetOfBehaviors.getFront() &&
            token.getType() == AbstractToken::TOperatorPunctuator &&
            ((const OperatorPunctuatorToken&)token).getType() ==
              OperatorPunctuatorToken::TSemiColon)
          DefineGotoCase(Begin);
        arguments.resetAnnotContext();
        if (state.point() == DCompleteBehavior)
          DefineAddError("Expecting an identifier after \"complete behaviors\" "
          "construct")
        else
          DefineAddError("Expecting an identifier after \"disjoint behaviors\" "
          "construct")
        DefineGotoCaseAndParse(BeforeSemiColon)
      }
    DefineParseCase(AfterComplete)
    DefineParseCase(AfterDisjoint)
      { AbstractToken token = arguments.queryToken();
        if (token.getType() == AbstractToken::TOperatorPunctuator) {
          OperatorPunctuatorToken::Type
            type = ((const OperatorPunctuatorToken&) token).getType();
          if (type == OperatorPunctuatorToken::TSemiColon)
            DefineGotoCase(Begin)
          if (type == OperatorPunctuatorToken::TComma)
            DefineGotoCaseWithIncrement(DCompleteBehavior-DAfterComplete,
              LCompleteBehavior);
        };
      }
      arguments.resetAnnotContext();
      if (state.point() == DAfterComplete)
        DefineAddError("Expecting ',' or ';' after complete construct")
      else
        DefineAddError("Expecting ',' or ';' after disjoint construct")
      DefineGotoCase(BeforeSemiColon)
    DefineParseCase(BeforeSemiColon)
      { AbstractToken token = arguments.queryToken();
        if (token.getType() == AbstractToken::TOperatorPunctuator) {
          OperatorPunctuatorToken::Type
            type = ((const OperatorPunctuatorToken&) token).getType();
          if (type == OperatorPunctuatorToken::TSemiColon)
            DefineGotoCase(Begin)
        };
        arguments.resetAnnotContext();
        DefineAddError(std::string("Expecting ';' after ")
            .append(_additionalMsg))
        DefineGotoCase(Begin)
      }
  } // End switch
  return result;
} // End readToken

#if defined(__clang__) || defined(__GNUC__)
#pragma GCC diagnostic pop
#endif

} // end of namespace Acsl