Support getting line for diagnostic

This commit is contained in:
Deukhoofd 2019-06-18 17:14:18 +02:00
parent e07d5cb7cb
commit dc35ba4698
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
4 changed files with 59 additions and 7 deletions

View File

@ -3,6 +3,7 @@
#define PORYGONLANG_DIAGNOSTICSHOLDER_HPP
#include <vector>
#include <string>
#include "DiagnosticSeverity.hpp"
#include "DiagnosticCode.hpp"
#include "Diagnostic.hpp"
@ -13,9 +14,21 @@ namespace Porygon::Diagnostics {
class DiagnosticsHolder {
bool _hasErrors;
vector<Diagnostic> _diagnostics;
vector<size_t> _lineStarts;
vector<size_t> _lineLength;
public:
DiagnosticsHolder() {
explicit DiagnosticsHolder(const u16string& str) {
_hasErrors = false;
_lineStarts = vector<size_t>{0};
size_t lineLength = 0;
for (size_t i = 0; i < str.size(); i++){
lineLength++;
if (str[i] == '\n'){
_lineStarts.push_back(i + 1);
_lineLength.push_back(lineLength);
lineLength = 0;
}
}
}
~DiagnosticsHolder() {
@ -37,6 +50,29 @@ namespace Porygon::Diagnostics {
int DiagnosticsCount();
Diagnostic *GetDiagnosticAt(int position);
size_t GetLineFromPosition(size_t i){
size_t topLimit = _lineStarts.size() - 1;
size_t bottomLimit = 0;
while (true){
if (bottomLimit == topLimit){
return bottomLimit;
}
size_t half = (topLimit - bottomLimit) / 2;
size_t pos = _lineStarts[half];
size_t length = _lineLength[half];
if (pos < i && pos + length > i){
return half;
}
if (pos > i){
bottomLimit = half;
} else if (pos < i){
topLimit = half;
} else{
return half;
}
}
}
};
}

View File

@ -10,9 +10,7 @@
#include "Binder/Binder.hpp"
Porygon::Script* Porygon::Script::Create(const u16string& script) {
auto s = new Script();
s -> Parse(script);
return s;
return new Script(script);
}
std::u16string To_UTF16(const string &s)
@ -24,11 +22,13 @@ Porygon::Script *Porygon::Script::Create(const string &script) {
return Script::Create(To_UTF16(script));
}
Porygon::Script::Script() {
Diagnostics = new Diagnostics::DiagnosticsHolder();
Porygon::Script::Script(const u16string& s) {
Diagnostics = new Diagnostics::DiagnosticsHolder(s);
_boundScript = nullptr;
_scriptVariables = new unordered_map<uint32_t, shared_ptr<EvalValue>>(0);
_evaluator = new Evaluator(this -> _scriptVariables);
this -> Parse(s);
}
EvalValue* Porygon::Script::Evaluate() {

View File

@ -22,7 +22,7 @@ namespace Porygon{
Binder::BoundScriptStatement* _boundScript;
shared_ptr<ScriptType> _returnType;
explicit Script();
explicit Script(const u16string&);
void Parse(const u16string& script);
public:
static Script* Create(const u16string& script);

View File

@ -23,8 +23,24 @@ TEST_CASE( "Diagnostic invalid token", "[integration]" ) {
CHECK(diags[0].GetCode() == Diagnostics::DiagnosticCode::UnexpectedToken);
CHECK(diags[0].GetStartPosition() == 3);
CHECK(diags[0].GetLength() == 1);
CHECK(script->Diagnostics->GetLineFromPosition(diags[0].GetStartPosition()) == 0);
delete script;
}
TEST_CASE( "Get diagnostic line", "[integration]" ) {
auto script = Script::Create(uR"(
1 +/ 1
)");
REQUIRE(script->Diagnostics -> HasErrors());
auto diags = script->Diagnostics -> GetDiagnostics();
REQUIRE(diags.size() == 1);
CHECK(diags[0].GetCode() == Diagnostics::DiagnosticCode::UnexpectedToken);
CHECK(diags[0].GetStartPosition() == 4);
CHECK(diags[0].GetLength() == 1);
CHECK(script->Diagnostics->GetLineFromPosition(diags[0].GetStartPosition()) == 1);
delete script;
}
#endif