help-make
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Structures or objects in make


From: Robert Mecklenburg
Subject: Structures or objects in make
Date: 20 Nov 2003 10:08:23 -0700

I was thinking the other day that it would occassionally be nice to
have structures in make.  They are useful for collecting related
information and for reducing the number of arguments passed to
functions.  Computed names are often used this way in a less formal
fashion.  I've hacked up a set of functions to implement a simple
structure.  I'd be interested in anyone's reaction.  The code can be
used like this:

# Define a structure foo with two slots a and b.  The default value
# for slot a is 1, for b is hi.
$(call defstruct,foo,a,1,b,hi)

# Allocate an instance of struct foo, call it foo1.
foo1 := $(call new, foo)

# Set foo1.a to 4.
$(call set-value,foo1,a,4)

# Allocate another instance of struct foo, call it foo2.
foo2 := $(call new,foo)
$(call set-value,foo2,b,there)

# Here is another structure with two slots and no default values.
$(call defstruct,file,path,,type,)
file1 := $(call new,file)
$(call set-value,file1,path,/c/home/mecklen/.emacs)
#$(call set-value,file1,type,lisp)

x:
        # foo1   = $(foo1)
        # foo1.a = $(call get-value,foo1,a)
        # foo1.b = $(call get-value,foo1,b)
        # foo1   = $(call print-instance,foo1)
        # foo1   = $(call dump-instance,foo1)
        #
        # foo2   = $(foo2)
        # foo2.a = $(call get-value,foo2,a)
        # foo2.b = $(call get-value,foo2,b)
        # foo2   = $(call print-instance,foo2)
        # foo2   = $(call dump-instance,foo2)
        #
        # file1      = $(file1)
        # file1.path = $(call get-value,file1,path)
        # file1.type = $(call get-value,file1,type)
        # file1      = $(call print-instance,file1)
        # file1      = $(call dump-instance,file1)
        #
        # $(all-instances)
        # $(all-structs)
        # $(call print-struct,foo)
        # $(call print-struct,file)
        # $(call dump-struct,foo)
        # $(call dump-struct,file)

The print-* functions display the user-visible values.  The dump-*
functions reveal the implementation variables as well.  The code to
implement this follows the message (not much documentation I'm
afraid).  This is definitely "proof of concept" quality code.

Currently, values can be null, but cannot contain blanks (this
limitation can be fixed).  I think it is clear this technique could be
extended to include at least single inheritance and obviously it
already supports a certain amount of reflection.  I'm not so sure how
methods would be usefully incorporated.

Comments?
-- 
Robert


# $(next-id) - return a unique number
next-id-counter :=
define next-id
$(words $(next-id-counter))$(eval next-id-counter += 1)
endef

# all-structs - a list of the defined structure names
all-structs :=

value-sep := XxSepxX

# $(call defstruct, struct-name, slot-name, value, ...)
define defstruct
  $(eval all-structs += $1)                                             \
  $(eval $1-def-slotnames :=)                                           \
  $(foreach v, $2$(value-sep)$3 $4$(value-sep)$5 $6$(value-sep)$7       \
               $8$(value-sep)$9 $(10)$(value-sep)$(11),                 \
    $(eval tmp-name  := $(word 1, $(subst $(value-sep), , $v)))         \
    $(if $(tmp-name),                                                   \
      $(eval tmp-value := $(word 2, $(subst $(value-sep), , $v)))       \
      $(eval $1-def-slotnames           += $(tmp-name))                 \
      $(eval $1-def-$(tmp-name)-default := $(tmp-value))))
endef

# all-instances - a list of all the instances of any structure
all-instances :=

# $(call new, struct-name)
define new
$(strip                                                         \
  $(if $(filter $1,$(all-structs)),,                            \
    $(error new on unknown struct '$1'))                        \
  $(eval struct := $1-$(next-id))                               \
  $(eval all-instances += $(struct))                            \
  $(foreach v, $($(strip $1)-def-slotnames),                    \
    $(eval $(struct)-$v := $($(strip $1)-def-$v-default)))      \
  $(struct))
endef

# $(call struct-name,instance-name)
define struct-name
$(firstword $(subst -, ,$($(strip $1))))
endef

# $(call check-params, struct-id, slot-name)
define check-params
  $(if $(filter $($(strip $1)),$(all-instances)),,              \
    $(error Invalid instance '$($(strip $1))'))                 \
  $(if $(filter $2,$($(call struct-name,$1)-def-slotnames)),,   \
    $(error Instance '$($(strip $1))' does not have slot '$2'))
endef

# $(call get-value, struct-id, slot-name)
define get-value
$(strip                         \
  $(call check-params,$1,$2)    \
  $($($1)-$2))
endef

# $(call set-value, struct-id, slot-name)
define set-value
  $(call check-params,$1,$2) \
  $(eval $($(strip $1))-$(strip $2) := $3)
endef

# $(call dump-struct, struct-name)
define dump-struct
{ $1-def-slotnames '$($1-def-slotnames)'        \
  $(foreach s,                                  \
    $($1-def-slotnames),$(strip                 \
    $1-def-$s-default '$($1-def-$s-default)')) }
endef

# $(call print-struct, struct-name)
define print-struct
{ $(foreach s,                  \
    $($1-def-slotnames),$(strip \
    { $s $($1-def-$s-default) })) }
endef

# $(call dump-instance, instance-name)
define dump-instance
{ $(eval tmp-name := $(call struct-name,$1))    \
  $(foreach s,                                  \
    $($(tmp-name)-def-slotnames),$(strip        \
    { $($1)-$s '$($($1)-$s)' })) }
endef

# $(call print-instance, instance-id)
define print-instance
{ $(foreach s,                                          \
    $($(call struct-name,$1)-def-slotnames),$(strip     \
    $(call get-value,$1,$s))) }
endef





reply via email to

[Prev in Thread] Current Thread [Next in Thread]