; .Chapitre n "Les Re`gles"
(deftrecord Rule
name~symbol
targ~fix
uarg~fix
table~RuleTable
(count~fix 0))
(de Rule (name targ uarg)
(omakeq Rule
name name
targ targ
uarg uarg
table (RuleTable '* '|| 0)))
(defmake {Rule} Rule)
(deftrecord RuleTable
model~symbol
msg~symbol
ltable~(List RuleTable)
level~fix)
(defmake {RuleTable} RuleTable (model msg level))
(demethod {RuleTable}:sem (table) (model msg)
(symbol model msg))
(demethod {RuleTable}:find (table model) (ltable)
(tag found
(while ltable
(if (eq model ({RuleTable}:model (car ltable)))
(exit found (car ltable))
(nextl ltable)))))
(demethod {RuleTable}:find-or-add (table model rule level) (msg ltable)
(or (send 'find table model)
(let ((newtable
(RuleTable model
(send 'tablemsg rule table level)
level)))
(ifn ltable
({RuleTable}:ltable table (list newtable))
(nconc1 ltable newtable))
newtable)))
(demethod {Rule}:tablemsg (rule table level) (name count)
(cond
((= 1 level) name)
((send 'ltable table) (send 'msg (car (send 'ltable table))))
(t (send 'count rule (incr count))
(concat name "!" count))))
(demethod {Rule}:find-or-add (rule lmodel) (name table targ)
(unless (= (length lmodel) targ)
(syserror 'defrule
(catenate name " has " targ "typed arguments")
lmodel))
(let ((model) (level 0))
(while lmodel
(setq model (nextl lmodel)
table (send 'find-or-add table model
rule (incr level))))
table))
(demethod {Rule}:def (rule lmodel args body) (table)
(let ((expansion)
(def))
(send 'find-or-add rule lmodel)
(while lmodel
(setq table (send 'find table (car lmodel))
def (send 'def table (nextl lmodel) args body))
(when def (newl expansion def)))
(nreverse expansion)))
(demethod {RuleTable}:def (table model args body) (level ltable)
(let ((sem (send 'sem table)))
(cond
((eq level 0))
((eq level 1)
(ifn ltable
`(de ,sem ,args ,@body)
(unless (typefn sem)
`(de ,sem ,args
(if (setq {Rule}:sem
(or
(getfn (type ,(cadr args))
',(send 'msg (car ltable))
'||)
(getfn ',(packagecell model)
',(send 'msg table)
'||)))
(funcall {Rule}:sem ,@args)
(syserror 'send
"Rule undefined for types"
(list
',(send 'msg table)
(type ,(car args))
(type ,(cadr args)))))))))
((eq level 2)
`(de ,sem ,args ,@body))
(t (syserror 'defrule "2 typed args only for the moment")))))
(defmacro defrule (name args . body)
(when (eq (setq args ({CeyxSys}:parse-fields args))
'parse-model-error)
(syserror 'defrule "Bad syntax for arguments" (list name args)))
(let ((rule)
(targs)
(uargs)
(lmodel (reverse (mapcar '{Model}:fieldstruct args)))
(expansion))
(setq args (mapcar '{{Model}:Field}:name args))
(while (eq (car lmodel) '*)
(nextl lmodel))
(setq lmodel (nreverse lmodel))
(ifn lmodel
(syserror 'defrule "At least one typed argument"
(list name args))
(setq targs (length lmodel)
uargs (- (length args) (length lmodel))))
(unless (<= targs 2)
(syserror 'defrule
"Au plus deux arguments types actuellement"
name))
(setq rule (or (getprop name '{Ceyx}:rule)
(putprop name (Rule name targs uargs) '{Ceyx}:rule)))
`(progn 'compile
,@({Rule}:def rule lmodel args body)
',name)))
(df undefrule (rulename)
(let ((rule (getprop rulename '{Ceyx}:rule))
(ltable))
(when rule
(setq ltable (send 'ltable (send 'table rule)))
(while ltable (send 'undef (nextl ltable)))
(remprop rulename '{Ceyx}:rule))))
(demethod {RuleTable}:undef (table) (ltable)
(remfn (send 'sem table))
(while ltable (send 'undef (nextl ltable))))