Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement user-defined symbolic operators & uncurry all operator applications #177

Merged
merged 7 commits into from
Sep 13, 2023

Conversation

LPTK
Copy link
Contributor

@LPTK LPTK commented Sep 12, 2023

Examples:

fun (>>) compose(f, g) = x => g(f(x))
//│ fun (>>) compose: forall 'a 'b 'c. ('a -> 'b, 'b -> 'c) -> 'a -> 'c

:js 
let r = succ >> succ
//│ let r: Int -> Int
//│ // Prelude
//│ function succ(x) {
//│   return x + 1;
//│ }
//│ class TypingUnit1 {}
//│ const typing_unit1 = new TypingUnit1;
//│ // Query 1
//│ globalThis.r = compose(succ, succ);
//│ // End of generated code
//│ r
//│   = [Function (anonymous)]

r(3)
//│ Int
//│ res
//│     = 5

At the type level:

type *[A, B] = [A, B]
//│ type *[A, B] = [A, B]


fun x : Int * Int
fun x = [0, 1]
//│ fun x: [0, 1]
//│ fun x: *[Int, Int]

@NeilKleistGao
Copy link
Member

It seems that there are some parsing problems:

fun (<<|+_+|>>) robot(a, b) = a + b
//│ fun (<<|+) robot: (Int, Int) -> Int
// should be `<<|+_+|>>`, but we got `<<|+`

fun (:-D) dd(a, b) = a + b
//│ fun (:-) dd: (Int, Int) -> Int
// should be `:-D`, but we got `:-`

The parsed operators are not complete. If there is any unsupported symbol in the defined operators, maybe we can reject it in the parser.

@LPTK
Copy link
Contributor Author

LPTK commented Sep 12, 2023

@NeilKleistGao Good catch! I've fixed the parsing bug (it was swallowing some erroneous tokens) and improved the error messages.

@chengluyu
Copy link
Member

chengluyu commented Sep 12, 2023

When will we support emoji? 😁😄😃 Can't wait to use real magic wind 🪄 instead of -*.

@LPTK
Copy link
Contributor Author

LPTK commented Sep 12, 2023

@chengluyu Good suggestion! But the lexer currently says "unexpected character" :^(

@LPTK
Copy link
Contributor Author

LPTK commented Sep 12, 2023

@NeilKleistGao @chengluyu Some parts of JSBackend.scala are really hairy, with strange/fishy logic. For example see all the // TODO Improve comments I added here:

// TODO Improve: (Lionel) I find this logic very strange! What's going on here?
// Why are we declaring some things above AND below?
// Why does the fact that a binding is recursive affect its declaration in the OUTER scope?
// Generate statements.
val queries = otherStmts.map {
case NuFunDef(isLetRec, nme @ Var(name), symNme, tys, rhs @ L(body)) =>
val recursive = isLetRec.getOrElse(true)
val isByname = isLetRec.isEmpty
val bodyIsLam = body match { case _: Lam => true case _ => false }
val symb = symNme.map(_.name)
(if (recursive) {
val isByvalueRecIn = if (isByname) None else Some(true)
val sym = scope.resolveValue(name) match {
case Some(s: ValueSymbol) => s
case _ => scope.declareValue(name, isByvalueRecIn, bodyIsLam, symb)
}
val isByvalueRecOut = if (isByname) None else Some(false)
try {
val translated = translateTerm(body) // TODO Improve: (Lionel) Why are the bodies translated in the SAME scope?!
scope.unregisterSymbol(sym) // TODO Improve: (Lionel) ???
R((translated, scope.declareValue(name, isByvalueRecOut, bodyIsLam, symb)))
} catch {
case e: UnimplementedError =>
scope.stubize(sym, e.symbol)
L(e.getMessage())
case NonFatal(e) =>
scope.unregisterSymbol(sym) // TODO Improve: (Lionel) You should only try/catch around the part that may actually fail, and if `unregisterSymbol` should always be called, that should be done in `finally`... but the very logic of calling `unregisterSymbol` is very fishy, to say the least
scope.declareValue(name, isByvalueRecOut, bodyIsLam, symb)
throw e
}
} else {
(try R(translateTerm(body)) catch { // TODO Improve: Why are the bodies translated in the SAME scope?!
case e: UnimplementedError =>
scope.declareStubValue(name, e.symbol, symb)
L(e.getMessage())
}) map {
val isByvalueRec = if (isByname) None else Some(false)
expr => (expr, scope.declareValue(name, isByvalueRec, bodyIsLam))
}

Because of this I couldn't easily tell why this one does not currently work:

val (-->) f(x, y) = [x, y]
//│ let (-->) f: forall 'a 'b. ('a, 'b) -> ['a, 'b]
//│ f
//│   = [Function: f]

:ge // FIXME
12 --> 34
//│ [12, 34]
//│ Code generation encountered an error:
//│   unresolved symbol -->

Copy link
Member

@NeilKleistGao NeilKleistGao left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@LPTK LPTK merged commit 0fde886 into new-definition-typing Sep 13, 2023
1 check passed
@LPTK LPTK deleted the symbolic-operators branch September 13, 2023 10:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants