Skip to content

Language

JasonQu edited this page Jul 11, 2023 · 83 revisions

Reader Syntax

Atoms

GLISP has seven types of Atoms: ints, floats, strings, chars, bools, bytes, and symbols. The following are different kinds of literal syntax for these atoms.

3 ; an int
-21 ; a negative int
0x41 ; int in hexadecimal
0o755 ; int in octal
0b1110 ; int in binary
4.1 ; a float
-2.3 ; a negative float
1.3e20 ; a float in scientific notation
#c ; the character 'c'
#\n ; the newline character
#\' ; the single quote character
#\( ; character (
#\) ; character )
#\[ : character [
#\] ; character ]
#\# ; character #
#\~ ; character ~
#\` ; character `
#\{ ; character {
#\} ; character }
#\" ; character "
#\; ; character ;
#\\ ; character \
"asdfsd" ; a string
#`raw string` ; raw string
asdfsd ; a symbol
true ; the "true" boolean
false ; the "false" boolean
0B676c69737020697320636f6f6c ; byte stream start with 0B

Note that semicolons are used for single-line comments. The syntax for symbols is quite flexible. Any non-whitespace character other than ' or # can be used in a symbol.

Lists

Lists are just cons-cell lists like in other LISP dialects and are delimited by parentheses

(a-function arg1 arg2
    (another-function arg1 arg2))

You can also just describe plain pairs (cons-cells in which the tail is not necessarily a list) using the dotted syntax.

(a . b)

Arrays

Arrays correspond to Go slices and are delimited by square braces.

[1 2 3 4]

Hashes

GLISP has mutable hashmaps which use Go maps internally. The literal syntax uses curly braces

{'a 3
 'b 2}

The hash above maps a to 3 and b to 2. Hash keys can only be integers, strings, chars, bools, or symbols.

Quoting

The quote symbol ' indicates that the following expression should be interpreted literally. This is useful for declaring symbols and lists.

'(1 2 3 4)
'a-symbol

Functions & Lambda

An anonymous function can be declared in GLISP like so

(fn [a b] (+ a b))

There is a shorter form for the fn anonymous function syntax implemented in the glisp reader: #(). This syntax omits the parameter list and names parameters based on their position.

  • % is used for a single parameter

  • %1, %2, %3, etc are used for multiple parameters

  • %N means total argument count

#(any-function %1 %2)
;; Equivalent to: (fn [x] (+ 6 x))
#(+ 6 %)

;; Equivalent to: (fn [x y] (+ x y))
#(+ %1 %2)

#(println %N) ;; print total argument count

A function can be declared with a name using defn.

(defn add3 [a] (+ a 3))

Note that like in Clojure, the argument list is given in an array instead of a list.

Bindings

A binding can be added in the current scope using def. You can also create a new scope and declare bindings in it using let or let*.

(def a 3)

(let [a 3
      b 4]
    (* a b))
; returns 12

(let* [a 2
       b (+ a 1)]
    (+ a b))
; returns 5

The difference between let and let* is that let creates bindings all at once, so you will not be able to access earlier bindings in later bindings. The let* form creates bindings one by one, so each binding can access bindings declared before it.

While def is the workhorse, sometimes set! is needed. set! is more powerful and thus more dangerous; it can modify non-local variables. Like def expression (set! x 10) will update the value of x with 10 if x is already defined in the current scope, and define a new binding if there is no x anywhere on the stack. However, if x is not found in the current scope, we will search up the scope stack for an earlier binding to x. If x is indeed found up the stack, the value of x in that higher scope will be updated to 10. If no binding is found, a local one is created. The non-local update of set! is essential is some cases, but should be used with care.

Calling functions

Functions can be called in the regular way.

(defn add3 [a] (+ a 3))
(add3 2) ; returns 5

They can also be called indirectly using apply.

(apply + [1 2 3]) ; returns 6
(apply + '(1 2 3)) ; same as above

This works exactly the same with anonymous functions

((fn [a b] a) 2 3) ; returns 2
(apply (fn [a b] a) [2 3]) ; same as above

Conditionals

GLISP has only a single conditional statement, cond. The syntax is as follows.

(cond
    first-condition first-expression
    second-condition second-expression
    ...
    default-expression)

The cond statement will check the conditions in order. If the condition is true, it will return the result of the corresponding expression. If not, it will move on the next condition. If none of the conditions are true, it will return the result of the default expression. The default expression is the only required portion of this statement. The way to think of this is that the first condition/expression pair is an if statement, the second is an else if statement, and the default is the else statement.

GLISP also provides the short-circuit boolean operators and and or. The and expression will return the first "falsy" sub-expression or, if all sub-expressions are "truthy", the last sub-expression is returned. The or expression is the opposite, returning the first "truthy" expression or the last expression.

The boolean false, the nil value (empty list) are considered "falsy". All other values are considered "truthy".

Sequencing

The begin statement is used to sequence expressions. It will run all sub-expressions and return the result of the final expression. The top-level, function bodies, and let-statement bodies have implicit begin statements.

Builtin Functions

The following builtin functions are provided by the language runtime.

Boolean operations

  • not

examples

(not true) ; returns false
(not false) ; returns true

Float operations

  • string convert float to string
(string float prec)
(string 14.285714285714286 3) ; returns 14.286

Char operations

  • int convert char to integer
(int #a) ; return 97
  • string convert char to string
(string #a) ; return "a"
  • char convert integer to char
(char 97) ; return #a

Type Introspection

  • zero? (returns true only for 0, 0.0, and null character)
  • nil? (returns true only for ())
  • empty? (returns true only for (), [], {} and string)
  • list? (returns true for list)
  • array? (returns true for array)
  • bool? (returns true for boolean)
  • number? (int, char, or float)
  • int? (returns true for integer)
  • float? (returns true for float)
  • char? (returns true for char)
  • string? (returns true for string)
  • symbol? (returns true for symbol)
  • hash? (returns true for hash)
  • bytes?(returns true for bytes)
  • type (returns symbol,string,array,bool,char,float,function,hash,int,list,bytes)

Symbolic

  • gensym (returns new anonymous symbol)
  • symbol (convert string to symbol)
  • str (convert symbol to string)

Array Functions

The array function can be used to construct an array. It is identical to the square brace literal syntax.

The make-array function creates an array of a given length. By default, the items in the array are intialized to null.

(make-array 3) ; => [() () ()]
(make-array 3 0) ; => [0 0 0]

The aget function indexes into an array.

(aget [0 1 2] 1) ; returns 1

The aset! function modifies the value in the array at the given index

(aset! [0 1 2] 1 3) ; arr should now be [0 3 2]

So yes, arrays are mutable in GLISP.

The exist? function tells whether an element exists

(exist? ["a" "b"] "a") ; returns true

The slice function get a sub range of array

(slice array from to) ; returns elements range [from,to) of array, the argument to can be omited
(slice [1 2 3 4] 1 3)  ; returns [2 3]
(slice [1 2 3 4] 1) ; returns [2 3 4]

List Functions

The list, cons, car, and cdr functions operate the same as in other LISP dialects. Note, however, that car and cdr can also work on arrays.

  • cons make a cons cell
(cons 1 2)  ; returns (1 . 2)
(cons 1 '(2 3))  ; returns '(1 2 3)
  • car and cdr
(car '(1 2 3)) ; returns 1
(cdr '(1 2 3)) ; returns '(2 3)
(cdr '(1 . 2)) ; returns 2
  • concat two list
(concat '(1 2) '(4 5))  ; returns '(1 2 4 5)
  • exist? function tells whether an element exists
(exist? '("a" "b") "a") ; returns true

Hashmap functions

The hget function retrieves a value from the hashmap by key.

(def h {'a 2 'b 3})
(hget h 'a) ; => 2

You can give the hget function a third argument, which is the default value that will be returned if the key is not found. If no default is given and the key is not found, a runtime error will occur.

(hget {'a 3} 'b 0) ; => 0

The hset! function works similar to aset! but using a key instead of an index.

(def h {'a 3})
(hset! h 'a 2) ; h is now {'a 2}

The hdel! function takes a hash and a key and deletes the given key from the hash.

(def h {'a 3 'b 2})
(hdel! h 'a) ; h is now {'b 2}

The exist? function tells whether a key exist in hash

(exist? {"a" "b"} "a") ; returns true

Generic Container Operations

The append function can append an expression to the end of an array or a character onto the end of a list.

(append [0 1] 2) ; => [0 1 2]
(append "ab" #c) ; => "abc"

The concat function can concatenate two arrays, two strings, or two lists

(concat [0 1] [2 3]) ; => [0 1 2 3]
(concat "ab" "cd") ; => "abcd"
(concat '(1 2) '(3 4)) ; => (1 2 3 4)

The len function returns the number of elements in an array or number of characters in a string.

(len "abc") ; returns 3
(len (bytes "abc")) ; returns 3
(len [1 2 3]) ; returns 3
(len {'a 1}) ; returns 1
(len '(1))  ; returns 1

Macros

  • defmac defines a macro. Macros use function syntax, with arguments in [] an array.
  • vargs after & support, for example the range macro is defined as:
(defmac when [predicate & body]
  `(cond ~predicate
      (begin
        ~@body) '()))
  • ` is the syntax-quote shortcut (e.g. backtick).
  • ~ is unquote. Use (quote ~sym) to capture the actual symbol name used in the argument (as above in the range example).
  • ~@ is splicing-unquote.
  • macexpand given an expression, returns the quoted expansion without running it. Useful for debugging macros.

Bytes Functions

  • string convert byte stream to string
(string 0B68656c6c6f) ; returns "hello"
  • bytes convert string to byte stream
(bytes "abc") ; returns 0B616263

String Functions

  • sget get char from string

The sget function is similar to the aget function, except it operates on characters of a string instead of elements of a list.

(sget "abcd" 2) ; returns #c
  • append char to string
(append "ab" #c) ; returns "abc"
  • slice return a sub range of string
(slice "abcd" 1 3) ; returns "bc"
(slice "abcd" 1) ; returns "bcd"
  • sexp-str show s-expr form of anything
(sexp-str 1) ; returns "1"
  • int or float convert string to integer/float
(int "123") ; returns 123
(float "3.14") ; returns 3.14

High Order Functions

  • map apply a function to each element of list/array/hash
;;; add3 is a function (fn [a] (+ 3 a))
(map add3 '(1 2 3)) ; returns '(4 5 6)
(map add3 [1 2 3])   ; returns [4 5 6]
  • flatmap
(flatmap (fn [a] [a (+ a 1)]) [100 200 300]) ; returns [100 101 200 201 300 301]
(flatmap (fn [a] (list a (+ a 1))) '(100 200 300)) ; returns (100 101 200 201 300 301)
  • foldl fold left for list/array/hash
(foldl + 0 [1 2 3 4]) ; returns the sum of [1 2 3 4], which is 10
(foldl * 1 [1 2 3 4]) ; returns the product of [1 2 3 4], which is 24
;; the first argument of foldl function is k-v conscell for hash
(foldl (fn [kv acc] (+ acc (cdr kv))) 0 {'a 1 'b 2}) ; returns 3
  • filter filter a list or array or hash by function
(defn even? [a] (= 0 (mod a 2)))
(filter even? [1 2 3 4]) ; return even numbers
(filter (fn [kv] (even? (cdr kv))) {'a 1 'b 2}) ; returns {'b 2}
  • compose multiple functions

Composes its arguments into a single composite function. All its arguments are assumed to designate functions which take one argument and return one argument.

((compose f g) 42) is equivalent to (f (g 42)). Composition is right-associative.

(map
    (compose
      ;; append char ! to string
      (fn [a] (append a #!))
      ;; convert integer to string
      str
      ;; add 1 to every integer
      (fn [a] (+ a 1))
      )
    [100 200 300 400])
; returns ["101!" "201!" "301!" "401!"]

Testing Functions

  • assert pass when condition is true, otherwise thow exception
(assert (> 2 1)) ;; ok
(assert (> 1 2)) ;; throw exception

assert can accept an additional argument as error message.

(assert (> 1 2) "1>2 would always false")
;; well, dynamic error message is also ok.
(assert (> 1 2) ((fn [a] (sprintf "%v would always false" a)) "1>2"))

Extensions

Core Extension

Arithmetic

  • +
  • -
  • *
  • /
  • mod (modulo)

examples

(+ 1 2 3) ; returns 6
(- 2 1)  ; returns 1
(* 3 4)  ; returns 12
(/ 10 5)  ; return 2
(mod 7 3) ; returns 1

Comparisons

  • <
  • >
  • <=
  • >=
  • =
  • not=, !=

examples

(< 1 2) ; returns true
(> 1 2) ; returns false
(<= 1 2) ; returns true
(>= 1 2) ; returns false
(!= 1 2) ; returns true

Metaprograming

  • alias add alias for a function
(defn user-define-function [arg] (+ arg 1))

(assert (= 2 (user-define-function 1)))
(alias udf user-define-function)
(assert (= 2 (udf 1)))
  • currying transform a normal function to currying function
(currying function arguments_count &optional argument)
(def add2
  ((currying (fn [a b] (+ a b)) 2) 100)
  )
(add2 1) ; returns 101
(add2 3) ; returns 103
  • partial transform a normal function to partial function
(partial function arg1 args2...)
(def double (partial * 2))
(double 1) ; returns 2
(double 2) ; returns 4

(def add3 (partial + 1 1 1))
(add3 1) ; returns 4
(add3 7) ; returns 10
  • override override an exist function

The function override accept two arguments:

  • first is the function symbol would be overrided;
  • second is the an anonymous function, which contains new logic, it's best practise to declare function signature same as old function;

Besides, if you want refer the old function still, you can use the same function name to call the old implement.

;; extend - operand to support array/list
(override - (fn [a b]
   (cond (or (list? a) (array? a)) (list/complement a b) (- a b))))

(- [1 2 3] [2 3]) ; returns [1]
;; override + with log printing
(override + (fn [a b] 
  (printf "before %v+%v=?\n" a b)
  (def x (+ a b))
  (printf "after %v+%v=%v\n" a b x)
  x))
; printing before 1+2=?
; printing after 1+2=3
; at last return 3
  • -> thread first
(-> x & forms)

Threads the expr through the forms. Inserts x as the second item in the first form. If there are more forms, inserts the first form as the second item in second form, etc.

(-> "INIT" (concat "1") (concat "2") (concat "3")) ;; return "INIT123"
  • ->> thread last
(->> x & forms)
(->> ["1 2 3" "4 5 6"]
     (flatmap #(str/split % " "))
     (map int)
     (filter #(not= 2 %))) ;; returns [1 3 4 5 6]

Threads the expr through the forms. Inserts x as the last item in the first form. If there are more forms, inserts the first form as the last item in second form, etc.

  • some->
(some-> expr & forms)

When expr is not nil, threads it into the first form (via ->), and when that result is not nil, through the next etc

  • some->>
(some->> expr & forms)

When expr is not nil, threads it into the first form (via ->>), and when that result is not nil, through the next etc

  • union union set a and b
(union ["a"] ["b" "c"]) ; returns ["a" "b" "c"]
(union '("a") '("b" "c")) ; returns '("a" "b" "c")
  • list/intersect set a and b's intersection
(list/intersect ["a" "b"] ["b" "c"]) ; returns ["b"]
(list/intersect '("a" "b") '("b" "c")) ; returns '("b")
  • uniq filter out repeated elements
(uniq ["a" "a" "b"]) ; returns ["a" "b"]
(uniq '("a" "a" "b")) ; returns '("a" "b")

Printing

  • println like golang's fmt.Println
  • print like golang's fmt.Print
  • printf like golang's fmt.Printf

Stream

  • streamable?
Usage: (streamable? x)

Return true if x implement Iterable interface.

type Iterable interface {
        glisp.Sexp
        Next() (glisp.Sexp, bool)
}

Besides, builtin types string/array/bytes/list/hash are streamable.

  • stream?
Usage: (stream? x)

Return true if x is a stream.

  • stream
Usage: (stream x)

Transform x to a stream. This function can convert builtin types string/array/bytes/list/hash or any Iterable object to a stream.

  • map, flatmap, filter, flatten, foldl

These functions can also work on a stream.

  • take
Usage: (take n stream)

Take first n elements of the stream.

(take f stream)

Take first x elements of the stream until f(elem) return false.

  • drop
Usage: (drop n stream)

Drop first n elements of the stream.

(drop f stream)

Drop first x elements of the stream until f(elem) return false.

  • range
Usage: (range)
(range end)
(range start end)
(range start end step)

Returns a lazy seq of nums from start (inclusive) to end (exclusive), by step, where start defaults to 0, step to 1, and end to infinity. When step is equal to 0, returns an infinite sequence of start. When start is equal to end, returns empty list.

  • realize
Usage: (realize stream)

Return real list of the stream.

  • partition
Usage: (partition n stream)

Partition stream into groups stream, every group size is n.

(partition f stream)

Partition stream into groups stream by function f, exclude separator.

(partition f separator_on_head stream)

Partition stream into groups stream by function f, include separator on head or tail.

  • zip
Usage: (zip stream1 stream2 ...)

Compose multiple stream to one, and every element of new stream is a list composite by stream-x's element.

  • index-of
Usage: (index-of f x)
Find index of x by f, return -1 if not found.
f can be a predicate function or a constant literal,
x can be stream or list or array.
e.g.
(index-of "lisp" ["go" "lisp"]) ; return 1
(index-of #(= % "lisp") ["go" "lisp"]) ; return 1

Math Extension

Bitwise operations

  • sla (shift-left arithmetic)
  • sra (shift-right arithmetic)
  • sll8 (8bit shift-left logical)
  • sll16 (16bit shift-left logical)
  • sll32 (32bit shift-left logical)
  • sll64 (64bit shift-left logical)
  • srl8 (8bit shift-right logical)
  • srl16 (16bit shift-right logical)
  • srl32 (32bit shift-right logical)
  • srl64 (64bit shift-right logical)

examples

(sla 1 3) ;; returns 8
(sra 1 1) ;; returns 0
  • bit-and
  • bit-or
  • bit-xor
  • bit-not (one's complement)

examples

(bit-and 3 2) ; return 2
(bit-or 3 1) ; return 3
(bit-xor 3 1) ; returns 2
(bit-not 2) ; returns -3

Float operations

  • round

convert float to nearest integer

(round 0.5) ; returns 1
(round 1.1) ; returns 1
  • floor and ceil
(floor 1.1) ; return 1
(ceil 1.1) ; return 2

JSON Extension

  • json/stringify transform s-expression to json string
(json/stringify {"a" 1}) ;return {"a":1}
(json/stringify {"a" 1} true)  ;return json string with indent
;return 
;{
;    "a": 1
;}

mapping rules:

S-expr JSON
integer integer
float float
string string
symbol string
() null
array array
bytes base64 encoded string(same as golang's json.Marshal)
list array
hash object
bool bool
char integer value of char
function -
  • json/parse parse string to s-expression

mapping rules:

JSON S-expr
integer integer
float float
string string
null nil
array array
object hash
bool bool
(json/stringify {'a 1 'b 2}) ; returns {"a":1,"b":2}
(json/parse "{\"a\":1,\"b\":2}") ; returns hash {"a" 1 "b" 2}
(json/parse "[1" [])  ; return default value if json string is invalid
  • The json/query function query hash/array by keyword
(def h {"a" {"b" 1}})
(json/query h "a.b") ; return 1

json/query can accept an additional default value.

(json/query {} "a" 1) ; return 1

Full search syntax please referer to qjson

  • The json/set function set value by path, return the modified hash/array
(def h {"a" {"b" 1}})
(json/set h "a.b" 2) ; return {"a" {"b" 2}}
  • The json/del function delete value by path, return the modified hash/array
(def h {"a" {"b" 1}})
(json/del h "a.b") ; return {"a" {}}
  • The json/q is design for interactive json query.

Default, json/q would display short json information:

(json/q js)
;; print short information
{
    "meta": {"view","controller"}  ;; meta is an object and contains two keys "view" and "controller"
    "data": [<len=42>] ;; data is an array which contains 42 elements
}

Add a bool flag to switch to full json information

(json/q js true) ;; display full json with indent
(json/q js false) ;; display full json without indent

Also, you can use query path:

(json/q js "meta.view") ;; display meta.view information
(json/q js "meta.view" true) ;; display full meta.view information with indent

Time Extension

  • time/now return current time
(time/now) ; return current time
  • time/format format time
(time/format (time/now) 'timestamp) ; returns unix timestamp
(time/format (time/now) 'timestamp-ms) ; returns unix timestamp mills
(time/format (time/now) 'timestamp-micro) ; returns unix timestamp micro seconds
(time/format (time/now) 'timestamp-nano) ; returns unix timestamp nano seconds
(time/format (time/now) "2006-01-02 15:04:05") ; returns time string by layout, layout reference https://pkg.go.dev/time#pkg-constants
  • time/parse parse string/timestamp to time
(time/parse 1655967400280) => parse unix timestamp to Time
(time/parse 1655967400280000 'timestamp-ms) => parse unix milli timestamp to Time
(time/parse 1655967400280000 'timestamp-micro) => parse unix micro timestamp to Time
(time/parse 1655967400280000 'timestamp-nano) => parse unix nano timestamp to Time
(time/parse "2015-02-23 23:54:55") => parse time by value, try with layout 2006-01-02 15:04:05 or  2006-01-02T15:04:05Z07:00
(time/parse "2014-Feb-04" "2006-Jan-02") => parse time by value and layout
(time/parse "2014-Feb-04" "2006-Jan-02" "Asia/Shanghai") => parse time by value and layout and location
  • time/add-date add year+month+day to time
(time/add-date (time/now) 1 2 3) ; add 1 year and 2 months and 3 days to current time
  • time/add add year/month/day/hour/minute/secod to time
(time/add (time/now) 1 'year) ; add 1 year to current time
(time/add (time/now) 1 'month); add 1 month to current time
(time/add (time/now) 1 'day)  ; add 1 day to current time
(time/add (time/now) 1 'hour)  ; add 1 hour to current time
(time/add (time/now) 1 'minute)  ; add 1 minute to current time
(time/add (time/now) 1 'second)  ; add 1 second to current time
  • time/sub sub time1 and time2, returns in seconds
(time/sub t1 t2) ; return (t1-t2) in seconds
  • time/year get year number of time
(time/year (time/now)) ; returns current year number
  • time/month get month munber of time
(time/month (time/now)) ; returns current month number
  • time/day get day number of time
(time/day (time/now)) ; returns current day number
  • time/hour get hour number of time
(time/hour (time/now)) ; return current hour number
  • time/minute get minute number of time
(time/minute (time/now)) ; return current minute number
  • time/second get second number of time
(time/second (time/now)) ; return current second number
  • time/weekday get weekday number of time
(time/weekday (time/now)) ; return current weeekday number

Base64 Extension

  • base64/decode convert a base64 string to byte stream (need base64 extension)
(base64/decode "aGVsbG8=") ; returns 0B68656c6c6f
  • base64/encode convert byte stream to base64 encoded string (need base64 extension)
(base64/encode 0B68656c6c6f) ; returns "aGVsbG8="

String Extension

  • str/contains? like golang's strings.Contains
(str/contains? "abc" "b") ; returns true
  • str/count like golang's strings.Count
(str/count "abcc" "c") ; returns 2
  • str/start-with? like golang's strings.HasPrefix
(str/start-with? "abc" "a") ; returns true
  • str/end-with? like golang's strings.HasSuffix
(str/end-with? "abc" "c") ; returns true
  • str/index like golang's strings.Index
(str/index "abc" "b") ; returns 1
  • str/alpha? check if string is all characters
(str/alpha? "abc") ; returns true
(str/alpha? "ab1") ; returns false
  • str/digit? check if string is all digits
(str/digit? "abc") ; return false
(str/digit? "123") ; returns true
  • str/integer? check if string is integer
(str/integer? "123") ;return true
  • str/float? check if string is float
(str/float? "3.14") ;return true
  • str/bool? check if string is boolean
(str/bool? "false") ;return true
  • str/join like golang's strings.Join
(str/join ["a" "b"] "_") ; returns "a_b"
  • str/lower transform all to lowercase
(str/lower "ABC") ; returns "abc"
  • str/replace like golang's strings.ReplaceAll
(str/replace "abc" "b" "B") ; returns "aBc"
  • str/split like golang's strings.Split
(str/split "a_b" "_")  ; returns ["a" "b"]
  • str/title turn first letter to title case
(str/title "abc")  ; returns "Abc"
  • str/title? check if string is title case
(str/title? "abc") ; returns false
(str/title? "Abc") ; returns true
  • str/trim-prefix like golang's strings.TrimPrefix
(str/trim-prefix "_abc" "_") ; returns "abc"
  • str/trim-space like golang's strings.TrimSpace
(str/trim-space " abc ") ; returns "abc"
  • str/trim-suffix like golang's strings.TrimSuffix
(str/trim-suffix "abc_" "_") ; returns "abc"
  • str/upper transform all to uppercase
(str/upper "abc") ; returns "ABC"
  • str/md5 calculate string md5
(str/md5 "abc") ; returns "900150983cd24fb0d6963f7d28e17f72"
  • str/mask mask string
(str/mask "hello" 1 2 "*") ; returns "h**lo"
;; -1 means mask all
(str/mask "hello" 1 -1 "*") ; returns "h****"
  • str/len return string length as utf8 []rune
(str/len "世界") ; return 2, but (len "世界") would return 6

Random Extension

  • rand random integer
(rand) ; return integer in [0,100)
(rand 200) ; return integer in [0,200]
  • randf random float in [0,1)
(randf) ; return float in [0,1)

OS Extension

  • os/read-file read file as bytes

  • os/write-file write string/bytes to file

  • os/file-exist? check whether file exist

  • os/remove-file delete file

(os/write-file "file.txt" "hello") ; create file file.txt and write "hello" into file
(os/read-file "file.txt") ; return "hello" as bytes
(os/file-exist? "file.txt") ; returns true
(os/remove-file "file.txt") ; delete file file.txt
  • os/exec! execute system command
(os/exec! "echo -n hello world") ; return "hello world"
  • os/exec execute system command, return conscell (exit_code . result)
(os/exec "echo hello") ; return (0 . "hello")
(os/exec "cat missing-file") ; return (1 . "cat: missing-file: No such file or directory")

HTTP Extension

  • http/get, http/post, http/put, http/patch, http/delete, http/options, http/head send http request by corresponding method, return bytes.
(http/get "http://example.com") ; return bytes

Send request with payload by option -d, the payload data can be string/bytes/hash/list/array:

(http/post "http://example.com" -d "body-string")

Send request with custom header -H:

(http/post "http://example.com" -d "{\"key\":100}" '-H "content-type:application/json")

Send request with timeout -timeout:

(http/get "http://example.com" -timeout 1) ; send request with timeout 1s
(http/get "http://example.com" -timeout "1m") ; send request with timeout 1m
(http/get "http://example.com" -timeout "1ms") ; send request with timeout 1ms

Return header within response by option -i:

(http/get "http://example.com" -i) ; return headers within response
;; HTTP/1.1 200 OK
;; Content-Type: application/json; charset=utf-8
;; Date: Fri, 19 Aug 2022 12:29:04 GMT
;; Content-Length: 18
;; 
;; {"message":"pong"}

Debug with option -v:

(http/get "http://example.com" -v)

Auto send json request if payload is hash/array/list:

(http/post "http://example.com" '-d {"a" 1 "b" 2}) ; send json request with json {"a":1,"b":2}
(http/post "http://example.com" '-d ["a" "b"]) ; send json request with json ["a","b"]
(http/post "http://example.com" '-d '("a" "b")) ; send json request with json ["a","b"]
  • http/curl

These http/METHOD functions don't return http status code to user, so here's http/curl, which return a cons cell (status_code . response_bytes).

(http/curl "http://example.com") ; return (200 . BODY_BYTES)
(http/curl -X "POST" "http://example.com" -d "payload") ; send a post request
;; get response status code
(car (http/curl "http://example.com")) ; return 200
;; get response body
(cdr (http/curl "http://example.com")) ; return body bytes

The function http/curl share same flags with http/METHOD functions:

(http/curl -H "header1:value1" "http://example.com") ; send request with custom header

REPL

Start repl by cd ./repl/glisp && go run main.go

query documentation

  • doc show function documentation.
(doc map)

Usage: (map f coll)

Returns a sequence consisting of the result of applying f to
the set of first items of each coll, followed by applying f to the
set of second items in each coll, until any one of the colls is
exhausted. coll can be array or list.