summaryrefslogtreecommitdiff
path: root/libguile/programs.c
diff options
context:
space:
mode:
Diffstat (limited to 'libguile/programs.c')
-rw-r--r--libguile/programs.c380
1 files changed, 380 insertions, 0 deletions
diff --git a/libguile/programs.c b/libguile/programs.c
new file mode 100644
index 000000000..675035727
--- /dev/null
+++ b/libguile/programs.c
@@ -0,0 +1,380 @@
+/* Copyright 2001,2009-2014,2017-2019
+ Free Software Foundation, Inc.
+
+ This file is part of Guile.
+
+ Guile is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Guile is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with Guile. If not, see
+ <https://www.gnu.org/licenses/>. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#include "alist.h"
+#include "boolean.h"
+#include "eval.h"
+#include "extensions.h"
+#include "gsubr.h"
+#include "instructions.h"
+#include "modules.h"
+#include "numbers.h"
+#include "pairs.h"
+#include "ports.h"
+#include "procprop.h" /* scm_sym_name */
+#include "variable.h"
+#include "version.h"
+#include "vm.h"
+
+#include "programs.h"
+
+
+static SCM write_program = SCM_BOOL_F;
+
+SCM_DEFINE (scm_program_code, "program-code", 1, 0, 0,
+ (SCM program),
+ "")
+#define FUNC_NAME s_scm_program_code
+{
+ SCM_VALIDATE_PROGRAM (1, program);
+
+ return scm_from_uintptr_t ((uintptr_t) SCM_PROGRAM_CODE (program));
+}
+#undef FUNC_NAME
+
+SCM
+scm_i_program_name (SCM program)
+{
+ static SCM program_name = SCM_BOOL_F;
+
+ if (SCM_PRIMITIVE_P (program))
+ return scm_i_primitive_name (SCM_PROGRAM_CODE (program));
+
+ if (scm_is_false (program_name) && scm_module_system_booted_p)
+ program_name =
+ scm_c_private_variable ("system vm program", "program-name");
+
+ return scm_call_1 (scm_variable_ref (program_name), program);
+}
+
+SCM
+scm_i_program_documentation (SCM program)
+{
+ static SCM program_documentation = SCM_BOOL_F;
+
+ if (SCM_PRIMITIVE_P (program))
+ return SCM_BOOL_F;
+
+ if (scm_is_false (program_documentation) && scm_module_system_booted_p)
+ program_documentation =
+ scm_c_private_variable ("system vm program", "program-documentation");
+
+ return scm_call_1 (scm_variable_ref (program_documentation), program);
+}
+
+SCM
+scm_i_program_properties (SCM program)
+{
+ static SCM program_properties = SCM_BOOL_F;
+
+ if (SCM_PRIMITIVE_P (program))
+ {
+ SCM name = scm_i_program_name (program);
+ if (scm_is_false (name))
+ return SCM_EOL;
+ return scm_acons (scm_sym_name, name, SCM_EOL);
+ }
+
+ if (scm_is_false (program_properties) && scm_module_system_booted_p)
+ program_properties =
+ scm_c_private_variable ("system vm program", "program-properties");
+
+ return scm_call_1 (scm_variable_ref (program_properties), program);
+}
+
+void
+scm_i_program_print (SCM program, SCM port, scm_print_state *pstate)
+{
+ static int print_error = 0;
+
+ if (scm_is_false (write_program) && scm_module_system_booted_p)
+ write_program = scm_c_private_variable ("system vm program",
+ "write-program");
+
+ if (SCM_PROGRAM_IS_CONTINUATION (program))
+ {
+ /* twingliness */
+ scm_puts ("#<continuation ", port);
+ scm_uintprint (SCM_UNPACK (program), 16, port);
+ scm_putc ('>', port);
+ }
+ else if (SCM_PROGRAM_IS_PARTIAL_CONTINUATION (program))
+ {
+ /* twingliness */
+ scm_puts ("#<partial-continuation ", port);
+ scm_uintprint (SCM_UNPACK (program), 16, port);
+ scm_putc ('>', port);
+ }
+ else if (scm_is_false (write_program) || print_error)
+ {
+ scm_puts ("#<program ", port);
+ scm_uintprint (SCM_UNPACK (program), 16, port);
+ scm_putc (' ', port);
+ scm_uintprint ((uintptr_t) SCM_PROGRAM_CODE (program), 16, port);
+ scm_putc ('>', port);
+ }
+ else
+ {
+ print_error = 1;
+ scm_call_2 (SCM_VARIABLE_REF (write_program), program, port);
+ print_error = 0;
+ }
+}
+
+
+/*
+ * Scheme interface
+ */
+
+SCM_DEFINE (scm_program_p, "program?", 1, 0, 0,
+ (SCM obj),
+ "")
+#define FUNC_NAME s_scm_program_p
+{
+ return scm_from_bool (SCM_PROGRAM_P (obj));
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_primitive_code_p, "primitive-code?", 1, 0, 0,
+ (SCM code),
+ "")
+#define FUNC_NAME s_scm_primitive_code_p
+{
+ const uint32_t * ptr = (const uint32_t *) scm_to_uintptr_t (code);
+
+ return scm_from_bool (scm_i_primitive_code_p (ptr));
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_primitive_call_ip, "primitive-call-ip", 1, 0, 0,
+ (SCM prim),
+ "")
+#define FUNC_NAME s_scm_primitive_call_ip
+{
+ uintptr_t ip;
+
+ SCM_MAKE_VALIDATE (1, prim, PRIMITIVE_P);
+
+ ip = scm_i_primitive_call_ip (prim);
+ return ip ? scm_from_uintptr_t (ip) : SCM_BOOL_F;
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_primitive_code_name, "primitive-code-name", 1, 0, 0,
+ (SCM code),
+ "")
+#define FUNC_NAME s_scm_primitive_code_name
+{
+ const uint32_t * ptr = (const uint32_t *) scm_to_uintptr_t (code);
+
+ if (scm_i_primitive_code_p (ptr))
+ return scm_i_primitive_name (ptr);
+
+ return SCM_BOOL_F;
+}
+#undef FUNC_NAME
+
+SCM
+scm_find_source_for_addr (SCM ip)
+{
+ static SCM source_for_addr = SCM_BOOL_F;
+
+ if (scm_is_false (source_for_addr)) {
+ if (!scm_module_system_booted_p)
+ return SCM_BOOL_F;
+
+ source_for_addr =
+ scm_c_private_variable ("system vm program", "source-for-addr");
+ }
+
+ return scm_call_1 (scm_variable_ref (source_for_addr), ip);
+}
+
+SCM
+scm_program_address_range (SCM program)
+{
+ static SCM program_address_range = SCM_BOOL_F;
+
+ if (scm_is_false (program_address_range) && scm_module_system_booted_p)
+ program_address_range =
+ scm_c_private_variable ("system vm program", "program-address-range");
+
+ return scm_call_1 (scm_variable_ref (program_address_range), program);
+}
+
+SCM_DEFINE (scm_program_num_free_variables, "program-num-free-variables", 1, 0, 0,
+ (SCM program),
+ "")
+#define FUNC_NAME s_scm_program_num_free_variables
+{
+ SCM_VALIDATE_PROGRAM (1, program);
+
+ return scm_from_ulong (SCM_PROGRAM_NUM_FREE_VARIABLES (program));
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_program_free_variable_ref, "program-free-variable-ref", 2, 0, 0,
+ (SCM program, SCM i),
+ "")
+#define FUNC_NAME s_scm_program_free_variable_ref
+{
+ unsigned long idx;
+
+ SCM_VALIDATE_PROGRAM (1, program);
+ SCM_VALIDATE_ULONG_COPY (2, i, idx);
+ if (idx >= SCM_PROGRAM_NUM_FREE_VARIABLES (program))
+ SCM_OUT_OF_RANGE (2, i);
+ return SCM_PROGRAM_FREE_VARIABLE_REF (program, idx);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_program_free_variable_set_x, "program-free-variable-set!", 3, 0, 0,
+ (SCM program, SCM i, SCM x),
+ "")
+#define FUNC_NAME s_scm_program_free_variable_set_x
+{
+ unsigned long idx;
+
+ SCM_VALIDATE_PROGRAM (1, program);
+ SCM_VALIDATE_ULONG_COPY (2, i, idx);
+ if (idx >= SCM_PROGRAM_NUM_FREE_VARIABLES (program))
+ SCM_OUT_OF_RANGE (2, i);
+ SCM_PROGRAM_FREE_VARIABLE_SET (program, idx, x);
+ return SCM_UNSPECIFIED;
+}
+#undef FUNC_NAME
+
+/* It's hacky, but it manages to cover all of the non-keyword cases. */
+static int
+try_parse_arity (SCM program, int *req, int *opt, int *rest)
+{
+ uint32_t *code = SCM_PROGRAM_CODE (program);
+ uint32_t slots, min;
+
+ if ((code[0] & 0xff) == scm_op_instrument_entry)
+ code += 2;
+
+ switch (code[0] & 0xff) {
+ case scm_op_assert_nargs_ee:
+ slots = code[0] >> 8;
+ *req = slots - 1;
+ *opt = 0;
+ *rest = 0;
+ return 1;
+ case scm_op_assert_nargs_ee_locals:
+ slots = (code[0] >> 8) & 0xfff;
+ *req = slots - 1;
+ *opt = 0;
+ *rest = 0;
+ return 1;
+ case scm_op_assert_nargs_le:
+ slots = code[0] >> 8;
+ *req = 0;
+ *opt = slots - 1;
+ *rest = 0;
+ return 1;
+ case scm_op_bind_rest:
+ slots = code[0] >> 8;
+ *req = 0;
+ *opt = slots - 1;
+ *rest = 1;
+ return 1;
+ case scm_op_assert_nargs_ge:
+ min = code[0] >> 8;
+ switch (code[1] & 0xff) {
+ case scm_op_assert_nargs_le:
+ slots = code[1] >> 8;
+ *req = min - 1;
+ *opt = slots - 1 - *req;
+ *rest = 0;
+ return 1;
+ case scm_op_bind_rest:
+ slots = code[1] >> 8;
+ *req = min - 1;
+ *opt = slots - min;
+ *rest = 1;
+ return 1;
+ case scm_op_shuffle_down:
+ case scm_op_abort:
+ *req = min - 1;
+ *opt = 0;
+ *rest = 1;
+ return 1;
+ default:
+ return 0;
+ }
+ case scm_op_continuation_call:
+ case scm_op_compose_continuation:
+ case scm_op_shuffle_down:
+ *req = 0;
+ *opt = 0;
+ *rest = 1;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int
+scm_i_program_arity (SCM program, int *req, int *opt, int *rest)
+{
+ static SCM program_minimum_arity = SCM_BOOL_F;
+ SCM l;
+
+ if (try_parse_arity (program, req, opt, rest))
+ return 1;
+
+ if (scm_is_false (program_minimum_arity) && scm_module_system_booted_p)
+ program_minimum_arity =
+ scm_c_private_variable ("system vm program", "program-minimum-arity");
+
+ l = scm_call_1 (scm_variable_ref (program_minimum_arity), program);
+ if (scm_is_false (l))
+ return 0;
+
+ *req = scm_to_int (scm_car (l));
+ *opt = scm_to_int (scm_cadr (l));
+ *rest = scm_is_true (scm_caddr (l));
+
+ return 1;
+}
+
+
+
+void
+scm_bootstrap_programs (void)
+{
+ scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
+ "scm_init_programs",
+ (scm_t_extension_init_func)scm_init_programs, NULL);
+}
+
+void
+scm_init_programs (void)
+{
+#ifndef SCM_MAGIC_SNARFER
+#include "programs.x"
+#endif
+}