Cinquecento Libraries
Cinquecento provides a syntax-based mechanism for modularizing code. The primary goals of this system are both to allow the creation of libraries that do not assign global variables, and to allow easy swapping of different implementations for the same set of symbols into a given piece of code.
In its most basic instantiation, a library is a file containing definitions for various functions and variables. There is currently no mechanism for putting macros (i.e. @defstx definitions) in a library -- any macros appearing in a library currently gets bound at the top level. Future version of the library system will remedy the macro limitations.
An example library file might look this file, named lib1.cqct:
@local helper_func2; @export( func1, func2 ); @define func1() { ... } @define helper_func2() { ... } @define func2() { ... }
@with_imports( lib1 ) { ... func1(); ... func2(); ... }
@define func1() { ... } @with_imports( (lib1_func1, lib1.func1) ) { ... func1(); //calls above function ... lib1_func1(); //calls func1 from lib1.cqct }
When writing a library one can use @import instead of @with_imports. Consider for example lib2.cqct
@export( something, somethingelse ); @import( lib1 ); @define something() { ... func1(); ... } @define somethingelse() { ... }
@import and @with_imports are both variable argument macros for which all of the following are legal:
@import( lib1, lib2 ); @with_imports( (f1, lib1.func1), lib2 ) { ... } @import( (func1, lib1.func1), (lib1_func2, lib1.func2), lib2 );
If one wants to import a file that is in a directory dir1 that is in the load path, one may use the following constructions:
@import( dir1/lib, (f1, dir1/lib.func1)); @with_imports( dir1/lib, (f1, dir1/lib.func1) ) { ... }
Imported libraries must be present in the load path. That is, when importing from lib1, there must be a lib1.cqct present in the load path at compile time. Recursive or mutually recursive libraries are not allowed. Any @defstx statements in any library are bound globally during compilation.
Dynamically determined imports
The above macros allow one to specify at compile time which library to import and what function renaming to do. If one wants to decide on the library that will be imported at runtime, one can use the dynamic_imports macro. This macro is just like the with_imports macro, except that it evaluates its arguments at runtime and imports libraries specified by the resulting strings. For instance:
lib = "dir1"; // dir1/somthing.cqct defines fn1 lib2 = "dir2"; // dir2/something.cqct also defines fn1 foreach(@lambda(dir) { @dynamic_imports( sprintfa("(f, %s/something.fn1)",dir) ) { f(); } }, [lib,lib2]);
Cinquecento Library Macros
@loadpath("/"); //legal @loadpath(loadpath[0]+"../something"); //legal path = compute_path(); //this statement does not execute until run time @loadpath(path); //error: path is unbound until runtime @loadpath(compute_path()); //error: compute_path is also unbound until runtime
- If the import_spec is (dir/)*libname, then the library libname is loaded
from the loadpath concatenated with the specified directory sequence. All
symbols exported from that library are bound to locals in the current library.
For example:
@import( dir1/lib1 );
- If the import_spec is (sym, (dir/)*libname.esym),
then the library libname is loaded and the symbol esym from that library
is bound to the symbol sym in the current library. For instance
@import( (myfn1, dir1/lib1.fn1) );