#include "posix.h" #include "functions/common.h" #include "functions/environment.h" #include "lang/interpreter.h" #include "log.h" static enum iteration_result typecheck_environment_dict_iter(struct workspace *wk, void *_ctx, obj key, obj val) { uint32_t *err_node = _ctx; enum obj_type t = get_obj(wk, val)->type; if (t != obj_string) { interp_error(wk, *err_node, "all values in environment dict must be strings, got: %s", obj_type_to_s(t)); return ir_err; } return ir_cont; } bool typecheck_environment_dict(struct workspace *wk, uint32_t err_node, obj dict) { return obj_dict_foreach(wk, dict, &err_node, typecheck_environment_dict_iter); } enum environment_set_mode { environment_set_mode_set, environment_set_mode_append, environment_set_mode_prepend, }; static bool environment_set_common(struct workspace *wk, obj rcvr, uint32_t args_node, enum environment_set_mode mode) { struct args_norm an[] = { { obj_string }, { ARG_TYPE_GLOB }, ARG_TYPE_NULL }; enum kwargs { kw_separator, }; struct args_kw akw[] = { [kw_separator] = { "separator", obj_string }, 0 }; if (!interp_args(wk, args_node, an, NULL, akw)) { return false; } obj dict = get_obj(wk, rcvr)->dat.environment.env, key = an[0].val, value = an[1].val, sep; if (akw[kw_separator].set) { sep = akw[kw_separator].val; } else { sep = make_str(wk, ":"); } assert(get_obj(wk, value)->type == obj_array); if (!get_obj(wk, value)->dat.arr.len) { interp_error(wk, an[0].node, "you must pass at least one value"); return false; } obj joined; if (!obj_array_join(wk, value, sep, &joined)) { return false; } obj orig; if (!obj_dict_index(wk, dict, key, &orig)) { obj_dict_set(wk, dict, key, joined); return true; } obj head, tail; switch (mode) { case environment_set_mode_set: obj_dict_set(wk, dict, key, joined); return true; case environment_set_mode_append: head = orig; tail = joined; break; case environment_set_mode_prepend: head = joined; tail = orig; break; default: head = 0; tail = 0; assert(false && "unreachable"); return false; } obj new_val; make_obj(wk, &new_val, obj_string)->dat.str = wk_str_pushf(wk, "%s%s%s", get_cstr(wk, head), get_cstr(wk, sep), get_cstr(wk, tail)); obj_dict_set(wk, dict, key, new_val); return true; } static bool func_environment_set(struct workspace *wk, obj rcvr, uint32_t args_node, obj *res) { return environment_set_common(wk, rcvr, args_node, environment_set_mode_set); } static bool func_environment_append(struct workspace *wk, obj rcvr, uint32_t args_node, obj *res) { return environment_set_common(wk, rcvr, args_node, environment_set_mode_append); } static bool func_environment_prepend(struct workspace *wk, obj rcvr, uint32_t args_node, obj *res) { return environment_set_common(wk, rcvr, args_node, environment_set_mode_prepend); } const struct func_impl_name impl_tbl_environment[] = { { "set", func_environment_set }, { "append", func_environment_append }, { "prepend", func_environment_prepend }, { NULL, NULL }, };