diff --git a/scripts/.gitkeep b/scripts/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/scripts/big_if_true.toy b/scripts/big_if_true.toy new file mode 100644 index 0000000..641fe73 --- /dev/null +++ b/scripts/big_if_true.toy @@ -0,0 +1,10 @@ +if (true) print "Correct"; else print "Error"; +if (true) print "Correct"; else print "Error"; +if (true) print "Correct"; else print "Error"; +if (true) print "Correct"; else print "Error"; +if (true) print "Correct"; else print "Error"; +if (true) print "Correct"; else print "Error"; +if (true) print "Correct"; else print "Error"; +if (true) print "Correct"; else print "Error"; +if (true) print "Correct"; else print "Error"; +if (true) print "Correct"; else print "Error"; diff --git a/scripts/brace_yourself.toy b/scripts/brace_yourself.toy new file mode 100644 index 0000000..145ddd3 --- /dev/null +++ b/scripts/brace_yourself.toy @@ -0,0 +1,11 @@ + +if (true) { print "Correct"; } else { print "Error"; } +if (true) { print "Correct"; } else { print "Error"; } +if (true) { print "Correct"; } else { print "Error"; } +if (true) { print "Correct"; } else { print "Error"; } +if (true) { print "Correct"; } else { print "Error"; } +if (true) { print "Correct"; } else { print "Error"; } +if (true) { print "Correct"; } else { print "Error"; } +if (false) { print "Correct"; } else { print "Error"; } +if (true) { print "Correct"; } else { print "Error"; } +if (true) { print "Correct"; } else { print "Error"; } diff --git a/scripts/concat.toy b/scripts/concat.toy new file mode 100644 index 0000000..6e88700 --- /dev/null +++ b/scripts/concat.toy @@ -0,0 +1,10 @@ +print "foo" .. "bar"; +print "foo" .. "bar"; +print "foo" .. "bar"; +print "foo" .. "bar"; +print "foo" .. "bar"; +print "foo" .. "bar"; +print "foo" .. "bar"; +print "foo" .. "bar"; +print "foo" .. "bar"; +print "foo" .. "bar"; diff --git a/scripts/cond.toy b/scripts/cond.toy index 1c83e6e..4fe0207 100644 --- a/scripts/cond.toy +++ b/scripts/cond.toy @@ -1,26 +1,26 @@ //literals if (true) { - print "Success"; + print "Success 1"; } else { - print "Failed"; + print "Failure 1"; } //false literals if (false) { - print "Failed"; + print "Failure 2"; } else { - print "Success"; + print "Success 2"; } //conditionals if (1 < 2) { - print "Success"; + print "Success 3"; } if (1 > 2) { - print "Failure"; + print "Failure 3"; } @@ -28,17 +28,40 @@ if (1 > 2) { var a = 42; if (a) { - print "Success"; + print "Success 4"; } else { - print "Failure"; + print "Failure 4"; } if (a == 42) { - print "Success"; + print "Success 5"; } else { - print "Failure"; + print "Failure 5"; +} + +//concatenated strings +if ("foo" .. "bar" == "foobar") { + print "Success 6"; +} +else { + print "Failure 6"; +} + + +if ("foobar" == "foo" .. "bar") { + print "Success 7"; +} +else { + print "Failure 7"; +} + +if ("fizz" .. "le" == "fi" .. "zzle") { + print "Success 8"; +} +else { + print "Failure 8"; } diff --git a/source/toy_string.c b/source/toy_string.c index 394dd88..c604320 100644 --- a/source/toy_string.c +++ b/source/toy_string.c @@ -182,7 +182,7 @@ Toy_String* Toy_concatStrings(Toy_Bucket** bucketHandle, Toy_String* left, Toy_S ret->as.node.left = left; ret->as.node.right = right; - incrementRefCount(left); + incrementRefCount(left);//URGENT: improve incrementRefCount(right); return ret; @@ -253,7 +253,7 @@ static int deepCompareUtil(Toy_String* left, Toy_String* right, const char** lef } //BUGFIX: if we're not currently iterating through the left leaf (and leftHead is not null), skip out - if (left->type == TOY_STRING_LEAF && (*leftHead) != NULL && (**leftHead) != '\0' && ((*leftHead) < left->as.leaf.data || (*leftHead) > (left->as.leaf.data + strlen(left->as.leaf.data))) ) { + if (left->type == TOY_STRING_LEAF && (*leftHead) != NULL && (**leftHead) != '\0' && ((*leftHead) < left->as.leaf.data || (*leftHead) > (left->as.leaf.data + strlen(left->as.leaf.data))) ) { //URGENT: replace strlen with the stored lengths return result; } @@ -328,7 +328,7 @@ int Toy_compareStrings(Toy_String* left, Toy_String* right) { exit(-1); } - return strcmp(left->as.name.data, right->as.name.data); + return strcmp(left->as.name.data, right->as.name.data); //URGENT: strncmp } //util pointers diff --git a/tests/cases/test_ast.c b/tests/cases/test_ast.c index 8ed9401..10bd98a 100644 --- a/tests/cases/test_ast.c +++ b/tests/cases/test_ast.c @@ -252,6 +252,81 @@ int test_type_emission(Toy_Bucket** bucketHandle) { } } + //emit keyword if-then + { + //build the AST + Toy_Ast* ast = NULL; + Toy_Ast* condBranch = NULL; + Toy_Ast* thenBranch = NULL; + + Toy_private_emitAstValue(bucketHandle, &condBranch, TOY_VALUE_FROM_INTEGER(42)); + Toy_private_emitAstValue(bucketHandle, &thenBranch, TOY_VALUE_FROM_INTEGER(69)); + + Toy_private_emitAstIfThenElse(bucketHandle, &ast, condBranch, thenBranch, NULL); + + //check if it worked + if ( + ast == NULL || + ast->type != TOY_AST_IF_THEN_ELSE || + ast->ifThenElse.condBranch == NULL || + ast->ifThenElse.condBranch->type != TOY_AST_VALUE || + TOY_VALUE_IS_INTEGER(ast->ifThenElse.condBranch->value.value) != true || + TOY_VALUE_AS_INTEGER(ast->ifThenElse.condBranch->value.value) != 42 || + + ast->ifThenElse.thenBranch == NULL || + ast->ifThenElse.thenBranch->type != TOY_AST_VALUE || + TOY_VALUE_IS_INTEGER(ast->ifThenElse.thenBranch->value.value) != true || + TOY_VALUE_AS_INTEGER(ast->ifThenElse.thenBranch->value.value) != 69 || + + ast->ifThenElse.elseBranch != NULL || + + false) + { + fprintf(stderr, TOY_CC_ERROR "ERROR: failed to emit a keyword 'if-then' as 'Toy_Ast', state unknown\n" TOY_CC_RESET); + return -1; + } + } + + //emit keyword if-then-else + { + //build the AST + Toy_Ast* ast = NULL; + Toy_Ast* condBranch = NULL; + Toy_Ast* thenBranch = NULL; + Toy_Ast* elseBranch = NULL; + + Toy_private_emitAstValue(bucketHandle, &condBranch, TOY_VALUE_FROM_INTEGER(42)); + Toy_private_emitAstValue(bucketHandle, &thenBranch, TOY_VALUE_FROM_INTEGER(69)); + Toy_private_emitAstValue(bucketHandle, &elseBranch, TOY_VALUE_FROM_INTEGER(420)); + + Toy_private_emitAstIfThenElse(bucketHandle, &ast, condBranch, thenBranch, elseBranch); + + //check if it worked + if ( + ast == NULL || + ast->type != TOY_AST_IF_THEN_ELSE || + ast->ifThenElse.condBranch == NULL || + ast->ifThenElse.condBranch->type != TOY_AST_VALUE || + TOY_VALUE_IS_INTEGER(ast->ifThenElse.condBranch->value.value) != true || + TOY_VALUE_AS_INTEGER(ast->ifThenElse.condBranch->value.value) != 42 || + + ast->ifThenElse.thenBranch == NULL || + ast->ifThenElse.thenBranch->type != TOY_AST_VALUE || + TOY_VALUE_IS_INTEGER(ast->ifThenElse.thenBranch->value.value) != true || + TOY_VALUE_AS_INTEGER(ast->ifThenElse.thenBranch->value.value) != 69 || + + ast->ifThenElse.elseBranch == NULL || + ast->ifThenElse.elseBranch->type != TOY_AST_VALUE || + TOY_VALUE_IS_INTEGER(ast->ifThenElse.elseBranch->value.value) != true || + TOY_VALUE_AS_INTEGER(ast->ifThenElse.elseBranch->value.value) != 420 || + + false) + { + fprintf(stderr, TOY_CC_ERROR "ERROR: failed to emit a keyword 'if-then-else' as 'Toy_Ast', state unknown\n" TOY_CC_RESET); + return -1; + } + } + //emit keyword print { //build the AST diff --git a/tests/cases/test_parser.c b/tests/cases/test_parser.c index 4aa5371..790ce18 100644 --- a/tests/cases/test_parser.c +++ b/tests/cases/test_parser.c @@ -456,7 +456,168 @@ int test_binary(Toy_Bucket** bucketHandle) { } int test_compound(Toy_Bucket** bucketHandle) { - //TODO: fix test_compound() + //TODO: implement test_compound() + return 0; +} + +int test_keywords(Toy_Bucket** bucketHandle) { + //test assert + { + char* source = "assert true;"; + Toy_Ast* ast = makeAstFromSource(bucketHandle, source); + + //check if it worked + if ( + ast == NULL || + ast->type != TOY_AST_BLOCK || + ast->block.child == NULL || + + ast->block.child->type != TOY_AST_ASSERT || + ast->block.child->assert.child == NULL || + ast->block.child->assert.child->type != TOY_AST_VALUE || + + TOY_VALUE_IS_BOOLEAN(ast->block.child->assert.child->value.value) == false || + TOY_VALUE_AS_BOOLEAN(ast->block.child->assert.child->value.value) != true || + + ast->block.child->assert.message != NULL) + { + fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser, source: %s\n" TOY_CC_RESET, source); + return -1; + } + } + + //test assert (with message) + { + char* source = "assert true, \"foobar\";"; + Toy_Ast* ast = makeAstFromSource(bucketHandle, source); + + //check if it worked + if ( + ast == NULL || + ast->type != TOY_AST_BLOCK || + ast->block.child == NULL || + + ast->block.child->type != TOY_AST_ASSERT || + ast->block.child->assert.child == NULL || + ast->block.child->assert.child->type != TOY_AST_VALUE || + + TOY_VALUE_IS_BOOLEAN(ast->block.child->assert.child->value.value) == false || + TOY_VALUE_AS_BOOLEAN(ast->block.child->assert.child->value.value) != true || + + ast->block.child->assert.message == NULL || + ast->block.child->assert.message->type != TOY_AST_VALUE || + TOY_VALUE_IS_STRING(ast->block.child->assert.message->value.value) == false || + TOY_VALUE_AS_STRING(ast->block.child->assert.message->value.value)->type != TOY_STRING_LEAF || + strncmp(TOY_VALUE_AS_STRING(ast->block.child->assert.message->value.value)->as.leaf.data, "foo", 3) != 0) + { + fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser, source: %s\n" TOY_CC_RESET, source); + return -1; + } + } + + //test print (tested first, to I can use it later) + { + char* source = "print \"foo\";"; + Toy_Ast* ast = makeAstFromSource(bucketHandle, source); + + //check if it worked + if ( + ast == NULL || + ast->type != TOY_AST_BLOCK || + ast->block.child == NULL || + + ast->block.child->type != TOY_AST_PRINT || + ast->block.child->print.child == NULL || + ast->block.child->print.child->type != TOY_AST_VALUE || + TOY_VALUE_IS_STRING(ast->block.child->print.child->value.value) == false || + TOY_VALUE_AS_STRING(ast->block.child->print.child->value.value)->type != TOY_STRING_LEAF || + strncmp(TOY_VALUE_AS_STRING(ast->block.child->print.child->value.value)->as.leaf.data, "foo", 3) != 0) + { + fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser, source: %s\n" TOY_CC_RESET, source); + return -1; + } + } + + //test if-then + { + char* source = "if (true) { print \"foo\"; }"; + Toy_Ast* ast = makeAstFromSource(bucketHandle, source); + + //check if it worked + if ( + ast == NULL || + ast->type != TOY_AST_BLOCK || + ast->block.child == NULL || + ast->block.child->type != TOY_AST_IF_THEN_ELSE || + + ast->block.child->ifThenElse.condBranch == NULL || + ast->block.child->ifThenElse.condBranch->type != TOY_AST_VALUE || + TOY_VALUE_IS_BOOLEAN(ast->block.child->ifThenElse.condBranch->value.value) == false || + TOY_VALUE_AS_BOOLEAN(ast->block.child->ifThenElse.condBranch->value.value) != true || + + ast->block.child->ifThenElse.thenBranch == NULL || + ast->block.child->ifThenElse.thenBranch->type != TOY_AST_BLOCK || + ast->block.child->ifThenElse.thenBranch->block.child == NULL || + + ast->block.child->ifThenElse.thenBranch->block.child->type != TOY_AST_PRINT || + ast->block.child->ifThenElse.thenBranch->block.child->print.child == NULL || + ast->block.child->ifThenElse.thenBranch->block.child->print.child->type != TOY_AST_VALUE || + TOY_VALUE_IS_STRING(ast->block.child->ifThenElse.thenBranch->block.child->print.child->value.value) == false || + TOY_VALUE_AS_STRING(ast->block.child->ifThenElse.thenBranch->block.child->print.child->value.value)->type != TOY_STRING_LEAF || + strncmp(TOY_VALUE_AS_STRING(ast->block.child->ifThenElse.thenBranch->block.child->print.child->value.value)->as.leaf.data, "foo", 3) != 0 || + + ast->block.child->ifThenElse.elseBranch != NULL) + { + fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser, source: %s\n" TOY_CC_RESET, source); + return -1; + } + } + + //test if-then-else + { + char* source = "if (true) { print \"foo\"; } else { print \"bar\"; }"; + Toy_Ast* ast = makeAstFromSource(bucketHandle, source); + + //check if it worked + if ( + ast == NULL || + ast->type != TOY_AST_BLOCK || + ast->block.child == NULL || + ast->block.child->type != TOY_AST_IF_THEN_ELSE || + + ast->block.child->ifThenElse.condBranch == NULL || + ast->block.child->ifThenElse.condBranch->type != TOY_AST_VALUE || + TOY_VALUE_IS_BOOLEAN(ast->block.child->ifThenElse.condBranch->value.value) == false || + TOY_VALUE_AS_BOOLEAN(ast->block.child->ifThenElse.condBranch->value.value) != true || + + ast->block.child->ifThenElse.thenBranch == NULL || + ast->block.child->ifThenElse.thenBranch->type != TOY_AST_BLOCK || + ast->block.child->ifThenElse.thenBranch->block.child == NULL || + + ast->block.child->ifThenElse.thenBranch->block.child->type != TOY_AST_PRINT || + ast->block.child->ifThenElse.thenBranch->block.child->print.child == NULL || + ast->block.child->ifThenElse.thenBranch->block.child->print.child->type != TOY_AST_VALUE || + TOY_VALUE_IS_STRING(ast->block.child->ifThenElse.thenBranch->block.child->print.child->value.value) == false || + TOY_VALUE_AS_STRING(ast->block.child->ifThenElse.thenBranch->block.child->print.child->value.value)->type != TOY_STRING_LEAF || + strncmp(TOY_VALUE_AS_STRING(ast->block.child->ifThenElse.thenBranch->block.child->print.child->value.value)->as.leaf.data, "foo", 3) != 0 || + + ast->block.child->ifThenElse.elseBranch == NULL || + ast->block.child->ifThenElse.elseBranch->type != TOY_AST_BLOCK || + ast->block.child->ifThenElse.elseBranch->block.child == NULL || + ast->block.child->ifThenElse.elseBranch->block.child->type != TOY_AST_PRINT || + ast->block.child->ifThenElse.elseBranch->block.child->print.child == NULL || + ast->block.child->ifThenElse.elseBranch->block.child->print.child->type != TOY_AST_VALUE || + TOY_VALUE_IS_STRING(ast->block.child->ifThenElse.elseBranch->block.child->print.child->value.value) == false || + TOY_VALUE_AS_STRING(ast->block.child->ifThenElse.elseBranch->block.child->print.child->value.value)->type != TOY_STRING_LEAF || + strncmp(TOY_VALUE_AS_STRING(ast->block.child->ifThenElse.elseBranch->block.child->print.child->value.value)->as.leaf.data, "bar", 3) != 0 || + + false) + { + fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser, source: %s\n" TOY_CC_RESET, source); + return -1; + } + } + return 0; } @@ -669,6 +830,16 @@ int main() { total += res; } + { + Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL); + res = test_keywords(&bucket); + Toy_freeBucket(&bucket); + if (res == 0) { + printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET); + } + total += res; + } + { Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL); res = test_precedence(&bucket); diff --git a/tests/cases/test_routine.c b/tests/cases/test_routine.c index 9dca928..4698010 100644 --- a/tests/cases/test_routine.c +++ b/tests/cases/test_routine.c @@ -719,6 +719,10 @@ int test_routine_binary(Toy_Bucket** bucketHandle) { } int test_routine_keywords(Toy_Bucket** bucketHandle) { + //TODO: implement assert + //TODO: implement if-then + //TODO: implement if-then-else + //print { //setup diff --git a/tests/cases/test_vm.c b/tests/cases/test_vm.c index 2481eba..2620c86 100644 --- a/tests/cases/test_vm.c +++ b/tests/cases/test_vm.c @@ -681,6 +681,8 @@ int main() { total += res; } + //TODO: test_ifThenElse() + { Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL); res = test_scope(&bucket); diff --git a/tests/integrations/test_keyword_if_then_else.toy b/tests/integrations/test_keyword_if_then_else.toy new file mode 100644 index 0000000..33d9144 --- /dev/null +++ b/tests/integrations/test_keyword_if_then_else.toy @@ -0,0 +1,66 @@ + +//literals +if (true) { + print "Success"; +} +else { + print "Failure"; +} + +//false literals +if (false) { + print "Failure"; +} +else { + print "Success"; +} + +//conditionals +if (1 < 2) { + print "Success"; +} +if (1 > 2) { + print "Failure"; +} + + +//variables +var a = 42; + +if (a) { + print "Success"; +} +else { + print "Failure"; +} + + +if (a == 42) { + print "Success"; +} +else { + print "Failure"; +} + +//concatenated strings +if ("foo" .. "bar" == "foobar") { + print "Success"; +} +else { + print "Failure"; +} + + +if ("foobar" == "foo" .. "bar") { + print "Success"; +} +else { + print "Failure"; +} + +if ("fizz" .. "le" == "fi" .. "zzle") { + print "Success"; +} +else { + print "Failure"; +} \ No newline at end of file