Login
7 branches 0 tags
Ben (X13/Void) Used the new [min]/[max] for the day14 test 153e296 4 years ago 315 Commits
nujel / stdlib / flow.nuj
; Nujel - Copyright (C) 2020-2021 - Benjamin Vincent Schulenburg
; This project uses the MIT license, a copy should be included under /LICENSE

;; Mostly macros implementing different control flow constructs

[defmacro if-not [pred then else]
          `[if ~pred ~else ~then]]

[defmacro if-let [binding then else]
          `[let* [def ~[car binding] ~[cadr binding]]
                 [if ~[car binding] ~then ~else]]]

[defmacro when-let [binding . body]
          `[if-let ~binding ~[cons 'do body] #nil]]

[defmacro when-not [pred . body]
          "Evalutes to BODY if PRED is false"
          `[if ~pred #nil [do ~@body]]]

[defmacro when [pred . body]
          "Evalutes to BODY if PRED is true"
          `[if ~pred [do ~@body] #nil]]

[defun let/arg [arg]
       [when-not [pair? arg] [throw `[:invalid-let-form "Please fix the structure of the let form" ~arg]]]
       [when-not [symbol? [car arg]] [throw `[:invalid-let-form "Please fix the structure of the let form" ~arg]]]
       `[def ~[car arg] ~[cadr arg]]]
[defun let/args [args]
       [if-not args #nil
               [cons [let/arg [car args]]
                     [let/args [cdr args]]]]]
[defmacro let [bindings . body]
          "Evalutes to BODY if PRED is true"
          `[let* [do ~@[let/args bindings] ~@body]]]

[defun case/clauses/multiple [key-sym cases]
       [when cases
             [cons [list '== key-sym [car cases]]
                   [case/clauses/multiple key-sym [cdr cases]]]]]
[defun case/clauses [key-sym clauses]
       [when clauses
             [if [== [caar clauses] 'otherwise]
                 [cons 'do [cdar clauses]]
                 [list 'if
                       [if [pair? [caar clauses]]
                           [if [and [== [car [caar clauses]] 'quote]
                                    [last? [cdr [caar clauses]]]
                                    [symbol? [cadr [caar clauses]]]]
                               [list '== key-sym [caar clauses]]
                               [cons 'or [case/clauses/multiple key-sym [caar clauses]]]]
                           [list '== key-sym [caar clauses]]]
                       [cons 'do [cdar clauses]]
                       [case/clauses key-sym [cdr clauses]]]]]]
[defmacro case [key-form . clauses]
          [def key-sym [gensym]]
          [list 'let*
                [list 'def key-sym key-form]
                [case/clauses key-sym clauses]]]

[defmacro cond body
          "Contains multiple cond clauses"
          [when body
                [list 'if
                      [caar body]
                      [cons 'do [cdar body]]
                      [macro-apply cond [cdr body]]]]]

[defmacro for [for-loop . body]
          "For loops, [for [name start stop] body]"
          [def symbol-name [car for-loop]]
	  [def loop-start [cadr for-loop]]
	  [def loop-stop  [caddr for-loop]]
	  [def dir 1]
	  [when [cadddr for-loop] [set! dir [cadddr for-loop]]]
	  [when-not [symbol? symbol-name]
	            [throw [list :invalid-for "Expected a symbol name within the for loop" symbol-name]]]
          [when-not loop-start
	            [throw [list :invalid-for "Expected a start value at the second position" for-loop]]]
          [when-not loop-stop
	            [throw [list :invalid-for "Expected a stop value at the third position" for-loop]]]
	  `[let [[~symbol-name ~loop-start]]
	        [while [!= ~symbol-name ~loop-stop]
                       ~@body
		       [set! ~symbol-name [add/int ~dir ~symbol-name]]
	        ]
	   ]
]

[defun thread/-> [init fun]
       [if-not fun init
          `[~[caar fun] ~[thread/-> init [cdr fun]] ~@[cdar fun]]]]
[defmacro -> [init . fun]
          "Thread init as the first argument through every function in fun"
	  [thread/-> init [nreverse fun]]]

[defun thread/->> [init fun]
       [if-not fun init
           [append [car fun] [cons [thread/->> init [cdr fun]] #nil]]]]
[defmacro ->> [init . fun]
          "Thread init as the last argument through every function in fun"
	  [thread/->> init [nreverse fun]]]