mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-06-09 21:40:33 +02:00
This header file turns out to only have internal details. Users that need introspection can use Scheme. * libguile/programs.h (SCM_PROGRAM_P, SCM_PROGRAM_CODE) (SCM_PROGRAM_FREE_VARIABLES, SCM_PROGRAM_FREE_VARIABLE_REF) (SCM_PROGRAM_FREE_VARIABLE_SET, SCM_PROGRAM_NUM_FREE_VARIABLES) (SCM_VALIDATE_PROGRAM, SCM_F_PROGRAM_IS_BOOT, SCM_F_PROGRAM_IS_PRIMITIVE) (SCM_F_PROGRAM_IS_PRIMITIVE_GENERIC, SCM_F_PROGRAM_IS_CONTINUATION) (SCM_F_PROGRAM_IS_PARTIAL_CONTINUATION, SCM_F_PROGRAM_IS_FOREIGN) (SCM_PROGRAM_IS_BOOT, SCM_PROGRAM_IS_PRIMITIVE) (SCM_PROGRAM_IS_PRIMITIVE_GENERIC, SCM_PROGRAM_IS_CONTINUATION) (SCM_PROGRAM_IS_PARTIAL_CONTINUATION, SCM_PROGRAM_IS_FOREIGN): Remove these macros, as we are making this whole API private. (struct scm_program, scm_is_program, scm_to_program, scm_from_program) (scm_program_flags, scm_program_is_boot, scm_program_is_primitive) (scm_program_is_primitive_generic, scm_program_is_continuation) (scm_program_is_partial_continuation, scm_program_is_foreign) (scm_program_code, scm_program_free_variable_count) (scm_program_free_variable_ref, scm_program_free_variable_set_x) (scm_i_make_program): New inline functions. * libguile/Makefile.am (noinst_HEADERS): Add programs.h; no longer installed. It was never directly included from libguile.h. * libguile/continuations.c: * libguile/continuations.h: * libguile/control.c: * libguile/foreign.c: * libguile/frames.c: * libguile/frames.h: * libguile/goops.c: * libguile/gsubr.c: * libguile/gsubr.h: * libguile/intrinsics.h: * libguile/procprop.c: * libguile/procs.c: * libguile/programs.c: * libguile/stacks.c: * libguile/vm-engine.c: * libguile/vm.c: * libguile/vm.h: Adapt all users.
405 lines
10 KiB
C
405 lines
10 KiB
C
/* Copyright 2001,2009-2014,2017-2019,2025
|
||
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"
|
||
|
||
|
||
|
||
|
||
#define SCM_PROGRAM_P(x) (scm_is_program (x))
|
||
#define SCM_VALIDATE_PROGRAM(p,x) SCM_MAKE_VALIDATE (p, x, PROGRAM_P)
|
||
|
||
|
||
|
||
static SCM write_program = SCM_BOOL_F;
|
||
|
||
SCM_DEFINE_STATIC (program_code, "program-code", 1, 0, 0,
|
||
(SCM program),
|
||
"")
|
||
#define FUNC_NAME s_program_code
|
||
{
|
||
SCM_VALIDATE_PROGRAM (1, program);
|
||
struct scm_program *p = scm_to_program (program);
|
||
|
||
return scm_from_uintptr_t ((uintptr_t) scm_program_code (p));
|
||
}
|
||
#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_to_program (program)->code);
|
||
|
||
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");
|
||
|
||
struct scm_program *p = scm_to_program (program);
|
||
if (scm_program_is_continuation (p))
|
||
{
|
||
/* twingliness */
|
||
scm_puts ("#<continuation ", port);
|
||
scm_uintprint (SCM_UNPACK (program), 16, port);
|
||
scm_putc ('>', port);
|
||
}
|
||
else if (scm_program_is_partial_continuation (p))
|
||
{
|
||
/* 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) p->code, 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_STATIC (program_p, "program?", 1, 0, 0,
|
||
(SCM obj),
|
||
"")
|
||
#define FUNC_NAME s_program_p
|
||
{
|
||
return scm_from_bool (scm_is_program (obj));
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE_STATIC (primitive_code_p, "primitive-code?", 1, 0, 0,
|
||
(SCM code),
|
||
"")
|
||
#define FUNC_NAME s_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_STATIC (primitive_call_ip, "primitive-call-ip", 1, 0, 0,
|
||
(SCM prim),
|
||
"")
|
||
#define FUNC_NAME s_primitive_call_ip
|
||
{
|
||
uintptr_t ip;
|
||
|
||
SCM_MAKE_VALIDATE (1, prim, PRIMITIVE_P);
|
||
|
||
ip = scm_i_primitive_call_ip (scm_to_program (prim));
|
||
return ip ? scm_from_uintptr_t (ip) : SCM_BOOL_F;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE_STATIC (primitive_code_name, "primitive-code-name", 1, 0, 0,
|
||
(SCM code),
|
||
"")
|
||
#define FUNC_NAME s_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_STATIC (program_num_free_variables, "program-num-free-variables",
|
||
1, 0, 0, (SCM program),
|
||
"")
|
||
#define FUNC_NAME s_program_num_free_variables
|
||
{
|
||
SCM_VALIDATE_PROGRAM (1, program);
|
||
struct scm_program *p = scm_to_program (program);
|
||
|
||
return scm_from_ulong (scm_program_free_variable_count (p));
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE_STATIC (program_free_variable_ref, "program-free-variable-ref",
|
||
2, 0, 0, (SCM program, SCM i),
|
||
"")
|
||
#define FUNC_NAME s_program_free_variable_ref
|
||
{
|
||
unsigned long idx;
|
||
|
||
SCM_VALIDATE_PROGRAM (1, program);
|
||
SCM_VALIDATE_ULONG_COPY (2, i, idx);
|
||
struct scm_program *p = scm_to_program (program);
|
||
if (idx >= scm_program_free_variable_count (p))
|
||
SCM_OUT_OF_RANGE (2, i);
|
||
return scm_program_free_variable_ref (p, idx);
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE_STATIC (program_free_variable_set_x, "program-free-variable-set!",
|
||
3, 0, 0, (SCM program, SCM i, SCM x),
|
||
"")
|
||
#define FUNC_NAME s_program_free_variable_set_x
|
||
{
|
||
unsigned long idx;
|
||
|
||
SCM_VALIDATE_PROGRAM (1, program);
|
||
SCM_VALIDATE_ULONG_COPY (2, i, idx);
|
||
struct scm_program *p = scm_to_program (program);
|
||
if (idx >= scm_program_free_variable_count (p))
|
||
SCM_OUT_OF_RANGE (2, i);
|
||
|
||
scm_program_free_variable_set_x (p, 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)
|
||
{
|
||
const uint32_t *code = scm_program_code (scm_to_program (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_optionals:
|
||
slots = code[0] >> 8;
|
||
*req = 0;
|
||
*opt = slots - 1;
|
||
*rest = ((code[1] & 0xff) == scm_op_bind_rest);
|
||
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_optionals:
|
||
slots = code[1] >> 8;
|
||
*req = min - 1;
|
||
*opt = slots - 1 - *req;
|
||
*rest = ((code[2] & 0xff) == scm_op_bind_rest);
|
||
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
|
||
}
|