Skip to content

Commit

Permalink
Dynamic error messages (#122)
Browse files Browse the repository at this point in the history
  • Loading branch information
JohnDTill committed Jul 31, 2023
1 parent e340ef8 commit b7e73eb
Show file tree
Hide file tree
Showing 27 changed files with 329 additions and 172 deletions.
4 changes: 2 additions & 2 deletions app/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ void MainWindow::run(){
if(editor->isRunning()) return;

editor->runThread();
if(editor->getModel()->errors.empty()){
if(Program::instance()->noErrors()){
interpreter_poll_timer.start(INTERPETER_POLL_PERIOD);

editor_had_focus = false;
Expand Down Expand Up @@ -431,7 +431,7 @@ void MainWindow::pollInterpreterThread(){
default:
auto model = editor->getModel();
Typeset::Selection c = model->parser.parse_tree.getSelection(interpreter.error_node);
model->errors.push_back(Code::Error(c, interpreter.error_code));
Program::instance()->error_stream.fail(c, interpreter.error_code);
Code::Error::writeErrors(model->errors, output, editor);
output->calculateSizes();
output->updateLayout();
Expand Down
4 changes: 1 addition & 3 deletions meta/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,10 @@ def main():
header_writer.write(f" {e.name.upper()},\n")
header_writer.write("};\n\n")

header_writer.write("inline std::string getMessage(ErrorCode code){\n"
header_writer.write("inline std::string_view getMessage(ErrorCode code){\n"
" switch(code){\n")
for e in errors:
header_writer.write(f" case {e.name.upper()}: return \"{e.msg}")
if e.quote == "y":
header_writer.write(": ")
header_writer.write("\";\n")
header_writer.write(" default: assert(false); return \"\";\n")
header_writer.write(" }\n}\n\n")
Expand Down
5 changes: 5 additions & 0 deletions src/forscape_dynamic_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ class Settings {
return static_cast<WarningLevel>(flags[setting]);
}

WarningLevel warningLevel(SettingId setting) const noexcept {
assert(setting < NUM_CODE_SETTINGS);
return static_cast<WarningLevel>(flags[setting]);
}

template<SettingId setting> void setWarningLevel(WarningLevel warning_level) alloc_except {
static_assert(setting < NUM_CODE_SETTINGS);
assert(warning_level < NUM_WARNING_LEVELS);
Expand Down
145 changes: 133 additions & 12 deletions src/forscape_error.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#include "forscape_error.h"

#include <typeset_line.h>
#include "forscape_program.h"
#include "typeset_line.h"
#include <typeset_markerlink.h>
#include <typeset_model.h>
#include <typeset_text.h>
#include "typeset_model.h"
#include "typeset_text.h"

namespace Forscape {

Expand All @@ -12,14 +13,24 @@ namespace Code {
#ifndef FORSCAPE_TYPESET_HEADLESS
void Error::writeTo(Typeset::Text* t, Typeset::View* caller) const {
Typeset::Line* l = selection.getStartLine();
Typeset::Model* model = t->getModel();
t->tags.push_back( SemanticTag(0, SEM_ERROR) );
t->setString("ERROR");
model->appendLine();
t = model->lastText();
t->tags.push_back( SemanticTag(0, SEM_ERROR) );
model->appendSerialToOutput(selection.getModel()->path.u8string());
model->appendLine();
t = model->lastText();

if(caller){
t->getParent()->appendConstruct(new Typeset::MarkerLink(l, caller, selection.getModel()));
t = t->nextTextAsserted();
t->setString(" - ");
t->getModel()->appendSerialToOutput(message());
model->appendSerialToOutput(std::string(consoleMessage()));
}else{
t->setString("Line " + line() + " - ");
t->getModel()->appendSerialToOutput(message());
model->appendSerialToOutput(std::string(consoleMessage()));
}
t->tags.push_back( SemanticTag(0, SEM_ERROR) );
}
Expand Down Expand Up @@ -48,20 +59,130 @@ Typeset::Model* Error::writeErrors(const std::vector<Error>& errors, Typeset::Vi
}
#endif

Error::Error(Typeset::Selection controller, ErrorCode code) noexcept
: selection(controller), code(code) {}
Error::Error(const Typeset::Selection& selection, ErrorCode code, size_t start, size_t len, const std::string* const error_out) noexcept
: selection(selection), code(code), tooltip_start(start), tooltip_len(len), buffer(error_out) {}

std::string Error::message() const{
std::string msg = getMessage(code);
if(shouldQuote(code)) msg += selection.str();
std::string_view Error::tooltipMessage() const noexcept {
assert(buffer != nullptr);
return std::string_view(buffer->data()+tooltip_start, tooltip_len);
}

return msg;
std::string_view Error::consoleMessage() const noexcept {
assert(buffer != nullptr);
return std::string_view(buffer->data()+console_start, console_len);
}

std::string Error::line() const{
std::string Error::line() const {
return std::to_string(selection.getStartLine()->id+1);
}

void ErrorStream::reset() noexcept {
error_warning_buffer.clear();
errors.clear();
warnings.clear();
}

bool ErrorStream::noErrors() const noexcept {
return errors.empty();
}

void ErrorStream::fail(const Typeset::Selection& selection, ErrorCode code) alloc_except {
Typeset::Model* model = selection.getModel();

const size_t start = active_buffer->size();
*active_buffer += getMessage(code);

Error error(selection, code, start, active_buffer->size()-start, active_buffer);

if(shouldQuote(code)){
*active_buffer += ": ";
*active_buffer += selection.str();
}

error.console_start = start;
error.console_len = active_buffer->size()-start;

errors.push_back(error);
model->errors.push_back(error);
}

void ErrorStream::fail(const Typeset::Selection& selection, const std::string& str, ErrorCode code) alloc_except {
Typeset::Model* model = selection.getModel();

const size_t start = active_buffer->size();
*active_buffer += str;
*active_buffer += '\n';
Error error(selection, code, start, str.length(), active_buffer);
error.console_start = start;
error.console_len = str.length();
errors.push_back(error);
model->errors.push_back(error);
}

void Forscape::Code::ErrorStream::warn(SettingId setting, const Typeset::Selection& selection, ErrorCode code) noexcept {
warn(Program::instance()->settings.warningLevel(setting), selection, code);
}

void ErrorStream::warn(WarningLevel warning_level, const Typeset::Selection& selection, ErrorCode code) alloc_except {
assert(warning_level < NUM_WARNING_LEVELS);
if(warning_level == NO_WARNING) return;

Typeset::Model* model = selection.getModel();

const size_t start = active_buffer->size();
*active_buffer += getMessage(code);

Error error(selection, code, start, active_buffer->size()-start, active_buffer);
error.console_start = start;
error.console_len = error.tooltip_len;

switch (warning_level) {
case ERROR: errors.push_back(error); model->errors.push_back(error); break;
case WARN: warnings.push_back(error); model->warnings.push_back(error); break;
default: break;
}

if(shouldQuote(code)){
*active_buffer += ": ";
*active_buffer += selection.str();
}
}

void ErrorStream::warn(SettingId setting, const Typeset::Selection& selection, const std::string& str, ErrorCode code) noexcept {
warn(Program::instance()->settings.warningLevel(setting), selection, str, code);
}

void ErrorStream::warn(WarningLevel warning_level, const Typeset::Selection& selection, const std::string& str, ErrorCode code) alloc_except {
if(warning_level == NO_WARNING) return;

Typeset::Model* model = selection.getModel();

const size_t start = active_buffer->size();
*active_buffer += str;

Error error(selection, code, start, str.size(), active_buffer);
error.console_start = start;
error.console_len = str.size();

switch (warning_level) {
case ERROR: errors.push_back(error); model->errors.push_back(error); break;
case WARN: warnings.push_back(error); model->warnings.push_back(error); break;
default: break;
}
}

void ErrorStream::setBuffer(std::string* buffer) noexcept {
active_buffer = buffer;
}

void Forscape::Code::ErrorStream::setProgramBuffer() noexcept {
active_buffer = &error_warning_buffer;
}

const std::vector<Error>& ErrorStream::getErrors() const noexcept {
return errors;
}

}

}
32 changes: 30 additions & 2 deletions src/forscape_error.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <typeset_selection.h>
#include <code_error_types.h>
#include <code_settings_constants.h>
#include <vector>

namespace Forscape {
Expand All @@ -17,19 +18,46 @@ struct Error {
Typeset::Selection selection;
ErrorCode code;
size_t flag;
size_t tooltip_start; //Index of buffer for tooltip
size_t tooltip_len; //Length of tooltip
size_t console_start; //Index of start for console
size_t console_len; //Length of console message
const std::string* const buffer = nullptr;

Error() noexcept = default;
Error(Typeset::Selection controller, ErrorCode code) noexcept;
Error(const Typeset::Selection& selection, ErrorCode code, size_t start, size_t len, const std::string* const error_out) noexcept;

#ifndef FORSCAPE_TYPESET_HEADLESS
void writeTo(Typeset::Text* t, Typeset::View* caller) const;
static void writeErrors(const std::vector<Error>& errors, Typeset::Model* m, Typeset::View* caller);
static Typeset::Model* writeErrors(const std::vector<Error>& errors, Typeset::View* caller);
#endif
std::string message() const;
std::string_view tooltipMessage() const noexcept;
std::string_view consoleMessage() const noexcept;
std::string line() const;
};

class ErrorStream {
private:
std::string error_warning_buffer;
std::string* active_buffer = &error_warning_buffer;
std::vector<Error> errors;
std::vector<Error> warnings;

public:
void reset() noexcept;
bool noErrors() const noexcept;
void fail(const Typeset::Selection& selection, ErrorCode code) alloc_except;
void fail(const Typeset::Selection& selection, const std::string& str, ErrorCode code = ErrorCode::VALUE_NOT_DETERMINED) alloc_except;
void warn(SettingId setting, const Typeset::Selection& selection, ErrorCode code) alloc_except;
void warn(WarningLevel warning_level, const Typeset::Selection& selection, ErrorCode code) alloc_except;
void warn(SettingId setting, const Typeset::Selection& selection, const std::string& str, ErrorCode code = ErrorCode::VALUE_NOT_DETERMINED) alloc_except;
void warn(WarningLevel warning_level, const Typeset::Selection& selection, const std::string& str, ErrorCode code = ErrorCode::VALUE_NOT_DETERMINED) alloc_except;
void setBuffer(std::string* buffer) noexcept;
void setProgramBuffer() noexcept;
const std::vector<Error>& getErrors() const noexcept;
};

}

}
Expand Down
Loading

0 comments on commit b7e73eb

Please sign in to comment.