Sun Apr 19 12:07:59 CEST 2009

compile time bindings

let's change the asmgen macro to add a syntax binding containing
assembler prototype.

Ok.. it's not what it needs to be, but the basic defining form is
there.  Time to give things a name.  How should we call the data
structure that when collected in stacks is symbolic machine code?
Let's call it ``op''.

Then:  - coma manipulates ops
       - assembler translates ops into binary code or simulator code.

So.. Now that the stage is set, what am i going to do with it?  I have
a little bit more information than just op's arity: types and rel/abs
addressing are available too.  Are these interesting?  Not really...
These only matter when the operands are numerical -- not during [op]
transformation phase.

So.. Until there is some form of abstract interpretation possible, we
can't do much more than simply checking existence and arity.

So.. Is it necessary to re-invent structures?  Will I use something a
static struct can't carry?  Yes..  It's exactly the "type" information
associated with the op that can lead to automatic transformer

Let's just see if the static structure is in place to actually verify
existence first.  In pattern-tx.ss

In the pattern expansion, tags now are wrapped in a verify struct
which looks up the tag in the (op) namespace.

Next: unify all definition syntaxes.

;; Main definer body for asm/dasm/op namespaces.
(define-syntax-rule (define-asm/dasm/op static asm-body dasm-body)
      (op) name static)
      (((asm)  name)
       ((dasm) name))
      (let ((asm asm-body)
            (dasm dasm-body))
        ;; backwards compat (later, use reflective operations for this)
        (asm-register! 'name asm)
        (dasm-register! #f #f dasm)
        (values asm dasm)))))

OK.. got arity checking working in pattern-tx.ss :

(define (check-ins type ins)
  (syntax-case ins ()
    ((rator rand ...)
     (if (not (identifier? #'rator))
         (printf "warning: can't verify parametric instruction template ~a\n"
                 (syntax->datum ins))
         (let* ((id (ns-prefixed #'(op) #'rator))
                (op (syntax-local-value id (lambda () #f))))
           (if (not op)
               (printf "warning: unchecked ~a: ~a\n"
                       type (syntax-e id))
               (if (= (op-arity op)
                      (length (syntax->list #'(rand ...))))
                   (void) ;; (printf "ok: ~a\n" (syntax->datum #'rator))
                   (raise-syntax-error #f
                                       "incorrect arity"

Some things can't be checked yet, which produces some warnings.

It's safe to remove the old run-time checking method now.

OK: i've left the symbolic representation as-is, and used the static
info just as a check : it emits warnings when it can't find

Now, is it possible to eliminate current warnings?

It should be possible to separate declaration and implementation of
certain instructions...  Somehow circularity needs to be broken.

The problem is that it is possible to define op manipulations (macros)
without having ops defined, with implementation following later.

Maybe we should allow single assignment of functionality?  This keeps
things declarative, but gets rid of order of particular definitions.

I'm a bit confused.. What's the right question to ask?

The problem is best understood with an example:

       (patterns (macro)
          (([cw a] primitive-exit)  ([jw a]))
          ((primitive-exit)         ([exit])))

This is from core.ss

The problem is that core.ss needs to know the definitions of cw, jw
and exit before this makes sense.

So, instead of using late binding (which is why the assemblers are in
a hash table right now) this could be solved using parameterized
modules : if you want to use core.ss, you need to first provide
meaningful definitions.

The fact that i want to export compile time values makes this