From 1597b678e1c5a60d8f0a35682e1b173001c9d838 Mon Sep 17 00:00:00 2001 From: Robert Bendun Date: Sun, 4 Sep 2022 13:16:40 +0200 Subject: [PATCH] Report error when index is too large --- include/musique.hh | 11 +++++++++++ src/errors.cc | 13 +++++++++++++ src/value.cc | 15 ++++++++++++--- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/include/musique.hh b/include/musique.hh index 221d1bf..f2acd2c 100644 --- a/include/musique.hh +++ b/include/musique.hh @@ -166,6 +166,16 @@ namespace errors std::string name; }; + /// When user tries to get element from collection with index higher then collection size + struct Out_Of_Range + { + /// Index that was required by the user + size_t required_index; + + /// Size of accessed collection + size_t size; + }; + /// Collection of messages that are considered internal and should not be printed to the end user. namespace internal { @@ -191,6 +201,7 @@ namespace errors Missing_Variable, Not_Callable, Operation_Requires_Midi_Connection, + Out_Of_Range, Undefined_Operator, Unexpected_Empty_Source, Unexpected_Keyword, diff --git a/src/errors.cc b/src/errors.cc index 966e6af..2b2f0ea 100644 --- a/src/errors.cc +++ b/src/errors.cc @@ -145,6 +145,7 @@ std::ostream& operator<<(std::ostream& os, Error const& err) [](errors::internal::Unexpected_Token const&) { return "Unexpected token"; }, [](errors::Expected_Expression_Separator_Before const&) { return "Missing semicolon"; }, [](errors::Literal_As_Identifier const&) { return "Literal used in place of an identifier"; }, + [](errors::Out_Of_Range const&) { return "Index out of range"; }, [](errors::Unsupported_Types_For const& type) { return type.type == errors::Unsupported_Types_For::Function ? "Function called with wrong arguments" @@ -339,6 +340,18 @@ std::ostream& operator<<(std::ostream& os, Error const& err) } os << '\n' << pretty::end; }, + + [&](errors::Out_Of_Range const& err) { + if (err.size == 0) { + os << "Can't get " << err.required_index << " element out of empty collection\n"; + } else { + os << "Can't get " << err.required_index << " element from collection with only " << err.size << " elements\n"; + } + + os << '\n'; + print_error_line(loc); + }, + [&](errors::Unexpected_Keyword const&) { unimplemented(); }, }, err.details); diff --git a/src/value.cc b/src/value.cc index 77d9a01..4229701 100644 --- a/src/value.cc +++ b/src/value.cc @@ -348,16 +348,25 @@ Result Block::operator()(Interpreter &i, std::vector arguments) return result; } +/// Helper that produces error when trying to access container with too few elements for given index +static inline Result guard_index(unsigned index, unsigned size) +{ + if (index < size) return {}; + return Error { + .details = errors::Out_Of_Range { .required_index = index, .size = size } + }; +} + // TODO Add memoization Result Block::index(Interpreter &i, unsigned position) { assert(parameters.size() == 0, "cannot index into block with parameters (for now)"); if (body.type != Ast::Type::Sequence) { - assert(position == 0, "Out of range"); // TODO(assert) + Try(guard_index(position, 1)); return i.eval((Ast)body); } - assert(position < body.arguments.size(), "Out of range"); // TODO(assert) + Try(guard_index(position, body.arguments.size())); return i.eval((Ast)body.arguments[position]); } @@ -368,7 +377,7 @@ usize Block::size() const Result Array::index(Interpreter &, unsigned position) { - assert(position < elements.size(), "Out of range"); // TODO(assert) + Try(guard_index(position, elements.size())); return elements[position]; }