Module: environment-protocols Synopsis: Environment Protocols Author: Andy Armstrong, Chris Page 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 /// Environment objects define constant = type-union(, ); define open abstract primary class () sealed slot %primitive-name :: false-or() = #f, init-keyword: name:; end class ; define open abstract primary class () constant sealed slot %id :: false-or(), required-init-keyword: id:; end class ; define open generic note-object-properties-changed (client, object :: , type :: ) => (); define generic closed-server-error (object :: ); define open generic environment-object-type (server :: , object :: ) => (type :: false-or()); define open generic environment-object-type-name (object :: ) => (type-name :: ); define open generic environment-object-id (server :: , object :: ) => (id :: false-or()); define open generic environment-object-exists? (server :: , object :: ) => (exists? :: ); define open generic environment-object-primitive-name (server :: , object :: ) => (name :: false-or()); define open generic get-environment-object-primitive-name (server :: , object :: ) => (name :: false-or()); define open generic environment-object-library (server :: , object :: ) => (library :: false-or()); define open generic environment-object-source (server :: , object :: ) => (source :: false-or()); define open generic environment-object-source-location (server :: , object :: ) => (location :: false-or()); define open generic source-location-environment-object (server :: , location :: ) => (object :: false-or()); /// Some convenience functions define method collect-environment-objects (function, server :: , object :: , #rest args) => (objects :: ) let results = make(); apply(function, method (object) add!(results, object) end, server, object, args); results end method collect-environment-objects; /// Environment object types define method environment-object-type (server :: , object :: ) => (type :: false-or()) #f end method environment-object-type; define method environment-object-type-name (object :: ) => (label :: ) "Object" end method environment-object-type-name; /// Environment object naming define method environment-object-primitive-name (server :: , object :: ) => (name :: false-or()) object.%primitive-name | begin let name = get-environment-object-primitive-name(server, object); object.%primitive-name := name end end method environment-object-primitive-name; define method get-environment-object-primitive-name (server :: , object :: ) => (name :: false-or()) #f end method get-environment-object-primitive-name; /// ID handling define method environment-object-id (server :: , object :: ) => (id == #f) #f end method environment-object-id; define method environment-object-id (server :: , object :: ) => (id :: false-or()) object.%id end method environment-object-id; /// Library handling //---*** Hack to make library a valid keyword define method initialize (object :: , #key library :: false-or(), #all-keys) next-method() end method initialize; define open abstract class () constant slot %library :: , required-init-keyword: library:; end class ; define method environment-object-library (project :: , object :: ) => (library :: false-or()) let server = choose-server(project, object); server & environment-object-library(server, object) end method environment-object-library; define method environment-object-library (project :: , object :: ) => (library :: ) ignore(project); object.%library end method environment-object-library; define method environment-object-library (server :: , object :: ) => (library :: false-or()) #f end method environment-object-library; /// Source define method environment-object-source-location (project :: , object :: ) => (location :: false-or()) let server = choose-server(project, object); server & environment-object-source-location(server, object) end method environment-object-source-location; define method environment-object-source-location (server :: , object :: ) => (location :: false-or()) #f end method environment-object-source-location; define method source-location-environment-object (project :: , location :: ) => (object :: false-or()) let database = project-compiler-database(project); database & source-location-environment-object(database, location) end method source-location-environment-object; define method source-location-environment-object (server :: , location :: ) => (object :: false-or()) #f end method source-location-environment-object; define method environment-object-source (server :: , object :: ) => (source :: false-or()) let location = environment-object-source-location(server, object); location & as(, location.copy-source-location-contents) end method environment-object-source; /// Parsing environment objects define sealed generic parse-environment-object-name (name :: , #key, #all-keys) => (id :: false-or()); define function tokenize-string (string :: , separator :: ) => (tokens :: ) let tokens = make(); let old-position :: = 0; let string-size :: = size(string); while (old-position < string-size & string[old-position] == ' ') old-position := old-position + 1 end; let position :: = old-position; while (position < string-size) while (position < string-size & string[position] ~= separator) position := position + 1 end; if (position <= string-size) let end-position = position; while (end-position > old-position & string[end-position - 1] == ' ') end-position := end-position - 1 end; add!(tokens, copy-sequence(string, start: old-position, end: end-position)); old-position := position + 1; while (old-position < string-size & string[old-position] == ' ') old-position := old-position + 1 end; position := old-position end; end; if (old-position < string-size - 1) add!(tokens, copy-sequence(string, start: old-position)) end; tokens end function tokenize-string; define method parse-environment-object-name (name :: , #key module :: false-or(), library :: false-or(), #all-keys) => (id :: false-or()) let (integer, next-index) = string-to-integer(name, default: $minimum-integer); let space-index = find-key(name, curry(\=, ' ')); case integer & integer > 0 & next-index == name.size => integer; space-index => let keyword = as(, copy-sequence(name, end: space-index)); let name-remainder = copy-sequence(name, start: space-index + 1); select (keyword) #"library" => make(, name: name-remainder); #"module" => let library = library | (module & id-library(module)); parse-module-name(name-remainder, library: library); #"method" => let library = library | (module & id-library(module)); parse-method-name(name-remainder, module: module, library: library); otherwise => #f; end; otherwise => parse-definition-name(name, module: module, library: library); end end method parse-environment-object-name; define method parse-module-name (name :: , #key library :: false-or()) => (id :: false-or()) let tokens = tokenize-string(name, ':'); if (~any?(empty?, tokens)) select (size(tokens)) 1 => library & make(, name: tokens[0], library: library); 2 => let library = make(, name: tokens[1]); make(, name: tokens[0], library: library); otherwise => #f; end end end method parse-module-name; define method parse-definition-name (name :: , #key module :: false-or(), library :: false-or()) => (id :: false-or()) let tokens = tokenize-string(name, ':'); if (~any?(empty?, tokens)) select (size(tokens)) 1 => module & make(, name: tokens[0], module: module); 2 => let library = library | (module & id-library(module)); if (library) let module = make(, name: tokens[1], library: library); make(, name: tokens[0], module: module) end; 3 => let library = make(, name: tokens[2]); let module = make(, name: tokens[1], library: library); make(, name: tokens[0], module: module); otherwise => #f; end end end method parse-definition-name; define method parse-method-name (name :: , #key module :: false-or(), library :: false-or()) => (id :: false-or()) local method local-parse-definition-name (name :: ) => (id :: false-or()) parse-definition-name(name, module: module, library: library) end method local-parse-definition-name; let tokens = tokenize-string(name, '('); let (gf, specializers) = if (size(tokens) == 2) let gf = tokens[0]; let rest = tokens[1]; let specializer-tokens = tokenize-string(rest, ')'); let specializers = if (size(specializer-tokens) <= 2) let string = specializer-tokens[0]; if (empty?(string)) #[] else tokenize-string(string, ',') end end; if (specializers) values(gf, specializers) else values(#f, #f) end else values(#f, #f) end; let (function-id, specializer-ids) = if (gf & specializers) let function-id = local-parse-definition-name(gf); let specializer-ids = map-as(, local-parse-definition-name, specializers); values(function-id, specializer-ids) else values(#f, #f) end; if (function-id & every?(rcurry(instance?, ), specializer-ids)) make(, generic-function: function-id, specializers: specializer-ids) end end method parse-method-name; /// Finding environment objects by name define open generic find-environment-object (server :: , name :: type-union(, ), #key, #all-keys) => (object :: false-or()); define method find-environment-object (server :: , id :: , #key, #all-keys) => (object :: false-or()) //--- Do we really want this? #f end method find-environment-object; define method find-environment-object (server :: , id :: , #key, #all-keys) => (object :: false-or()) let project = server.server-project; lookup-environment-object-by-id(project, id) end method find-environment-object; define method find-environment-object (server :: , name :: , #rest keys, #key module :: false-or(), library :: false-or(), #all-keys) => (object :: false-or()) let module-id = if (module) environment-object-id(server, module) end; let library-id = if (library) environment-object-id(server, library) end; let id = parse-environment-object-name (name, module: module-id, library: library-id); id & apply(find-environment-object, server, id, keys) end method find-environment-object;