mirror of
https://github.com/carp-lang/Carp.git
synced 2024-09-11 13:37:57 +03:00
* feat: add fstr * test: add fstr test * fix: memory error in test * fix: fix backslash parser * feat: add octal escape literals
232 lines
7.7 KiB
Plaintext
232 lines
7.7 KiB
Plaintext
;; Defining the meta data macros early so that they can be used by all the other code.
|
|
|
|
(defmacro and [x y]
|
|
(list 'if x y false))
|
|
|
|
(defmacro or [x y]
|
|
(list 'if x true y))
|
|
|
|
;; Defined early so that `doc` can accept a rest arg
|
|
(defndynamic map-internal [f xs acc]
|
|
(if (= 0 (length xs))
|
|
acc
|
|
(map-internal f (cdr xs) (cons-last (f (car xs)) acc))))
|
|
|
|
(defndynamic list-to-array-internal [xs acc]
|
|
(if (= 0 (length xs))
|
|
acc
|
|
(list-to-array-internal (cdr xs) (append acc (array (car xs))))))
|
|
|
|
(defmodule Dynamic
|
|
(defndynamic /= [a b] (not (= a b)))
|
|
|
|
(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)))))
|
|
(defndynamic cddddr [pair] (cdr (cdr (cdr (cdr pair))))))
|
|
|
|
|
|
(meta-set! doc "doc" "Set documentation for a binding.")
|
|
(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
|
|
())]
|
|
(eval (list 'meta-set! name "doc" (Dynamic.String.concat (list-to-array-internal separated []))))))
|
|
|
|
(doc print-doc "Print the documentation for a binding.")
|
|
(defmacro print-doc [name]
|
|
(eval (list 'macro-log (list 'meta name "doc"))))
|
|
|
|
(doc sig "Annotate a binding with the desired signature.")
|
|
(defmacro sig [name signature]
|
|
(eval (list 'meta-set! name "sig" signature)))
|
|
|
|
(doc print-sig "Print the annotated signature for a binding.")
|
|
(defmacro print-sig [name]
|
|
(eval (list 'macro-log (list 'meta name "sig"))))
|
|
|
|
(doc hide "Mark a binding as hidden, this will make it not print with the 'info' command.")
|
|
(defmacro hidden [name]
|
|
(eval (list 'meta-set! name "hidden" true)))
|
|
|
|
(doc private "Mark a binding as private, this will make it inaccessible from other modules.")
|
|
(defmacro private [name]
|
|
(eval (list 'meta-set! name "private" true)))
|
|
|
|
(doc todo "sets the todo property for a binding.")
|
|
(defmacro todo [name value]
|
|
(eval (list 'meta-set! name "todo" value)))
|
|
|
|
(doc private? "Is this binding private?")
|
|
(defmacro private? [name]
|
|
(eval (list 'not (list 'list? (list 'meta name "private")))))
|
|
|
|
(doc hidden? "Is this binding hidden?")
|
|
(defmacro hidden? [name]
|
|
(eval (list 'not (list 'list? (list 'meta name "hidden")))))
|
|
|
|
(defndynamic annotate-helper [name annotation]
|
|
(list 'cons annotation (list 'meta name "annotations")))
|
|
|
|
(doc annotate "Add an annotation to this binding.")
|
|
(defmacro annotate [name annotation]
|
|
(eval (list 'meta-set! name "annotations" (eval (annotate-helper name annotation)))))
|
|
|
|
(defmodule Dynamic
|
|
|
|
(defndynamic quoted [x]
|
|
(list 'quote x))
|
|
|
|
)
|
|
|
|
(defndynamic cond-internal [xs]
|
|
(if (= (length xs) 0)
|
|
(list)
|
|
(if (= (length xs) 2)
|
|
(macro-error "cond has even number of branches; add an else branch")
|
|
(if (= (length xs) 1)
|
|
(car xs)
|
|
(list
|
|
'if
|
|
(car xs)
|
|
(cadr xs)
|
|
(cond-internal (cddr xs)))))))
|
|
|
|
(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\"))"
|
|
"```")
|
|
(defmacro cond [:rest xs]
|
|
(cond-internal xs))
|
|
|
|
(defmacro refstr [x]
|
|
(list 'ref
|
|
(list 'str x)))
|
|
|
|
(defmacro swap! [x y]
|
|
(list 'let (array 'tmp y) (list 'do (list 'set! y x) (list 'set! x 'tmp))))
|
|
|
|
(defmacro update! [x f]
|
|
(list 'set! x (list f x)))
|
|
|
|
(defndynamic use-all-fn [names]
|
|
(if (= (length names) 0)
|
|
(macro-error "Trying to call use-all without arguments")
|
|
(do
|
|
(eval (list 'use (car names)))
|
|
(if (= (length names) 1)
|
|
()
|
|
(use-all-fn (cdr names))))))
|
|
|
|
(defmacro use-all [:rest names]
|
|
(use-all-fn names))
|
|
|
|
(defmacro load-and-use [name]
|
|
(do
|
|
(eval (list 'load (str name ".carp")))
|
|
(eval (list 'use name))))
|
|
|
|
(defmacro comment [:rest forms]
|
|
())
|
|
|
|
(defndynamic build-vararg [func forms]
|
|
(if (= (length forms) 0)
|
|
(macro-error "vararg macro needs at least one argument")
|
|
(if (= (length forms) 1)
|
|
(car forms)
|
|
(list func (car forms) (build-vararg func (cdr forms))))))
|
|
|
|
(defmacro and* [:rest forms]
|
|
(build-vararg 'and forms))
|
|
|
|
(defmacro or* [:rest forms]
|
|
(build-vararg 'or forms))
|
|
|
|
(defmacro ignore [form]
|
|
(list 'let (array '_ form) (list)))
|
|
|
|
(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.")
|
|
(defndynamic const-assert [expr msg]
|
|
(if expr () (macro-error msg)))
|
|
|
|
(doc defdynamic-once "Creates a dynamic variable and sets its value if it's not already defined.")
|
|
(defmacro defdynamic-once [var expr]
|
|
(eval
|
|
(list 'if (list 'defined? var)
|
|
()
|
|
(list 'defdynamic var expr))))
|
|
|
|
(doc inline-c "Inlines some custom C code.")
|
|
(defmacro inline-c [name defcode :rest declcode]
|
|
(eval (list 'deftemplate name (list) defcode (if (empty? declcode) "" (car declcode)))))
|
|
|
|
(deftemplate bottom (Fn [] a) "$a $NAME()" "$DECL { abort(); }")
|
|
|
|
(doc unreachable
|
|
"Asserts that a block of code will never be reached. If it is"
|
|
"the program will be aborted with an error message.")
|
|
(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)))
|
|
(list 'System.abort)
|
|
(list 'bottom)))
|
|
|
|
(defmacro save-docs [:rest modules]
|
|
;; A trick to be able to send unquoted symbols to 'save-docs'
|
|
(eval (list 'save-docs-internal (list 'quote modules))))
|
|
|
|
(defndynamic implement-declaration [mod interface]
|
|
(list 'implements interface (Symbol.prefix mod interface)))
|
|
|
|
(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)))
|