Module: emulator-environment-backend
Synopsis: Emulator Environment Backend
Author: Andy Armstrong
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
/// Project handling
define constant $emulator-filename = "emulator-application";
//---*** We need some way to uncache projects!
define variable *projects* = make(
);
define class ()
end class ;
define method ensure-emulator-project
(proxy) => (project :: )
element(*projects*, proxy, default: #f)
| (element(*projects*, proxy) := make(, proxy: proxy))
end method ensure-emulator-project;
define method ensure-server-object-of-class
(project :: , object,
class :: subclass())
=> (object :: )
ensure-emulator-project(object)
end method ensure-server-object-of-class;
/// Project opening/closing
define method find-project
(name :: ) => (project :: false-or())
let dylan-project = find-dylan-project(name);
if (dylan-project)
let project = ensure-emulator-project(dylan-project);
ensure-application(project);
project
end
end method find-project;
define method open-project-from-file
(locator :: )
=> (project :: false-or())
let base = locator.locator-base;
base & find-project(base)
end method open-project-from-file;
define method import-project-from-file
(locator :: )
=> (project :: false-or())
open-project-from-file(locator)
end method import-project-from-file;
define method open-projects
() => (projects :: )
as(, *projects*)
end method open-projects;
define method project-used-projects
(project :: ) => (projects :: )
let dylan-libraries
= dylan-library-used-libraries
(compiler-object-proxy(project-library(project)));
map(method (library)
let name = dylan-library-name(library);
find-project(name)
end,
dylan-libraries)
end method project-used-projects;
define method get-environment-object-primitive-name
(project :: , object :: )
=> (name :: )
dylan-project-name(project-proxy(object))
end method get-environment-object-primitive-name;
define method get-environment-object-primitive-name
(project :: , application :: )
=> (name :: )
"dylan-emulator"
end method get-environment-object-primitive-name;
define method get-environment-object-primitive-name
(project :: , database :: )
=> (name :: )
"emulator-database"
end method get-environment-object-primitive-name;
define method project-library
(database :: ) => (library :: )
let project = server-project(database);
let proxy = dylan-project-libraries(project-proxy(project))[0];
make-environment-object(,
project: project,
compiler-object-proxy: proxy)
end method project-library;
define method project-directory
(project :: ) => (directory :: )
dylan-project-directory(project-proxy(project))
end method project-directory;
define method make-source-record
(locator :: ) => (source-record :: )
make(,
location: locator,
date: file-property(locator, #"modification-date"))
end method make-source-record;
define method make-source-record
(filename :: ) => (source-record :: )
make-source-record(as(, file-truename(filename)))
end method make-source-record;
define method project-sources
(project :: ) => (sources :: )
let (libraries, files) = dylan-project-contents(project-proxy(project));
ignore(libraries);
map(method (file)
make-source-record(project-source-location(project, file))
end,
files)
end method project-sources;
/// Source records
define sealed method source-record-colorization-info
(project :: , source-record :: )
=> (info :: singleton(#f))
// No color info in the emulator, sorry.
#f
end method source-record-colorization-info;
/// Project properties
define method project-read-only?
(project :: )
=> (read-only? :: )
#f
end method project-read-only?;
define method project-compiled?
(project :: )
=> (compiled? :: )
//---*** This doesn't matter as linking doesn't mean anything in the emulator
#f
end method project-compiled?;
define method project-compilation-mode
(project :: )
=> (compilation-mode :: )
#"loose"
end method project-compilation-mode;
define method project-compilation-mode-setter
(compilation-mode :: , project :: )
=> (compilation-mode :: )
//---*** Should we try to do this better?
compilation-mode
end method project-compilation-mode-setter;
define method project-target-type
(project :: )
=> (target-type :: )
#"executable"
end method project-target-type;
define method project-target-type-setter
(target-type :: , project :: )
=> (target-type :: )
//---*** Should we try to do this better?
target-type
end method project-target-type-setter;
define method project-major-version
(project :: )
=> (version :: )
1
end method project-major-version;
define method project-major-version-setter
(version :: , project :: )
=> (version :: )
//---*** Should we do better?
version
end method project-major-version-setter;
define method project-minor-version
(project :: )
=> (version :: )
1
end method project-minor-version;
define method project-minor-version-setter
(version :: , project :: )
=> (version :: )
//---*** Should we do better?
version
end method project-minor-version-setter;
/// File extensions
define sideways method project-file-extension
() => (extension :: )
"hdp"
end method project-file-extension;
define sideways method lid-file-extension
() => (extension :: )
"lid"
end method lid-file-extension;
define sideways method dylan-file-extension
() => (extension :: )
"dylan"
end method dylan-file-extension;
/// Project building
define method compile-project
(project :: , #key progress-callback, error-handler) => ()
let records = project-sources(project);
let range = size(records) * 2;
for (record in records,
count from 0 by 2)
let needs-compiling? = ~project-file-compiled?(project, record);
let needs-loading? = ~project-file-loaded?(project, record);
let filename = locator-name(as(, source-record-location(record)));
progress-callback
& progress-callback
(count, range,
label: format-to-string
("%s %s...",
if (needs-compiling?) "Compiling" else "Skipping" end,
filename));
if (needs-compiling?)
compile-project-file(project, record);
needs-loading? := #t;
end;
if (needs-loading?)
progress-callback
& progress-callback
(count + 1, range, label: format-to-string("Loading %s...", filename));
load-project-file(project, record);
end
end;
ensure-application(project)
end method compile-project;
//--- In the emulator we have to build it!
define method parse-project-source
(project :: , #key progress-callback, error-handler) => ()
compile-project(project,
progress-callback: progress-callback,
error-handler: error-handler)
end method parse-project-source;
define method recompile-project
(project :: , #key progress-callback, error-handler) => ()
let files = project-sources(project);
let range = size(files) * 2;
for (file in files,
count from 0 by 2)
progress-callback
& progress-callback
(count, range, label: format-to-string("Compiling %s...", file));
compile-project-file(project, file);
progress-callback
& progress-callback
(count + 1, range, label: format-to-string("Loading %s...", file));
load-project-file(project, file);
end;
ensure-application(project);
end method recompile-project;
define method link-project
(project :: , #key progress-callback, error-handler) => ()
error("Wouldn't it be nice to be able to link in Lisp!")
end method link-project;
define method dylan-project-loaded?
(project :: ) => (loaded? :: )
let project-name = environment-object-primitive-name(project, project);
let library = find-dylan-library(project-name);
block (return)
do-dylan-library-modules
(method (module-name)
ignore(module-name);
return(#t)
end,
library);
#f
end
end method dylan-project-loaded?;
define method ensure-application
(project :: ) => ()
if (dylan-project-loaded?(project))
project-application(project)
:= make(,
project: project,
filename: $emulator-filename);
project-compiler-database(project)
:= make(, project: project)
end
end method ensure-application;
define method update-application
(project :: , #key progress-callback) => ()
//--- These turn out to be the same in the emulator
compile-project(project, progress-callback: progress-callback);
ensure-application(project);
end method update-application;
define method run-application
(project :: , #key debug?, filename, arguments)
=> (application :: false-or())
update-application(project)
end method run-application;
define method compile-project-file
(project :: , record :: )
=> ()
let filename = as(, source-record-location(record));
compile-dylan-project-file(project-proxy(project), filename)
end method compile-project-file;
define method load-project-file
(project :: , record :: )
=> ()
let filename = as(, source-record-location(record));
load-dylan-project-file(project-proxy(project), filename)
end method load-project-file;
define method project-file-compiled?
(project :: , record :: )
=> (compiled? :: )
let filename = as(, source-record-location(record));
dylan-project-file-compiled?(filename)
end method project-file-compiled?;
define method project-file-loaded?
(project :: , record :: )
=> (loaded? :: )
let filename = as(, source-record-location(record));
dylan-project-file-loaded?(project-proxy(project), filename)
end method project-file-loaded?;
define method project-valid-code?
(project :: , code :: , thread :: ,
#key module, runtime-context)
=> (valid :: , warnings :: )
ignore(thread, runtime-context);
let emulator-module
= if (module) compiler-object-proxy(module) else #() end;
let (expression, reason) = parsed-dylan-form(code, module: emulator-module);
if (expression)
values(#t, "")
else
values(#f, reason)
end
end method project-valid-code?;
define method project-execute-code
(project :: , code :: ,
thread :: , #key module)
=> (results :: , success? :: )
ignore(thread);
let emulator-module
= if (module) compiler-object-proxy(module) else #() end;
let results = evaluate-dylan-form(code, module: emulator-module);
if (results)
values(map-as(,
curry(ensure-server-object, project),
results),
#t)
else
values(#[], #f)
end
end method project-execute-code;
define method project-bind-variable
(project :: ,
variable-name :: ,
object :: ,
#key module)
=> (success? :: )
if (module)
bind-dylan-variable(variable-name,
application-object-proxy(object),
compiler-object-proxy(module));
#t
end
end method project-bind-variable;
/// Library handling
define method get-environment-object-primitive-name
(database :: , object :: )
=> (name :: )
dylan-library-name(compiler-object-proxy(object))
end method get-environment-object-primitive-name;
define class (