| /* |
| Copyright 2019 Alain Dargelas |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| /* |
| * File: PythonAPICache.cpp |
| * Author: alain |
| * |
| * Created on May 28, 2017, 10:49 PM |
| */ |
| |
| #include "CommandLine/CommandLineParser.h" |
| #include "ErrorReporting/ErrorContainer.h" |
| #include "SourceCompile/SymbolTable.h" |
| #include "SourceCompile/CompilationUnit.h" |
| #include "SourceCompile/PreprocessFile.h" |
| #include "SourceCompile/CompileSourceFile.h" |
| #include "SourceCompile/Compiler.h" |
| #include "SourceCompile/ParseFile.h" |
| #include "Utils/StringUtils.h" |
| #include "Utils/FileUtils.h" |
| #include "Cache/Cache.h" |
| #include "flatbuffers/util.h" |
| #include <cstdio> |
| #include <ctime> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| |
| #include "antlr4-runtime.h" |
| using namespace antlr4; |
| |
| #include "API/PythonAPI.h" |
| #include "Cache/PythonAPICache.h" |
| #include "SourceCompile/PythonListen.h" |
| |
| using namespace SURELOG; |
| |
| static std::string FlbSchemaVersion = "1.0"; |
| |
| PythonAPICache::PythonAPICache(PythonListen* listener) : m_listener(listener) {} |
| |
| PythonAPICache::PythonAPICache(const PythonAPICache& orig) {} |
| |
| PythonAPICache::~PythonAPICache() {} |
| |
| std::string PythonAPICache::getCacheFileName_(std::string svFileName) { |
| SymbolId cacheDirId = |
| m_listener->getCompileSourceFile()->getCommandLineParser()->getCacheDir(); |
| std::string cacheDirName = m_listener->getParseFile()->getSymbol(cacheDirId); |
| if (svFileName == "") |
| svFileName = m_listener->getParseFile()->getFileName(LINE1); |
| svFileName = StringUtils::getRootFileName(svFileName); |
| Library* lib = m_listener->getCompileSourceFile()->getLibrary(); |
| std::string libName = lib->getName() + "/"; |
| std::string cacheFileName = cacheDirName + libName + svFileName + ".slpy"; |
| return cacheFileName; |
| } |
| |
| bool PythonAPICache::restore_(std::string cacheFileName) { |
| uint8_t* buffer_pointer = openFlatBuffers(cacheFileName); |
| if (buffer_pointer == NULL) return false; |
| |
| const PYTHONAPICACHE::PythonAPICache* ppcache = |
| PYTHONAPICACHE::GetPythonAPICache(buffer_pointer); |
| SymbolTable canonicalSymbols; |
| restoreErrors(ppcache->m_errors(), ppcache->m_symbols(), canonicalSymbols, |
| m_listener->getCompileSourceFile()->getErrorContainer(), |
| m_listener->getCompileSourceFile()->getSymbolTable()); |
| |
| delete[] buffer_pointer; |
| return true; |
| } |
| |
| bool PythonAPICache::checkCacheIsValid_(std::string cacheFileName) { |
| uint8_t* buffer_pointer = openFlatBuffers(cacheFileName); |
| if (buffer_pointer == NULL) return false; |
| if (!PYTHONAPICACHE::PythonAPICacheBufferHasIdentifier(buffer_pointer)) { |
| delete[] buffer_pointer; |
| return false; |
| } |
| const PYTHONAPICACHE::PythonAPICache* ppcache = |
| PYTHONAPICACHE::GetPythonAPICache(buffer_pointer); |
| auto header = ppcache->m_header(); |
| |
| auto scriptFile = ppcache->m_python_script_file()->c_str(); |
| if (scriptFile) { |
| time_t ct = get_mtime(cacheFileName.c_str()); |
| time_t ft = get_mtime(scriptFile); |
| if (ft == -1) { |
| delete[] buffer_pointer; |
| return false; |
| } |
| if (ct == -1) { |
| delete[] buffer_pointer; |
| return false; |
| } |
| if (ct < ft) { |
| delete[] buffer_pointer; |
| return false; |
| } |
| } |
| |
| if (!checkIfCacheIsValid(header, FlbSchemaVersion, cacheFileName)) { |
| delete[] buffer_pointer; |
| return false; |
| } |
| |
| delete[] buffer_pointer; |
| return true; |
| } |
| |
| bool PythonAPICache::isValid() { |
| std::string cacheFileName = getCacheFileName_(); |
| return checkCacheIsValid_(cacheFileName); |
| } |
| |
| bool PythonAPICache::restore() { |
| bool cacheAllowed = m_listener->getCompileSourceFile() |
| ->getCommandLineParser() |
| ->cacheAllowed(); |
| if (!cacheAllowed) return false; |
| |
| std::string cacheFileName = getCacheFileName_(); |
| if (!checkCacheIsValid_(cacheFileName)) { |
| return false; |
| } |
| |
| return restore_(cacheFileName); |
| } |
| |
| bool PythonAPICache::save() { |
| bool cacheAllowed = m_listener->getCompileSourceFile() |
| ->getCommandLineParser() |
| ->cacheAllowed(); |
| if (!cacheAllowed) return false; |
| std::string svFileName = m_listener->getParseFile()->getPpFileName(); |
| std::string origFileName = svFileName; |
| |
| std::string cacheFileName = getCacheFileName_(); |
| |
| flatbuffers::FlatBufferBuilder builder(1024); |
| /* Create header section */ |
| auto header = createHeader(builder, FlbSchemaVersion, origFileName); |
| |
| std::string pythonScriptFile = PythonAPI::getListenerScript(); |
| auto scriptFile = builder.CreateString(pythonScriptFile); |
| |
| /* Cache the errors and canonical symbols */ |
| ErrorContainer* errorContainer = |
| m_listener->getCompileSourceFile()->getErrorContainer(); |
| SymbolId subjectFileId = m_listener->getParseFile()->getFileId(LINE1); |
| SymbolTable canonicalSymbols; |
| auto errorSymbolPair = cacheErrors( |
| builder, canonicalSymbols, errorContainer, |
| m_listener->getCompileSourceFile()->getSymbolTable(), subjectFileId); |
| |
| /* Create Flatbuffers */ |
| auto ppcache = PYTHONAPICACHE::CreatePythonAPICache( |
| builder, header, scriptFile, errorSymbolPair.first, |
| errorSymbolPair.second); |
| FinishPythonAPICacheBuffer(builder, ppcache); |
| |
| /* Save Flatbuffer */ |
| bool status = saveFlatbuffers(builder, cacheFileName); |
| |
| return status; |
| } |