1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-04-30 11:50:28 +02:00

a different tack for syncase macro representation

* libguile/macros.c (macro_print): Show syntax-case bindings, if present.
  (macro_mark): Mark the extra two words if they're there.
  (scm_make_syncase_macro, scm_make_extended_syncase_macro): OK! A new
  take at the "how do we represent syncase macros in Guile" problem.
  Whereas we need a disjoint type, but would like it to be compatible
  with old predicates (e.g. `macro?'), and need to be able to extend
  existing syntax definitions (e.g. `cond'), let's add a bit to macros to
  indicate whether they have syncase macro bindings or not, and a fourth
  macro type for native syncase macros.
  (scm_macro_type): Return 'syntax-case for native syntax-case macros.
  Note that other macro types may have syntax-case bindings.
  (scm_macro_name): Return #f if the transformer is not a procedure.
  (scm_syncase_macro_type, scm_syncase_macro_binding): New accessors for
  the syncase macro bindings.

* libguile/macros.h: Add API for syncase macros.

* module/ice-9/boot-9.scm (module-define-keyword!): Adapt to use syncase
  macros, though they are not yet used. Reorder other syncase API.

* module/ice-9/psyntax.scm (chi-expr): Fix syntax-violation invocation.
This commit is contained in:
Andy Wingo 2009-04-29 00:38:12 +02:00
parent 5f1a2fb10f
commit 5a0132b337
5 changed files with 132 additions and 31 deletions

View file

@ -48,10 +48,13 @@ macro_print (SCM macro, SCM port, scm_print_state *pstate)
|| scm_is_false (scm_printer_apply (SCM_PRINT_CLOSURE, || scm_is_false (scm_printer_apply (SCM_PRINT_CLOSURE,
macro, port, pstate))) macro, port, pstate)))
{ {
scm_puts ("#<", port);
if (SCM_MACRO_TYPE (macro) < 4 && SCM_MACRO_IS_EXTENDED (macro))
scm_puts ("extended-", port);
if (!SCM_CLOSUREP (code) && !SCM_PROGRAM_P (code)) if (!SCM_CLOSUREP (code) && !SCM_PROGRAM_P (code))
scm_puts ("#<primitive-", port); scm_puts ("primitive-", port);
else
scm_puts ("#<", port);
if (SCM_MACRO_TYPE (macro) == 0) if (SCM_MACRO_TYPE (macro) == 0)
scm_puts ("syntax", port); scm_puts ("syntax", port);
@ -63,6 +66,8 @@ macro_print (SCM macro, SCM port, scm_print_state *pstate)
scm_puts ("macro!", port); scm_puts ("macro!", port);
if (SCM_MACRO_TYPE (macro) == 3) if (SCM_MACRO_TYPE (macro) == 3)
scm_puts ("builtin-macro!", port); scm_puts ("builtin-macro!", port);
if (SCM_MACRO_TYPE (macro) == 4)
scm_puts ("syncase-macro", port);
scm_putc (' ', port); scm_putc (' ', port);
scm_iprin1 (scm_macro_name (macro), port, pstate); scm_iprin1 (scm_macro_name (macro), port, pstate);
@ -77,12 +82,30 @@ macro_print (SCM macro, SCM port, scm_print_state *pstate)
scm_iprin1 (src, port, pstate); scm_iprin1 (src, port, pstate);
} }
if (SCM_MACRO_IS_EXTENDED (macro))
{
scm_putc (' ', port);
scm_write (SCM_SMOB_OBJECT_2 (macro), port);
scm_putc (' ', port);
scm_write (SCM_SMOB_OBJECT_3 (macro), port);
}
scm_putc ('>', port); scm_putc ('>', port);
} }
return 1; return 1;
} }
static SCM
macro_mark (SCM macro)
{
if (SCM_MACRO_IS_EXTENDED (macro))
{ scm_gc_mark (SCM_SMOB_OBJECT_2 (macro));
scm_gc_mark (SCM_SMOB_OBJECT_3 (macro));
}
return SCM_SMOB_OBJECT (macro);
}
static SCM static SCM
makmac (SCM code, scm_t_bits flags) makmac (SCM code, scm_t_bits flags)
{ {
@ -164,6 +187,40 @@ SCM_DEFINE (scm_makmacro, "procedure->macro", 1, 0, 0,
#endif #endif
SCM_DEFINE (scm_make_syncase_macro, "make-syncase-macro", 2, 0, 0,
(SCM type, SCM binding),
"Return a @dfn{macro} that requires expansion by syntax-case.\n"
"While users should not call this function, it is useful to know\n"
"that syntax-case macros are represented as Guile primitive macros.")
#define FUNC_NAME s_scm_make_syncase_macro
{
SCM z;
SCM_VALIDATE_SYMBOL (1, type);
SCM_NEWSMOB3 (z, scm_tc16_macro, SCM_UNPACK (binding), SCM_UNPACK (type),
SCM_UNPACK (binding));
SCM_SET_SMOB_FLAGS (z, 4 | SCM_F_MACRO_EXTENDED);
return z;
}
#undef FUNC_NAME
SCM_DEFINE (scm_make_extended_syncase_macro, "make-extended-syncase-macro", 3, 0, 0,
(SCM m, SCM type, SCM binding),
"Extend a core macro @var{m} with a syntax-case binding.")
#define FUNC_NAME s_scm_make_extended_syncase_macro
{
SCM z;
SCM_VALIDATE_SMOB (1, m, macro);
SCM_VALIDATE_SYMBOL (2, type);
SCM_NEWSMOB3 (z, scm_tc16_macro, SCM_SMOB_DATA (m), SCM_UNPACK (type),
SCM_UNPACK (binding));
SCM_SET_SMOB_FLAGS (z, SCM_SMOB_FLAGS (m) | SCM_F_MACRO_EXTENDED);
return z;
}
#undef FUNC_NAME
SCM_DEFINE (scm_macro_p, "macro?", 1, 0, 0, SCM_DEFINE (scm_macro_p, "macro?", 1, 0, 0,
(SCM obj), (SCM obj),
@ -182,14 +239,15 @@ SCM_SYMBOL (scm_sym_macro, "macro");
#endif #endif
SCM_SYMBOL (scm_sym_mmacro, "macro!"); SCM_SYMBOL (scm_sym_mmacro, "macro!");
SCM_SYMBOL (scm_sym_bimacro, "builtin-macro!"); SCM_SYMBOL (scm_sym_bimacro, "builtin-macro!");
SCM_SYMBOL (scm_sym_syncase_macro, "syncase-macro");
SCM_DEFINE (scm_macro_type, "macro-type", 1, 0, 0, SCM_DEFINE (scm_macro_type, "macro-type", 1, 0, 0,
(SCM m), (SCM m),
"Return one of the symbols @code{syntax}, @code{macro} or\n" "Return one of the symbols @code{syntax}, @code{macro},\n"
"@code{macro!}, depending on whether @var{m} is a syntax\n" "@code{macro!}, or @code{syntax-case}, depending on whether\n"
"transformer, a regular macro, or a memoizing macro,\n" "@var{m} is a syntax transformer, a regular macro, a memoizing\n"
"respectively. If @var{m} is not a macro, @code{#f} is\n" "macro, or a syntax-case macro, respectively. If @var{m} is\n"
"returned.") "not a macro, @code{#f} is returned.")
#define FUNC_NAME s_scm_macro_type #define FUNC_NAME s_scm_macro_type
{ {
if (!SCM_SMOB_PREDICATE (scm_tc16_macro, m)) if (!SCM_SMOB_PREDICATE (scm_tc16_macro, m))
@ -202,6 +260,7 @@ SCM_DEFINE (scm_macro_type, "macro-type", 1, 0, 0,
#endif #endif
case 2: return scm_sym_mmacro; case 2: return scm_sym_mmacro;
case 3: return scm_sym_bimacro; case 3: return scm_sym_bimacro;
case 4: return scm_sym_syncase_macro;
default: scm_wrong_type_arg (FUNC_NAME, 1, m); default: scm_wrong_type_arg (FUNC_NAME, 1, m);
} }
} }
@ -214,7 +273,9 @@ SCM_DEFINE (scm_macro_name, "macro-name", 1, 0, 0,
#define FUNC_NAME s_scm_macro_name #define FUNC_NAME s_scm_macro_name
{ {
SCM_VALIDATE_SMOB (1, m, macro); SCM_VALIDATE_SMOB (1, m, macro);
return scm_procedure_name (SCM_PACK (SCM_SMOB_DATA (m))); if (scm_is_true (scm_procedure_p (SCM_SMOB_OBJECT (m))))
return scm_procedure_name (SCM_SMOB_OBJECT (m));
return SCM_BOOL_F;
} }
#undef FUNC_NAME #undef FUNC_NAME
@ -236,6 +297,34 @@ SCM_DEFINE (scm_macro_transformer, "macro-transformer", 1, 0, 0,
} }
#undef FUNC_NAME #undef FUNC_NAME
SCM_DEFINE (scm_syncase_macro_type, "syncase-macro-type", 1, 0, 0,
(SCM m),
"Return the type of the macro @var{m}.")
#define FUNC_NAME s_scm_syncase_macro_type
{
SCM_VALIDATE_SMOB (1, m, macro);
if (SCM_MACRO_IS_EXTENDED (m))
return SCM_SMOB_OBJECT_2 (m);
else
return SCM_BOOL_F;
}
#undef FUNC_NAME
SCM_DEFINE (scm_syncase_macro_binding, "syncase-macro-binding", 1, 0, 0,
(SCM m),
"Return the binding of the macro @var{m}.")
#define FUNC_NAME s_scm_syncase_macro_binding
{
SCM_VALIDATE_SMOB (1, m, macro);
if (SCM_MACRO_IS_EXTENDED (m))
return SCM_SMOB_OBJECT_3 (m);
else
return SCM_BOOL_F;
}
#undef FUNC_NAME
SCM SCM
scm_make_synt (const char *name, SCM (*macroizer) (), SCM (*fcn)() ) scm_make_synt (const char *name, SCM (*macroizer) (), SCM (*fcn)() )
{ {
@ -249,7 +338,7 @@ void
scm_init_macros () scm_init_macros ()
{ {
scm_tc16_macro = scm_make_smob_type ("macro", 0); scm_tc16_macro = scm_make_smob_type ("macro", 0);
scm_set_smob_mark (scm_tc16_macro, scm_markcdr); scm_set_smob_mark (scm_tc16_macro, macro_mark);
scm_set_smob_print (scm_tc16_macro, macro_print); scm_set_smob_print (scm_tc16_macro, macro_print);
#include "libguile/macros.x" #include "libguile/macros.x"
} }

View file

@ -29,9 +29,15 @@
#define SCM_ASSYNT(_cond, _msg, _subr) \ #define SCM_ASSYNT(_cond, _msg, _subr) \
if (!(_cond)) scm_misc_error (_subr, _msg, SCM_EOL); if (!(_cond)) scm_misc_error (_subr, _msg, SCM_EOL);
#define SCM_MACRO_TYPE_BITS (3)
#define SCM_MACRO_TYPE_MASK ((1<<SCM_MACRO_TYPE_BITS)-1)
#define SCM_F_MACRO_EXTENDED (1<<SCM_MACRO_TYPE_BITS)
#define SCM_MACROP(x) SCM_SMOB_PREDICATE (scm_tc16_macro, (x)) #define SCM_MACROP(x) SCM_SMOB_PREDICATE (scm_tc16_macro, (x))
#define SCM_MACRO_TYPE(m) SCM_SMOB_FLAGS (m) #define SCM_MACRO_TYPE(m) (SCM_SMOB_FLAGS (m) & SCM_MACRO_TYPE_MASK)
#define SCM_MACRO_IS_EXTENDED(m) (SCM_SMOB_FLAGS (m) & SCM_F_MACRO_EXTENDED)
#define SCM_BUILTIN_MACRO_P(x) (SCM_MACROP (x) && SCM_MACRO_TYPE (x) == 3) #define SCM_BUILTIN_MACRO_P(x) (SCM_MACROP (x) && SCM_MACRO_TYPE (x) == 3)
#define SCM_SYNCASE_MACRO_P(x) (SCM_MACROP (x) && SCM_MACRO_TYPE (x) == 4)
#define SCM_MACRO_CODE(m) SCM_SMOB_OBJECT (m) #define SCM_MACRO_CODE(m) SCM_SMOB_OBJECT (m)
SCM_API scm_t_bits scm_tc16_macro; SCM_API scm_t_bits scm_tc16_macro;
@ -39,10 +45,15 @@ SCM_API scm_t_bits scm_tc16_macro;
SCM_INTERNAL SCM scm_i_makbimacro (SCM code); SCM_INTERNAL SCM scm_i_makbimacro (SCM code);
SCM_API SCM scm_makmmacro (SCM code); SCM_API SCM scm_makmmacro (SCM code);
SCM_API SCM scm_makacro (SCM code); SCM_API SCM scm_makacro (SCM code);
SCM_API SCM scm_make_syncase_macro (SCM type, SCM binding);
SCM_API SCM scm_make_extended_syncase_macro (SCM builtin, SCM type,
SCM binding);
SCM_API SCM scm_macro_p (SCM obj); SCM_API SCM scm_macro_p (SCM obj);
SCM_API SCM scm_macro_type (SCM m); SCM_API SCM scm_macro_type (SCM m);
SCM_API SCM scm_macro_name (SCM m); SCM_API SCM scm_macro_name (SCM m);
SCM_API SCM scm_macro_transformer (SCM m); SCM_API SCM scm_macro_transformer (SCM m);
SCM_API SCM scm_syncase_macro_type (SCM m);
SCM_API SCM scm_syncase_macro_binding (SCM m);
SCM_API SCM scm_make_synt (const char *name, SCM_API SCM scm_make_synt (const char *name,
SCM (*macroizer) (SCM), SCM (*macroizer) (SCM),
SCM (*fcn) ()); SCM (*fcn) ());

View file

@ -161,12 +161,13 @@
;;; Keywords are syntactic bindings; variables are value bindings. ;;; Keywords are syntactic bindings; variables are value bindings.
(define (module-define-keyword! mod sym type val) (define (module-define-keyword! mod sym type val)
(let ((v (or (module-local-variable mod sym) (let ((v (or (module-local-variable mod sym)
(let ((v (make-variable val))) (let ((v (make-undefined-variable)))
(module-add! mod sym v) (module-add! mod sym v)
v)))) v))))
(if (or (not (variable-bound? v)) (variable-set! v
(not (macro? (variable-ref v)))) (if (and (variable-bound? v) (macro? (variable-ref v)))
(variable-set! v val)) (make-extended-syncase-macro (variable-ref v) type val)
(make-syncase-macro type val)))
(set-object-property! v '*sc-expander* (cons type val)))) (set-object-property! v '*sc-expander* (cons type val))))
(define (module-lookup-keyword mod sym) (define (module-lookup-keyword mod sym)
@ -180,20 +181,25 @@
;; probably should unbind the variable too ;; probably should unbind the variable too
(set-object-properties! v (delq p (object-properties v))))))) (set-object-properties! v (delq p (object-properties v)))))))
(define sc-expand #f) ;;; API provided by psyntax
(define sc-expand3 #f)
(define install-global-transformer #f)
(define $sc-dispatch #f)
(define syntax-violation #f) (define syntax-violation #f)
(define (annotation? x) #f)
(define datum->syntax #f) (define datum->syntax #f)
(define syntax->datum #f) (define syntax->datum #f)
(define identifier? #f) (define identifier? #f)
(define generate-temporaries #f) (define generate-temporaries #f)
(define bound-identifier=? #f) (define bound-identifier=? #f)
(define free-identifier=? #f) (define free-identifier=? #f)
(define sc-expand #f)
(define sc-expand3 #f)
;;; Implementation detail of psyntax -- the thing that does expand-time
;;; dispatch for syntax-case macros
(define $sc-dispatch #f)
;;; Useless crap I'd like to get rid of
(define install-global-transformer #f)
(define (annotation? x) #f)
(define andmap (define andmap
(lambda (f first . rest) (lambda (f first . rest)
@ -213,14 +219,9 @@
(apply f (cons x xr)) (apply f (cons x xr))
(and (apply f (cons x xr)) (andmap first rest))))))))) (and (apply f (cons x xr)) (andmap first rest)))))))))
(define (syncase-error who format-string why what)
(%start-stack 'syncase-stack
(lambda ()
(scm-error 'misc-error who "~A ~S" (list why what) '()))))
;; Until the module system is booted, this will be the current expander.
(primitive-load-path "ice-9/psyntax-pp") (primitive-load-path "ice-9/psyntax-pp")
;; Until the module system is booted, this will be the current expander.
(define %pre-modules-transformer sc-expand) (define %pre-modules-transformer sc-expand)

File diff suppressed because one or more lines are too long

View file

@ -1167,8 +1167,8 @@
(syntax-violation #f "reference to pattern variable outside syntax form" (syntax-violation #f "reference to pattern variable outside syntax form"
(source-wrap e w s mod))) (source-wrap e w s mod)))
((displaced-lexical) ((displaced-lexical)
(syntax-violation #f (source-wrap e w s mod) (syntax-violation #f "reference to identifier outside its scope"
"reference to identifier outside its scope")) (source-wrap e w s mod)))
(else (syntax-violation #f "unexpected syntax" (else (syntax-violation #f "unexpected syntax"
(source-wrap e w s mod)))))) (source-wrap e w s mod))))))