diff --git a/src/lib/builtins/basic.c b/src/lib/builtins/basic.c index 54ac6a5..7f78e09 100644 --- a/src/lib/builtins/basic.c +++ b/src/lib/builtins/basic.c @@ -383,12 +383,13 @@ void bins_basic_init(StaticMapSlot slots[]) slots[0].as_type = Object_GetTypeType(); slots[1].as_type = Object_GetNoneType(); slots[2].as_type = Object_GetIntType(); - slots[3].as_type = Object_GetFloatType(); - slots[4].as_type = Object_GetStringType(); - slots[5].as_type = Object_GetListType(); - slots[6].as_type = Object_GetMapType(); - slots[7].as_type = Object_GetFileType(); - slots[8].as_type = Object_GetDirType(); + slots[3].as_type = Object_GetBoolType(); + slots[4].as_type = Object_GetFloatType(); + slots[5].as_type = Object_GetStringType(); + slots[6].as_type = Object_GetListType(); + slots[7].as_type = Object_GetMapType(); + slots[8].as_type = Object_GetFileType(); + slots[9].as_type = Object_GetDirType(); } StaticMapSlot bins_basic[] = { @@ -396,6 +397,7 @@ StaticMapSlot bins_basic[] = { { "Type", SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ }, { "None", SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ }, { "int", SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ }, + { "bool", SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ }, { "float", SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ }, { "String", SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ }, { "List", SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ }, diff --git a/src/lib/common/executable.c b/src/lib/common/executable.c index 95dc759..918233b 100644 --- a/src/lib/common/executable.c +++ b/src/lib/common/executable.c @@ -105,9 +105,13 @@ static const InstrInfo instr_table[] = { [OPCODE_PUSHFUN] = {"PUSHFUN", 2, (OperandType[]) {OPTP_INT, OPTP_INT}}, [OPCODE_PUSHLST] = {"PUSHLST", 1, (OperandType[]) {OPTP_INT}}, [OPCODE_PUSHMAP] = {"PUSHMAP", 1, (OperandType[]) {OPTP_INT}}, + [OPCODE_PUSHTYP] = {"PUSHTYP", 0, NULL}, + [OPCODE_PUSHTYPTYP] = {"PUSHTYPTYP", 0, NULL}, [OPCODE_RETURN] = {"RETURN", 1, (OperandType[]) {OPTP_INT}}, + [OPCODE_ERROR] = {"ERROR", 1, (OperandType[]) {OPTP_STRING}}, + [OPCODE_JUMPIFNOTANDPOP] = {"JUMPIFNOTANDPOP", 1, (OperandType[]) {OPTP_INT}}, [OPCODE_JUMPIFANDPOP] = {"JUMPIFANDPOP", 1, (OperandType[]) {OPTP_INT}}, [OPCODE_JUMP] = {"JUMP", 1, (OperandType[]) {OPTP_INT}}, diff --git a/src/lib/common/executable.h b/src/lib/common/executable.h index ebf286b..63ae633 100644 --- a/src/lib/common/executable.h +++ b/src/lib/common/executable.h @@ -84,7 +84,10 @@ typedef enum { OPCODE_PUSHFUN, OPCODE_PUSHLST, OPCODE_PUSHMAP, + OPCODE_PUSHTYP, + OPCODE_PUSHTYPTYP, OPCODE_RETURN, + OPCODE_ERROR, OPCODE_JUMPIFANDPOP, OPCODE_JUMPIFNOTANDPOP, OPCODE_JUMP, diff --git a/src/lib/compiler/ASTi.h b/src/lib/compiler/ASTi.h index 194ae81..de5ee4b 100644 --- a/src/lib/compiler/ASTi.h +++ b/src/lib/compiler/ASTi.h @@ -192,5 +192,7 @@ typedef struct { typedef struct { Node base; char *name; + int typec; + Node *typev; } ArgumentNode; #endif \ No newline at end of file diff --git a/src/lib/compiler/codegen.c b/src/lib/compiler/codegen.c index ddac83a..af5a24d 100644 --- a/src/lib/compiler/codegen.c +++ b/src/lib/compiler/codegen.c @@ -124,6 +124,19 @@ static void emitInstr_JUMPIFANDPOP_2(CodegenContext *ctx, CodegenContext_EmitInstr(ctx, OPCODE_JUMPIFANDPOP, opv, 1, off, len); } +static void emitInstr_EQL(CodegenContext *ctx, int off, int len) +{ + CodegenContext_EmitInstr(ctx, OPCODE_EQL, NULL, 0, off, len); +} + +static void emitInstr_ERROR(CodegenContext *ctx, const char *msg, int off, int len) +{ + Operand opv[1] = { + { .type = OPTP_STRING, .as_string = msg }, + }; + CodegenContext_EmitInstr(ctx, OPCODE_ERROR, opv, 1, off, len); +} + static void emitInstr_PUSHTRU(CodegenContext *ctx, int off, int len) { CodegenContext_EmitInstr(ctx, OPCODE_PUSHTRU, NULL, 0, off, len); @@ -134,6 +147,16 @@ static void emitInstr_PUSHFLS(CodegenContext *ctx, int off, int len) CodegenContext_EmitInstr(ctx, OPCODE_PUSHFLS, NULL, 0, off, len); } +static void emitInstr_PUSHTYP(CodegenContext *ctx, int off, int len) +{ + CodegenContext_EmitInstr(ctx, OPCODE_PUSHTYP, NULL, 0, off, len); +} + +static void emitInstr_PUSHTYPTYP(CodegenContext *ctx, int off, int len) +{ + CodegenContext_EmitInstr(ctx, OPCODE_PUSHTYPTYP, NULL, 0, off, len); +} + static void emitInstrForNode(CodegenContext *ctx, Node *node, Label *label_break); static Opcode exprkind_to_opcode(ExprKind kind) @@ -182,6 +205,103 @@ static void emitInstrForFuncCallNode(CodegenContext *ctx, CallExprNode *expr, CodegenContext_EmitInstr(ctx, OPCODE_CALL, ops, 2, expr->base.base.offset, expr->base.base.length); } +static void emitInstrForArgumentNode(CodegenContext *ctx, ArgumentNode *arg, int argidx) +{ + /* + * PUSHTYP; + * // What if this isn't a type? + * PUSHTYP; + * PUSHTYPTYP; + * EQL; + * JUMPIFANDPOP argument_annotation_0_not_type; + * EQL; + * JUMPIFANDPOP argument_type_ok; + * + * PUSHTYP; + * + * PUSHTYP; + * PUSHTYPTYP; + * EQL; + * JUMPIFANDPOP argument_annotation_1_not_type; + * EQL; + * JUMPIFANDPOP argument_type_ok; + * + * PUSHTYP; + * + * PUSHTYP; + * PUSHTYPTYP; + * EQL; + * JUMPIFANDPOP argument_annotation_2_not_type; + * EQL; + * JUMPIFANDPOP argument_type_ok; + * + * ERROR "Bad type of argument N"; + * argument_annotation_0_not_a_type: + * ERROR "Argument N annotation M isn't a type"; + * argument_type_ok: + * ASS ; + * POP 1; + */ + + if(arg->typev != NULL) { + + /* Emit checks for the argument type */ + + Node *typev = arg->typev; + int typec = arg->typec; + assert(typec > 0); + + Label *maybe[8]; + Label **label_annotation_not_a_type; + if((size_t) typec > sizeof(maybe)/sizeof(maybe[0])) { + label_annotation_not_a_type = malloc(typec * sizeof(Label*)); + if(label_annotation_not_a_type == NULL) + CodegenContext_ReportErrorAndJump(ctx, 1, "No memory"); + } else + label_annotation_not_a_type = maybe; + + for(int i = 0; i < typec; i += 1) + label_annotation_not_a_type[i] = Label_New(ctx); + + Label *label_argument_type_ok = Label_New(ctx); + + Node *type = typev; + for(int i = 0; i < typec; i += 1) { + assert(type != NULL); + emitInstr_PUSHTYP(ctx, arg->base.offset, arg->base.length); // The source slice should refer only to the name label, not the whole operand + emitInstrForNode(ctx, type, NULL); + { + emitInstr_PUSHTYP(ctx, type->offset, type->length); + emitInstr_PUSHTYPTYP(ctx, type->offset, type->length); + emitInstr_EQL(ctx, type->offset, type->length); + emitInstr_JUMPIFNOTANDPOP(ctx, label_annotation_not_a_type[i], type->offset, type->length); + } + emitInstr_EQL(ctx, type->offset, type->length); + emitInstr_JUMPIFANDPOP_2(ctx, label_argument_type_ok, type->offset, type->length); + type = type->next; + } + + char msg[256]; + snprintf(msg, sizeof(msg), "Bad type for argument %d", argidx); + emitInstr_ERROR(ctx, msg, arg->base.offset, arg->base.length); + for(int i = 0; i < typec; i += 1) { + Label_SetHere(label_annotation_not_a_type[i], ctx); + snprintf(msg, sizeof(msg), "Argument %d type annotation %d is not a type", argidx, i); + emitInstr_ERROR(ctx, msg, arg->base.offset, arg->base.length); + } + + Label_SetHere(label_argument_type_ok, ctx); + + Label_Free(label_argument_type_ok); + for(int i = 0; i < typec; i += 1) + Label_Free(label_annotation_not_a_type[i]); + if(label_annotation_not_a_type != maybe) + free(label_annotation_not_a_type); + } + emitInstr_ASS(ctx, arg->name, arg->base.offset, arg->base.length); + emitInstr_POP1(ctx, arg->base.offset, arg->base.length); +} + static void emitInstrForFuncNode(CodegenContext *ctx, FunctionNode *func) { Label *label_func = Label_New(ctx); @@ -204,11 +324,12 @@ static void emitInstrForFuncNode(CodegenContext *ctx, FunctionNode *func) { // Assign the arguments. ArgumentNode *arg = (ArgumentNode*) func->argv; + int argidx = func->argc-1; while(arg) { - emitInstr_ASS(ctx, arg->name, arg->base.offset, arg->base.length); - emitInstr_POP1(ctx, arg->base.offset, arg->base.length); + emitInstrForArgumentNode(ctx, arg, argidx); arg = (ArgumentNode*) arg->base.next; + argidx -= 1; } emitInstrForNode(ctx, func->body, NULL); @@ -539,7 +660,7 @@ static void emitInstrForWhileLoopNode(CodegenContext *ctx, WhileNode *loop, Labe /* * start: * - * JUMPIFNOTANDPOP end + * JUMPIFNOTANDPOP end * * JUMP start * end: @@ -673,19 +794,26 @@ Executable *codegen(AST *ast, BPAlloc *alloc, Error *error) assert(ast != NULL); assert(error != NULL); + jmp_buf env; + CodegenContext *ctx = CodegenContext_New(error, alloc); if(ctx == NULL) { Error_Report(error, 1, "No memory"); return NULL; } - bool jumped = CodegenContext_SetOrCatchJump(ctx); - if(jumped) { + if(setjmp(env)) { + assert(error->occurred == true); CodegenContext_Free(ctx); return NULL; } + assert(error->occurred == false); + CodegenContext_SetJumpDest(ctx, &env); + emitInstrForNode(ctx, ast->root, NULL); emitInstr_RETURN(ctx, 0, Source_GetSize(ast->src), 0); + assert(error->occurred == false); + return CodegenContext_MakeExecutableAndFree(ctx, ast->src); } diff --git a/src/lib/compiler/codegenctx.c b/src/lib/compiler/codegenctx.c index 7426184..ff5758d 100644 --- a/src/lib/compiler/codegenctx.c +++ b/src/lib/compiler/codegenctx.c @@ -1,4 +1,3 @@ -#include #include #include "../utils/defs.h" #include "codegenctx.h" @@ -8,7 +7,8 @@ struct CodegenContext { BPAlloc *alloc; ExeBuilder *builder; bool own_alloc; - jmp_buf env; + bool env_set; + jmp_buf *env; }; Label *Label_New(CodegenContext *ctx) @@ -48,7 +48,9 @@ Promise *Label_ToPromise(Label *label) static void okNowJump(CodegenContext *ctx) { - longjmp(ctx->env, 1); + assert(ctx->env_set == true); + longjmp(*ctx->env, 1); + UNREACHABLE; } void CodegenContext_ReportErrorAndJump_(CodegenContext *ctx, const char *file, @@ -61,12 +63,14 @@ void CodegenContext_ReportErrorAndJump_(CodegenContext *ctx, const char *file, va_end(args); okNowJump(ctx); + UNREACHABLE; } -_Bool CodegenContext_SetOrCatchJump(CodegenContext *ctx) +void CodegenContext_SetJumpDest(CodegenContext *ctx, jmp_buf *env) { - bool jumped = setjmp(ctx->env); - return jumped; + assert(ctx->env_set == false); + ctx->env = env; + ctx->env_set = true; } CodegenContext *CodegenContext_New(Error *error, BPAlloc *alloc) @@ -101,6 +105,7 @@ CodegenContext *CodegenContext_New(Error *error, BPAlloc *alloc) ctx->error = error; ctx->alloc = alloc; ctx->builder = builder; + ctx->env_set = false; ctx->own_alloc = own_alloc; return ctx; } @@ -120,8 +125,10 @@ void CodegenContext_Free(CodegenContext *ctx) Executable *CodegenContext_MakeExecutableAndFree(CodegenContext *ctx, Source *src) { Executable *exe = ExeBuilder_Finalize(ctx->builder, ctx->error); - if(exe == NULL) + if(exe == NULL) { okNowJump(ctx); + UNREACHABLE; + } if(src != NULL) Executable_SetSource(exe, src); @@ -132,6 +139,8 @@ Executable *CodegenContext_MakeExecutableAndFree(CodegenContext *ctx, Source *sr void CodegenContext_EmitInstr(CodegenContext *ctx, Opcode opcode, Operand *opv, int opc, int off, int len) { - if(!ExeBuilder_Append(ctx->builder, ctx->error, opcode, opv, opc, off, len)) + if(!ExeBuilder_Append(ctx->builder, ctx->error, opcode, opv, opc, off, len)) { okNowJump(ctx); + UNREACHABLE; + } } diff --git a/src/lib/compiler/codegenctx.h b/src/lib/compiler/codegenctx.h index 3b19350..d12b1d4 100644 --- a/src/lib/compiler/codegenctx.h +++ b/src/lib/compiler/codegenctx.h @@ -1,11 +1,12 @@ #ifndef CODEGENCTX_H #define CODEGENCTX_H +#include #include "../common/executable.h" typedef struct CodegenContext CodegenContext; CodegenContext *CodegenContext_New(Error *error, BPAlloc *alloc); void CodegenContext_EmitInstr(CodegenContext *ctx, Opcode opcode, Operand *opv, int opc, int off, int len); -_Bool CodegenContext_SetOrCatchJump(CodegenContext *ctx); +void CodegenContext_SetJumpDest(CodegenContext *ctx, jmp_buf *env); void CodegenContext_Free(CodegenContext *ctx); Executable *CodegenContext_MakeExecutableAndFree(CodegenContext *ctx, Source *src); void CodegenContext_ReportErrorAndJump_(CodegenContext *ctx, const char *file, const char *func, int line, bool internal, const char *format, ...); diff --git a/src/lib/compiler/parse.c b/src/lib/compiler/parse.c index 4640927..797c457 100644 --- a/src/lib/compiler/parse.c +++ b/src/lib/compiler/parse.c @@ -469,7 +469,6 @@ static inline TokenKind current(Context *ctx) // Compile with -DDEBUG to get debugging messages printed to stderr. #ifdef DEBUG - #include static inline TokenKind next(Context *ctx, const char *file, int line) @@ -501,6 +500,22 @@ static inline TokenKind prev(Context *ctx) #define next(ctx) next(ctx, __FILE__, __LINE__) +static void Error_Report_(Error *error, const char *file, const char *func, int line, _Bool internal, const char *fmt, ...) +{ + fprintf(stderr, "Reporting error at %s:%d (in %s)\n", file, line, func); + + va_list args; + va_start(args, fmt); + _Error_Report2(error, internal, file, func, line, fmt, args); + va_end(args); +} + +#ifdef Error_Report +#undef Error_Report +#endif + +#define Error_Report(error, internal, fmt, ...) Error_Report_(error, __FILE__, __func__, __LINE__, internal, fmt, ## __VA_ARGS__) + #else static inline TokenKind next(Context *ctx) @@ -1850,40 +1865,9 @@ static Node *parse_compound_statement(Context *ctx, TokenKind end) return (Node*) node; } -static Node *parse_function_definition(Context *ctx) +static Node *parse_function_arguments(Context *ctx, int *argc_) { - assert(ctx != NULL); - - if(done(ctx)) - { - Error_Report(ctx->error, 0, "Source ended where a function definition was expected"); - return NULL; - } - - if(current(ctx) != TKWFUN) - { - Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where a function definition was expected", ctx->token->length, ctx->src + ctx->token->offset); - return NULL; - } - - int offset = current_token(ctx)->offset; - - if(next(ctx) != TIDENT) - { - if(done(ctx)) - Error_Report(ctx->error, 0, "Source ended where an identifier was expected as function name"); - else - Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where an identifier was expected as function name", ctx->token->length, ctx->src + ctx->token->offset); - return NULL; - } - - char *name = copy_token_text(ctx); - - if(name == NULL) - { - Error_Report(ctx->error, 1, "No memory"); - return NULL; - } +#warning "What if the source ends here?" if(next(ctx) != '(') { @@ -1923,6 +1907,30 @@ static Node *parse_function_definition(Context *ctx) return NULL; } + int typec; + Node *typev = NULL; + + if(next(ctx) == ':') { + next(ctx); // Skip the ':'. + + Node *type = parse_expression(ctx, 0); + if(type == NULL) + return NULL; + typev = type; + typec = 1; + Node *tail = type; + while(current(ctx) == '|') { + next(ctx); + type = parse_expression(ctx, 0); + if(type == NULL) + return NULL; + tail->next = type; + tail = type; + typec += 1; + } + } else + typec = 0; + ArgumentNode *arg; { // Make argument node. @@ -1939,6 +1947,8 @@ static Node *parse_function_definition(Context *ctx) arg->base.offset = current_token(ctx)->offset; arg->base.length = current_token(ctx)->length; arg->name = arg_name; + arg->typev = typev; + arg->typec = typec; } // Add it to the list. @@ -1946,10 +1956,7 @@ static Node *parse_function_definition(Context *ctx) arg->base.next = argv; argv = (Node*) arg; - // Get either ',' or ')'. - - if(next(ctx) == ')') - break; + // Expect either ',' or ')'. if(done(ctx)) { @@ -1957,6 +1964,9 @@ static Node *parse_function_definition(Context *ctx) return NULL; } + if(current(ctx) == ')') + break; + if(current(ctx) != ',') { Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" inside function argument list, where either ',' or ')' were expected", ctx->token->length, ctx->src + ctx->token->offset); @@ -1970,6 +1980,50 @@ static Node *parse_function_definition(Context *ctx) next(ctx); // Consume the ')'. + if(argc_ != NULL) + *argc_ = argc; + + return argv; +} + +static Node *parse_function_definition(Context *ctx) +{ + assert(ctx != NULL); + + if(done(ctx)) + { + Error_Report(ctx->error, 0, "Source ended where a function definition was expected"); + return NULL; + } + + if(current(ctx) != TKWFUN) + { + Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where a function definition was expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } + + int offset = current_token(ctx)->offset; + + if(next(ctx) != TIDENT) + { + if(done(ctx)) + Error_Report(ctx->error, 0, "Source ended where an identifier was expected as function name"); + else + Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where an identifier was expected as function name", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } + + char *name = copy_token_text(ctx); + + if(name == NULL) + { + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } + + int argc = 0; // Initialization for the warning. + Node *argv = parse_function_arguments(ctx, &argc); + if(done(ctx)) { Error_Report(ctx->error, 0, "Source ended before function body"); diff --git a/src/lib/noja.c b/src/lib/noja.c index 8b423a3..b8a42e2 100644 --- a/src/lib/noja.c +++ b/src/lib/noja.c @@ -139,7 +139,10 @@ static _Bool interpret_file(const char *file) } Executable *exe = compile_source_and_print_error_on_failure(src); - if(exe == NULL) return 0; + if(exe == NULL) { + Source_Free(src); + return 0; + } _Bool r = interpret(exe); @@ -164,7 +167,10 @@ static _Bool interpret_code(const char *code) } Executable *exe = compile_source_and_print_error_on_failure(src); - if(exe == NULL) return 0; + if(exe == NULL) { + Source_Free(src); + return 0; + } _Bool r = interpret(exe); diff --git a/src/lib/runtime/runtime.c b/src/lib/runtime/runtime.c index bf4e6be..dd8c4f9 100644 --- a/src/lib/runtime/runtime.c +++ b/src/lib/runtime/runtime.c @@ -1147,6 +1147,39 @@ static _Bool step(Runtime *runtime, Error *error) return 1; } + case OPCODE_PUSHTYPTYP: + { + assert(opc == 0); + + Object *obj = (Object*) Object_GetTypeType(); + assert(obj != NULL); + + if(!Runtime_Push(runtime, error, obj)) + return 0; + return 1; + } + + case OPCODE_PUSHTYP: + { + assert(opc == 0); + + if(runtime->frame->used < 1) + { + Error_Report(error, 1, "Frame has not enough values on the stack to run PUSHTYP instruction"); + return 0; + } + + Object *top = Stack_Top(runtime->stack, 0); + assert(top != NULL); + + Object *typ = (Object*) Object_GetType(top); + assert(typ != NULL); + + if(!Runtime_Push(runtime, error, typ)) + return 0; + return 1; + } + case OPCODE_RETURN: { assert(opc == 1); @@ -1157,6 +1190,15 @@ static _Bool step(Runtime *runtime, Error *error) return 0; } + case OPCODE_ERROR: + { + assert(opc == 1); + assert(ops[0].type == OPTP_STRING); + const char *msg = ops[0].as_string; + Error_Report(error, 0, "%s", msg); + return 0; + } + case OPCODE_JUMP: assert(opc == 1); assert(ops[0].type == OPTP_INT); diff --git a/src/lib/utils/error.c b/src/lib/utils/error.c index 6949ca7..51d11f2 100644 --- a/src/lib/utils/error.c +++ b/src/lib/utils/error.c @@ -71,6 +71,12 @@ void _Error_Report2(Error *err, _Bool internal, assert(func); assert(line > 0); assert(fmt); + +#ifdef DEBUG + if(err->occurred != 0) { + fprintf(stderr, "Error previously reported at %s:%d (in %s) :: %s\n", err->file, err->line, err->func, err->message); + } +#endif assert(err->occurred == 0); err->occurred = 1; diff --git a/tests/suite/Testcase_011_003 b/tests/suite/Testcase_011_003 index b05450f..e8b159b 100644 --- a/tests/suite/Testcase_011_003 +++ b/tests/suite/Testcase_011_003 @@ -1,24 +1,20 @@ #source - fun add(a, b) { - return a + b; + fun nop(a) { + return a; } #bytecode - PUSHFUN fun, 2; - ASS "add"; + PUSHFUN fun, 1; + ASS "nop"; POP 1; JUMP end; fun: - ASS "b"; - POP 1; ASS "a"; POP 1; PUSHVAR "a"; - PUSHVAR "b"; - ADD; RETURN 1; RETURN 0; end: diff --git a/tests/suite/Testcase_011_004 b/tests/suite/Testcase_011_004 new file mode 100644 index 0000000..b05450f --- /dev/null +++ b/tests/suite/Testcase_011_004 @@ -0,0 +1,25 @@ + +#source + + fun add(a, b) { + return a + b; + } + +#bytecode + + PUSHFUN fun, 2; + ASS "add"; + POP 1; + JUMP end; +fun: + ASS "b"; + POP 1; + ASS "a"; + POP 1; + PUSHVAR "a"; + PUSHVAR "b"; + ADD; + RETURN 1; + RETURN 0; +end: + RETURN 0; \ No newline at end of file diff --git a/tests/suite/Testcase_011_005 b/tests/suite/Testcase_011_005 new file mode 100644 index 0000000..cda18fd --- /dev/null +++ b/tests/suite/Testcase_011_005 @@ -0,0 +1,33 @@ + +#source + + fun nop(a: None) { + return a; + } + +#bytecode + + PUSHFUN fun, 1; + ASS "nop"; + POP 1; + JUMP end; +fun: + PUSHTYP; + PUSHVAR "None"; + PUSHTYP; + PUSHTYPTYP; + EQL; + JUMPIFNOTANDPOP arg_annot_not_type; + EQL; + JUMPIFANDPOP arg_ok; + ERROR "Bad type for argument 0"; +arg_annot_not_type: + ERROR "Argument 0 type annotation 0 is not a type"; +arg_ok: + ASS "a"; + POP 1; + PUSHVAR "a"; + RETURN 1; + RETURN 0; +end: + RETURN 0; \ No newline at end of file diff --git a/tests/suite/Testcase_011_006 b/tests/suite/Testcase_011_006 new file mode 100644 index 0000000..ab5104c --- /dev/null +++ b/tests/suite/Testcase_011_006 @@ -0,0 +1,37 @@ + +#source + + fun add(a: int, b) { + return a + b; + } + +#bytecode + + PUSHFUN fun, 2; + ASS "add"; + POP 1; + JUMP end; +fun: + ASS "b"; + POP 1; + PUSHTYP; + PUSHVAR "int"; + PUSHTYP; + PUSHTYPTYP; + EQL; + JUMPIFNOTANDPOP arg0_annot0_bad; + EQL; + JUMPIFANDPOP arg_ok; + ERROR "Bad type for argument 0"; +arg0_annot0_bad: + ERROR "Argument 0 type annotation 0 is not a type"; +arg_ok: + ASS "a"; + POP 1; + PUSHVAR "a"; + PUSHVAR "b"; + ADD; + RETURN 1; + RETURN 0; +end: + RETURN 0; \ No newline at end of file diff --git a/tests/suite/Testcase_011_007 b/tests/suite/Testcase_011_007 new file mode 100644 index 0000000..2c61c53 --- /dev/null +++ b/tests/suite/Testcase_011_007 @@ -0,0 +1,37 @@ + +#source + + fun add(a, b: int) { + return a + b; + } + +#bytecode + + PUSHFUN fun, 2; + ASS "add"; + POP 1; + JUMP end; +fun: + PUSHTYP; + PUSHVAR "int"; + PUSHTYP; + PUSHTYPTYP; + EQL; + JUMPIFNOTANDPOP annot_bad; + EQL; + JUMPIFANDPOP arg_ok; + ERROR "Bad type for argument 1"; +annot_bad: + ERROR "Argument 1 type annotation 0 is not a type"; +arg_ok: + ASS "b"; + POP 1; + ASS "a"; + POP 1; + PUSHVAR "a"; + PUSHVAR "b"; + ADD; + RETURN 1; + RETURN 0; +end: + RETURN 0; \ No newline at end of file diff --git a/tests/suite/Testcase_011_008 b/tests/suite/Testcase_011_008 new file mode 100644 index 0000000..697af3e --- /dev/null +++ b/tests/suite/Testcase_011_008 @@ -0,0 +1,49 @@ + +#source + + fun add(a: int, b: int) { + return a + b; + } + +#bytecode + + PUSHFUN fun, 2; + ASS "add"; + POP 1; + JUMP end; +fun: + PUSHTYP; + PUSHVAR "int"; + PUSHTYP; + PUSHTYPTYP; + EQL; + JUMPIFNOTANDPOP arg1_annot0_not_type; + EQL; + JUMPIFANDPOP arg1_ok; + ERROR "Bad type for argument 1"; +arg1_annot0_not_type: + ERROR "Argument 1 type annotation 0 is not a type"; +arg1_ok: + ASS "b"; + POP 1; + PUSHTYP; + PUSHVAR "int"; + PUSHTYP; + PUSHTYPTYP; + EQL; + JUMPIFNOTANDPOP arg0_annot0_not_type; + EQL; + JUMPIFANDPOP arg0_ok; + ERROR "Bad type for argument 0"; +arg0_annot0_not_type: + ERROR "Argument 0 type annotation 0 is not a type"; +arg0_ok: + ASS "a"; + POP 1; + PUSHVAR "a"; + PUSHVAR "b"; + ADD; + RETURN 1; + RETURN 0; +end: + RETURN 0; \ No newline at end of file diff --git a/tests/suite/Testcase_011_009 b/tests/suite/Testcase_011_009 new file mode 100644 index 0000000..1140f64 --- /dev/null +++ b/tests/suite/Testcase_011_009 @@ -0,0 +1,69 @@ + +#source + + fun add(a: int | float, b: bool | Map) { + return a + b; + } + +#bytecode + + PUSHFUN fun, 2; + ASS "add"; + POP 1; + JUMP end; +fun: + PUSHTYP; + PUSHVAR "bool"; + PUSHTYP; + PUSHTYPTYP; + EQL; + JUMPIFNOTANDPOP arg1_annot0_bad; + EQL; + JUMPIFANDPOP arg1_ok; + PUSHTYP; + PUSHVAR "Map"; + PUSHTYP; + PUSHTYPTYP; + EQL; + JUMPIFNOTANDPOP arg1_annot1_bad; + EQL; + JUMPIFANDPOP arg1_ok; + ERROR "Bad type for argument 1"; +arg1_annot0_bad: + ERROR "Argument 1 type annotation 0 is not a type"; +arg1_annot1_bad: + ERROR "Argument 1 type annotation 1 is not a type"; +arg1_ok: + ASS "b"; + POP 1; + PUSHTYP; + PUSHVAR "int"; + PUSHTYP; + PUSHTYPTYP; + EQL; + JUMPIFNOTANDPOP arg0_annot0_bad; + EQL; + JUMPIFANDPOP arg0_ok; + PUSHTYP; + PUSHVAR "float"; + PUSHTYP; + PUSHTYPTYP; + EQL; + JUMPIFNOTANDPOP arg0_annot1_bad; + EQL; + JUMPIFANDPOP arg0_ok; + ERROR "Bad type for argument 0"; +arg0_annot0_bad: + ERROR "Argument 0 type annotation 0 is not a type"; +arg0_annot1_bad: + ERROR "Argument 0 type annotation 1 is not a type"; +arg0_ok: + ASS "a"; + POP 1; + PUSHVAR "a"; + PUSHVAR "b"; + ADD; + RETURN 1; + RETURN 0; +end: + RETURN 0; \ No newline at end of file