Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #22

Merged
merged 11 commits into from
Oct 1, 2023
1 change: 0 additions & 1 deletion Caprica/common/CapricaConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ namespace PCompiler {
bool pCompilerCompatibilityMode{false};
bool all{false};
bool norecurse{false};
bool ignorecwd{false};
}

namespace CodeGeneration {
Expand Down
1 change: 0 additions & 1 deletion Caprica/common/CapricaConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ namespace PCompiler {
extern bool pCompilerCompatibilityMode;
extern bool all;
extern bool norecurse;
extern bool ignorecwd;
}

// Options related to code generation.
Expand Down
3 changes: 1 addition & 2 deletions Caprica/common/CapricaJobManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ bool CapricaJob::tryRun() {

void CapricaJobManager::startup(size_t initialWorkerCount) {
defaultJob.await();

for (size_t i = 0; i < initialWorkerCount; i++) {
for (size_t i = workerCount; i < initialWorkerCount; i++) {
std::thread thr { [this] {
this->workerMain();
} };
Expand Down
14 changes: 7 additions & 7 deletions Caprica/common/CapricaReportingContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,16 @@ bool CapricaReportingContext::isWarningEnabled(CapricaFileLocation /* location *
size_t CapricaReportingContext::getLocationLine(CapricaFileLocation location, size_t lastLineHint) {
if (!lineOffsets.size())
CapricaReportingContext::logicalFatal("Unable to locate line at offset {}.", location.startOffset);
if (lastLineHint != 0) {
Copy link
Collaborator Author

@nikitalita nikitalita Sep 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Orvid I had to remove this because it was resulting in incorrect line numbers in the debug info; this was just for speed, correct?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, it was there purely for speed. If it's causing problems, removing it is fine.

if (location.startOffset >= lineOffsets.at(lastLineHint - 1))
return lastLineHint + 1;
if (lastLineHint + 1 < lineOffsets.size()) {
auto a = std::lower_bound(lineOffsets.begin(), lineOffsets.end(), location.startOffset);
if (a == lineOffsets.end()) {
if (lastLineHint != 0) {
if (location.startOffset >= lineOffsets.at(lastLineHint - 1))
return lastLineHint + 1;
if (lastLineHint + 1 < lineOffsets.size()) {
if (location.startOffset >= lineOffsets.at(lastLineHint - 1))
return lastLineHint + 1;
}
}
}
auto a = std::lower_bound(lineOffsets.begin(), lineOffsets.end(), location.startOffset);
if (a == lineOffsets.end()) {
// TODO: Fix line offsets during parsing for reals, remove this hack
// maybePushMessage(this, nullptr, "Warning:", 0, fmt::format("Unable to locate line at offset {}, using last known line {}...", location.startOffset, lineOffsets.size()), true);
return lineOffsets.size();
Expand Down
60 changes: 59 additions & 1 deletion Caprica/common/FakeScripts.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "FakeScripts.h"
#include "common/GameID.h"
#include <common/GameID.h>

namespace caprica {
constexpr const char* FAKE_SKYRIM_SCRIPTOBJECT_SCRIPT =
Expand Down Expand Up @@ -66,6 +66,57 @@ Function DropWall(ObjectReference WallEffect)
EndFunction
)";

constexpr const char* STARFIELD_FAKE_FLAGS_FILE =
R"(// Starfield flags file, by NikitaLita
// This file is conjecture, based on the userflags set by the base starfield game scripts.

// Flag hides the script or property from the game editor
Flag Hidden 0
{
Script
Property
StructVar
}

// Flag on an object designates it as the script the condition system will look at
// Flag on a variable allows the script variable to be examined by the condition system
Flag Conditional 1
{
Script
Variable
}

// Flags the specified script as a default script, for filtering in the editor
Flag Default 2
{
Script
}

// Flags this group as collapsed on the reference in the editor
Flag CollapsedOnRef 3
{
Group
}

// Flags this group as collapsed on the base object in the editor
Flag CollapsedOnBase 4
{
Group
}

// Flags this group as collapsed (on both ref and base) in the editor
Flag Collapsed CollapsedOnRef & CollapsedOnBase

// Flags a property as mandatory - in other words, will spit out a warning in
// the editor if it isn't given a value
Flag Mandatory 5
{
Property
}
)";



static const caseless_unordered_identifier_ref_map<identifier_ref> FAKE_SCRIPTS = {
{"fake://skyrim/__ScriptObject.psc", FAKE_SKYRIM_SCRIPTOBJECT_SCRIPT },
{ "fake://skyrim/DLC1SCWispWallScript.psc", MISSING_DLC1SCWispWallScript_SKYRIM},
Expand All @@ -88,4 +139,11 @@ size_t FakeScripts::getSizeOfFakeScript(const identifier_ref& name, GameID game)
return it->second.size();
}

identifier_ref FakeScripts::getFakeFlagsFile(GameID game) {
if (game != GameID::Starfield)
return {};
return STARFIELD_FAKE_FLAGS_FILE;
}


}
6 changes: 4 additions & 2 deletions Caprica/common/FakeScripts.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
#pragma once
#include "CaselessStringComparer.h"
#include "GameID.h"
#include <common/CaselessStringComparer.h>
#include <common/GameID.h>


namespace caprica {
struct FakeScripts {
static identifier_ref getFakeScript(const identifier_ref& name, GameID game);
static size_t getSizeOfFakeScript(const identifier_ref& name, GameID game);
static identifier_ref getFakeFlagsFile(GameID game);
};
}
15 changes: 15 additions & 0 deletions Caprica/common/parser/CapricaUserFlagsLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <unordered_map>
#include <utility>

#include <common/FakeScripts.h>
#include <common/CapricaConfig.h>
#include <common/CaselessStringComparer.h>

Expand Down Expand Up @@ -207,5 +208,19 @@ void CapricaUserFlagsLexer::consume() {
reportingContext.fatal(baseLoc, "Unexpected character '{}'!", (char)c);
}
}
CapricaUserFlagsLexer::CapricaUserFlagsLexer(CapricaReportingContext& repCtx, const std::string& file)
: filename(file), cur(TokenType::Unknown), reportingContext(repCtx) {
if (filename.starts_with("fake://")){
strmString.str(FakeScripts::getFakeFlagsFile(conf::Papyrus::game).to_string());
strm = &strmString;
} else {
strmFile.open(filename, std::ifstream::binary);
if (!strmFile.is_open()) {
CapricaReportingContext::logicalFatal("Unable to open file '%s'!", filename.c_str());
}
strm = &strmFile;
}
consume(); // set the first token.
}

}}
13 changes: 6 additions & 7 deletions Caprica/common/parser/CapricaUserFlagsLexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,7 @@ struct CapricaUserFlagsLexer {
static const std::string prettyTokenType(TokenType tp);
};

explicit CapricaUserFlagsLexer(CapricaReportingContext& repCtx, const std::string& file)
: filename(file), strm(file, std::ifstream::binary), cur(TokenType::Unknown), reportingContext(repCtx) {
consume(); // set the first token.
}
explicit CapricaUserFlagsLexer(CapricaReportingContext& repCtx, const std::string& file);
CapricaUserFlagsLexer(const CapricaUserFlagsLexer&) = delete;
~CapricaUserFlagsLexer() = default;

Expand All @@ -77,14 +74,16 @@ struct CapricaUserFlagsLexer {
void consume();

private:
std::ifstream strm;
std::istream * strm;
std::istringstream strmString;
std::ifstream strmFile;
CapricaFileLocation location {};

int getChar() {
location.startOffset++;
return strm.get();
return strm->get();
}
int peekChar() { return strm.peek(); }
int peekChar() { return strm->peek(); }
void setTok(TokenType tp, CapricaFileLocation loc);
void setTok(Token& tok);
};
Expand Down
65 changes: 45 additions & 20 deletions Caprica/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ static const std::unordered_set FAKE_SKYRIM_SCRIPTS_SET = {
"fake://skyrim/__ScriptObject.psc",
"fake://skyrim/DLC1SCWispWallScript.psc",
};

static caseless_unordered_identifier_set abs_import_dirs {};
bool handleImports(const std::vector<std::string> &f, caprica::CapricaJobManager *jobManager);

PapyrusCompilationNode *getNode(const PapyrusCompilationNode::NodeType &nodeType,
Expand Down Expand Up @@ -194,26 +194,28 @@ bool addFilesFromDirectory(const std::string &f,
FindClose(hFind);

if (conf::Papyrus::game > GameID::Skyrim) {
// check that all the values in the base script dir map are true
if (!gBaseFound && !baseDirMap.empty()) {
bool allTrue = true;
for (auto &pair: baseDirMap) {
if (!pair.second) {
allTrue = false;
break;
if (!namespaceMap.empty()) {
// check that all the values in the base script dir map are true
if (!gBaseFound && !baseDirMap.empty()) {
bool allTrue = true;
for (auto& pair : baseDirMap) {
if (!pair.second) {
allTrue = false;
break;
}
}
if (allTrue && namespaceMap.size() >= getBaseLowerFileCountLimit(conf::Papyrus::game)) {
// if it's true, then this is the base dir and the namespace should be root
gBaseFound = true;
l_startNS = "";
}
}
if (allTrue && namespaceMap.size() >= getBaseLowerFileCountLimit(conf::Papyrus::game)) {
// if it's true, then this is the base dir and the namespace should be root
gBaseFound = true;
l_startNS = "";
}
// if it's true, then this is the base dir and the namespace should be root
auto namespaceName = l_startNS + curDir;
std::replace(namespaceName.begin(), namespaceName.end(), '\\', ':');
namespaceName = namespaceName.substr(1);
caprica::papyrus::PapyrusCompilationContext::pushNamespaceFullContents(namespaceName, std::move(namespaceMap));
}
// if it's true, then this is the base dir and the namespace should be root
auto namespaceName = l_startNS + curDir;
std::replace(namespaceName.begin(), namespaceName.end(), '\\', ':');
namespaceName = namespaceName.substr(1);
caprica::papyrus::PapyrusCompilationContext::pushNamespaceFullContents(namespaceName, std::move(namespaceMap));
} else {
caprica::papyrus::PapyrusCompilationContext::pushNamespaceFullContents("", std::move(namespaceMap));
}
Expand Down Expand Up @@ -308,12 +310,14 @@ bool handleImports(const std::vector<std::string> &f, caprica::CapricaJobManager
}
std::cout << "Importing files..." << std::endl;
int i = 0;
abs_import_dirs.reserve(f.size());
for (auto& dir : f) {
std::string ns = "";
if (conf::Papyrus::game > GameID::Skyrim)
ns = "!!temp" + std::to_string(i++);
if (!addFilesFromDirectory(dir, true, "", jobManager, PapyrusCompilationNode::NodeType::PapyrusImport, ns))
return false;
abs_import_dirs.emplace(std::filesystem::absolute(dir).string());
}
CapricaStats::outputImportedCount();
caprica::papyrus::PapyrusCompilationContext::RenameImports(jobManager);
Expand Down Expand Up @@ -349,13 +353,34 @@ bool addSingleFile(const std::string &f,
auto ppath = caprica::FSUtils::parentPathAsRef(f);
if (ppath.compare(filename.c_str()) != 0) {
namespaceDir += ppath;
absBaseDir = absBaseDir.find(namespaceDir) != std::string::npos ? absBaseDir.substr(0, absBaseDir.find(namespaceDir)) : absBaseDir;
absBaseDir = absBaseDir.rfind(namespaceDir) != std::string::npos
? absBaseDir.substr(0, absBaseDir.rfind(namespaceDir))
: absBaseDir;
}
} else {
// PCompiler-like namespace resolution by scanning imports
bool found = false;
for (auto& dir : abs_import_dirs) {
auto relPath = std::filesystem::relative(f, dir);
// check if relpath begins with ".."
if (relPath != path && !relPath.string().starts_with("..")) {
namespaceDir += relPath.parent_path().string();
absBaseDir = dir;
found = true;
break;
}
}
if (!found) {
std::cout << "ERROR: Absolute file path '" << f << "' is not in an import directory, cannot resolve namespace!"
<< std::endl;
return false;
}
}
auto namespaceName = namespaceDir;
std::replace(namespaceName.begin(), namespaceName.end(), '\\', ':');
namespaceName = namespaceName.substr(1);
std::cout << "Adding file '" << filename << "' to namespace '" << namespaceName << "'." << std::endl;
if (!conf::General::quietCompile)
std::cout << "Adding file '" << filename << "' to namespace '" << namespaceName << "'." << std::endl;
auto node = getNode(nodeType,
jobManager,
baseOutputDir,
Expand Down
Loading