2018-03-26 17:51:43 +03:00
|
|
|
;; Defining the meta data macros early so that they can be used by all the other code.
|
Make `doc` take a rest parameter of strings
Carp preserves tabulation and other whitespace in strings, as it should.
This sometimes results in awkward code indentation when it comes to long
doc strings that exceed 80 characters. Often, one has to continue the
string on a newline, but needs to avoid adding tabs to prevent Carp from
rendering them in the output.
This change alters the behavior of doc to take a series of strings as a
rest parameter instead, allowing for neater organization in the source,
for example, after this change the following long doc string for
compose:
~~~
"Returns the composition of two functions `f` and `g` for functions of any
arity; concretely, returns a function accepting the correct number of
arguments for `g`, applies `g` to those arguments, then applies `f` to the
result.
If you only need to compose functions that take a single argument (unary arity)
see `comp`. Comp also generates the form that corresponds to the composition,
compose contrarily evaluates 'eagerly' and returns a computed symbol.
For exmaple:
```
;; a silly composition
((compose empty take) 3 [1 2 3 4 5])
;; => []
(String.join (collect-into ((compose reverse map) Symbol.str '(p r a c)) array))
;; => 'carp'
;; comp for comparison
((comp (curry + 1) (curry + 2)) 4)
;; => (+ 1 (+ 2 4))
```"
~~~
becomes:
~~~
"Returns the composition of two functions `f` and `g` for functions of any"
"arity; concretely, returns a function accepting the correct number of"
"arguments for `g`, applies `g` to those arguments, then applies `f` to the"
"result."
""
"If you only need to compose functions that take a single argument (unary arity)"
"see `comp`. Comp also generates the form that corresponds to the composition,"
"compose contrarily evaluates 'eagerly' and returns a computed symbol."
"```"
";; a silly composition"
"((compose empty take) 3 [1 2 3 4 5])"
";; => []"
""
"(String.join (collect-into ((compose reverse map) Symbol.str '(p r a c)) array))"
";; => 'carp'"
""
";; comp for comparison"
"((comp (curry + 1) (curry + 2)) 4)"
";; => (+ 1 (+ 2 4))"
"```")
~~~
And the output remains the same; this just enables better alignment in
the source file.
The strings passed to doc are newline separated by default, but one can
circumvent this behavior by passing a bool along with the string as
follows:
~~~
(doc foo
("My amazing doc " false)
"continues on one line."
""
"And then another.")
~~~
The above doc string will result in the following output:
~~~
My amazing doc continues on one line.
And then another.
~~~
Of course, the original behavior of doc also remains valid, so if one
prefers to use the old indentation-mixed single string format, one still
can!
This change also reformats the doc strings in macro to utilize the new
rest parameter and make the source a bit neater.
2020-10-01 18:41:05 +03:00
|
|
|
;; Defined early so that `doc` can accept a rest arg
|
2021-07-01 10:42:37 +03:00
|
|
|
(meta-set! map-internal "hidden" true)
|
Make `doc` take a rest parameter of strings
Carp preserves tabulation and other whitespace in strings, as it should.
This sometimes results in awkward code indentation when it comes to long
doc strings that exceed 80 characters. Often, one has to continue the
string on a newline, but needs to avoid adding tabs to prevent Carp from
rendering them in the output.
This change alters the behavior of doc to take a series of strings as a
rest parameter instead, allowing for neater organization in the source,
for example, after this change the following long doc string for
compose:
~~~
"Returns the composition of two functions `f` and `g` for functions of any
arity; concretely, returns a function accepting the correct number of
arguments for `g`, applies `g` to those arguments, then applies `f` to the
result.
If you only need to compose functions that take a single argument (unary arity)
see `comp`. Comp also generates the form that corresponds to the composition,
compose contrarily evaluates 'eagerly' and returns a computed symbol.
For exmaple:
```
;; a silly composition
((compose empty take) 3 [1 2 3 4 5])
;; => []
(String.join (collect-into ((compose reverse map) Symbol.str '(p r a c)) array))
;; => 'carp'
;; comp for comparison
((comp (curry + 1) (curry + 2)) 4)
;; => (+ 1 (+ 2 4))
```"
~~~
becomes:
~~~
"Returns the composition of two functions `f` and `g` for functions of any"
"arity; concretely, returns a function accepting the correct number of"
"arguments for `g`, applies `g` to those arguments, then applies `f` to the"
"result."
""
"If you only need to compose functions that take a single argument (unary arity)"
"see `comp`. Comp also generates the form that corresponds to the composition,"
"compose contrarily evaluates 'eagerly' and returns a computed symbol."
"```"
";; a silly composition"
"((compose empty take) 3 [1 2 3 4 5])"
";; => []"
""
"(String.join (collect-into ((compose reverse map) Symbol.str '(p r a c)) array))"
";; => 'carp'"
""
";; comp for comparison"
"((comp (curry + 1) (curry + 2)) 4)"
";; => (+ 1 (+ 2 4))"
"```")
~~~
And the output remains the same; this just enables better alignment in
the source file.
The strings passed to doc are newline separated by default, but one can
circumvent this behavior by passing a bool along with the string as
follows:
~~~
(doc foo
("My amazing doc " false)
"continues on one line."
""
"And then another.")
~~~
The above doc string will result in the following output:
~~~
My amazing doc continues on one line.
And then another.
~~~
Of course, the original behavior of doc also remains valid, so if one
prefers to use the old indentation-mixed single string format, one still
can!
This change also reformats the doc strings in macro to utilize the new
rest parameter and make the source a bit neater.
2020-10-01 18:41:05 +03:00
|
|
|
(defndynamic map-internal [f xs acc]
|
|
|
|
(if (= 0 (length xs))
|
|
|
|
acc
|
|
|
|
(map-internal f (cdr xs) (cons-last (f (car xs)) acc))))
|
|
|
|
|
2021-07-01 10:42:37 +03:00
|
|
|
(meta-set! list-to-array-internal "hidden" true)
|
Make `doc` take a rest parameter of strings
Carp preserves tabulation and other whitespace in strings, as it should.
This sometimes results in awkward code indentation when it comes to long
doc strings that exceed 80 characters. Often, one has to continue the
string on a newline, but needs to avoid adding tabs to prevent Carp from
rendering them in the output.
This change alters the behavior of doc to take a series of strings as a
rest parameter instead, allowing for neater organization in the source,
for example, after this change the following long doc string for
compose:
~~~
"Returns the composition of two functions `f` and `g` for functions of any
arity; concretely, returns a function accepting the correct number of
arguments for `g`, applies `g` to those arguments, then applies `f` to the
result.
If you only need to compose functions that take a single argument (unary arity)
see `comp`. Comp also generates the form that corresponds to the composition,
compose contrarily evaluates 'eagerly' and returns a computed symbol.
For exmaple:
```
;; a silly composition
((compose empty take) 3 [1 2 3 4 5])
;; => []
(String.join (collect-into ((compose reverse map) Symbol.str '(p r a c)) array))
;; => 'carp'
;; comp for comparison
((comp (curry + 1) (curry + 2)) 4)
;; => (+ 1 (+ 2 4))
```"
~~~
becomes:
~~~
"Returns the composition of two functions `f` and `g` for functions of any"
"arity; concretely, returns a function accepting the correct number of"
"arguments for `g`, applies `g` to those arguments, then applies `f` to the"
"result."
""
"If you only need to compose functions that take a single argument (unary arity)"
"see `comp`. Comp also generates the form that corresponds to the composition,"
"compose contrarily evaluates 'eagerly' and returns a computed symbol."
"```"
";; a silly composition"
"((compose empty take) 3 [1 2 3 4 5])"
";; => []"
""
"(String.join (collect-into ((compose reverse map) Symbol.str '(p r a c)) array))"
";; => 'carp'"
""
";; comp for comparison"
"((comp (curry + 1) (curry + 2)) 4)"
";; => (+ 1 (+ 2 4))"
"```")
~~~
And the output remains the same; this just enables better alignment in
the source file.
The strings passed to doc are newline separated by default, but one can
circumvent this behavior by passing a bool along with the string as
follows:
~~~
(doc foo
("My amazing doc " false)
"continues on one line."
""
"And then another.")
~~~
The above doc string will result in the following output:
~~~
My amazing doc continues on one line.
And then another.
~~~
Of course, the original behavior of doc also remains valid, so if one
prefers to use the old indentation-mixed single string format, one still
can!
This change also reformats the doc strings in macro to utilize the new
rest parameter and make the source a bit neater.
2020-10-01 18:41:05 +03:00
|
|
|
(defndynamic list-to-array-internal [xs acc]
|
|
|
|
(if (= 0 (length xs))
|
|
|
|
acc
|
|
|
|
(list-to-array-internal (cdr xs) (append acc (array (car xs))))))
|
|
|
|
|
2020-11-28 14:53:18 +03:00
|
|
|
(defmodule Dynamic
|
2021-03-03 10:57:36 +03:00
|
|
|
(defndynamic quoted [x]
|
|
|
|
(list 'quote x))
|
|
|
|
|
2021-01-26 08:18:16 +03:00
|
|
|
(defndynamic /= [a b] (not (= a b)))
|
|
|
|
|
2020-11-28 14:53:18 +03:00
|
|
|
(defndynamic caar [pair] (car (car pair)))
|
|
|
|
(defndynamic cadr [pair] (car (cdr pair)))
|
|
|
|
(defndynamic cdar [pair] (cdr (car pair)))
|
|
|
|
(defndynamic cddr [pair] (cdr (cdr pair)))
|
|
|
|
(defndynamic caaar [pair] (car (car (car pair))))
|
|
|
|
(defndynamic caadr [pair] (car (car (cdr pair))))
|
|
|
|
(defndynamic cadar [pair] (car (cdr (car pair))))
|
|
|
|
(defndynamic cdaar [pair] (cdr (car (car pair))))
|
|
|
|
(defndynamic caddr [pair] (car (cdr (cdr pair))))
|
|
|
|
(defndynamic cdadr [pair] (cdr (car (cdr pair))))
|
|
|
|
(defndynamic cddar [pair] (cdr (cdr (car pair))))
|
|
|
|
(defndynamic cdddr [pair] (cdr (cdr (cdr pair))))
|
|
|
|
(defndynamic caaaar [pair] (car (car (car (car pair)))))
|
|
|
|
(defndynamic caaadr [pair] (car (car (car (cdr pair)))))
|
|
|
|
(defndynamic caadar [pair] (car (car (cdr (car pair)))))
|
|
|
|
(defndynamic caaddr [pair] (car (car (cdr (cdr pair)))))
|
|
|
|
(defndynamic cadaar [pair] (car (cdr (car (car pair)))))
|
|
|
|
(defndynamic cadadr [pair] (car (cdr (car (cdr pair)))))
|
|
|
|
(defndynamic caddar [pair] (car (cdr (cdr (car pair)))))
|
|
|
|
(defndynamic cadddr [pair] (car (cdr (cdr (cdr pair)))))
|
|
|
|
(defndynamic cdaaar [pair] (cdr (car (car (car pair)))))
|
|
|
|
(defndynamic cdaadr [pair] (cdr (car (car (cdr pair)))))
|
|
|
|
(defndynamic cdadar [pair] (cdr (car (cdr (car pair)))))
|
|
|
|
(defndynamic cdaddr [pair] (cdr (car (cdr (cdr pair)))))
|
|
|
|
(defndynamic cddaar [pair] (cdr (cdr (car (car pair)))))
|
|
|
|
(defndynamic cddadr [pair] (cdr (cdr (car (cdr pair)))))
|
|
|
|
(defndynamic cdddar [pair] (cdr (cdr (cdr (car pair)))))
|
2021-01-26 15:22:26 +03:00
|
|
|
(defndynamic cddddr [pair] (cdr (cdr (cdr (cdr pair)))))
|
|
|
|
|
|
|
|
(defmodule List
|
2021-02-11 11:12:58 +03:00
|
|
|
; this should be defined using cond, but is defined before cond
|
2021-01-26 15:22:26 +03:00
|
|
|
(defndynamic in? [elem l]
|
2021-02-11 11:12:58 +03:00
|
|
|
(if (empty? l)
|
|
|
|
false
|
|
|
|
(if (= elem (car l))
|
|
|
|
true
|
|
|
|
(List.in? elem (cdr l))))))
|
2021-01-26 15:22:26 +03:00
|
|
|
|
|
|
|
(defndynamic string? [s]
|
|
|
|
(= (dynamic-type s) 'string))
|
|
|
|
|
|
|
|
(defndynamic symbol? [s]
|
|
|
|
(= (dynamic-type s) 'symbol))
|
|
|
|
|
|
|
|
(defndynamic list? [s]
|
|
|
|
(= (dynamic-type s) 'list))
|
|
|
|
|
|
|
|
(defndynamic array? [s]
|
|
|
|
(= (dynamic-type s) 'array))
|
|
|
|
|
|
|
|
(defndynamic number? [s]
|
2021-03-03 10:57:36 +03:00
|
|
|
(List.in? (dynamic-type s) '(int long double float byte))))
|
2021-01-26 08:18:16 +03:00
|
|
|
|
2018-03-26 17:51:43 +03:00
|
|
|
(meta-set! doc "doc" "Set documentation for a binding.")
|
Make `doc` take a rest parameter of strings
Carp preserves tabulation and other whitespace in strings, as it should.
This sometimes results in awkward code indentation when it comes to long
doc strings that exceed 80 characters. Often, one has to continue the
string on a newline, but needs to avoid adding tabs to prevent Carp from
rendering them in the output.
This change alters the behavior of doc to take a series of strings as a
rest parameter instead, allowing for neater organization in the source,
for example, after this change the following long doc string for
compose:
~~~
"Returns the composition of two functions `f` and `g` for functions of any
arity; concretely, returns a function accepting the correct number of
arguments for `g`, applies `g` to those arguments, then applies `f` to the
result.
If you only need to compose functions that take a single argument (unary arity)
see `comp`. Comp also generates the form that corresponds to the composition,
compose contrarily evaluates 'eagerly' and returns a computed symbol.
For exmaple:
```
;; a silly composition
((compose empty take) 3 [1 2 3 4 5])
;; => []
(String.join (collect-into ((compose reverse map) Symbol.str '(p r a c)) array))
;; => 'carp'
;; comp for comparison
((comp (curry + 1) (curry + 2)) 4)
;; => (+ 1 (+ 2 4))
```"
~~~
becomes:
~~~
"Returns the composition of two functions `f` and `g` for functions of any"
"arity; concretely, returns a function accepting the correct number of"
"arguments for `g`, applies `g` to those arguments, then applies `f` to the"
"result."
""
"If you only need to compose functions that take a single argument (unary arity)"
"see `comp`. Comp also generates the form that corresponds to the composition,"
"compose contrarily evaluates 'eagerly' and returns a computed symbol."
"```"
";; a silly composition"
"((compose empty take) 3 [1 2 3 4 5])"
";; => []"
""
"(String.join (collect-into ((compose reverse map) Symbol.str '(p r a c)) array))"
";; => 'carp'"
""
";; comp for comparison"
"((comp (curry + 1) (curry + 2)) 4)"
";; => (+ 1 (+ 2 4))"
"```")
~~~
And the output remains the same; this just enables better alignment in
the source file.
The strings passed to doc are newline separated by default, but one can
circumvent this behavior by passing a bool along with the string as
follows:
~~~
(doc foo
("My amazing doc " false)
"continues on one line."
""
"And then another.")
~~~
The above doc string will result in the following output:
~~~
My amazing doc continues on one line.
And then another.
~~~
Of course, the original behavior of doc also remains valid, so if one
prefers to use the old indentation-mixed single string format, one still
can!
This change also reformats the doc strings in macro to utilize the new
rest parameter and make the source a bit neater.
2020-10-01 18:41:05 +03:00
|
|
|
(defmacro doc [name :rest strings]
|
|
|
|
(let [newline "
|
|
|
|
" ;; Looks a bit odd but the newline literal is important here! (str \newline) currently results in unwanted escapes
|
|
|
|
separated (map-internal (fn [x] (if (list? x)
|
|
|
|
(if (cadr x)
|
|
|
|
(Dynamic.String.concat [(car x) newline])
|
|
|
|
(car x))
|
|
|
|
(Dynamic.String.concat [x newline])))
|
|
|
|
strings
|
|
|
|
())]
|
2021-07-01 10:42:37 +03:00
|
|
|
(eval (list 'meta-set! name "doc" (Dynamic.String.concat (list-to-array-internal separated []))))))
|
2018-03-26 17:51:43 +03:00
|
|
|
|
|
|
|
(doc print-doc "Print the documentation for a binding.")
|
|
|
|
(defmacro print-doc [name]
|
2020-04-17 13:29:21 +03:00
|
|
|
(eval (list 'macro-log (list 'meta name "doc"))))
|
2018-03-26 17:51:43 +03:00
|
|
|
|
|
|
|
(doc sig "Annotate a binding with the desired signature.")
|
|
|
|
(defmacro sig [name signature]
|
2020-04-17 13:29:21 +03:00
|
|
|
(eval (list 'meta-set! name "sig" signature)))
|
2018-03-26 17:51:43 +03:00
|
|
|
|
|
|
|
(doc print-sig "Print the annotated signature for a binding.")
|
|
|
|
(defmacro print-sig [name]
|
2020-04-17 13:29:21 +03:00
|
|
|
(eval (list 'macro-log (list 'meta name "sig"))))
|
2018-03-26 17:51:43 +03:00
|
|
|
|
2021-03-03 10:57:36 +03:00
|
|
|
(doc hidden "Mark a binding as hidden, this will make it not print with the 'info' command.")
|
2018-03-27 15:21:12 +03:00
|
|
|
(defmacro hidden [name]
|
2020-04-17 13:29:21 +03:00
|
|
|
(eval (list 'meta-set! name "hidden" true)))
|
2018-03-26 17:51:43 +03:00
|
|
|
|
|
|
|
(doc private "Mark a binding as private, this will make it inaccessible from other modules.")
|
2018-03-27 15:14:30 +03:00
|
|
|
(defmacro private [name]
|
2020-04-17 13:29:21 +03:00
|
|
|
(eval (list 'meta-set! name "private" true)))
|
2018-03-26 17:51:43 +03:00
|
|
|
|
2021-06-20 22:44:04 +03:00
|
|
|
(hidden and-)
|
|
|
|
(defndynamic and- [xs]
|
|
|
|
; (defndynamic and- [xs] ; shorter but currently not entirely stable
|
|
|
|
; (if (= 0 (length xs))
|
|
|
|
; true
|
|
|
|
; (list 'if (car xs) (and- (cdr xs)) false) ))
|
|
|
|
(if (= 0 (length xs))
|
|
|
|
true
|
|
|
|
(if (= 1 (length xs))
|
|
|
|
(car xs)
|
|
|
|
(list 'if (car xs) (and- (cdr xs)) false) )))
|
2021-07-01 10:42:37 +03:00
|
|
|
(doc and "evaluates the forms `xs` one at a time, from left to right. If a form
|
|
|
|
evaluates to `false`, `and` returns that value and doesn't evaluate any of the
|
|
|
|
other expressions, otherwise it returns the value of the last form in `xs`.
|
|
|
|
`(and)` returns `true`.")
|
2021-06-28 20:56:59 +03:00
|
|
|
(defmacro and [:rest xs]
|
2021-06-20 22:44:04 +03:00
|
|
|
(and- xs))
|
|
|
|
|
|
|
|
(hidden or-)
|
|
|
|
(defndynamic or- [xs]
|
|
|
|
; (if (= 0 (length xs)) ; shorter but currently not entirely stable
|
|
|
|
; false
|
|
|
|
; (list 'if (car xs) true (or- (cdr xs))) ))
|
|
|
|
(if (= 0 (length xs))
|
|
|
|
false
|
|
|
|
(if (= 1 (length xs))
|
|
|
|
(car xs)
|
|
|
|
(list 'if (car xs) true (or- (cdr xs))) )))
|
2021-07-01 10:42:37 +03:00
|
|
|
(doc or "evaluates the forms `xs` one at a time, from left to right. If a form
|
|
|
|
evaluates to `true`, `or` returns that value and doesn't evaluate any of the
|
|
|
|
other expressions, otherwise it returns the value of the last form in `xs`.
|
|
|
|
`(or)` returns `false`.")
|
2021-06-28 20:56:59 +03:00
|
|
|
(defmacro or [:rest xs]
|
2021-06-20 22:44:04 +03:00
|
|
|
(or- xs))
|
|
|
|
|
|
|
|
|
2019-06-22 21:18:32 +03:00
|
|
|
(doc todo "sets the todo property for a binding.")
|
|
|
|
(defmacro todo [name value]
|
2020-04-17 13:29:21 +03:00
|
|
|
(eval (list 'meta-set! name "todo" value)))
|
2019-06-22 21:18:32 +03:00
|
|
|
|
2018-03-27 15:08:49 +03:00
|
|
|
(doc private? "Is this binding private?")
|
|
|
|
(defmacro private? [name]
|
2020-05-20 11:04:05 +03:00
|
|
|
(eval (list 'not (list 'list? (list 'meta name "private")))))
|
2018-03-27 15:08:49 +03:00
|
|
|
|
|
|
|
(doc hidden? "Is this binding hidden?")
|
|
|
|
(defmacro hidden? [name]
|
2020-05-20 11:04:05 +03:00
|
|
|
(eval (list 'not (list 'list? (list 'meta name "hidden")))))
|
2018-03-26 17:51:43 +03:00
|
|
|
|
2021-07-01 10:42:37 +03:00
|
|
|
(hidden annotate-helper)
|
2019-06-04 12:30:22 +03:00
|
|
|
(defndynamic annotate-helper [name annotation]
|
2020-05-20 11:04:05 +03:00
|
|
|
(list 'cons annotation (list 'meta name "annotations")))
|
2019-06-04 12:30:22 +03:00
|
|
|
|
|
|
|
(doc annotate "Add an annotation to this binding.")
|
|
|
|
(defmacro annotate [name annotation]
|
2020-05-20 11:04:05 +03:00
|
|
|
(eval (list 'meta-set! name "annotations" (eval (annotate-helper name annotation)))))
|
2018-03-26 17:51:43 +03:00
|
|
|
|
2021-01-26 15:22:50 +03:00
|
|
|
(doc deprecated "Declares that a binding is deprecated, using an optional explanation.")
|
|
|
|
(defmacro deprecated [name :rest explanation]
|
|
|
|
(let [v (if (= (length explanation) 0) true (car explanation))]
|
|
|
|
(eval (list 'meta-set! name "deprecated" v))))
|
|
|
|
|
2021-03-03 10:57:36 +03:00
|
|
|
(doc defn- "Declares a function while marking it as private and hidden.")
|
|
|
|
(defmacro defn- [name args form]
|
|
|
|
(do
|
|
|
|
(eval (list 'private name))
|
|
|
|
(eval (list 'hidden name))
|
|
|
|
(list 'defn name args form)))
|
|
|
|
|
|
|
|
(doc def- "Declares a variable while marking it as private and hidden.")
|
|
|
|
(defmacro def- [name value]
|
|
|
|
(do
|
|
|
|
(eval (list 'private name))
|
|
|
|
(eval (list 'hidden name))
|
|
|
|
(list 'def name value)))
|
2018-01-02 20:13:52 +03:00
|
|
|
|
2021-07-01 10:42:37 +03:00
|
|
|
(hidden cond-internal)
|
2019-03-13 20:49:48 +03:00
|
|
|
(defndynamic cond-internal [xs]
|
2018-05-20 10:57:51 +03:00
|
|
|
(if (= (length xs) 0)
|
2017-06-26 12:15:03 +03:00
|
|
|
(list)
|
2018-05-20 10:57:51 +03:00
|
|
|
(if (= (length xs) 2)
|
2017-12-15 19:43:06 +03:00
|
|
|
(macro-error "cond has even number of branches; add an else branch")
|
2018-05-20 10:57:51 +03:00
|
|
|
(if (= (length xs) 1)
|
2017-06-26 12:15:03 +03:00
|
|
|
(car xs)
|
|
|
|
(list
|
2017-10-17 10:02:12 +03:00
|
|
|
'if
|
2017-06-26 12:15:03 +03:00
|
|
|
(car xs)
|
2018-01-02 20:13:52 +03:00
|
|
|
(cadr xs)
|
|
|
|
(cond-internal (cddr xs)))))))
|
2017-06-26 12:15:03 +03:00
|
|
|
|
Make `doc` take a rest parameter of strings
Carp preserves tabulation and other whitespace in strings, as it should.
This sometimes results in awkward code indentation when it comes to long
doc strings that exceed 80 characters. Often, one has to continue the
string on a newline, but needs to avoid adding tabs to prevent Carp from
rendering them in the output.
This change alters the behavior of doc to take a series of strings as a
rest parameter instead, allowing for neater organization in the source,
for example, after this change the following long doc string for
compose:
~~~
"Returns the composition of two functions `f` and `g` for functions of any
arity; concretely, returns a function accepting the correct number of
arguments for `g`, applies `g` to those arguments, then applies `f` to the
result.
If you only need to compose functions that take a single argument (unary arity)
see `comp`. Comp also generates the form that corresponds to the composition,
compose contrarily evaluates 'eagerly' and returns a computed symbol.
For exmaple:
```
;; a silly composition
((compose empty take) 3 [1 2 3 4 5])
;; => []
(String.join (collect-into ((compose reverse map) Symbol.str '(p r a c)) array))
;; => 'carp'
;; comp for comparison
((comp (curry + 1) (curry + 2)) 4)
;; => (+ 1 (+ 2 4))
```"
~~~
becomes:
~~~
"Returns the composition of two functions `f` and `g` for functions of any"
"arity; concretely, returns a function accepting the correct number of"
"arguments for `g`, applies `g` to those arguments, then applies `f` to the"
"result."
""
"If you only need to compose functions that take a single argument (unary arity)"
"see `comp`. Comp also generates the form that corresponds to the composition,"
"compose contrarily evaluates 'eagerly' and returns a computed symbol."
"```"
";; a silly composition"
"((compose empty take) 3 [1 2 3 4 5])"
";; => []"
""
"(String.join (collect-into ((compose reverse map) Symbol.str '(p r a c)) array))"
";; => 'carp'"
""
";; comp for comparison"
"((comp (curry + 1) (curry + 2)) 4)"
";; => (+ 1 (+ 2 4))"
"```")
~~~
And the output remains the same; this just enables better alignment in
the source file.
The strings passed to doc are newline separated by default, but one can
circumvent this behavior by passing a bool along with the string as
follows:
~~~
(doc foo
("My amazing doc " false)
"continues on one line."
""
"And then another.")
~~~
The above doc string will result in the following output:
~~~
My amazing doc continues on one line.
And then another.
~~~
Of course, the original behavior of doc also remains valid, so if one
prefers to use the old indentation-mixed single string format, one still
can!
This change also reformats the doc strings in macro to utilize the new
rest parameter and make the source a bit neater.
2020-10-01 18:41:05 +03:00
|
|
|
(doc cond
|
|
|
|
"Executes a block of code if a specified condition is true. Multiple"
|
|
|
|
"such blocks can be chained."
|
|
|
|
""
|
|
|
|
"```"
|
|
|
|
"(cond"
|
|
|
|
" (< 10 1) (println \"Condition 1 is true\")"
|
|
|
|
" (> 10 1) (println \"Condition 2 is true\")"
|
|
|
|
" (println \"Else branch\"))"
|
|
|
|
"```")
|
2017-06-26 12:15:03 +03:00
|
|
|
(defmacro cond [:rest xs]
|
|
|
|
(cond-internal xs))
|
|
|
|
|
2021-07-01 10:42:37 +03:00
|
|
|
(doc refstr "stringifies `x` and takes the reference of that string.")
|
2017-06-29 18:05:34 +03:00
|
|
|
(defmacro refstr [x]
|
2017-10-17 10:02:12 +03:00
|
|
|
(list 'ref
|
|
|
|
(list 'str x)))
|
2017-10-13 14:48:40 +03:00
|
|
|
|
2021-07-01 10:42:37 +03:00
|
|
|
(doc swap! "swaps its arguments `x` and `y` in place.
|
|
|
|
|
|
|
|
*Note*: Unhygienic!")
|
2017-11-29 17:28:21 +03:00
|
|
|
(defmacro swap! [x y]
|
2018-02-02 09:19:10 +03:00
|
|
|
(list 'let (array 'tmp y) (list 'do (list 'set! y x) (list 'set! x 'tmp))))
|
2017-11-30 15:43:58 +03:00
|
|
|
|
2021-07-01 10:42:37 +03:00
|
|
|
(doc update! "updates `x` in place using the function `f`.")
|
2018-01-02 20:13:52 +03:00
|
|
|
(defmacro update! [x f]
|
2018-02-02 09:19:10 +03:00
|
|
|
(list 'set! x (list f x)))
|
2018-01-02 20:13:52 +03:00
|
|
|
|
2021-07-01 10:42:37 +03:00
|
|
|
(hidden use-all-fn)
|
2019-03-13 20:49:48 +03:00
|
|
|
(defndynamic use-all-fn [names]
|
2018-05-20 10:57:51 +03:00
|
|
|
(if (= (length names) 0)
|
2017-12-12 17:08:33 +03:00
|
|
|
(macro-error "Trying to call use-all without arguments")
|
2020-04-10 18:31:51 +03:00
|
|
|
(do
|
|
|
|
(eval (list 'use (car names)))
|
|
|
|
(if (= (length names) 1)
|
|
|
|
()
|
|
|
|
(use-all-fn (cdr names))))))
|
2017-12-12 17:08:33 +03:00
|
|
|
|
2021-07-01 10:42:37 +03:00
|
|
|
(doc use-all "is a variadic version of `use`.")
|
2017-12-12 17:08:33 +03:00
|
|
|
(defmacro use-all [:rest names]
|
2020-04-10 18:31:51 +03:00
|
|
|
(use-all-fn names))
|
2017-12-12 19:39:15 +03:00
|
|
|
|
2021-07-01 10:42:37 +03:00
|
|
|
(doc load-and-use "loads a file and uses the module with in it. Assumes that
|
|
|
|
the filename and module name are the same.")
|
2018-03-24 12:28:19 +03:00
|
|
|
(defmacro load-and-use [name]
|
2020-04-10 18:31:51 +03:00
|
|
|
(do
|
|
|
|
(eval (list 'load (str name ".carp")))
|
|
|
|
(eval (list 'use name))))
|
2018-03-24 12:28:19 +03:00
|
|
|
|
2021-07-01 10:42:37 +03:00
|
|
|
(doc comment "ignores `forms`.")
|
2017-12-14 18:28:06 +03:00
|
|
|
(defmacro comment [:rest forms]
|
|
|
|
())
|
|
|
|
|
2021-07-01 10:42:37 +03:00
|
|
|
(hidden build-vararg)
|
2019-03-13 20:49:48 +03:00
|
|
|
(defndynamic build-vararg [func forms]
|
2018-05-20 10:57:51 +03:00
|
|
|
(if (= (length forms) 0)
|
2017-12-29 13:49:51 +03:00
|
|
|
(macro-error "vararg macro needs at least one argument")
|
2018-05-20 10:57:51 +03:00
|
|
|
(if (= (length forms) 1)
|
2017-12-29 13:49:51 +03:00
|
|
|
(car forms)
|
2018-06-15 13:07:32 +03:00
|
|
|
(list func (car forms) (build-vararg func (cdr forms))))))
|
2017-12-29 13:49:51 +03:00
|
|
|
|
2021-07-01 10:42:37 +03:00
|
|
|
(doc ignore "ignores the return value of the expression `form`.")
|
2018-01-25 19:26:20 +03:00
|
|
|
(defmacro ignore [form]
|
2018-02-01 20:01:45 +03:00
|
|
|
(list 'let (array '_ form) (list)))
|
2018-03-12 18:30:36 +03:00
|
|
|
|
Make `doc` take a rest parameter of strings
Carp preserves tabulation and other whitespace in strings, as it should.
This sometimes results in awkward code indentation when it comes to long
doc strings that exceed 80 characters. Often, one has to continue the
string on a newline, but needs to avoid adding tabs to prevent Carp from
rendering them in the output.
This change alters the behavior of doc to take a series of strings as a
rest parameter instead, allowing for neater organization in the source,
for example, after this change the following long doc string for
compose:
~~~
"Returns the composition of two functions `f` and `g` for functions of any
arity; concretely, returns a function accepting the correct number of
arguments for `g`, applies `g` to those arguments, then applies `f` to the
result.
If you only need to compose functions that take a single argument (unary arity)
see `comp`. Comp also generates the form that corresponds to the composition,
compose contrarily evaluates 'eagerly' and returns a computed symbol.
For exmaple:
```
;; a silly composition
((compose empty take) 3 [1 2 3 4 5])
;; => []
(String.join (collect-into ((compose reverse map) Symbol.str '(p r a c)) array))
;; => 'carp'
;; comp for comparison
((comp (curry + 1) (curry + 2)) 4)
;; => (+ 1 (+ 2 4))
```"
~~~
becomes:
~~~
"Returns the composition of two functions `f` and `g` for functions of any"
"arity; concretely, returns a function accepting the correct number of"
"arguments for `g`, applies `g` to those arguments, then applies `f` to the"
"result."
""
"If you only need to compose functions that take a single argument (unary arity)"
"see `comp`. Comp also generates the form that corresponds to the composition,"
"compose contrarily evaluates 'eagerly' and returns a computed symbol."
"```"
";; a silly composition"
"((compose empty take) 3 [1 2 3 4 5])"
";; => []"
""
"(String.join (collect-into ((compose reverse map) Symbol.str '(p r a c)) array))"
";; => 'carp'"
""
";; comp for comparison"
"((comp (curry + 1) (curry + 2)) 4)"
";; => (+ 1 (+ 2 4))"
"```")
~~~
And the output remains the same; this just enables better alignment in
the source file.
The strings passed to doc are newline separated by default, but one can
circumvent this behavior by passing a bool along with the string as
follows:
~~~
(doc foo
("My amazing doc " false)
"continues on one line."
""
"And then another.")
~~~
The above doc string will result in the following output:
~~~
My amazing doc continues on one line.
And then another.
~~~
Of course, the original behavior of doc also remains valid, so if one
prefers to use the old indentation-mixed single string format, one still
can!
This change also reformats the doc strings in macro to utilize the new
rest parameter and make the source a bit neater.
2020-10-01 18:41:05 +03:00
|
|
|
(doc const-assert
|
|
|
|
"Asserts that the expression `expr` is true at compile time."
|
|
|
|
"Otherwise it will fail with the message `msg`."
|
|
|
|
""
|
|
|
|
"The expression must be evaluable at compile time.")
|
2019-05-22 21:01:03 +03:00
|
|
|
(defndynamic const-assert [expr msg]
|
|
|
|
(if expr () (macro-error msg)))
|
2019-09-09 10:59:22 +03:00
|
|
|
|
Make `doc` take a rest parameter of strings
Carp preserves tabulation and other whitespace in strings, as it should.
This sometimes results in awkward code indentation when it comes to long
doc strings that exceed 80 characters. Often, one has to continue the
string on a newline, but needs to avoid adding tabs to prevent Carp from
rendering them in the output.
This change alters the behavior of doc to take a series of strings as a
rest parameter instead, allowing for neater organization in the source,
for example, after this change the following long doc string for
compose:
~~~
"Returns the composition of two functions `f` and `g` for functions of any
arity; concretely, returns a function accepting the correct number of
arguments for `g`, applies `g` to those arguments, then applies `f` to the
result.
If you only need to compose functions that take a single argument (unary arity)
see `comp`. Comp also generates the form that corresponds to the composition,
compose contrarily evaluates 'eagerly' and returns a computed symbol.
For exmaple:
```
;; a silly composition
((compose empty take) 3 [1 2 3 4 5])
;; => []
(String.join (collect-into ((compose reverse map) Symbol.str '(p r a c)) array))
;; => 'carp'
;; comp for comparison
((comp (curry + 1) (curry + 2)) 4)
;; => (+ 1 (+ 2 4))
```"
~~~
becomes:
~~~
"Returns the composition of two functions `f` and `g` for functions of any"
"arity; concretely, returns a function accepting the correct number of"
"arguments for `g`, applies `g` to those arguments, then applies `f` to the"
"result."
""
"If you only need to compose functions that take a single argument (unary arity)"
"see `comp`. Comp also generates the form that corresponds to the composition,"
"compose contrarily evaluates 'eagerly' and returns a computed symbol."
"```"
";; a silly composition"
"((compose empty take) 3 [1 2 3 4 5])"
";; => []"
""
"(String.join (collect-into ((compose reverse map) Symbol.str '(p r a c)) array))"
";; => 'carp'"
""
";; comp for comparison"
"((comp (curry + 1) (curry + 2)) 4)"
";; => (+ 1 (+ 2 4))"
"```")
~~~
And the output remains the same; this just enables better alignment in
the source file.
The strings passed to doc are newline separated by default, but one can
circumvent this behavior by passing a bool along with the string as
follows:
~~~
(doc foo
("My amazing doc " false)
"continues on one line."
""
"And then another.")
~~~
The above doc string will result in the following output:
~~~
My amazing doc continues on one line.
And then another.
~~~
Of course, the original behavior of doc also remains valid, so if one
prefers to use the old indentation-mixed single string format, one still
can!
This change also reformats the doc strings in macro to utilize the new
rest parameter and make the source a bit neater.
2020-10-01 18:41:05 +03:00
|
|
|
(doc defdynamic-once "Creates a dynamic variable and sets its value if it's not already defined.")
|
2019-12-18 14:10:47 +03:00
|
|
|
(defmacro defdynamic-once [var expr]
|
2021-01-11 15:21:29 +03:00
|
|
|
(eval
|
|
|
|
(list 'if (list 'defined? var)
|
|
|
|
()
|
|
|
|
(list 'defdynamic var expr))))
|
2019-11-29 17:25:27 +03:00
|
|
|
|
Make `doc` take a rest parameter of strings
Carp preserves tabulation and other whitespace in strings, as it should.
This sometimes results in awkward code indentation when it comes to long
doc strings that exceed 80 characters. Often, one has to continue the
string on a newline, but needs to avoid adding tabs to prevent Carp from
rendering them in the output.
This change alters the behavior of doc to take a series of strings as a
rest parameter instead, allowing for neater organization in the source,
for example, after this change the following long doc string for
compose:
~~~
"Returns the composition of two functions `f` and `g` for functions of any
arity; concretely, returns a function accepting the correct number of
arguments for `g`, applies `g` to those arguments, then applies `f` to the
result.
If you only need to compose functions that take a single argument (unary arity)
see `comp`. Comp also generates the form that corresponds to the composition,
compose contrarily evaluates 'eagerly' and returns a computed symbol.
For exmaple:
```
;; a silly composition
((compose empty take) 3 [1 2 3 4 5])
;; => []
(String.join (collect-into ((compose reverse map) Symbol.str '(p r a c)) array))
;; => 'carp'
;; comp for comparison
((comp (curry + 1) (curry + 2)) 4)
;; => (+ 1 (+ 2 4))
```"
~~~
becomes:
~~~
"Returns the composition of two functions `f` and `g` for functions of any"
"arity; concretely, returns a function accepting the correct number of"
"arguments for `g`, applies `g` to those arguments, then applies `f` to the"
"result."
""
"If you only need to compose functions that take a single argument (unary arity)"
"see `comp`. Comp also generates the form that corresponds to the composition,"
"compose contrarily evaluates 'eagerly' and returns a computed symbol."
"```"
";; a silly composition"
"((compose empty take) 3 [1 2 3 4 5])"
";; => []"
""
"(String.join (collect-into ((compose reverse map) Symbol.str '(p r a c)) array))"
";; => 'carp'"
""
";; comp for comparison"
"((comp (curry + 1) (curry + 2)) 4)"
";; => (+ 1 (+ 2 4))"
"```")
~~~
And the output remains the same; this just enables better alignment in
the source file.
The strings passed to doc are newline separated by default, but one can
circumvent this behavior by passing a bool along with the string as
follows:
~~~
(doc foo
("My amazing doc " false)
"continues on one line."
""
"And then another.")
~~~
The above doc string will result in the following output:
~~~
My amazing doc continues on one line.
And then another.
~~~
Of course, the original behavior of doc also remains valid, so if one
prefers to use the old indentation-mixed single string format, one still
can!
This change also reformats the doc strings in macro to utilize the new
rest parameter and make the source a bit neater.
2020-10-01 18:41:05 +03:00
|
|
|
(doc inline-c "Inlines some custom C code.")
|
2020-10-26 21:20:01 +03:00
|
|
|
(defmacro inline-c [name defcode :rest declcode]
|
|
|
|
(eval (list 'deftemplate name (list) defcode (if (empty? declcode) "" (car declcode)))))
|
2020-05-12 21:24:40 +03:00
|
|
|
|
2021-07-01 10:42:37 +03:00
|
|
|
(doc bottom "aborts the program if reached.")
|
2020-06-26 19:57:06 +03:00
|
|
|
(deftemplate bottom (Fn [] a) "$a $NAME()" "$DECL { abort(); }")
|
|
|
|
|
Make `doc` take a rest parameter of strings
Carp preserves tabulation and other whitespace in strings, as it should.
This sometimes results in awkward code indentation when it comes to long
doc strings that exceed 80 characters. Often, one has to continue the
string on a newline, but needs to avoid adding tabs to prevent Carp from
rendering them in the output.
This change alters the behavior of doc to take a series of strings as a
rest parameter instead, allowing for neater organization in the source,
for example, after this change the following long doc string for
compose:
~~~
"Returns the composition of two functions `f` and `g` for functions of any
arity; concretely, returns a function accepting the correct number of
arguments for `g`, applies `g` to those arguments, then applies `f` to the
result.
If you only need to compose functions that take a single argument (unary arity)
see `comp`. Comp also generates the form that corresponds to the composition,
compose contrarily evaluates 'eagerly' and returns a computed symbol.
For exmaple:
```
;; a silly composition
((compose empty take) 3 [1 2 3 4 5])
;; => []
(String.join (collect-into ((compose reverse map) Symbol.str '(p r a c)) array))
;; => 'carp'
;; comp for comparison
((comp (curry + 1) (curry + 2)) 4)
;; => (+ 1 (+ 2 4))
```"
~~~
becomes:
~~~
"Returns the composition of two functions `f` and `g` for functions of any"
"arity; concretely, returns a function accepting the correct number of"
"arguments for `g`, applies `g` to those arguments, then applies `f` to the"
"result."
""
"If you only need to compose functions that take a single argument (unary arity)"
"see `comp`. Comp also generates the form that corresponds to the composition,"
"compose contrarily evaluates 'eagerly' and returns a computed symbol."
"```"
";; a silly composition"
"((compose empty take) 3 [1 2 3 4 5])"
";; => []"
""
"(String.join (collect-into ((compose reverse map) Symbol.str '(p r a c)) array))"
";; => 'carp'"
""
";; comp for comparison"
"((comp (curry + 1) (curry + 2)) 4)"
";; => (+ 1 (+ 2 4))"
"```")
~~~
And the output remains the same; this just enables better alignment in
the source file.
The strings passed to doc are newline separated by default, but one can
circumvent this behavior by passing a bool along with the string as
follows:
~~~
(doc foo
("My amazing doc " false)
"continues on one line."
""
"And then another.")
~~~
The above doc string will result in the following output:
~~~
My amazing doc continues on one line.
And then another.
~~~
Of course, the original behavior of doc also remains valid, so if one
prefers to use the old indentation-mixed single string format, one still
can!
This change also reformats the doc strings in macro to utilize the new
rest parameter and make the source a bit neater.
2020-10-01 18:41:05 +03:00
|
|
|
(doc unreachable
|
|
|
|
"Asserts that a block of code will never be reached. If it is"
|
|
|
|
"the program will be aborted with an error message.")
|
2020-06-23 13:19:14 +03:00
|
|
|
(defmacro unreachable [msg]
|
|
|
|
(list 'do
|
|
|
|
(list 'IO.println
|
|
|
|
(list 'ref
|
|
|
|
(list 'fmt "%s:%d:%d: %s"
|
|
|
|
(eval (list 'file msg))
|
|
|
|
(eval (list 'line msg))
|
|
|
|
(eval (list 'column msg))
|
|
|
|
msg)))
|
2020-06-23 13:26:53 +03:00
|
|
|
(list 'System.abort)
|
2020-06-26 19:57:06 +03:00
|
|
|
(list 'bottom)))
|
2020-08-25 12:58:20 +03:00
|
|
|
|
2021-07-01 10:42:37 +03:00
|
|
|
(hidden implement-declaration)
|
2020-11-28 14:53:18 +03:00
|
|
|
(defndynamic implement-declaration [mod interface]
|
|
|
|
(list 'implements interface (Symbol.prefix mod interface)))
|
2020-05-12 21:24:40 +03:00
|
|
|
|
2020-11-28 14:53:18 +03:00
|
|
|
(doc implements-all
|
|
|
|
"Declares functions in mod with names matching `interfaces` as implementations"
|
|
|
|
"of those interfaces.")
|
|
|
|
(defmacro implements-all [mod :rest interfaces]
|
|
|
|
(cons 'do (map (curry implement-declaration mod) interfaces)))
|
feat: add macros for emitting C compiler directives (#1182)
* feat: Add support for emitting literal C
This commit adds a new Obj type, C, as well as a command for emitting C
literals (which are represented by this object).
This is necessary for circumstances in which Carp's handling of
templates and emission orders prevents interop with C. For example, the
c11 macro static_assert must only take a string literal in its second
position. However, Carp's memory management will typically assign a
string literal (in Carp) to an anonymous variable, which makes them
impossible to use with static_assert. The new emit-c command will
support this use case:
```
(static-assert 0 (Unsafe.emit-c "\"message!\""))
```
The literal string "message!" will be emitted in the compiler's C output
in the position corresponding to the macro call.
We also add a special type for c literals, CTy, to prevent conflating
them with Strings. This helps maintainers define clear boundaries and
express what interop code requires the use of literal C.
Likewise, we need to emit `c_code` to represent this type in C. This
wouldn't be necessary except that Carp sometimes auto-generates
functions that refer to Carp types in their C equivalents, so we need
this for completeness. It is typed as the void pointer.
N.B. That the command is not yet exposed in Carp in this commit.
Thanks to @TimDeve for recommending the name emit-c!
* feat: Add preproc command and add emit-c to Unsafe module
This commit adds the preproc command, which enables users to emit
arbitrary C in the compilers emitted C output.
The C emitted by calls to preproc will be appended to the output after
include directives but prior to any other emissions. One can use it to
call preprocessor directives in C, define helper functions etc.
preproc takes a C type value as an argument and must be used in
conjunction with emit-c. Both functions are added to the Unsafe module
to signal their dangerousness.
One can use `register` in combination with preproc to define code
entirely in Carp and obviate the need of additional header files. For
example:
```
(Unsafe.preproc (Unsafe.emit-c "#define FOO 0"))
(Unsafe.preproc (Unsafe.emit-c "void foo() { printf(\"%d\\n\", 1); }"))
(register FOO Int)
(register foo (Fn [] ()))
(defn main []
(do (foo)
(IO.println &(fmt "%d" FOO))))
```
The prior example emits C that defines a FOO macro and foo function,
which are both referenced in the main function emitted by Carps normal
processing. Here's what the output looks like:
```
// .. several other includes emitted by the compiler...
void foo() { printf("%d\n", 1); }
//Types:
// Depth 3
typedef struct {
union {
struct {
Long member0;
} Just;
// Nothing
char __dummy;
} u;
char _tag;
} Maybe__Long;
```
The C passed to preproc calls is emitted prior to Carps other emissions,
ensuring the user has access to these definitions before any Carp code
is called.
* docs: Add documentation on emit-c and preproc
* feat: add macros for emitting C compiler directives
This suite of macros uses the `Unsafe.emit-c` and `Unsafe.preproc`
functions to provide macros for emitting common C compiler directives,
such as #ifdef, #define, #pragma and others.
2021-03-09 12:43:44 +03:00
|
|
|
|
|
|
|
(defmodule Unsafe
|
|
|
|
(defmodule C
|
|
|
|
(defndynamic emit-c-line [append-strings args]
|
|
|
|
(let [strs (map (fn [x] (String.concat [x " "])) (map str args))
|
|
|
|
arr (collect-into strs array)
|
|
|
|
code (String.concat (append append-strings arr))]
|
|
|
|
(list 'Unsafe.preproc (list 'Unsafe.emit-c code))))
|
|
|
|
|
|
|
|
(doc pragma
|
|
|
|
"Emits a #pragma compiler directive in Carp's c output.")
|
|
|
|
(defmacro pragma [:rest args]
|
|
|
|
(eval (Unsafe.C.emit-c-line ["#pragma "] args)))
|
|
|
|
|
|
|
|
(doc define
|
|
|
|
"Emits a #define compiler directive in Carp's c output.")
|
|
|
|
(defmacro define [name value]
|
|
|
|
(Unsafe.C.emit-c-line ["#define "] [name value]))
|
|
|
|
|
|
|
|
(doc undef
|
|
|
|
"Emits a #undef compiler directive in Carp's c output.")
|
|
|
|
(defmacro undef [name]
|
|
|
|
(Unsafe.C.emit-c-line ["#undef "] [name]))
|
|
|
|
|
|
|
|
(defndynamic if- [if-pre name then else]
|
|
|
|
(do (eval (Unsafe.C.emit-c-line [if-pre] [name]))
|
|
|
|
(eval (Unsafe.C.emit-c-line [" "] [then]))
|
|
|
|
(if (not (empty? else))
|
|
|
|
(do (eval (Unsafe.C.emit-c-line ["#else"] []))
|
|
|
|
(eval (Unsafe.C.emit-c-line [" "] else)))
|
|
|
|
())
|
|
|
|
(eval (Unsafe.C.emit-c-line ["#endif"] []))))
|
|
|
|
|
|
|
|
(doc ifpre
|
|
|
|
"Emits a #if compiler directive in Carp's c output.")
|
|
|
|
(defmacro ifpre [name then :rest else]
|
|
|
|
(Unsafe.C.if- "#if " name then else))
|
|
|
|
|
|
|
|
(doc ifdef
|
|
|
|
"Emits a #ifdef compiler directive in Carp's c output.")
|
|
|
|
(defmacro ifdef [name then :rest else]
|
|
|
|
(Unsafe.C.if- "#ifdef " name then else))
|
|
|
|
|
|
|
|
(doc ifndef
|
|
|
|
"Emits a #ifndef compiler directive in Carp's c output.")
|
|
|
|
(defmacro ifndef [name then :rest else]
|
|
|
|
(Unsafe.C.if- "#ifndef " name then else))
|
|
|
|
|
|
|
|
(doc warning
|
|
|
|
"Emits a #warning compiler directive in Carp's c output.")
|
|
|
|
(defmacro warning [message]
|
|
|
|
(eval (Unsafe.C.emit-c-line ["#warning "] [message])))
|
|
|
|
|
|
|
|
(doc error
|
|
|
|
"Emits a #error compiler directive in Carp's c output.")
|
|
|
|
(defmacro error [message]
|
|
|
|
(eval (Unsafe.C.emit-c-line ["#error "] [message])))
|
2021-05-03 16:14:26 +03:00
|
|
|
|
|
|
|
(hidden asmify)
|
|
|
|
(defndynamic asmify [instruction]
|
|
|
|
(if (string? instruction)
|
|
|
|
(String.concat ["\"" instruction "\" "])
|
|
|
|
(str instruction)))
|
|
|
|
|
|
|
|
(doc asm
|
|
|
|
"Allows to define a named ASM construct. It allows both simple and "
|
|
|
|
"extended ASM."
|
|
|
|
""
|
|
|
|
"Example:"
|
|
|
|
"```"
|
|
|
|
"; exits with eit code 5, uses macOS syscalls"
|
|
|
|
"(Unsafe.C.asm exit5 \"mov $0x2000001, %rax\\n\" \"mov $5, %rdi\\n\" \"syscall\")"
|
|
|
|
""
|
|
|
|
"; writes from a variable called src into a variable dst and then adds 1 to dst"
|
|
|
|
"(Unsafe.C.asm addr \"mov %1, %0\\n\" \"add $1, %0\\n\" : \"=r\" (dst) : \"r\" (src))"
|
|
|
|
"```")
|
|
|
|
(defmacro asm [name :rest instructions]
|
|
|
|
(do
|
|
|
|
(eval (list 'Unsafe.C.define (String.concat [(str name) "()"])
|
|
|
|
(String.concat [
|
|
|
|
"__asm__("
|
|
|
|
(String.concat (collect-into (Dynamic.map Unsafe.C.asmify instructions) array))
|
|
|
|
");"])))
|
|
|
|
(eval (list 'register name '(Fn [] ())))))
|
feat: add macros for emitting C compiler directives (#1182)
* feat: Add support for emitting literal C
This commit adds a new Obj type, C, as well as a command for emitting C
literals (which are represented by this object).
This is necessary for circumstances in which Carp's handling of
templates and emission orders prevents interop with C. For example, the
c11 macro static_assert must only take a string literal in its second
position. However, Carp's memory management will typically assign a
string literal (in Carp) to an anonymous variable, which makes them
impossible to use with static_assert. The new emit-c command will
support this use case:
```
(static-assert 0 (Unsafe.emit-c "\"message!\""))
```
The literal string "message!" will be emitted in the compiler's C output
in the position corresponding to the macro call.
We also add a special type for c literals, CTy, to prevent conflating
them with Strings. This helps maintainers define clear boundaries and
express what interop code requires the use of literal C.
Likewise, we need to emit `c_code` to represent this type in C. This
wouldn't be necessary except that Carp sometimes auto-generates
functions that refer to Carp types in their C equivalents, so we need
this for completeness. It is typed as the void pointer.
N.B. That the command is not yet exposed in Carp in this commit.
Thanks to @TimDeve for recommending the name emit-c!
* feat: Add preproc command and add emit-c to Unsafe module
This commit adds the preproc command, which enables users to emit
arbitrary C in the compilers emitted C output.
The C emitted by calls to preproc will be appended to the output after
include directives but prior to any other emissions. One can use it to
call preprocessor directives in C, define helper functions etc.
preproc takes a C type value as an argument and must be used in
conjunction with emit-c. Both functions are added to the Unsafe module
to signal their dangerousness.
One can use `register` in combination with preproc to define code
entirely in Carp and obviate the need of additional header files. For
example:
```
(Unsafe.preproc (Unsafe.emit-c "#define FOO 0"))
(Unsafe.preproc (Unsafe.emit-c "void foo() { printf(\"%d\\n\", 1); }"))
(register FOO Int)
(register foo (Fn [] ()))
(defn main []
(do (foo)
(IO.println &(fmt "%d" FOO))))
```
The prior example emits C that defines a FOO macro and foo function,
which are both referenced in the main function emitted by Carps normal
processing. Here's what the output looks like:
```
// .. several other includes emitted by the compiler...
void foo() { printf("%d\n", 1); }
//Types:
// Depth 3
typedef struct {
union {
struct {
Long member0;
} Just;
// Nothing
char __dummy;
} u;
char _tag;
} Maybe__Long;
```
The C passed to preproc calls is emitted prior to Carps other emissions,
ensuring the user has access to these definitions before any Carp code
is called.
* docs: Add documentation on emit-c and preproc
* feat: add macros for emitting C compiler directives
This suite of macros uses the `Unsafe.emit-c` and `Unsafe.preproc`
functions to provide macros for emitting common C compiler directives,
such as #ifdef, #define, #pragma and others.
2021-03-09 12:43:44 +03:00
|
|
|
)
|
|
|
|
)
|