// ********************************************************************* // Copyright (c) 1989, Lawrence Erlbaum Assoc. All rights reserved. // // Use and copying of this software and preparation of derivative works // based upon this software are permitted. Any distribution of this // software or derivative works must comply with all applicable United // States export control laws. // // This software is made available AS IS. The author makes no warranty // about the software, its performance or its conformity to any // specification. // ********************************************************************* // LTD: No macros. #"insist"; define method make-insist-forms (fnname, exps) ~ empty?(exps) & pair(list(#"or", head(exps), list(#"error", "~S failed in ~S", list(#"quote", head(exps)), list(#"quote", fnname))), make-insist-forms(fnname, tail(exps))); end method make-insist-forms; // LTD: No macros. #"define-table"; define method delete-key (table, key) remove-property!(table, key); table; end method delete-key; define method table-keys (table) table & pair(head(table), table-keys(tail(tail(table)))); end method table-keys; *for-keys* := #f; define-table(for-key, key(), *for-keys*); // LTD: No macros. #"for"; define method for-var-forms (l) l & instance?(head(l), ) & pair(head(l), for-var-forms(tail(l))); end method for-var-forms; define method for-body (l) l & (for-key(head(l)) & l | for-body(tail(l))); end method for-body; define method for-expander (var-forms, when-form, body-forms) insist(for, ~ empty?(var-forms), ~ empty?(body-forms)); let vars = map(head, var-forms); let lists = map(method (var-form) head(tail(tail(var-form))); end method, var-forms); let mapfn-body = (for-key(head(body-forms)))(when-form, pair(#"progn", tail(body-forms))); apply(list, head(mapfn-body), list(#"function", list(#"lambda", vars, head(tail(mapfn-body)))), lists); end method for-expander; // LTD: No macros. #"define-for-key"; define-for-key(always: test(body), #"every", if (test) list(#"or", list(#"not", test), body); else body; end if); define-for-key(do: test(body), #"mapc", if (test) list(#"and", test, body); else body; end if); define-for-key(filter: test(body), #"mapcan", begin let fbody = apply(list, #"let", list(list(#"x", body)), #(#(#"and", #"x", #(#"list", #"x")))); if (test) list(#"and", test, fbody); else fbody; end if; end); define-for-key(first: test(body), #"some", if (test) list(#"and", test, body); else body; end if); define-for-key(save: test(body), if (test) #"mapcan"; else #"mapcar"; end if, if (test) list(#"and", test, list(#"list", body)); else body; end if); define-for-key(splice: test(body), #"mapcan", list(#"copy-list", if (test) list(#"and", test, body); else body; end if)); *mop-tables* := #f; define-table(mop-table, table-name(), *mop-tables*); define-table(mop-absts, mop(), mop-table(#"absts")); define-table(mop-all-absts, mop(), mop-table(#"all-absts")); define-table(mop-specs, mop(), mop-table(#"specs")); define-table(mop-slots, mop(), mop-table(#"slots")); define-table(mop-type, mop(), mop-table(#"type")); define method mopp (x) instance?(x, ) | (instance?(x, ) & mop-type(x)); end method mopp; define method instance-mopp (x) mopp(x) & (instance?(x, ) | mop-type(x) == #"instance"); end method instance-mopp; define method abst-mopp (x) mopp(x) & mop-type(x) == #"mop"; end method abst-mopp; define method abstp (abst, spec) abst == spec | member?(abst, mop-all-absts(spec)); end method abstp; define method patternp (x) abstp(#"m-pattern", x); end method patternp; define method groupp (x) abstp(#"m-group", x); end method groupp; define method slot-role (slot) head(slot); end method slot-role; define method slot-filler (slot) head(tail(slot)); end method slot-filler; define method make-slot (role, mop) list(role, mop); end method make-slot; define method role-slot (role, x) insist(role-slot, mopp(x) | instance?(x, )); cl-assoc(role, if (mopp(x)) mop-slots(x); else x; end if); end method role-slot; define method role-filler (role, x) slot-filler(role-slot(role, x)); end method role-filler; define method add-role-filler (role, mop, filler) insist(add-role-filler, mopp(mop), empty?(role-filler(role, mop))); format-out("\n%=:%= <= %=", mop, role, filler); mop-slots(mop) := pair(make-slot(role, filler), mop-slots(mop)); filler; end method add-role-filler; define method link-abst (spec, abst) insist(link-abst, abst-mopp(abst), mopp(spec), ~ abstp(spec, abst)); if (~ abstp(abst, spec)) mop-absts(spec) := pair(abst, mop-absts(spec)); mop-specs(abst) := pair(spec, mop-specs(abst)); redo-all-absts(spec); elseif (nil); end if; spec; end method link-abst; define method unlink-abst (spec, abst) if (abstp(abst, spec)) mop-absts(spec) := remove(mop-absts(spec), abst); mop-specs(abst) := remove(mop-specs(abst), spec); redo-all-absts(spec); elseif (nil); end if; spec; end method unlink-abst; define method redo-all-absts (mop) mop-all-absts(mop) := calc-all-absts(mop); for (spec(in: mop-specs(mop))) #"do"; redo-all-absts(spec); end for; end method redo-all-absts; define method calc-all-absts (mop) cl-remove-duplicates(pair(mop, for (abst(in: mop-absts(mop))) #"splice"; mop-all-absts(abst); end for)); end method calc-all-absts; define method new-mop (name, absts, type, slots) insist(new-mop, instance?(name, ), for (abst(in: absts)) #"always"; mopp(abst); end for); type | (type := calc-type(absts, slots)); name | (name := spec-name(absts, type)); mop-type(name) := type; slots & (mop-slots(name) := slots); for (abst(in: absts)) #"do"; link-abst(name, abst); end for; name; end method new-mop; define method calc-type (absts, slots) for (abst(in: absts)) #"when"; patternp(abst); #"first"; #"mop"; end for | (empty?(slots) & #"mop") | for (slot(in: slots)) #"when"; ~ instance-mopp(slot-filler(slot)); #"first"; #"mop"; end for | #"instance"; end method calc-type; define method spec-name (absts, type) generate-symbol(#"string"((if (type == #"mop") "~S."; else "I-~S."; end if)(#f, head(absts)))); end method spec-name; define method clear-memory () *mop-tables* := #f; new-mop(#"m-root", #f, #"mop", #f); mop-all-absts(#"m-root") := calc-all-absts(#"m-root"); #"m-root"; end method clear-memory; define method all-mops () table-keys(mop-table(#"type")); end method all-mops; define method remove-mop (name) for (abst(in: mop-absts(name))) #"do"; unlink-abst(name, abst); end for; for (table-name(in: table-keys(*mop-tables*))) #"do"; mop-table(table-name) := delete-key(mop-table(table-name), name); end for; end method remove-mop; define method inherit-filler (role, mop) for (abst(in: mop-all-absts(mop))) #"first"; role-filler(role, abst); end for; end method inherit-filler; define method get-filler (role, mop) role-filler(role, mop) | begin let filler = inherit-filler(role, mop); (filler & (instance-mopp(filler) & filler | (abstp(#"m-function", filler) & filler) | begin let fn = get-filler(#"calc-fn", filler); (fn & begin let new-filler = fn(filler, mop); (new-filler & add-role-filler(role, mop, new-filler)); end); end)); end; end method get-filler; define method path-filler (path, mop) for (role(in: path)) #"always"; (mop := get-filler(role, mop)); end for & mop; end method path-filler; define method slots-abstp (mop, slots) abst-mopp(mop) & ~ empty?(mop-slots(mop)) & for (slot(in: mop-slots(mop))) #"always"; satisfiedp(slot-filler(slot), get-filler(slot-role(slot), slots), slots); end for; end method slots-abstp; define method satisfiedp (constraint, filler, slots) let _that = #f; if (_that := empty?(constraint)) _that; elseif (patternp(constraint)) (inherit-filler(#"abst-fn", constraint))(constraint, filler, slots); elseif (_that := abstp(constraint, filler)) _that; elseif (instance-mopp(constraint)) empty?(filler); elseif (filler) slots-abstp(constraint, filler); else #f; end if; end method satisfiedp; define method mop-includesp (mop1, mop2) mop-type(mop1) == mop-type(mop2) & for (slot(in: mop-slots(mop2))) #"always"; slot-filler(slot) == get-filler(slot-role(slot), mop1); end for & mop1; end method mop-includesp; define method mop-equalp (mop1, mop2) mop-includesp(mop2, mop1) & mop-includesp(mop1, mop2); end method mop-equalp; // // (DEFUN GET-TWIN (MOP) // (FOR (ABST :IN (MOP-ABSTS MOP)) // :FIRST (FOR (SPEC :IN (MOP-SPECS ABST)) // :WHEN (NOT (EQL SPEC MOP)) // :FIRST (MOP-EQUALP SPEC MOP)))) // define method get-twin (mop) for (abst(in: mop-absts(mop))) #"first"; for (spec(in: mop-specs(abst))) #"when"; ~ (spec == mop); #"first"; mop-includesp(spec, mop) & (~ groupp(mop) | mop-includesp(mop, spec)) & spec; end for; end for; end method get-twin; define method refine-instance (instance) for (abst(in: mop-absts(instance))) #"when"; mops-abstp(mop-specs(abst), instance); #"first"; unlink-abst(instance, abst); refine-instance(instance); end for; end method refine-instance; define method mops-abstp (mops, instance) ~ empty?(for (mop(in: mops)) #"when"; slots-abstp(mop, instance); #"save"; link-abst(instance, mop); end for); end method mops-abstp; define method install-instance (instance) refine-instance(instance); let twin = get-twin(instance); if (twin) remove-mop(instance); twin; elseif (has-legal-absts-p(instance)) instance; else remove-mop(instance); #f; end if; end method install-instance; define method has-legal-absts-p (instance) for (abst(in: mop-absts(instance))) #"when"; ~ legal-abstp(abst, instance); #"do"; unlink-abst(instance, abst); end for; mop-absts(instance); end method has-legal-absts-p; define method legal-abstp (abst, instance) mop-slots(abst) & for (spec(in: mop-specs(abst))) #"always"; instance-mopp(spec); end for; end method legal-abstp; define method install-abstraction (mop) let twin = get-twin(mop); if (twin) remove-mop(mop); twin; else reindex-siblings(mop); end if; end method install-abstraction; define method reindex-siblings (mop) for (abst(in: mop-absts(mop))) #"do"; for (spec(in: mop-specs(abst))) #"when"; instance-mopp(spec) & slots-abstp(mop, spec); #"do"; unlink-abst(spec, abst); link-abst(spec, mop); end for; end for; mop; end method reindex-siblings; define method slots->mop (slots, absts, must-work) insist(slots->mop, ~ empty?(absts), for (abst(in: absts)) #"always"; mopp(abst); end for); empty?(slots) & empty?(tail(absts)) & head(absts) | begin let type = (slots & not(instance?(head(slots), )) & head(slots)); (type & (slots := tail(slots))); let mop = new-mop(#f, absts, type, slots); let result = if (instance-mopp(mop)) install-instance(mop); else install-abstraction(mop); end if; insist(slots->mop, (result | empty?(must-work))); result; end; end method slots->mop; // LTD: No macros. #"defmop"; define method forms->slots (slot-forms) for (slot-form(in: slot-forms)) #"save"; if (not(instance?(slot-form, ))) slot-form; else make-slot(slot-role(slot-form), begin let abst = head(tail(slot-form)); insist(forms->slots, not(instance?(abst, ))); abst & slots->mop(forms->slots(tail(tail(slot-form))), list(abst), #t); end); end if; end for; end method forms->slots; define method group-size (x) groupp(x) & size(mop-slots(x)); end method group-size; define method group->list (group) group & insist(group->list, groupp(group)) & for (index(in: make-m-n(1, group-size(group)))) #"filter"; role-filler(index, group); end for; end method group->list; define method list->group (l) if (empty?(l)) #"i-m-empty-group"; else slots->mop(for (x(in: l)) i(in: make-m-n(1, size(l))); #"save"; make-slot(i, x); end for, #(#"m-group"), #t); end if; end method list->group; define method make-m-n (m, n) insist(make-m-n, instance?(m, ), instance?(n, )); if (m == n) list(n); elseif (m < n) pair(m, make-m-n(m + 1, n)); else pair(m, make-m-n(m - 1, n)); end if; end method make-m-n; define method dah (mop) print(tree->list(mop, specs->list, #f), *standard-output*, pretty: #t); end method dah; define method dph (mop) print(tree->list(mop, slots->forms, #f), *standard-output*, pretty: #t); end method dph; define method specs->list (mop, visited) for (spec(in: mop-specs(mop))) #"save"; tree->list(spec, specs->list, visited); end for; end method specs->list; define method slots->forms (mop, visited) for (slot(in: mop-slots(mop))) #"save"; pair(slot-role(slot), mop->form(slot-filler(slot), visited)); end for; end method slots->forms; define method mop->form (mop, visited) tree->list(mop, slots->forms, visited); end method mop->form; define method tree->list (mop, fn, visited) if (member?(mop, visited)) list(mop); else visited := pair(mop, visited); pair(mop, fn(mop, visited)); end if; end method tree->list; define method constraint-fn (constraint, filler, slots) #t; end method constraint-fn; define method not-constraint (constraint, filler, slots) insist(not-constraint, ~ empty?(filler)); ~ satisfiedp(get-filler(#"object", constraint), filler, slots); end method not-constraint; define method get-sibling (pattern, mop) for (abst(in: mop-absts(mop))) #"first"; for (spec(in: mop-specs(abst))) #"when"; instance-mopp(spec) & ~ (spec == mop) & ~ abstp(#"m-failed-solution", spec); #"first"; spec; end for; end for; end method get-sibling;