release 0.1.0
This commit is contained in:
commit
30d94536a9
90 changed files with 7722 additions and 0 deletions
17
modules/core/assert.owa
Normal file
17
modules/core/assert.owa
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
(namespace assert
|
||||
(defmacro ok! [] (if (bool.and $%&)
|
||||
:true
|
||||
(throw! "assertion failed")))
|
||||
|
||||
(defmacro not! [] (if (bool.and $%&)
|
||||
(throw! "assertion failed")
|
||||
:true))
|
||||
|
||||
(defmacro eq! [] (if-eq $(%&)
|
||||
:true
|
||||
(throw! "assertion failed")))
|
||||
|
||||
(defmacro nq! [] (if-eq $(%&)
|
||||
(throw! "assertion failed")
|
||||
:true))
|
||||
)
|
||||
10
modules/core/ast.owa
Normal file
10
modules/core/ast.owa
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
(namespace ast
|
||||
(defmacro pack! [v]
|
||||
(builtins.ast.pack $v))
|
||||
|
||||
(defmacro value! [v]
|
||||
(map.get (ast.pack! $v) :data))
|
||||
|
||||
(defmacro type! [v]
|
||||
(map.get (ast.pack! $v) :type))
|
||||
)
|
||||
12
modules/core/branch.owa
Normal file
12
modules/core/branch.owa
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
(seq
|
||||
;; builtins
|
||||
(def if-eq builtins.cond.if_eq)
|
||||
(def match builtins.cond.match)
|
||||
(def if-has builtins.cond.if_has)
|
||||
|
||||
(defmacro if [cond then]
|
||||
(if-eq (:false $cond) (seq $%&) (seq $then)))
|
||||
|
||||
(defmacro unless [cond then]
|
||||
(if-eq (:false $cond) (seq $then) (seq $%&)))
|
||||
)
|
||||
25
modules/core/cmp.owa
Normal file
25
modules/core/cmp.owa
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
(seq
|
||||
(defmacro eq? <Bool>[]
|
||||
(if-eq ($%%) :true :false))
|
||||
(defmacro nq? <Bool>[]
|
||||
(if-eq ($%%) :false :true))
|
||||
|
||||
(fn cmp <Keyword>[left right]
|
||||
(match (builtins.cmp left right)
|
||||
(-1 :less)
|
||||
(0 :equal)
|
||||
(1 :greater)))
|
||||
|
||||
|
||||
(fn lt? <Bool>[left right]
|
||||
(eq? (cmp left right) :less))
|
||||
|
||||
(fn lte? <Bool>[left right]
|
||||
(bool.or (lt? left right) (eq? left right)))
|
||||
|
||||
(fn gt? <Bool>[left right]
|
||||
(eq? (cmp left right) :greater))
|
||||
|
||||
(fn gte? <Bool>[left right]
|
||||
(bool.or (gt? left right) (eq? left right)))
|
||||
)
|
||||
22
modules/core/error.owa
Normal file
22
modules/core/error.owa
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
(seq
|
||||
(fn throw! []
|
||||
(throw.runtime_error! (str.join "" %%)))
|
||||
(fn panic! [v]
|
||||
(throw.panic! v))
|
||||
(fn unreachable! []
|
||||
(throw! "Reached unreachable code"))
|
||||
(fn not_implemented! []
|
||||
(throw! "Not implemented"))
|
||||
(def try builtins.errors.try)
|
||||
|
||||
(defmacro catch [pattern then]
|
||||
(lambda [msg type] (if-eq (type $pattern)
|
||||
$then
|
||||
:null)))
|
||||
|
||||
(namespace throw
|
||||
(def panic! builtins.errors.throw_panic)
|
||||
(def type_error! builtins.errors.throw_type_error)
|
||||
(def arity_error! builtins.errors.throw_arity_error)
|
||||
(def runtime_error! builtins.errors.throw_runtime_error)
|
||||
))
|
||||
32
modules/core/ffi.owa
Normal file
32
modules/core/ffi.owa
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
(namespace ffi
|
||||
(def unload builtins.ffi.unload)
|
||||
|
||||
(def ctypes [
|
||||
:i8 :i16 :i32 :i64
|
||||
:u8 :u16 :u32 :u64
|
||||
:f32 :f64
|
||||
:ptr
|
||||
:str
|
||||
])
|
||||
|
||||
(defmacro extern [name libname]
|
||||
(namespace $name
|
||||
(builtins.ffi.load $libname)
|
||||
(fn call [symbol signature args]
|
||||
(builtins.ffi.call $libname symbol signature args)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro native [name libname]
|
||||
(namespace $name
|
||||
(builtins.ffi.load $libname)
|
||||
(defmacro fn [name symbol args ret]
|
||||
(def '$name #(builtins.ffi.call $libname '$symbol ['$args '$ret] %&))
|
||||
)
|
||||
$%&
|
||||
)
|
||||
)
|
||||
|
||||
(extern ucrtbase "ucrtbase.dll")
|
||||
)
|
||||
8
modules/core/lambda.owa
Normal file
8
modules/core/lambda.owa
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
(seq
|
||||
;; builtins
|
||||
(def apply builtins.apply)
|
||||
(def lambda builtins.lambda)
|
||||
|
||||
(defmacro fn [name params body]
|
||||
(def $name (lambda $params $body)))
|
||||
)
|
||||
23
modules/core/loop.owa
Normal file
23
modules/core/loop.owa
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
(seq
|
||||
(def break builtins.flow.break)
|
||||
(def continue builtins.flow.continue)
|
||||
(def loop builtins.flow.loop)
|
||||
|
||||
(defmacro return []
|
||||
(builtins.flow.return $%% null))
|
||||
|
||||
(defmacro while [cond] (loop
|
||||
(if (eq? $cond :false) (break) :null)
|
||||
$%&))
|
||||
|
||||
(defmacro do-while [cond] (loop
|
||||
$%&
|
||||
(if (eq? $cond :false) (break) :null)))
|
||||
|
||||
(defmacro for [var iter] (vec.map
|
||||
(lambda [x] (seq
|
||||
(def $var x)
|
||||
$%&))
|
||||
(vec.from $iter)
|
||||
))
|
||||
)
|
||||
25
modules/core/main.owa
Normal file
25
modules/core/main.owa
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
(builtins.seq
|
||||
(builtins.def include builtins.include)
|
||||
|
||||
(include "scope")
|
||||
(include "branch")
|
||||
(include "lambda")
|
||||
|
||||
(def exec builtins.exec)
|
||||
(def trace builtins.trace)
|
||||
(def typeof builtins.typeof)
|
||||
|
||||
(fn identity [x] x)
|
||||
|
||||
(include "types")
|
||||
(include "assert")
|
||||
(include "ast")
|
||||
(include "cmp")
|
||||
(include "error")
|
||||
(include "ffi")
|
||||
(include "loop")
|
||||
(include "math")
|
||||
(include "test")
|
||||
|
||||
(test.space "core" (include "tests/main"))
|
||||
)
|
||||
14
modules/core/math.owa
Normal file
14
modules/core/math.owa
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
(seq
|
||||
(def + builtins.math.add)
|
||||
(def - builtins.math.sub)
|
||||
(def * builtins.math.mul)
|
||||
(def / builtins.math.div)
|
||||
(def % builtins.math.mod)
|
||||
(def ** builtins.math.pow)
|
||||
|
||||
(fn ++ <Number>[<Number>x]
|
||||
(+ x 1))
|
||||
|
||||
(fn -- <Number>[<Number>x]
|
||||
(- x 1))
|
||||
)
|
||||
22
modules/core/scope.owa
Normal file
22
modules/core/scope.owa
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
(builtins.seq
|
||||
;; builtins
|
||||
(builtins.def def builtins.def)
|
||||
(def lookup builtins.lookup)
|
||||
(def set! builtins.set!)
|
||||
(def scope builtins.scope)
|
||||
|
||||
;; macro
|
||||
(def macro builtins.macro)
|
||||
(def defmacro (macro [name params body]
|
||||
(def $name (macro $params $body))))
|
||||
|
||||
;; flow
|
||||
(defmacro seq []
|
||||
(builtins.seq :null $%&))
|
||||
(defmacro namespace [name] (def $name (scope $%&)))
|
||||
|
||||
;; other
|
||||
(defmacro mut! [v fn] (seq
|
||||
(set! (ast.value! $v) ($fn $v $%&)))
|
||||
)
|
||||
)
|
||||
16
modules/core/test.owa
Normal file
16
modules/core/test.owa
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
(namespace test
|
||||
(def target (lookup __test__ null))
|
||||
|
||||
(defmacro if-target [then]
|
||||
(if-eq (test.target null) :null (seq $%%)))
|
||||
|
||||
(defmacro case [name] (test.if-target
|
||||
(builtins.errors.try
|
||||
(scope $%& (trace "Running test \"" $name "\": OK ✅"))
|
||||
#(trace "Running test \"" $name "\": FAILED ❌ (" %2 ": " %1 ")"))))
|
||||
|
||||
(defmacro space [name] (if
|
||||
(bool.or (eq? test.target $name) (eq? test.target "."))
|
||||
(namespace $name (seq $%&))
|
||||
))
|
||||
)
|
||||
38
modules/core/tests/bool.owa
Normal file
38
modules/core/tests/bool.owa
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
(namespace tests.bool
|
||||
(test.case "bool.bool?"
|
||||
(assert.ok! (bool? true))
|
||||
(assert.ok! (bool? false))
|
||||
(assert.not! (bool? 1))
|
||||
)
|
||||
|
||||
(test.case "bool.not"
|
||||
(assert.eq! (bool.not true) false)
|
||||
(assert.eq! (bool.not false) true)
|
||||
)
|
||||
|
||||
(test.case "bool.and"
|
||||
(assert.ok! (bool.and true true))
|
||||
(assert.not! (bool.and true false))
|
||||
(assert.not! (bool.and false true))
|
||||
(assert.not! (bool.and false false))
|
||||
)
|
||||
|
||||
(test.case "bool.or"
|
||||
(assert.ok! (bool.or true true))
|
||||
(assert.ok! (bool.or true false))
|
||||
(assert.ok! (bool.or false true))
|
||||
(assert.not! (bool.or false false))
|
||||
)
|
||||
|
||||
(test.case "bool.nand"
|
||||
(assert.not! (bool.nand true true))
|
||||
(assert.ok! (bool.nand true false))
|
||||
(assert.ok! (bool.nand false true))
|
||||
(assert.ok! (bool.nand false false))
|
||||
)
|
||||
|
||||
(test.case "bool.new"
|
||||
(assert.eq! (bool.new true) true)
|
||||
(assert.eq! (bool.new false) false)
|
||||
)
|
||||
)
|
||||
41
modules/core/tests/cmp.owa
Normal file
41
modules/core/tests/cmp.owa
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
(namespace tests.cmp
|
||||
(test.case "cmp.eq?"
|
||||
(assert.ok! (eq? 1 1))
|
||||
(assert.not! (eq? 1 2))
|
||||
)
|
||||
|
||||
(test.case "cmp.nq?"
|
||||
(assert.ok! (nq? 1 2))
|
||||
(assert.not! (nq? 1 1))
|
||||
)
|
||||
|
||||
(test.case "cmp.cmp"
|
||||
(assert.eq! (cmp 1 2) :less)
|
||||
(assert.eq! (cmp 2 1) :greater)
|
||||
(assert.eq! (cmp 1 1) :equal)
|
||||
)
|
||||
|
||||
(test.case "cmp.lt?"
|
||||
(assert.ok! (lt? 1 2))
|
||||
(assert.not! (lt? 2 1))
|
||||
(assert.not! (lt? 1 1))
|
||||
)
|
||||
|
||||
(test.case "cmp.lte?"
|
||||
(assert.ok! (lte? 1 2))
|
||||
(assert.ok! (lte? 1 1))
|
||||
(assert.not! (lte? 2 1))
|
||||
)
|
||||
|
||||
(test.case "cmp.gt?"
|
||||
(assert.ok! (gt? 2 1))
|
||||
(assert.not! (gt? 1 2))
|
||||
(assert.not! (gt? 1 1))
|
||||
)
|
||||
|
||||
(test.case "cmp.gte?"
|
||||
(assert.ok! (gte? 2 1))
|
||||
(assert.ok! (gte? 1 1))
|
||||
(assert.not! (gte? 1 2))
|
||||
)
|
||||
)
|
||||
42
modules/core/tests/loop.owa
Normal file
42
modules/core/tests/loop.owa
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
(namespace tests.loop
|
||||
(test.case "while.basic-true"
|
||||
(def counter 0)
|
||||
(while (eq? counter 0)
|
||||
(set! counter 1))
|
||||
(assert.eq! counter 1)
|
||||
)
|
||||
|
||||
(test.case "while.condition-false"
|
||||
(def counter 5)
|
||||
(while (lt? counter 0)
|
||||
(set! counter (+ counter 1)))
|
||||
(assert.eq! counter 5)
|
||||
)
|
||||
|
||||
(test.case "while.counting-loop"
|
||||
(def n 0)
|
||||
(while (lt? n 10)
|
||||
(set! n (+ n 1)))
|
||||
(assert.eq! n 10)
|
||||
)
|
||||
|
||||
(test.case "while.loop-condition-reached"
|
||||
(def i 0)
|
||||
(while (lt? i 5)
|
||||
(set! i (+ i 1)))
|
||||
(assert.eq! i 5)
|
||||
)
|
||||
|
||||
(test.case "while.nested"
|
||||
(def outer 0)
|
||||
(def inner 0)
|
||||
(def total 0)
|
||||
(while (lt? outer 3)
|
||||
(set! inner 0)
|
||||
(while (lt? inner 2)
|
||||
(set! total (+ total 1))
|
||||
(set! inner (+ inner 1)))
|
||||
(set! outer (+ outer 1)))
|
||||
(assert.eq! total 6)
|
||||
)
|
||||
)
|
||||
14
modules/core/tests/main.owa
Normal file
14
modules/core/tests/main.owa
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
(seq
|
||||
(include "vec")
|
||||
(include "str")
|
||||
(include "set")
|
||||
(include "map")
|
||||
(include "bool")
|
||||
(include "option")
|
||||
(include "scope")
|
||||
(include "null")
|
||||
(include "cmp")
|
||||
(include "math")
|
||||
(include "types")
|
||||
(include "loop")
|
||||
)
|
||||
83
modules/core/tests/map.owa
Normal file
83
modules/core/tests/map.owa
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
(namespace tests.map
|
||||
(test.case "map.len"
|
||||
(assert.eq! (map.len (map.new)) 0)
|
||||
)
|
||||
|
||||
(test.case "map.empty?"
|
||||
(assert.ok! (map.empty? (map.new)))
|
||||
)
|
||||
|
||||
(test.case "map.is-empty?"
|
||||
(assert.ok! (map.is-empty? (map.new)))
|
||||
)
|
||||
|
||||
(test.case "map.get"
|
||||
(seq
|
||||
(def m (map.new :a 1 :b 2))
|
||||
(assert.eq! (map.get m :a) 1)
|
||||
(assert.eq! (map.get m :b) 2)
|
||||
(assert.eq! (map.get m :c) null)
|
||||
)
|
||||
)
|
||||
|
||||
(test.case "map.put"
|
||||
(seq
|
||||
(def m (map.new :a 1))
|
||||
(def m2 (map.put m :b 2))
|
||||
(assert.eq! (map.len m2) 2)
|
||||
(assert.eq! (map.get m2 :b) 2)
|
||||
)
|
||||
)
|
||||
|
||||
(test.case "map.has-key?"
|
||||
(seq
|
||||
(def m (map.new :a 1 :b 2))
|
||||
(assert.ok! (map.has-key? m :a))
|
||||
(assert.not! (map.has-key? m :c))
|
||||
)
|
||||
)
|
||||
|
||||
(test.case "map.has-value?"
|
||||
(seq
|
||||
(def m (map.new :a 1 :b 2))
|
||||
(assert.ok! (map.has-value? m 1))
|
||||
(assert.not! (map.has-value? m 5))
|
||||
)
|
||||
)
|
||||
|
||||
(test.case "map.keys"
|
||||
(seq
|
||||
(def m (map.new :a 1 :b 2))
|
||||
(def ks (map.keys m))
|
||||
(assert.eq! (vec.len ks) 2)
|
||||
)
|
||||
)
|
||||
|
||||
(test.case "map.values"
|
||||
(seq
|
||||
(def m (map.new :a 1 :b 2))
|
||||
(def vs (map.values m))
|
||||
(assert.eq! (vec.len vs) 2)
|
||||
)
|
||||
)
|
||||
|
||||
(test.case "map.merge"
|
||||
(seq
|
||||
(def m1 (map.new :a 1 :b 2))
|
||||
(def m2 (map.new :b 20 :c 3))
|
||||
(def m3 (map.merge m1 m2))
|
||||
(assert.eq! (map.get m3 :a) 1)
|
||||
(assert.eq! (map.get m3 :b) 20)
|
||||
(assert.eq! (map.get m3 :c) 3)
|
||||
)
|
||||
)
|
||||
|
||||
(test.case "map.dissoc"
|
||||
(seq
|
||||
(def m (map.new :a 1 :b 2 :c 3))
|
||||
(def m2 (map.dissoc m :b))
|
||||
(assert.eq! (map.len m2) 2)
|
||||
(assert.not! (map.has-key? m2 :b))
|
||||
)
|
||||
)
|
||||
)
|
||||
40
modules/core/tests/math.owa
Normal file
40
modules/core/tests/math.owa
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
(namespace tests.math
|
||||
(test.case "math.add"
|
||||
(assert.eq! (+ 1 2) 3)
|
||||
(assert.eq! (+ 0 0) 0)
|
||||
)
|
||||
|
||||
(test.case "math.sub"
|
||||
(assert.eq! (- 5 3) 2)
|
||||
(assert.eq! (- 1 1) 0)
|
||||
)
|
||||
|
||||
(test.case "math.mul"
|
||||
(assert.eq! (* 3 4) 12)
|
||||
(assert.eq! (* 0 5) 0)
|
||||
)
|
||||
|
||||
(test.case "math.div"
|
||||
(assert.eq! (/ 10 2) 5)
|
||||
)
|
||||
|
||||
(test.case "math.mod"
|
||||
(assert.eq! (% 10 3) 1)
|
||||
(assert.eq! (% 5 5) 0)
|
||||
)
|
||||
|
||||
(test.case "math.pow"
|
||||
(assert.eq! (** 2 3) 8)
|
||||
(assert.eq! (** 5 2) 25)
|
||||
)
|
||||
|
||||
(test.case "math.++"
|
||||
(assert.eq! (++ 5) 6)
|
||||
(assert.eq! (++ 0) 1)
|
||||
)
|
||||
|
||||
(test.case "math.--"
|
||||
(assert.eq! (-- 5) 4)
|
||||
(assert.eq! (-- 0) -1)
|
||||
)
|
||||
)
|
||||
8
modules/core/tests/null.owa
Normal file
8
modules/core/tests/null.owa
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
(namespace tests.null
|
||||
(test.case "null.null?"
|
||||
(assert.ok! (null? null))
|
||||
(assert.ok! (null? :nil))
|
||||
(assert.not! (null? 0))
|
||||
(assert.not! (null? false))
|
||||
)
|
||||
)
|
||||
33
modules/core/tests/option.owa
Normal file
33
modules/core/tests/option.owa
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
(namespace tests.option
|
||||
(test.case "option.ok"
|
||||
(seq
|
||||
(def opt (option.ok 42))
|
||||
(assert.ok! (option.ok? opt))
|
||||
(assert.eq! (vec.get opt 1) 42)
|
||||
)
|
||||
)
|
||||
|
||||
(test.case "option.err"
|
||||
(seq
|
||||
(def opt (option.err "error"))
|
||||
(assert.ok! (option.err? opt))
|
||||
(assert.eq! (vec.get opt 1) "error")
|
||||
)
|
||||
)
|
||||
|
||||
(test.case "option.ok?"
|
||||
(assert.ok! (option.ok? (option.ok 1)))
|
||||
(assert.not! (option.ok? (option.err "x")))
|
||||
)
|
||||
|
||||
(test.case "option.err?"
|
||||
(assert.ok! (option.err? (option.err "x")))
|
||||
(assert.not! (option.err? (option.ok 1)))
|
||||
)
|
||||
|
||||
(test.case "option.option?"
|
||||
(assert.ok! (option? (option.ok 1)))
|
||||
(assert.ok! (option? (option.err "x")))
|
||||
(assert.not! (option? [1 2]))
|
||||
)
|
||||
)
|
||||
78
modules/core/tests/scope.owa
Normal file
78
modules/core/tests/scope.owa
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
(namespace tests.scopes
|
||||
(test.case "def"
|
||||
(def x 1)
|
||||
(assert.eq! x 1)
|
||||
|
||||
(def [y z] [1 2])
|
||||
(assert.eq! y 1)
|
||||
(assert.eq! z 2)
|
||||
)
|
||||
|
||||
(test.case "def bounded"
|
||||
(def x 1)
|
||||
(try
|
||||
(def x 2)
|
||||
(catch :Panic (return))
|
||||
)
|
||||
(unreachable!)
|
||||
)
|
||||
|
||||
(test.case "set!"
|
||||
(def [x y] [1 1])
|
||||
(set! x 2)
|
||||
(assert.eq! x 2)
|
||||
|
||||
(set! [x y] [3 4])
|
||||
(assert.eq! x 3)
|
||||
(assert.eq! y 4)
|
||||
)
|
||||
|
||||
(test.case "set! unbounded"
|
||||
(try
|
||||
(set! x 2)
|
||||
(catch :UnboundVariable (return))
|
||||
)
|
||||
(unreachable!)
|
||||
)
|
||||
|
||||
(test.case "lookup"
|
||||
(def x 1)
|
||||
(assert.eq! (lookup x null) 1)
|
||||
(assert.eq! (lookup y null) null)
|
||||
)
|
||||
|
||||
(test.case "inheritance"
|
||||
(scope
|
||||
(def x 1)
|
||||
(scope
|
||||
(assert.eq! x 1)
|
||||
(set! x 2)
|
||||
)
|
||||
(assert.eq! x 2)
|
||||
)
|
||||
)
|
||||
|
||||
(test.case "shadowing"
|
||||
(scope
|
||||
(def x 100)
|
||||
(scope
|
||||
(def x 1)
|
||||
)
|
||||
(assert.eq! x 100)
|
||||
)
|
||||
(assert.eq! (lookup x null) null)
|
||||
)
|
||||
|
||||
(test.case "leakage"
|
||||
(scope (def x 1))
|
||||
(assert.eq! (lookup x null) null)
|
||||
|
||||
(scope (def y 2))
|
||||
(assert.eq! (lookup y null) null)
|
||||
|
||||
(scope
|
||||
(scope (def z 1))
|
||||
(assert.eq! (lookup z null) null)
|
||||
)
|
||||
)
|
||||
)
|
||||
44
modules/core/tests/set.owa
Normal file
44
modules/core/tests/set.owa
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
(namespace tests.set
|
||||
(test.case "set.empty?"
|
||||
(assert.ok! (set.empty? (set.new)))
|
||||
(assert.not! (set.empty? (set.new 1)))
|
||||
)
|
||||
|
||||
(test.case "set.len"
|
||||
(assert.eq! (set.len (set.new)) 0)
|
||||
(assert.eq! (set.len (set.new 1)) 1)
|
||||
(assert.eq! (set.len (set.new 1 2 3)) 3)
|
||||
)
|
||||
|
||||
(test.case "set.has"
|
||||
(assert.ok! (set.has (set.new 1 2 3) 2))
|
||||
(assert.not! (set.has (set.new 1 2 3) 5))
|
||||
)
|
||||
|
||||
(test.case "set.add"
|
||||
(assert.ok! (set.has (set.add (set.new 1 2) 3) 3))
|
||||
(assert.eq! (set.len (set.add (set.new 1 2) 3)) 3)
|
||||
)
|
||||
|
||||
(test.case "set.remove"
|
||||
(assert.not! (set.has (set.remove (set.new 1 2 3) 2) 2))
|
||||
(assert.eq! (set.len (set.remove (set.new 1 2 3) 2)) 2)
|
||||
)
|
||||
|
||||
(test.case "set.union"
|
||||
(assert.eq! (set.len (set.union (set.new 1 2) (set.new 2 3))) 3)
|
||||
(assert.ok! (set.has (set.union (set.new 1 2) (set.new 2 3)) 1))
|
||||
(assert.ok! (set.has (set.union (set.new 1 2) (set.new 2 3)) 3))
|
||||
)
|
||||
|
||||
(test.case "set.intersection"
|
||||
(assert.eq! (set.len (set.intersection (set.new 1 2 3) (set.new 2 3 4))) 2)
|
||||
(assert.ok! (set.has (set.intersection (set.new 1 2 3) (set.new 2 3 4)) 2))
|
||||
(assert.ok! (set.has (set.intersection (set.new 1 2 3) (set.new 2 3 4)) 3))
|
||||
)
|
||||
|
||||
(test.case "set.difference"
|
||||
(assert.eq! (set.len (set.difference (set.new 1 2 3) (set.new 2 3))) 1)
|
||||
(assert.ok! (set.has (set.difference (set.new 1 2 3) (set.new 2 3)) 1))
|
||||
)
|
||||
)
|
||||
67
modules/core/tests/str.owa
Normal file
67
modules/core/tests/str.owa
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
(namespace tests.str
|
||||
(test.case "str.len"
|
||||
(assert.eq! (str.len "") 0)
|
||||
(assert.eq! (str.len "hello") 5)
|
||||
)
|
||||
|
||||
(test.case "str.empty?"
|
||||
(assert.ok! (str.empty? ""))
|
||||
(assert.not! (str.empty? "a"))
|
||||
)
|
||||
|
||||
(test.case "str.is-empty?"
|
||||
(assert.ok! (str.is-empty? ""))
|
||||
(assert.not! (str.is-empty? "a"))
|
||||
)
|
||||
|
||||
(test.case "str.first"
|
||||
(assert.eq! (str.first "hello") "h")
|
||||
)
|
||||
|
||||
(test.case "str.last"
|
||||
(assert.eq! (str.last "hello") "o")
|
||||
)
|
||||
|
||||
(test.case "str.concat"
|
||||
(assert.eq! (str.concat "hello" " " "world") "hello world")
|
||||
)
|
||||
|
||||
(test.case "str.substring"
|
||||
(assert.eq! (str.substring "hello" 0 3) "hel")
|
||||
(assert.eq! (str.substring "hello" 1 4) "ell")
|
||||
)
|
||||
|
||||
(test.case "str.take"
|
||||
(assert.eq! (str.take "hello" 3) "hel")
|
||||
)
|
||||
|
||||
(test.case "str.drop"
|
||||
(assert.eq! (str.drop "hello" 2) "llo")
|
||||
)
|
||||
|
||||
(test.case "str.reverse"
|
||||
(assert.eq! (str.reverse "hello") "olleh")
|
||||
)
|
||||
|
||||
(test.case "str.starts-with?"
|
||||
(assert.ok! (str.starts-with? "hello" "hel"))
|
||||
(assert.not! (str.starts-with? "hello" "xyz"))
|
||||
)
|
||||
|
||||
(test.case "str.ends-with?"
|
||||
(assert.ok! (str.ends-with? "hello" "lo"))
|
||||
(assert.not! (str.ends-with? "hello" "xyz"))
|
||||
)
|
||||
|
||||
(test.case "str.split"
|
||||
(assert.eq! (str.split "hello world" " ") ["hello" "world"])
|
||||
(assert.eq! (str.split "hello world" "w") ["hello " "orld"])
|
||||
(assert.eq! (str.split "hello world" "x") ["hello world"])
|
||||
)
|
||||
|
||||
(test.case "str.join"
|
||||
(assert.eq! (str.join " " ["hello" "world"]) "hello world")
|
||||
(assert.eq! (str.join "w" ["hello " "orld"]) "hello world")
|
||||
(assert.eq! (str.join "x" ["hello world"]) "hello world")
|
||||
)
|
||||
)
|
||||
53
modules/core/tests/types.owa
Normal file
53
modules/core/tests/types.owa
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
(namespace tests.types
|
||||
(test.case "types.is?"
|
||||
(assert.ok! (is? 42 :int))
|
||||
(assert.ok! (is? "hello" :str))
|
||||
(assert.ok! (is? [] :vec))
|
||||
(assert.not! (is? 42 :str))
|
||||
)
|
||||
|
||||
(test.case "types.guard"
|
||||
(seq
|
||||
(def int-guard (guard :int))
|
||||
(assert.ok! (int-guard 42))
|
||||
(assert.not! (int-guard "42"))
|
||||
)
|
||||
)
|
||||
|
||||
(test.case "types.kw?"
|
||||
(assert.ok! (kw? :keyword))
|
||||
(assert.not! (kw? "not-keyword"))
|
||||
)
|
||||
|
||||
(test.case "types.type?"
|
||||
(assert.ok! (type? :int))
|
||||
(assert.ok! (type? :str))
|
||||
(assert.not! (type? :unknown))
|
||||
)
|
||||
|
||||
(test.case "types.str?"
|
||||
(assert.ok! (str? "hello"))
|
||||
(assert.not! (str? 42))
|
||||
)
|
||||
|
||||
(test.case "types.vec?"
|
||||
(assert.ok! (vec? []))
|
||||
(assert.ok! (vec? [1 2 3]))
|
||||
(assert.not! (vec? 42))
|
||||
)
|
||||
|
||||
(test.case "types.bool?"
|
||||
(assert.ok! (bool? true))
|
||||
(assert.ok! (bool? false))
|
||||
(assert.not! (bool? 1))
|
||||
)
|
||||
|
||||
(test.case "types.null?"
|
||||
(assert.ok! (null? null))
|
||||
(assert.not! (null? 0))
|
||||
)
|
||||
|
||||
(test.case "types.map.is?"
|
||||
(assert.ok! (map.is? (map.new)))
|
||||
)
|
||||
)
|
||||
91
modules/core/tests/vec.owa
Normal file
91
modules/core/tests/vec.owa
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
(namespace tests.vec
|
||||
(test.case "vec.empty?"
|
||||
(assert.ok! (vec.empty? []))
|
||||
(assert.not! (vec.empty? [1]))
|
||||
)
|
||||
|
||||
(test.case "vec.len"
|
||||
(assert.eq! (vec.len []) 0)
|
||||
(assert.eq! (vec.len [1]) 1)
|
||||
(assert.eq! (vec.len [1 2 3]) 3)
|
||||
)
|
||||
|
||||
(test.case "vec.first"
|
||||
(assert.eq! (vec.first [1 2 3]) 1)
|
||||
(assert.eq! (vec.first ["a"]) "a")
|
||||
)
|
||||
|
||||
(test.case "vec.last"
|
||||
(assert.eq! (vec.last [1 2 3]) 3)
|
||||
(assert.eq! (vec.last ["x"]) "x")
|
||||
)
|
||||
|
||||
(test.case "vec.get"
|
||||
(assert.eq! (vec.get [10 20 30] 0) 10)
|
||||
(assert.eq! (vec.get [10 20 30] 1) 20)
|
||||
(assert.eq! (vec.get [10 20 30] 2) 30)
|
||||
)
|
||||
|
||||
(test.case "vec.map"
|
||||
(assert.eq!
|
||||
(vec.map (lambda [x _] (+ x 1)) [1 2 3])
|
||||
[2 3 4])
|
||||
)
|
||||
|
||||
(test.case "vec.filter"
|
||||
(assert.eq!
|
||||
(vec.filter (lambda [x _] (gt? x 1)) [1 2 3])
|
||||
[2 3])
|
||||
)
|
||||
|
||||
(test.case "vec.has"
|
||||
(assert.ok! (vec.has [1 2 3] 2))
|
||||
(assert.not! (vec.has [1 2 3] 5))
|
||||
)
|
||||
|
||||
(test.case "vec.includes?"
|
||||
(assert.ok! (vec.includes? [1 2 3] 2))
|
||||
(assert.not! (vec.includes? [1 2 3] 5))
|
||||
)
|
||||
|
||||
(test.case "vec.find"
|
||||
(assert.eq!
|
||||
(vec.find (lambda [x _] (gt? x 2)) [1 2 3 4])
|
||||
3)
|
||||
)
|
||||
|
||||
(test.case "vec.reverse"
|
||||
(assert.eq! (vec.reverse [1 2 3]) [3 2 1])
|
||||
)
|
||||
|
||||
(test.case "vec.take"
|
||||
(assert.eq! (vec.take [1 2 3 4 5] 3) [1 2 3])
|
||||
)
|
||||
|
||||
(test.case "vec.drop"
|
||||
(assert.eq! (vec.drop [1 2 3 4 5] 2) [3 4 5])
|
||||
)
|
||||
|
||||
(test.case "vec.uniq"
|
||||
(assert.eq! (vec.uniq [1 2 2 3 3 3]) [1 2 3])
|
||||
)
|
||||
|
||||
(test.case "vec.every?"
|
||||
(assert.ok! (vec.every? (lambda [x _] (gt? x 0)) [1 2 3]))
|
||||
(assert.not! (vec.every? (lambda [x _] (gt? x 1)) [1 2 3]))
|
||||
)
|
||||
|
||||
(test.case "vec.some?"
|
||||
(assert.ok! (vec.some? (lambda [x _] (gt? x 2)) [1 2 3]))
|
||||
(assert.not! (vec.some? (lambda [x _] (gt? x 5)) [1 2 3]))
|
||||
)
|
||||
|
||||
(test.case "vec.count"
|
||||
(assert.eq! (vec.count (lambda [x _] (gt? x 1)) [1 2 3]) 2)
|
||||
)
|
||||
|
||||
(test.case "vec.sum"
|
||||
(assert.eq! (vec.sum [1 2 3]) 6)
|
||||
(assert.eq! (vec.sum []) 0)
|
||||
)
|
||||
)
|
||||
23
modules/core/types/bool.owa
Normal file
23
modules/core/types/bool.owa
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
(seq
|
||||
(def true :true)
|
||||
(def false :false)
|
||||
(fn bool? [x]
|
||||
(bool.or (eq? x true) (eq? x false)))
|
||||
|
||||
(namespace bool
|
||||
(fn new [x]
|
||||
(eq? x true))
|
||||
(def __call__ new)
|
||||
|
||||
(defmacro or []
|
||||
(if-eq (false $%%) false true))
|
||||
|
||||
(defmacro and []
|
||||
(if-has false ($%%) false true))
|
||||
|
||||
(defmacro nand []
|
||||
(if-has false ($%%) true false))
|
||||
|
||||
(fn not [x]
|
||||
(if-eq (x true) false true))
|
||||
))
|
||||
39
modules/core/types/main.owa
Normal file
39
modules/core/types/main.owa
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
(seq
|
||||
(def types [
|
||||
:symbol
|
||||
:keyword
|
||||
:str
|
||||
:float
|
||||
:int
|
||||
:vec
|
||||
:call
|
||||
:set
|
||||
:map
|
||||
:quote
|
||||
:lambda
|
||||
:macro
|
||||
])
|
||||
|
||||
(fn is? [x type]
|
||||
(eq? (typeof x) type))
|
||||
(fn guard [type]
|
||||
(lambda [x] (is? x type)))
|
||||
|
||||
(def kw? (guard :keyword))
|
||||
(def kw builtins.str.kw)
|
||||
|
||||
(include "bool")
|
||||
(include "map")
|
||||
(include "null")
|
||||
(include "option")
|
||||
(include "set")
|
||||
(include "str")
|
||||
(include "struct")
|
||||
(include "vec")
|
||||
|
||||
(def vec? (guard :vec))
|
||||
(def map? (guard :map))
|
||||
|
||||
(fn type? [x]
|
||||
(vec.has types x))
|
||||
)
|
||||
94
modules/core/types/map.owa
Normal file
94
modules/core/types/map.owa
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
(namespace map
|
||||
(def type :map)
|
||||
(def is? (guard type))
|
||||
(def new builtins.map.new)
|
||||
(def __call__ new)
|
||||
|
||||
(fn keys [m]
|
||||
(vec.map #(vec.first %1) (vec.from m)))
|
||||
|
||||
(fn values [m]
|
||||
(vec.map #(vec.last %1) (vec.from m)))
|
||||
|
||||
(fn len [m]
|
||||
(vec.len (vec.from m)))
|
||||
|
||||
(fn empty? [m]
|
||||
(eq? (len m) 0))
|
||||
|
||||
(fn is-empty? [m]
|
||||
(empty? m))
|
||||
|
||||
(fn get [m key]
|
||||
(vec.fold
|
||||
(lambda [result pair _]
|
||||
(if (eq? (vec.get pair 0) key)
|
||||
(vec.get pair 1)
|
||||
result))
|
||||
null
|
||||
(vec.from m)))
|
||||
|
||||
(fn put [m key value]
|
||||
(apply apply new (vec.from m) [[key value]]))
|
||||
|
||||
(fn assoc [m key value]
|
||||
(put m key value))
|
||||
|
||||
(fn dissoc [m key]
|
||||
(apply apply new (vec.filter
|
||||
(lambda [pair _] (nq?
|
||||
(vec.get pair 0)
|
||||
key
|
||||
))
|
||||
(vec.from m))
|
||||
))
|
||||
|
||||
(fn has-key? [m key]
|
||||
(if (null? (get m key))
|
||||
false
|
||||
true))
|
||||
|
||||
(fn has-value? [m value]
|
||||
(vec.fold
|
||||
(lambda [result pair _]
|
||||
(seq
|
||||
(def k (vec.get pair 0))
|
||||
(def v (vec.get pair 1))
|
||||
(bool.or result (eq? v value))))
|
||||
false
|
||||
(vec.from m)))
|
||||
|
||||
(fn map [callback m]
|
||||
(apply new (vec.apply-flat (vec.map
|
||||
(lambda [pair _]
|
||||
(seq
|
||||
(def k (vec.get pair 0))
|
||||
(def v (vec.get pair 1))
|
||||
(def new-v (callback v k))
|
||||
[k new-v]))
|
||||
(vec.from m)))))
|
||||
|
||||
(fn filter [callback m]
|
||||
(apply new (vec.apply-flat (vec.filter
|
||||
(lambda [pair _]
|
||||
(seq
|
||||
(def k (vec.get pair 0))
|
||||
(def v (vec.get pair 1))
|
||||
(callback v k)))
|
||||
(vec.from m)))))
|
||||
|
||||
(fn merge [m1 m2]
|
||||
(apply apply new (vec.from m1) (vec.from m2)))
|
||||
|
||||
(fn merge-all []
|
||||
(vec.fold
|
||||
(lambda [acc m _]
|
||||
(merge acc m))
|
||||
(new)
|
||||
%%))
|
||||
|
||||
(fn conj [m other]
|
||||
(if (map.is? other)
|
||||
(merge m other)
|
||||
m))
|
||||
)
|
||||
5
modules/core/types/null.owa
Normal file
5
modules/core/types/null.owa
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
(seq
|
||||
(def null :null)
|
||||
(fn null? [x]
|
||||
(bool.or (eq? x null) (eq? x :nil)))
|
||||
)
|
||||
26
modules/core/types/option.owa
Normal file
26
modules/core/types/option.owa
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
(seq
|
||||
(namespace option
|
||||
(fn ok <Option>[value]
|
||||
(vec :ok value))
|
||||
|
||||
(fn ok? <Bool>[x]
|
||||
(bool.and
|
||||
(vec? x)
|
||||
(eq? (vec.first x) :ok)))
|
||||
|
||||
(fn err <Option>[value]
|
||||
(vec :err value))
|
||||
|
||||
(fn err? <Bool>[x]
|
||||
(bool.and
|
||||
(vec? x)
|
||||
(eq? (vec.first x) :err)))
|
||||
)
|
||||
|
||||
(fn option? [x]
|
||||
(bool.and
|
||||
(vec? x)
|
||||
(bool.or
|
||||
(eq? (vec.first x) :err)
|
||||
(eq? (vec.first x) :ok))))
|
||||
)
|
||||
60
modules/core/types/set.owa
Normal file
60
modules/core/types/set.owa
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
(seq
|
||||
(namespace set
|
||||
(def type :set)
|
||||
(def is? (guard type))
|
||||
(fn new [] (apply from %%))
|
||||
(def __call__ new)
|
||||
|
||||
(def fold builtins.set.fold)
|
||||
(def from builtins.set.from)
|
||||
|
||||
(def empty #{})
|
||||
(fn empty? <Bool>[s]
|
||||
(eq? s empty))
|
||||
|
||||
(fn len <Int>[<Set>s]
|
||||
(fold (lambda [acc _] (+ acc 1)) 0 s))
|
||||
|
||||
(fn has <Bool>[<Set>s item]
|
||||
(fold
|
||||
(lambda [acc elem]
|
||||
(bool.or acc (eq? elem item)))
|
||||
false
|
||||
s))
|
||||
|
||||
(fn add <Set>[<Set>s item]
|
||||
(from s [item]))
|
||||
|
||||
(fn remove <Set>[<Set>s item]
|
||||
(fold
|
||||
(lambda [acc elem]
|
||||
(if (eq? elem item)
|
||||
acc
|
||||
(from acc elem)))
|
||||
#{}
|
||||
s))
|
||||
|
||||
(fn union <Set>[]
|
||||
(apply from %%))
|
||||
|
||||
(fn intersection <Set>[<Set>s1 <Set>s2]
|
||||
(fold
|
||||
(lambda [acc elem]
|
||||
(if (has s2 elem)
|
||||
(add acc elem)
|
||||
acc))
|
||||
#{}
|
||||
s1))
|
||||
|
||||
(fn difference <Set>[<Set>s1 <Set>s2]
|
||||
(fold
|
||||
(lambda [acc elem]
|
||||
(if (has s2 elem)
|
||||
acc
|
||||
(add acc elem)))
|
||||
#{}
|
||||
s1))
|
||||
)
|
||||
|
||||
(def set? (guard set.type))
|
||||
)
|
||||
76
modules/core/types/str.owa
Normal file
76
modules/core/types/str.owa
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
(seq
|
||||
(namespace str
|
||||
(def type :str)
|
||||
(def new builtins.str.new)
|
||||
(def __call__ new)
|
||||
|
||||
(fn len <Int>[<Str>s]
|
||||
(vec.len (vec.from s)))
|
||||
|
||||
(fn concat <Str>[]
|
||||
(apply new %%))
|
||||
|
||||
(fn empty? <Bool>[<Str>s]
|
||||
(eq? s ""))
|
||||
|
||||
(fn is-empty? <Bool>[<Str>s]
|
||||
(empty? s))
|
||||
|
||||
(fn chars-at <Str>[<Str>s <Int>idx]
|
||||
(vec.get (vec.from s) idx))
|
||||
|
||||
(fn first <Str>[<Str>s]
|
||||
(chars-at s 0))
|
||||
|
||||
(fn last <Str>[<Str>s]
|
||||
(chars-at s (-- (len s))))
|
||||
|
||||
(fn substring <Str>[<Str>s <Int>start <Int>end]
|
||||
(apply concat (vec.slice (vec.from s) start end)))
|
||||
|
||||
(fn substr <Str>[<Str>s <Int>start <Int>len-sub]
|
||||
(substring s start (+ start len-sub)))
|
||||
|
||||
(fn take <Str>[<Str>s <Int>n]
|
||||
(apply concat (vec.take (vec.from s) n)))
|
||||
|
||||
(fn drop <Str>[<Str>s <Int>n]
|
||||
(apply concat (vec.drop (vec.from s) n)))
|
||||
|
||||
(fn reverse <Str>[<Str>s]
|
||||
(apply concat (vec.reverse (vec.from s))))
|
||||
|
||||
(fn starts-with? <Bool>[<Str>s <Str>prefix]
|
||||
(eq? (substring s 0 (len prefix)) prefix))
|
||||
|
||||
(fn ends-with? <Bool>[<Str>s <Str>suffix]
|
||||
(eq? (substring s (- (len s) (len suffix)) (len s)) suffix))
|
||||
|
||||
(fn split <Vec>[<Str>s <Str>sep] (seq
|
||||
(vec.fold
|
||||
(lambda [acc elem _]
|
||||
(if-eq (elem sep)
|
||||
(vec.conj acc "")
|
||||
(vec.conj (vec.take acc (- (len acc) 1))
|
||||
(str.concat (vec.last acc) elem)
|
||||
)
|
||||
))
|
||||
[""]
|
||||
(vec.from s)
|
||||
)))
|
||||
|
||||
(fn join <Str>[<Str>sep <Vec>strs]
|
||||
(if (vec.empty? strs)
|
||||
""
|
||||
(vec.fold
|
||||
(lambda [acc elem _]
|
||||
(new acc sep elem))
|
||||
(vec.first strs)
|
||||
(vec.tail strs))))
|
||||
|
||||
(fn map <Str>[callback self]
|
||||
(join "" (vec.map callback (vec.from self))))
|
||||
)
|
||||
|
||||
(def str? (guard str.type))
|
||||
)
|
||||
22
modules/core/types/struct.owa
Normal file
22
modules/core/types/struct.owa
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
(seq
|
||||
(defmacro struct [name fields] (seq
|
||||
(for field $fields
|
||||
(if (bool.not (kw? %1))
|
||||
(throw! "Struct fields must be keywords"))
|
||||
)
|
||||
(def $name {
|
||||
:__struct_type__ true
|
||||
:new (lambda [data] (vec.map
|
||||
#(if (map.has-key? data %1)
|
||||
map.get data %1
|
||||
(throw! "Missing field: " %1)
|
||||
)
|
||||
$fields))
|
||||
})
|
||||
))
|
||||
|
||||
(fn struct-type? [v]
|
||||
(if (bool.and (map? v) (map.get v :__struct_type__))
|
||||
true
|
||||
false))
|
||||
)
|
||||
301
modules/core/types/vec.owa
Normal file
301
modules/core/types/vec.owa
Normal file
|
|
@ -0,0 +1,301 @@
|
|||
(namespace vec
|
||||
(def type :vec)
|
||||
(def is? (guard type))
|
||||
(def new builtins.vec.new)
|
||||
(def __call__ new)
|
||||
|
||||
(def fold builtins.vec.fold)
|
||||
(def from builtins.vec.from)
|
||||
|
||||
;; Empty vector
|
||||
(def empty [])
|
||||
|
||||
;; Guard to check if a value is a empty vector
|
||||
(fn empty? [<Vec>v]
|
||||
(eq? v empty))
|
||||
|
||||
;; Get the count of items in a vector
|
||||
(fn len [<Vec>v]
|
||||
(fold (lambda [acc _] (+ acc 1)) 0 v))
|
||||
|
||||
;; Append an item to the end of a vector
|
||||
(fn conj [<Vec>v item]
|
||||
(apply new v [item]))
|
||||
|
||||
;; Check if a vector contains an item
|
||||
(fn has [<Vec>v item]
|
||||
(fold
|
||||
(lambda [acc elem _]
|
||||
(bool.or acc (eq? elem item)))
|
||||
false
|
||||
v))
|
||||
|
||||
;; Get an item from a vector by index
|
||||
(fn get [<Vec>v idx]
|
||||
(fold
|
||||
(lambda [result elem index]
|
||||
(if (eq? index idx)
|
||||
elem
|
||||
result))
|
||||
null
|
||||
v))
|
||||
|
||||
;; Update an item in a vector
|
||||
;; If the index is out of bounds, the original vector is returned
|
||||
(fn assoc [<Vec>v <Int>index item]
|
||||
(fold
|
||||
(lambda [acc elem idx]
|
||||
(if (eq? idx index)
|
||||
(conj acc item)
|
||||
(conj acc elem)))
|
||||
[]
|
||||
v))
|
||||
|
||||
;; Remove an item from a vector by index
|
||||
;; If the index is out of bounds, the original vector is returned
|
||||
(fn remove [<Vec>v <Int>index]
|
||||
(filter
|
||||
(lambda [elem idx]
|
||||
(nq? idx index))
|
||||
v))
|
||||
|
||||
;; Reverse a vector
|
||||
(fn reverse [<Vec>v]
|
||||
(fold
|
||||
(lambda [acc elem _]
|
||||
(apply merge elem acc))
|
||||
[]
|
||||
v))
|
||||
|
||||
;; Flatten a vector of vectors into a single vector
|
||||
(fn flat [<Vec>v]
|
||||
(fold
|
||||
(lambda [acc elem _]
|
||||
(apply conj [acc elem]))
|
||||
[]
|
||||
v))
|
||||
|
||||
;; Get the first item in a vector
|
||||
(fn first [<Vec>v]
|
||||
(get v 0))
|
||||
|
||||
;; Get the last item in a vector
|
||||
(fn last [<Vec>v]
|
||||
(get v (-- (len v))))
|
||||
|
||||
;; Get all items except the first
|
||||
(fn tail [<Vec>v]
|
||||
(filter
|
||||
(lambda [elem idx]
|
||||
(nq? idx 0))
|
||||
v))
|
||||
|
||||
;; Get the first n items from a vector
|
||||
(fn take [<Vec>v <Int>n]
|
||||
(filter
|
||||
(lambda [elem idx]
|
||||
(lt? idx n))
|
||||
v))
|
||||
|
||||
;; Get all items except the first n
|
||||
(fn drop [<Vec>v n]
|
||||
(filter
|
||||
(lambda [elem idx]
|
||||
(gte? idx n))
|
||||
v))
|
||||
|
||||
;; Get all items except the last
|
||||
(fn drop-last [<Vec>v]
|
||||
(filter
|
||||
(lambda [elem idx]
|
||||
(nq? idx (-- (len v))))
|
||||
v))
|
||||
|
||||
(fn enumerate [<Vec>v]
|
||||
(map
|
||||
(lambda [elem idx]
|
||||
(new [idx elem]))
|
||||
v))
|
||||
|
||||
(fn zip [v1 v2]
|
||||
(map
|
||||
(lambda [elem idx]
|
||||
(new elem (get v2 idx)))
|
||||
v1))
|
||||
|
||||
(fn slice [<Vec>v start end]
|
||||
(filter
|
||||
(lambda [elem idx]
|
||||
(bool.and (gte? idx start) (lt? idx end)))
|
||||
v))
|
||||
|
||||
(fn includes? [<Vec>v item]
|
||||
(has v item))
|
||||
|
||||
(fn index-of [<Vec>v item]
|
||||
(fold
|
||||
(lambda [result elem idx]
|
||||
(if (null? result)
|
||||
(if (eq? elem item)
|
||||
idx
|
||||
result)
|
||||
result))
|
||||
null
|
||||
v))
|
||||
|
||||
(fn join-str [sep v]
|
||||
(if (empty? v)
|
||||
""
|
||||
(fold
|
||||
(lambda [acc elem _]
|
||||
(str.new acc sep elem))
|
||||
(first v)
|
||||
(tail v))))
|
||||
|
||||
;; Map a callback to each item in a vector
|
||||
(fn map [callback <Vec>v]
|
||||
(fold
|
||||
(lambda [acc elem index]
|
||||
(apply conj [acc (callback elem index)]))
|
||||
[]
|
||||
v))
|
||||
|
||||
;; Filter a vector by a callback
|
||||
(fn filter [callback <Vec>v]
|
||||
(fold
|
||||
(lambda [acc elem index]
|
||||
(if (callback elem index)
|
||||
(apply conj [acc elem])
|
||||
acc))
|
||||
[]
|
||||
v))
|
||||
|
||||
;; Find the first item that matches the callback
|
||||
(fn find [callback <Vec>v]
|
||||
(fold
|
||||
(lambda [result elem index]
|
||||
(if (null? result)
|
||||
(if (callback elem index)
|
||||
elem
|
||||
result)
|
||||
result))
|
||||
null
|
||||
v))
|
||||
|
||||
;; Check if every item in a vector matches the callback
|
||||
;; TODO: Break at first non-match for better performance
|
||||
(fn every? <Bool>[callback <Vec>v]
|
||||
(fold
|
||||
(lambda [result elem idx]
|
||||
(bool.and result (callback elem idx)))
|
||||
true
|
||||
v))
|
||||
|
||||
;; Check if any item in a vector matches the callback
|
||||
;; TODO: Break at first match for better performance
|
||||
(fn some? <Bool>[callback <Vec>v]
|
||||
(fold
|
||||
(lambda [result elem idx]
|
||||
(bool.or result (callback elem idx)))
|
||||
false
|
||||
v))
|
||||
|
||||
;; Reduce a vector into a single value
|
||||
(fn reduce <Bool>[callback initial <Vec>v]
|
||||
(fold callback initial v))
|
||||
|
||||
;; Count the number of items that match the callback
|
||||
(fn count [callback v]
|
||||
(fold
|
||||
(lambda [count elem idx]
|
||||
(if (callback elem idx)
|
||||
(+ count 1)
|
||||
count))
|
||||
0
|
||||
v))
|
||||
|
||||
;; Merge all vectors into a single vector
|
||||
(fn merge []
|
||||
(fold
|
||||
(lambda [acc elem _]
|
||||
(apply conj [acc elem]))
|
||||
[]
|
||||
%%))
|
||||
|
||||
(fn max-by [comparator v]
|
||||
(fold
|
||||
(lambda [current elem _]
|
||||
(if (null? current)
|
||||
elem
|
||||
(if (eq? (comparator elem current) :greater)
|
||||
elem
|
||||
current)))
|
||||
null
|
||||
v))
|
||||
|
||||
(fn min-by [comparator v]
|
||||
(fold
|
||||
(lambda [current elem _]
|
||||
(if (null? current)
|
||||
elem
|
||||
(if (eq? (comparator elem current) :less)
|
||||
elem
|
||||
current)))
|
||||
null
|
||||
v))
|
||||
|
||||
(fn uniq [<Vec>v]
|
||||
(fold
|
||||
(lambda [result elem _]
|
||||
(if (has result elem)
|
||||
result
|
||||
(conj result elem)))
|
||||
[]
|
||||
v))
|
||||
|
||||
(fn partition [callback v]
|
||||
(fold
|
||||
(lambda [result elem idx]
|
||||
(seq
|
||||
(def group (if (callback elem idx) 0 1))
|
||||
(def current-part (get result group))
|
||||
(assoc result group (conj current-part elem))))
|
||||
[[] []]
|
||||
v))
|
||||
|
||||
(fn group-by [key-fn v]
|
||||
(fold
|
||||
(lambda [result elem idx]
|
||||
(seq
|
||||
(def key (key-fn elem idx))
|
||||
(def group (map.get result key))
|
||||
(def new-group (if (null? group) [] group))
|
||||
(map.put result key (conj new-group elem))))
|
||||
(map.new)
|
||||
v))
|
||||
|
||||
(fn flatten [<Vec>v]
|
||||
(fold
|
||||
(lambda [result elem _]
|
||||
(if (vec.is? elem)
|
||||
(conj result (flatten elem))
|
||||
(conj result elem)))
|
||||
[]
|
||||
v))
|
||||
|
||||
(fn distinct [<Vec>v]
|
||||
(uniq v))
|
||||
|
||||
(fn compact [<Vec>v]
|
||||
(filter
|
||||
(lambda [elem _]
|
||||
(not (null? elem)))
|
||||
v))
|
||||
|
||||
(fn sum [<Vec>v]
|
||||
(fold
|
||||
(lambda [acc elem _]
|
||||
(+ acc elem))
|
||||
0
|
||||
v))
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue