Module: dfmc-definitions Synopsis: Signature specs. Author: Keith Playford Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND //// Variable, argument, and value specs. define abstract dood-class () lazy constant slot spec-variable-name, required-init-keyword: variable-name:; end dood-class; define sealed domain make (subclass()); define sealed domain initialize (); define function dylan-object-expression () %library-description-object-expression(dylan-library-description()) | (%library-description-object-expression(dylan-library-description()) := dylan-variable-name(#"")); end function; define method spec-type-expression (spec :: ) => (res) dylan-object-expression() end method; define abstract dood-class () lazy constant slot spec-type-expression = #f, init-keyword: type-expression:; end dood-class; define method spec-variable-typed? (var :: ) => (well? :: ) spec-type-expression(var) ~== #f & spec-type-expression ~== dylan-object-expression() end method; define method spec-variable-typed? (var :: ) => (well? :: ) #f end method; define class () end; define class (, ) end class; define method make (class == , #rest all-keys, #key variable-name, type-expression) => (res :: ) if (type-expression) apply(make, , all-keys) else next-method() end if end method; define class () end; define class (, ) end class; define class () end; define class (, ) end class; define class () end class; define method spec-keyword-expression (spec :: ) => (res) // TODO: less consing let name = spec-variable-name(spec); make-literal-fragment(fragment-name(name)) end method; define method spec-default-expression (spec :: ) => (res) %library-description-false-expression(dylan-library-description()) | (%library-description-false-expression(dylan-library-description()) := make(, record: #f, source-position: #f)); end method; define dood-class () lazy constant slot spec-default-expression, required-init-keyword: default-expression:; end dood-class; define dood-class (, ) lazy constant slot spec-keyword-expression, required-init-keyword: keyword-expression:; end dood-class; define method make (class == , #rest all-keys, #key variable-name, keyword-expression, type-expression, default-expression) => (res :: ) local method non-object-type-expression? (type-expression) type-expression & macro-case (type-expression) { } => #f; { ?other:* } => #t; end macro-case; end method, method non-false-default-expression? (default-expression) default-expression & macro-case (default-expression) { #f } => #f; { ?other:* } => #t; end macro-case; end method; if (non-object-type-expression?(type-expression) | keyword-expression) if (keyword-expression) apply(make, , all-keys) else apply(make, , keyword-expression: make-literal-fragment(fragment-name(variable-name)), all-keys) end if elseif (non-false-default-expression?(default-expression)) make(, variable-name: variable-name, default-expression: default-expression) else next-method(, variable-name: variable-name); end if end method; //// SIGNATURE SPECS FOR VARIOUS KINDS OF FUNCTION. define constant = ; // define constant variable-specs = vector; // define constant $empty-variable-specs = #[]; define abstract dood-class () end dood-class; define method make (class == , #rest all-keys, #key argument-rest-variable-spec, argument-key?, value-required-variable-specs, value-rest-variable-spec) => (res :: ) // format-out("ALL-KEYS %=\n", all-keys); if (argument-key?) // complex args? if (value-rest-variable-spec) // complex vals? apply(make, , all-keys) elseif (value-required-variable-specs) apply(make, , all-keys) else apply(make, , all-keys) end if elseif (argument-rest-variable-spec) // rested args? if (value-rest-variable-spec) // complex vals? apply(make, , all-keys) elseif (value-required-variable-specs) apply(make, , all-keys) else apply(make, , all-keys) end if else // simple args if (value-rest-variable-spec) // complex vals? apply(make, , all-keys) elseif (value-required-variable-specs) apply(make, , all-keys) else apply(make, , all-keys) end if end if; end method; define sealed domain make (subclass()); define sealed domain initialize (); define method spec-argument-required-variable-specs (spec :: ) #[] end method; define method spec-argument-rest-variable-spec (spec :: ) #f end method; define method spec-argument-next-variable-spec (spec :: ) #f end method; define method spec-argument-key-variable-specs (spec :: ) #[] end method; define method spec-argument-key? (spec :: ) #f end method; define inline function spec-argument-number-required (spec :: ) => (number :: ) size(spec-argument-required-variable-specs(spec)) end; define method spec-value-required-variable-specs (spec :: ) #[] end method; define inline function spec-value-number-required (spec :: ) => (number :: ) size(spec-value-required-variable-specs(spec)) end; define function spec-default-value-rest-variable-spec () => (spec :: ) %library-description-default-value-rest-spec(dylan-library-description()) | (%library-description-default-value-rest-spec(dylan-library-description()) := make(, variable-name: dylan-variable-name(#"results"))); end function; define method spec-value-rest-variable-spec (spec :: ) spec-default-value-rest-variable-spec() end method; define inline function spec-value-rest? (spec :: ) => (rest? :: ) as-boolean(spec-value-rest-variable-spec(spec)) end; /// VALUES-SPEC define class () end class; define method make (class == , #rest all-keys, #key value-required-variable-specs, value-rest-variable-spec) => (res :: ) // format-out("ALL-KEYS %=\n", all-keys); if (value-rest-variable-spec) apply(make, , all-keys) elseif (value-required-variable-specs) apply(make, , all-keys) else next-method() end if end method; define dood-class () lazy constant slot spec-value-required-variable-specs :: , required-init-keyword: value-required-variable-specs:; end dood-class; define method spec-value-rest-variable-spec (spec :: ) #f end method; define dood-class () lazy constant slot spec-value-rest-variable-spec :: false-or(), required-init-keyword: value-rest-variable-spec:; end dood-class; define primary dood-class () lazy constant slot spec-argument-required-variable-specs :: , required-init-keyword: argument-required-variable-specs:; end dood-class; define class (, ) end class; define class (, ) end class; /// COMPLEX-SIGNATURE-SPEC define primary dood-class () lazy constant slot spec-argument-rest-variable-spec :: false-or(), required-init-keyword: argument-rest-variable-spec:; end dood-class; define class (, ) end class; define class (, ) end class; define primary dood-class () lazy constant slot spec-argument-key-variable-specs :: , required-init-keyword: argument-key-variable-specs:; lazy constant slot spec-argument-key? :: type-union(, singleton(#"all")), required-init-keyword: argument-key?:; end dood-class; define inline function spec-argument-all-keys? (spec :: ) spec-argument-key?(spec) == #"all" end function; define inline function spec-argument-number-keys (spec :: ) => (number :: ) size(spec-argument-key-variable-specs(spec)) end; define inline function spec-argument-rest? (spec :: ) => (rest? :: ) as-boolean(spec-argument-rest-variable-spec(spec)) end; define inline function spec-argument-optionals? (spec :: ) => (optionals? :: ) as-boolean(spec-argument-key?(spec) | spec-argument-rest?(spec)) end; define class (, ) end class; define class (, ) end class; /// METHOD SIGNATURES define abstract dood-class () lazy slot spec-argument-next-variable-spec :: false-or(), required-init-keyword: argument-next-variable-spec:; end dood-class; define method make (class == , #rest all-keys, #key argument-rest-variable-spec, argument-key?, value-required-variable-specs, value-rest-variable-spec) => (res :: ) // format-out("ALL-KEYS %=\n", all-keys); if (argument-key?) // complex args? if (value-rest-variable-spec) // complex vals? apply(make, , all-keys) elseif (value-required-variable-specs) apply(make, , all-keys) else apply(make, , all-keys) end if elseif (argument-rest-variable-spec) // rested args if (value-rest-variable-spec) // complex vals? apply(make, , all-keys) elseif (value-required-variable-specs) apply(make, , all-keys) else apply(make, , all-keys) end if else // simple args if (value-rest-variable-spec) // complex vals? apply(make, , all-keys) elseif (value-required-variable-specs) apply(make, , all-keys) else apply(make, , all-keys) end if end if; end method; define class (, ) end class; define class (, ) end class; define class (, ) end class; define class (, ) end class; define class (, ) end class; define class (, ) end class; define class (, ) end class; define class (, ) end class; define class (, ) end class; /// GENERIC-SIGNATURE-SPEC define constant = ; /// PARSING ROUTINES define serious-program-warning format-string "Unexpected #next in result values declaration - ignoring."; end serious-program-warning; define serious-program-warning format-string "Unexpected #key in result values declaration - ignoring."; end serious-program-warning; define serious-program-warning format-string "Unexpected #all-keys in result values declaration - ignoring."; end serious-program-warning; //// General purpose parameter/values list parser. define method parse-variables-list (fragment) => (requireds :: , next :: false-or(), rest :: false-or(), key? :: , all-keys? :: , keys :: ) collecting (required :: , key :: ) let next = #f; let rest = #f; let key? = #f; let all-keys? = #f; macro-case (fragment) { ?parameters:* } => values(collected(required), next, rest, key?, all-keys?, collected(key)); parameters: { } => #f; { ?:name, ?parameters } => collect-first-into (required, make(, variable-name: name)); { ?:name :: ?type:expression, ?parameters } => collect-first-into (required, make(, variable-name: name, type-expression: type)); { ?:name == ?object:expression, ?parameters } => collect-first-into (required, make(, variable-name: name, type-expression: as-expression(#{ singleton(?object) }))); { ?next-etc } => #f; next-etc: { \#next ?:name, ?rest-etc } => next := make(, variable-name: name); { \#next ?:name :: ?type:expression, ?rest-etc } => next := make(, variable-name: name, type-expression: type); { ?rest-etc } => #f; rest-etc: { } => #f; { \#rest ?:name, ?key-etc } => rest := make(, variable-name: name); { \#rest ?:name :: ?type:expression, ?key-etc } => rest := make(, variable-name: name, type-expression: type); { ?key-etc } => #f; key-etc: { } => #f; { \#key, \#all-keys } => key? := (all-keys? := #t); { \#key ?key-spec-etc } => key? := #t; key-spec-etc: { } => #f; { ?opt-keyword ?:name :: ?type:expression ?opt-default, ?key-spec-etc } => collect-first-into (key, make(, variable-name: name, type-expression: type, default-expression: opt-default, keyword-expression: opt-keyword)); { ?all-keys-etc } => #f; all-keys-etc: { } => #f; { \#all-keys } => all-keys? := #t; opt-keyword: { } => #f; { ?:symbol } => symbol; opt-default: { } => #f; { = ?:expression } => expression; end macro-case; end collecting; end method; //// General purpose signature parser. define method parse-values-list (vals) => (requireds :: false-or(), rest :: false-or()) let (value-requireds, value-next, value-rest, value-key?, value-all-keys?, value-keys) = if (vals) parse-variables-list(vals); else values(#f, #f, #f, #f, #f, #f) end if; when (value-next) note(, source-location: fragment-source-location(vals)); end when; when (value-key?) note(, source-location: fragment-source-location(vals)); end when; when (value-all-keys?) note(, source-location: fragment-source-location(vals)); end when; values(value-requireds, value-rest) end method; define method parse-signature-as (sig-class :: , fragment) => (signature :: , remains) local method parse-using-fragments (sig-class, args, vals) let (requireds, next, rest, key?, all-keys?, keys) = parse-variables-list(args); let (value-requireds, value-rest) = parse-values-list(vals); let sig-spec = make(sig-class, argument-required-variable-specs: requireds, argument-next-variable-spec: next, argument-rest-variable-spec: rest, argument-key?: if (all-keys?) #"all" else key? end, argument-key-variable-specs: keys, value-required-variable-specs: value-requireds, value-rest-variable-spec: value-rest); sig-spec end method; macro-case (fragment) { (?args:*) => (?vals:*); ?more:* } => values(parse-using-fragments(sig-class, args, vals), more); { (?args:*) => (?vals:*) ?more:* } => values(parse-using-fragments(sig-class, args, vals), more); { (?args:*) => ?val:variable; ?more:* } => values(parse-using-fragments(sig-class, args, val), more); { (?args:*); ?more:* } => values(parse-using-fragments(sig-class, args, #f), more); { (?args:*) ?more:* } => values(parse-using-fragments(sig-class, args, #f), more); end macro-case; end method; //// Utilities. define inline function as-boolean (object) => (boolean :: ) if (object) #t else #f end end function; // eof