Assigments, array updating function. Test runner update
This commit is contained in:
parent
118837f6d8
commit
91eaa0ceea
@ -18,7 +18,7 @@ syn match musiqueInteger display "[0-9][0-9_]*"
|
|||||||
|
|
||||||
syn keyword musiqueConstant true false nil
|
syn keyword musiqueConstant true false nil
|
||||||
|
|
||||||
syn keyword musiqueDefaultBuiltins if len play
|
syn keyword musiqueDefaultBuiltins if len play permute par shuffle chord bpm oct note_on note_off flat update
|
||||||
syn keyword musiqueLinuxBuiltins say
|
syn keyword musiqueLinuxBuiltins say
|
||||||
|
|
||||||
syn match musiqueComment "--.*$"
|
syn match musiqueComment "--.*$"
|
||||||
|
@ -116,18 +116,33 @@ def record_tests(file_paths: list):
|
|||||||
tc = Test_Case.from_run(res, [])
|
tc = Test_Case.from_run(res, [])
|
||||||
tc.save(test_case_file)
|
tc.save(test_case_file)
|
||||||
|
|
||||||
|
def add_tests(file_paths: list):
|
||||||
|
to_be_added = []
|
||||||
|
|
||||||
|
for program_file in file_paths:
|
||||||
|
test_case_file = find_path_for_test_case(program_file)
|
||||||
|
if not os.path.exists(test_case_file):
|
||||||
|
print(f"Add test {program_file}? (yes/no)")
|
||||||
|
if "yes".startswith(input().strip().lower()):
|
||||||
|
to_be_added.append(program_file)
|
||||||
|
|
||||||
|
record_tests(to_be_added)
|
||||||
|
|
||||||
|
|
||||||
# list of files to test
|
# list of files to test
|
||||||
def main():
|
def main():
|
||||||
file_paths, mode = [], run_tests
|
file_paths, mode = [], run_tests
|
||||||
|
|
||||||
if len(argv) < 2:
|
if len(argv) < 2:
|
||||||
print("[ERROR] Expected mode argument (either 'record' or 'test')")
|
print("[ERROR] Expected mode argument (either 'record', 'add' or 'test')")
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
if argv[1] == "test":
|
if argv[1] == "test":
|
||||||
mode = run_tests
|
mode = run_tests
|
||||||
elif argv[1] == "record":
|
elif argv[1] == "record":
|
||||||
mode = record_tests
|
mode = record_tests
|
||||||
|
elif argv[1] == "add":
|
||||||
|
mode = add_tests
|
||||||
else:
|
else:
|
||||||
print(f"[ERROR] Unrecognized mode '{argv[1]}'")
|
print(f"[ERROR] Unrecognized mode '{argv[1]}'")
|
||||||
exit(1)
|
exit(1)
|
||||||
@ -142,6 +157,8 @@ def main():
|
|||||||
file_paths.extend(glob(f"{path}/*.mq"))
|
file_paths.extend(glob(f"{path}/*.mq"))
|
||||||
else:
|
else:
|
||||||
file_paths.append(path)
|
file_paths.append(path)
|
||||||
|
elif mode == add_tests:
|
||||||
|
print("Adding: " + path)
|
||||||
|
|
||||||
mode(file_paths)
|
mode(file_paths)
|
||||||
|
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"returncode": 0,
|
||||||
|
"stdout": "10\n20\n30\n20\n20\n20\n[1; 2; 3]\n[1; 10; 3]\n[1; 3; 3]\n",
|
||||||
|
"stderr": "",
|
||||||
|
"flags": []
|
||||||
|
}
|
6
examples/.tests_cache/permutations.mq.json
Normal file
6
examples/.tests_cache/permutations.mq.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"returncode": 0,
|
||||||
|
"stdout": "[1; 2; 3; 4; 5]\n[1; 2; 3; 5; 4]\n[1; 2; 4; 3; 5]\n[1; 2; 4; 5; 3]\n[1; 2; 5; 3; 4]\n[1; 2; 5; 4; 3]\n[1; 3; 2; 4; 5]\n[1; 3; 2; 5; 4]\n[1; 3; 4; 2; 5]\n[1; 3; 4; 5; 2]\n[1; 3; 5; 2; 4]\n[1; 3; 5; 4; 2]\n[1; 4; 2; 3; 5]\n[1; 4; 2; 5; 3]\n[1; 4; 3; 2; 5]\n[1; 4; 3; 5; 2]\n[1; 4; 5; 2; 3]\n[1; 4; 5; 3; 2]\n[1; 5; 2; 3; 4]\n[1; 5; 2; 4; 3]\n[1; 5; 3; 2; 4]\n[1; 5; 3; 4; 2]\n[1; 5; 4; 2; 3]\n[1; 5; 4; 3; 2]\n[2; 1; 3; 4; 5]\n[2; 1; 3; 5; 4]\n[2; 1; 4; 3; 5]\n[2; 1; 4; 5; 3]\n[2; 1; 5; 3; 4]\n[2; 1; 5; 4; 3]\n[2; 3; 1; 4; 5]\n[2; 3; 1; 5; 4]\n[2; 3; 4; 1; 5]\n[2; 3; 4; 5; 1]\n[2; 3; 5; 1; 4]\n[2; 3; 5; 4; 1]\n[2; 4; 1; 3; 5]\n[2; 4; 1; 5; 3]\n[2; 4; 3; 1; 5]\n[2; 4; 3; 5; 1]\n[2; 4; 5; 1; 3]\n[2; 4; 5; 3; 1]\n[2; 5; 1; 3; 4]\n[2; 5; 1; 4; 3]\n[2; 5; 3; 1; 4]\n[2; 5; 3; 4; 1]\n[2; 5; 4; 1; 3]\n[2; 5; 4; 3; 1]\n[3; 1; 2; 4; 5]\n[3; 1; 2; 5; 4]\n[3; 1; 4; 2; 5]\n[3; 1; 4; 5; 2]\n[3; 1; 5; 2; 4]\n[3; 1; 5; 4; 2]\n[3; 2; 1; 4; 5]\n[3; 2; 1; 5; 4]\n[3; 2; 4; 1; 5]\n[3; 2; 4; 5; 1]\n[3; 2; 5; 1; 4]\n[3; 2; 5; 4; 1]\n[3; 4; 1; 2; 5]\n[3; 4; 1; 5; 2]\n[3; 4; 2; 1; 5]\n[3; 4; 2; 5; 1]\n[3; 4; 5; 1; 2]\n[3; 4; 5; 2; 1]\n[3; 5; 1; 2; 4]\n[3; 5; 1; 4; 2]\n[3; 5; 2; 1; 4]\n[3; 5; 2; 4; 1]\n[3; 5; 4; 1; 2]\n[3; 5; 4; 2; 1]\n[4; 1; 2; 3; 5]\n[4; 1; 2; 5; 3]\n[4; 1; 3; 2; 5]\n[4; 1; 3; 5; 2]\n[4; 1; 5; 2; 3]\n[4; 1; 5; 3; 2]\n[4; 2; 1; 3; 5]\n[4; 2; 1; 5; 3]\n[4; 2; 3; 1; 5]\n[4; 2; 3; 5; 1]\n[4; 2; 5; 1; 3]\n[4; 2; 5; 3; 1]\n[4; 3; 1; 2; 5]\n[4; 3; 1; 5; 2]\n[4; 3; 2; 1; 5]\n[4; 3; 2; 5; 1]\n[4; 3; 5; 1; 2]\n[4; 3; 5; 2; 1]\n[4; 5; 1; 2; 3]\n[4; 5; 1; 3; 2]\n[4; 5; 2; 1; 3]\n[4; 5; 2; 3; 1]\n[4; 5; 3; 1; 2]\n[4; 5; 3; 2; 1]\n[5; 1; 2; 3; 4]\n[5; 1; 2; 4; 3]\n[5; 1; 3; 2; 4]\n[5; 1; 3; 4; 2]\n[5; 1; 4; 2; 3]\n[5; 1; 4; 3; 2]\n[5; 2; 1; 3; 4]\n[5; 2; 1; 4; 3]\n[5; 2; 3; 1; 4]\n[5; 2; 3; 4; 1]\n[5; 2; 4; 1; 3]\n[5; 2; 4; 3; 1]\n[5; 3; 1; 2; 4]\n[5; 3; 1; 4; 2]\n[5; 3; 2; 1; 4]\n[5; 3; 2; 4; 1]\n[5; 3; 4; 1; 2]\n[5; 3; 4; 2; 1]\n[5; 4; 1; 2; 3]\n[5; 4; 1; 3; 2]\n[5; 4; 2; 1; 3]\n[5; 4; 2; 3; 1]\n[5; 4; 3; 1; 2]\n[5; 4; 3; 2; 1]\n",
|
||||||
|
"stderr": "",
|
||||||
|
"flags": []
|
||||||
|
}
|
27
examples/assigments-state-management.mq
Normal file
27
examples/assigments-state-management.mq
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
----------------------------------
|
||||||
|
Simple variable assigment
|
||||||
|
----------------------------------
|
||||||
|
var x = 10;
|
||||||
|
var y = 20;
|
||||||
|
say x;
|
||||||
|
say y;
|
||||||
|
|
||||||
|
x = 30;
|
||||||
|
say x;
|
||||||
|
say y;
|
||||||
|
|
||||||
|
x = y;
|
||||||
|
say x;
|
||||||
|
say y;
|
||||||
|
|
||||||
|
----------------------------------
|
||||||
|
Array updates
|
||||||
|
----------------------------------
|
||||||
|
var array = flat 1 2 3;
|
||||||
|
say array;
|
||||||
|
|
||||||
|
array = update array 1 10;
|
||||||
|
say array;
|
||||||
|
|
||||||
|
array = update array 1 (array.2);
|
||||||
|
say array;
|
@ -14,6 +14,15 @@ static inline bool typecheck(std::vector<Value> const& args, auto const& ...expe
|
|||||||
} (std::make_index_sequence<sizeof...(expected_types)>{});
|
} (std::make_index_sequence<sizeof...(expected_types)>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Intrinsic implementation primitive providing a short way to move values based on matched type signature
|
||||||
|
static inline bool typecheck_front(std::vector<Value> const& args, auto const& ...expected_types)
|
||||||
|
{
|
||||||
|
return (args.size() >= sizeof...(expected_types)) &&
|
||||||
|
[&args, expected_types...]<std::size_t ...I>(std::index_sequence<I...>) {
|
||||||
|
return ((expected_types == args[I].type) && ...);
|
||||||
|
} (std::make_index_sequence<sizeof...(expected_types)>{});
|
||||||
|
}
|
||||||
|
|
||||||
/// Intrinsic implementation primitive providing a short way to move values based on matched type signature
|
/// Intrinsic implementation primitive providing a short way to move values based on matched type signature
|
||||||
template<auto ...Types>
|
template<auto ...Types>
|
||||||
static inline auto move_from(std::vector<Value>& args)
|
static inline auto move_from(std::vector<Value>& args)
|
||||||
@ -27,8 +36,9 @@ static inline auto move_from(std::vector<Value>& args)
|
|||||||
template<auto ...Types>
|
template<auto ...Types>
|
||||||
struct Shape
|
struct Shape
|
||||||
{
|
{
|
||||||
static inline auto move_from(std::vector<Value>& args) { return ::move_from<Types...>(args); }
|
static inline auto move_from(std::vector<Value>& args) { return ::move_from<Types...>(args); }
|
||||||
static inline auto typecheck(std::vector<Value>& args) { return ::typecheck(args, Types...); }
|
static inline auto typecheck(std::vector<Value>& args) { return ::typecheck(args, Types...); }
|
||||||
|
static inline auto typecheck_front(std::vector<Value>& args) { return ::typecheck_front(args, Types...); }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Returns if type can be indexed
|
/// Returns if type can be indexed
|
||||||
@ -295,6 +305,27 @@ Interpreter::Interpreter()
|
|||||||
|
|
||||||
register_note_length_constants();
|
register_note_length_constants();
|
||||||
|
|
||||||
|
global.force_define("update", +[](Interpreter &i, std::vector<Value> args) -> Result<Value> {
|
||||||
|
assert(args.size() == 3, "Update requires 3 arguments"); // TODO(assert)
|
||||||
|
using Eager_And_Number = Shape<Value::Type::Array, Value::Type::Number>;
|
||||||
|
using Lazy_And_Number = Shape<Value::Type::Block, Value::Type::Number>;
|
||||||
|
|
||||||
|
if (Eager_And_Number::typecheck_front(args)) {
|
||||||
|
auto [v, index] = Eager_And_Number::move_from(args);
|
||||||
|
v.elements[index.as_int()] = std::move(args.back());
|
||||||
|
return Value::from(std::move(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Lazy_And_Number::typecheck_front(args)) {
|
||||||
|
auto [v, index] = Lazy_And_Number::move_from(args);
|
||||||
|
auto array = Try(into_flat_array(i, { Value::from(std::move(v)) }));
|
||||||
|
array.elements[index.as_int()] = std::move(args.back());
|
||||||
|
return Value::from(std::move(array));
|
||||||
|
}
|
||||||
|
|
||||||
|
unimplemented("Wrong shape of update function");
|
||||||
|
});
|
||||||
|
|
||||||
global.force_define("typeof", +[](Interpreter&, std::vector<Value> args) -> Result<Value> {
|
global.force_define("typeof", +[](Interpreter&, std::vector<Value> args) -> Result<Value> {
|
||||||
assert(args.size() == 1, "typeof expects only one argument");
|
assert(args.size() == 1, "typeof expects only one argument");
|
||||||
return Value::from(std::string(type_name(args.front().type)));
|
return Value::from(std::string(type_name(args.front().type)));
|
||||||
@ -446,11 +477,20 @@ Result<Value> Interpreter::eval(Ast &&ast)
|
|||||||
|
|
||||||
case Ast::Type::Binary:
|
case Ast::Type::Binary:
|
||||||
{
|
{
|
||||||
std::vector<Value> values;
|
assert(ast.arguments.size() == 2, "Expected arguments of binary operation to be 2 long");
|
||||||
values.reserve(ast.arguments.size());
|
|
||||||
|
if (ast.token.source == "=") {
|
||||||
|
auto lhs = std::move(ast.arguments.front());
|
||||||
|
auto rhs = std::move(ast.arguments.back());
|
||||||
|
assert(lhs.type == Ast::Type::Literal && lhs.token.type == Token::Type::Symbol,
|
||||||
|
"Currently LHS of assigment must be an identifier"); // TODO(assert)
|
||||||
|
|
||||||
|
Value *v = env->find(std::string(lhs.token.source));
|
||||||
|
assert(v, "Cannot resolve variable: "s + std::string(lhs.token.source)); // TODO(assert)
|
||||||
|
return *v = Try(eval(std::move(rhs)));
|
||||||
|
}
|
||||||
|
|
||||||
if (ast.token.source == "and" || ast.token.source == "or") {
|
if (ast.token.source == "and" || ast.token.source == "or") {
|
||||||
assert(ast.arguments.size() == 2, "Expected arguments of binary operation to be 2 long");
|
|
||||||
auto lhs = std::move(ast.arguments.front());
|
auto lhs = std::move(ast.arguments.front());
|
||||||
auto rhs = std::move(ast.arguments.back());
|
auto rhs = std::move(ast.arguments.back());
|
||||||
|
|
||||||
@ -463,7 +503,6 @@ Result<Value> Interpreter::eval(Ast &&ast)
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto op = operators.find(std::string(ast.token.source));
|
auto op = operators.find(std::string(ast.token.source));
|
||||||
|
|
||||||
if (op == operators.end()) {
|
if (op == operators.end()) {
|
||||||
return Error {
|
return Error {
|
||||||
.details = errors::Undefined_Operator { .op = ast.token.source },
|
.details = errors::Undefined_Operator { .op = ast.token.source },
|
||||||
@ -471,6 +510,8 @@ Result<Value> Interpreter::eval(Ast &&ast)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<Value> values;
|
||||||
|
values.reserve(ast.arguments.size());
|
||||||
for (auto& a : ast.arguments) {
|
for (auto& a : ast.arguments) {
|
||||||
values.push_back(Try(eval(std::move(a))));
|
values.push_back(Try(eval(std::move(a))));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user