refactor: use quasiquoting in STDLIB and go through array in quasiquote (#1135)

This commit is contained in:
Veit Heller 2021-01-21 06:20:03 +01:00 committed by GitHub
parent 2584518d1c
commit bdaf96550f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 116 additions and 144 deletions

View File

@ -9,20 +9,14 @@
(cadddr (cdr settings))
(if (< step (- step step)) '> '<))
]
(list
'let (array variable from)
(list
'while (list comp variable to)
(list
'do
(if (= (length body) 0)
()
(if (list? body)
(car body)
body))
(list
'set! variable
(list '+ variable step))))))))
`(let [%variable %from]
(while (%comp %variable %to)
(do
%(cond
(= (length body) 0) ()
(list? body) (car body)
body)
(set! %variable (+ %variable %step))))))))
(defmodule Array
@ -423,18 +417,18 @@ It will create a copy. If you want to avoid that, consider using [`endo-filter`]
darr)))
(defmacro doall [f xs]
(list 'for ['i 0 (list 'Array.length (list 'ref xs))]
(list f (list 'Array.unsafe-nth (list 'ref xs) 'i))))
`(for [i 0 (Array.length &%xs)]
(%f (Array.unsafe-nth &%xs i))))
(defndynamic foreach-internal [var xs expr]
(let [xsym (gensym-with 'xs)
len (gensym-with 'len)
i (gensym-with 'i)]
(list 'let [xsym xs
len (list 'Array.length xsym)]
(list 'for [i 0 len]
(list 'let [var (list 'Array.unsafe-nth xsym i)]
expr)))))
`(let [%xsym %xs
%len (Array.length %xsym)]
(for [%i 0 %len]
(let [%var (Array.unsafe-nth %xsym %i)]
%expr)))))
(defmacro foreach [binding expr]
(if (array? binding)

View File

@ -109,16 +109,16 @@ If your functions takes a large amount of time, experimenting with this might ma
(defmacro benchn [n form]
(list 'let ['before (Bench.get-time-elapsed)
'times []]
(list 'do
(list 'for ['i 0 n]
(list 'let ['before-once (Bench.get-time-elapsed)]
(list 'do
form
(list 'set! &times (Array.push-back (Array.copy &times) (Double.- (Bench.get-time-elapsed) before-once))))))
(list 'let ['total (Double.- (Bench.get-time-elapsed) before)
'per (list 'Double./ 'total (list 'Double.from-int n))]
`(let [before (Bench.get-time-elapsed)
times []]
(do
(for [i 0 %n]
(let [before-once (Bench.get-time-elapsed)]
(do
%form
(set! &times (Array.push-back (Array.copy &times) (Double.- (Bench.get-time-elapsed) before-once))))))
(let [total (Double.- (Bench.get-time-elapsed) before)
per (Double./ total (Double.from-int %n))]
(do
(Bench.print "Total time elapsed: " total)
(Bench.print "Time elapsed per run (average): " per)

View File

@ -51,7 +51,6 @@
(load-once "IO.carp")
(load-once "Pattern.carp")
(load-once "Debug.carp")
(load-once "Format.carp")
(load-once "Random.carp")
(load-once "Map.carp")
(load-once "Heap.carp")

View File

@ -19,37 +19,35 @@ immediately, raising a `SIGABRT` if it fails.")
(doc memory-logged "logs all calls to memory allocation within the form. Requires the flag `--log-memory` to be passed during compilation.")
(defmacro memory-logged [form]
(list 'do
'(Debug.log-memory-balance! true)
form
'(Debug.log-memory-balance! false)))
`(do
(Debug.log-memory-balance! true)
%form
(Debug.log-memory-balance! false)))
(doc assert-balanced "raises an error if the memory balance (number of `alloc`s - number of `free`s) isn't `0`. Requires the flag `--log-memory` to be passed durng compilation.")
(defmacro assert-balanced [form]
(list 'let '[balance (Debug.memory-balance)]
(list 'do
(list 'let []
form)
'(if (= balance (Debug.memory-balance))
()
(do (IO.println &(fmt "Invalid memory balance: %d" (Debug.memory-balance)))
(System.exit 1)))
())))
`(let [balance (Debug.memory-balance)]
(do
(let [] %form)
(unless (= balance (Debug.memory-balance))
(do
(IO.println &(fmt "Invalid memory balance: %d" (Debug.memory-balance)))
(System.exit 1))))))
(doc trace "prints the value of an expression to `stdout`, then returns its value.")
(defmacro trace [x]
(let [sym (gensym)]
(list 'let-do [sym x]
`(let-do [%sym %x]
; we use eval here to ensure we resolve the symbol before putting it
; into file, line, and column
(list 'IO.println
(list 'ref
(list 'fmt "%s:%d:%d: %s"
(eval (list 'file x))
(eval (list 'line x))
(eval (list 'column x))
(list 'ref (list 'str sym)))))
sym)
(IO.println
(ref
(fmt "%s:%d:%d: %s"
%(eval `(file %x))
%(eval `(line %x))
%(eval `(column %x))
&(str %sym))))
%sym)
)
)
@ -60,8 +58,7 @@ immediately, raising a `SIGABRT` if it fails.")
;; Crash the program with an error message unless the expression evaluates to 'true'.
(defmacro assert [expr]
(list 'if (list '= true expr)
()
(list 'do
(list 'println* (list 'fmt "Assertion '%s' failed at line %d, column %d in file %s" (str expr) (line) (column) (file)))
'(System.abort))))
`(unless (= true %expr)
(do
(println* (fmt "Assertion '%s' failed at line %d, column %d in file %s" %(str expr) %(line) %(column) %(file)))
(System.abort))))

View File

@ -12,10 +12,10 @@
(if (= len 1)
(macro-error "error in format string: expected expression after last %")
(if (= \% (String.char-at s (inc idx))) ; this is an escaped %
(list 'ref
(list 'String.append
"%"
(fmt-internal (String.slice s (+ idx 2) len) args)))
`(ref
(String.append
"%"
%(fmt-internal (String.slice s (+ idx 2) len) args)))
(if (= 0 (length args)) ; we need to insert something, but have nothing
(macro-error
(str "error in format string: not enough arguments to format string (missing argument for '%"
@ -30,13 +30,13 @@
(str "error in format string: too many arguments to format string (missing directive for '"
(cadr args)
"')"))
(list 'ref (list 'format s (car args))))
`(ref (format %s %(car args))))
(let [slice (String.slice s 0 (+ (inc idx) next))]
(list 'ref
(list 'String.append
(list 'ref (list 'format slice (car args)))
(fmt-internal (String.slice s (+ (inc idx) next) len)
(cdr args)))))))))))))
`(ref
(String.append
(ref (format %slice %(car args)))
%(fmt-internal (String.slice s (+ (inc idx) next) len)
(cdr args)))))))))))))
(doc fmt "formats a string. It supports all of the string interpolations defined in format of the type that should be interpolated (e.g. %d and %x on integers).")
(defmacro fmt [s :rest args]

View File

@ -83,7 +83,7 @@
)
(defmacro println* [:rest forms]
(list 'IO.println (build-str* forms)))
`(IO.println %(build-str* forms)))
(defmacro print* [:rest forms]
(list 'IO.print (build-str* forms)))
`(IO.print %(build-str* forms)))

View File

@ -55,7 +55,9 @@ Example:
(list 'cons-last (quasiquote- elem) acc)))
'()
arg)))
(list 'quote arg)))
(if (array? arg)
(collect-into (map quasiquote- arg) array)
(list 'quote arg))))
(doc quasiquote "is a quotation that may have expressions inside it in the
form of [`unquote](#unquote) and [`unquote-splicing`](#unquote-splicing).

View File

@ -20,11 +20,11 @@
(let [xsym (gensym-with 'xs)
len (gensym-with 'len)
i (gensym-with 'i)]
(list 'let [xsym xs
len (list 'StaticArray.length xsym)]
(list 'for [i 0 len]
(list 'let [var (list 'StaticArray.unsafe-nth xsym i)]
expr)))))
`(let [%xsym %xs
%len (StaticArray.length %xsym)]
(for [%i 0 %len]
(let [%var (StaticArray.unsafe-nth %xsym %i)]
%expr)))))
(defmacro foreach [binding expr]
(StaticArray.foreach-internal (car binding) (cadr binding) expr))

View File

@ -479,10 +479,10 @@
(defndynamic build-str* [forms]
(if (= (length forms) 0)
(list "")
'("")
(if (= (length forms) 1)
(list 'ref (list 'str (car forms)))
(list 'ref (list 'String.append (list 'ref (list 'str (car forms))) (build-str* (cdr forms)))))))
`&(str %(car forms))
`&(String.append &(str %(car forms)) %(build-str* (cdr forms))))))
(defmacro str* [:rest forms]
(list 'copy (build-str* forms)))
`(copy %(build-str* forms)))

View File

@ -137,26 +137,26 @@
(defndynamic with-test-internal [name forms]
(if (= (length forms) 1)
(list (list 'set! name (list 'ref (car forms))))
(cons (list 'set! name (list 'ref (car forms)))
`((set! %name &%(car forms)))
(cons `(set! %name &%(car forms))
(with-test-internal name (cdr forms)))))
(defmacro with-test [name :rest forms]
(list 'let (array name '&(Test.State.init 0 0))
(cons-last
(list 'Int.copy (list 'Test.State.failed name))
`(let [%name &(Test.State.init 0 0)]
%(cons-last
`@(Test.State.failed %name)
(cons-last
(list 'Test.print-test-results name)
(cons 'do (with-test-internal name forms))))
`(Test.print-test-results %name)
`(do %@(with-test-internal name forms))))
))
(defmacro deftest [name :rest forms]
(eval
(list 'defn 'main (array)
(list 'let (array name '&(Test.State.init 0 0))
(cons-last
(list 'Int.copy (list 'Test.State.failed name))
`(defn main []
(let [%name &(Test.State.init 0 0)]
%(cons-last
`@(Test.State.failed %name)
(cons-last
(list 'Test.print-test-results name)
(cons 'do (with-test-internal name forms))))))))
`(Test.print-test-results %name)
`(do %@(with-test-internal name forms))))))))

View File

@ -2,8 +2,8 @@
(private deftuple-type-)
(hidden deftuple-type-)
(defndynamic deftuple-type- [name props]
(list 'deftype (cons name props)
(collect-into (flatten (map (fn [x] (list x x)) props)) array)))
`(deftype (%name %@props)
%(collect-into (flatten (map (fn [x] `(%x %x)) props)) array)))
(private deftuple-lt-)
(hidden deftuple-lt-)
@ -12,10 +12,10 @@
'false
(let [fst (Symbol.prefix name (car props))]
(if (= (length props) 1)
(list '< (list fst 't1) (list fst 't2))
(list 'if (list '= (list fst 't1) (list fst 't2))
(deftuple-lt- name (cdr props))
(list '< (list fst 't1) (list fst 't2)))))))
`(< (%fst t1) (%fst t2))
`(if (= (%fst t1) (%fst t2))
%(deftuple-lt- name (cdr props))
(< (%fst t1) (%fst t2)))))))
; this is basically just a giant template
(private deftuple-module-)
@ -23,55 +23,33 @@
(defndynamic deftuple-module- [name props]
(let [sname (Symbol.str name)
module-name (Symbol.concat [name 'Ref])]
(list 'do
(list 'defmodule module-name
(list 'defn '= ['t1 't2]
(cons 'and*
(map (fn [p]
(list '=
(list (Symbol.prefix name p) 't1)
(list (Symbol.prefix name p) 't2)))
props)))
(list 'implements '= (Symbol.prefix module-name '=))
`(do
(defmodule %module-name
(defn < [t1 t2] %(deftuple-lt- name props))
(implements < %(Symbol.prefix module-name '<))
(list 'defn '< ['t1 't2] (deftuple-lt- name props))
(list 'implements '< (Symbol.prefix module-name '<))
(defn > [t1 t2] (%(Symbol.prefix module-name '<) t2 t1))
(implements > %(Symbol.prefix module-name '>)))
(list 'defn '> ['t1 't2] (list (Symbol.prefix module-name '<) 't2 't1))
(list 'implements '> (Symbol.prefix module-name '>)))
(defmodule %name
(doc init-from-refs
%(String.concat ["initializes a `" sname "` from member references."]))
%(let [prop-vars (map (fn [x] (Symbol.concat [x '-val])) props)]
`(defn init-from-refs %(collect-into prop-vars array)
(init %@(map (fn [x] `(copy %x)) prop-vars))))
(list 'defmodule name
(list 'doc 'init-from-refs
(String.concat ["initializes a `" sname "` from member references."]))
(let [prop-vars (map (fn [x] (Symbol.concat [x '-val])) props)]
(list 'defn 'init-from-refs (collect-into prop-vars array)
(cons 'init (map (fn [x] (list 'copy x)) prop-vars))))
(defn < [t1 t2]
(%(Symbol.prefix module-name '<) &t1 &t2))
(implements < %(Symbol.prefix name '<))
(list 'defn '= ['t1 't2]
(cons 'and*
(map (fn [p] (list '= (list p '(ref t1)) (list p '(ref t2)))) props)))
(list 'implements '= (Symbol.prefix name '=))
(defn > [t1 t2]
(%(Symbol.prefix module-name '>) &t1 &t2))
(implements > %(Symbol.prefix name '>))
(list 'defn '< ['t1 't2]
(list (Symbol.prefix module-name '<) '(ref t1) '(ref t2)))
(list 'implements '< (Symbol.prefix name '<))
(list 'defn '> ['t1 't2]
(list (Symbol.prefix module-name '>) '(ref t1) '(ref t2)))
(list 'implements '> (Symbol.prefix name '>))
(list 'doc 'reverse
(String.concat ["reverses a `" sname "` by reversing its member positions."]))
(list 'defn 'reverse ['t]
(cons 'init (map (fn [x] (list 'copy (list x 't))) (reverse props))))
(list 'meta-set! 'zero "doc"
(String.concat [
"initializes a `" sname
"` by calling `zero` for all its members. `zero` must be defined for all member types."]))
(list 'defn 'zero [] (cons 'init (map (fn [_] '(zero)) props))))
(list 'implements 'zero (Symbol.prefix name 'zero))
)))
(doc reverse
%(String.concat ["reverses a `" sname "` by reversing its member positions."]))
(defn reverse [t]
(init %@(map (fn [x] `(copy (%x t))) (reverse props))))))))
(doc deftuple "defines a tuple type.
@ -83,6 +61,8 @@ For example:
(defmacro deftuple [name :rest props]
(do
(eval (deftuple-type- name props))
(eval `(derive %name zero))
(eval `(derive %name =))
(eval (deftuple-module- name props))
))
)