diff options
author | Google Code Exporter <GoogleCodeExporter@users.noreply.github.com> | 2016-02-25 22:24:50 -0500 |
---|---|---|
committer | Google Code Exporter <GoogleCodeExporter@users.noreply.github.com> | 2016-02-25 22:24:50 -0500 |
commit | 0f74e7ad4a0d2e57193eb6b174167c691eba7e81 (patch) | |
tree | 4f56a9b78e26806e64098c38785694ecf3530ccc |
Migrating wiki contents from Google Codewiki
-rw-r--r-- | BuildingFoment.md | 48 | ||||
-rw-r--r-- | ControlFeaturesAPI.md | 85 | ||||
-rw-r--r-- | ControlFeaturesInternals.md | 107 | ||||
-rw-r--r-- | FileSystemAPI.md | 94 | ||||
-rw-r--r-- | Foment.md | 45 | ||||
-rw-r--r-- | HashContainerAPI.md | 151 | ||||
-rw-r--r-- | InputAndOutput.md | 116 | ||||
-rw-r--r-- | License.md | 21 | ||||
-rw-r--r-- | MemoryManagementAPI.md | 133 | ||||
-rw-r--r-- | MemoryManagementInternals.md | 31 | ||||
-rw-r--r-- | MiscellaneousAPI.md | 73 | ||||
-rw-r--r-- | MiscellaneousInternals.md | 43 | ||||
-rw-r--r-- | ProjectHome.md | 27 | ||||
-rw-r--r-- | R7RS.md | 14 | ||||
-rw-r--r-- | R7RSExtensions.md | 19 | ||||
-rw-r--r-- | ReleaseNotes.md | 68 | ||||
-rw-r--r-- | RunningFoment.md | 95 | ||||
-rw-r--r-- | SRFISupport.md | 17 | ||||
-rw-r--r-- | Sockets.md | 112 | ||||
-rw-r--r-- | SynchronizationAndThreadAPI.md | 157 | ||||
-rw-r--r-- | UsingLibraries.md | 49 |
21 files changed, 1505 insertions, 0 deletions
diff --git a/BuildingFoment.md b/BuildingFoment.md new file mode 100644 index 0000000..8e707cd --- /dev/null +++ b/BuildingFoment.md @@ -0,0 +1,48 @@ +# Building Foment # + +Use git to get a local copy of the repository. + +## Windows ## + +Install Microsoft Visual C++ Express 2010 or Microsoft Visual Studio Express 2013 for Desktop. +Use the 2013 version if you want to build a 64 bit version. +Note that Microsoft Visual C++ Express and Microsoft Visual Studio Express do not cost +anything. + +2010: Open a Visual Studio Command Prompt; this will set your environment variables correctly. + +2013 for 32 bit: Open a Developer Command Prompt for VS2013; this will set your environment +variables correctly. + +2013 for 64 bit: Open VS2013 x64 Cross Tools Command Prompt; this will set your environment +variables correctly. + +``` +cd foment\windows +nmake +nmake test +nmake stress +``` + +`debug\foment.exe` contains extra checks and debugging information so that you can use the +debugger built into Visual Studio to debug the C level code only. + +`release\foment.exe` should be a little faster, but I recommend using `debug\foment.exe` at +this point. + +## Linux ## + +I have built it on Debian 32 bit and Debian 64 bit. + +``` +cd foment/unix +make +make test +make stress +``` + +`debug/foment` contains extra checks and debugging information so that you can use gdb +to debug the C level code only. + +`release/foment` should be a little faster, but I recommend using `debug/foment` at +this point.
\ No newline at end of file diff --git a/ControlFeaturesAPI.md b/ControlFeaturesAPI.md new file mode 100644 index 0000000..ddb730c --- /dev/null +++ b/ControlFeaturesAPI.md @@ -0,0 +1,85 @@ +# Control Features API # + +`(import (foment base))` to use these procedures. + +## Continuations ## + +procedure: `(call-with-continuation-prompt` _proc_ _prompt-tag_ _handler_ _arg_ _..._`)` + +Mark the current continuation with _prompt\_tag_ and apply _proc_ to _arg_ _..._. + +Within the dynamic extent of _proc_ if `abort-current-continuation` is called with _prompt\_tag_ +then the continuation is reset to the closest _prompt\_tag_ mark, _handler_ is applied +to the _val_ _..._ passed to `abort-current-continuation`. And the result of +`call-with-continuation-prompt` is the result of _handler_. + +Otherwise, _proc_ returns normally and the result of `call-with-continuation-prompt` is the +result of _proc_. + +If _prompt\_tag_ is the default prompt tag, then _handler_ must be `default-prompt-handler`. + +procedure: `(abort-current-continuation` _prompt-tag_ _val_ _..._`)` + +Reset the continuation to the nearest _prompt\_tag_ mark. Apply _handler_ +(from `call-with-continuation-prompt`) to the _val_ _..._. + +If aborting to the default prompt tag, pass a thunk as the _val_ _..._. + +procedure: `(default-prompt-tag)` +<br>procedure: <code>(default-continuation-prompt-tag)</code> + +Return the default prompt tag. The start of the continuation for every thread has a mark for the<br> +default prompt tag.<br> +<br> +procedure: default-prompt-handler<br> +<br> +<code>default-prompt-handler</code> reinstalls the mark for the default prompt tag and calls the thunk.<br> +<br> +<pre><code>(define (default-prompt-handler proc)<br> + (call-with-continuation-prompt proc (default-prompt-tag) default-prompt-handler))<br> +</code></pre> + +<h2>Continuation Marks</h2> + +A continuation mark consists of a key and a value.<br> +<br> +syntax: <code>(with-continuation-mark</code> <i>key</i> <i>val</i> <i>expr</i><code>)</code> + +The front of the continuation is marked with <i>key</i> and <i>val</i>. If the front of the continuation<br> +already contains a mark with <i>key</i> then it is updated to have <i>val</i> as its value. Otherwise, a<br> +new mark is added for <i>key</i> and <i>val</i>. If the front of the continuation already has any marks,<br> +irrespective of what keys those marks contain, then <i>expr</i> is called in the tail position.<br> +<br> +<pre><code>(with-continuation-mark 'key 1<br> + (with-continuation-mark 'key 2<br> + (with-continuation-mark 'key 3<br> + (current-continuation-marks))))<br> +=> ((key . 3))<br> +<br> +(define (count n m)<br> + (if (= n m)<br> + (current-continuation-marks)<br> + (let ((r (with-continuation-mark 'key n (count (+ n 1) m))))<br> + r)))<br> +(count 0 4) => (((key . 3)) ((key . 2)) ((key . 1)) ((key . 0)))<br> +</code></pre> + +procedure: <code>(current-continuation-marks)</code> + +Return all marks for the current continuation as a list of lists of marks.<br> +Each mark consists of a pair: <code>(</code><i>key</i> . <i>value</i><code>)</code>. The lists of marks are ordered from<br> +front to back (inner to outer).<br> +<br> +<h2>Notify and Control-C</h2> + +procedure: <code>(with-notify-handler</code> <i>handler</i> <i>thunk</i><code>)</code> + +Execute <i>thunk</i>. If any notifications happen in the dynamic extent of <i>thunk</i> then <i>handler</i> will<br> +be called.<br> +<br> +procedure: <code>(set-ctrl-c-notify! _disposition_</code>)`<br> +<br> +<i>disposition</i> must be <code>exit</code>, <code>ignore</code>, or <code>broadcast</code>. If <i>disposition</i> is <code>exit</code>, then the<br> +program will exit when ctrl-c is pressed. If <i>disposition</i> is <code>ignore</code>, then ctrl-c will be<br> +ignored. If <i>disposition</i> is <code>broadcast</code>, then call every notify <i>handler</i> for every thread<br> +with <code>sigint</code> as the argument.
\ No newline at end of file diff --git a/ControlFeaturesInternals.md b/ControlFeaturesInternals.md new file mode 100644 index 0000000..1e957dd --- /dev/null +++ b/ControlFeaturesInternals.md @@ -0,0 +1,107 @@ +# Control Features Internals # + +## Continuation Marks ## + +The implementation of continuation marks is based on John Clements' dissertation: +_Portable and high-level access to the stack with Continuation Marks_. + +The syntax `with-continuation-mark` expands directly into a call to the procedure +`%mark-continuation`. + +``` +(define-syntax with-continuation-mark + (syntax-rules () + ((_ key val expr) (%mark-continuation key val (lambda () expr))))) +``` + +procedure: `(%mark-continuation` _who_ _key_ _val_ _thunk_`)` + +`%mark-continuation` looks at the front of the continuation to see what procedure it would +return to, if it were to return. If that procedure is `%mark-continuation` and has the same +_who_ then +an existing mark with the same key can be updated or a new mark can be added, and a tail call +can be made to _thunk_. Otherwise, a new mark is placed on the front of the continuation +and a normal call is make to _thunk_. Note that updating an existing mark only applies for marks +at the front of the continuation. + +``` +(define dynamic-stack '()) + +(define (update-mark key val) + (let ((p (assq key (car dynamic-stack)))) + (if p + (set-cdr! p val) + (set-car! dynamic-stack (cons (cons key val) (car dynamic-stack)))))) + +(define (%mark-continuation key val thunk) + (if (eq? (continuation-front-procedure) %mark-continuation) + (begin + (update-mark key val) + (thunk)) + (begin + (set! dynamic-stack (cons (list (cons key val)) dynamic-stack)) + (let-values ((v (thunk))) + (set! dynamic-stack (cdr dynamic-stack)) + (apply values v)))))) +``` + +The procedure `continuation-front-procedure` returns the procedure on the front of the +continuation. + +``` +(define (a) + (define (b) + (continuation-front-procedure)) + (let ((p (b))) + (eq? (b) a))) +=> #t +``` + +In the actual implementation, `%mark-continuation` is a primitive. Frames on the dynamic stack +are created by calls to `%mark-continuation`. Each frame is an object containing a list of marks +and a location in the continuation. + +procedure: `(%dynamic-stack)` +<br> procedure: <code>(%dynamic-stack</code> <i>stack</i><code>)</code> + +Get and set the dynamic stack.<br> +<br> +procedure: <code>(%dynamic-marks _dynamic_ </code>)`<br> +<br> +Get the list of marks contained in the <i>dynamic</i> frame.<br> +<br> +<pre><code>(let ((ml (with-continuation-mark 'key 10<br> + (%dynamic-marks (car (%dynamic-stack))))))<br> + ml)<br> +=> ((key . 10))<br> +</code></pre> + +procedure: <code>(%find-mark</code> <i>key</i> <i>default</i><code>)</code> + +Find the first mark with <i>key</i> and return its values; otherwise return <i>default</i>.<br> +<br> +<h2>Continuations</h2> + +The implementation of continuations is inspired by these two papers:<br> +<br> +Matthew Flatt, Gang Yu, Robert Bruce Findler, and Matthias Felleisen.<br> +<i>Adding Delimited and Composable Control to a Production Programming Environment</i> +<a href='http://www.cs.utah.edu/plt/publications/icfp07-fyff.pdf'>http://www.cs.utah.edu/plt/publications/icfp07-fyff.pdf</a> + +Marc Feeley. <i>A Better API for First-Class Continuations</i> +<a href='http://www.schemeworkshop.org/2001/feeley.pdf'>http://www.schemeworkshop.org/2001/feeley.pdf</a> + +Note that delimited and composable continuations are not yet supported.<br> +<br> +procedure: <code>(%capture-continuation</code> <i>proc</i><code>)</code> + +Capture the current continuation as an object and pass it to <i>proc</i>.<br> +<br> +procedure: <code>(%call-continuation</code> <i>cont</i> <i>thunk</i><code>)</code> + +Replace the current continuation with <i>cont</i> and call <i>thunk</i>. The continuation of <i>thunk</i> +is <i>cont</i>.<br> +<br> +procedure: <code>(%abort-dynamic</code> <i>dynamic</i> <i>thunk</i><code>)</code> + +Unwind the current continuation to location of <i>dynamic</i> and call <i>thunk</i>.<br> diff --git a/FileSystemAPI.md b/FileSystemAPI.md new file mode 100644 index 0000000..8c3fb30 --- /dev/null +++ b/FileSystemAPI.md @@ -0,0 +1,94 @@ +# File System API # + +`(import (foment base))` to use these procedures. + +## Windows and Unix ## + +procedure: `(file-size` _filename_`)` + +Return the size of _filename_ in bytes. +If _filename_ does not exist, an error that satifies `file-error?` is signaled. + +procedure: `(file-regular?` _filename_`)` + +Return `#t` if _filename_ is a regular file and `#f` otherwise. + +procedure: `(file-directory?` _filename_`)` + +Return `#t` if _filename_ is a directory and `#f` otherwise. + +procedure: `(file-symbolic-link?` _filename_`)` + +Return `#t` if _filename_ is a symbolic link and `#f` otherwise. + +procedure: `(file-readable?` _filename_`)` + +Return `#t` if _filename_ is readable and `#f` otherwise. + +procedure: `(file-writable?` _filename_`)` + +Return `#t` if _filename_ is writable and `#f` otherwise. + +procedure: `(file-stat-mtime` _filename_`)` + +Return when _filename_ was last modified in seconds since the beginning of time. +If _filename_ does not exist, an error that satifies `file-error?` is signaled. + +procedure: `(file-stat-atime` _filename_`)` + +Return when _filename_ was last accessed in seconds since the beginning of time. +If _filename_ does not exist, an error that satifies `file-error?` is signaled. + +procedure: `(create-symbolic-link` _old\_path_ _new\_path_`)` + +Create a symbolic link named _new\_path_ that points at _old\_path_. +If the operation fails, an error that satifies `file-error?` is signaled. + +procedure: `(rename-file` _old\_path_ _new\_path_`)` + +Rename file from _old\_path_ to _new\_path_, overwriting _new\_path_ if it already exists. +If the operation fails, an error that satifies `file-error?` is signaled. + +procedure: `(create-directory` _path_`)` + +Create a directory named _path_. +If the operation fails, an error that satifies `file-error?` is signaled. + +procedure: `(delete-directory` _path_`)` + +Delete the directory named _path_. +If the operation fails, an error that satifies `file-error?` is signaled. + +procedure: `(list-directory` _path_`)` + +Return the contents of the directory named _path_ as a list of strings, where each string is the +name of a file contained in the directory. `.` and `..` are not included in the list. +If the operation fails, an error that satifies `file-error?` is signaled. + +procedure: `(current-directory)` +procedure: `(current-directory` _path_`)` + +Without an argument, the current working directory is returned. With an argument, the current +working directory is set to _path_. +If the operation fails, an error that satifies `file-error?` is signaled. + +## Windows Only ## + +procedure: `(file-archive?` _filename_`)` + +Return `#t` if _filename_ has the archive attribute and `#f` otherwise. + +procedure: `(file-system?` _filename_`)` + +Return `#t` if _filename_ has the system attribute and `#f` otherwise. + +procedure: `(file-hidden?` _filename_`)` + +Return `#t` if _filename_ has the hidden attribute and `#f` otherwise. + +## Unix Only ## + +procedure: `(file-executable?` _filename_`)` + +Return `#t` if _filename_ is executable and `#f` otherwise. + diff --git a/Foment.md b/Foment.md new file mode 100644 index 0000000..a63f8d5 --- /dev/null +++ b/Foment.md @@ -0,0 +1,45 @@ +# API # + +[R7RS](R7RS.md) + +[RunningFoment](RunningFoment.md) + +[InputAndOutput](InputAndOutput.md) + +[Sockets](Sockets.md) + +[UsingLibraries](UsingLibraries.md) + +[SRFISupport](SRFISupport.md) + +[MemoryManagementAPI](MemoryManagementAPI.md) + +[SynchronizationAndThreadAPI](SynchronizationAndThreadAPI.md) + +[ControlFeaturesAPI](ControlFeaturesAPI.md) + +[FileSystemAPI](FileSystemAPI.md) + +[HashContainerAPI](HashContainerAPI.md) + +[MiscellaneousAPI](MiscellaneousAPI.md) + +[R7RSExtensions](R7RSExtensions.md) + +# Internals # + +[MemoryManagementInternals](MemoryManagementInternals.md) + +[ControlFeaturesInternals](ControlFeaturesInternals.md) + +[MiscellaneousInternals](MiscellaneousInternals.md) + +[BuildingFoment](BuildingFoment.md) + + +--- + + +[ReleaseNotes](ReleaseNotes.md) + +[License](License.md)
\ No newline at end of file diff --git a/HashContainerAPI.md b/HashContainerAPI.md new file mode 100644 index 0000000..7313225 --- /dev/null +++ b/HashContainerAPI.md @@ -0,0 +1,151 @@ +# Hash Container API # + +`(import (foment base))` to use these procedures. + +## Hash Maps ## + +procedure: `(make-hash-map)` +<br>procedure: <code>(make-hash-map</code> <i>comparator</i><code>)</code> + +Return a new hash map. Use <i>comparator</i> as the comparator for the new hash map if specified;<br> +otherwise, use <code>default-comparator</code>.<br> +<br> +procedure: <code>(alist->hash-map</code> <i>alist</i><code>)</code> +<br>procedure: <code>(alist->hash-map</code> <i>alist</i> <i>comparator</i><code>)</code> + +Takes an association list, <i>alist</i>, and returns a new hash map which maps the <code>car</code> of every<br> +element in <i>alist</i> to the <code>cdr</code> of corresponding elements in <i>alist</i>. Use <i>comparator</i> as the<br> +comparator for the new hash map if specified; otherwise, use <code>default-comparator</code>.<br> +If some key occurs multiple times in <i>alist</i>, the value in the first association will take<br> +precedence over later ones.<br> +<br> +procedure: <code>(hash-map? _obj_</code>)`<br> +<br> +Return <code>#t</code> if <i>obj</i> is a hash map and <code>#f</code> otherwise.<br> +<br> +procedure: <code>(hash-map-size</code> <i>hash-map</i><code>)</code> +<br>procedure: <code>(hash-map-size</code> <i>eq-hash-map</i><code>)</code> + +Return the number of entries in <i>hash-map</i> or <i>eq-hash-map</i>.<br> +<br> +procedure: <code>(hash-map-ref</code> <i>hash-map</i> <i>key</i> <i>default</i><code>)</code> + +Return the value associated with <i>key</i> in <i>hash-map</i>; otherwise return <i>default</i>.<br> +<br> +procedure: <code>(hash-map-set!</code> <i>hash-map</i> <i>key</i> <i>value</i><code>)</code> + +Set the value associated with <i>key</i> in <i>hash-map</i> to be <i>value</i>. If there already exists a value<br> +associated with <i>key</i> it is replaced.<br> +<br> +procedure: <code>(hash-map-delete!</code> <i>hash-map</i> <i>key</i><code>)</code> +If <i>key</i> exists in <i>hash-map</i> remove <i>key</i> and its associated value.<br> +<br> +procedure: <code>(hash-map-contains?</code> <i>hash-map</i> <i>key</i><code>)</code> + +Return <code>#t</code> if <i>key</i> exists in <i>hash-map</i> and <code>#f</code> otherwise.<br> +<br> +procedure: <code>(hash-map-update!</code> <i>hash-map</i> <i>key</i> <i>proc</i> <i>default</i><code>)</code> +<br>procedure: <code>(</code><i>proc</i> <i>value</i><code>)</code> +Applies <i>proc</i> to the value in <i>hash-map</i> associated with <i>key</i>, or to <i>default</i> if <i>hash-map</i> +does not contain an association for <i>key</i>. The <i>hash-map</i> is then changed to associate <i>key</i> +with the value returned by <i>proc</i>.<br> +<br> +procedure: <code>(hash-map-copy</code> <i>hash-map</i><code>)</code> +Return a copy of <i>hash-map</i>.<br> +<br> +procedure: <code>(hash-map-keys</code> <i>hash-map</i><code>)</code> +<br>procedure: <code>(hash-map-keys</code> <i>eq-hash-map</i><code>)</code> +Returns a vector of all keys in <i>hash-map</i> or <i>eq-hash-map</i>. The order of the vector is<br> +unspecified.<br> +<br> +procedure: <code>(hash-map-entries</code> <i>hash-map</i><code>)</code> +<br>procedure: <code>(hash-map-entries</code> <i>eq-hash-map</i><code>)</code> +Returns two values, a vector of the keys in <i>hash-map</i> or <i>eq-hash_map</i>, and<br> +a vector of the corresponding values.<br> +<br> +procedure: <code>(hash-map-comparator</code> <i>hash-map</i><code>)</code> +Returns the comparator used by <i>hash-map</i>.<br> +<br> +procedure: <code>(hash-map-walk</code> <i>hash-map</i> <i>proc</i><code>)</code> +<br>procedure: <code>(hash-map-walk</code> <i>eq-hash-map</i> <i>proc</i><code>)</code> +<br>procedure: <code>(</code><i>proc</i> <i>key</i> <i>value</i><code>)</code> +Call <i>proc</i> for each association in <i>hash-map</i> or <i>eq-hash_map</i>, giving the key of the<br> +association as <i>key</i> and the value of the association as <i>value</i>. The results of <i>proc</i> are<br> +discarded. The order in which <i>proc</i> is called for the different associations is unspecified.<br> +<br> +procedure: <code>(hash-map-fold</code> <i>hash-map</i> <i>func</i> <i>init</i><code>)</code> +<br>procedure: <code>(hash-map-fold</code> <i>eq-hash-map</i> <i>func</i> <i>init</i><code>)</code> +<br>procedure: <code>(</code><i>func</i> <i>key</i> <i>value</i> <i>accum</i><code>)</code> + +Call <i>func</i> for every association in <i>hash-map</i> or <i>eq-hash-map</i> with three arguments: the<br> +key of the association, <i>key</i>, the value of the association, <i>value</i>, and an accumulated<br> +value, <i>accum</i>. For the first invocation of <i>func</i>, <i>accum</i> is <i>init</i>. For subsequent<br> +invocations of <i>func</i>, <i>accum</i> is the return value of the previous invocation of <i>func</i>.<br> +The value returned by <code>hash-map-fold</code> is the return value of the last invocation of <i>func</i>.<br> +The order in which <i>func</i> is called for different associations is unspecified.<br> +<br> +procedure: <code>(hash-map->alist</code> <i>hash-map</i><code>)</code> +<br>procedure: <code>(hash-map->alist</code> <i>eq-hash-map</i><code>)</code> + +Return an association list such that the <code>car</code> of each element in alist is a key in <i>hash-map</i> +or <i>eq-hash-map</i> and the corresponding <code>cdr</code> of each element in alist is the value associated<br> +to the key in <i>hash-map</i> or <i>eq-hash-map</i>. The order of the elements is unspecified.<br> +<br> +<h2>Eq Hash Maps</h2> + +Eq hash maps automatically use trackers (see <a href='MemoryManagementAPI.md'>MemoryManagementAPI</a>) to update when the garbage<br> +collector moves objects.<br> +<br> +procedure: <code>(make-eq-hash-map)</code> + +Return a new hash map that uses <code>eq</code> to compare keys.<br> +<br> +procedure: <code>(alist->eq-hash-map</code> <i>alist</i><code>)</code> + +Takes an association list, <i>alist</i>, and returns a new eq hash map which maps the <code>car</code> of every<br> +element in <i>alist</i> to the <code>cdr</code> of corresponding elements in <i>alist</i>.<br> +If some key occurs multiple times in <i>alist</i>, the value in the first association will take<br> +precedence over later ones.<br> +<br> +procedure: <code>(eq-hash-map?</code> <i>obj</i><code>)</code> + +Return <code>#t</code> if <i>obj</i> is a hash map that uses <code>eq</code> to compare keys and <code>#f</code> otherwise.<br> +<br> +procedure: <code>(eq-hash-map-ref</code> <i>eq-hash-map</i> <i>key</i> <i>default</i><code>)</code> + +Lookup <i>key</i> in <i>eq-hash-map</i> and return the <i>key</i>'s associated value. If the <i>key</i> is not found,<br> +then return <i>default</i>.<br> +<br> +procedure: <code>(eq-hash-map-set!</code> <i>eq-hash-map</i> <i>key</i> <i>value</i><code>)</code> + +Set the value associated with <i>key</i> to <i>value</i>. If <i>key</i> is not in the <i>eq-hash-map</i> it will be<br> +added.<br> +<br> +procedure: <code>(eq-hash-map-delete</code> <i>eq-hash-map</i> <i>key</i><code>)</code> + +Delete <i>key</i> from <i>eq-hash-map</i>.<br> +<br> +<h2>Eq Hash Sets</h2> + +Eq hash sets automatically use trackers (see <a href='MemoryManagementAPI.md'>MemoryManagementAPI</a>) to update when the garbage<br> +collector moves objects.<br> +<br> +procedure: <code>(make-eq-hash-set)</code> + +Return a new hash set that uses <code>eq</code> to compare elements.<br> +<br> +procedure: <code>(eq-hash-set?</code> <i>obj</i><code>)</code> + +Return <code>#t</code> if <i>obj</i> is a hash set that uses <code>eq</code> to compare elements and <code>#f</code> otherwise.<br> +<br> +procedure: <code>(eq-hash-set-contains</code> <i>eq-hash-set</i> <i>element</i><code>)</code> + +Returns <code>#t</code> if <i>eq-hash-set</i> contains <i>element</i> and <code>#f</code> otherwise.<br> +<br> +procedure: <code>(eq-hash-set-adjoint!</code> <i>eq-hash-set</i> <i>element</i> <i>...</i><code>)</code> + +Add each <i>element</i> to <i>eq-hash-set</i> if it is not already there.<br> +<br> +procedure: <code>(eq-hash-set-delete!</code> <i>eq-hash-set</i> <i>element</i><code>)</code> + +If <i>element</i> is in <i>eq-hash-set</i>, delete it from the set.
\ No newline at end of file diff --git a/InputAndOutput.md b/InputAndOutput.md new file mode 100644 index 0000000..dfc1107 --- /dev/null +++ b/InputAndOutput.md @@ -0,0 +1,116 @@ +# Input and Output # + +## Sockets ## + +See [Sockets](Sockets.md). + +## Ports ## + +`(import (foment base))` to use these procedures. + +procedure: `(make-buffered-port` _binary\_port_`)` + +Make a buffered binary port from _binary\_port_; if _binary\_port_ is already buffered, then it is +returned. If the +_binary-port_ is an input port, then the new buffered binary port will be an input port. +Likewise, if the +_binary-port_ is an output port or an input and output port then the new textual port will be the +same. + +procedure: `(make-ascii-port` _binary-port`)`_ + +Make a textual port which reads and/or writes characters in the ASCII encoding to the +_binary-port_. If the +_binary-port_ is an input port, then the new textual port will be an input port. Likewise, if the +_binary-port_ is an output port or an input and output port then the new textual port will be the +same. + +procedure: `(make-latin1-port` _binary-port`)`_ + +Make a textual port which reads and/or writes characters in the Latin-1 encoding to the +_binary-port_. If the +_binary-port_ is an input port, then the new textual port will be an input port. Likewise, if the +_binary-port_ is an output port or an input and output port then the new textual port will be the +same. + +procedure: `(make-utf8-port` _binary-port`)`_ + +Make a textual port which reads and/or writes characters in the UTF-8 encoding to the +_binary-port_. If the +_binary-port_ is an input port, then the new textual port will be an input port. Likewise, if the +_binary-port_ is an output port or an input and output port then the new textual port will be the +same. + +procedure: `(make-utf16-port` _binary-port_`)` + +Make a textual port which reads and/or writes characters in the UTF-16 encoding to the +_binary-port_. If the +_binary-port_ is an input port, then the new textual port will be an input port. Likewise, if the +_binary-port_ is an output port or an input and output port then the new textual port will be the +same. + +procedure: `(make-encoded-port` _binary\_port_`)` + +Automatically detect the encoding of _binary\_port_ and make a textual port which reads and/or +writes characters in the correct encoding to the _binary\_port_. + +The UTF-16 byte order mark is automatically detected. Otherwise, the string `coding:` is searched +for in the first 1024 bytes of the _binary\_port_. Following `coding:` should be the name of a +character encoding. Currently, `ascii`, `utf-8`, `latin-1`, and `iso-8859-1` are supported. If the +encoding can not be automatically determined, `ascii` is used. + +procedure: `(file-encoding)` +<br>procedure: <code>(file-encoding</code> <i>proc</i><code>)</code> +<br>procedure: <code>(</code><i>proc</i> <i>binary-port</i><code>)</code> + +<code>file-encoding</code> is a parameter. <i>proc</i> is called by <code>open-input-file</code> and <code>open-output-file</code> to<br> +return a textual port appropriate for the encoding of a binary port.<br> +<br> +The following example will open a file encoded using UTF-16.<br> +<br> +<pre><code>(parameterize ((file-encoding make-utf8-port))<br> + (open-input-file "textfile.utf8"))<br> +</code></pre> + +procedure: <code>(want-identifiers</code> <i>port</i> <i>flag</i><code>)</code> + +Textual input ports can read symbols or identifiers. Identifiers contain location information<br> +which improve error messages and stack traces. If <i>flag</i> is <code>#f</code> then symbols will be read<br> +from <i>port</i> by read. Otherwise, identifiers will be read.<br> +<br> +procedure: <code>(port-has-port-position?</code> <i>port</i><code>)</code> + +Returns <code>#t</code> if <i>port</i> supports the <code>port-position</code> operation.<br> +<br> +procedure: <code>(port-position</code> <i>port</i><code>)</code> + +Returns the position of the next read or write operation on <i>port</i> as a non-negative exact integer.<br> +<br> +procedure: <code>(port-has-set-port-position!? _port_</code>)`<br> +<br> +Returns <code>#t</code> if <i>port</i> supports the <code>set-port-position!</code> operation.<br> +<br> +procedure: <code>(set-port-position! _port_ _position_</code>)`<br> +procedure: <code>(set-port-position! _port_ _position_ _whence_</code>)`<br> +<br> +Sets the position of the next read or write operation on <i>port</i>. The <i>position</i> must be an<br> +exact integer taken as relative to <i>whence</i> which may be <code>begin</code>, <code>current</code>, or <code>end</code>.<br> +If <i>whence</i> is not specified, then <code>begin</code> is used.<br> +<br> +<h2>Console</h2> + +<code>(import (foment base))</code> to use these procedures.<br> +<br> +procedure: <code>(console-port?</code> <i>obj</i><code>)</code> + +Return <code>#t</code> is <i>obj</i> is a console port and <code>#f</code> otherwise.<br> +<br> +procedure: <code>(set-console-input-editline!</code> <i>port</i> <i>flag</i><code>)</code> + +<i>port</i> must be a console inport port. <i>flag</i> must be <code>#t</code> or <code>#f</code>. Turn on or off editline mode<br> +for <i>port</i>.<br> +<br> +procedure: <code>(set-console-input-echo!</code> <i>port</i> <i>flag</i><code>)</code> + +<i>port</i> must be a console inport port. <i>flag</i> must be <code>#t</code> or <code>#f</code>. Turn on or off echo mode<br> +for <i>port</i>.
\ No newline at end of file diff --git a/License.md b/License.md new file mode 100644 index 0000000..588eff2 --- /dev/null +++ b/License.md @@ -0,0 +1,21 @@ +# License # + +Copyright (c) 2013, 2014 Michael Montague + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.
\ No newline at end of file diff --git a/MemoryManagementAPI.md b/MemoryManagementAPI.md new file mode 100644 index 0000000..a2c1596 --- /dev/null +++ b/MemoryManagementAPI.md @@ -0,0 +1,133 @@ +# Memory Management API # + +`(import (foment base))` to use these procedures. + +## Guardians ## + +procedure: `(make-guardian)` +<br>procedure: <code>(</code><i>guardian</i><code>)</code> +<br>procedure: <code>(</code><i>guardian</i> <i>obj</i><code>)</code> + +A new guardian will be returned. A guardian is a procedure which encapsulates a group of objects<br> +to be protected from being collected by the garbage collector and a group of objects saved from<br> +collection. Initially, both groups of objects are empty.<br> +<br> +To add an object to the group of objects being protected, call the guardian with the object as the<br> +only argument.<br> +<br> +<pre><code>(define g (make-guardian))<br> +(define obj (cons 'a 'b))<br> +(g obj)<br> +</code></pre> + +When a protected object is inaccessible, other than from a guardian, and could be collected, it<br> +is moved to the saved group of any guardians protecting it, rather than being collected. To get<br> +the objects from the saved group, the guardian is called without any arguments. The objects from<br> +the saved group are returned one at a time until the saved group is empty in which case <code>#f</code> is<br> +returned.<br> +<br> +<pre><code>(g) => #f<br> +(set! obj 123)<br> +(collect)<br> +(g) => (a . b)<br> +(g) => #f<br> +</code></pre> + +An object may be protected by more than on guardians and more than once by the same guardian. When<br> +an object becomes inaccessible it will be moved into saved groups the same number of times that<br> +it was protected. Finally, guardians may be protected by guardians.<br> +<br> +<h2>Trackers</h2> + +procedure: <code>(make-tracker)</code> +<br>procedure: <code>(</code><i>tracker</i><code>)</code> +<br>procedure: <code>(</code><i>tracker</i> <i>obj</i><code>)</code> +<br>procedure: <code>(</code><i>tracker</i> <i>obj</i> <i>ret</i><code>)</code> + +A new tracker will be returned. A tracker is a procedure which encapsulates a group of objects to<br> +be tracked for when the garbage collector moves them during a copying collection and a group of<br> +objects which have been moved. Initially, both groups of objects are empty.<br> +<br> +To add an object to the group of objects being tracked, call the tracker<br> +with the object as the only argument. Or call the tracker with the object to be tracked and an<br> +object to be returned when the tracked object moves.<br> +<br> +<pre><code>(define t (make-tracker))<br> +(define obj (cons 'a 'b))<br> +(define ret (cons (cons 'w 'x) (cons 'y 'z)))<br> +(t obj)<br> +(t (car ret) ret)<br> +</code></pre> + +When a tracked object has moved in memory, it is put into the moved group of any trackers<br> +tracking it. To get the objects from the moved group, the tracker is called without any arguments.<br> +The objects from the moved group are returned one at a time until the moved group is empty in<br> +which case <code>#f</code> is returned.<br> +<br> +<pre><code>(t) => #f<br> +(collect)<br> +(t) => (a . b)<br> +(t) => ((w . x) y . z)<br> +(t) => #f<br> +(collect)<br> +(t) => #f<br> +</code></pre> + +To continue tracking an object once it has been placed in the moved group, it will need to<br> +registered with the tracker again.<br> +<br> +Tracking the movement of objects is important for <code>eq-hash</code> which uses an object's address as<br> +it's hash. When the object is<br> +moved during a copying collection, it is the same object, but it has a different hash because it<br> +is now at a different address. Uses of <code>eq-hash</code> will need to used a tracker to follow address<br> +changes of objects.<br> +<br> +<h2>Garbage Collection</h2> + +procedure: <code>(collect)</code> +<br> procedure: <code>(collect</code> <i>full</i><code>)</code> + +If <i>full</i> is not specified or <code>#f</code> then a partial collection is performed. Otherwise, a full<br> +collection is performed.<br> +<br> +<hr /> + +procedure: <code>(partial-per-full)</code> +<br> procedure: <code>(partial-per-full</code> <i>val</i><code>)</code> + +<code>partial-per-full</code> is the number of partial collections performed for every full collection.<br> +If <i>val</i> is specified, it specifies a new value for <code>partial-per-full</code>.<br> +<i>val</i> must be a non-negative fixnum. A value of zero means that every<br> +collection is a full collection. The current value of <code>partial-per-full</code> is returned.<br> +<br> +<hr /> + +procedure: <code>(trigger-bytes)</code> +<br> procedure: <code>(trigger-bytes</code> <i>val</i><code>)</code> + +<code>trigger-bytes</code> is the number of bytes allocated since the last collection before<br> +triggering another collection.<br> +If <i>val</i> is specified, it specifies a new value for <code>trigger-bytes</code>.<br> +<i>val</i> must be a non-negative fixnum. The current value of <code>trigger-bytes</code> is<br> +returned.<br> +<br> +Many more bytes than <code>trigger-bytes</code> may be allocated before a collection actually occurs.<br> +<br> +<hr /> + +procedure: <code>(trigger-objects)</code> +<br> procedure: <code>(trigger-objects</code> <i>val</i><code>)</code> + +<code>trigger-objects</code> is the number of objects allocated since the last collection before<br> +triggering another collection.<br> +If <i>val</i> is specified, it specifies a new value for <code>trigger-objects</code>.<br> +<i>val</i> must be a non-negative fixnum. The current value of <code>trigger-objects</code> is<br> +returned.<br> +<br> +Many more objects than <code>trigger-objects</code> may be allocated before a collection actually occurs.<br> +<br> +<hr /> + +procedure: <code>(dump-gc)</code> + +Dump information about memory to standard output.
\ No newline at end of file diff --git a/MemoryManagementInternals.md b/MemoryManagementInternals.md new file mode 100644 index 0000000..3f93144 --- /dev/null +++ b/MemoryManagementInternals.md @@ -0,0 +1,31 @@ +# Memory Management Internals # + +The garbage collector uses three generations: zero, one, and mature. Zero and one are young +generations. They are always collected together using a copying collector. The mature generation +is collected using a mark and sweep collector. A partial collection collects the young generations +only. A full collection collects all three generations. + +## Guardians ## + +The implementation of guardians closely follows this paper: + +R. Kent Dybvig, Carl Bruggeman, and David Eby. Guardians in a generation-based garbage collector. +In _Proceedings of the SIGPLAN '93 Conference on Programming Language Design and Implementation_, +207-216, June 1993. http://www.cs.indiana.edu/~dyb/pubs/guardians-pldi93.pdf + +## Trackers ## + +The implemenation of trackers is inspired by guardians and this paper: + +Abdulaziz Ghuloum and R. Kent Dybvig. Generation-friendly eq hash tables. +In _2007 Workshop on Scheme and Functional Programming_, 27-35, 2007 +http://www.schemeworkshop.org/2007/procPaper3.pdf + +Trackers are like guardians, but rather than watching for objects to become inaccessible, they +watch for objects to move during a copying collection. + +procedure: `(install-tracker` _obj_ _ret_ _tconc_`)` + +`install-tracker` is used by `make-tracker` to tell the collector to start tracking _obj_. When +_obj_ moves, the collector will put _ret_ onto the end of _tconc_. Tracking will continue as long +as _obj_, _ret_, and _tconc_ are all accessible and _obj_ has not yet moved. diff --git a/MiscellaneousAPI.md b/MiscellaneousAPI.md new file mode 100644 index 0000000..31be0f5 --- /dev/null +++ b/MiscellaneousAPI.md @@ -0,0 +1,73 @@ +# Miscellaneous API # + +These procedures are in addition to the procedures specified by R7RS. +`(import (foment base))` to use these procedures. + +## Assignments ## + +syntax: `(set!-values` `(`_var_ _..._`)` _expr_`)` + +_expr_ is evaluated and must return as many values as there are _var\_s. Each_var_is set to +the corresponding value returned by_expr_._ + +## Syntax ## + +procedure: `(syntax` _expr_`)` + +Return the expansion of _expr_. `syntax` and `unsyntax` are best used together. + +procedure: `(unsyntax` _expr_`)` + +Return _expr_ converted to datum. + +``` +(unsyntax (syntax '(when (not (null? lst)) (write "not null")))) +=> (#<syntax: if> (not (null? lst)) (#<syntax: begin> (write "not null"))) +``` + +## Exceptions ## + +Error objects contains type, who, message, and irritants fields. Type is a symbol, typically one of +`error`, `assertion-violation`, `implementation-restriction`, `lexical-violation`, +`syntax-violation`, or `undefined-violation`. Who is a symbol, typically which procedure raised +the exception. Message is a string explaining the error to be displayed to the user. Irritants +is a list of additional context for the error. + +procedure: `(error-object-type` _error-object_`)` + +Return the `type` field of _error\_object_. + +procedure: `(error-object-who` _error-object_`)` + +Return the `who` field of _error-object_. + +procedure: `(error-object-kind` _error-object_`)` + +Return the `kind` field of _error-object_. + +procedure: `(full-error` _type_ _who_ _kind_ _message_ _obj_ _..._`)` + +Raise an exception by calling raise on a new error object. The procedure `error` could be defined +in terms of `full-error` as follows. + +``` +(define (error message . objs) + (apply full-error 'assertion-violation 'error #f message objs)) +``` + +## Libraries ## + +procedure: `(loaded-libraries)` + +Return the list of loaded libraries. + +procedure: `(library-path)` + +Return the library path. The command line options, `-A` and `-I`, and the environment variable +`FOMENT_LIBPATH` can be used to add to the library path. + +## Miscellaneous ## + +procedure: `(random` _k_`)` + +Return a random number between 0 and _k_ `- 1`. diff --git a/MiscellaneousInternals.md b/MiscellaneousInternals.md new file mode 100644 index 0000000..3b28126 --- /dev/null +++ b/MiscellaneousInternals.md @@ -0,0 +1,43 @@ +# Miscellaneous Internals # + +These procedures are in addition to the procedures specified by R7RS. +`(import (foment base))` to use these procedures. + +## Hash Trees ## + +The implementation of hash trees follows this paper: + +Phil Bagwell (2000). Ideal Hash Trees (Report). Infoscience Department, +�cole Polytechnique F�d�rale de Lausanne. +http://infoscience.epfl.ch/record/64398/files/idealhashtrees.pdf + +Hash tree indexes must be between `0` inclusive and `#x7ffffff`. + +procedure: `(make-hash-tree)` + +Return a new hash tree. + +procedure: `(hash-tree?` _obj_`)` + +Return `#t` if _obj_ is a hash tree and `#f` otherwise. + +procedure: `(hash-tree-ref` _hash-tree_ _index_ _not-found_`)` + +If a value has been set at _index_ in _hash-tree_ return it; otherwise return _not-found_. + +procedure: `(hash-tree-set!` _hash-tree_ _index_ _value_`)` + +Set the value of _index_ in _hash-tree_ to be _value_. A new hash tree may be returned. + +procedure: `(hash-tree-delete` _hash-tree_ _index_`)` + +Remove the value for _index_ in _hash-tree_. A new hash tree may be returned. + +procedure: `(hash-tree-buckets` _hash-tree_`)` + +Return the buckets of _hash-tree_ as a vector. There will be as many as 64 buckets. Each bucket +will either be another hash tree or a box containing a value in the tree. + +procedure: `(hash-tree-bitmap` _hash-tree_`)` + +Return the bitmap which indicates which slots have values.
\ No newline at end of file diff --git a/ProjectHome.md b/ProjectHome.md new file mode 100644 index 0000000..82e61d2 --- /dev/null +++ b/ProjectHome.md @@ -0,0 +1,27 @@ +[Foment](Foment.md) is an implementation of Scheme. + + * Full R7RS. + * Libraries and programs work. + * Native threads and some synchronization primitives. + * Memory management using a garbage collector with two copying and one mark-sweep generations. Guardians protect objects from being collected and trackers follow objects as they get moved by the copying part of the collector. + * Full Unicode including reading and writing unicode characters to the console. Files in UTF-8 and UTF-16 encoding can be read and written. + * The system is built around a compiler and VM. There is support for prompts and continuation marks. + * Network support. + * Editing at the REPL including () matching. + * Portable: Windows, Linux, and FreeBSD. + * 32 bit and 64 bit. + * SRFI 106: Basic socket interface. + * SRFI 111: Boxes. + * SRFI 112: Environment Inquiry. + +See [Foment](Foment.md) for more details. + +Future plans include + + * Providing line numbers and stack traces on errors. + * R7RS large SRFIs. + * composable continuations + +Please note that this is very much a work in progress. Please let me know if you find bugs and omissions. I will do my best to fix them. + +mikemon@gmail.com
\ No newline at end of file @@ -0,0 +1,14 @@ +# R7RS # + +All of [R7RS](http://trac.sacrideo.us/wg/raw-attachment/wiki/WikiStart/r7rs.pdf) is supported. + + +--- + + +procedure: `(exit)` +<br>procedure: <code>(exit</code> <i>obj</i><code>)</code> + +Runs all outstanding <code>dynamic-wind</code> <i>after</i> procedures for the current thread and terminates<br> +the running program. See <code>exit-thread</code> to exit the current thread without terminating the running<br> +program.
\ No newline at end of file diff --git a/R7RSExtensions.md b/R7RSExtensions.md new file mode 100644 index 0000000..534fd20 --- /dev/null +++ b/R7RSExtensions.md @@ -0,0 +1,19 @@ +# R7RS Extensions # + +procedure: `(interaction-environment` _import-set_ _..._ `)` + +The procedure `interaction-environment` can be passed one or more +_import-set\_s. A mutable environment will be returned containing the bindings specified by +the_import-set\_s. + +procedure: `(eval` _expr_ _env_ `)` +<br> procedure: <code>(load</code> <i>filename</i> <code>)</code> +<br> procedure: <code>(load</code> <i>filename</i> <i>env</i> <code>)</code> + +These procedures will recognize <code>define-library</code> forms and define the specified library. This<br> +means that you can define libraries in interactive sessions and load them using <code>load</code> and<br> +the command line option <code>-l</code>.<br> +<br> +library declaration: <code>(aka</code> <i>library_name</i><code>)</code> + +Declare <i>library_name</i> as an additional name for a library.<br> diff --git a/ReleaseNotes.md b/ReleaseNotes.md new file mode 100644 index 0000000..164928a --- /dev/null +++ b/ReleaseNotes.md @@ -0,0 +1,68 @@ +# Release Notes # + +## 0.1 ## + +23 Oct 2013: initial release + +## 0.2 ## + +5 November 2013 + + * command line argument handling changed + * `FOMENT_LIBPATH` environment variable added + * 64 bit version on Windows + * `cond-expand` works in programs + * `environment` procedure added + * unicode conversion routines rewritten; convertutf.c is no longer used + * Linux version: 32 and 64 bit + * SRFI 112: Environment Inquiry is fully supported + * SRFI 111: Boxes is fully supported + * `(scheme lazy)` is no longer delayed + +## 0.3 ## + +12 January 2014 + + * `syntax-rules` now treat `...` and `_` as identifiers rather than symbols + * FreeBSD version + * `set!-values` + * read datum labels and datum references + * `equal?` works with circular data structures + * `current-second` fixed to return an inexact number + * numbers fully supported + * `(scheme r5rs)` library added + * `scheme-report-environment` and `null-environment` added + * `(aka` _library\_name_`)` to declare an additional name for a library + +## 0.4 ## + +29 March 2014 + + * library extensions: .scm and .sld + * use command line argument `-X` to specify additional library extensions + * gc: wait on conditions in a loop and test predicate correctly + * `exit` supported + * `exit-thread` and `emergency-exit-thread` + * ctrl-c handling + * editline with history + * `console-port?`, `set-console-input-editline!`, and `set-console-input-echo!` + * `with-notify-handler` and `set-ctrl-c-notify!` + * `char-ready?` and `byte-ready?` work correctly; all of R7RS is now supported + * sockets are supported + * SRFI 106: Basic socket interface is fully supported + * use `coding:` to specify the encoding of a text file + * threads blocked on read, recv-socket, accept-socket, and connect-socket will no longer block garbage collection + +## 0.5 ## + + * on unix, using foment for scripts works: #!/usr/local/bin/foment as the first line of a program + * empty `cond-expand` works + * include, include-ci, and include-library-declarations are relative to including file + * number->string returns lowercase rather than uppercase + * SRFI 60: Integers as Bits is fully supported. + * [FileSystemAPI](FileSystemAPI.md) + * `port-has-port-position?`, `port-position`, `port-has-set-port-position!?', and `set-port-position!` + * hash trees supported: [MiscellaneousInternals](MiscellaneousInternals.md) + * hash maps supported: [HashContainerAPI](HashContainerAPI.md) + * hashtables changed to hash-maps + * SRFI 114: Comparators is fully supported.
\ No newline at end of file diff --git a/RunningFoment.md b/RunningFoment.md new file mode 100644 index 0000000..360bb2a --- /dev/null +++ b/RunningFoment.md @@ -0,0 +1,95 @@ +# Running Foment # + +Foment works on Windows, Linux, and FreeBSD. + +If you are using Windows, you will need at least Windows Vista +for it to work. To see more Unicode characters, change the font of the console window from a +raster font to a TrueType font. + +Foment can be used in two modes: program mode and interactive mode. In program mode, Foment will +compile and run a program. In interactive mode, Foment will run an interactive session (REPL). + +## Program Mode ## + +`foment` _option_ _..._ _program_ _arg_ _..._ + +Compile and run the program in the file named _program_. There may be zero or more options and +zero or more arguments. + +Everything from `foment` to _program_ will be concatenated into a single string; this string +will be the `(car (command-line))`. Everything after _program_ will be the +`(cdr (command-line))`, with each _arg_ being a seperate string. + +### Options ### + +`-A` _directory_ + +Append _directory_ to the library search path. + +`-I` _directory_ + +Prepend _directory_ to the library search path. + +`-X` _ext_ + +Add _ext_ as a possible extension for the filename of a library. See [UsingLibraries](UsingLibraries.md). + +`-no-inline-procedures` + +The compiler is not allowed to inline some procedures. + +`-no-inline-imports` + +The compiler is not allowed to inline imports that it knows are constant. + +## Interactive Mode ## + +`foment` _option_ _..._ _flag_ ... _arg_ ... +<br><code>foment</code> <i>option</i> <i>...</i> <i>flag</i> ...<br> +<br> +Run an interactive session. Any options must be specified before any flags.<br> +If one or more <i>args</i> are specified, then at least<br> +one flag must be specified; otherwise, Foment will think the first <i>arg</i> is a program.<br> +<br> +<h3>Flags</h3> + +<code>-i</code> + +Run an interactive session.<br> +<br> +<code>-e</code> <i>expr</i> + +Evalute <i>expr</i>.<br> +<br> +<code>-p</code> <i>expr</i> + +Print the result of evaluating <i>expr</i>.<br> +<br> +<code>-l</code> <i>filename</i> + +Load <i>filename</i>.<br> +<br> +<h1>Using Foment</h1> + +As an extension to R7RS, <code>eval</code> recognizes (define-library ...) and loads it as a library. This<br> +works in an interactive session and when a file is loaded via <code>load</code> or <code>-l</code> on the command line.<br> +As a result, you can start developing your program and libraries all in one file and run it<br> +via <code>-l</code> on the command line.<br> +<br> +<h1>Interactive Session</h1> + +The REPL uses editline which provides interactive editing of lines of input.<br> +<br> +<code>ctrl-a</code> : beginning-of-line<br> +<br><code>ctrl-b</code> : backward-char<br> +<br><code>ctrl-d</code> : delete-char<br> +<br><code>ctrl-e</code> : end-of-line<br> +<br><code>ctrl-f</code> : forward-char<br> +<br><code>ctrl-h</code> : delete-backward-char<br> +<br><code>ctrl-k</code> : kill-line<br> +<br><code>alt-b</code> : backward-word<br> +<br><code>alt-d</code> : kill-word<br> +<br><code>alt-f</code> : forward-word<br> +<br><code>backspace</code> : delete-backward-char<br> +<br><code>left-arrow</code> : backward-char<br> +<br><code>right-arrow</code> : forward-char
\ No newline at end of file diff --git a/SRFISupport.md b/SRFISupport.md new file mode 100644 index 0000000..2f33fa7 --- /dev/null +++ b/SRFISupport.md @@ -0,0 +1,17 @@ +# SRFI Support # + +[SRFI 60: Integers as Bits](http://srfi.schemers.org/srfi-60/srfi-60.html) is fully +supported. `(import (srfi 60))` to use it. + +[SRFI 106: Basic socket interface](http://srfi.schemers.org/srfi-106/srfi-106.html) is fully +supported. `(import (srfi 106))` to use it. + +[SRFI 111: Boxes](http://srfi.schemers.org/srfi-111/srfi-111.html) is fully supported. +`(import (srfi 111))` to use it. + +[SRFI 112: Environment Inquiry](http://srfi.schemers.org/srfi-112/srfi-112.html) is fully supported. +`(import (srfi 112))` to use it. + +[SRFI 114: Comparators](http://srfi.schemers.org/srfi-114/srfi-114.html) is fully supported. +`(import (srfi 114))` to use it. + diff --git a/Sockets.md b/Sockets.md new file mode 100644 index 0000000..c1c9575 --- /dev/null +++ b/Sockets.md @@ -0,0 +1,112 @@ +# Sockets # + +The socket support in Foment is based on +[SRFI 106: Basic socket interface](http://srfi.schemers.org/srfi-106/srfi-106.html) with one +important difference: sockets are ports. + +## Procedures ## + +`(import (foment base))` to use these procedures. + +procedure: `(socket?` _obj_`)` + +Return `#t` if _obj_ is a socket and `#f` otherwise. + +procedure: `(make-socket` _address-family_ _socket-domain_ _ip-protocol_`)` + +Return a new socket. To use this socket to listen for incoming connection requests, `bind-socket`, +`listen-socket`, and `accept-socket` must be used. To connect this socket with a server, +`connect-socket` must be used. +_address-family_, _socket-domain_, and _ip-protocol_ are specified below. + +procedure: `(bind-socket` _socket_ _node_ _service_ _address-family_ _socket-domain_ +_ip-protocol_`)` + +Bind _socket_ to _node_ and _service_. _node_ must be a string. If _node_ is the empty string, +then the _socket_ will be bound to all available IP addresses. If _node_ is `"localhost"`, then +the _socket_ will be bound to all available loopback addresses. _service_ must be a string. It +may be a numeric port number, for example, `"80"`. Or it may be the name of a service, for +example, `"http"`. +_address-family_, _socket-domain_, and _ip-protocol_ are specified below. + +procedure: `(listen-socket` _socket_`)` +<br>procedure: <code>(listen-socket</code> <i>socket</i> <i>backlog</i><code>)</code> + +Start <i>socket</i> listening for incoming connections. <i>socket</i> must be bound using <code>bind-socket</code> +before calling <code>listen-socket</code>.<br> +<br> +procedure: <code>(accept-socket</code> <i>socket</i><code>)</code> + +Wait for a client to connect to the <i>socket</i>. A new socket will be returned which can be used to<br> +communicate with the connected client socket. <i>socket</i> may continue to be used with <code>accept-socket</code> +to wait for more clients to connect. <i>socket</i> must be put into a listening state using<br> +<code>listen-socket</code> before calling <code>accept-socket</code>.<br> +<br> +procedure: <code>(connect-socket</code> <i>socket</i> <i>node</i> <i>service</i> <i>address-family</i> <i>socket-domain</i> +<i>address-info</i> <i>ip-protocol</i><code>)</code> + +Connect <i>socket</i> to a server. <i>node</i> and <i>service</i> must be strings.<br> +<i>address-family</i>, <i>socket-domain</i>, <i>address-info</i>, and <i>ip-protocol</i> are specified below.<br> +<br> +procedure: <code>(shutdown-socket</code> <i>socket</i> <i>how</i><code>)</code> + +Shutdown the <i>socket</i>. <i>how</i> must be one of <code>*shut-rd*</code>, <code>*shut-wr*</code>, or <code>*shut-rdwr*</code>.<br> +<br> +procedure: <code>(send-socket</code> <i>socket</i> <i>bytevector</i> <i>flags</i><code>)</code> + +Send the contents of <i>bytevector</i> on <i>socket</i>. <i>flags</i> must be <code>0</code> or <code>*msg-oob*</code>.<br> +<br> +procedure: <code>(recv-socket</code> <i>socket</i> <i>size</i> <i>flags</i><code>)</code> + +Wait for and receive a block of data of <i>size</i> bytes from <i>socket</i>. The data will be returned<br> +as a bytevector. A zero length bytevector indicates that the peer connection is closed.<br> +<i>flags</i> must be <code>0</code>, <code>*msg-peek*</code>, <code>*msg-oob*</code>, or <code>*msg-waitall*</code>.<br> +<br> +procedure: <code>(get-ip-addresses</code> <i>address-family</i><code>)</code> + +Return a list of the local IP addresses in the specified <i>address-family</i>.<br> +<br> +<h2>Flag Operations and Constants</h2> + +These are the same as<br> +<a href='http://srfi.schemers.org/srfi-106/srfi-106.html'>SRFI 106: Basic socket interface</a>.<br> +<br> +<h2>Example</h2> + +This is a simple example of using sockets. The client reads a line of text, converts it<br> +to UTF-8, and sends it to the server. The server receives UTF-8, converts it to a string, and<br> +writes it.<br> +<br> +<pre><code>(import (foment base))<br> +<br> +(define (server)<br> + (define (loop s)<br> +;; (let ((bv (recv-socket s 128 0)))<br> +;; (if (> (bytevector-length bv) 0)<br> + (let ((bv (read-bytevector 128 s)))<br> + (if (not (eof-object? bv))<br> + (begin<br> + (display (utf8->string bv))<br> + (newline)<br> + (loop s)))))<br> + (let ((s (make-socket (address-family inet) (socket-domain stream) (ip-protocol tcp))))<br> + (bind-socket s "localhost" "12345" (address-family inet) (socket-domain stream)<br> + (ip-protocol tcp))<br> + (listen-socket s)<br> + (loop (accept-socket s))))<br> +<br> +(define (client)<br> + (define (loop s)<br> +;; (socket-send s (string->utf8 (read-line)) 0)<br> + (write-bytevector (string->utf8 (read-line)) s)<br> + (loop s))<br> + (let ((s (make-socket (address-family inet) (socket-domain stream) (ip-protocol tcp))))<br> + (connect-socket s "localhost" "12345" (address-family inet) (socket-domain stream)<br> + 0 (ip-protocol tcp))<br> + (loop s)))<br> +<br> +(cond<br> + ((member "client" (command-line)) (client))<br> + ((member "server" (command-line)) (server))<br> + (else (display "error: expected client or server on the command line") (newline)))<br> +</code></pre> diff --git a/SynchronizationAndThreadAPI.md b/SynchronizationAndThreadAPI.md new file mode 100644 index 0000000..864444b --- /dev/null +++ b/SynchronizationAndThreadAPI.md @@ -0,0 +1,157 @@ +# Synchronization And Thread API # + +`(import (foment base))` to use these procedures. + +## Threads ## + +procedure: `(current-thread)` + +Returns the current thread. + +procedure: `(thread?` _obj_`)` + +Returns `#t` if _obj_ is a thread, otherwise returns `#f`. + +procedure: `(run-thread` _thunk_`)` + +A new thread will be returned. The new thread will execute _thunk_ which is a procedure taking +no arguments. + +procedure: `(exit-thread` _obj_`)` + +Runs all outstanding `dynamic-wind` _after_ procedures for the current thread. +If the current thread is the only thread, then the running program is terminated. Otherwise, only +the current thread is terminated. + +procedure: `(emergency-exit-thread` _obj_`)` + +Terminate the current thread. + +procedure: `(sleep` _k_`)` + +Sleep for _k_ milliseconds. + +## Exclusives ## + +procedure: `(exclusive?` _obj_`)` + +Returns `#t` if _obj_ is an exclusive, otherwise returns `#f`. + +procedure: `(make-exclusive)` + +Returns a new exclusive. + +procedure: `(enter-exclusive` _exclusive_`)` + +Wait, if necessary, until the _exclusive_ is available, and then enter it. Only a single thread +at a time may enter the _exclusive_. The wait for the _exclusive_ could be potentially +indefinate. + +Exclusives may be entered recursively. For the _exclusive_ to become available, `leave-exclusive` +must be called once for ever call to `enter-exclusive`. + +procedure: `(leave-exclusive` _exclusive_`)` + +Leave the _exclusive_ and make it available. Another thread may enter it. + +procedure: `(try-exclusive` _exclusive_`)` + +Attempt to enter the _exclusive_ without waiting. If the _exclusive_ is entered return `#t`, +otherwise return `#f`. + +syntax: `(with-exclusive` _exclusive_ _expr1_ _expr2_ _..._`)` + +Enter the _exclusive_, evaluate the expressions _expr1_ _expr2_ _..._, and leave the _exclusive_. +The _exclusive_ will be entered when the execution of the expressions begin and when a +capture continuation is invoked. +The _exclusive_ will be left whether the expressions return normally or by an exception being +raised or by a capture continuation being invoked. + +## Conditions ## + +procedure: `(condition?` _obj_`)` + +Returns `#t` if _obj_ is an condition, otherwise returns `#f`. + +procedure: `(make-condition)` + +Returns a new condition. + +procedure: `(condition-wait` _condition_ _exclusive_`)` + +Leave _exclusive_ and wait on _condition_. This is done atomically. When `condition-wait` returns +the _exclusive_ will have been entered. Conditions are subject to wakeups not associated with an +explicit wake. You must recheck a predicate when `condition-wait` returns. + +procedure: `(condition-wake` _condition_`)` + +Wake one thread waiting on _condition_. + +procedure: `(condition-wake-all` _condition_ `)` + +Wake all threads waiting on _condition_. + +## Example ## + +Conditions and exclusives are used to implement a mailbox. One or more producer threads put +items into the mailbox and one or more consumer threads get items out of the mailbox. + +``` +(define not-empty (make-condition)) +(define not-full (make-condition)) +(define lock (make-exclusive)) +(define mailbox #f) +(define mailbox-full #f) +(define next-item 1) +(define last-item 100) + +(define (producer) + (sleep (random 100)) + (enter-exclusive lock) + (let ((item next-item)) + (define (put item) + (if mailbox-full + (begin + (condition-wait not-full lock) + (put item)) + (begin + (set! mailbox item) + (set! mailbox-full #t) + (leave-exclusive lock) + (condition-wake not-empty)))) + (set! next-item (+ next-item 1)) + (if (> next-item last-item) + (leave-exclusive lock) ; All done. + (begin + (put item) + (producer))))) + +(define (consumer) + (define (get) + (if mailbox-full + (begin + (set! mailbox-full #f) + (let ((item mailbox)) + (condition-wake not-full) + (leave-exclusive lock) + item)) + (begin + (condition-wait not-empty lock) + (get)))) + (enter-exclusive lock) + (let ((item (get))) + (write item) + (display " ") + (consumer))) + +(run-thread producer) +(run-thread producer) +(run-thread consumer) +(run-thread consumer) +(run-thread consumer) +(run-thread consumer) + +(sleep 4000) +(display " +") +```
\ No newline at end of file diff --git a/UsingLibraries.md b/UsingLibraries.md new file mode 100644 index 0000000..d62972b --- /dev/null +++ b/UsingLibraries.md @@ -0,0 +1,49 @@ +# Using Libraries # + +All procedures exported by Foment are in the `(foment base)` library. + +Each program loads all imported libraries exactly once. If a library is loaded, it is +guaranteed to be loaded exactly once. + +Libraries are contained in files. A file may contain more than one library: +`(define-library ...)`. When the file is loaded, all of the libraries in the file will be +loaded. + +Library names get mapped to filenames two different ways: deep names and flat names. + +Deep names use directories to seperate the components of the library name. The library name +`(`_name1_ _name2_ _..._ _namen_`)` gets mapped to the filename +_name1_`\`_name2_`\`_..._`\`_namen_`.`_ext_. + +The use of deep names is strongly recommended for portable libraries. + +Flat names use `-` to seperate the components of the library name. The library name +`(`_name1_ _name2_ _..._ _namen_`)` gets mapped to the filename +_name1_`-`_name2_`-`_..._`-`_namen_`.`_ext_. + +By default, Foment uses `sld` and `scm` for _ext_. Additional extensions can be specified using +the `-X` command line option. See [RunningFoment](RunningFoment.md). + +The library path is a list of one or more directories to search for libraries. To start with, +the library path contains the current directory and the directory containing foment. +The environment variable `FOMENT_LIBPATH` can contain a list of directories to put on the +front of the library path. +The command line switch `-I` adds a directory to the front of the list of directories and `-A` adds +a directory to the end. + +For example, if a library named `(tiny example library)` is imported and the library path is +`("." "..\Tools" "d:\Scheme") then the filenames in the following order will be used to try +to load the library. + + 1. `.\tiny-example-library.sld` + 1. `.\tiny\example\library.sld` + 1. `..\Tools\tiny-example-library.sld` + 1. `..\Tools\tiny\example\library.sld` + 1. `d:\Scheme\tiny-example-library.sld` + 1. `d:\Scheme\tiny\example\library.sld` + +Warning: the libraries `(tiny example library)` and `(tiny-example-library)` both map to the +same flat name: `tiny-example-library.sld`. + +The character encoding of the files containing libraries is automatically detected. +See `make-encoded-port` in [InputAndOutput](InputAndOutput.md).
\ No newline at end of file |