Assigments, array updating function. Test runner update

This commit is contained in:
Robert Bendun 2022-06-06 04:03:40 +02:00
parent 118837f6d8
commit 91eaa0ceea
6 changed files with 105 additions and 8 deletions

View File

@ -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 "--.*$"

View File

@ -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)

View File

@ -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": []
}

View 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": []
}

View 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;

View File

@ -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)
@ -29,6 +38,7 @@ 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))));
} }