about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2016-08-18 21:09:27 -0700
committerKartik K. Agaram <vc@akkartik.com>2016-08-18 21:09:27 -0700
commita621ef95f4728d15bdf0b1828ac7dd6ac5af2795 (patch)
tree55e215014e53dfd5327dbd6eefb8d072b5b08a08
parent47219d0b2b41096547a02b506d7413fe9a3d308a (diff)
downloadmu-a621ef95f4728d15bdf0b1828ac7dd6ac5af2795.tar.gz
3225 - testable interface for writing files
For example usage of file operations, see filesystem.mu.

Is it ugly that we don't actually write to disk unless we wait for the
writing routine to exit? Maybe there's a nice way to wrap it. At any
rate, all buffering is explicit, which seems a win compared to *nix.
-rw-r--r--075channel.mu1
-rw-r--r--087file.cc4
-rw-r--r--088file.mu27
-rw-r--r--filesystem.mu24
4 files changed, 41 insertions, 15 deletions
diff --git a/075channel.mu b/075channel.mu
index d47410da..1ee716a2 100644
--- a/075channel.mu
+++ b/075channel.mu
@@ -302,7 +302,6 @@ after <channel-write-initial> [
   closed?:boolean <- get *chan, closed?:offset
   return-if closed?
 ]
-
 after <channel-read-empty> [
   closed?:boolean <- get *chan, closed?:offset
   {
diff --git a/087file.cc b/087file.cc
index 6109fe26..ebb90689 100644
--- a/087file.cc
+++ b/087file.cc
@@ -125,8 +125,8 @@ case _WRITE_TO_FILE: {
     raise << maybe(get(Recipe, r).name) << "first ingredient of '$write-to-file' should be a number, but got '" << to_string(inst.ingredients.at(0)) << "'\n" << end();
     break;
   }
-  if (!is_mu_number(inst.ingredients.at(1))) {
-    raise << maybe(get(Recipe, r).name) << "second ingredient of '$write-to-file' should be a number, but got '" << to_string(inst.ingredients.at(0)) << "'\n" << end();
+  if (!is_mu_character(inst.ingredients.at(1))) {
+    raise << maybe(get(Recipe, r).name) << "second ingredient of '$write-to-file' should be a character, but got '" << to_string(inst.ingredients.at(0)) << "'\n" << end();
     break;
   }
   break;
diff --git a/088file.mu b/088file.mu
index 6e6a89e1..b26ae438 100644
--- a/088file.mu
+++ b/088file.mu
@@ -8,12 +8,12 @@ container filesystem [
 def start-reading fs:address:filesystem, filename:address:array:character -> contents:address:source:character [
   local-scope
   load-ingredients
-  x:number/file <- $open-file-for-reading filename
+  file:number <- $open-file-for-reading filename
   contents:address:source:character, sink:address:sink:character <- new-channel 30
-  start-running transmit x, sink
+  start-running transmit-from-file file, sink
 ]
 
-def transmit file:number, sink:address:sink:character -> file:number, sink:address:sink:character [
+def transmit-from-file file:number, sink:address:sink:character -> file:number, sink:address:sink:character [
   local-scope
   load-ingredients
   {
@@ -23,4 +23,25 @@ def transmit file:number, sink:address:sink:character -> file:number, sink:addre
     loop
   }
   sink <- close sink
+  $close-file file
+]
+
+def start-writing fs:address:filesystem, filename:address:array:character -> sink:address:sink:character, routine-id:number [
+  local-scope
+  load-ingredients
+  file:number <- $open-file-for-writing filename
+  source:address:source:character, sink:address:sink:character <- new-channel 30
+  routine-id <- start-running transmit-to-file file, source
+]
+
+def transmit-to-file file:number, source:address:source:character -> file:number, source:address:source:character [
+  local-scope
+  load-ingredients
+  {
+    c:character, done?:boolean, source <- read source
+    break-if done?
+    $write-to-file file, c
+    loop
+  }
+  $close-file file
 ]
diff --git a/filesystem.mu b/filesystem.mu
index 274397be..3e6c45f7 100644
--- a/filesystem.mu
+++ b/filesystem.mu
@@ -1,16 +1,22 @@
+# example program: copy one file into another, character by character
+# BEWARE: this will modify your file system
+# before running it, put some text into /tmp/mu-x
+# after running it, check /tmp/mu-y
+
 def main [
   local-scope
-  $print [reading characters from /tmp/mu-fs], 10/newline
-  # initialize filesystem
-  fs:address:filesystem <- copy 0/real-filesystem
-  content-source:address:source:character <- start-reading fs, [/tmp/mu-fs]
-  # read from channel until exhausted and print out characters
+  source-file:address:source:character <- start-reading 0/real-filesystem, [/tmp/mu-x]
+  sink-file:address:sink:character, write-routine:number <- start-writing 0/real-filesystem, [/tmp/mu-y]
   {
-    c:character, done?:boolean, content-source <- read content-source
+    c:character, done?:boolean, source-file <- read source-file
     break-if done?
-    $print [  ], c, 10/newline
+    eof?:boolean <- equal c, -1
+    break-if eof?
+    sink-file <- write sink-file, c
     loop
   }
-  $print [done reading], 10/newline
-  # TODO: writing to file
+  close sink-file
+  # make sure to wait for the file to be actually written to disk
+  # (Mu practices structured concurrency: http://250bpm.com/blog:71)
+  wait-for-routine write-routine
 ]