<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Vassil Vassilev <vvasilev@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "cling/Interpreter/InterpreterCallbacks.h"

#include "cling/Interpreter/Interpreter.h"

#include "clang/AST/ASTContext.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Sema.h"
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/ASTDeserializationListener.h"

using namespace clang;

namespace cling {

  ///\brief Translates 'interesting' for the interpreter
  /// ASTDeserializationListener events into interpreter callback.
  ///
  class InterpreterPPCallbacks : public PPCallbacks {
  private:
    cling::InterpreterCallbacks* m_Callbacks;
  public:
    InterpreterPPCallbacks(InterpreterCallbacks* C) : m_Callbacks(C) { }
    ~InterpreterPPCallbacks() { }

    virtual void InclusionDirective(clang::SourceLocation HashLoc,
                                    const clang::Token &IncludeTok,
                                    llvm::StringRef FileName,
                                    bool IsAngled,
                                    clang::CharSourceRange FilenameRange,
                                    const clang::FileEntry *File,
                                    llvm::StringRef SearchPath,
                                    llvm::StringRef RelativePath,
                                    const clang::Module *Imported) {
      if (m_Callbacks) {
        m_Callbacks->InclusionDirective(HashLoc, IncludeTok, FileName,
                                        IsAngled, FilenameRange, File,
                                        SearchPath, RelativePath, Imported);
        InterpreterCallbacks* current = m_Callbacks;
        while (current = current->getNext())
          current->InclusionDirective(HashLoc, IncludeTok, FileName,
                                      IsAngled, FilenameRange, File,
                                      SearchPath, RelativePath, Imported);;

      }
    }

    virtual bool FileNotFound(llvm::StringRef FileName,
                              llvm::SmallVectorImpl<char>& RecoveryPath) {
      if (m_Callbacks) {
        bool result = m_Callbacks->FileNotFound(FileName, RecoveryPath);
        InterpreterCallbacks* current = m_Callbacks;
        while (current = current->getNext())
          result = current->FileNotFound(FileName, RecoveryPath) || result;
        return result;
      }
      // Returning true would mean that the preprocessor should try to recover.
      return false;
    }
  };

  ///\brief Translates 'interesting' for the interpreter
  /// ASTDeserializationListener events into interpreter callback.
  ///
  class InterpreterDeserializationListener : public ASTDeserializationListener {
  private:
    cling::InterpreterCallbacks* m_Callbacks;
  public:
    InterpreterDeserializationListener(InterpreterCallbacks* C)
      : m_Callbacks(C) {}

    virtual void DeclRead(serialization::DeclID, const Decl *D) {
      if (m_Callbacks) {
        m_Callbacks->DeclDeserialized(D);
        InterpreterCallbacks* current = m_Callbacks;
        while (current = current->getNext())
          current->DeclDeserialized(D);
      }
    }

    virtual void TypeRead(serialization::TypeIdx, QualType T) {
      if (m_Callbacks) {
        m_Callbacks->TypeDeserialized(T.getTypePtr());
        InterpreterCallbacks* current = m_Callbacks;
        while (current = current->getNext())
          current->TypeDeserialized(T.getTypePtr());
      }
    }
  };

  ///\brief Translates 'interesting' for the interpreter ExternalSemaSource
  /// events into interpreter callbacks.
  ///
  class InterpreterExternalSemaSource : public clang::ExternalSemaSource {
  protected:
    ///\brief The interpreter callback which are subscribed for the events.
    ///
    /// Usually the callbacks is the owner of the class and the interpreter owns
    /// the callbacks so they can't be out of sync. Eg we notifying the wrong
    /// callback class.
    ///
    InterpreterCallbacks* m_Callbacks; // we don't own it.

    Sema* m_Sema; // we don't own // FIXME: once we remove ForgetSema delete.

  public:
    InterpreterExternalSemaSource(InterpreterCallbacks* C)
      : m_Callbacks(C), m_Sema(0) {}

    ~InterpreterExternalSemaSource() {
      // FIXME: Another gross hack due to the missing multiplexing AST external
      // source see Interpreter::setCallbacks.
      if (m_Sema) {
        ASTContext& C = m_Sema->getASTContext();
        // tell the owning ptr to not delete it, the callbacks will delete it.
        if (C.ExternalSource.get() == this)
          C.ExternalSource.resetWithoutRelease();
      }
    }

    virtual void InitializeSema(Sema& S) {
      m_Sema = &S;
    }

    virtual void ForgetSema() {
      m_Sema = 0;
    }

    InterpreterCallbacks* getCallbacks() const { return m_Callbacks; }

    /// \brief Provides last resort lookup for failed unqualified lookups.
    ///
    /// This gets translated into InterpreterCallback's call.
    ///
    ///\param[out] R The recovered symbol.
    ///\param[in] S The scope in which the lookup failed.
    ///
    ///\returns true if a suitable declaration is found.
    ///
    virtual bool LookupUnqualified(clang::LookupResult& R, clang::Scope* S) {
      if (m_Callbacks) {
        bool result = m_Callbacks->LookupObject(R, S);
        InterpreterCallbacks* current = m_Callbacks;
        while (current = current->getNext())
          result = current->LookupObject(R, S) || result;
        return result;
      }

      return false;
    }

    virtual bool FindExternalVisibleDeclsByName(const clang::DeclContext* DC,
                                                clang::DeclarationName Name) {
      if (m_Callbacks) {
        bool result = m_Callbacks->LookupObject(DC, Name);
        InterpreterCallbacks* current = m_Callbacks;
        while (current = current->getNext())
          result = current->LookupObject(DC, Name) || result;
        return result;
      }

      return false;
    }

    // Silence warning virtual function was hidden.
    using ExternalASTSource::CompleteType;
    virtual void CompleteType(TagDecl* Tag) {
      if (m_Callbacks) {
        m_Callbacks->LookupObject(Tag);
        InterpreterCallbacks* current = m_Callbacks;
        while (current = current->getNext())
          current->LookupObject(Tag);
      }
    }

    void UpdateWithNewDeclsFwd(const DeclContext *DC, DeclarationName Name,
                               llvm::ArrayRef<NamedDecl*> Decls) {
      SetExternalVisibleDeclsForName(DC, Name, Decls);
    }
  };

  InterpreterCallbacks::InterpreterCallbacks(Interpreter* interp,
                                            InterpreterExternalSemaSource* IESS,
                                        InterpreterDeserializationListener* IDL,
                                             InterpreterPPCallbacks* IPPC)
    : m_Interpreter(interp),  m_ExternalSemaSource(IESS),
      m_DeserializationListener(IDL), m_IsRuntime(false), m_Next(0) {
    if (IESS)
      m_Interpreter->getSema().addExternalSource(m_ExternalSemaSource.get());
    ASTReader* Reader = m_Interpreter->getCI()->getModuleManager().get();
    if (IDL && Reader)
      Reader->setDeserializationListener(IDL);
    if (IPPC)
      m_Interpreter->getCI()->getPreprocessor().addPPCallbacks(IPPC);
  }

  InterpreterCallbacks::InterpreterCallbacks(Interpreter* interp,
                             bool enableExternalSemaSourceCallbacks/* = false*/,
                        bool enableDeserializationListenerCallbacks/* = false*/,
                                             bool enablePPCallbacks/* = false*/)
    : m_Interpreter(interp), m_IsRuntime(false), m_Next(0) {
    if (enableExternalSemaSourceCallbacks) {
      m_ExternalSemaSource.reset(new InterpreterExternalSemaSource(this));
      m_ExternalSemaSource->InitializeSema(interp->getSema());
      m_Interpreter->getSema().addExternalSource(m_ExternalSemaSource.get());
    }

    ASTReader* Reader = m_Interpreter->getCI()->getModuleManager().get();
    if (enableDeserializationListenerCallbacks && Reader) {
      // FIXME: need to create a multiplexer if a DeserializationListener is
      // alreday present.
      m_DeserializationListener.
        reset(new InterpreterDeserializationListener(this));
      Reader->setDeserializationListener(m_DeserializationListener.get());
    }

    if (enablePPCallbacks) {
      m_PPCallbacks = new InterpreterPPCallbacks(this);
      Preprocessor& PP = m_Interpreter->getCI()->getPreprocessor();
      PP.addPPCallbacks(m_PPCallbacks);
    }
  }

  // pin the vtable here
  InterpreterCallbacks::~InterpreterCallbacks() {
    // FIXME: we have to remove the external source at destruction time. Needs
    // further tweaks of the patch in clang. This will be done later once the
    // patch is in clang's mainline.
  }

  void InterpreterCallbacks::SetIsRuntime(bool val) {
    m_IsRuntime = val;
    InterpreterCallbacks* current = this;
    while (current = current->getNext())
      current->m_IsRuntime = val;
  }

  ExternalSemaSource*
  InterpreterCallbacks::getInterpreterExternalSemaSource() const {
    return m_ExternalSemaSource.get();
  }

  ASTDeserializationListener*
  InterpreterCallbacks::getInterpreterDeserializationListener() const {
    return m_DeserializationListener.get();
  }

  bool InterpreterCallbacks::FileNotFound(llvm::StringRef FileName,
                                    llvm::SmallVectorImpl<char>& RecoveryPath) {
    // Default implementation is no op.
    return false;
  }

  bool InterpreterCallbacks::LookupObject(LookupResult&, Scope*) {
    // Default implementation is no op.
    return false;
  }

  bool InterpreterCallbacks::LookupObject(const DeclContext*, DeclarationName) {
    // Default implementation is no op.
    return false;
  }

  bool InterpreterCallbacks::LookupObject(TagDecl*) {
    // Default implementation is no op.
    return false;
  }

  void InterpreterCallbacks::UpdateWithNewDecls(const DeclContext *DC,
                                                DeclarationName Name,
                                             llvm::ArrayRef<NamedDecl*> Decls) {
    if (m_ExternalSemaSource)
      m_ExternalSemaSource->UpdateWithNewDeclsFwd(DC, Name, Decls);
  }
} // end namespace cling

// TODO: Make the build system in the testsuite aware how to build that class
// and extract it out there again.
#include "DynamicLookup.h"
#include "cling/Utils/AST.h"

#include "clang/AST/ASTContext.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
namespace cling {
namespace test {
  TestProxy* Tester = 0;

  extern "C" int printf(const char* fmt, ...);
  TestProxy::TestProxy(){}
  int TestProxy::Draw(){ return 12; }
  const char* TestProxy::getVersion(){ return "Interpreter.cpp"; }

  int TestProxy::Add10(int num) { return num + 10;}

  int TestProxy::Add(int a, int b) {
    return a + b;
  }

  void TestProxy::PrintString(std::string s) { printf("%s\n", s.c_str()); }

  bool TestProxy::PrintArray(int a[], size_t size) {
    for (unsigned i = 0; i < size; ++i)
      printf("%i", a[i]);

    printf("%s", "\n");

    return true;
  }

  void TestProxy::PrintArray(float a[][5], size_t size) {
    for (unsigned i = 0; i < size; ++i)
      for (unsigned j = 0; j < 5; ++j)
        printf("%i", (int)a[i][j]);

    printf("%s", "\n");
  }

  void TestProxy::PrintArray(int a[][4][5], size_t size) {
    for (unsigned i = 0; i < size; ++i)
      for (unsigned j = 0; j < 4; ++j)
        for (unsigned k = 0; k < 5; ++k)
          printf("%i", a[i][j][k]);

    printf("%s", "\n");
  }

  SymbolResolverCallback::SymbolResolverCallback(Interpreter* interp)
    : InterpreterCallbacks(interp, /*enableExternalSemaSourceCallbacks*/true),
      m_TesterDecl(0) {
    m_Interpreter->process("cling::test::Tester = new cling::test::TestProxy();");
  }

  SymbolResolverCallback::~SymbolResolverCallback() { }

  bool SymbolResolverCallback::LookupObject(LookupResult& R, Scope* S) {
    if (m_IsRuntime) {
      // Only for demo resolve all unknown objects to cling::test::Tester
      if (!m_TesterDecl) {
        clang::Sema& SemaR = m_Interpreter->getSema();
        clang::NamespaceDecl* NSD = utils::Lookup::Namespace(&SemaR, "cling");
        NSD = utils::Lookup::Namespace(&SemaR, "test", NSD);
        m_TesterDecl = utils::Lookup::Named(&SemaR, "Tester", NSD);
      }
      assert (m_TesterDecl && "Tester not found!");
      R.addDecl(m_TesterDecl);
      return true; // Tell clang to continue.
    }

    if (ShouldResolveAtRuntime(R, S)) {
      ASTContext& C = R.getSema().getASTContext();
      DeclContext* DC = 0;
      // For DeclContext-less scopes like if (dyn_expr) {}
      while (!DC) {
        DC = static_cast<DeclContext*>(S->getEntity());
        S = S->getParent();
      }
      DeclarationName Name = R.getLookupName();
      IdentifierInfo* II = Name.getAsIdentifierInfo();
      SourceLocation Loc = R.getNameLoc();
      VarDecl* Res = VarDecl::Create(C, DC, Loc, Loc, II, C.DependentTy,
                                     /*TypeSourceInfo*/0, SC_None);

      // Annotate the decl to give a hint in cling. FIXME: Current implementation
      // is a gross hack, because TClingCallbacks shouldn't know about
      // EvaluateTSynthesizer at all!
      SourceRange invalidRange;
      Res->addAttr(new (C) AnnotateAttr(invalidRange, C, "__ResolveAtRuntime", 0));
      R.addDecl(Res);
      DC->addDecl(Res);
      // Say that we can handle the situation. Clang should try to recover
      return true;
    }

    return false;
  }

  bool SymbolResolverCallback::ShouldResolveAtRuntime(LookupResult& R,
                                                      Scope* S) {

    if (R.getLookupKind() != Sema::LookupOrdinaryName)
      return false;

    if (R.isForRedeclaration())
      return false;

    if (!R.empty())
      return false;

    // FIXME: Figure out better way to handle:
    // C++ [basic.lookup.classref]p1:
    //   In a class member access expression (5.2.5), if the . or -> token is
    //   immediately followed by an identifier followed by a <, the
    //   identifier must be looked up to determine whether the < is the
    //   beginning of a template argument list (14.2) or a less-than operator.
    //   The identifier is first looked up in the class of the object
    //   expression. If the identifier is not found, it is then looked up in
    //   the context of the entire postfix-expression and shall name a class
    //   or function template.
    //
    // We want to ignore object(.|->)member<template>
    if (R.getSema().PP.LookAhead(0).getKind() == tok::less)
      // TODO: check for . or -> in the cached token stream
      return false;

    for (Scope* DepScope = S; DepScope; DepScope = DepScope->getParent()) {
      if (DeclContext* Ctx = static_cast<DeclContext*>(DepScope->getEntity())) {
        if (!Ctx->isDependentContext())
          // For now we support only the prompt.
          if (isa<FunctionDecl>(Ctx))
            return true;
      }
    }

    return false;
  }

} // end test
} // end cling
<commit_msg>No need to create an extra external sema source.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Vassil Vassilev <vvasilev@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "cling/Interpreter/InterpreterCallbacks.h"

#include "cling/Interpreter/Interpreter.h"

#include "clang/AST/ASTContext.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Sema.h"
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/ASTDeserializationListener.h"

using namespace clang;

namespace cling {

  ///\brief Translates 'interesting' for the interpreter
  /// ASTDeserializationListener events into interpreter callback.
  ///
  class InterpreterPPCallbacks : public PPCallbacks {
  private:
    cling::InterpreterCallbacks* m_Callbacks;
  public:
    InterpreterPPCallbacks(InterpreterCallbacks* C) : m_Callbacks(C) { }
    ~InterpreterPPCallbacks() { }

    virtual void InclusionDirective(clang::SourceLocation HashLoc,
                                    const clang::Token &IncludeTok,
                                    llvm::StringRef FileName,
                                    bool IsAngled,
                                    clang::CharSourceRange FilenameRange,
                                    const clang::FileEntry *File,
                                    llvm::StringRef SearchPath,
                                    llvm::StringRef RelativePath,
                                    const clang::Module *Imported) {
      if (m_Callbacks) {
        m_Callbacks->InclusionDirective(HashLoc, IncludeTok, FileName,
                                        IsAngled, FilenameRange, File,
                                        SearchPath, RelativePath, Imported);
        InterpreterCallbacks* current = m_Callbacks;
        while (current = current->getNext())
          current->InclusionDirective(HashLoc, IncludeTok, FileName,
                                      IsAngled, FilenameRange, File,
                                      SearchPath, RelativePath, Imported);;

      }
    }

    virtual bool FileNotFound(llvm::StringRef FileName,
                              llvm::SmallVectorImpl<char>& RecoveryPath) {
      if (m_Callbacks) {
        bool result = m_Callbacks->FileNotFound(FileName, RecoveryPath);
        InterpreterCallbacks* current = m_Callbacks;
        while (current = current->getNext())
          result = current->FileNotFound(FileName, RecoveryPath) || result;
        return result;
      }
      // Returning true would mean that the preprocessor should try to recover.
      return false;
    }
  };

  ///\brief Translates 'interesting' for the interpreter
  /// ASTDeserializationListener events into interpreter callback.
  ///
  class InterpreterDeserializationListener : public ASTDeserializationListener {
  private:
    cling::InterpreterCallbacks* m_Callbacks;
  public:
    InterpreterDeserializationListener(InterpreterCallbacks* C)
      : m_Callbacks(C) {}

    virtual void DeclRead(serialization::DeclID, const Decl *D) {
      if (m_Callbacks) {
        m_Callbacks->DeclDeserialized(D);
        InterpreterCallbacks* current = m_Callbacks;
        while (current = current->getNext())
          current->DeclDeserialized(D);
      }
    }

    virtual void TypeRead(serialization::TypeIdx, QualType T) {
      if (m_Callbacks) {
        m_Callbacks->TypeDeserialized(T.getTypePtr());
        InterpreterCallbacks* current = m_Callbacks;
        while (current = current->getNext())
          current->TypeDeserialized(T.getTypePtr());
      }
    }
  };

  ///\brief Translates 'interesting' for the interpreter ExternalSemaSource
  /// events into interpreter callbacks.
  ///
  class InterpreterExternalSemaSource : public clang::ExternalSemaSource {
  protected:
    ///\brief The interpreter callback which are subscribed for the events.
    ///
    /// Usually the callbacks is the owner of the class and the interpreter owns
    /// the callbacks so they can't be out of sync. Eg we notifying the wrong
    /// callback class.
    ///
    InterpreterCallbacks* m_Callbacks; // we don't own it.

    Sema* m_Sema; // we don't own // FIXME: once we remove ForgetSema delete.

  public:
    InterpreterExternalSemaSource(InterpreterCallbacks* C)
      : m_Callbacks(C), m_Sema(0) {}

    ~InterpreterExternalSemaSource() {
      // FIXME: Another gross hack due to the missing multiplexing AST external
      // source see Interpreter::setCallbacks.
      if (m_Sema) {
        ASTContext& C = m_Sema->getASTContext();
        // tell the owning ptr to not delete it, the callbacks will delete it.
        if (C.ExternalSource.get() == this)
          C.ExternalSource.resetWithoutRelease();
      }
    }

    virtual void InitializeSema(Sema& S) {
      m_Sema = &S;
    }

    virtual void ForgetSema() {
      m_Sema = 0;
    }

    InterpreterCallbacks* getCallbacks() const { return m_Callbacks; }

    /// \brief Provides last resort lookup for failed unqualified lookups.
    ///
    /// This gets translated into InterpreterCallback's call.
    ///
    ///\param[out] R The recovered symbol.
    ///\param[in] S The scope in which the lookup failed.
    ///
    ///\returns true if a suitable declaration is found.
    ///
    virtual bool LookupUnqualified(clang::LookupResult& R, clang::Scope* S) {
      if (m_Callbacks) {
        bool result = m_Callbacks->LookupObject(R, S);
        InterpreterCallbacks* current = m_Callbacks;
        while (current = current->getNext())
          result = current->LookupObject(R, S) || result;
        return result;
      }

      return false;
    }

    virtual bool FindExternalVisibleDeclsByName(const clang::DeclContext* DC,
                                                clang::DeclarationName Name) {
      if (m_Callbacks) {
        bool result = m_Callbacks->LookupObject(DC, Name);
        InterpreterCallbacks* current = m_Callbacks;
        while (current = current->getNext())
          result = current->LookupObject(DC, Name) || result;
        return result;
      }

      return false;
    }

    // Silence warning virtual function was hidden.
    using ExternalASTSource::CompleteType;
    virtual void CompleteType(TagDecl* Tag) {
      if (m_Callbacks) {
        m_Callbacks->LookupObject(Tag);
        InterpreterCallbacks* current = m_Callbacks;
        while (current = current->getNext())
          current->LookupObject(Tag);
      }
    }

    void UpdateWithNewDeclsFwd(const DeclContext *DC, DeclarationName Name,
                               llvm::ArrayRef<NamedDecl*> Decls) {
      SetExternalVisibleDeclsForName(DC, Name, Decls);
    }
  };

  InterpreterCallbacks::InterpreterCallbacks(Interpreter* interp,
                                            InterpreterExternalSemaSource* IESS,
                                        InterpreterDeserializationListener* IDL,
                                             InterpreterPPCallbacks* IPPC)
    : m_Interpreter(interp),  m_ExternalSemaSource(IESS),
      m_DeserializationListener(IDL), m_IsRuntime(false), m_Next(0) {
    if (IESS)
      m_Interpreter->getSema().addExternalSource(m_ExternalSemaSource.get());
    ASTReader* Reader = m_Interpreter->getCI()->getModuleManager().get();
    if (IDL && Reader)
      Reader->setDeserializationListener(IDL);
    if (IPPC)
      m_Interpreter->getCI()->getPreprocessor().addPPCallbacks(IPPC);
  }

  InterpreterCallbacks::InterpreterCallbacks(Interpreter* interp,
                             bool enableExternalSemaSourceCallbacks/* = false*/,
                        bool enableDeserializationListenerCallbacks/* = false*/,
                                             bool enablePPCallbacks/* = false*/)
    : m_Interpreter(interp), m_IsRuntime(false), m_Next(0) {
    if (enableExternalSemaSourceCallbacks) {
      m_ExternalSemaSource.reset(new InterpreterExternalSemaSource(this));
      m_ExternalSemaSource->InitializeSema(interp->getSema());
      m_Interpreter->getSema().addExternalSource(m_ExternalSemaSource.get());
    }

    ASTReader* Reader = m_Interpreter->getCI()->getModuleManager().get();
    if (enableDeserializationListenerCallbacks && Reader) {
      // FIXME: need to create a multiplexer if a DeserializationListener is
      // alreday present.
      m_DeserializationListener.
        reset(new InterpreterDeserializationListener(this));
      Reader->setDeserializationListener(m_DeserializationListener.get());
    }

    if (enablePPCallbacks) {
      m_PPCallbacks = new InterpreterPPCallbacks(this);
      Preprocessor& PP = m_Interpreter->getCI()->getPreprocessor();
      PP.addPPCallbacks(m_PPCallbacks);
    }
  }

  // pin the vtable here
  InterpreterCallbacks::~InterpreterCallbacks() {
    // FIXME: we have to remove the external source at destruction time. Needs
    // further tweaks of the patch in clang. This will be done later once the
    // patch is in clang's mainline.
  }

  void InterpreterCallbacks::SetIsRuntime(bool val) {
    m_IsRuntime = val;
    InterpreterCallbacks* current = this;
    while (current = current->getNext())
      current->m_IsRuntime = val;
  }

  ExternalSemaSource*
  InterpreterCallbacks::getInterpreterExternalSemaSource() const {
    return m_ExternalSemaSource.get();
  }

  ASTDeserializationListener*
  InterpreterCallbacks::getInterpreterDeserializationListener() const {
    return m_DeserializationListener.get();
  }

  bool InterpreterCallbacks::FileNotFound(llvm::StringRef FileName,
                                    llvm::SmallVectorImpl<char>& RecoveryPath) {
    // Default implementation is no op.
    return false;
  }

  bool InterpreterCallbacks::LookupObject(LookupResult&, Scope*) {
    // Default implementation is no op.
    return false;
  }

  bool InterpreterCallbacks::LookupObject(const DeclContext*, DeclarationName) {
    // Default implementation is no op.
    return false;
  }

  bool InterpreterCallbacks::LookupObject(TagDecl*) {
    // Default implementation is no op.
    return false;
  }

  void InterpreterCallbacks::UpdateWithNewDecls(const DeclContext *DC,
                                                DeclarationName Name,
                                             llvm::ArrayRef<NamedDecl*> Decls) {
    if (m_ExternalSemaSource)
      m_ExternalSemaSource->UpdateWithNewDeclsFwd(DC, Name, Decls);
  }
} // end namespace cling

// TODO: Make the build system in the testsuite aware how to build that class
// and extract it out there again.
#include "DynamicLookup.h"
#include "cling/Utils/AST.h"

#include "clang/AST/ASTContext.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
namespace cling {
namespace test {
  TestProxy* Tester = 0;

  extern "C" int printf(const char* fmt, ...);
  TestProxy::TestProxy(){}
  int TestProxy::Draw(){ return 12; }
  const char* TestProxy::getVersion(){ return "Interpreter.cpp"; }

  int TestProxy::Add10(int num) { return num + 10;}

  int TestProxy::Add(int a, int b) {
    return a + b;
  }

  void TestProxy::PrintString(std::string s) { printf("%s\n", s.c_str()); }

  bool TestProxy::PrintArray(int a[], size_t size) {
    for (unsigned i = 0; i < size; ++i)
      printf("%i", a[i]);

    printf("%s", "\n");

    return true;
  }

  void TestProxy::PrintArray(float a[][5], size_t size) {
    for (unsigned i = 0; i < size; ++i)
      for (unsigned j = 0; j < 5; ++j)
        printf("%i", (int)a[i][j]);

    printf("%s", "\n");
  }

  void TestProxy::PrintArray(int a[][4][5], size_t size) {
    for (unsigned i = 0; i < size; ++i)
      for (unsigned j = 0; j < 4; ++j)
        for (unsigned k = 0; k < 5; ++k)
          printf("%i", a[i][j][k]);

    printf("%s", "\n");
  }

  SymbolResolverCallback::SymbolResolverCallback(Interpreter* interp)
    : InterpreterCallbacks(interp),
      m_TesterDecl(0) {
    m_Interpreter->process("cling::test::Tester = new cling::test::TestProxy();");
  }

  SymbolResolverCallback::~SymbolResolverCallback() { }

  bool SymbolResolverCallback::LookupObject(LookupResult& R, Scope* S) {
    if (m_IsRuntime) {
      // Only for demo resolve all unknown objects to cling::test::Tester
      if (!m_TesterDecl) {
        clang::Sema& SemaR = m_Interpreter->getSema();
        clang::NamespaceDecl* NSD = utils::Lookup::Namespace(&SemaR, "cling");
        NSD = utils::Lookup::Namespace(&SemaR, "test", NSD);
        m_TesterDecl = utils::Lookup::Named(&SemaR, "Tester", NSD);
      }
      assert (m_TesterDecl && "Tester not found!");
      R.addDecl(m_TesterDecl);
      return true; // Tell clang to continue.
    }

    if (ShouldResolveAtRuntime(R, S)) {
      ASTContext& C = R.getSema().getASTContext();
      DeclContext* DC = 0;
      // For DeclContext-less scopes like if (dyn_expr) {}
      while (!DC) {
        DC = static_cast<DeclContext*>(S->getEntity());
        S = S->getParent();
      }
      DeclarationName Name = R.getLookupName();
      IdentifierInfo* II = Name.getAsIdentifierInfo();
      SourceLocation Loc = R.getNameLoc();
      VarDecl* Res = VarDecl::Create(C, DC, Loc, Loc, II, C.DependentTy,
                                     /*TypeSourceInfo*/0, SC_None);

      // Annotate the decl to give a hint in cling. FIXME: Current implementation
      // is a gross hack, because TClingCallbacks shouldn't know about
      // EvaluateTSynthesizer at all!
      SourceRange invalidRange;
      Res->addAttr(new (C) AnnotateAttr(invalidRange, C, "__ResolveAtRuntime", 0));
      R.addDecl(Res);
      DC->addDecl(Res);
      // Say that we can handle the situation. Clang should try to recover
      return true;
    }

    return false;
  }

  bool SymbolResolverCallback::ShouldResolveAtRuntime(LookupResult& R,
                                                      Scope* S) {

    if (R.getLookupKind() != Sema::LookupOrdinaryName)
      return false;

    if (R.isForRedeclaration())
      return false;

    if (!R.empty())
      return false;

    // FIXME: Figure out better way to handle:
    // C++ [basic.lookup.classref]p1:
    //   In a class member access expression (5.2.5), if the . or -> token is
    //   immediately followed by an identifier followed by a <, the
    //   identifier must be looked up to determine whether the < is the
    //   beginning of a template argument list (14.2) or a less-than operator.
    //   The identifier is first looked up in the class of the object
    //   expression. If the identifier is not found, it is then looked up in
    //   the context of the entire postfix-expression and shall name a class
    //   or function template.
    //
    // We want to ignore object(.|->)member<template>
    if (R.getSema().PP.LookAhead(0).getKind() == tok::less)
      // TODO: check for . or -> in the cached token stream
      return false;

    for (Scope* DepScope = S; DepScope; DepScope = DepScope->getParent()) {
      if (DeclContext* Ctx = static_cast<DeclContext*>(DepScope->getEntity())) {
        if (!Ctx->isDependentContext())
          // For now we support only the prompt.
          if (isa<FunctionDecl>(Ctx))
            return true;
      }
    }

    return false;
  }

} // end test
} // end cling
<|endoftext|>


<commit_before>#include "logging.hpp"

#include <android/log.h>
#include <cassert>

#include "../../../../../base/assert.hpp"
#include "../../../../../base/logging.hpp"
#include "../../../../../base/exception.hpp"
#include "../../../../../coding/file_writer.hpp"
#include "../../../../../platform/platform.hpp"

#include "../../../../../std/unique_ptr.hpp"

//#define MWM_LOG_TO_FILE

namespace jni
{

using namespace my;

void AndroidLogMessage(LogLevel l, SrcPoint const & src, string const & s)
{
  android_LogPriority pr = ANDROID_LOG_SILENT;

  switch (l)
  {
  case LINFO: pr = ANDROID_LOG_INFO; break;
  case LDEBUG: pr = ANDROID_LOG_DEBUG; break;
  case LWARNING: pr = ANDROID_LOG_WARN; break;
  case LERROR: pr = ANDROID_LOG_ERROR; break;
  case LCRITICAL: pr = ANDROID_LOG_FATAL; break;
  }

  string const out = DebugPrint(src) + " " + s;
  __android_log_write(pr, "MapsWithMe_JNI", out.c_str());
}

void AndroidLogToFile(LogLevel l, SrcPoint const & src, string const & s)
{
  static unique_ptr<FileWriter> file;

  if (file == NULL)
  {
    if (GetPlatform().WritableDir().empty())
      return;

    file.reset(new FileWriter(GetPlatform().WritablePathForFile("logging.txt")));
  }

  string srcString = DebugPrint(src) + " " + s + "\n";

  file->Write(srcString.c_str(), srcString.size());
  file->Flush();
}

void AndroidAssertMessage(SrcPoint const & src, string const & s)
{
#if defined(MWM_LOG_TO_FILE)
  AndroidLogToFile(LERROR, src, s);
#else
  AndroidLogMessage(LERROR, src, s);
#endif

#ifdef DEBUG
    assert(false);
#else
    MYTHROW(RootException, (s));
#endif
}

void InitSystemLog()
{
#if defined(MWM_LOG_TO_FILE)
  SetLogMessageFn(&AndroidLogToFile);
#else
  SetLogMessageFn(&AndroidLogMessage);
#endif
}

void InitAssertLog()
{
  SetAssertFunction(&AndroidAssertMessage);
}

}
<commit_msg>[android] Added DbgPrintC function in case when need to debug some c-code with logs.<commit_after>#include "logging.hpp"

#include <android/log.h>
#include <cassert>

#include "../../../../../base/assert.hpp"
#include "../../../../../base/logging.hpp"
#include "../../../../../base/exception.hpp"
#include "../../../../../coding/file_writer.hpp"
#include "../../../../../platform/platform.hpp"

#include "../../../../../std/unique_ptr.hpp"

//#define MWM_LOG_TO_FILE

namespace jni
{

using namespace my;

void AndroidLogMessage(LogLevel l, SrcPoint const & src, string const & s)
{
  android_LogPriority pr = ANDROID_LOG_SILENT;

  switch (l)
  {
  case LINFO: pr = ANDROID_LOG_INFO; break;
  case LDEBUG: pr = ANDROID_LOG_DEBUG; break;
  case LWARNING: pr = ANDROID_LOG_WARN; break;
  case LERROR: pr = ANDROID_LOG_ERROR; break;
  case LCRITICAL: pr = ANDROID_LOG_FATAL; break;
  }

  string const out = DebugPrint(src) + " " + s;
  __android_log_write(pr, "MapsWithMe_JNI", out.c_str());
}

void AndroidLogToFile(LogLevel l, SrcPoint const & src, string const & s)
{
  static unique_ptr<FileWriter> file;

  if (file == NULL)
  {
    if (GetPlatform().WritableDir().empty())
      return;

    file.reset(new FileWriter(GetPlatform().WritablePathForFile("logging.txt")));
  }

  string srcString = DebugPrint(src) + " " + s + "\n";

  file->Write(srcString.c_str(), srcString.size());
  file->Flush();
}

void AndroidAssertMessage(SrcPoint const & src, string const & s)
{
#if defined(MWM_LOG_TO_FILE)
  AndroidLogToFile(LERROR, src, s);
#else
  AndroidLogMessage(LERROR, src, s);
#endif

#ifdef DEBUG
    assert(false);
#else
    MYTHROW(RootException, (s));
#endif
}

void InitSystemLog()
{
#if defined(MWM_LOG_TO_FILE)
  SetLogMessageFn(&AndroidLogToFile);
#else
  SetLogMessageFn(&AndroidLogMessage);
#endif
}

void InitAssertLog()
{
  SetAssertFunction(&AndroidAssertMessage);
}

}

extern "C" {

void DbgPrintC(char const * format, ...)
{
  va_list argptr;
  va_start(argptr, format);

  __android_log_vprint(ANDROID_LOG_INFO, "MapsWithMe_Debug", format, argptr);

  va_end(argptr);
}

}
<|endoftext|>


<commit_before>#include "nova_renderer/frontend/procedural_mesh.hpp"

#include "nova_renderer/render_engine.hpp"

#include "../memory/block_allocation_strategy.hpp"
#include "../memory/mallocator.hpp"
#include "../util/logger.hpp"
#include "../util/memory_utils.hpp"

namespace nova::renderer {
    using namespace rhi;

    ProceduralMesh::ProceduralMesh(uint64_t vertex_buffer_size, uint64_t index_buffer_size, RenderEngine& device)
        : render_engine(device)
#ifndef NDEBUG
          ,
          vertex_buffer_size(vertex_buffer_size),
          index_buffer_size(index_buffer_size)
#endif
    {
        const auto aligned_vertex_buffer_size = bvestl::polyalloc::align(vertex_buffer_size, 256);
        const auto aligned_index_buffer_size = bvestl::polyalloc::align(index_buffer_size, 256);
        const auto host_memory_size = aligned_vertex_buffer_size + aligned_index_buffer_size;
        const auto device_memory_size = host_memory_size * 3;

        // TODO: Don't allocate a separate device memory for each procedural mesh
        device.allocate_device_memory(device_memory_size.b_count(), MemoryUsage::LowFrequencyUpload, ObjectType::Buffer)
            .map([&](DeviceMemory* memory) {
                // TODO: Find a good way to keep these around
                const auto
                    allocation_strategy = std::make_unique<bvestl::polyalloc::BlockAllocationStrategy>(new bvestl::polyalloc::Mallocator(),
                                                                                device_memory_size);
                auto memory_resource = DeviceMemoryResource(memory, allocation_strategy.get());

                const auto vertex_create_info = BufferCreateInfo{vertex_buffer_size, BufferUsage::VertexBuffer};
                for(auto& vertex_buffer : vertex_buffers) {
                    vertex_buffer = device.create_buffer(vertex_create_info, memory_resource);
                }

                const auto index_create_info = BufferCreateInfo{index_buffer_size, BufferUsage::IndexBuffer};
                for(auto& index_buffer : index_buffers) {
                    index_buffer = device.create_buffer(index_create_info, memory_resource);
                }

                return ntl::Result<bool>(true);
            })
            .on_error([](const ntl::NovaError& error) {
                NOVA_LOG(ERROR) << "Could not allocate device memory for procedural mesh. Error: " << error.to_string();
                // TODO: Propagate the error
            });

        device.allocate_device_memory(host_memory_size.b_count(), MemoryUsage::StagingBuffer, ObjectType::Buffer)
            .map([&](DeviceMemory* memory) {
                // TODO: Find a good way to keep these around
                const auto
                    allocation_strategy = std::make_unique<bvestl::polyalloc::BlockAllocationStrategy>(new bvestl::polyalloc::Mallocator(),
                                                                                host_memory_size);
                auto memory_resource = DeviceMemoryResource(memory, allocation_strategy.get());

                cached_vertex_buffer = device.create_buffer({vertex_buffer_size, BufferUsage::StagingBuffer}, memory_resource);
                cached_index_buffer = device.create_buffer({index_buffer_size, BufferUsage::StagingBuffer}, memory_resource);

                return ntl::Result<bool>(true);
            })
            .on_error([](const ntl::NovaError& error) {
                NOVA_LOG(ERROR) << "Could not allocate host memory for procedural mesh. Error: " << error.to_string();
                // TODO: Propagate the error
            });
    }

    void ProceduralMesh::set_vertex_data(const void* data, const uint64_t size) {
        render_engine.write_data_to_buffer(data, size, 0, cached_vertex_buffer);
        num_vertex_bytes_to_upload = size;
    }

    void ProceduralMesh::set_index_data(const void* data, const uint64_t size) {
        render_engine.write_data_to_buffer(data, size, 0, cached_index_buffer);
        num_index_bytes_to_upload = size;
    }

    void ProceduralMesh::record_commands_to_upload_data(CommandList* cmds, const uint8_t frame_idx) {
        const bool should_upload_vertex_buffer = num_vertex_bytes_to_upload > 0;
        const bool should_upload_index_buffer = num_index_bytes_to_upload > 0;

        auto* cur_vertex_buffer = vertex_buffers.at(frame_idx);
        auto* cur_index_buffer = index_buffers.at(frame_idx);

        std::vector<ResourceBarrier> barriers_before_upload;

        if(should_upload_vertex_buffer) {
            ResourceBarrier barrier_before_vertex_upload = {};
            barrier_before_vertex_upload.resource_to_barrier = cur_vertex_buffer;
            barrier_before_vertex_upload.access_before_barrier = AccessFlags::VertexAttributeRead;
            barrier_before_vertex_upload.access_after_barrier = AccessFlags::MemoryWrite;
            barrier_before_vertex_upload.old_state = ResourceState::VertexBuffer;
            barrier_before_vertex_upload.new_state = ResourceState::CopyDestination;
            barrier_before_vertex_upload.source_queue = QueueType::Graphics;
            barrier_before_vertex_upload.destination_queue = QueueType::Transfer;
            barrier_before_vertex_upload.buffer_memory_barrier.offset = 0;
            barrier_before_vertex_upload.buffer_memory_barrier.size = num_vertex_bytes_to_upload;

            barriers_before_upload.push_back(barrier_before_vertex_upload);
        }

        if(should_upload_index_buffer) {
            ResourceBarrier barrier_before_index_upload = {};
            barrier_before_index_upload.resource_to_barrier = cur_index_buffer;
            barrier_before_index_upload.access_before_barrier = AccessFlags::IndexRead;
            barrier_before_index_upload.access_after_barrier = AccessFlags::MemoryWrite;
            barrier_before_index_upload.old_state = ResourceState::IndexBuffer;
            barrier_before_index_upload.new_state = ResourceState::CopyDestination;
            barrier_before_index_upload.source_queue = QueueType::Graphics;
            barrier_before_index_upload.destination_queue = QueueType::Transfer;
            barrier_before_index_upload.buffer_memory_barrier.offset = 0;
            barrier_before_index_upload.buffer_memory_barrier.size = num_vertex_bytes_to_upload;

            barriers_before_upload.push_back(barrier_before_index_upload);
        }

        if(barriers_before_upload.empty()) {
            return;
        }

        cmds->resource_barriers(PipelineStageFlags::BottomOfPipe, PipelineStageFlags::Transfer, barriers_before_upload);

        if(should_upload_vertex_buffer) {
            cmds->copy_buffer(cur_vertex_buffer, 0, cached_vertex_buffer, 0, num_vertex_bytes_to_upload);
        }

        if(should_upload_index_buffer) {
            cmds->copy_buffer(cur_index_buffer, 0, cached_index_buffer, 0, num_index_bytes_to_upload);
        }

        std::vector<ResourceBarrier> barriers_after_upload;

        if(should_upload_vertex_buffer) {
            ResourceBarrier barrier_after_vertex_upload = {};
            barrier_after_vertex_upload.resource_to_barrier = cur_vertex_buffer;
            barrier_after_vertex_upload.access_before_barrier = AccessFlags::MemoryWrite;
            barrier_after_vertex_upload.access_after_barrier = AccessFlags::VertexAttributeRead;
            barrier_after_vertex_upload.old_state = ResourceState::CopyDestination;
            barrier_after_vertex_upload.new_state = ResourceState::VertexBuffer;
            barrier_after_vertex_upload.source_queue = QueueType::Graphics;
            barrier_after_vertex_upload.destination_queue = QueueType::Graphics;
            barrier_after_vertex_upload.buffer_memory_barrier.offset = 0;
            barrier_after_vertex_upload.buffer_memory_barrier.size = num_vertex_bytes_to_upload;
            barriers_after_upload.push_back(barrier_after_vertex_upload);
        }

        if(should_upload_index_buffer) {
            ResourceBarrier barrier_after_index_upload = {};
            barrier_after_index_upload.resource_to_barrier = cur_index_buffer;
            barrier_after_index_upload.access_before_barrier = AccessFlags::MemoryWrite;
            barrier_after_index_upload.access_after_barrier = AccessFlags::IndexRead;
            barrier_after_index_upload.old_state = ResourceState::CopyDestination;
            barrier_after_index_upload.new_state = ResourceState::IndexBuffer;
            barrier_after_index_upload.source_queue = QueueType::Graphics;
            barrier_after_index_upload.destination_queue = QueueType::Graphics;
            barrier_after_index_upload.buffer_memory_barrier.offset = 0;
            barrier_after_index_upload.buffer_memory_barrier.size = num_index_bytes_to_upload;
            barriers_after_upload.push_back(barrier_after_index_upload);
        }

        if(barriers_after_upload.empty()) {
            return;
        }

        cmds->resource_barriers(PipelineStageFlags::Transfer, PipelineStageFlags::TopOfPipe, barriers_after_upload);
    }
} // namespace nova::renderer
<commit_msg>[frontend] Add error checking in debug mode<commit_after>#include "nova_renderer/frontend/procedural_mesh.hpp"

#include "nova_renderer/render_engine.hpp"

#include "../memory/block_allocation_strategy.hpp"
#include "../memory/mallocator.hpp"
#include "../util/logger.hpp"
#include "../util/memory_utils.hpp"

namespace nova::renderer {
    using namespace rhi;

    ProceduralMesh::ProceduralMesh(const uint64_t vertex_buffer_size, const uint64_t index_buffer_size, RenderEngine& device)
        : render_engine(device)
#ifndef NDEBUG
          ,
          vertex_buffer_size(vertex_buffer_size),
          index_buffer_size(index_buffer_size)
#endif
    {
        const auto aligned_vertex_buffer_size = bvestl::polyalloc::align(vertex_buffer_size, 256);
        const auto aligned_index_buffer_size = bvestl::polyalloc::align(index_buffer_size, 256);
        const auto host_memory_size = aligned_vertex_buffer_size + aligned_index_buffer_size;
        const auto device_memory_size = host_memory_size * 3;

        // TODO: Don't allocate a separate device memory for each procedural mesh
        device.allocate_device_memory(device_memory_size.b_count(), MemoryUsage::LowFrequencyUpload, ObjectType::Buffer)
            .map([&](DeviceMemory* memory) {
                // TODO: Find a good way to keep these around
                const auto
                    allocation_strategy = std::make_unique<bvestl::polyalloc::BlockAllocationStrategy>(new bvestl::polyalloc::Mallocator(),
                                                                                device_memory_size);
                auto memory_resource = DeviceMemoryResource(memory, allocation_strategy.get());

                const auto vertex_create_info = BufferCreateInfo{vertex_buffer_size, BufferUsage::VertexBuffer};
                for(auto& vertex_buffer : vertex_buffers) {
                    vertex_buffer = device.create_buffer(vertex_create_info, memory_resource);
                }

                const auto index_create_info = BufferCreateInfo{index_buffer_size, BufferUsage::IndexBuffer};
                for(auto& index_buffer : index_buffers) {
                    index_buffer = device.create_buffer(index_create_info, memory_resource);
                }

                return ntl::Result<bool>(true);
            })
            .on_error([](const ntl::NovaError& error) {
                NOVA_LOG(ERROR) << "Could not allocate device memory for procedural mesh. Error: " << error.to_string();
                // TODO: Propagate the error
            });

        device.allocate_device_memory(host_memory_size.b_count(), MemoryUsage::StagingBuffer, ObjectType::Buffer)
            .map([&](DeviceMemory* memory) {
                // TODO: Find a good way to keep these around
                const auto
                    allocation_strategy = std::make_unique<bvestl::polyalloc::BlockAllocationStrategy>(new bvestl::polyalloc::Mallocator(),
                                                                                host_memory_size);
                auto memory_resource = DeviceMemoryResource(memory, allocation_strategy.get());

                cached_vertex_buffer = device.create_buffer({vertex_buffer_size, BufferUsage::StagingBuffer}, memory_resource);
                cached_index_buffer = device.create_buffer({index_buffer_size, BufferUsage::StagingBuffer}, memory_resource);

                return ntl::Result<bool>(true);
            })
            .on_error([](const ntl::NovaError& error) {
                NOVA_LOG(ERROR) << "Could not allocate host memory for procedural mesh. Error: " << error.to_string();
                // TODO: Propagate the error
            });
    }

    void ProceduralMesh::set_vertex_data(const void* data, const uint64_t size) {
#ifndef NDEBUG
        if(size > vertex_buffer_size) {
            NOVA_LOG(ERROR) << "Cannot upload vertex data. There's only space for " << vertex_buffer_size << " bytes, you tried to upload "
                            << size << ". Truncating vertex data to fit";

            render_engine.write_data_to_buffer(data, vertex_buffer_size, 0, cached_vertex_buffer);
            num_vertex_bytes_to_upload = vertex_buffer_size;

        } else {
#endif

            render_engine.write_data_to_buffer(data, size, 0, cached_vertex_buffer);
            num_vertex_bytes_to_upload = size;

#ifndef NDEBUG
        }
#endif
    }

    void ProceduralMesh::set_index_data(const void* data, const uint64_t size) {
#ifndef NDEBUG
        if(size > index_buffer_size) {
            NOVA_LOG(ERROR) << "Cannot upload index data. There's only space for " << index_buffer_size << " bytes, you tried to upload "
                            << size << ". Truncating vertex data to fit";

            render_engine.write_data_to_buffer(data, index_buffer_size, 0, cached_index_buffer);
            num_index_bytes_to_upload = index_buffer_size;

        } else {
#endif
            render_engine.write_data_to_buffer(data, size, 0, cached_index_buffer);
            num_index_bytes_to_upload = size;

#ifndef NDEBUG
        }
#endif
    }

    void ProceduralMesh::record_commands_to_upload_data(CommandList* cmds, const uint8_t frame_idx) {
        const bool should_upload_vertex_buffer = num_vertex_bytes_to_upload > 0;
        const bool should_upload_index_buffer = num_index_bytes_to_upload > 0;

        auto* cur_vertex_buffer = vertex_buffers.at(frame_idx);
        auto* cur_index_buffer = index_buffers.at(frame_idx);

        std::vector<ResourceBarrier> barriers_before_upload;

        if(should_upload_vertex_buffer) {
            ResourceBarrier barrier_before_vertex_upload = {};
            barrier_before_vertex_upload.resource_to_barrier = cur_vertex_buffer;
            barrier_before_vertex_upload.access_before_barrier = AccessFlags::VertexAttributeRead;
            barrier_before_vertex_upload.access_after_barrier = AccessFlags::MemoryWrite;
            barrier_before_vertex_upload.old_state = ResourceState::VertexBuffer;
            barrier_before_vertex_upload.new_state = ResourceState::CopyDestination;
            barrier_before_vertex_upload.source_queue = QueueType::Graphics;
            barrier_before_vertex_upload.destination_queue = QueueType::Transfer;
            barrier_before_vertex_upload.buffer_memory_barrier.offset = 0;
            barrier_before_vertex_upload.buffer_memory_barrier.size = num_vertex_bytes_to_upload;

            barriers_before_upload.push_back(barrier_before_vertex_upload);
        }

        if(should_upload_index_buffer) {
            ResourceBarrier barrier_before_index_upload = {};
            barrier_before_index_upload.resource_to_barrier = cur_index_buffer;
            barrier_before_index_upload.access_before_barrier = AccessFlags::IndexRead;
            barrier_before_index_upload.access_after_barrier = AccessFlags::MemoryWrite;
            barrier_before_index_upload.old_state = ResourceState::IndexBuffer;
            barrier_before_index_upload.new_state = ResourceState::CopyDestination;
            barrier_before_index_upload.source_queue = QueueType::Graphics;
            barrier_before_index_upload.destination_queue = QueueType::Transfer;
            barrier_before_index_upload.buffer_memory_barrier.offset = 0;
            barrier_before_index_upload.buffer_memory_barrier.size = num_vertex_bytes_to_upload;

            barriers_before_upload.push_back(barrier_before_index_upload);
        }

        if(barriers_before_upload.empty()) {
            return;
        }

        cmds->resource_barriers(PipelineStageFlags::BottomOfPipe, PipelineStageFlags::Transfer, barriers_before_upload);

        if(should_upload_vertex_buffer) {
            cmds->copy_buffer(cur_vertex_buffer, 0, cached_vertex_buffer, 0, num_vertex_bytes_to_upload);
        }

        if(should_upload_index_buffer) {
            cmds->copy_buffer(cur_index_buffer, 0, cached_index_buffer, 0, num_index_bytes_to_upload);
        }

        std::vector<ResourceBarrier> barriers_after_upload;

        if(should_upload_vertex_buffer) {
            ResourceBarrier barrier_after_vertex_upload = {};
            barrier_after_vertex_upload.resource_to_barrier = cur_vertex_buffer;
            barrier_after_vertex_upload.access_before_barrier = AccessFlags::MemoryWrite;
            barrier_after_vertex_upload.access_after_barrier = AccessFlags::VertexAttributeRead;
            barrier_after_vertex_upload.old_state = ResourceState::CopyDestination;
            barrier_after_vertex_upload.new_state = ResourceState::VertexBuffer;
            barrier_after_vertex_upload.source_queue = QueueType::Graphics;
            barrier_after_vertex_upload.destination_queue = QueueType::Graphics;
            barrier_after_vertex_upload.buffer_memory_barrier.offset = 0;
            barrier_after_vertex_upload.buffer_memory_barrier.size = num_vertex_bytes_to_upload;
            barriers_after_upload.push_back(barrier_after_vertex_upload);
        }

        if(should_upload_index_buffer) {
            ResourceBarrier barrier_after_index_upload = {};
            barrier_after_index_upload.resource_to_barrier = cur_index_buffer;
            barrier_after_index_upload.access_before_barrier = AccessFlags::MemoryWrite;
            barrier_after_index_upload.access_after_barrier = AccessFlags::IndexRead;
            barrier_after_index_upload.old_state = ResourceState::CopyDestination;
            barrier_after_index_upload.new_state = ResourceState::IndexBuffer;
            barrier_after_index_upload.source_queue = QueueType::Graphics;
            barrier_after_index_upload.destination_queue = QueueType::Graphics;
            barrier_after_index_upload.buffer_memory_barrier.offset = 0;
            barrier_after_index_upload.buffer_memory_barrier.size = num_index_bytes_to_upload;
            barriers_after_upload.push_back(barrier_after_index_upload);
        }

        if(barriers_after_upload.empty()) {
            return;
        }

        cmds->resource_barriers(PipelineStageFlags::Transfer, PipelineStageFlags::TopOfPipe, barriers_after_upload);
    }
} // namespace nova::renderer
<|endoftext|>


<commit_before>//
//  bootstrap.cpp
//  Parse
//
//  Created by Andrew Hunter on 21/05/2011.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#include "bootstrap.h"

#include "Dfa/ndfa_regex.h"
#include "ContextFree/item.h"
#include "Lr/weak_symbols.h"
#include "Lr/ignored_symbols.h"
#include "Lr/lalr_builder.h"

using namespace dfa;
using namespace contextfree;
using namespace lr;
using namespace language;

/// \brief Adds a new terminal item to an NDFA, and to this object
contextfree::item_container bootstrap::add_terminal(dfa::ndfa_regex* ndfa, const std::wstring& name, const std::wstring& regex) {
    // Add to the terminal dictionary
    int termIdentifier = m_Terminals.symbol_for_name(name);

    if (termIdentifier == -1) {
        termIdentifier = m_Terminals.add_symbol(name);
    }

    // Add to the DFA
    ndfa->add_regex(0, regex, termIdentifier);

    // Return a new container
    return item_container(new terminal(termIdentifier), true);
}

/// \brief Creates the lexer for the language
dfa::ndfa* bootstrap::create_dfa() {
    // Create the NDFA (which we'll eventually turn into the lexer)
    ndfa_regex* languageNdfa = new ndfa_regex();

    // The weak keywords
    t.language          = add_terminal(languageNdfa, L"language", L"language");
    t.grammar           = add_terminal(languageNdfa, L"grammar", L"grammar");
    t.lexersymbols      = add_terminal(languageNdfa, L"lexer-symbols", L"lexer-symbols");
    t.lexer             = add_terminal(languageNdfa, L"lexer", L"lexer");
    t.weaklexer         = add_terminal(languageNdfa, L"weaklexer", L"weaklexer");
    t.ignore            = add_terminal(languageNdfa, L"ignore", L"ignore");
    t.keywords          = add_terminal(languageNdfa, L"keywords", L"keywords");

    // Single character elements (these are also weak)
	t.equals            = add_terminal(languageNdfa, L"'='", L"\\=");
    t.question          = add_terminal(languageNdfa, L"'?'", L"\\?");
    t.plus              = add_terminal(languageNdfa, L"'+'", L"\\+");
    t.star              = add_terminal(languageNdfa, L"'*'", L"\\*");
    t.colon             = add_terminal(languageNdfa, L"':'", L"\\:");
    t.openparen         = add_terminal(languageNdfa, L"'('", L"\\(");
    t.closeparen        = add_terminal(languageNdfa, L"')'", L"\\)");
    t.opencurly         = add_terminal(languageNdfa, L"'{'", L"\\{");
    t.closecurly        = add_terminal(languageNdfa, L"'}'", L"\\}");
    t.dot               = add_terminal(languageNdfa, L"'.'", L"\\.");
    t.pipe              = add_terminal(languageNdfa, L"'|'", L"\\|");

    // The lexical constructs
    t.identifier        = add_terminal(languageNdfa, L"identifier", L"[A-Za-z\\-][A-Za-z\\-0-9]*");
    t.nonterminal       = add_terminal(languageNdfa, L"nonterminal", L"\\<[A-Za-z\\-][A-Za-z\\-0-9]*\\>");
    //t.regex             = add_terminal(languageNdfa, L"regex", L"/([^/]|(\\\\/))*/");
    //t.string            = add_terminal(languageNdfa, L"string", L"\"([^\"]|(\\\"))*\"");
    //t.character         = add_terminal(languageNdfa, L"character", L"'(.|(\\\\.))'");
    t.character         = add_terminal(languageNdfa, L"character", L"'([a-z]|(\\\\[a-z]))'");

    // Ignored elements
    t.newline           = add_terminal(languageNdfa, L"newline", L"[\n\r]");
    t.whitespace        = add_terminal(languageNdfa, L"whitespace", L"[ ]");
    t.comment           = add_terminal(languageNdfa, L"comment", L"//[^\n\r]*");

    // Build into a DFA
    ndfa* uniqueSyms = languageNdfa->to_ndfa_with_unique_symbols();
    delete languageNdfa;

    ndfa* result = uniqueSyms->to_dfa();
    delete uniqueSyms;

    return result;
}

/// \brief Creates the grammar for the language
contextfree::grammar* bootstrap::create_grammar() {
    // Create a new grammar
    grammar* result = new grammar();

    // Generate nonterminals
    nt.parser_language          = result->get_nonterminal(L"Parser-Language");
    nt.toplevel_block           = result->get_nonterminal(L"TopLevel-Block");
    nt.language_block           = result->get_nonterminal(L"Language-Block");
    nt.language_inherits        = result->get_nonterminal(L"Language-Inherits");
    nt.language_definition      = result->get_nonterminal(L"Language-Definition");
    nt.lexer_symbols_definition = result->get_nonterminal(L"Lexer-Symbols-Definition");
    nt.lexer_definition         = result->get_nonterminal(L"Lexer-Definition");
    nt.ignore_definition        = result->get_nonterminal(L"Ignore-Definition");
    nt.keywords_definition      = result->get_nonterminal(L"Keywords-Definition");
    nt.keyword_definition       = result->get_nonterminal(L"Keyword-Definition");
    nt.weak_symbols_definition  = result->get_nonterminal(L"Weak-Symbols-Definition");
    nt.lexeme_definition        = result->get_nonterminal(L"Lexeme-Definition");
    nt.grammar_definition       = result->get_nonterminal(L"Grammar-Definition");
    nt.nonterminal_definition   = result->get_nonterminal(L"Nonterminal-Definition");
    nt.production               = result->get_nonterminal(L"Production");
    nt.ebnf_item                = result->get_nonterminal(L"Ebnf-Item");
    nt.simple_ebnf_item         = result->get_nonterminal(L"Simple-Ebnf-Item");
    nt.nonterminal              = result->get_nonterminal(L"Nonterminal");
    nt.terminal                 = result->get_nonterminal(L"Terminal");
    nt.basic_terminal           = result->get_nonterminal(L"Basic-Terminal");

    // Generate productions
    ebnf_repeating_optional listToplevel;
    (*listToplevel.get_rule()) << nt.toplevel_block;
    ((*result) += L"Parser-Language") << listToplevel;

    // Top level block (language)
    ((*result) += L"TopLevel-Block") << nt.language_block;

    // Language block ('language x (: y) { ... }
    ebnf_optional           optionalLanguageInherits;
    ebnf_repeating_optional listLanguageDefinition;
    (*optionalLanguageInherits.get_rule()) << nt.language_inherits;
    (*listLanguageDefinition.get_rule()) << nt.language_definition;
    ((*result) += L"Language-Block") << t.language << t.identifier << optionalLanguageInherits << t.opencurly << listLanguageDefinition << t.closecurly;

    ((*result) += L"Language-Inherits") << t.colon << t.identifier;

    // Types of definition within a language block
    ((*result) += L"Language-Definition") << nt.lexer_symbols_definition;
    ((*result) += L"Language-Definition") << nt.lexer_definition;
    ((*result) += L"Language-Definition") << nt.ignore_definition;
    ((*result) += L"Language-Definition") << nt.weak_symbols_definition;
    ((*result) += L"Language-Definition") << nt.keywords_definition;
    ((*result) += L"Language-Definition") << nt.grammar_definition;

    // Some simple definitions
    ebnf_repeating_optional lexemeList;
    ebnf_repeating_optional keywordDefinitionList;
    ebnf_repeating_optional lexemeOrIdentifierList;
    ebnf_alternate          lexemeOrIdentifier;

    (*lexemeList.get_rule()) << nt.lexeme_definition;
    (*lexemeOrIdentifier.get_rule()) << nt.lexeme_definition;
    (*lexemeOrIdentifier.add_rule()) << t.identifier;
    (*lexemeOrIdentifierList.get_rule()) << lexemeOrIdentifier;
    (*keywordDefinitionList.get_rule()) << nt.keyword_definition;

    ((*result) += L"Lexer-Symbols-Definition") << t.lexersymbols << t.opencurly << lexemeList << t.closecurly;
    ((*result) += L"Lexer-Definition") << t.lexer << t.opencurly << lexemeList << t.closecurly;
    ((*result) += L"Ignore-Definition") << t.ignore << t.opencurly << lexemeOrIdentifierList << t.closecurly;
    ((*result) += L"Keywords-Definition") << t.keywords << t.opencurly << keywordDefinitionList << t.closecurly;
    ((*result) += L"Keyword-Definition") << t.identifier;
    ((*result) += L"Keyword-Definition") << t.identifier << t.equals << t.string;
    ((*result) += L"Keyword-Definition") << t.identifier << t.equals << t.character;
    ((*result) += L"Weak-Symbols-Definition") << t.weaklexer << t.opencurly << lexemeList << t.closecurly;
    ((*result) += L"Lexeme-Definition") << t.identifier << t.equals << t.regex;
    ((*result) += L"Lexeme-Definition") << t.identifier << t.equals << t.identifier << t.dot << t.identifier;

    // Definitions for a grammar
    ebnf_repeating_optional nonterminalDefinitionList;
    ebnf_repeating_optional orProductionList;
    ebnf_repeating_optional ebnfItemList;
    ebnf_repeating_optional simpleEbnfItemList;

    (*nonterminalDefinitionList.get_rule()) << nt.nonterminal_definition;
    (*orProductionList.get_rule()) << t.pipe << nt.production;
    (*ebnfItemList.get_rule()) << nt.ebnf_item;
    (*simpleEbnfItemList.get_rule()) << nt.simple_ebnf_item;

    ((*result) += L"Grammar-Definition") << t.grammar << t.opencurly << nonterminalDefinitionList << t.closecurly;

    ((*result) += L"Nonterminal-Definition") << t.nonterminal << t.equals << nt.production << orProductionList;
    // (Not supporting the inheritance forms of these in the bootstrap language)

    // Productions
    ((*result) += L"Production") << simpleEbnfItemList;

    ((*result) += L"Ebnf-Item") << nt.simple_ebnf_item;
    ((*result) += L"Ebnf-Item") << nt.simple_ebnf_item << t.pipe << nt.simple_ebnf_item;

    ((*result) += L"Simple-Ebnf-Item") << nt.nonterminal;
    ((*result) += L"Simple-Ebnf-Item") << nt.terminal;
    ((*result) += L"Simple-Ebnf-Item") << nt.simple_ebnf_item << t.star;
    ((*result) += L"Simple-Ebnf-Item") << nt.simple_ebnf_item << t.plus;
    ((*result) += L"Simple-Ebnf-Item") << nt.simple_ebnf_item << t.question;
    ((*result) += L"Simple-Ebnf-Item") << t.openparen << ebnfItemList << t.closeparen;

    ((*result) += L"Nonterminal") << t.nonterminal;

    ((*result) += L"Terminal") << nt.basic_terminal;
    ((*result) += L"Basic-Terminal") << t.identifier;
    ((*result) += L"Basic-Terminal") << t.string;
    ((*result) += L"Basic-Terminal") << t.character;

    // Return the new grammar
    return result;
}

/// \brief Constructs the bootstrap language
bootstrap::bootstrap() {
    // Create the DFA for this language
    ndfa* dfa = create_dfa();

    // Create the grammar for this language
    m_Grammar = create_grammar();

    // Set up the list of 'weak symbols'
    weak_symbols weak;

    // All of the keywords are weak
    item_set weaklings;

    weaklings.insert(t.language);
    weaklings.insert(t.grammar);
    weaklings.insert(t.lexersymbols);
    weaklings.insert(t.lexer);
    weaklings.insert(t.ignore);
    weaklings.insert(t.keywords);

    weak.add_symbols(*dfa, weaklings, m_Terminals);

    // Set up the list of ignored symbols
    ignored_symbols ignore;

    ignore.add_item(t.newline);
    ignore.add_item(t.whitespace);
    ignore.add_item(t.comment);

    // Create the lexer for this language
    m_Lexer = new dfa::lexer(*dfa);

    // No longer need the DFA at this point
    delete dfa;

    // Build the parser
    m_Builder = new lalr_builder(*m_Grammar, m_Terminals);

    m_Builder->add_rewriter(weak);
    m_Builder->add_rewriter(ignore);

    m_Builder->add_initial_state(nt.parser_language);

    // Finish up the parser
    m_Builder->complete_parser();

    // TODO: log information about shift/reduce and reduce/reduce conflicts

    // Turn into the finished parser
    m_Parser = new ast_parser(*m_Builder);
}

/// \brief Destructor
bootstrap::~bootstrap() {
    delete m_Lexer;
    delete m_Grammar;
    delete m_Builder;
    delete m_Parser;
}
<commit_msg>Converted everything to its 'positive' equivalent: the language now successfully builds.<commit_after>//
//  bootstrap.cpp
//  Parse
//
//  Created by Andrew Hunter on 21/05/2011.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#include "bootstrap.h"

#include "Dfa/ndfa_regex.h"
#include "ContextFree/item.h"
#include "Lr/weak_symbols.h"
#include "Lr/ignored_symbols.h"
#include "Lr/lalr_builder.h"

using namespace dfa;
using namespace contextfree;
using namespace lr;
using namespace language;

/// \brief Adds a new terminal item to an NDFA, and to this object
contextfree::item_container bootstrap::add_terminal(dfa::ndfa_regex* ndfa, const std::wstring& name, const std::wstring& regex) {
    // Add to the terminal dictionary
    int termIdentifier = m_Terminals.symbol_for_name(name);

    if (termIdentifier == -1) {
        termIdentifier = m_Terminals.add_symbol(name);
    }

    // Add to the DFA
    ndfa->add_regex(0, regex, termIdentifier);

    // Return a new container
    return item_container(new terminal(termIdentifier), true);
}

/// \brief Creates the lexer for the language
dfa::ndfa* bootstrap::create_dfa() {
    // Create the NDFA (which we'll eventually turn into the lexer)
    ndfa_regex* languageNdfa = new ndfa_regex();

    // The weak keywords
    t.language          = add_terminal(languageNdfa, L"language", L"language");
    t.grammar           = add_terminal(languageNdfa, L"grammar", L"grammar");
    t.lexersymbols      = add_terminal(languageNdfa, L"lexer-symbols", L"lexer-symbols");
    t.lexer             = add_terminal(languageNdfa, L"lexer", L"lexer");
    t.weaklexer         = add_terminal(languageNdfa, L"weaklexer", L"weaklexer");
    t.ignore            = add_terminal(languageNdfa, L"ignore", L"ignore");
    t.keywords          = add_terminal(languageNdfa, L"keywords", L"keywords");

    // Single character elements (these are also weak)
	t.equals            = add_terminal(languageNdfa, L"'='", L"\\=");
    t.question          = add_terminal(languageNdfa, L"'?'", L"\\?");
    t.plus              = add_terminal(languageNdfa, L"'+'", L"\\+");
    t.star              = add_terminal(languageNdfa, L"'*'", L"\\*");
    t.colon             = add_terminal(languageNdfa, L"':'", L"\\:");
    t.openparen         = add_terminal(languageNdfa, L"'('", L"\\(");
    t.closeparen        = add_terminal(languageNdfa, L"')'", L"\\)");
    t.opencurly         = add_terminal(languageNdfa, L"'{'", L"\\{");
    t.closecurly        = add_terminal(languageNdfa, L"'}'", L"\\}");
    t.dot               = add_terminal(languageNdfa, L"'.'", L"\\.");
    t.pipe              = add_terminal(languageNdfa, L"'|'", L"\\|");

    // The lexical constructs
    t.identifier        = add_terminal(languageNdfa, L"identifier", L"[A-Za-z\\-][A-Za-z\\-0-9]*");
    t.nonterminal       = add_terminal(languageNdfa, L"nonterminal", L"\\<[A-Za-z\\-][A-Za-z\\-0-9]*\\>");
    //t.regex             = add_terminal(languageNdfa, L"regex", L"/([^/]|(\\\\/))*/");
    //t.string            = add_terminal(languageNdfa, L"string", L"\"([^\"]|(\\\"))*\"");
    //t.character         = add_terminal(languageNdfa, L"character", L"'(.|(\\\\.))'");
    t.regex             = add_terminal(languageNdfa, L"regex", L"/([a-z]|(\\\\/))*/");
    t.string            = add_terminal(languageNdfa, L"string", L"\"([a-zA-Z ]|(\\\"))*\"");
    t.character         = add_terminal(languageNdfa, L"character", L"'([a-z]|(\\\\[a-z]))'");

    // Ignored elements
    t.newline           = add_terminal(languageNdfa, L"newline", L"[\n\r]");
    t.whitespace        = add_terminal(languageNdfa, L"whitespace", L"[ \t]+");
    //t.comment           = add_terminal(languageNdfa, L"comment", L"//[^\n\r]*");
    t.comment           = add_terminal(languageNdfa, L"comment", L"//[A-Za-z ]*");

    // Build into a DFA
    ndfa* uniqueSyms = languageNdfa->to_ndfa_with_unique_symbols();
    delete languageNdfa;

    ndfa* result = uniqueSyms->to_dfa();
    delete uniqueSyms;

    return result;
}

/// \brief Creates the grammar for the language
contextfree::grammar* bootstrap::create_grammar() {
    // Create a new grammar
    grammar* result = new grammar();

    // Generate nonterminals
    nt.parser_language          = result->get_nonterminal(L"Parser-Language");
    nt.toplevel_block           = result->get_nonterminal(L"TopLevel-Block");
    nt.language_block           = result->get_nonterminal(L"Language-Block");
    nt.language_inherits        = result->get_nonterminal(L"Language-Inherits");
    nt.language_definition      = result->get_nonterminal(L"Language-Definition");
    nt.lexer_symbols_definition = result->get_nonterminal(L"Lexer-Symbols-Definition");
    nt.lexer_definition         = result->get_nonterminal(L"Lexer-Definition");
    nt.ignore_definition        = result->get_nonterminal(L"Ignore-Definition");
    nt.keywords_definition      = result->get_nonterminal(L"Keywords-Definition");
    nt.keyword_definition       = result->get_nonterminal(L"Keyword-Definition");
    nt.weak_symbols_definition  = result->get_nonterminal(L"Weak-Symbols-Definition");
    nt.lexeme_definition        = result->get_nonterminal(L"Lexeme-Definition");
    nt.grammar_definition       = result->get_nonterminal(L"Grammar-Definition");
    nt.nonterminal_definition   = result->get_nonterminal(L"Nonterminal-Definition");
    nt.production               = result->get_nonterminal(L"Production");
    nt.ebnf_item                = result->get_nonterminal(L"Ebnf-Item");
    nt.simple_ebnf_item         = result->get_nonterminal(L"Simple-Ebnf-Item");
    nt.nonterminal              = result->get_nonterminal(L"Nonterminal");
    nt.terminal                 = result->get_nonterminal(L"Terminal");
    nt.basic_terminal           = result->get_nonterminal(L"Basic-Terminal");

    // Generate productions
    ebnf_repeating_optional listToplevel;
    (*listToplevel.get_rule()) << nt.toplevel_block;
    ((*result) += L"Parser-Language") << listToplevel;

    // Top level block (language)
    ((*result) += L"TopLevel-Block") << nt.language_block;

    // Language block ('language x (: y) { ... }
    ebnf_optional           optionalLanguageInherits;
    ebnf_repeating_optional listLanguageDefinition;
    (*optionalLanguageInherits.get_rule()) << nt.language_inherits;
    (*listLanguageDefinition.get_rule()) << nt.language_definition;
    ((*result) += L"Language-Block") << t.language << t.identifier << optionalLanguageInherits << t.opencurly << listLanguageDefinition << t.closecurly;

    ((*result) += L"Language-Inherits") << t.colon << t.identifier;

    // Types of definition within a language block
    ((*result) += L"Language-Definition") << nt.lexer_symbols_definition;
    ((*result) += L"Language-Definition") << nt.lexer_definition;
    ((*result) += L"Language-Definition") << nt.ignore_definition;
    ((*result) += L"Language-Definition") << nt.weak_symbols_definition;
    ((*result) += L"Language-Definition") << nt.keywords_definition;
    ((*result) += L"Language-Definition") << nt.grammar_definition;

    // Some simple definitions
    ebnf_repeating_optional lexemeList;
    ebnf_repeating_optional keywordDefinitionList;
    ebnf_repeating_optional lexemeOrIdentifierList;
    ebnf_alternate          lexemeOrIdentifier;

    (*lexemeList.get_rule()) << nt.lexeme_definition;
    (*lexemeOrIdentifier.get_rule()) << nt.lexeme_definition;
    (*lexemeOrIdentifier.add_rule()) << t.identifier;
    (*lexemeOrIdentifierList.get_rule()) << lexemeOrIdentifier;
    (*keywordDefinitionList.get_rule()) << nt.keyword_definition;

    ((*result) += L"Lexer-Symbols-Definition") << t.lexersymbols << t.opencurly << lexemeList << t.closecurly;
    ((*result) += L"Lexer-Definition") << t.lexer << t.opencurly << lexemeList << t.closecurly;
    ((*result) += L"Ignore-Definition") << t.ignore << t.opencurly << lexemeOrIdentifierList << t.closecurly;
    ((*result) += L"Keywords-Definition") << t.keywords << t.opencurly << keywordDefinitionList << t.closecurly;
    ((*result) += L"Keyword-Definition") << t.identifier;
    ((*result) += L"Keyword-Definition") << t.identifier << t.equals << t.string;
    ((*result) += L"Keyword-Definition") << t.identifier << t.equals << t.character;
    ((*result) += L"Weak-Symbols-Definition") << t.weaklexer << t.opencurly << lexemeList << t.closecurly;
    ((*result) += L"Lexeme-Definition") << t.identifier << t.equals << t.regex;
    ((*result) += L"Lexeme-Definition") << t.identifier << t.equals << t.identifier << t.dot << t.identifier;

    // Definitions for a grammar
    ebnf_repeating_optional nonterminalDefinitionList;
    ebnf_repeating_optional orProductionList;
    ebnf_repeating_optional ebnfItemList;
    ebnf_repeating_optional simpleEbnfItemList;

    (*nonterminalDefinitionList.get_rule()) << nt.nonterminal_definition;
    (*orProductionList.get_rule()) << t.pipe << nt.production;
    (*ebnfItemList.get_rule()) << nt.ebnf_item;
    (*simpleEbnfItemList.get_rule()) << nt.simple_ebnf_item;

    ((*result) += L"Grammar-Definition") << t.grammar << t.opencurly << nonterminalDefinitionList << t.closecurly;

    ((*result) += L"Nonterminal-Definition") << t.nonterminal << t.equals << nt.production << orProductionList;
    // (Not supporting the inheritance forms of these in the bootstrap language)

    // Productions
    ((*result) += L"Production") << simpleEbnfItemList;

    ((*result) += L"Ebnf-Item") << nt.simple_ebnf_item;
    ((*result) += L"Ebnf-Item") << nt.simple_ebnf_item << t.pipe << nt.simple_ebnf_item;

    ((*result) += L"Simple-Ebnf-Item") << nt.nonterminal;
    ((*result) += L"Simple-Ebnf-Item") << nt.terminal;
    ((*result) += L"Simple-Ebnf-Item") << nt.simple_ebnf_item << t.star;
    ((*result) += L"Simple-Ebnf-Item") << nt.simple_ebnf_item << t.plus;
    ((*result) += L"Simple-Ebnf-Item") << nt.simple_ebnf_item << t.question;
    ((*result) += L"Simple-Ebnf-Item") << t.openparen << ebnfItemList << t.closeparen;

    ((*result) += L"Nonterminal") << t.nonterminal;

    ((*result) += L"Terminal") << nt.basic_terminal;
    ((*result) += L"Basic-Terminal") << t.identifier;
    ((*result) += L"Basic-Terminal") << t.string;
    ((*result) += L"Basic-Terminal") << t.character;

    // Return the new grammar
    return result;
}

/// \brief Constructs the bootstrap language
bootstrap::bootstrap() {
    // Create the DFA for this language
    ndfa* dfa = create_dfa();

    // Create the grammar for this language
    m_Grammar = create_grammar();

    // Set up the list of 'weak symbols'
    weak_symbols weak;

    // All of the keywords are weak
    item_set weaklings;

    weaklings.insert(t.language);
    weaklings.insert(t.grammar);
    weaklings.insert(t.lexersymbols);
    weaklings.insert(t.lexer);
    weaklings.insert(t.ignore);
    weaklings.insert(t.keywords);

    weak.add_symbols(*dfa, weaklings, m_Terminals);

    // Set up the list of ignored symbols
    ignored_symbols ignore;

    ignore.add_item(t.newline);
    ignore.add_item(t.whitespace);
    ignore.add_item(t.comment);

    // Create the lexer for this language
    m_Lexer = new dfa::lexer(*dfa);

    // No longer need the DFA at this point
    delete dfa;

    // Build the parser
    m_Builder = new lalr_builder(*m_Grammar, m_Terminals);

    m_Builder->add_rewriter(weak);
    m_Builder->add_rewriter(ignore);

    m_Builder->add_initial_state(nt.parser_language);

    // Finish up the parser
    m_Builder->complete_parser();

    // TODO: log information about shift/reduce and reduce/reduce conflicts

    // Turn into the finished parser
    m_Parser = new ast_parser(*m_Builder);
}

/// \brief Destructor
bootstrap::~bootstrap() {
    delete m_Lexer;
    delete m_Grammar;
    delete m_Builder;
    delete m_Parser;
}
<|endoftext|>