Wed Apr 2 09:15:33 EDT 2008
purr18 / redefine
maybe leave the incremental compilation bit till later, and try to
port the core purrr18 language first, then figure out how to modify
the assembler. maybe the latter should really be kept separate so i
can target external assemblers.
ok.. the next problem is the use of a lot of undefined bindings in the
previous pic18 spec. it needs a proper mechanism for target plugin
behaviour. one way to solve it is to wipe it under the carpet and move
it to the assembler, since that's symbolic. but this probably won't
work for everything. i.e. if a DUP is defined in the kernel, it needs
to be replaced in all the code that uses it. it's true late binding.
there are 2 paths to take, the static one (units + explicit linking)
and the dynamic one (just redefine the macro structs). since the
core language is macros only, that's ok.
there is one problem though: the core language's code should be
independent of target. if some target decides that a core macro needs
to change, core shouldn't have to know that. that means it has to
provide an exact specification of all words that can be
this looks like too much of a hassle, so let's go for redefine using
mutation of word structs + some mechanism to at least keep track of
what about this: allow for macros to be redefined by checking for the
availability of the identifier. if they are defined, bind the old
functionality to a name SUPER, so one could do things like:
(([drop] dup) ([movf 'INDF0 0 0]))
((dup) (macro: SUPER))
this makes sure that words are at least defined, and it also makes the
hierarchy between redefines clear (= same as module hierarchy).
what model is this? it's not late binding (at least one binding needs
to be present).
* fix 'insert' syntax to something simpler. OK
* add redefines to the macro syntax
think more about why this is a bad idea.
redefine can be a postprocess step by having it refer to itself first,
then to swap the old and new implementations.
why are assignments bad? no sharing is possible. that's where
parameters are better in some cases: at least the extent of the side
effect is limited. so should i just make each word a parameter?
- if the name exists, it doesn't get redefined, but the word that's
returned by the wrapper is swapped with the one defined
(define <name> <body) ->
(letrec ((macro/super <body>))
(swap-word! <name> macro/super))
can this be handled by define-ns ?
no.. it needs to be at the module language level: that's where the
define-ns macro is inserted. nope.. it needs to be deeper than that.
got it working with this:
(define (define/swap!-ns-tx define stx)
(syntax-case stx ()
((swap! ns name val)
(let ((id (ns-prefixed #'ns #'name)))
(if (identifier-binding id)
;; introduce 'super' as temporary self-ref
#'ns (datum->syntax #'val 'super))))
#`(letrec ((#,super val))
;; swap to undo self-ref
(swap! #,super #,id)))
#`(#,define #,id val))))))
(define/swap!-ns word-swap! (macro) dup (macro: super super))
-> expands to
(letrec-values (((macro/super) (macro: super super)))
(word-swap! macro/super macro/dup))
(macro/dup (make-state '() '((qw 123))))
-> #(struct:state () ((qw 123) (qw 123) (qw 123)))
the module level thing didn't work because the 'require' statements
were not expanded yet, so bindings were not there.
now, the test case with forth lang doesnt work. FIXED: problem was
the introduction of 'super' from syntax context != source.