Ensure when adding new operators we add them right
Operators not only are needed to be defined by their implementation in Interpreter constructor, but also are needed to be included in precedense resolution. To prevent partial definition we predefine number of builtin operators as numeric constant and test against it in all relevant places.
This commit is contained in:
parent
e090778db9
commit
a3d0a942e4
@ -711,27 +711,31 @@ error:
|
|||||||
global.force_define("program_change", pgmchange);
|
global.force_define("program_change", pgmchange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Operators definition table
|
||||||
|
static constexpr auto Operators = std::array {
|
||||||
|
std::tuple { "+", plus_minus_operator<std::plus<>> },
|
||||||
|
std::tuple { "-", plus_minus_operator<std::minus<>> },
|
||||||
|
std::tuple { "*", binary_operator<std::multiplies<>, '*'> },
|
||||||
|
std::tuple { "/", binary_operator<std::divides<>, '/'> },
|
||||||
|
|
||||||
operators["+"] = plus_minus_operator<std::plus<>>;
|
std::tuple { "<", comparison_operator<std::less<>> },
|
||||||
operators["-"] = plus_minus_operator<std::minus<>>;
|
std::tuple { ">", comparison_operator<std::greater<>> },
|
||||||
operators["*"] = binary_operator<std::multiplies<>, '*'>;
|
std::tuple { "<=", comparison_operator<std::less_equal<>> },
|
||||||
operators["/"] = binary_operator<std::divides<>, '/'>;
|
std::tuple { ">=", comparison_operator<std::greater_equal<>> },
|
||||||
|
|
||||||
operators["<"] = comparison_operator<std::less<>>;
|
std::tuple { "==", equality_operator<std::equal_to<>> },
|
||||||
operators[">"] = comparison_operator<std::greater<>>;
|
std::tuple { "!=", equality_operator<std::not_equal_to<>> },
|
||||||
operators["<="] = comparison_operator<std::less_equal<>>;
|
|
||||||
operators[">="] = comparison_operator<std::greater_equal<>>;
|
|
||||||
|
|
||||||
operators["=="] = equality_operator<std::equal_to<>>;
|
std::tuple { ".",
|
||||||
operators["!="] = equality_operator<std::not_equal_to<>>;
|
+[](Interpreter &i, std::vector<Value> args) -> Result<Value> {
|
||||||
|
|
||||||
operators["."] = +[](Interpreter &i, std::vector<Value> args) -> Result<Value> {
|
|
||||||
assert(args.size() == 2, "Operator . requires two arguments"); // TODO(assert)
|
assert(args.size() == 2, "Operator . requires two arguments"); // TODO(assert)
|
||||||
assert(args.back().type == Value::Type::Number, "Only numbers can be used for indexing"); // TODO(assert)
|
assert(args.back().type == Value::Type::Number, "Only numbers can be used for indexing"); // TODO(assert)
|
||||||
return std::move(args.front()).index(i, std::move(args.back()).n.as_int());
|
return std::move(args.front()).index(i, std::move(args.back()).n.as_int());
|
||||||
};
|
}
|
||||||
|
},
|
||||||
|
|
||||||
operators["&"] = +[](Interpreter &i, std::vector<Value> args) -> Result<Value> {
|
std::tuple { "&",
|
||||||
|
+[](Interpreter&, std::vector<Value> args) -> Result<Value> {
|
||||||
using Chord_Chord = Shape<Value::Type::Music, Value::Type::Music>;
|
using Chord_Chord = Shape<Value::Type::Music, Value::Type::Music>;
|
||||||
|
|
||||||
if (Chord_Chord::typecheck(args)) {
|
if (Chord_Chord::typecheck(args)) {
|
||||||
@ -756,7 +760,17 @@ error:
|
|||||||
},
|
},
|
||||||
.location = {}
|
.location = {}
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// All operators should be defined here except 'and' and 'or' which handle evaluation differently
|
||||||
|
// and are need unevaluated expressions for their proper evaluation. Exclusion of them is marked
|
||||||
|
// as subtraction of total excluded operators from expected constant
|
||||||
|
static_assert(Operators.size() == Operators_Count - 2, "All operators handlers are defined here");
|
||||||
|
|
||||||
|
// Set all predefined operators into operators array
|
||||||
|
for (auto &[name, fptr] : Operators) { operators[name] = fptr; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,7 +404,8 @@ struct Token
|
|||||||
Location location;
|
Location location;
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr auto Keywords_Count = 6;
|
static constexpr usize Keywords_Count = 6;
|
||||||
|
static constexpr usize Operators_Count = 14;
|
||||||
|
|
||||||
std::string_view type_name(Token::Type type);
|
std::string_view type_name(Token::Type type);
|
||||||
|
|
||||||
|
@ -498,6 +498,12 @@ constexpr bool one_of(std::string_view id, auto const& ...args)
|
|||||||
|
|
||||||
static usize precedense(std::string_view op)
|
static usize precedense(std::string_view op)
|
||||||
{
|
{
|
||||||
|
// Operators that are not included below are
|
||||||
|
// '.' since it have own precedense rules and is not binary expression but its own kind of expression
|
||||||
|
//
|
||||||
|
// Exclusion of them is marked by subtracting total number of excluded operators.
|
||||||
|
static_assert(Operators_Count - 1 == 13, "Ensure that all operators have defined precedense below");
|
||||||
|
|
||||||
if (one_of(op, "or")) return 100;
|
if (one_of(op, "or")) return 100;
|
||||||
if (one_of(op, "and")) return 150;
|
if (one_of(op, "and")) return 150;
|
||||||
if (one_of(op, "<", ">", "<=", ">=", "==", "!=")) return 200;
|
if (one_of(op, "<", ">", "<=", ">=", "==", "!=")) return 200;
|
||||||
|
Loading…
Reference in New Issue
Block a user