diff --git a/include/musique.hh b/include/musique.hh index 7d64318..9aa1ac8 100644 --- a/include/musique.hh +++ b/include/musique.hh @@ -122,6 +122,22 @@ namespace errors std::string_view op; }; + /// When user tries to use operator with wrong arity of arguments + struct Wrong_Arity_Of + { + /// Type of operation + enum Type { Operator, Function } type; + + /// Name of operation + std::string_view name; + + /// Arity that was expected by given operation + size_t expected_arity; + + /// Arit that user provided + size_t actual_arity; + }; + /// When user tried to call something that can't be called struct Not_Callable { @@ -227,6 +243,7 @@ namespace errors Unexpected_Keyword, Unrecognized_Character, Unsupported_Types_For, + Wrong_Arity_Of, internal::Unexpected_Token >; } diff --git a/src/builtin_functions.cc b/src/builtin_functions.cc index acc90f9..13f9a2f 100644 --- a/src/builtin_functions.cc +++ b/src/builtin_functions.cc @@ -350,7 +350,14 @@ static Result builtin_sim(Interpreter &interpreter, std::vector ar return {}; } - unimplemented(); + // Invalid type for sim function + return errors::Unsupported_Types_For { + .type = errors::Unsupported_Types_For::Function, + .name = "sim", + .possibilities = { + "(music | array of music)+" + }, + }; } } append { interpreter }; @@ -600,7 +607,17 @@ static Result builtin_try(Interpreter &interpreter, std::vector ar /// Update value inside of array static Result builtin_update(Interpreter &i, std::vector args) { - assert(args.size() == 3, "Update requires 3 arguments"); // TODO(assert) + auto const guard = Guard<1> { + .name = "update", + .possibilities = { + "array index:number new_value" + } + }; + + if (args.size() != 3) { + return guard.yield_error(); + } + using Eager_And_Number = Shape; using Lazy_And_Number = Shape; @@ -617,7 +634,7 @@ static Result builtin_update(Interpreter &i, std::vector args) return Value::from(std::move(array)); } - unimplemented("Wrong shape of update function"); + return guard.yield_error(); } /// Return typeof variable diff --git a/src/errors.cc b/src/errors.cc index bdb3914..72b17e0 100644 --- a/src/errors.cc +++ b/src/errors.cc @@ -134,18 +134,19 @@ void unreachable(Location loc) std::ostream& operator<<(std::ostream& os, Error const& err) { std::string_view short_description = visit(Overloaded { - [](errors::Operation_Requires_Midi_Connection const&) { return "Operation requires MIDI connection"; }, - [](errors::Missing_Variable const&) { return "Cannot find variable"; }, + [](errors::Expected_Expression_Separator_Before const&) { return "Missing semicolon"; }, [](errors::Failed_Numeric_Parsing const&) { return "Failed to parse a number"; }, + [](errors::Literal_As_Identifier const&) { return "Literal used in place of an identifier"; }, + [](errors::Missing_Variable const&) { return "Cannot find variable"; }, [](errors::Not_Callable const&) { return "Value not callable"; }, + [](errors::Operation_Requires_Midi_Connection const&) { return "Operation requires MIDI connection"; }, + [](errors::Out_Of_Range const&) { return "Index out of range"; }, [](errors::Undefined_Operator const&) { return "Undefined operator"; }, [](errors::Unexpected_Empty_Source const&) { return "Unexpected end of file"; }, [](errors::Unexpected_Keyword const&) { return "Unexpected keyword"; }, [](errors::Unrecognized_Character const&) { return "Unrecognized character"; }, + [](errors::Wrong_Arity_Of const&) { return "Different arity then expected"; }, [](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::Arithmetic const& err) { switch (err.type) { case errors::Arithmetic::Division_By_Zero: return "Division by 0"; @@ -296,6 +297,19 @@ std::ostream& operator<<(std::ostream& os, Error const& err) } }, + [&](errors::Wrong_Arity_Of const& err) { + switch (err.type) { + break; case errors::Wrong_Arity_Of::Function: + os << "Function " << err.name << " expects " << err.expected_arity << " arguments but you provided " << err.actual_arity << "\n"; + os << "\n"; + print_error_line(loc); + break; case errors::Wrong_Arity_Of::Operator: + os << "Operator " << err.name << " expects " << err.expected_arity << " arguments but you provided " << err.actual_arity << "\n"; + os << "\n"; + print_error_line(loc); + } + }, + [&](errors::Not_Callable const& err) { os << "Value of type " << err.type << " cannot be called.\n"; os << "\n"; @@ -403,7 +417,11 @@ std::ostream& operator<<(std::ostream& os, Error const& err) } }, - [&](errors::Unexpected_Keyword const&) { unimplemented(); }, + [&](errors::Unexpected_Keyword const& err) { + os << "Keyword " << err.keyword << " should not be used here\n\n"; + + print_error_line(loc); + }, }, err.details); return os; diff --git a/src/interpreter.cc b/src/interpreter.cc index d42d25b..10b49b4 100644 --- a/src/interpreter.cc +++ b/src/interpreter.cc @@ -201,10 +201,9 @@ Result Interpreter::eval(Ast &&ast) block.body = std::move(ast.arguments.back()); return Value::from(std::move(block)); } - - default: - unimplemented(); } + + unreachable(); } void Interpreter::enter_scope() diff --git a/src/number.cc b/src/number.cc index cef8565..2ea1361 100644 --- a/src/number.cc +++ b/src/number.cc @@ -332,7 +332,7 @@ Result Number::pow(Number n) const // Hard case, we raise this to fractional power. // Essentialy finding n.den root of (x to n.num power). // We need to protect ourselfs against even roots of negative numbers. - unimplemented(); + unimplemented("nth root calculation is not implemented yet"); } std::size_t std::hash::operator()(Number const& value) const diff --git a/src/parser.cc b/src/parser.cc index 05213fa..bb4aa91 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -310,6 +310,18 @@ Result Parser::parse_atomic_expression() return ast; } + break; case Token::Type::Operator: + return Error { + .details = errors::Wrong_Arity_Of { + .type = errors::Wrong_Arity_Of::Operator, + .name = peek()->source, + .expected_arity = 2, // TODO This should be resolved based on operator + .actual_arity = 0, + }, + .location = peek()->location, + }; + + default: return Error { .details = errors::internal::Unexpected_Token { diff --git a/src/value.cc b/src/value.cc index 60bce30..b4bb0f9 100644 --- a/src/value.cc +++ b/src/value.cc @@ -71,7 +71,7 @@ Result Value::from(Token t) return Value::from(Chord::from(t.source)); default: - unimplemented(); + unreachable(); } } @@ -329,7 +329,16 @@ Result Block::operator()(Interpreter &i, std::vector arguments) auto old_scope = std::exchange(i.env, context); i.enter_scope(); - assert(parameters.size() == arguments.size(), "wrong number of arguments"); + if (parameters.size() != arguments.size()) { + return errors::Wrong_Arity_Of { + .type = errors::Wrong_Arity_Of::Function, + // TODO Let user defined functions have name of their first assigment (Zig like) + // or from place of definition like + .name = "", + .expected_arity = parameters.size(), + .actual_arity = arguments.size(), + }; + } for (usize j = 0; j < parameters.size(); ++j) { i.env->force_define(parameters[j], std::move(arguments[j])); @@ -521,7 +530,13 @@ Result Chord::operator()(Interpreter&, std::vector args) continue; default: - unimplemented(); + return errors::Unsupported_Types_For { + .type = errors::Unsupported_Types_For::Function, + .name = "note creation", + .possibilities = { + "(note:music [octave:number [duration:number]])+" + } + }; } }