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

Export TypeScript Declarations in New Syntax #139

Merged
merged 44 commits into from
Sep 29, 2022
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
8106de6
Update
NeilKleistGao Sep 9, 2022
f349b5f
Fix type parameter substitution
NeilKleistGao Sep 13, 2022
5acdc5c
Fix function convert
NeilKleistGao Sep 13, 2022
234f8dc
Fix namespaces parse
NeilKleistGao Sep 13, 2022
cc5bc3a
Fix class/trait names
NeilKleistGao Sep 13, 2022
af5a927
Fix bra type
NeilKleistGao Sep 13, 2022
87b8f15
Fix type parameters application
NeilKleistGao Sep 13, 2022
d2ee8d0
Fix parentheses
NeilKleistGao Sep 13, 2022
a4f0b12
Fix error tup
NeilKleistGao Sep 13, 2022
4c52471
Fix class format
NeilKleistGao Sep 13, 2022
ca99046
Add comments
NeilKleistGao Sep 13, 2022
463fbf8
Merge branch 'hkust-taco:mlscript' into new-class
Sep 13, 2022
50b8c14
Update fun/let
NeilKleistGao Sep 13, 2022
1bb4c2f
Fix nested type arguments
NeilKleistGao Sep 14, 2022
7fce986
Hide warning temporarily
NeilKleistGao Sep 14, 2022
1bd4097
Update shared/src/main/scala/mlscript/NewParser.scala
Sep 15, 2022
7b09aae
Update ts2mls/js/src/main/scala/ts2mls/types/Converter.scala
Sep 15, 2022
15dfcb4
Fix ce
NeilKleistGao Sep 15, 2022
921f1ff
Remove silent errors
NeilKleistGao Sep 15, 2022
1866480
Fix fun
NeilKleistGao Sep 15, 2022
9c9a9a5
Fix fun
NeilKleistGao Sep 15, 2022
75317f8
Add inner class translation
NeilKleistGao Sep 15, 2022
1fa6c95
Add constructor translation
NeilKleistGao Sep 15, 2022
90738e2
Add tparams for fun
NeilKleistGao Sep 16, 2022
4e5fc5e
Add typeparameters
NeilKleistGao Sep 16, 2022
3b1401e
Fix record func
NeilKleistGao Sep 16, 2022
0ac1384
Name parameters
NeilKleistGao Sep 19, 2022
af5f657
Fix ignored overloading
NeilKleistGao Sep 19, 2022
218e6b8
Fix ignored overloading in classes
NeilKleistGao Sep 19, 2022
e916a40
Fix parameter names
NeilKleistGao Sep 20, 2022
5fe4271
Refactor
NeilKleistGao Sep 21, 2022
b8445db
Refactor
NeilKleistGao Sep 21, 2022
d1d3ca1
Refactor
NeilKleistGao Sep 21, 2022
58fdeae
Refactor
NeilKleistGao Sep 21, 2022
6bcd284
Clean converter
NeilKleistGao Sep 21, 2022
70dde71
Add comments
NeilKleistGao Sep 21, 2022
d652e7e
Fix multiple angles in bracket function
NeilKleistGao Sep 26, 2022
5463253
Merge branch 'mlscript' into new-class
LPTK Sep 29, 2022
5dab58b
Merge branch 'mlscript' into new-class
LPTK Sep 29, 2022
0a62009
Use assert and require
NeilKleistGao Sep 29, 2022
3e23dae
Revert
NeilKleistGao Sep 29, 2022
0f6ee20
Use AssertionError instead
NeilKleistGao Sep 29, 2022
765c9ae
Use NotImplementedError instead
NeilKleistGao Sep 29, 2022
150f88b
Merge branch 'hkust-taco:mlscript' into new-class
Sep 29, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions shared/src/main/scala/mlscript/JSBackend.scala
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,7 @@ class JSBackend {
traits += topLevelScope.declareTrait(name, tparams map { _.name }, body, methods)
case TypeDef(Cls, TypeName(name), tparams, baseType, _, members, _) =>
classes += topLevelScope.declareClass(name, tparams map { _.name }, baseType, members)
case TypeDef(Nms, TypeName(name), _, _, _, members, _) => () // TODO: deal with namespace
LPTK marked this conversation as resolved.
Show resolved Hide resolved
}
(traits.toList, classes.toList)
}
Expand Down
1 change: 1 addition & 0 deletions shared/src/main/scala/mlscript/MLParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ class MLParser(origin: Origin, indent: Int = 0, recordLocations: Bool = true) {
ms.collect { case R(md) => md }, ms.collect{ case L(md) => md }, Nil)
}
case (k @ Als, id, ts) => "=" ~ ty map (bod => TypeDef(k, id, ts, bod, Nil, Nil, Nil))
case (k @ Nms, id, _) => "=" ~ ty map (bod => TypeDef(k, id, Nil, bod, Nil, Nil, Nil)) // TODO: deal with namespaces
})
def tyParams[p: P]: P[Ls[TypeName]] =
("[" ~ tyName.rep(0, ",") ~ "]").?.map(_.toList.flatten)
Expand Down
15 changes: 14 additions & 1 deletion shared/src/main/scala/mlscript/NewLexer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) {
val (txt, k) =
takeWhile(j)(c => c =/= '\n')
go(k, COMMENT(txt))
case '/' if bytes.lift(i + 1).contains('*') =>
val j = i + 2
var prev1 = '/'; var prev2 = '*'
val (txt, k) =
takeWhile(j)(c => {
val r = prev1 =/= '*' || prev2 =/= '/'
prev1 = prev2; prev2 = c
r
})
go(k, COMMENT(txt.dropRight(2)))
case BracketKind(Left(k)) => go(i + 1, OPEN_BRACKET(k))
case BracketKind(Right(k)) => go(i + 1, CLOSE_BRACKET(k))
case '\n' =>
Expand Down Expand Up @@ -119,6 +129,8 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) {
val (name, k) = takeWhile(j)(isIdentChar)
go(k, SELECT(name))
}
else if (c === '>' && n.length > 1 && n.foldLeft(true)((r, i) => r && (i === c)))
go(i + 1, IDENT(">", true))
else go(j, if (isSymKeyword.contains(n)) KEYWORD(n) else IDENT(n, true))
case _ if isDigit(c) =>
val (str, j) = takeWhile(i)(isDigit)
Expand Down Expand Up @@ -164,7 +176,7 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) {
if (k0 =/= k1)
raise(ErrorReport(msg"Mistmatched closing ${k1.name}" -> S(l1) ::
msg"does not correspond to opening ${k0.name}" -> S(l0) :: Nil, source = Parsing))
go(rest, false, stack, BRACKETS(k0, acc.reverse)(l0.right ++ l1.left) -> (l0 ++ l1) :: oldAcc)
go(rest, true, stack, BRACKETS(k0, acc.reverse)(l0.right ++ l1.left) -> (l0 ++ l1) :: oldAcc)
case Nil =>
raise(ErrorReport(msg"Unexpected closing ${k1.name}" -> S(l1) :: Nil, source = Parsing))
go(rest, false, stack, acc)
Expand Down Expand Up @@ -234,6 +246,7 @@ object NewLexer {
"trait",
"interface",
"new",
"namespace"
)

def printToken(tl: TokLoc): Str = tl match {
Expand Down
8 changes: 6 additions & 2 deletions shared/src/main/scala/mlscript/NewParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,10 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D

private def cur(implicit l: Line, n: Name) = {
if (dbg) printDbg(s"? ${n.value}\t\tinspects ${summarizeCur} [at l.${l.value}]")
_cur
_cur.dropWhile(_._1 match {
case COMMENT(_) => true
case _ => false
})
NeilKleistGao marked this conversation as resolved.
Show resolved Hide resolved
}

def consume(implicit l: Line, n: Name): Unit = {
Expand Down Expand Up @@ -235,12 +238,13 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D
case (SPACE, _) :: _ => consume; block
case c =>
val t = c match {
case (KEYWORD(k @ ("class" | "trait" | "type")), l0) :: c =>
case (KEYWORD(k @ ("class" | "trait" | "type" | "namespace")), l0) :: c =>
consume
val kind = k match {
case "class" => Cls
case "trait" => Trt
case "type" => Als
case "namespace" => Nms
case _ => die
}
val (tn, success) = yeetSpaces match {
Expand Down
4 changes: 4 additions & 0 deletions shared/src/main/scala/mlscript/TypeDefs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ class TypeDefs extends NuTypeDefs { self: Typer =>

val rightParents = td.kind match {
case Als => checkCycle(td.bodyTy)(Set.single(L(td.nme)))
case Nms => checkCycle(td.bodyTy)(Set.single(L(td.nme)))
case k: ObjDefKind =>
val parentsClasses = MutSet.empty[TypeRef]
def checkParents(ty: SimpleType): Bool = ty match {
Expand All @@ -246,6 +247,9 @@ class TypeDefs extends NuTypeDefs { self: Typer =>
} else
checkParents(tr.expand)
case Trt => checkParents(tr.expand)
case Nms =>
err(msg"cannot inherit from a namespace", prov.loco)
false
case Als =>
err(msg"cannot inherit from a type alias", prov.loco)
false
Expand Down
3 changes: 3 additions & 0 deletions shared/src/main/scala/mlscript/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,8 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool)
case Trt => trtNameToNomTag(td)(tyTp(tyLoc, "trait tag"), ctx)
case Als => err(
msg"Type alias ${name.capitalize} cannot be used as a type tag", tyLoc)(raise)
case Nms => err(
msg"Namespaces ${name.capitalize} cannot be used as a type tag", tyLoc)(raise)
}
case _ => e()
}
Expand Down Expand Up @@ -750,6 +752,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool)
case Some(td) =>
td.kind match {
case Als => err(msg"can only match on classes and traits", pat.toLoc)(raise)
case Nms => err(msg"can only match on classes and traits", pat.toLoc)(raise)
case Cls => clsNameToNomTag(td)(tp(pat.toLoc, "class pattern"), ctx)
case Trt => trtNameToNomTag(td)(tp(pat.toLoc, "trait pattern"), ctx)
}
Expand Down
1 change: 1 addition & 0 deletions shared/src/main/scala/mlscript/TyperDatatypes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer =>
else TopType
subst(td.kind match {
case Als => td.bodyTy
case Nms => td.bodyTy // TODO: deal with namespaces
case Cls => clsNameToNomTag(td)(prov, ctx) & td.bodyTy & tparamTags
case Trt => trtNameToNomTag(td)(prov, ctx) & td.bodyTy & tparamTags
}, td.targs.lazyZip(targs).toMap) //.withProv(prov)
Expand Down
4 changes: 3 additions & 1 deletion shared/src/main/scala/mlscript/codegen/Scope.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import mlscript.utils.shorthands._
import mlscript.{JSStmt, JSExpr, JSLetDecl}
import mlscript.Type
import scala.reflect.ClassTag
import mlscript.{TypeName, Top, Bot, TypeDef, Als, Trt, Cls}
import mlscript.{TypeName, Top, Bot, TypeDef, Als, Trt, Cls, Nms}
import mlscript.MethodDef
import mlscript.Term
import mlscript.utils.{AnyOps, lastWords}
Expand Down Expand Up @@ -200,6 +200,8 @@ class Scope(name: Str, enclosing: Opt[Scope]) {
declareTrait(name, tparams map { _.name }, body, mthdDefs)
case TypeDef(Cls, TypeName(name), tparams, baseType, _, members, _) =>
declareClass(name, tparams map { _.name }, baseType, members)
case TypeDef(Nms, TypeName(name), _, body, _, _, _) =>
declareTypeAlias(name, Ls(), body) // TODO: deal with namespaces
LPTK marked this conversation as resolved.
Show resolved Hide resolved
}

def declareClass(
Expand Down
7 changes: 6 additions & 1 deletion shared/src/main/scala/mlscript/helpers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -428,10 +428,15 @@ trait TermImpl extends StatementImpl { self: Term =>
case Tup(fields) => Tuple(fields.map(fld => (fld._1, fld._2 match {
case Fld(m, s, v) => val ty = v.toType_!; Field(Option.when(m)(ty), ty)
})))
case Bra(rcd, trm) if (!rcd) => trm.toType_!
case TyApp(lhs, targs) => lhs.toType_! match {
case p: TypeName => AppliedType(p, targs)
case _ => throw new NotAType(this)
}
// TODO:
// case Rcd(fields) => ???
// case Sel(receiver, fieldName) => ???
// case Let(isRec, name, rhs, body) => ???
// case Let(isRec, name, rhs, body) =>
// case Blk(stmts) => ???
// case Bra(rcd, trm) => ???
// case Asc(trm, ty) => ???
Expand Down
1 change: 1 addition & 0 deletions shared/src/main/scala/mlscript/syntax.scala
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ sealed trait ObjDefKind
case object Cls extends TypeDefKind("class") with ObjDefKind
case object Trt extends TypeDefKind("trait") with ObjDefKind
case object Als extends TypeDefKind("type alias")
case object Nms extends TypeDefKind("namespace")

sealed abstract class Term extends Terms with TermImpl
sealed abstract class Lit extends SimpleTerm with LitImpl
Expand Down
14 changes: 4 additions & 10 deletions shared/src/test/diff/parser/Comments.mls
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,8 @@
// TODO comments
1 // whoops
//│ |1| |/* whoops*/|
//│ ╔══[PARSE ERROR] Unexpected comment in expression position
//│ ║ l.3: 1 // whoops
//│ ╙── ^^^^^^^^^
//│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here
//│ ║ l.3: 1 // whoops
//│ ╙── ^
//│ ╔══[WARNING] Paren-less applications should use the 'of' keyword
//│ ║ l.3: 1 // whoops
//│ ╙── ^^^^^^^^^^^
//│ Parsed: {1 (undefined,)}
//│ Parsed: {1}

2 /* whoops */
//│ |2| |/* whoops */|
//│ Parsed: {2}
2 changes: 2 additions & 0 deletions ts2mls/js/src/main/scala/ts2mls/JSWriter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ class JSWriter(filename: String) {
private var fileSize = 0 // how many bytes we've written in the file
private var needTruncate = false

writeln(":NewParser\n:ParseOnly")

def writeln(str: String) = {
val strln = str + "\n"
val buffer = createBuffer(strln.length)
Expand Down
58 changes: 35 additions & 23 deletions ts2mls/js/src/main/scala/ts2mls/TSNamespace.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ts2mls

import scala.collection.mutable.{HashMap, ListBuffer}
import types._
import mlscript.utils._

class TSNamespace(name: String, parent: Option[TSNamespace]) {
private val subSpace = HashMap[String, TSNamespace]()
Expand Down Expand Up @@ -34,40 +35,51 @@ class TSNamespace(name: String, parent: Option[TSNamespace]) {
def containsMember(name: String, searchParent: Boolean = true): Boolean =
if (parent.isEmpty) members.contains(name) else (members.contains(name) || (searchParent && parent.get.containsMember(name)))

def generate(writer: JSWriter): Unit =
def generate(writer: JSWriter, indent: String): Unit =
order.toList.foreach((p) => p match {
case Left(name) => subSpace(name).generate(writer)
case Left(subName) => {
writer.writeln(s"${indent}namespace $subName {")
subSpace(subName).generate(writer, indent + " ")
writer.writeln(s"$indent}")
}
case Right(name) => {
val mem = members(name)
val fullName = getFullPath(name)
// val fullName = getFullPath(name)
mem match {
case inter: TSIntersectionType => // overloaded functions
writer.writeln(s"def ${fullName}: ${Converter.convert(inter)}")
case f: TSFunctionType => {
val typeParams = f.typeVars.map((t) => t.name)
if (typeParams.isEmpty)
writer.writeln(s"def ${fullName}: ${Converter.convert(f)}")
else // TODO: add constraints
writer.writeln(s"def ${fullName}[${typeParams.reduceLeft((r, s) => s"$r, $s")}]: ${Converter.convert(f)}")
}
case overload @ TSIgnoredOverload(base, _) => {
val typeParams = base.typeVars.map((t) => t.name)
if (typeParams.isEmpty)
writer.writeln(s"def ${fullName}: ${Converter.convert(overload)}")
else // TODO: add constraints
writer.writeln(s"def ${fullName}[${typeParams.reduceLeft((r, s) => s"$r, $s")}]: ${Converter.convert(overload)}")
}
case _ => writer.writeln(Converter.convert(mem))
writer.writeln(s"${indent}let ${name}: ${Converter.convert(inter)}")
case f: TSFunctionType =>
writer.writeln(s"${indent}let ${name}: ${Converter.convert(f)}")
// {
// val typeParams = f.typeVars.map((t) => t.name)
// if (typeParams.isEmpty)
// writer.writeln(s"def ${fullName}: ${Converter.convert(f)}")
// else // TODO: add constraints
// writer.writeln(s"def ${fullName}[${typeParams.reduceLeft((r, s) => s"$r, $s")}]: ${Converter.convert(f)}")
// }
case overload @ TSIgnoredOverload(base, _) =>
writer.writeln(s"${indent}let ${name}: ${Converter.convert(overload)}")
// {
// val typeParams = base.typeVars.map((t) => t.name)
// if (typeParams.isEmpty)
// writer.writeln(s"def ${fullName}: ${Converter.convert(overload)}")
// else // TODO: add constraints
// writer.writeln(s"def ${fullName}[${typeParams.reduceLeft((r, s) => s"$r, $s")}]: ${Converter.convert(overload)}")
// }
case _: TSClassType => writer.writeln(indent + Converter.convert(mem)(indent))
case _ @ TSInterfaceType(name, _, _, _) if (name =/= "") =>
writer.writeln(indent + Converter.convert(mem)(indent))
case _ => writer.writeln(indent + Converter.convert(mem))
}
}
})

// generate full path with namespaces' names
// e.g. f => Namespace1.Namespace2.f
def getFullPath(nm: String): String = parent match {
case Some(p) => p.getFullPath(s"$name'$nm")
case _ => nm
}
// def getFullPath(nm: String): String = parent match {
// case Some(p) => p.getFullPath(s"$name'$nm")
// case _ => nm
// }
}

object TSNamespace {
Expand Down
2 changes: 1 addition & 1 deletion ts2mls/js/src/main/scala/ts2mls/TSProgram.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class TSProgram(filenames: Seq[String]) {
implicit val checker = TSTypeChecker(program.getTypeChecker())
filenames.foreach(filename => TSSourceFile(program.getSourceFile(filename), globalNamespace))

def generate(writer: JSWriter): Unit = globalNamespace.generate(writer)
def generate(writer: JSWriter): Unit = globalNamespace.generate(writer, "")
}

object TSProgram {
Expand Down
4 changes: 2 additions & 2 deletions ts2mls/js/src/main/scala/ts2mls/TSSourceFile.scala
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,9 @@ object TSSourceFile {
}
}
else if (node.isClassDeclaration)
ns.put(name, parseMembers(ns.getFullPath(name), node, true))
ns.put(name, parseMembers(name, node, true))
else if (node.isInterfaceDeclaration)
ns.put(name, parseMembers(ns.getFullPath(name), node, false))
ns.put(name, parseMembers(name, node, false))
else if (node.isNamespace)
parseNamespace(node)

Expand Down
Loading