Login
7 branches 0 tags
Ben (X13/Arch) Improved perf. reporting 25757e2 3 years ago 816 Commits
nujel / binlib / io.nuj
; Nujel - Copyright (C) 2020-2021 - Benjamin Vincent Schulenburg
; This project uses the MIT license, a copy should be included under /LICENSE

[defn file/read [path]
      "Read in a file using the Nujel reader"
      [read [file/load path]]]

[defn file/read/single [path]
      "Read a single value from a file"
      [car [file/read path]]]

[defn file/eval [path environment]
       "Evaluate a Nujel source file in the current context"
       [when-not environment [set! environment root-closure]]
       [eval-in environment [cons 'do [read [file/read path]]]]]

[defn file/compile [path environment]
      "Compile a Nujel source file into optimized object code"
      [def source [cons 'do [read [file/read path]]]]
      [def object-code [compile* source [or environment [environment*]]]]
      [file/write [if object-code [string/write object-code] ""]
                  [cat [path/without-extension path] ".no"]]
      [return object-code]]

[defn file/compile/module [path environment base-dir]
      "Compile a Nujel source file into optimized object code"
      [def module-name [string->keyword [path/without-extension [string/cut path [length base-dir]]]]]
      [def source `[defmodule/defer ~module-name [def *module* ~module-name] ~@[read [file/read path]]]]
      [def object-code [compile* source [or environment [environment*]]]]
      [file/write [if object-code [string/write object-code] ""]
                  [cat [path/without-extension path] ".no"]]
      [return object-code]]

[defn file/compile/argv []
      [def path [car [last-pair repl/args]]]
      [def module [index-of path "_modules/"]]
      [if [>= module 0]
          [file/compile/module path #nil [string/cut path 0 [+ module 9]]]
          [file/compile path]]]

[defn file/test/module/run [tests module-name]
      [require :test]
      [doseq [expr tests]
             [test/run-test! [eval [cadr expr]]
                             `[do [require ~module-name] ~@[cddr expr]]]]]

[defn file/test/valid-test-form? [form]
      [== [car form] 'deftest]]

[defn file/test/module [path base-dir]
      "Test a module by running all contained tests"
      [def rel-path [string/cut path [length base-dir]]]
      [when [== [buffer/ref rel-path 0] #\/]
            [set! rel-path [string/cut rel-path 1]]]
      [def module-name [string->keyword [path/without-extension rel-path]]]
      [require :test]
      [test/init!]
      [-> [read [file/read path]]
          [filter file/test/valid-test-form?]
          [file/test/module/run module-name]]
      [test/finish! [ansi-blue module-name]]]

[defn file/test/directory [base-dir]
      "Compile a Nujel source file into optimized object code"
      [-> [directory/read-recursive base-dir]
          [flatten]
          [sort]
          [filter [path/ext?! "nuj"]]
          [map [fn [path] [file/test/module path base-dir]]]
          [sum]]]

[defn file/file? [filename]
       [ref [file/stat filename] :regular-file?]]

[defn file/dir? [filename]
       [ref [file/stat filename] :directory?]]

[defn directory/read-relative [path]
      [map [directory/read path]
           [fn [a]
               [cat path "/" a]]]]

[defn directory/read-recursive [path]
       [flatten [map [directory/read-relative path]
                     [fn [A] [if [file/dir? A]
                                 [directory/read-recursive A]
                                 A]]]]]

[defn load [filename]
  [try [fn [err]
         [print/error err]
         #f]
       [file/eval filename]
       [pfmtln "Loaded {filename}"]
       #t]]

[defn popen/trim [cmd]
  "Run CMD using popen and return the trimmed stdout"
  [trim [cdr [popen cmd]]]]

[def +root-working-dir+ [path/working-directory]]

[defn file/module-loader [name]
      [def module-path [fmt "{+root-working-dir+}/modules/{}.nuj" [keyword->string name]]]
      [def source [file/read module-path]]
      [when-not source [return #nil]]
      [def expr [list 'module [cons do [read source]]]]
      [def mod [eval expr]]
      [return mod]]

[module/add-loader file/module-loader]