|
841 | 841 | ;; Higher Order Functions ;;
|
842 | 842 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
843 | 843 |
|
| 844 | +(defn apply-kw |
| 845 | + [f & args] |
| 846 | + (basilisp.lang.runtime/apply-kw f args)) |
| 847 | + |
844 | 848 | (defmacro lazy-seq
|
845 | 849 | "Takes a body of expressions which will produce a seq or nil. When
|
846 | 850 | seq is first called on the resulting lazy-seq, the sequence will be
|
|
2312 | 2316 | (basilisp.lang.runtime/to-lisp o))
|
2313 | 2317 | ([o & {:keys [keywordize-keys] :or {keywordize-keys true}}]
|
2314 | 2318 | (basilisp.lang.runtime/to-lisp o keywordize-keys)))
|
| 2319 | + |
| 2320 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 2321 | +;; Data Types & Protocols ;; |
| 2322 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 2323 | + |
| 2324 | +(import* abc) |
| 2325 | + |
| 2326 | +(defmulti ^:private munge |
| 2327 | + "Munge the input value into a Python-safe string. Converts keywords and |
| 2328 | + symbols into strings as by `name` prior to munging. Returns a string." |
| 2329 | + builtins/type) |
| 2330 | + |
| 2331 | +(defmethod munge basilisp.lang.keyword/Keyword |
| 2332 | + [kw] |
| 2333 | + (basilisp.lang.util/munge (name kw))) |
| 2334 | + |
| 2335 | +(defmethod munge basilisp.lang.symbol/Symbol |
| 2336 | + [s] |
| 2337 | + (basilisp.lang.util/munge (name s))) |
| 2338 | + |
| 2339 | +(defmethod munge builtins/str |
| 2340 | + [s] |
| 2341 | + (basilisp.lang.util/munge s)) |
| 2342 | + |
| 2343 | +(defn gen-interface |
| 2344 | + "Generate and return a new Python interface (abstract base clase). |
| 2345 | + |
| 2346 | + Callers should use `definterface` to generate new interfaces." |
| 2347 | + [interface-name methods] |
| 2348 | + (let [methods (reduce (fn [m [method-name args]] |
| 2349 | + (let [method-args (->> (concat ['self] args) |
| 2350 | + (apply vector)) |
| 2351 | + method (->> (list 'fn* method-name method-args) |
| 2352 | + (eval) |
| 2353 | + (abc/abstractmethod))] |
| 2354 | + (assoc m (munge method-name) method))) |
| 2355 | + {} |
| 2356 | + methods)] |
| 2357 | + (builtins/type interface-name |
| 2358 | + #py (abc/ABC) |
| 2359 | + (lisp->py methods)))) |
| 2360 | + |
| 2361 | +(defmacro definterface |
| 2362 | + "Define a new Python interface (abstract base clase) with the given name |
| 2363 | + and method signatures. |
| 2364 | + |
| 2365 | + Method signatures are in the form (method-name [arg1 arg2 ...]). |
| 2366 | + |
| 2367 | + Interface objects cannot be directly instantiated. Instead, you must create |
| 2368 | + a concrete implementation of an interface (perhaps via deftype) and supply |
| 2369 | + implementations for all of the abstract methods. |
| 2370 | + |
| 2371 | + The generated interface derives from Python's `abc.ABC` and all method |
| 2372 | + definitions are declared as `abc.abstractmethod`s and thus must be implemented |
| 2373 | + by a concrete type. |
| 2374 | + |
| 2375 | + The generated interface will be immediately available after this form has |
| 2376 | + been evaluated and its utility is not limited to compilation." |
| 2377 | + [interface-name & methods] |
| 2378 | + (let [name-str (name interface-name) |
| 2379 | + method-sigs (map #(list 'quote %) methods)] |
| 2380 | + `(def ~interface-name |
| 2381 | + (gen-interface ~name-str [~@method-sigs])))) |
| 2382 | + |
| 2383 | +(defmacro deftype |
| 2384 | + "Define a new Python concrete type which can implement 0 or more Python |
| 2385 | + interfaces or Basilisp protocols. |
| 2386 | + |
| 2387 | + The new type will have fields matching the names in `fields`. Fields may |
| 2388 | + be referred to unqualified in the bodies of implemented methods. By default |
| 2389 | + the fields of this type are immutable. Attempting to set non-mutable fields |
| 2390 | + from a method body will result in a compiler error. |
| 2391 | + |
| 2392 | + Fields may be made mutable by annotating their definition with `:mutable` |
| 2393 | + metadata. Mutable fields may be set within method bodies using the `set!` |
| 2394 | + special form. It is not advised to use mutable fields unless you are sure |
| 2395 | + you know what you are doing. As a consequence of Python's lax policy towards |
| 2396 | + immutability, types with even one mutable field may be mutated by outside |
| 2397 | + callers using `set!`, so bear that in mind when choosing mutability. |
| 2398 | + |
| 2399 | + Interface or protocol implementations are declared as the name of the |
| 2400 | + interface or protocol as a symbol, followed by 1 or more method |
| 2401 | + definitions for that interface. Types are not required to declare |
| 2402 | + any interface implementations. Types which do declare interface |
| 2403 | + implementations are required to implement all interface methods. Failing |
| 2404 | + to implement all interface methods is a compile time error. Types |
| 2405 | + implementing `object` are not required to implement all `object` methods. |
| 2406 | + |
| 2407 | + Method declarations should appear as: |
| 2408 | + |
| 2409 | + (method-name [arg1 arg2 ...] & body) |
| 2410 | + |
| 2411 | + Type objects are created with sensible `object` defaults as by `attrs`. |
| 2412 | + New types may override `object` defaults. An `__init__` function is |
| 2413 | + automatically created which takes positional arguments matching the |
| 2414 | + order of definition in `fields`. Additionally, given a name `NewType`, |
| 2415 | + a factory function will be created `->NewType` which can be used to |
| 2416 | + generate new instances of the type. |
| 2417 | + |
| 2418 | + Methods must supply a `this` or `self` parameter. `recur` special forms |
| 2419 | + used in the body of a method should not include that parameter, as it |
| 2420 | + will be supplied automatically." |
| 2421 | + [type-name fields & method-impls] |
| 2422 | + (let [ctor-name (with-meta |
| 2423 | + (symbol (str "->" (name type-name))) |
| 2424 | + (meta type-name))] |
| 2425 | + `(do |
| 2426 | + (deftype* ~type-name ~fields |
| 2427 | + ~@method-impls) |
| 2428 | + (def ~ctor-name ~type-name) |
| 2429 | + ~type-name))) |
0 commit comments