Skip to content
Snippets Groups Projects
ACSLCodeAnnotation.cpp 5.67 KiB
Newer Older
/**************************************************************************/
/*                                                                        */
/*  This file is part of Frama-Clang                                      */
/*                                                                        */
Virgile Prevosto's avatar
Virgile Prevosto committed
/*  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 code annotations, like an assert.
//

#include "ACSLCodeAnnotation.h"

namespace Acsl {

using namespace DLexer;

Parser::ReadResult
CodeAnnotation::readToken(Parser::State& state, Parser::Arguments& arguments)
{ enum Delimiters
  { DBegin, DAssert, DForId, DAfterForId, DEnd };

  ReadResult result = RRNeedChars;
  switch (state.point()) {
    DefineParseCase(Begin)
      arguments.setCodeAnnotContext();
      // Logic label Pre, Here and Old are always present,
      // Post only exists in post-condition, assigns and allocates
      arguments.addLogicLabel("Pre");
      arguments.addLogicLabel("Here");
      arguments.addLogicLabel("Old");
      { AbstractToken token = arguments.queryToken();
        if (token.getType() == AbstractToken::TKeyword) {
          KeywordToken::Type type = ((const KeywordToken&) token).getType();
          if (type == KeywordToken::TAssert) {
            TermOrPredicate* pred = new TermOrPredicate;
            state.absorbRuleResult(&pred->setPredicate());
            { logic_type thisRecordType = arguments.queryThisType();
              if (thisRecordType)
                arguments.addLogicFormal("this", thisRecordType);
            }
            DefineShift(Assert, *pred, &TermOrPredicate::readToken)
          }
          if (type == KeywordToken::TFor) {
            if (_behaviors)
              DefineAddError("multiple 'for' behaviors in code annotation")
            DefineGotoCase(ForId)
          }
        };
      }
      arguments.resetAnnotContext();
      DefineAddError("expecting 'assert' or 'for' in code annotation")
      DefineGotoCaseAndParse(End)
    DefineParseCase(Assert)
      { Parser::State::RuleAccess::TCastFromRule<TermOrPredicate>
          rule(state.getRuleResult());
        predicate_named pred = rule->extractPredicate(arguments);
        state.freeRuleResult();
        if (pred) {
          _annotResult = code_annotation_Assert(_behaviors, pred);
          _behaviors = NULL;
          _behaviorAdder.clear();
        }
        else {
          arguments.resetAnnotContext();
          DefineAddError("expecting a predicate");
        }
      }
      DefineGotoCaseAndParse(End)
    DefineParseCase(ForId)
      if (arguments.queryToken().getType() == AbstractToken::TIdentifier) {
        const IdentifierToken& token
            = (const IdentifierToken&) arguments.getContentToken();
        _behaviorAdder.insertContainer(strdup(token.content().c_str()));
        DefineGotoCase(AfterForId)
      }
      if (arguments.queryToken().getType() == AbstractToken::TKeyword) {
        const KeywordToken& token
            = (const KeywordToken&) arguments.getContentToken();
        _behaviorAdder.insertContainer(strdup(token.text().c_str()));
        DefineGotoCase(AfterForId)
      }
      arguments.resetAnnotContext();
      DefineAddError("expecting identifier after 'for' in code annotation")
      DefineGotoCaseAndParse(End)
    DefineParseCase(AfterForId)
      { AbstractToken token = arguments.queryToken();
        if (token.getType() == AbstractToken::TOperatorPunctuator) {
          OperatorPunctuatorToken::Type
            type = ((const OperatorPunctuatorToken&) token).getType();
          if (type == OperatorPunctuatorToken::TComma)
            DefineGotoCase(ForId)
          if (type == OperatorPunctuatorToken::TColon)
            DefineGotoCase(Begin)
        };
      }
      arguments.resetAnnotContext();
      DefineAddError("expecting ',' or ':' in a code annotation")
      DefineGotoCaseAndParse(End)
    DefineParseCase(End)
      { AbstractToken token = arguments.queryToken();
        if (token.getType() == AbstractToken::TOperatorPunctuator) {
          OperatorPunctuatorToken::Type
            type = ((const OperatorPunctuatorToken&) token).getType();
          if (type == OperatorPunctuatorToken::TSemiColon) {
            arguments.resetAnnotContext();
            DefineReduce
              }
        };
      }
      arguments.resetAnnotContext();
      DefineAddError("expecting ';' at the end of a code annotation")
      DefineGotoCase(End)
  }
  return result;
}

} // end of namespace Acsl