int run_tests(int argc, char **args) { memset(&test_main, 0, sizeof(test_main)); int arg; int incl_filter = 0; int excl_filter = 0; for (arg = 1; arg < argc; arg++) { if (strlen(args[arg]) == 0) continue; if (0 == strcmp("-f", args[arg])) { incl_filter = 1; continue; } if (0 == strcmp("-e", args[arg])) { excl_filter = 1; continue; } if (incl_filter) { strcpy(test_main.incl_filter, args[arg]); incl_filter = 0; } else if (excl_filter) { strcpy(test_main.excl_filter, args[arg]); excl_filter = 0; } else { printf("running tests from %s\n", args[arg]); FILE *fd = fopen(args[1], "r"); if (fd == NULL) { printf("%s not found\n", args[arg]); return -2; } test_main.spec = fd; } } DBGT("adding suites...\n"); add_suites(); DBGT("%i tests added\n", test_main.test_count); if (test_main.spec) { fclose(test_main.spec); } if (test_main.test_count == 0) { printf("No tests to run\n"); return 0; } int fd_success = open("_tests_ok", O_APPEND | O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); int fd_bad = open("_tests_fail", O_APPEND | O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); DBGT("running tests...\n"); int ok = 0; int failed = 0; int stopped = 0; test *cur_t = test_main.tests; int i = 1; while (cur_t) { cur_t->setup(cur_t); test *next_test = cur_t->_next; DBGT("TEST %i/%i : running test %s\n", i, test_main.test_count, cur_t->name); i++; int start_error_count = get_error_count(); int res = cur_t->f(cur_t); if (res == TEST_RES_OK && get_error_count() != start_error_count) { res = TEST_RES_FAIL; } cur_t->test_result = res; int fd = res == TEST_RES_OK ? fd_success : fd_bad; write(fd, cur_t->name, strlen(cur_t->name)); write(fd, "\n", 1); switch (res) { case TEST_RES_OK: ok++; printf(" .. ok\n"); break; case TEST_RES_FAIL: failed++; printf(" .. FAILED\n"); if (test_main.on_stop) test_main.on_stop(cur_t); add_res(cur_t, &test_main.failed, &test_main.failed_last); break; case TEST_RES_ASSERT: stopped++; printf(" .. ABORTED\n"); if (test_main.on_stop) test_main.on_stop(cur_t); add_res(cur_t, &test_main.stopped, &test_main.stopped_last); break; } cur_t->teardown(cur_t); free(cur_t); cur_t = next_test; } close(fd_success); close(fd_bad); DBGT("ran %i tests\n", test_main.test_count); printf("Test report, %i tests\n", test_main.test_count); printf("%i succeeded\n", ok); printf("%i failed\n", failed); dump_res(&test_main.failed); printf("%i stopped\n", stopped); dump_res(&test_main.stopped); if (ok < test_main.test_count) { printf("\nFAILED\n"); return -1; } else { printf("\nALL TESTS OK\n"); return 0; } }
ast_result_t pass_expr(ast_t** astp, pass_opt_t* options) { typecheck_t* t = &options->check; ast_t* ast = *astp; bool r = true; switch(ast_id(ast)) { case TK_NOMINAL: r = expr_nominal(options, astp); break; case TK_FVAR: case TK_FLET: case TK_PARAM: r = expr_field(options, ast); break; case TK_NEW: case TK_BE: case TK_FUN: r = expr_fun(options, ast); break; case TK_SEQ: r = expr_seq(ast); break; case TK_VAR: case TK_LET: r = expr_local(t, ast); break; case TK_BREAK: r = expr_break(t, ast); break; case TK_CONTINUE: r = expr_continue(t, ast); break; case TK_RETURN: r = expr_return(options, ast); break; case TK_IS: case TK_ISNT: r = expr_identity(options, ast); break; case TK_ASSIGN: r = expr_assign(options, ast); break; case TK_CONSUME: r = expr_consume(t, ast); break; case TK_RECOVER: r = expr_recover(ast); break; case TK_DOT: r = expr_dot(options, astp); break; case TK_TILDE: r = expr_tilde(options, astp); break; case TK_QUALIFY: r = expr_qualify(options, astp); break; case TK_CALL: r = expr_call(options, astp); break; case TK_IF: r = expr_if(options, ast); break; case TK_WHILE: r = expr_while(options, ast); break; case TK_REPEAT: r = expr_repeat(options, ast); break; case TK_TRY_NO_CHECK: case TK_TRY: r = expr_try(options, ast); break; case TK_MATCH: r = expr_match(options, ast); break; case TK_CASES: r = expr_cases(ast); break; case TK_CASE: r = expr_case(options, ast); break; case TK_TUPLE: r = expr_tuple(ast); break; case TK_ARRAY: r = expr_array(options, astp); break; case TK_REFERENCE: r = expr_reference(options, astp); break; case TK_THIS: r = expr_this(options, ast); break; case TK_TRUE: case TK_FALSE: r = expr_literal(options, ast, "Bool"); break; case TK_ERROR: r = expr_error(ast); break; case TK_COMPILER_INTRINSIC: r = expr_compiler_intrinsic(t, ast); break; case TK_POSITIONALARGS: case TK_NAMEDARGS: case TK_NAMEDARG: case TK_UPDATEARG: ast_inheritflags(ast); break; case TK_AMP: r = expr_addressof(options, ast); break; case TK_DONTCARE: r = expr_dontcare(ast); break; case TK_INT: // Integer literals can be integers or floats make_literal_type(ast); break; case TK_FLOAT: make_literal_type(ast); break; case TK_STRING: if(ast_id(ast_parent(ast)) == TK_PACKAGE) return AST_OK; r = expr_literal(options, ast, "String"); break; case TK_FFICALL: return expr_ffi(options, ast); default: {} } if(!r) { assert(get_error_count() > 0); return AST_ERROR; } // Can't use ast here, it might have changed symtab_t* symtab = ast_get_symtab(*astp); if(symtab != NULL && !symtab_check_all_defined(symtab)) return AST_ERROR; return AST_OK; }
bool expr_fun(pass_opt_t* opt, ast_t* ast) { typecheck_t* t = &opt->check; AST_GET_CHILDREN(ast, cap, id, typeparams, params, type, can_error, body); if(ast_id(body) == TK_NONE) return true; if(!coerce_literals(&body, type, opt)) return false; bool is_trait = (ast_id(t->frame->type) == TK_TRAIT) || (ast_id(t->frame->type) == TK_INTERFACE) || (ast_id((ast_t*)ast_data(ast)) == TK_TRAIT) || (ast_id((ast_t*)ast_data(ast)) == TK_INTERFACE); // Check partial functions. if(ast_id(can_error) == TK_QUESTION) { // If a partial function, check that we might actually error. ast_t* body_type = ast_type(body); if(body_type == NULL) { // An error has already occurred. assert(get_error_count() > 0); return false; } if(!is_trait && !ast_canerror(body) && (ast_id(body_type) != TK_COMPILE_INTRINSIC)) { ast_error(can_error, "function body is not partial but the function is"); return false; } } else { // If not a partial function, check that we can't error. if(ast_canerror(body)) { ast_error(can_error, "function body is partial but the function is not"); show_partiality(body); return false; } } if(!check_primitive_init(t, ast) || !check_finaliser(t, ast)) return false; switch(ast_id(ast)) { case TK_NEW: { bool ok = true; if(is_machine_word(type)) { if(!check_return_type(ast)) ok = false; } if(!check_fields_defined(ast)) ok = false; if(!check_main_create(t, ast)) ok = false; return ok; } case TK_FUN: return check_return_type(ast); default: {} } return true; }
int main(int argc, char* argv[]) { stringtab_init(); pass_opt_t opt; pass_opt_init(&opt); opt.release = true; opt.output = "."; ast_setwidth(get_width()); bool print_program_ast = false; bool print_package_ast = false; opt_state_t s; opt_init(args, &s, &argc, argv); bool ok = true; bool print_usage = false; int id; while((id = opt_next(&s)) != -1) { switch(id) { case OPT_VERSION: printf("%s\n", PONY_VERSION); return 0; case OPT_DEBUG: opt.release = false; break; case OPT_BUILDFLAG: define_build_flag(s.arg_val); break; case OPT_STRIP: opt.strip_debug = true; break; case OPT_PATHS: package_add_paths(s.arg_val); break; case OPT_OUTPUT: opt.output = s.arg_val; break; case OPT_LIBRARY: opt.library = true; break; case OPT_DOCS: opt.docs = true; break; case OPT_SAFE: if(!package_add_safe(s.arg_val)) ok = false; break; case OPT_IEEEMATH: opt.ieee_math = true; break; case OPT_CPU: opt.cpu = s.arg_val; break; case OPT_FEATURES: opt.features = s.arg_val; break; case OPT_TRIPLE: opt.triple = s.arg_val; break; case OPT_STATS: opt.print_stats = true; break; case OPT_AST: print_program_ast = true; break; case OPT_ASTPACKAGE: print_package_ast = true; break; case OPT_TRACE: parse_trace(true); break; case OPT_WIDTH: ast_setwidth(atoi(s.arg_val)); break; case OPT_IMMERR: error_set_immediate(true); break; case OPT_VERIFY: opt.verify = true; break; case OPT_FILENAMES: opt.print_filenames = true; break; case OPT_CHECKTREE: enable_check_tree(true); break; case OPT_BNF: print_grammar(false, true); return 0; case OPT_ANTLR: print_grammar(true, true); return 0; case OPT_ANTLRRAW: print_grammar(true, false); return 0; case OPT_PASSES: if(!limit_passes(&opt, s.arg_val)) { ok = false; print_usage = true; } break; default: usage(); return -1; } } for(int i = 1; i < argc; i++) { if(argv[i][0] == '-') { printf("Unrecognised option: %s\n", argv[i]); ok = false; print_usage = true; } } #ifdef PLATFORM_IS_WINDOWS opt.strip_debug = true; #endif if(!ok) { print_errors(); if(print_usage) usage(); return -1; } if(package_init(&opt)) { if(argc == 1) { ok &= compile_package(".", &opt, print_program_ast, print_package_ast); } else { for(int i = 1; i < argc; i++) ok &= compile_package(argv[i], &opt, print_program_ast, print_package_ast); } } if(!ok && get_error_count() == 0) printf("Error: internal failure not reported\n"); package_done(&opt); pass_opt_done(&opt); stringtab_done(); return ok ? 0 : -1; }