diff --git a/include/kinx.h b/include/kinx.h index 3021d6010..827370b72 100644 --- a/include/kinx.h +++ b/include/kinx.h @@ -31,8 +31,9 @@ typedef struct kx_lexinfo_ { int is_trim; kx_lexinner_t inner; kx_yyin_t in; - int tempbuf[16]; + const char *pkgkey; const int *restart; + int tempbuf[16]; } kx_lexinfo_t; kvec_init_t(kx_lexinfo_t); diff --git a/include/kxastobject.h b/include/kxastobject.h index 9588932a2..06effb634 100644 --- a/include/kxastobject.h +++ b/include/kxastobject.h @@ -34,6 +34,7 @@ extern kx_object_t *kx_gen_str_object_pos(name_t name); extern const char *kx_gen_constant_string(const char *name); extern const char *kx_check_the_name(kx_object_t *obj); extern kx_object_t *kx_gen_stmtlist(kx_object_t *lhs, kx_object_t *rhs); +extern kx_object_t *kx_gen_exprlist(kx_object_t *lhs, kx_object_t *rhs); extern kx_object_t *kx_gen_range_object(kx_object_t *start, kx_object_t *end, int include_end); extern kx_object_t *kx_gen_case_when_object(kx_object_t *decl, kx_object_t *expr, kx_object_t *modifier); extern kx_object_t *kx_gen_forin_object(kx_object_t *var, kx_object_t *range, kx_object_t *stmt, int is_decl); diff --git a/include/parser.h b/include/parser.h index cef129b9d..1a888a53b 100644 --- a/include/parser.h +++ b/include/parser.h @@ -4,6 +4,13 @@ #include #include +#include + +typedef struct package_t_ { + const char *vers; + struct package_t_ *next; +} package_t; +KHASH_MAP_INIT_STR(package, package_t *) typedef struct name_t_ { const char *name; @@ -11,11 +18,13 @@ typedef struct name_t_ { int pos1; int pos2; } name_t; + typedef struct arytype_t_ { int type; int depth; const char *name; /* class name */ } arytype_t; + typedef struct named_stmt_ { const char *name; /* class name */ kx_object_t *stmt; diff --git a/src/ast_analyzer.c b/src/ast_analyzer.c index 00f6bbb6b..79e621a35 100644 --- a/src/ast_analyzer.c +++ b/src/ast_analyzer.c @@ -1477,7 +1477,8 @@ LOOP_HEAD:; case KXST_EXPRSEQ: /* lhs: expr1: rhs: expr2 */ case KXST_EXPRLIST: /* lhs: expr1: rhs: expr2 */ analyze_ast(ctx, node->lhs, actx); - analyze_ast(ctx, node->rhs, actx); + node = node->rhs; + if (node) goto LOOP_HEAD; break; case KXST_STMTLIST: /* lhs: stmt2: rhs: stmt1 */ analyze_ast(ctx, node->lhs, actx); diff --git a/src/ast_defdisp.c b/src/ast_defdisp.c index 2b3c99781..7acde0bd4 100644 --- a/src/ast_defdisp.c +++ b/src/ast_defdisp.c @@ -555,7 +555,8 @@ LOOP_HEAD:; break; case KXST_EXPRLIST: /* lhs: expr1: rhs: expr2 */ display_def_ast(dctx, node->lhs, lvalue); - display_def_ast(dctx, node->rhs, lvalue); + node = node->rhs; + if (node) goto LOOP_HEAD; break; case KXST_STMTLIST: /* lhs: stmt1: rhs: stmt2 */ display_def_ast(dctx, node->lhs, lvalue); diff --git a/src/ast_display.c b/src/ast_display.c index e97eecfe6..0c53ed89d 100644 --- a/src/ast_display.c +++ b/src/ast_display.c @@ -399,7 +399,8 @@ LOOP_HEAD:; break; case KXST_EXPRLIST: /* lhs: expr1: rhs: expr2 */ display_ast(node->lhs, indent, lvalue); - display_ast(node->rhs, indent, lvalue); + node = node->rhs; + if (node) goto LOOP_HEAD; break; case KXST_STMTLIST: /* lhs: stmt1: rhs: stmt2 */ display_ast(node->lhs, indent, 0); diff --git a/src/ast_gencode.c b/src/ast_gencode.c index 87482de67..7a3763023 100644 --- a/src/ast_gencode.c +++ b/src/ast_gencode.c @@ -1099,6 +1099,7 @@ static void gencode_ast(kx_context_t *ctx, kx_object_t *node, kx_analyze_t *ana, } LOOP_HEAD:; +// printf("%s:%d, node->type = %d (%s:%d)\n", __FILE__, __LINE__, node->type, node->file, node->line); kx_module_t *module = ana->module; switch (node->type) { case KXVL_UNKNOWN: @@ -1994,9 +1995,8 @@ LOOP_HEAD:; } case KXST_EXPRLIST: { /* lhs: expr1: rhs: expr2 */ gencode_ast_hook(ctx, node->lhs, ana, 0); - if (node->rhs) { - gencode_ast_hook(ctx, node->rhs, ana, 0); - } + node = node->rhs; + if (node) goto LOOP_HEAD; break; } case KXST_STMTLIST: { /* lhs: stmt1: rhs: stmt2 */ diff --git a/src/ast_object.c b/src/ast_object.c index ceaaabba0..8415c1aee 100644 --- a/src/ast_object.c +++ b/src/ast_object.c @@ -257,6 +257,22 @@ kx_object_t *kx_gen_stmtlist(kx_object_t *lhs, kx_object_t *rhs) return lhs; } +kx_object_t *kx_gen_exprlist(kx_object_t *lhs, kx_object_t *rhs) +{ + if (!lhs) { + return rhs; + } + if (lhs->type != KXST_EXPRLIST) { + return kx_gen_bexpr_object(KXST_EXPRLIST, lhs, rhs); + } + kx_object_t *node = lhs->ex ? lhs->ex : lhs; + while (node->rhs && node->rhs->type == KXST_EXPRLIST) { + node = node->rhs; + } + lhs->ex = node->rhs = kx_gen_bexpr_object(KXST_EXPRLIST, node->rhs, rhs); + return lhs; +} + kx_object_t *kx_gen_range_object(kx_object_t *lhs, kx_object_t *end, int exclude_end) { return kx_gen_obj(KXOP_MKRANGE, exclude_end, lhs, end, NULL); @@ -690,9 +706,6 @@ static kx_object_t *kx_gen_func_object_impl(int type, int optional, arytype_t *r } } kx_object_t *obj = kx_gen_obj(type, (type != KXST_NATIVE) ? optional : KXFT_ANONYMOUS, lhs, rhs, ex); - if (inherit) { - obj->typename = inherit; - } obj->line2 = obj->line; if (line > 0) { obj->line = line; diff --git a/src/global.c b/src/global.c index 7a0072dae..99c14be62 100644 --- a/src/global.c +++ b/src/global.c @@ -1,6 +1,9 @@ #include #include +#include #include +#define KX_NO_INCLUDE_PARSER_TAB_H +#include /* used in parsing, parsing phase is not reentrant. */ kx_lexinfo_t kx_lexinfo = {0}; @@ -10,6 +13,7 @@ kx_object_t *kx_ast_root = NULL; int g_yyerror = 0; int g_yywarning = 0; kx_context_t *g_parse_ctx = NULL; +khash_t(package) *g_packages; /* used in runtime. */ volatile int g_terminated = 0; diff --git a/src/kinx.y b/src/kinx.y index 72af82c8b..f87cd2f73 100644 --- a/src/kinx.y +++ b/src/kinx.y @@ -821,7 +821,7 @@ AssignExpressionObjList KeyValueList : KeyValue - | KeyValueList ',' KeyValue { $$ = kx_gen_bexpr_object(KXST_EXPRLIST, $1, $3); } + | KeyValueList ',' KeyValue { $$ = kx_gen_exprlist($1, $3); } ; KeyValue @@ -1034,9 +1034,9 @@ Inherit_Opt .name = kx_check_the_name($3), .stmt = kx_gen_bexpr_object(KXST_STMTLIST, - kx_gen_bexpr_object(KXOP_DECL, kx_gen_var_object_line("this", KX_UNKNOWN_T, $2), + kx_gen_bexpr_object(KXOP_DECL, kx_gen_var_object_line("this", KX_OBJ_T, $2), kx_gen_bexpr_object(KXOP_CALL, kx_gen_bexpr_object(KXOP_IDX, $3, kx_gen_str_object("create")), $4)), - kx_gen_bexpr_object(KXOP_DECL, kx_gen_var_object_line("super", KX_UNKNOWN_T, $2), + kx_gen_bexpr_object(KXOP_DECL, kx_gen_var_object_line("super", KX_OBJ_T, $2), kx_gen_bexpr_object(KXOP_CALL, kx_gen_bexpr_object(KXOP_IDX, kx_gen_var_object("System", KX_UNKNOWN_T), kx_gen_str_object("makeSuper")), kx_gen_var_object("this", KX_UNKNOWN_T))) ), }; diff --git a/src/lexer.c b/src/lexer.c index cbe0d48d6..24863e0f3 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -15,6 +15,7 @@ static int g_binmode = 0; static int g_regexmode = 0; static const char *varname = NULL; static const char *modulename = NULL; +extern khash_t(package) *g_packages; static const char *parent_path(const char *str) { @@ -45,6 +46,7 @@ void setup_lexinfo(kx_context_t *ctx, const char *file, kx_yyin_t *yyin) kx_lexinfo.inner.brcount = 0; kx_lexinfo.inner.quote = 0; kx_lexinfo.in = *yyin; + kx_lexinfo.pkgkey = NULL; } void init_lexer(kx_context_t *ctx) @@ -69,7 +71,22 @@ void kx_make_regex_mode(int br) g_regexmode = br; } -static void load_using_module_asta(const char *name, int len) +static const char *search_using_path(const char *name) +{ + char libname[LIBNAME_BUFSIZE*2] = {0}; + const char *file = NULL; + /* Trying to search the file in the same directory first. */ + snprintf(libname, LIBNAME_BUFSIZE*2-1, "%s%c%s.kx", parent_path(kx_lexinfo.file), PATH_DELCH, name); + if (file_exists(libname)) { + file = libname; + } else { + snprintf(libname, LIBNAME_BUFSIZE*2-1, "%s.kx", name); + file = kxlib_file_exists(libname); + } + return file; +} + +static void load_using_module_asta(const char *name, int len, const char *pkgkey) { char *path = kx_calloc(len+2, sizeof(char)); memcpy(path, name, len); @@ -87,6 +104,10 @@ static void load_using_module_asta(const char *name, int len) .str = NULL, .file = const_str(g_parse_ctx, file) }); + if (pkgkey) { + kx_lexinfo.pkgkey = pkgkey; + pkgkey = NULL; + } kv_push(kx_lexinfo_t, kx_lex_stack, kx_lexinfo); } } @@ -95,7 +116,7 @@ static void load_using_module_asta(const char *name, int len) kx_free(path); } -static int load_using_module(const char *name, int no_error) +static int load_using_module(const char *name, const char *pkgkey, int no_error) { char libname[LIBNAME_BUFSIZE*2] = {0}; const char *file = NULL; @@ -104,27 +125,21 @@ static int load_using_module(const char *name, int no_error) if (name[len-2] != PATH_DELCH) { kx_yywarning("Can not use '*' with a current directoy in 'using' directive"); } else { - load_using_module_asta(name, len); + load_using_module_asta(name, len, pkgkey); return kx_yylex(); } } else { - /* Trying to search the file in the same directory first. */ - snprintf(libname, LIBNAME_BUFSIZE*2-1, "%s%c%s.kx", parent_path(kx_lexinfo.file), PATH_DELCH, name); - if (file_exists(libname)) { - file = libname; - } else { - snprintf(libname, LIBNAME_BUFSIZE*2-1, "%s.kx", name); - if (!(file = kxlib_file_exists(libname))) { - if (!no_error) { - char buf[LIBNAME_BUFSIZE*3] = {0}; - snprintf(buf, LIBNAME_BUFSIZE*3-1, "File not found(%s)", libname); - kx_yywarning(buf); - } - while (kx_lexinfo.ch && kx_lexinfo.ch != ';') { - kx_lex_next(kx_lexinfo); - } - return no_error ? ';' : ERROR; + file = search_using_path(name); + if (!file) { + if (!no_error) { + char buf[LIBNAME_BUFSIZE*3] = {0}; + snprintf(buf, LIBNAME_BUFSIZE*3-1, "Library file not found(%s)", name); + kx_yywarning(buf); + } + while (kx_lexinfo.ch && kx_lexinfo.ch != ';') { + kx_lex_next(kx_lexinfo); } + return no_error ? ';' : ERROR; } kv_push(kx_lexinfo_t, kx_lex_stack, kx_lexinfo); @@ -134,12 +149,63 @@ static int load_using_module(const char *name, int no_error) .str = NULL, .file = const_str(g_parse_ctx, file) }); + if (pkgkey) { + kx_lexinfo.pkgkey = pkgkey; + } } kx_lex_next(kx_lexinfo); return kx_yylex(); /* recursive call for the new file. */ } +static void push_package_version(const char *key, const char *ver) +{ + khint_t k = kh_get(package, g_packages, key); + if (k != kh_end(g_packages)) { + key = kx_const_str(g_parse_ctx, key); + ver = kx_const_str(g_parse_ctx, ver); + package_t *pkg = kh_value(g_packages, k); + package_t *newp = kx_calloc(1, sizeof(package_t)); + newp->vers = ver; + newp->next = pkg; + kh_value(g_packages, k) = newp; + } +} + +static void pop_package_version(const char *key) +{ + khint_t k = kh_get(package, g_packages, key); + if (k != kh_end(g_packages)) { + package_t *pkg = kh_value(g_packages, k); + if (pkg->next) { + package_t *next = pkg->next; + kx_free(pkg); + kh_value(g_packages, k) = next; + } + } +} + +static int set_package_version(const char *pkgname, int pos) +{ + khint_t k = kh_get(package, g_packages, pkgname); + if (k != kh_end(g_packages)) { + package_t *pkg = kh_value(g_packages, k); + const char *p = pkg->vers; + if (p) { + kx_strbuf[pos++] = PATH_DELCH; + while (*p) { + kx_strbuf[pos++] = *p++; + } + kx_strbuf[pos++] = PATH_DELCH; + kx_strbuf[pos++] = 'l'; + kx_strbuf[pos++] = 'i'; + kx_strbuf[pos++] = 'b'; + kx_strbuf[pos++] = PATH_DELCH; + } + } + return pos; +} + static int process_using(void) { int no_error = 0; @@ -151,16 +217,65 @@ static int process_using(void) while (kx_is_whitespace(kx_lexinfo)) { kx_lex_next(kx_lexinfo); } + const char *pkgname = NULL; + int pushed_version = 0; + int is_package = kx_lexinfo.ch == '@'; + int is_package_version = 0; + int is_package_verspos = 0; + int is_package_namepos = 0; int pos = 0; - kx_strbuf[pos++] = kx_lexinfo.ch; + if (is_package) { + kx_strbuf[pos++] = 'p'; + kx_strbuf[pos++] = 'a'; + kx_strbuf[pos++] = 'c'; + kx_strbuf[pos++] = 'k'; + kx_strbuf[pos++] = 'a'; + kx_strbuf[pos++] = 'g'; + kx_strbuf[pos++] = 'e'; + kx_strbuf[pos++] = PATH_DELCH; + is_package_namepos = pos; + } else { + kx_strbuf[pos++] = kx_lexinfo.ch; + } kx_lex_next(kx_lexinfo); while (pos < POSMAX && (kx_is_filechar(kx_lexinfo) || kx_lexinfo.ch == '*')) { - kx_strbuf[pos++] = kx_lexinfo.ch == '.' ? PATH_DELCH : kx_lexinfo.ch; + if (is_package) { + if (is_package_version == 0 && kx_lexinfo.ch == '.') { + kx_strbuf[pos] = 0; + pkgname = kx_const_str(g_parse_ctx, kx_strbuf + is_package_namepos); + pos = set_package_version(pkgname, pos); + is_package_version = 2; + } else if (is_package_version == 0 && kx_lexinfo.ch == '(') { + kx_strbuf[pos] = 0; + pkgname = kx_const_str(g_parse_ctx, kx_strbuf + is_package_namepos); + is_package_version = 1; + kx_strbuf[pos++] = PATH_DELCH; + is_package_verspos = pos; + } else if (is_package_version == 1 && kx_lexinfo.ch == ')') { + kx_strbuf[pos] = 0; + const char *ver = kx_const_str(g_parse_ctx, kx_strbuf + is_package_verspos); + pushed_version = 1; + push_package_version(pkgname, ver); + is_package_version = 2; + kx_strbuf[pos++] = PATH_DELCH; + kx_strbuf[pos++] = 'l'; + kx_strbuf[pos++] = 'i'; + kx_strbuf[pos++] = 'b'; + } else { + if (is_package_version == 1) { + kx_strbuf[pos++] = kx_lexinfo.ch; + } else { + kx_strbuf[pos++] = kx_lexinfo.ch == '.' ? PATH_DELCH : kx_lexinfo.ch; + } + } + } else { + kx_strbuf[pos++] = kx_lexinfo.ch == '.' ? PATH_DELCH : kx_lexinfo.ch; + } kx_lex_next(kx_lexinfo); } kx_strbuf[pos] = 0; - return load_using_module(kx_strbuf, no_error); + return load_using_module(kx_strbuf, pushed_version ? pkgname : NULL, no_error); } static int get_keyword_token(const char *val) @@ -646,7 +761,7 @@ static int process_import(void) return ';'; case 6: g_import = 0; - return load_using_module(modulename, 1); + return load_using_module(modulename, NULL, 1); } return ERROR; } @@ -683,6 +798,9 @@ int kx_yylex() if (kx_lexinfo.in.fp && kx_lexinfo.in.fp != stdin) { fclose(kx_lexinfo.in.fp); } + if (kx_lexinfo.pkgkey) { + pop_package_version(kx_lexinfo.pkgkey); + } kx_lexinfo = kv_pop(kx_lex_stack); if (!kx_lexinfo.in.fp && !kx_lexinfo.in.str) { kx_lexinfo.in.fp = fopen(kx_lexinfo.in.file, "r"); diff --git a/src/loadlib.c b/src/loadlib.c index ecbdb62b6..024cd44d0 100644 --- a/src/loadlib.c +++ b/src/loadlib.c @@ -107,6 +107,21 @@ void unload_library(void *h) } #endif +const char *kxlib_package_file(void) +{ + const char *checkfile = make_path_with(get_kinx_path(), "lib"PATH_DELIM"package", "kxpackage.ini"); + if (file_exists(checkfile)) { + return checkfile; + } + #if !defined(KCC_WINDOWS) + checkfile = make_path_with("/usr/bin", "kinxlib/package", "kxpackage.ini"); + if (file_exists(checkfile)) { + return checkfile; + } + #endif + return NULL; +} + const char *kxlib_file_exists_no_current(const char *file) { const char *checkfile = make_path(get_kinx_path(), file); diff --git a/src/mainlib.c b/src/mainlib.c index 380b47d3b..78897db04 100644 --- a/src/mainlib.c +++ b/src/mainlib.c @@ -38,6 +38,8 @@ extern void alloc_initialize(void); extern void alloc_finalize(void); extern void init_allocator(void); extern volatile int g_terminated; +extern khash_t(package) *g_packages; +extern const char *kxlib_package_file(void); #ifdef YYDEBUG extern int kx_yydebug; @@ -122,7 +124,18 @@ static void version(int detail) if (detail) { printf("- platform: %s\n", sljit_get_platform_name()); printf("- path: %s\n", get_kinx_path()); - printf("\n"); + + /* Package List */ + if (kh_end(g_packages) > 0) { + printf("\nPackages:\n"); + for (khint_t k = 0; k < kh_end(g_packages); ++k) { + if (kh_exist(g_packages, k)) { + const char *key = kh_key(g_packages, k); + package_t *p = kh_value(g_packages, k); + printf(" * %s v%s\n", key, p->vers); + } + } + } } } @@ -166,6 +179,72 @@ static void setup_run_environment(const char *filename) #endif } +static void setup_package_info(kx_context_t *ctx) +{ + g_packages = kh_init(package); + const char *pkgfile = kxlib_package_file(); + if (!pkgfile) { + return; + } + FILE *fp = fopen(pkgfile, "r"); + if (fp) { + char buf[1024] = {0}; + while (fgets(buf, 1020, fp)) { + char *p = strrchr(buf, '='); + if (!p || p == buf) continue; + char *s = p; + while (buf < s) { + --s; + if (*s != ' ' && *s != '\t') { + break; + } + *s = 0; + } + if (buf == s) continue; + ++p; + while (*p) { + if (*p != ' ' && *p != '\t') { + break; + } + ++p; + } + char *e = p + strlen(p) - 1; + while (*e == '\n' || *e == '\r') { + *e = 0; + --e; + } + if (*p) { + int absent; + const char *key = kx_const_str(ctx, buf); + const char *ver = kx_const_str(ctx, p); + package_t *pkg = kx_calloc(1, sizeof(package_t)); + pkg->vers = ver; + khint_t k = kh_put(package, g_packages, key, &absent); + kh_value(g_packages, k) = pkg; + if (absent) { + kh_key(g_packages, k) = key; + } + } + } + fclose(fp); + } +} + +static void free_package_info(void) +{ + for (khint_t k = 0; k < kh_end(g_packages); ++k) { + if (kh_exist(g_packages, k)) { + package_t *p = kh_value(g_packages, k); + while (p) { + package_t *n = p->next; + kx_free(p); + p = n; + } + } + } + kh_destroy(package, g_packages); +} + DllExport int do_main(int ac, char **av) { int r = 1; @@ -196,6 +275,7 @@ DllExport int do_main(int ac, char **av) const char *workdir = NULL; kx_context_t *ctx = make_context(); g_main_thread = ctx; + setup_package_info(ctx); char lname[LONGNAME_MAX] = {0}; char param[LONGNAME_MAX] = {0}; char *execname = NULL; @@ -395,6 +475,7 @@ DllExport int do_main(int ac, char **av) } g_terminated = 1; + free_package_info(); context_cleanup(ctx); free_nodes(); pthread_mutex_destroy(&g_mutex); diff --git a/src/parser.c b/src/parser.c index e5508ae51..921813db1 100644 --- a/src/parser.c +++ b/src/parser.c @@ -2841,7 +2841,7 @@ int yyparse(YYPARSE_ARG) { yyval.obj = kx_gen_bexpr_object(KXST_EXPRSEQ, YYASP(1-4).obj, kx_gen_uexpr_object_line(KXOP_MKOBJ, NULL, YYASP(3-4).intval)); } break; case 363: #line 824 "src/kinx.y" -{ yyval.obj = kx_gen_bexpr_object(KXST_EXPRLIST, YYASP(1-3).obj, YYASP(3-3).obj); } break; +{ yyval.obj = kx_gen_exprlist(YYASP(1-3).obj, YYASP(3-3).obj); } break; case 364: #line 828 "src/kinx.y" { yyval.obj = kx_gen_keyvalue_object(YYASP(2-5).strval, YYASP(5-5).obj); } break; @@ -3254,9 +3254,9 @@ int yyparse(YYPARSE_ARG) .name = kx_check_the_name(YYASP(3-4).obj), .stmt = kx_gen_bexpr_object(KXST_STMTLIST, - kx_gen_bexpr_object(KXOP_DECL, kx_gen_var_object_line("this", KX_UNKNOWN_T, YYASP(2-4).intval), + kx_gen_bexpr_object(KXOP_DECL, kx_gen_var_object_line("this", KX_OBJ_T, YYASP(2-4).intval), kx_gen_bexpr_object(KXOP_CALL, kx_gen_bexpr_object(KXOP_IDX, YYASP(3-4).obj, kx_gen_str_object("create")), YYASP(4-4).obj)), - kx_gen_bexpr_object(KXOP_DECL, kx_gen_var_object_line("super", KX_UNKNOWN_T, YYASP(2-4).intval), + kx_gen_bexpr_object(KXOP_DECL, kx_gen_var_object_line("super", KX_OBJ_T, YYASP(2-4).intval), kx_gen_bexpr_object(KXOP_CALL, kx_gen_bexpr_object(KXOP_IDX, kx_gen_var_object("System", KX_UNKNOWN_T), kx_gen_str_object("makeSuper")), kx_gen_var_object("this", KX_UNKNOWN_T))) ), };