diff --git a/editors/vscode/src/lsp-server.ts b/editors/vscode/src/lsp-server.ts index 1396957..262835f 100644 --- a/editors/vscode/src/lsp-server.ts +++ b/editors/vscode/src/lsp-server.ts @@ -25,6 +25,8 @@ const documents: TextDocuments = new TextDocuments(TextDocument); const languageService = new CosmoLanguageService(documents); +const ENABLE_HOVER = false; + const offsetOf = (doc: TextDocument | undefined, pos: Position) => doc?.offsetAt(pos) ?? 0; @@ -72,7 +74,7 @@ connection.onInitialize((params: InitializeParams) => { completionProvider: { resolveProvider: true, }, - hoverProvider: true, + hoverProvider: ENABLE_HOVER, diagnosticProvider: { interFileDependencies: false, workspaceDiagnostics: false, diff --git a/packages/cosmo/snapshots/ParserTests/samples/Syntax/expr.syntax.cos-ast b/packages/cosmo/snapshots/ParserTests/samples/Syntax/expr.syntax.cos-ast index 2c663cf..1b875b9 100644 --- a/packages/cosmo/snapshots/ParserTests/samples/Syntax/expr.syntax.cos-ast +++ b/packages/cosmo/snapshots/ParserTests/samples/Syntax/expr.syntax.cos-ast @@ -83,236 +83,6 @@ Some( ) ), ct = false - ), - Match(lhs = Ident(name = "a"), rhs = Block(stmts = List())), - Match( - lhs = BinOp(op = "+", lhs = Ident(name = "a"), rhs = IntLit(value = 1)), - rhs = Block(stmts = List()) - ), - Match( - lhs = Select(lhs = Ident(name = "a"), rhs = Ident(name = "method"), ct = false), - rhs = Block(stmts = List()) - ), - Match( - lhs = Apply( - lhs = Select(lhs = Ident(name = "a"), rhs = Ident(name = "method"), ct = false), - rhs = List(), - ct = false - ), - rhs = Block(stmts = List()) - ), - Match( - lhs = BinOp(op = "*", lhs = Ident(name = "a"), rhs = IntLit(value = 1)), - rhs = Block(stmts = List()) - ), - BinOp( - op = "=", - lhs = Ident(name = "a"), - rhs = Match(lhs = IntLit(value = 1), rhs = Block(stmts = List())) - ), - BinOp( - op = "=", - lhs = Ident(name = "a"), - rhs = Match(lhs = Ident(name = "a"), rhs = Block(stmts = List())) - ), - Match( - lhs = IntLit(value = 1), - rhs = CaseBlock(stmts = List(Case(cond = IntLit(value = 1), body = None))) - ), - Match( - lhs = IntLit(value = 1), - rhs = CaseBlock( - stmts = List( - Case(cond = IntLit(value = 1), body = Some(value = IntLit(value = 2))) - ) - ) - ), - Match( - lhs = IntLit(value = 1), - rhs = CaseBlock( - stmts = List( - Case(cond = BoolLit(value = false), body = Some(value = IntLit(value = 2))) - ) - ) - ), - Match( - lhs = BinOp(op = "+", lhs = IntLit(value = 1), rhs = IntLit(value = 1)), - rhs = CaseBlock( - stmts = List( - Case( - cond = BinOp(op = "+", lhs = IntLit(value = 1), rhs = IntLit(value = 1)), - body = Some(value = IntLit(value = 2)) - ) - ) - ) - ), - Match( - lhs = BinOp(op = "+", lhs = IntLit(value = 1), rhs = IntLit(value = 1)), - rhs = CaseBlock( - stmts = List( - Case( - cond = BinOp( - op = "+", - lhs = BinOp(op = "*", lhs = IntLit(value = 1), rhs = IntLit(value = 1)), - rhs = IntLit(value = 1) - ), - body = Some(value = IntLit(value = 2)) - ) - ) - ) - ), - Match( - lhs = IntLit(value = 1), - rhs = CaseBlock( - stmts = List( - Case(cond = Ident(name = "a"), body = Some(value = IntLit(value = 2))) - ) - ) - ), - Match( - lhs = IntLit(value = 1), - rhs = CaseBlock( - stmts = List( - Case(cond = Ident(name = "a"), body = Some(value = IntLit(value = 2))) - ) - ) - ), - Match( - lhs = BinOp(op = "+", lhs = IntLit(value = 1), rhs = IntLit(value = 1)), - rhs = CaseBlock( - stmts = List( - Case( - cond = BinOp(op = "+", lhs = IntLit(value = 1), rhs = Ident(name = "a")), - body = Some(value = IntLit(value = 2)) - ) - ) - ) - ), - Match( - lhs = BinOp(op = "+", lhs = IntLit(value = 1), rhs = IntLit(value = 1)), - rhs = CaseBlock( - stmts = List( - Case( - cond = BinOp( - op = "+", - lhs = BinOp(op = "*", lhs = IntLit(value = 1), rhs = IntLit(value = 1)), - rhs = Ident(name = "a") - ), - body = Some(value = IntLit(value = 2)) - ) - ) - ) - ), - Match( - lhs = BinOp(op = "+", lhs = IntLit(value = 1), rhs = IntLit(value = 1)), - rhs = CaseBlock( - stmts = List( - Case( - cond = Ident(name = "a"), - body = Some(value = Block(stmts = List(IntLit(value = 2)))) - ) - ) - ) - ), - Match( - lhs = BinOp(op = "+", lhs = IntLit(value = 1), rhs = IntLit(value = 1)), - rhs = CaseBlock( - stmts = List( - Case( - cond = Apply( - lhs = Select(lhs = Ident(name = "A"), rhs = Ident(name = "B"), ct = false), - rhs = List(), - ct = false - ), - body = Some(value = Block(stmts = List(IntLit(value = 2)))) - ) - ) - ) - ), - Match( - lhs = BinOp(op = "+", lhs = IntLit(value = 1), rhs = IntLit(value = 1)), - rhs = CaseBlock( - stmts = List( - Case( - cond = Apply( - lhs = Select(lhs = Ident(name = "A"), rhs = Ident(name = "B"), ct = false), - rhs = List(), - ct = false - ), - body = Some(value = Block(stmts = List(IntLit(value = 2)))) - ) - ) - ) - ), - Match( - lhs = Match( - lhs = IntLit(value = 1), - rhs = CaseBlock( - stmts = List( - Case( - cond = Ident(name = "a"), - body = Some(value = Block(stmts = List(IntLit(value = 2)))) - ) - ) - ) - ), - rhs = CaseBlock( - stmts = List( - Case( - cond = Ident(name = "b"), - body = Some(value = Block(stmts = List(IntLit(value = 2)))) - ) - ) - ) - ), - As( - lhs = Match( - lhs = IntLit(value = 1), - rhs = CaseBlock( - stmts = List( - Case( - cond = Ident(name = "a"), - body = Some(value = Block(stmts = List(IntLit(value = 2)))) - ) - ) - ) - ), - rhs = Ident(name = "a") - ), - Match( - lhs = As(lhs = IntLit(value = 1), rhs = Ident(name = "a")), - rhs = CaseBlock( - stmts = List( - Case( - cond = Ident(name = "a"), - body = Some(value = Block(stmts = List(IntLit(value = 2)))) - ) - ) - ) - ), - Match( - lhs = As(lhs = IntLit(value = 1), rhs = Ident(name = "a")), - rhs = CaseBlock(stmts = List(Case(cond = Ident(name = "_"), body = None))) - ), - Match( - lhs = As(lhs = IntLit(value = 1), rhs = Ident(name = "a")), - rhs = CaseBlock(stmts = List(Case(cond = Ident(name = "_"), body = None))) - ), - Match( - lhs = As(lhs = IntLit(value = 1), rhs = Ident(name = "a")), - rhs = CaseBlock( - stmts = List( - Case(cond = Ident(name = "_"), body = Some(value = Ident(name = "a"))) - ) - ) - ), - Match( - lhs = As(lhs = IntLit(value = 1), rhs = Ident(name = "a")), - rhs = CaseBlock( - stmts = List( - Case(cond = Ident(name = "_"), body = Some(value = Ident(name = "a"))) - ) - ) ) ) ) diff --git a/packages/cosmo/snapshots/ParserTests/samples/Syntax/matchExpr.syntax.cos-ast b/packages/cosmo/snapshots/ParserTests/samples/Syntax/matchExpr.syntax.cos-ast new file mode 100644 index 0000000..1be4a4e --- /dev/null +++ b/packages/cosmo/snapshots/ParserTests/samples/Syntax/matchExpr.syntax.cos-ast @@ -0,0 +1,430 @@ +Some( + value = Block( + stmts = List( + Decorate( + lhs = Apply(lhs = Ident(name = "noCore"), rhs = List(), ct = false), + rhs = Semi(semi = None) + ), + Def( + name = Ident(name = "main"), + params = Some(value = List()), + ret = None, + rhs = Some( + value = Block( + stmts = List( + Match(lhs = Ident(name = "a"), rhs = Block(stmts = List())), + Match( + lhs = BinOp(op = "+", lhs = Ident(name = "a"), rhs = IntLit(value = 1)), + rhs = Block(stmts = List()) + ), + Match( + lhs = Select(lhs = Ident(name = "a"), rhs = Ident(name = "method"), ct = false), + rhs = Block(stmts = List()) + ), + Match( + lhs = Apply( + lhs = Select(lhs = Ident(name = "a"), rhs = Ident(name = "method"), ct = false), + rhs = List(), + ct = false + ), + rhs = Block(stmts = List()) + ), + Match( + lhs = BinOp(op = "*", lhs = Ident(name = "a"), rhs = IntLit(value = 1)), + rhs = Block(stmts = List()) + ), + BinOp( + op = "=", + lhs = Ident(name = "a"), + rhs = Match(lhs = IntLit(value = 1), rhs = Block(stmts = List())) + ), + BinOp( + op = "=", + lhs = Ident(name = "a"), + rhs = Match(lhs = Ident(name = "a"), rhs = Block(stmts = List())) + ), + Match( + lhs = IntLit(value = 1), + rhs = CaseBlock(stmts = List(Case(cond = IntLit(value = 1), body = None))) + ), + Match( + lhs = IntLit(value = 1), + rhs = CaseBlock( + stmts = List( + Case(cond = IntLit(value = 1), body = Some(value = IntLit(value = 2))) + ) + ) + ), + Match( + lhs = IntLit(value = 1), + rhs = CaseBlock( + stmts = List( + Case(cond = BoolLit(value = false), body = Some(value = IntLit(value = 2))) + ) + ) + ), + Match( + lhs = BinOp(op = "+", lhs = IntLit(value = 1), rhs = IntLit(value = 1)), + rhs = CaseBlock( + stmts = List( + Case( + cond = BinOp(op = "+", lhs = IntLit(value = 1), rhs = IntLit(value = 1)), + body = Some(value = IntLit(value = 2)) + ) + ) + ) + ), + Match( + lhs = BinOp(op = "+", lhs = IntLit(value = 1), rhs = IntLit(value = 1)), + rhs = CaseBlock( + stmts = List( + Case( + cond = BinOp( + op = "+", + lhs = BinOp(op = "*", lhs = IntLit(value = 1), rhs = IntLit(value = 1)), + rhs = IntLit(value = 1) + ), + body = Some(value = IntLit(value = 2)) + ) + ) + ) + ), + Match( + lhs = IntLit(value = 1), + rhs = CaseBlock( + stmts = List( + Case(cond = Ident(name = "a"), body = Some(value = IntLit(value = 2))) + ) + ) + ), + Match( + lhs = IntLit(value = 1), + rhs = CaseBlock( + stmts = List( + Case(cond = Ident(name = "a"), body = Some(value = IntLit(value = 2))) + ) + ) + ), + Match( + lhs = BinOp(op = "+", lhs = IntLit(value = 1), rhs = IntLit(value = 1)), + rhs = CaseBlock( + stmts = List( + Case( + cond = BinOp(op = "+", lhs = IntLit(value = 1), rhs = Ident(name = "a")), + body = Some(value = IntLit(value = 2)) + ) + ) + ) + ), + Match( + lhs = BinOp(op = "+", lhs = IntLit(value = 1), rhs = IntLit(value = 1)), + rhs = CaseBlock( + stmts = List( + Case( + cond = BinOp( + op = "+", + lhs = BinOp(op = "*", lhs = IntLit(value = 1), rhs = IntLit(value = 1)), + rhs = Ident(name = "a") + ), + body = Some(value = IntLit(value = 2)) + ) + ) + ) + ), + Match( + lhs = BinOp(op = "+", lhs = IntLit(value = 1), rhs = IntLit(value = 1)), + rhs = CaseBlock( + stmts = List( + Case( + cond = Ident(name = "a"), + body = Some(value = Block(stmts = List(IntLit(value = 2)))) + ) + ) + ) + ), + Match( + lhs = BinOp(op = "+", lhs = IntLit(value = 1), rhs = IntLit(value = 1)), + rhs = CaseBlock( + stmts = List( + Case( + cond = Apply( + lhs = Select(lhs = Ident(name = "A"), rhs = Ident(name = "B"), ct = false), + rhs = List(), + ct = false + ), + body = Some(value = Block(stmts = List(IntLit(value = 2)))) + ) + ) + ) + ), + Match( + lhs = BinOp(op = "+", lhs = IntLit(value = 1), rhs = IntLit(value = 1)), + rhs = CaseBlock( + stmts = List( + Case( + cond = Apply( + lhs = Select(lhs = Ident(name = "A"), rhs = Ident(name = "B"), ct = false), + rhs = List(), + ct = false + ), + body = Some(value = Block(stmts = List(IntLit(value = 2)))) + ) + ) + ) + ), + Match( + lhs = Match( + lhs = IntLit(value = 1), + rhs = CaseBlock( + stmts = List( + Case( + cond = Ident(name = "a"), + body = Some(value = Block(stmts = List(IntLit(value = 2)))) + ) + ) + ) + ), + rhs = CaseBlock( + stmts = List( + Case( + cond = Ident(name = "b"), + body = Some(value = Block(stmts = List(IntLit(value = 2)))) + ) + ) + ) + ), + As( + lhs = Match( + lhs = IntLit(value = 1), + rhs = CaseBlock( + stmts = List( + Case( + cond = Ident(name = "a"), + body = Some(value = Block(stmts = List(IntLit(value = 2)))) + ) + ) + ) + ), + rhs = Ident(name = "a") + ), + Match( + lhs = As(lhs = IntLit(value = 1), rhs = Ident(name = "a")), + rhs = CaseBlock( + stmts = List( + Case( + cond = Ident(name = "a"), + body = Some(value = Block(stmts = List(IntLit(value = 2)))) + ) + ) + ) + ), + Match( + lhs = As(lhs = IntLit(value = 1), rhs = Ident(name = "a")), + rhs = CaseBlock(stmts = List(Case(cond = Ident(name = "_"), body = None))) + ), + Match( + lhs = As(lhs = IntLit(value = 1), rhs = Ident(name = "a")), + rhs = CaseBlock(stmts = List(Case(cond = Ident(name = "_"), body = None))) + ), + Match( + lhs = As(lhs = IntLit(value = 1), rhs = Ident(name = "a")), + rhs = CaseBlock( + stmts = List( + Case(cond = Ident(name = "_"), body = Some(value = Ident(name = "a"))) + ) + ) + ), + Match( + lhs = As(lhs = IntLit(value = 1), rhs = Ident(name = "a")), + rhs = CaseBlock( + stmts = List( + Case(cond = Ident(name = "_"), body = Some(value = Ident(name = "a"))) + ) + ) + ), + Block( + stmts = List( + Match( + lhs = IntLit(value = 1), + rhs = CaseBlock( + stmts = List( + Case(cond = Ident(name = "a"), body = Some(value = Ident(name = "a"))) + ) + ) + ) + ) + ), + Block( + stmts = List( + Val( + name = Ident(name = "a"), + ty = None, + init = Some(value = Semi(semi = Some(value = IntLit(value = 1)))) + ), + Match( + lhs = IntLit(value = 1), + rhs = CaseBlock( + stmts = List( + Case(cond = Ident(name = "a"), body = Some(value = Ident(name = "a"))) + ) + ) + ) + ) + ), + Block( + stmts = List( + Val( + name = Ident(name = "a"), + ty = None, + init = Some(value = Semi(semi = Some(value = IntLit(value = 1)))) + ), + Match( + lhs = IntLit(value = 1), + rhs = CaseBlock( + stmts = List( + Case( + cond = Select( + lhs = Ident(name = "a"), + rhs = Ident(name = "b"), + ct = false + ), + body = Some(value = Ident(name = "a")) + ) + ) + ) + ) + ) + ), + Block( + stmts = List( + Match( + lhs = IntLit(value = 1), + rhs = CaseBlock( + stmts = List( + Case( + cond = Apply( + lhs = Select( + lhs = Ident(name = "a"), + rhs = Ident(name = "b"), + ct = false + ), + rhs = List(Ident(name = "a")), + ct = false + ), + body = Some(value = Ident(name = "a")) + ) + ) + ) + ) + ) + ), + Block( + stmts = List( + Val( + name = Ident(name = "a"), + ty = None, + init = Some(value = Semi(semi = Some(value = IntLit(value = 1)))) + ), + Match( + lhs = IntLit(value = 1), + rhs = CaseBlock( + stmts = List( + Case( + cond = Apply( + lhs = Select( + lhs = Ident(name = "a"), + rhs = Ident(name = "b"), + ct = false + ), + rhs = List(Ident(name = "a")), + ct = false + ), + body = Some(value = Ident(name = "a")) + ) + ) + ) + ) + ) + ), + Block( + stmts = List( + Match( + lhs = IntLit(value = 1), + rhs = CaseBlock(stmts = List(Case(cond = Ident(name = "_"), body = None))) + ) + ) + ), + Block( + stmts = List( + Match( + lhs = IntLit(value = 1), + rhs = CaseBlock( + stmts = List( + Case(cond = Ident(name = "_"), body = Some(value = Ident(name = "_"))) + ) + ) + ) + ) + ), + Block( + stmts = List( + Match( + lhs = IntLit(value = 1), + rhs = CaseBlock( + stmts = List( + Case( + cond = Apply( + lhs = Select( + lhs = Ident(name = "a"), + rhs = Ident(name = "b"), + ct = false + ), + rhs = List(KeyedArg(key = Ident(name = "b"), value = Ident(name = "a"))), + ct = false + ), + body = Some( + value = ArgsLit(values = List(Ident(name = "a"), Ident(name = "b"))) + ) + ) + ) + ) + ) + ) + ), + Block( + stmts = List( + Val( + name = Ident(name = "a"), + ty = None, + init = Some(value = Semi(semi = Some(value = IntLit(value = 1)))) + ), + Match( + lhs = IntLit(value = 1), + rhs = CaseBlock( + stmts = List( + Case( + cond = Apply( + lhs = Select( + lhs = Ident(name = "a"), + rhs = Ident(name = "b"), + ct = false + ), + rhs = List(KeyedArg(key = Ident(name = "b"), value = Ident(name = "a"))), + ct = false + ), + body = Some( + value = ArgsLit(values = List(Ident(name = "a"), Ident(name = "b"))) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) +) \ No newline at end of file diff --git a/packages/cosmo/src/main/scala/cosmo/CodeGen.scala b/packages/cosmo/src/main/scala/cosmo/CodeGen.scala index 44604c2..996900b 100644 --- a/packages/cosmo/src/main/scala/cosmo/CodeGen.scala +++ b/packages/cosmo/src/main/scala/cosmo/CodeGen.scala @@ -30,8 +30,8 @@ class CodeGen(implicit val env: Env) { def mayGenDef(ast: ir.Item, tl: Boolean): Option[String] = { implicit val topLevel = tl; val info = ast match { - case ir.Var(info, _, _, _) => Some(info) - case ir.Fn(info, _, _) => Some(info) + case ir.Var(info, _, _) => Some(info) + case ir.Fn(info, _, _) => Some(info) case ir.Class(info, _, _, _, _, _, _, _) => Some(info) case ir.Impl(info, _, _, _, _) => Some(info) @@ -41,8 +41,7 @@ class CodeGen(implicit val env: Env) { val nsb = if inClass then "" else nsb_ val nse = if inClass then "" else nse_ val res: String = ast match { - case ir.NoneItem => "" - case ir.Semi(value) => return mayGenDef(value, tl) + case ir.NoneItem => "" case Fn(defInfo, Sig(params, retTy, body), level) if level > 0 => val name = defInfo.defName(stem = true) val templateCode = dependentParams(params); @@ -273,29 +272,29 @@ class CodeGen(implicit val env: Env) { ) def genVarParam(node: ir.Var) = { - val ir.Var(defInfo, init, isContant, _) = node - val name = defInfo.nameStem(defInfo.id.id) - val ty = paramTy(defInfo.instantiateTy) - var constantStr = if isContant then "const " else "" + val ir.Var(info, init, _) = node + val name = info.nameStem(info.id.id) + val ty = paramTy(info.instantiateTy) + var constantStr = if info.isMut then "" else "const " s"${constantStr}${ty} ${name}_p" } def genVarCons(node: ir.Var) = { - val ir.Var(defInfo, init, isContant, _) = node - val name = defInfo.nameStem(defInfo.id.id) - val ty = defInfo.instantiateTy + val ir.Var(info, init, _) = node + val name = info.nameStem(info.id.id) + val ty = info.instantiateTy val p = s"std::move(${name}_p)" if ty == SelfTy then s"$name(std::move(std::make_unique($p)))" else s"$name($p)" } def genVarStore(node: ir.Var) = { - val ir.Var(defInfo, init, isContant, _) = node - val name = defInfo.nameStem(defInfo.id.id) - val ty = storeTy(defInfo.instantiateTy) - var constantStr = if isContant then "const " else "" + val ir.Var(info, init, _) = node + val name = info.nameStem(info.id.id) + val ty = storeTy(info.instantiateTy) + var constantStr = if info.isMut then "" else "const " val kInit = - if (defInfo.inClass) then + if (info.inClass) then val initStr = init match { case Some(value) => s"${expr(value)}" case None => "{}" @@ -304,7 +303,7 @@ class CodeGen(implicit val env: Env) { else "" val initStr = if (init.isEmpty) then "" - else if (defInfo.inClass) then s" = k${name.capitalize}Default" + else if (info.inClass) then s" = k${name.capitalize}Default" else s" = ${expr(init.getOrElse(NoneItem))}" s"$kInit$constantStr$ty $name$initStr" } @@ -337,7 +336,7 @@ class CodeGen(implicit val env: Env) { // todo: analysis it concretely def mayClone(v: ir.VarField, value: String): String = { v.item match { - case ir.Var(info, _, _, _) => + case ir.Var(info, _, _) => if (info.instantiateTy == SelfTy) { // todo: detect rvalue correctly if (value.endsWith(")")) { @@ -447,7 +446,7 @@ class CodeGen(implicit val env: Env) { List(lhs), recv, ) - case ir.IApply(BoundField(lhs, impl: Impl, true, field), rhs) => + case ir.Apply(BoundField(lhs, impl: Impl, true, field), rhs) => val iface = storeTy(impl.iface) val cls = storeTy(impl.cls) val lhsIsMut = lhs match { @@ -458,19 +457,19 @@ class CodeGen(implicit val env: Env) { val castedOp = if lhsIsType(lhs) then s"$casted::" else s"$casted(${expr(lhs)})." return literalCall(s"$castedOp${field.item.id.name}", rhs, recv) - case ir.IApply(BoundField(lhs, _: Class, true, field), rhs) => + case ir.Apply(BoundField(lhs, _: Class, true, field), rhs) => return literalCall( s"${dispatchOp(lhs, field, true)}${field.item.id.name}", rhs, recv, ) - case ir.IApply(BoundField(lhs, by, false, field), rhs) => + case ir.Apply(BoundField(lhs, by, false, field), rhs) => return literalCall( s"${dispatchOp(lhs, field, genInImpl)}${field.item.id.name}", rhs, recv, ) - case ir.IApply(lhs, rhs) => return literalCall(expr(lhs), rhs, recv) + case ir.Apply(lhs, rhs) => return literalCall(expr(lhs), rhs, recv) case BoundField(lhs, by, false, field) => s"${dispatchOp(lhs, field, genInImpl)}${field.item.id.name}" case ir.Select(SelfVal, rhs) => rhs @@ -496,7 +495,6 @@ class CodeGen(implicit val env: Env) { s"${solveDict(items)}{${items .map { case (k, v) => s"""{"$k", ${expr(v)}}""" } .mkString(", ")}}" - case ir.Semi(value) => return exprWith(value, ValRecv.None) case v: ir.CIdent => storeTy(v) case v: ir.CppInsType => storeTy(v) case v: ir.Var => v.id.defName(stem = false) diff --git a/packages/cosmo/src/main/scala/cosmo/Doc.scala b/packages/cosmo/src/main/scala/cosmo/Doc.scala index 0799185..9e015c3 100644 --- a/packages/cosmo/src/main/scala/cosmo/Doc.scala +++ b/packages/cosmo/src/main/scala/cosmo/Doc.scala @@ -11,7 +11,7 @@ enum Doc { case Concat(is: Array[Doc], sep: Doc = Doc.empty) case Region(name: String, Attrs: Option[Doc], children: Doc) - def pretty: String = { + def pretty(implicit showDef: Boolean = false): String = { var sb = new StringBuilder Doc.prettyImpl(sb, this); sb.toString @@ -32,7 +32,9 @@ object Doc { val rbrace = Doc.Str("}") val smallIndents = (0 to 30).map { " " * _ }.toArray - private def prettyImpl(sb: StringBuilder, doc: Doc): Unit = { + private def prettyImpl(sb: StringBuilder, doc: Doc)(implicit + showDef: Boolean = false, + ): Unit = { val stack = collection.mutable.Stack[(Int, Doc)]() stack.push((0, doc)) while (stack.nonEmpty) { @@ -43,6 +45,8 @@ object Doc { sb.append(smallIndents(indent)) case Doc.Str(v) => sb.append(v) + case Doc.Item(v: ir.Name) if showDef => + sb.append(s"<$v is ${v.of.getOrElse("!")}>") case Doc.Item(v) => sb.append(v.toString()) case Doc.Indent(i, d) => @@ -90,13 +94,14 @@ object Doc { ret_ty: Option[ir.Type], body: Option[ir.Item], ): Doc = { + val n = s"${pe.id.name}@${pe.id.id.id}" val p = pe.params.map(_.d(", ".d)).getOrElse(empty) val cs = if pe.constraints.isEmpty then empty else Array(" where [".d, pe.constraints.d(", ".d), "]".d).d val r = ret_ty.d.getOrElse("_".d) val b = body.d.getOrElse("_".d) - Array(kind.d, pe.id.name.d, Doc.paren(p), ": ".d, r, cs, " = ".d, b).d + Array(kind.d, n.d, Doc.paren(p), ": ".d, r, cs, " = ".d, b).d } def buildItem(item: ir.Item): Doc = item match { case b: ir.Region => Doc.block("block", b.stmts.d(NewLine)) @@ -113,14 +118,18 @@ object Doc { val p = impl.params.map(_.d(", ".d)).getOrElse(empty) Array("impl".d, Doc.paren(p), " ".d, i, cls, " = ".d, impl.body.d).d case i: ir.VarExpr => + val n = s"${i.id.name}@${i.id.id.id}" val mod = if i.id.isTypeVar then "type " else if i.id.isMut then "var " else "val " val r = i.ty.d.getOrElse("_".d) val b = i.init.d.getOrElse("_".d) - Array(mod.d, i.id.name.d, ": ".d, r, " = ".d, b).d - case i: ir.ApplyExpr => Array(i.lhs.d, Doc.paren(i.rhs.d(", ".d))).d + Array(mod.d, n.d, ": ".d, r, " = ".d, b).d + case i: ir.Hole => + val n = s"${i.id.name}@${i.id.id.id}" + Array("hole ".d, n.d).d + case i: ir.Apply => Array(i.lhs.d, Doc.paren(i.rhs.d(", ".d))).d case i: ir.Name => Doc.item(i) case ir.ItemE(item) => item.d case ir.TupleLit(items) => Doc.paren(items.d(", ".d)) @@ -150,8 +159,8 @@ object Doc { case ir.If(cond, thenp, elsep) => val el = elsep.d.map { e => Array(" else ".d, e).d }.getOrElse(empty) Array("if (".d, cond.d, ") ".d, thenp.d, el).d - case ir.MatchExpr(cond, cases) => - val cs = cases.map { c => + case ir.MatchExpr(cond, cb) => + val cs = cb.cases.map { c => Array("case (".d, c._1.d, ") => ".d, c._2.d.getOrElse("_".d)).d } val body = (") {".d +: cs).d(NewLine) diff --git a/packages/cosmo/src/main/scala/cosmo/Eval.scala b/packages/cosmo/src/main/scala/cosmo/Eval.scala index 04dd2db..f18646b 100644 --- a/packages/cosmo/src/main/scala/cosmo/Eval.scala +++ b/packages/cosmo/src/main/scala/cosmo/Eval.scala @@ -8,8 +8,8 @@ import cosmo.syntax.CaseBlock import cosmo.syntax.FloatLit import scala.annotation.tailrec -type SParam = syntax.Param; -type SParams = List[SParam]; +type EParam = VarExpr; +type EParams = List[EParam]; final class DefId(val id: Int) extends AnyVal {} @@ -145,16 +145,19 @@ class Env(val fid: Option[FileId], val pacMgr: cosmo.PackageManager) { def entry(ast: syntax.Block): Env = { stgE.module = stgE.expr(ast) - // if (!noCore) then importNative(libPath("std.prelude"), Some(Ident("_"))) - // val m = term(stgE.module)(0) - // if !m.isInstanceOf[Region] then err("module must be a block") - // module = m.asInstanceOf[Region] + if (!noCore) then importNative(libPath("std.prelude"), Some(Ident("_"))) + val m = term(stgE.module)(0) + if !m.isInstanceOf[Region] then err("module must be a block") + module = m.asInstanceOf[Region] this } /// Item Creation + def err(msg: String): Item = + errors = errors :+ msg; return NoneItem + /// Creates Def def ct(src: syntax.Ident | String, hidden: Boolean = false): DefInfo = { val (name, pos) = extractSrc(src) @@ -173,165 +176,61 @@ class Env(val fid: Option[FileId], val pacMgr: cosmo.PackageManager) { /// Creates Infer Variable def createInfer(info: DefInfo, lvl: Int) = InferVar(info, level = lvl) - def err(msg: String): Item = - errors = errors :+ msg; return NoneItem - - def resolveParams(params: Option[SParams]) = params.map { params => - params.map { p => - val info = scopes.get(p.name.name).get; - // todo: compute canonical type - Param(info, (info.ty.level - 1).max(0)) - } - } - - def byName(name: String)(implicit level: Int) = scopes.get(name) match { - case Some(id) => byRef(id) - case None => - errors = s"Undefined variable $name in $fid" :: errors; - Unresolved(ct(name)) - } - + /// Creates Reference def byRef(info: DefInfo)(implicit level: Int): Item = { val v = items.get(info.id).map(deref) debugln(s"byRef $info ${v.map(_.level)}") v match { - case Some(v: ir.Term) => v - case _ => - Term(info, v.map(_.level).getOrElse(level), value = v) + case Some(v: Term) => v + case _ => Term(info, v.map(_.level).getOrElse(level), value = v) } } - def newDefWithInfoOr(name: Ident | String, id: Option[DefInfo]) = { - id.foreach(scopes.set(xId(name), _)) - id.getOrElse(ct(name)) - } - - def paramsOr(classSelf: Option[Item], params: Option[SParams]) = { - classSelf match { - case Some(cls: ir.Class) => cls.params.map(Right(_)) - case _ => params.map(Left(_)) + def valueTermO(node: Option[Item])(implicit level: Int = 0): Item = + node.map(valueTerm).getOrElse(NoneItem) + def valueTerm(node: Item)(implicit level: Int = 0): Item = term(node) + def typeTerm(node: Item)(implicit level: Int = 1): Type = term(node) + def term(item: Item)(implicit level: Int): ir.Item = { + if !item.isInstanceOf[Expr] then return item + item.asInstanceOf[Expr] match { + // control flow, todo: duplicate patterns + case item: (Break | Continue | Opaque) => item + case Return(v) => Return(term(v)) + case If(cond, x, y) => If(term(cond), term(x), y.map(term)) + case Loop(body) => Loop(term(body)) + case While(cond, body) => While(term(cond), term(body)) + case For(name, iter, body) => For(name, term(iter), term(body)) + case Region(stmts) => Region(stmts.map(term)) + // operations + case Name(id, of) => of.map(term).getOrElse(Unresolved(id)) + case UnOp("&", UnOp("mut", lhs)) => RefItem(term(lhs), true) + case UnOp("&", lhs) => RefItem(term(lhs), false) + case UnOp("mut", lhs) => + errors = s"mut must be used after &" :: errors; term(lhs) + case UnOp("*", lhs) => derefPtr(lhs) + case UnOp(op, lhs) => UnOp(op, term(lhs)) + case BinOp(op, lhs, rhs) => binOp(op, term(lhs), term(rhs)) + case As(lhs, rhs) => As(term(lhs), typeTerm(rhs)) + case KeyedArg(k, v) => KeyedArg(term(k), term(v)) + // todo: check is compile time + case SelectExpr(lhs, rhs) => deref(select(term(lhs), rhs)) + case Apply(lhs, rhs) => $apply(term(lhs), rhs.map(term)) + case b: MatchExpr => matchExpr(b) + case ItemE(item) => term(item) + // declarations + case VarExpr(id, ty, init) => varItem(id, ty, init) + case d: DefExpr => defItem(d) + case c: ClassExpr => classItem(c, Some(classItem(c, None))) + case i: ImplExpr => implItem(i) + case Hole(id) => err(s"hole $id in the air") + case id: ParamExpr => err(s"param $id in the air") + case cr: CaseRegion => err(s"case region $cr in the air") } } - def withNs[T](mayNs: Option[DefInfo], ast: syntax.Node)(f: => T): T = { - val cr = currentRegion - currentRegion = (ast.offset, ast.end) - if mayNs.isEmpty then { - val cd = currentDef - currentDef = None - val result = f - currentRegion = cr - currentDef = cd - return result - } - val ns = mayNs.get - val cd = currentDef - currentDef = Some(ns.id) - this.ns = ns.name :: this.ns - val result = f - this.ns = this.ns.tail - currentDef = cd - currentRegion = cr - result - } + def expr(ast: syntax.Node)(implicit level: Int): ir.Item = ??? - def withNsParams[T]( - ns: Option[DefInfo], - reg: syntax.Node, - params: Option[Either[SParams, List[Param]]], - )( - f: => T, - ): T = { - debugln(s"withNsParams $ns $params") - withNs(ns, reg) { - scopes.withScope { - params.foreach { - case Right(params) => - params.iterator.foreach { case Param(info, _) => - scopes.set(info.name, info) - } - case Left(params) => - params.iterator.foreach { case SParam(name, ty, init, _) => - varItem(ct(name), ty, init.map(valueExpr), true)(0) - } - } - f - } - } - } - - def term(ast: Expr)(implicit level: Int): ir.Item = { - ast - } - - def valueExprO(node: Option[syntax.Node])(implicit level: Int = 0): Item = - node.map(valueExpr).getOrElse(NoneItem) - def valueExpr(node: syntax.Node)(implicit level: Int = 0): Item = expr(node) - def typeExpr(node: syntax.Node)(implicit level: Int = 1): Type = expr(node) - def expr(ast: syntax.Node)(implicit level: Int): ir.Item = { - // ast match { - // // literals - // case syntax.TodoLit => TodoLit - // case syntax.BoolLit(value) => Bool(value) - // case syntax.IntLit(value) => - // if (value.isValidInt) Integer(value.toInt) - // else Opaque.expr(value.toString) - // case syntax.FloatLit(value) => Opaque.expr(value.toString) - // case syntax.StringLit(value) => Str(value) - // case syntax.Ident("self") => SelfVal - // case syntax.Ident("Self") => SelfTy - // case syntax.Ident(name) => byName(name) - // case syntax.ArgsLit(values) => argsLit(values) - // // control flow - // case b: syntax.Block => block(b) - // case l: syntax.Loop => Loop(expr(l.body)) - // case w: syntax.While => While(expr(w.cond), expr(w.body)) - // case f: syntax.For => For(f.name, expr(f.iter), expr(f.body)) - // case syntax.Break() => Break() - // case syntax.Continue() => Continue() - // case syntax.Return(value) => Return(expr(value)) - // case syntax.If(cond, x, y) => If(expr(cond), expr(x), y.map(expr)) - // // operations - // case syntax.UnOp("&", syntax.UnOp("mut", lhs)) => RefItem(expr(lhs), true) - // case syntax.UnOp("&", lhs) => RefItem(expr(lhs), false) - // case syntax.UnOp("mut", lhs) => - // errors = s"mut must be used after &" :: errors; expr(lhs) - // case syntax.UnOp("*", lhs) => derefPtr(lhs) - // case syntax.UnOp(op, lhs) => UnOp(op, expr(lhs)) - // case syntax.BinOp(op, lhs, rhs) => binOp(op, expr(lhs), expr(rhs)) - // case syntax.As(lhs, rhs) => As(expr(lhs), typeExpr(rhs)) - // case syntax.KeyedArg(k, v) => KeyedArg(castKey(k), expr(v)) - // // todo: check is compile time - // case syntax.Select(lhs, rhs, _) => deref(select(expr(lhs), rhs.name)) - // case b: syntax.Match => matchExpr(b) - // case syntax.Apply(lhs, rhs) => $apply(expr(lhs), rhs.map(expr)) - // // todo: decorator - // case syntax.Decorate(syntax.Apply(Ident("noCore"), _), _) => - // noCore = true - // NoneItem - // case syntax.Decorate(lhs, rhs) => expr(rhs) - // // declarations - // case syntax.Import(p, dest) => $import(p, dest) - // case syntax.Val(x, ty, y) => varItem(ct(x), ty, y.map(expr), true) - // case syntax.Typ(x, ty, y) => varItem(ct(x), ty, y.map(typeExpr), true) - // case syntax.Var(x, ty, y) => varItem(ct(x), ty, y.map(expr), false) - // case d: syntax.Def => defItem(d, ct(d.name)) - // case c: syntax.Class => classItem(c, Some(classItem(c, None))) - // case d: syntax.Impl => implItem(d) - // } - ??? - } - - /// Literals - - def castKey(key: syntax.Node)(implicit level: Int): String = key match { - case syntax.Ident(name) => name - case syntax.StrLit(s) => s - case _ => { - errors = s"Invalid key" :: errors; - "" - } - } + /// imports def $import(p: syntax.Node, dest: Option[syntax.Node]): Item = { val path = p match { @@ -396,161 +295,10 @@ class Env(val fid: Option[FileId], val pacMgr: cosmo.PackageManager) { /// Expressions - case class MatchCaseInfo( - destructor: syntax.Node, - body: Option[syntax.Node], - pattern: Item, - ); - - case class MatchInfo( - lhs: Item, - cases: List[MatchCaseInfo], - defaultCase: Option[Item], - ); - - def matchExpr(b: syntax.Match)(implicit level: Int): Item = { - var lhs = expr(b.lhs) - var lhsTy = tyOf(lhs) match - case None => return err("cannot match a untyped value") - case Some(ty) => ty; - - debugln(s"matchExpr $lhs ($lhsTy) on ${b.rhs}") - val sCases = b.rhs match { - case b: syntax.CaseBlock => b.stmts - case b: syntax.Block if (b.stmts.isEmpty) => List() - case b: syntax.Block => return err("match body contains non-case items") - case _ => return err("match body must be a case block") - } - - // Calculate the kind of match. - var defaultCase: Option[Item] = None - var matchCases: List[MatchCaseInfo] = List() - - val (patterns, restTy) = - sCases.foldLeft((List[(Item, Item)](), curryView(lhsTy))) { - case ((patterns, lhs), syntax.Case(destructor, body)) => - val (pattern, rests) = destruct(lhs, destructor, valueExprO(body)) - (patterns :+ pattern, rests) - } - - checkedDestructed(restTy) - ValueMatch(lhs, lhsTy, patterns, Some(Unreachable)) - } - - def destruct(lhs: DestructShape, by: syntax.Node, cont: => Item)(implicit - level: Int, - ): ((Item, Item), DestructShape) = { - - // for (syntax.Case(destructor, body) <- sCases) { - // destructor match { - // case Ident("_") => - // defaultCase match { - // case Some(_) => - // errors = s"multiple default cases" :: errors - // case None => - // defaultCase = valueExprO(body) - // } - // case _ => - // val casePattern = destruct(lhs, destructor); - // matchCases = - // matchCases :+ MatchCaseInfo(destructor, body, casePattern) - // } - // } - val (name, args) = by match { - // Consider destructing cases. - case name: (syntax.Ident | syntax.Select) => (name, None) - // TODO: nested apply matching - case syntax.Apply(name, rhs, _) => (name, Some(rhs)) - // Matching by value, just return the value. - case _ => return ((expr(by), cont), lhs) - } - val variant = enumShape(expr(name)) match { - case Some(v) => v - case None if args.isEmpty => - // Must be resolved ident/select, also use matching by value. - // TODO: Better fuse the check with the lines above. - return ((expr(by), cont), lhs) - case None => - err(s"Invalid enum variant $name"); return ((expr(by), cont), lhs) - } - // val binding = args.iterator.flatten.map { - // case syntax.Ident(name) => name - // case _ => "" - // } - // EnumDestruct(lhs, variant, binding.toList, None) - ??? - - // If any of matchCases is a EnumDestruct, ... - - // val isValueMatch = matchCases.headOption match { - // case None => ??? - // case Some(MatchCaseInfo(_, _, _: EnumDestruct)) => false - // case _ => true - // } - - // var vMappings = - // Map[String, List[(EnumDestruct, Option[syntax.Node])]]() - - // matchCases.foreach { - // case MatchCaseInfo(destructor, body, ed: EnumDestruct) => - // // todo: stable toString - // val variantBase = ed.variant.variantOf.get - // val vs = storeTy(variantBase) - // vMappings.get(vs) match { - // case Some(lst) => - // vMappings = vMappings + (vs -> (lst :+ (ed, body))) - // case None => - // vMappings = vMappings + (vs -> List((ed, body))) - // } - // // Check if the value matches. - // case _ => - // errors = s"not implemented mixed enum match" :: errors - // } - - // // assert that there is only one match - // if (vMappings.size != 1) { - // errors = s"not implemented mixed enum match" :: errors - // return NoneItem - // } - - // val (_, cases) = vMappings.head - // val ty = cases.head._1.variant.variantOf.get - - // debugln(s"matchExpr mappings default $defaultCase") - // debugln(s"matchExpr mappings $ty => $cases") - - // var matchBody = List[(Class, Item)]() - // for ((ed, body) <- cases) { - // val variant = ed.variant - // val bindings = ed.bindings - - // val stmts = body.map(body => - // scopes.withScope { - // // bindings - // variant.vars.zip(bindings).map { (vv, name) => - // val defInfo = ct(name); defInfo.isVar = true - // defInfo.ty = vv.item.id.ty - // val ty: Type = defInfo.ty - // val tyLvl = ty.level - // val valLvl = (tyLvl - 1).max(0) - // val res = Term(defInfo, valLvl) - // items += (defInfo.id -> res) - // } - // List(EnumDestruct(lhs, variant, bindings, None)) :+ valueExpr(body) - // }, - // ); - // matchBody = matchBody :+ (variant, Region(stmts.getOrElse(List()))) - // } - - // val defaultCaseItem = defaultCase.getOrElse(Unreachable) - // TypeMatch(lhs, ty, matchBody, defaultCaseItem) - - } - - def derefPtr(lhs: syntax.Node)(implicit level: Int): Item = { + def derefPtr(lhs: Item)(implicit level: Int): Item = { lhs match { - case Ident("self") => SelfVal - case lhs => UnOp("*", expr(lhs).e) + case SelfVal => SelfVal + case lhs => UnOp("*", term(lhs)) } } @@ -677,22 +425,22 @@ class Env(val fid: Option[FileId], val pacMgr: cosmo.PackageManager) { case BoundField(_, by, _, TypeField(ev: EnumVariant)) => $apply(ev.base.copy(variantOf = Some(by)), rhs) case BoundField(that, by, _, DefField(f)) => - IApply(lhs.e, castArgs(f.sig.params, rhs, Some(Right(that)))) + Apply(lhs.e, castArgs(f.sig.params, rhs, Some(Right(that)))) case HKTInstance(ty, syntax) => val res = hktTranspose(syntax, $apply(ty, rhs)) if (res.level == 0) { res } else { - HKTInstance(res, IApply(syntax, rhs)) + HKTInstance(res, Apply(syntax, rhs)) } - case _ => IApply(lhs, rhs) + case _ => Apply(lhs, rhs) } } def applyF(fn: Sig, info: Option[Fn], args: List[Item]): Item = { val Sig(params, ret_ty, body) = fn if (ret_ty.map(_.level).getOrElse(0) <= 1) { - return IApply(info.getOrElse(fn), castArgs(fn.params, args)); + return Apply(info.getOrElse(fn), castArgs(fn.params, args)); } implicit val level = 1; @@ -725,15 +473,168 @@ class Env(val fid: Option[FileId], val pacMgr: cosmo.PackageManager) { }; } + case class MatchCaseInfo( + destructor: syntax.Node, + body: Option[syntax.Node], + pattern: Item, + ); + + case class MatchInfo( + lhs: Item, + cases: List[MatchCaseInfo], + defaultCase: Option[Item], + ); + + def matchExpr(b: MatchExpr)(implicit level: Int): Item = { + // var lhs = expr(b.lhs) + // var lhsTy = tyOf(lhs) match + // case None => return err("cannot match a untyped value") + // case Some(ty) => ty; + + // debugln(s"matchExpr $lhs ($lhsTy) on ${b.rhs}") + // val sCases = b.rhs match { + // case b: syntax.CaseBlock => b.stmts + // case b: syntax.Block if (b.stmts.isEmpty) => List() + // case b: syntax.Block => return err("match body contains non-case items") + // case _ => return err("match body must be a case block") + // } + + // // Calculate the kind of match. + // var defaultCase: Option[Item] = None + // var matchCases: List[MatchCaseInfo] = List() + + // val (patterns, restTy) = + // sCases.foldLeft((List[(Item, Item)](), curryView(lhsTy))) { + // case ((patterns, lhs), syntax.Case(destructor, body)) => + // val (pattern, rests) = destruct(lhs, destructor, valueTermO(body)) + // (patterns :+ pattern, rests) + // } + + // checkedDestructed(restTy) + // ValueMatch(lhs, lhsTy, patterns, Some(Unreachable)) + ??? + } + + def destruct(lhs: DestructShape, by: syntax.Node, cont: => Item)(implicit + level: Int, + ): ((Item, Item), DestructShape) = { + + // for (syntax.Case(destructor, body) <- sCases) { + // destructor match { + // case Ident("_") => + // defaultCase match { + // case Some(_) => + // errors = s"multiple default cases" :: errors + // case None => + // defaultCase = valueTermO(body) + // } + // case _ => + // val casePattern = destruct(lhs, destructor); + // matchCases = + // matchCases :+ MatchCaseInfo(destructor, body, casePattern) + // } + // } + val (name, args) = by match { + // Consider destructing cases. + case name: (syntax.Ident | syntax.Select) => (name, None) + // TODO: nested apply matching + case syntax.Apply(name, rhs, _) => (name, Some(rhs)) + // Matching by value, just return the value. + case _ => return ((expr(by), cont), lhs) + } + val variant = enumShape(expr(name)) match { + case Some(v) => v + case None if args.isEmpty => + // Must be resolved ident/select, also use matching by value. + // TODO: Better fuse the check with the lines above. + return ((expr(by), cont), lhs) + case None => + err(s"Invalid enum variant $name"); return ((expr(by), cont), lhs) + } + // val binding = args.iterator.flatten.map { + // case syntax.Ident(name) => name + // case _ => "" + // } + // EnumDestruct(lhs, variant, binding.toList, None) + ??? + + // If any of matchCases is a EnumDestruct, ... + + // val isValueMatch = matchCases.headOption match { + // case None => ??? + // case Some(MatchCaseInfo(_, _, _: EnumDestruct)) => false + // case _ => true + // } + + // var vMappings = + // Map[String, List[(EnumDestruct, Option[syntax.Node])]]() + + // matchCases.foreach { + // case MatchCaseInfo(destructor, body, ed: EnumDestruct) => + // // todo: stable toString + // val variantBase = ed.variant.variantOf.get + // val vs = storeTy(variantBase) + // vMappings.get(vs) match { + // case Some(lst) => + // vMappings = vMappings + (vs -> (lst :+ (ed, body))) + // case None => + // vMappings = vMappings + (vs -> List((ed, body))) + // } + // // Check if the value matches. + // case _ => + // errors = s"not implemented mixed enum match" :: errors + // } + + // // assert that there is only one match + // if (vMappings.size != 1) { + // errors = s"not implemented mixed enum match" :: errors + // return NoneItem + // } + + // val (_, cases) = vMappings.head + // val ty = cases.head._1.variant.variantOf.get + + // debugln(s"matchExpr mappings default $defaultCase") + // debugln(s"matchExpr mappings $ty => $cases") + + // var matchBody = List[(Class, Item)]() + // for ((ed, body) <- cases) { + // val variant = ed.variant + // val bindings = ed.bindings + + // val stmts = body.map(body => + // scopes.withScope { + // // bindings + // variant.vars.zip(bindings).map { (vv, name) => + // val defInfo = ct(name); defInfo.isVar = true + // defInfo.ty = vv.item.id.ty + // val ty: Type = defInfo.ty + // val tyLvl = ty.level + // val valLvl = (tyLvl - 1).max(0) + // val res = Term(defInfo, valLvl) + // items += (defInfo.id -> res) + // } + // List(EnumDestruct(lhs, variant, bindings, None)) :+ valueTerm(body) + // }, + // ); + // matchBody = matchBody :+ (variant, Region(stmts.getOrElse(List()))) + // } + + // val defaultCaseItem = defaultCase.getOrElse(Unreachable) + // TypeMatch(lhs, ty, matchBody, defaultCaseItem) + + } + + /// Declarations + def varItem( defInfo: DefInfo, - oty: Option[syntax.Node], + oty: Option[Item], initExprE: Option[Item], - isMut: Boolean, )(implicit level: Int): ir.Var = { defInfo.isVar = true; - val initExpr = initExprE.map(normalizeExpr) - val initTy = (oty.map(typeExpr), defInfo.name) match { + val initExpr = initExprE.map(normalize) + val initTy = (oty.map(typeTerm), defInfo.name) match { case (Some(ty), _) => Some(ty) case (None, "self") => Some(RefItem(SelfTy, false)) case _ => { @@ -747,65 +648,59 @@ class Env(val fid: Option[FileId], val pacMgr: cosmo.PackageManager) { } } val valLvl = (initTy.map(_.level).getOrElse(0) - 1).max(0) - val res = ir.Var(defInfo, initExpr, isMut, valLvl) - defInfo.isMut = isMut + val res = ir.Var(defInfo, initExpr, valLvl) defInfo.ty = initTy.getOrElse(createInfer(defInfo, valLvl + 1)) items += (defInfo.id -> initExpr.getOrElse(res)) items += (defInfo.id -> byRef(defInfo)) res } - def defItem(ast: syntax.Def, defInfo: DefInfo, withBody: Boolean = true) = { - debugln(s"defItem ${defInfo.name}") - val syntax.Def(name, params, ret_ty, rhs) = ast - val sig = withNsParams(None, ast, params.map(Left(_))) { - Sig( - resolveParams(params), - ret_ty.map(typeExpr), - None, - ) - } - val f = Fn(defInfo, sig, sig.resolveLevel) - items += (defInfo.id -> f) + def defItem(e: DefExpr, withBody: Boolean = true) = { + debugln(s"defItem ${e.id.name}") + val DefExpr(info, params, constraints, ret_ty, rhs) = e + val sig = Sig( + resolveParams(params), + ret_ty.map(typeTerm), + None, + ) + val f = Fn(info, sig, sig.resolveLevel) + items += (info.id -> f) if (withBody) { val annotated = sig.ret_ty - val body = withNsParams(None, ast, params.map(Left(_))) { - rhs.map(e => normalizeExpr(valueExpr(e))) - } + val body = rhs.map(e => normalize(valueTerm(e))) val bodyTy = body.flatMap(tyOf) - debugln(s"defItem $name, $bodyTy <: $annotated") + debugln(s"defItem $info, $bodyTy <: $annotated") // we have already checked annotated <: bodyTy when we are - // making valueExpr. + // making valueTerm. val sigRetTy = annotated.orElse(bodyTy) val sig2 = sig.copy(body = body, ret_ty = sigRetTy) val l2 = sig2.resolveLevel; - defInfo.isDependent = + info.isDependent = if l2 > 0 then body.map(isDependent).getOrElse(false) else false val f2 = f.copy(sig = sig2, level = l2) - items += (defInfo.id -> f2) + items += (info.id -> f2) f2 } else { f } } - def classItem(ast: syntax.Class, classSelf: Option[Class] = None): Class = { - val syntax.Class(name, params, body, isAbstract) = ast - val defInfo = newDefWithInfoOr(name, classSelf.map(_.id)) + def classItem(e: ClassExpr, classSelf: Option[Class] = None): Class = { + val ClassExpr(info, params, constraints, body, isAbstract) = e val ss = selfRef - val cls = withNsParams(Some(defInfo), ast, paramsOr(classSelf, params)) { + val cls = { classSelf.foreach(cls => selfRef = Some(cls)) val (vars, restFields) = body match - case _: syntax.CaseBlock if isAbstract => + case _: CaseRegion if isAbstract => errors = "Cannot have an enumerated trait" :: errors; (List(), List()) - case body: syntax.Block => + case body: Region => baseClass(body, classSelf.map(p => p.vars ::: p.restFields)) - case caseBlock: syntax.CaseBlock => - (List(), enumClass(caseBlock, defInfo, classSelf.map(_.restFields))) + case caseBlock: CaseRegion => + (List(), enumClass(caseBlock, info, classSelf.map(_.restFields))) case _ => val kind = if isAbstract then "trait" else "class" errors = s"Invalid $kind body" :: errors; (List(), List()) @@ -815,11 +710,11 @@ class Env(val fid: Option[FileId], val pacMgr: cosmo.PackageManager) { case _ => } } - Class(defInfo, resolveParams(params), None, vars, restFields, isAbstract) + Class(info, resolveParams(params), None, vars, restFields, isAbstract) } - defInfo.ty = cls + info.ty = cls selfRef = ss - items += (defInfo.id -> cls) + items += (info.id -> cls) // Check conflict var existings = Map[String, VField](); @@ -833,42 +728,28 @@ class Env(val fid: Option[FileId], val pacMgr: cosmo.PackageManager) { cls } - def baseClass(ast: syntax.Block, fields: Option[List[VField]]) = { + def baseClass(ast: Region, fields: Option[List[VField]]) = { val withBody = !fields.isEmpty var vars = List[VarField](); var rests = List[VField](); - val nn = (name: Ident | String) => { - // todo: high complexity - val oid = fields.iterator.flatten.map(_.item.id).find(x => x.name == name) - val info = ct(name); info.inClass = true; - oid.foreach { scopes.set(xId(name), _) } - oid.getOrElse(info) - } - - def classItem(item: syntax.Node) = item match { + ast.stmts.foreach { // todo: syntax.Typ - case syntax.Val(x, ty, y) => - vars = vars :+ VarField(varItem(nn(x), ty, y.map(valueExpr), false)(0)) - case syntax.Var(x, ty, y) => - vars = vars :+ VarField(varItem(nn(x), ty, y.map(valueExpr), true)(0)) - case d: syntax.Def => - rests = rests :+ DefField(defItem(d, nn(d.name), withBody = withBody)) + case VarExpr(x, ty, y) => + x.inClass = true; + vars = vars :+ VarField(varItem(x, ty, y.map(valueTerm))(0)) + case d: DefExpr => + d.id.inClass = true; + rests = rests :+ DefField(defItem(d, withBody = withBody)) case node => errors = s"Invalid class item $node" :: errors } - ast.stmts.foreach { - case syntax.Semi(None) => - case syntax.Semi(Some(stmt)) => classItem(stmt) - case stmt => classItem(stmt) - } - (vars, rests) } def enumClass( - ast: syntax.CaseBlock, + ast: CaseRegion, info: DefInfo, fields: Option[List[VField]], ) = { @@ -877,19 +758,19 @@ class Env(val fid: Option[FileId], val pacMgr: cosmo.PackageManager) { .map(_.item.asInstanceOf[EnumVariant]) var selfRestFields2 = fields.map(_.filter(!_.isInstanceOf[TypeField])) - val stmts: List[VField] = ast.stmts - .filter(!_.isWildcard) + val stmts: List[VField] = ast.cases + .filter(!_._1.isWildcard) .map(p => TypeField( enumVariant(p, info, info.name, classSelf = subs.nextOption()), ), ) - val restFields = ast.stmts - .find(_.isWildcard) - .map { case syntax.Case(_, body) => + val restFields = ast.cases + .find(_._1.isWildcard) + .map { case (_, body) => baseClass( // todo: as instance of Block - body.getOrElse(syntax.Block(List())).asInstanceOf[syntax.Block], + body.getOrElse(Region(List())).asInstanceOf[Region], fields = selfRestFields2, ) } match { @@ -905,74 +786,76 @@ class Env(val fid: Option[FileId], val pacMgr: cosmo.PackageManager) { } def enumVariant( - node: syntax.Case, + node: (Expr, Option[Expr]), baseId: DefInfo, baseName: String, classSelf: Option[EnumVariant] = None, ) = { - val syntax.Case(cond, body) = node; - val (subName, params) = cond match { - case name: syntax.Ident => (name, List()) - case syntax.Apply(name: syntax.Ident, params, _) => (name, params) - case _ => (Ident("invalid"), List()) - } + // val (cond, body) = node; + // val (subName, params) = cond match { + // case name: Name => (name.id, List()) + // case Apply(name: Name, params) => (name.id, params) + // case _ => (ct("invalid"), List()) + // } - val vars = params.zipWithIndex.map { - case (n: syntax.Ident, index) => - val ty = if (n.name == baseName) { syntax.Ident("Self") } - else { n } - syntax.Var(Ident(s"_${index}"), Some(ty), None) - // todo: replace self - case (n: syntax.Apply, index) => - syntax.Var(Ident(s"_${index}"), Some(n), None) - case (_, index) => syntax.Var(Ident(s"_${index}"), None, None) - } + // val vars = params.zipWithIndex.map { + // case (n: syntax.Ident, index) => + // val ty = if (n.name == baseName) { syntax.Ident("Self") } + // else { n } + // syntax.Var(Ident(s"_${index}"), Some(ty), None) + // // todo: replace self + // case (n: syntax.Apply, index) => + // syntax.Var(Ident(s"_${index}"), Some(n), None) + // case (_, index) => syntax.Var(Ident(s"_${index}"), None, None) + // } - val b = (body, vars) match { - case (_, Nil) => body.getOrElse(syntax.Block(List())) - case (Some(syntax.Block(bc)), vars) => syntax.Block(vars ::: bc) - case (Some(n), vars) => syntax.Block(vars :+ n) - case _ => syntax.Block(vars) - } + // val b = (body, vars) match { + // case (_, Nil) => body.getOrElse(syntax.Block(List())) + // case (Some(syntax.Block(bc)), vars) => syntax.Block(vars ::: bc) + // case (Some(n), vars) => syntax.Block(vars :+ n) + // case _ => syntax.Block(vars) + // } - val cls = classItem( - // todo: trait enum - syntax.Class(subName, None, b, false), - classSelf = classSelf.map(_.base), - ) - // todo: right way to hide it - cls.vars.foreach { v => v.item.id.isHidden = true } - val info = ct(subName); info.inClass = true; cls.id.inClass = true; - EnumVariant(info, cls) + // val cls = classItem( + // // todo: trait enum + // ClassExpr(subName, params, b, false), + // classSelf = classSelf.map(_.base), + // ) + // // todo: right way to hide it + // cls.vars.foreach { v => v.item.id.isHidden = true } + // val info = ct(subName); info.inClass = true; cls.id.inClass = true; + // EnumVariant(info, cls) + ??? } - def implItem(ast: syntax.Impl) = { - val syntax.Impl(rhs, lhs, params, body) = ast - val defInfo = ct("$impl", hidden = true) + def implItem(ast: ImplExpr) = { + val ImplExpr(info, params, constraints, i, c, body) = ast val ss = selfImplRef val ss2 = selfRef - val impl = withNsParams(None, ast, params.map(Left(_))) { - val (iface, cls) = (lhs.map(typeExpr), typeExpr(rhs)) + val impl = { + val (iface, cls) = (i.map(typeTerm), typeTerm(c)) selfRef = Some(cls) val defs = body match { - case body: syntax.Block => - selfImplRef = - Some(Impl(defInfo, resolveParams(params), iface.get, cls, List())) + case body: Region => + selfImplRef = Some( + Impl(info, resolveParams(params), iface.get, cls, List()), + ) val (vars, decls) = baseClass(body, None) if (!vars.isEmpty) { errors = s"impl cannot have vars" :: errors } - selfImplRef = - Some(Impl(defInfo, resolveParams(params), iface.get, cls, decls)) + selfImplRef = Some( + Impl(info, resolveParams(params), iface.get, cls, decls), + ) baseClass(body, Some(vars ::: decls))._2 case _ => errors = s"Invalid impl body" :: errors; List() } defs.foreach { d => d.item.id.isOverride = true } - Impl(defInfo, resolveParams(params), iface.get, cls, defs) + Impl(info, resolveParams(params), iface.get, cls, defs) } selfRef = ss2 selfImplRef = ss - items += (defInfo.id -> impl) + items += (info.id -> impl) associateImpl(impl, impl.cls) impl } @@ -999,7 +882,7 @@ class Env(val fid: Option[FileId], val pacMgr: cosmo.PackageManager) { value: Item, ): Item = { if f.isEmpty then return value - def ins(ty: Type) = HKTInstance(ty, IApply(f.get, args)) + def ins(ty: Type) = HKTInstance(ty, Apply(f.get, args)) value match { case _: (CIdent | CppInsType | ClassInstance) => value case i: Class => ins(i) @@ -1108,13 +991,6 @@ class Env(val fid: Option[FileId], val pacMgr: cosmo.PackageManager) { } } - def exprOpa(ast: syntax.Node): String = { - valueExpr(ast) match { - case Opaque(Some(expr), _) => expr - case _ => "" - } - } - def defByName(info: DefInfo): String = info.defName(stem = false) def varByRef(vv: Term): String = { @@ -1159,7 +1035,7 @@ class Env(val fid: Option[FileId], val pacMgr: cosmo.PackageManager) { case Term(_, _, Some(v)) => storeTy(v) case RefItem(lhs, isMut) => s"${if (isMut) "" else "const "}${storeTy(lhs)}&" - case ApplyExpr(lhs, rhs) => { + case Apply(lhs, rhs) => { val lhsTy = storeTy(lhs) val rhsTy = rhs.map(storeTy).mkString(", ") s"$lhsTy<$rhsTy>" @@ -1194,11 +1070,10 @@ class Env(val fid: Option[FileId], val pacMgr: cosmo.PackageManager) { } } - def normalizeExpr(body: Item): Item = { - debugln(s"normalizeExpr $body") + def normalize(body: Item): Item = { + debugln(s"normalize $body") body match { - case Semi(value) => normalizeExpr(value) - case _ => body + case _ => body } } @@ -1206,7 +1081,6 @@ class Env(val fid: Option[FileId], val pacMgr: cosmo.PackageManager) { def isDependent(body: Item): Boolean = { body match { - case Semi(value) => isDependent(value) case _: (CIdent | CppInsType) => false case _ => true @@ -1331,11 +1205,10 @@ class Env(val fid: Option[FileId], val pacMgr: cosmo.PackageManager) { def tyOf(lhs: Item): Option[Type] = { debugln(s"tyOf $lhs") lhs match { - case Semi(t) => tyOf(t) - case _: Integer => Some(IntegerTy(32, false)) - case _: Rune => Some(IntegerTy(32, false)) - case _: Str => Some(StrTy) - case _: (ApplyExpr | Select) => Some(TopTy) + case _: Integer => Some(IntegerTy(32, false)) + case _: Rune => Some(IntegerTy(32, false)) + case _: Str => Some(StrTy) + case _: (Apply | Select) => Some(TopTy) case _: (While | Loop | For | Break | Continue) => Some(UnitTy) case Unreachable => Some(BottomTy) case _: (CIdent | Class | CppInsType) => @@ -1354,8 +1227,8 @@ class Env(val fid: Option[FileId], val pacMgr: cosmo.PackageManager) { case TodoLit => Some(BottomTy) case reg: Region => { reg.stmts.lastOption match { - case Some(Semi(_)) | None => Some(UnitTy) - case Some(v) => tyOf(v) + case None => Some(UnitTy) + case Some(v) => tyOf(v) } } case TypeMatch(_, _, cases, d) => { @@ -1378,7 +1251,6 @@ class Env(val fid: Option[FileId], val pacMgr: cosmo.PackageManager) { def lift(item: Item): Type = { debugln(s"lift $item") item match { - case Semi(value) => lift(value) case item: CIdent => CIdent(item.name, item.ns, 1) case item: CppInsType => CppInsType( @@ -1395,6 +1267,11 @@ class Env(val fid: Option[FileId], val pacMgr: cosmo.PackageManager) { lhs.orElse(rhs) } + // todo: meaninglessly resolve + def resolveParams(params: Option[EParams]) = params.map { params => + params.map { p => Param(p.id, (p.id.ty.level - 1).max(0)) } + } + def findItem(offset: Int): Option[Item] = logln(s"findItem in $fid with offset $offset") val node = nodeCovering(offset) diff --git a/packages/cosmo/src/main/scala/cosmo/Expr.scala b/packages/cosmo/src/main/scala/cosmo/Expr.scala index d57164c..45f92cc 100644 --- a/packages/cosmo/src/main/scala/cosmo/Expr.scala +++ b/packages/cosmo/src/main/scala/cosmo/Expr.scala @@ -4,6 +4,9 @@ import ir._ import syntax as s import syntax.{Ident, No} +type SParam = s.Param; +type SParams = List[SParam]; + class ExprEnv(val env: Env) { import env.{ct, scopes} @@ -12,7 +15,13 @@ class ExprEnv(val env: Env) { def err(e: String) = env.err(e).e def resolve(name: String) = scopes.get(name).map(Name(_, None)) - def byName(name: Ident) = Name(ct(name, true), resolve(name.name)) + def nameOrProduce(name: Ident, strict: Boolean) = + scopes.get(name.name) match { + case Some(x) => Name(ct(name, true), Some(Name(x, None))) + case None if strict => Name(ct(name, true), None) + case None => hole(ct(name)) + } + def byName(name: Ident) = nameOrProduce(name, true) def withNs[T](ns: Defo, ast: syntax.Node)(f: => T): T = { env.ns = ns.name :: env.ns; val res = f; env.ns = env.ns.tail @@ -72,12 +81,12 @@ class ExprEnv(val env: Env) { case s.UnOp(op, lhs) => UnOp(op, expr(lhs)) case s.BinOp(op, lhs, rhs) => BinOp(op, expr(lhs), expr(rhs)) case s.As(lhs, rhs) => As(expr(lhs), expr(rhs)) - case s.KeyedArg(k, v) => KeyedArg(expr(k), expr(v)) + case s.KeyedArg(k, v) => KeyedArg(keyExpr(k), expr(v)) // todo: check is compile time case s.Select(lhs, rhs, _) => SelectExpr(expr(lhs), rhs.name) case b: s.Match => $match(b) // todo: check is compile time - case s.Apply(lhs, rhs, _) => ApplyExpr(expr(lhs), rhs.map(expr)) + case s.Apply(lhs, rhs, _) => Apply(expr(lhs), rhs.map(expr)) case s.TmplApply(Ident("a"), rhs) => Rune(rhs.head._1.head.toInt).e case s.TmplApply(Ident("c"), rhs) => Rune(rhs.head._1.head.toInt).e case s.TmplApply(Ident("b"), rhs) => Bytes(rhs.head._1.getBytes()).e @@ -100,12 +109,10 @@ class ExprEnv(val env: Env) { case i: s.Impl => impl(i, ct("$impl", hidden = true)) // syntax errors case SParam(name, _, _, _) => Opaque.expr(s"panic(\"param: $name\")") + case b: s.CaseBlock => caseBlock(b) case b: s.ParamsLit => err(s"params lit without body") Opaque.expr(s"0/* error: case block without body */") - case b: s.CaseBlock => - err(s"case block without match") - Opaque.expr(s"0/* error: case block without match */") case s.Case(cond, body) => err(s"case clause without match") Opaque.expr(s"0/* error: case clause without match */") @@ -120,20 +127,50 @@ class ExprEnv(val env: Env) { return TupleLit(arr).e } - def block(ast: syntax.Block) = Region(scopes.withScope(ast.stmts.map(expr))) + def keyExpr(n: syntax.Node): Expr = { + n match { + case i: Ident => Str(i.name).e + case _ => expr(n) + } + } + + def hole(di: Defo): Expr = { + di.isVar = true; + Hole(di) + } + + def block(ast: s.Block) = Region(scopes.withScope(ast.stmts.map(expr))) - def $match(b: syntax.Match): Expr = { + def $match(b: s.Match): Expr = { var lhs = expr(b.lhs) val cases = b.rhs match { - case b: syntax.CaseBlock => - b.stmts.map { c => (expr(c.cond), c.body.map(expr)) } - case b: syntax.Block if (b.stmts.isEmpty) => List() - case b: syntax.Block => return err(s"match body contains non-cases $b") - case _ => return err("match body must be a case block") + case b: s.CaseBlock => caseBlock(b) + case b: s.Block if (b.stmts.isEmpty) => CaseRegion(List()) + case b: s.Block => return err(s"match body contains non-cases $b") + case _ => return err("match body must be a case block") } MatchExpr(lhs, cases) } + def caseBlock(b: s.CaseBlock): CaseRegion = { + val cases = b.stmts.map { c => + scopes.withScope { + val cond = destruct(c.cond); + val body = c.body.map(expr); + (cond, body) + } + } + CaseRegion(cases) + } + + def destruct(ast: syntax.Node): Expr = ast match { + case i: Ident => nameOrProduce(i, false) + // todo: check is compile time + case s.Apply(l, r, ct) => Apply(expr(l), r.map(destruct)) + case s.KeyedArg(l, r) => KeyedArg(keyExpr(l), destruct(r)) + case _ => expr(ast) + } + def $var(di: Defo, ty: Ni, init: No, mut: Boolean, ct: Boolean): VarExpr = { di.isMut = mut; di.isTypeVar = ct; di.isVar = true; VarExpr(di, ty, init.map(expr)) @@ -149,6 +186,32 @@ class ExprEnv(val env: Env) { def $class(ast: syntax.Class, defInfo: Defo): Expr = { val syntax.Class(_, params, body, isAbstract) = ast val (ps, cs, init) = withNs(defInfo, ast)(withParams(params)(expr(body))) + + // val (cond, body) = node; + // val (subName, params) = cond match { + // case name: Name => (name.id, List()) + // case Apply(name: Name, params) => (name.id, params) + // case _ => (ct("invalid"), List()) + // } + + // val vars = params.zipWithIndex.map { + // case (n: syntax.Ident, index) => + // val ty = if (n.name == baseName) { syntax.Ident("Self") } + // else { n } + // syntax.Var(Ident(s"_${index}"), Some(ty), None) + // // todo: replace self + // case (n: syntax.Apply, index) => + // syntax.Var(Ident(s"_${index}"), Some(n), None) + // case (_, index) => syntax.Var(Ident(s"_${index}"), None, None) + // } + + // val b = (body, vars) match { + // case (_, Nil) => body.getOrElse(syntax.Block(List())) + // case (Some(syntax.Block(bc)), vars) => syntax.Block(vars ::: bc) + // case (Some(n), vars) => syntax.Block(vars :+ n) + // case _ => syntax.Block(vars) + // } + ClassExpr(defInfo, ps, cs, init, isAbstract) } diff --git a/packages/cosmo/src/main/scala/cosmo/Item.scala b/packages/cosmo/src/main/scala/cosmo/Item.scala index aa48c69..6790e13 100644 --- a/packages/cosmo/src/main/scala/cosmo/Item.scala +++ b/packages/cosmo/src/main/scala/cosmo/Item.scala @@ -42,7 +42,15 @@ sealed abstract class Item { def e: Expr = ItemE(this) def toDoc: Doc = Doc.buildItem(this) } -abstract class Expr extends Item {} +// todo: don't inherit item? +sealed abstract class Expr extends Item { + def isWildcard: Boolean = this match { + case d: DeclExpr if d.id.name == "_" => true; case _ => false + } +} +sealed abstract class DeclExpr extends Expr { + val id: DefInfo +} /// Expressions @@ -53,38 +61,37 @@ object Opaque { def expr(expr: String) = Opaque(Some(expr), None) def stmt(stmt: String) = Opaque(None, Some(stmt)) } -final case class Region(stmts: List[Expr]) extends Expr { +final case class Region(stmts: List[Item]) extends Expr { override def toString: String = stmts.mkString("Region{ ", "; ", " }") } -final case class Loop(body: Expr) extends Expr {} -final case class While(cond: Expr, body: Expr) extends Expr {} -final case class For(name: Expr, iter: Expr, body: Expr) extends Expr {} +final case class Loop(body: Item) extends Expr {} +final case class While(cond: Item, body: Item) extends Expr {} +final case class For(name: Item, iter: Item, body: Item) extends Expr {} final case class Break() extends Expr {} final case class Continue() extends Expr {} -final case class Return(value: Expr) extends Expr {} -final case class If(cond: Expr, cont_bb: Expr, else_bb: Option[Expr]) +final case class Return(value: Item) extends Expr {} +final case class If(cond: Item, cont_bb: Item, else_bb: Option[Item]) extends Expr {} -final case class SelectExpr(lhs: Expr, rhs: String) extends Expr {} -final case class As(lhs: Expr, rhs: Expr) extends Expr {} -final case class UnOp(op: String, lhs: Expr) extends Expr {} -final case class BinOp(op: String, lhs: Expr, rhs: Expr) extends Expr {} -final case class KeyedArg(key: Expr, value: Expr) extends Expr {} -final case class Semi(value: Expr) extends Expr {} -final case class ApplyExpr(lhs: Expr, rhs: List[Expr]) extends Expr { - override def toString: String = s"$lhs(${rhs.mkString(", ")})" -} -final case class IApply(lhs: Item, rhs: List[Item]) extends Item { +final case class As(lhs: Item, rhs: Item) extends Expr {} +final case class UnOp(op: String, lhs: Item) extends Expr {} +final case class BinOp(op: String, lhs: Item, rhs: Item) extends Expr {} +final case class KeyedArg(key: Item, value: Item) extends Expr {} +final case class Apply(lhs: Item, rhs: List[Item]) extends Expr { override def toString: String = s"$lhs(${rhs.mkString(", ")})" } +final case class SelectExpr(lhs: Expr, rhs: String) extends Expr {} final case class Name(val id: DefInfo, val of: Option[Expr] = None) - extends Expr { - override def toString: String = id.defName(false) + extends DeclExpr { + override def toString: String = s"${id.defName(false)}@${id.id.id}" +} +final case class Hole(id: DefInfo) extends DeclExpr { + override def toString: String = s"hole(${id.defName(false)})" } final case class VarExpr(id: DefInfo, ty: Option[Type], init: Option[Expr]) - extends Expr { + extends DeclExpr { override def toString: String = s"var(${id.defName(false)})" } -abstract class ParamExpr extends Expr { +abstract class ParamExpr extends DeclExpr { val id: DefInfo val params: Option[List[VarExpr]] val constraints: List[Expr] @@ -113,9 +120,8 @@ final case class ImplExpr( cls: Type, body: Item, ) extends ParamExpr {} - -final case class MatchExpr(lhs: Expr, cases: List[(Expr, Option[Expr])]) - extends Expr {} +final case class CaseRegion(cases: List[(Expr, Option[Expr])]) extends Expr {} +final case class MatchExpr(lhs: Expr, body: CaseRegion) extends Expr {} /// Types @@ -181,15 +187,14 @@ final case class Param(id: DefInfo, override val level: Int) extends DeclLike { final case class Var( id: DefInfo, init: Option[Item], - isConstant: Boolean, override val level: Int, ) extends DeclLike { override def toString: String = - val mod = if isConstant then "val" else "var" + val mod = if !id.isMut then "val" else "var" s"($mod ${id.defName(false)}:${id.id.id} = ${init.getOrElse(NoneItem)})" def pretty(implicit rec: Item => String = _.toString): String = - val mod = if isConstant then "val" else "var" + val mod = if !id.isMut then "val" else "var" val initStr = init.map(rec).getOrElse("None") s"$mod ${id.defName(false)}" } @@ -243,7 +248,7 @@ final case class HKTInstance(ty: Type, syntax: Item) extends Item { override def toString(): String = s"(hkt($syntax)::type as $ty)" def repr(rec: Type => String): String = syntax match { case t: (Term | Fn) => rec(t) - case ApplyExpr(lhs, rhs) => + case Apply(lhs, rhs) => s"${rec(HKTInstance(ty, lhs))}<${rhs.map(rec).mkString(", ")}>::type" case Select(lhs, rhs) => s"${rec(HKTInstance(ty, lhs))}::$rhs" case _ => syntax.toString diff --git a/packages/cosmo/src/main/scala/cosmo/Parser.scala b/packages/cosmo/src/main/scala/cosmo/Parser.scala index ae67490..159ea76 100644 --- a/packages/cosmo/src/main/scala/cosmo/Parser.scala +++ b/packages/cosmo/src/main/scala/cosmo/Parser.scala @@ -35,7 +35,7 @@ object Parser { def delimStr[T, $: P](d: String, body: => P[T]) = d ~~/ delimStrCont(d, body) def delimStrCont[T, $: P](d: String, body: => P[T]) = - (!End ~ !d ~~ body).repX.! ~~ (d | End.err("Unclosed string")) + (!End ~~ !d ~~ body).repX.! ~~ (d | End.err("Unclosed string")) def shortStr[$: P] = P(shortStr0.map(unescapeStr)) def shortStr0[$: P] = delimStr("\"", strEscape) def longStr[$: P] = P("\"".repX(3).!./.flatMapX(longStr0)) @@ -58,7 +58,7 @@ object Parser { P(longChars("\"$", delim).repX.! ~~/ tmplExpr) def longChars[$: P](mores: String, delim: String): P[Unit] = - !End ~ P(litCharsWhile(mores) | !delim ~~ "\"".repX) + !End ~~ P(litCharsWhile(mores) | !delim ~~ "\"".repX) def litCharsWhile[$: P](mores: String) = P(CharsWhile(!mores.contains(_))) def escapeseq[$: P]: P[Unit] = P("\\" ~ AnyChar) def tmplExpr[$: P]: P[Option[(Node, Option[String])]] = diff --git a/packages/cosmo/src/main/scala/cosmo/Syntax.scala b/packages/cosmo/src/main/scala/cosmo/Syntax.scala index 18b9048..743d134 100644 --- a/packages/cosmo/src/main/scala/cosmo/Syntax.scala +++ b/packages/cosmo/src/main/scala/cosmo/Syntax.scala @@ -141,8 +141,4 @@ final case class Apply(lhs: Node, rhs: List[Node], ct: Boolean) extends Node final case class TmplApply(lhs: Node, rhs: List[(String, TmplExp)]) extends Node final case class KeyedArg(key: Node, value: Node) extends Node // Kind: Clauses -final case class Case(cond: Node, body: No) extends Node { - def isWildcard: Boolean = cond match { - case Ident("_") => true; case _ => false - } -} +final case class Case(cond: Node, body: No) extends Node; diff --git a/packages/cosmo/src/test/scala/cosmo/ParserTests.scala b/packages/cosmo/src/test/scala/cosmo/ParserTests.scala index e6fd3f5..5799214 100644 --- a/packages/cosmo/src/test/scala/cosmo/ParserTests.scala +++ b/packages/cosmo/src/test/scala/cosmo/ParserTests.scala @@ -82,6 +82,9 @@ class ParserTest extends munit.FunSuite { test("Syntax/lambda.syntax") { runTestOnFile("samples/Syntax/lambda.syntax.cos") } + test("Syntax/matchExpr.syntax") { + runTestOnFile("samples/Syntax/matchExpr.syntax.cos") + } test("Vec/push") { runTestOnFile("samples/Vec/push.cos") } diff --git a/packages/cosmo/src/test/scala/cosmo/SampleTests.scala b/packages/cosmo/src/test/scala/cosmo/SampleTests.scala index 68c5723..9787721 100644 --- a/packages/cosmo/src/test/scala/cosmo/SampleTests.scala +++ b/packages/cosmo/src/test/scala/cosmo/SampleTests.scala @@ -17,13 +17,16 @@ class SampleTest extends munit.FunSuite: var src = cosmo.NodeFs.readFileSync(path, "utf8").asInstanceOf[String] var result = compiler.transpile(src) if (syntaxOnly) { - println(result.map(_._2.stgE.module.toDoc.pretty)) + println(result.map(_._2.stgE.module.toDoc.pretty(showDef = true))) } else { println(result.map(_._1)) } } - test("HelloWorld") { + test("Syntax/playground") { + runTestOnFile("samples/Syntax/playground.cos") + } + test("HelloWorld".only) { runTestOnFile("samples/HelloWorld/main.cos") } test("Syntax/literal") { @@ -47,7 +50,7 @@ class SampleTest extends munit.FunSuite: test("Syntax/try-catch.syntax") { runTestOnFile("samples/Syntax/try-catch.syntax.cos") } - test("Syntax/errs/tmplLit01".only) { + test("Syntax/errs/tmplLit01") { runTestOnFile("samples/Syntax/errs/tmplLit01.cos-ast") } test("Syntax/tmplLit.syntax") { diff --git a/samples/Syntax/expr.syntax.cos b/samples/Syntax/expr.syntax.cos index ce538cd..f0ed26a 100644 --- a/samples/Syntax/expr.syntax.cos +++ b/samples/Syntax/expr.syntax.cos @@ -10,73 +10,4 @@ def main() = { print(1 / 2 + 3) print(1 * 2 / 3) print(1 / 2 * 3) - - a match {} - a + 1 match {} - a.method match {} - a.method() match {} - a * 1 match {} - a = 1 match {} - a = a match {} - - 1 match { - case 1 - } - 1 match { - case 1 => 2 - } - 1 match { - case false => 2 - } - 1 + 1 match { - case (1 + 1) => 2 - } - 1 + 1 match { - case (1 * 1 + 1) => 2 - } - 1 match { - case a => 2 - } - 1 match { - case (a) => 2 - } - 1 + 1 match { - case (1 + a) => 2 - } - 1 + 1 match { - case (1 * 1 + a) => 2 - } - 1 + 1 match { - case a => { 2 } - } - 1 + 1 match { - case A.B() => { 2 } - } - 1 + 1 match { - case (A.B()) => { 2 } - } - 1 match { - case a => { 2 } - } match { - case b => { 2 } - } - 1 match { - case a => { 2 } - } as a - 1 as a match { - case a => { 2 } - } - - 1 as a match { - case _ - } - 1 as a match { - case _; - } - 1 as a match { - case _ => a - } - 1 as a match { - case _ => a; - } } diff --git a/samples/Syntax/matchExpr.syntax.cos b/samples/Syntax/matchExpr.syntax.cos new file mode 100644 index 0000000..13fcfe5 --- /dev/null +++ b/samples/Syntax/matchExpr.syntax.cos @@ -0,0 +1,123 @@ + +@noCore(); + +def main() = { + + a match {} + a + 1 match {} + a.method match {} + a.method() match {} + a * 1 match {} + a = 1 match {} + a = a match {} + + 1 match { + case 1 + } + 1 match { + case 1 => 2 + } + 1 match { + case false => 2 + } + 1 + 1 match { + case (1 + 1) => 2 + } + 1 + 1 match { + case (1 * 1 + 1) => 2 + } + 1 match { + case a => 2 + } + 1 match { + case (a) => 2 + } + 1 + 1 match { + case (1 + a) => 2 + } + 1 + 1 match { + case (1 * 1 + a) => 2 + } + 1 + 1 match { + case a => { 2 } + } + 1 + 1 match { + case A.B() => { 2 } + } + 1 + 1 match { + case (A.B()) => { 2 } + } + 1 match { + case a => { 2 } + } match { + case b => { 2 } + } + 1 match { + case a => { 2 } + } as a + 1 as a match { + case a => { 2 } + } + + 1 as a match { + case _ + } + 1 as a match { + case _; + } + 1 as a match { + case _ => a + } + 1 as a match { + case _ => a; + } + { + 1 match { + case a => a + } + } + { + val a = 1; + 1 match { + case a => a + } + } + { + val a = 1; + 1 match { + case a.b => a + } + } + { + 1 match { + case a.b(a) => a + } + } + { + val a = 1; + 1 match { + case a.b(a) => a + } + } + { + 1 match { + case _ + } + } + { + 1 match { + case _ => _ + } + } + { + 1 match { + case a.b(b: a) => (a, b) + } + } + { + val a = 1; + 1 match { + case a.b(b: a) => (a, b) + } + } +} \ No newline at end of file diff --git a/samples/Syntax/playground.cos b/samples/Syntax/playground.cos new file mode 100644 index 0000000..a0e6cd0 --- /dev/null +++ b/samples/Syntax/playground.cos @@ -0,0 +1,5 @@ + +@noCore(); + +def main() = { +}