Skip to content

Instantly share code, notes, and snippets.

@eduardoejp
Created September 10, 2022 03:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eduardoejp/47cf26c1aded95303238c1ec1bacc1ef to your computer and use it in GitHub Desktop.
Save eduardoejp/47cf26c1aded95303238c1ec1bacc1ef to your computer and use it in GitHub Desktop.
Toy example of an extension for the Lux analysis phase for doing type-agnostic arithmetic (specifically, addition)
... Arithmetical operations are defined on a per-type basis.
... Here, we'll define a "universal" way of adding numbers that works on the default numerical types in Lux, so long as the types of all the parameters line up.
(.require
[library
[lux (.except)
[abstract
["[0]" monad (.only do)]]
[control
[try (.only Try)]
["<>" parser]
["[0]" exception (.only Exception)]]
[data
[text
["%" \\format]]
[collection
["[0]" list (.use "[1]#[0]" mix)]]]
[meta
[extension (.only analysis)]
["[0]" code
["<[1]>" \\parser]]
[macro
[syntax (.only syntax)]]
[type
["[0]" check]]
[compiler
["[0]" phase (.use "[1]#[0]" monad)]
[language
[lux
["[0]" analysis (.only Analysis Operation Phase)
["[0]" type]]]]
[meta
[archive (.only Archive)]]]]]]
[/
[number
["[0]" nat]
["[0]" int]
["[0]" rev]
["[0]" frac]]])
(exception.def (no_arithmetic_for type)
(Exception Type)
(exception.report
(list ["Type" (%.type type)])))
(def (composite phase archive <+> last prevs)
(-> Phase Archive Code Analysis (List Analysis) (Operation Analysis))
(when <+>
[_ {.#Text $}]
(phase#in (list#mix (function (_ left right)
{analysis.#Extension $ (list left right)})
last
prevs))
_
(do phase.monad
[[_ $] (type.inferring
(phase archive <+>))]
(in (list#mix (function (_ left right)
(analysis.reified [$ (list left right)]))
last
prevs)))))
(with_expansions [<scenarios> (these [.Nat (in (analysis.nat 0)) "lux i64 +"]
[.Int (in (analysis.int +0)) "lux i64 +"]
[.Rev (in (analysis.rev .0)) "lux i64 +"]
[.Frac (in (analysis.frac +0.0)) "lux f64 +"])]
(analysis ("universal +" self phase archive [operands (<>.some <code>.any)])
(<| type.with_var
(function (_ [$it :it:]))
(do [! phase.monad]
[operands (monad.each ! (|>> (phase archive) (type.expecting :it:))
operands)
_ (type.inference :it:)
:it: (type.check (check.identity (list) $it))]
(when (list.reversed operands)
(list single)
(in single)
(list)
(`` (cond (check.subsumes? .I64 :it:)
(phase.except ..no_arithmetic_for [:it:])
(,, (with_template [<type> <0> <+>]
[(check.subsumes? <type> :it:)
<0>]
<scenarios>))
... else
(phase.except ..no_arithmetic_for [:it:])))
(list.partial last prevs)
(`` (cond (check.subsumes? .I64 :it:)
(phase.except ..no_arithmetic_for [:it:])
(,, (with_template [<type> <0> <+>]
[(check.subsumes? <type> :it:)
(..composite phase archive (` <+>) last prevs)]
<scenarios>))
... else
(phase.except ..no_arithmetic_for [:it:]))))))))
(def .public +
(syntax (_ [operands (<>.some <code>.any)])
(in (list (` ("universal +" (,* operands)))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment