Skip to content

Commit ac7c3d1

Browse files
committed
Remove reliance on global state to deal with symbol UIDs
1 parent d08424f commit ac7c3d1

File tree

15 files changed

+75
-54
lines changed

15 files changed

+75
-54
lines changed

hkmc2/jvm/src/test/scala/hkmc2/MLsDiffMaker.scala

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ abstract class MLsDiffMaker extends DiffMaker:
6363
if doTrace then super.trace(pre, post)(thunk)
6464
else thunk
6565

66-
var curCtx = Elaborator.Ctx.init.nest(N)
66+
var curCtx = Elaborator.State.init.nest(N)
6767

6868

6969
override def run(): Unit =
@@ -103,7 +103,8 @@ abstract class MLsDiffMaker extends DiffMaker:
103103
if showParse.isSet || dbgParsing.isSet then
104104
output(syntax.Lexer.printTokens(tokens))
105105

106-
val p = new syntax.Parser(origin, tokens, raise, dbg = dbgParsing.isSet):
106+
val rules = syntax.ParseRules()
107+
val p = new syntax.Parser(origin, tokens, rules, raise, dbg = dbgParsing.isSet):
107108
def doPrintDbg(msg: => Str): Unit = if dbg then output(msg)
108109
val res = p.parseAll(p.block(allowNewlines = true))
109110
val imprtSymbol =
@@ -136,7 +137,8 @@ abstract class MLsDiffMaker extends DiffMaker:
136137
if showParse.isSet || dbgParsing.isSet then
137138
output(syntax.Lexer.printTokens(tokens))
138139

139-
val p = new syntax.Parser(origin, tokens, raise, dbg = dbgParsing.isSet):
140+
val rules = syntax.ParseRules()
141+
val p = new syntax.Parser(origin, tokens, rules, raise, dbg = dbgParsing.isSet):
140142
def doPrintDbg(msg: => Str): Unit = if dbg then output(msg)
141143
val res = p.parseAll(p.block(allowNewlines = true))
142144

hkmc2/jvm/src/test/scala/hkmc2/Watcher.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ class Watcher(dir: File):
8787
val relativeName = basePath.map(_ + "/").mkString + path.baseName
8888
val preludePath = os.pwd/os.up/"shared"/"src"/"test"/"mlscript"/"decls"/"Prelude.mls"
8989
val predefPath = os.pwd/os.up/"shared"/"src"/"test"/"mlscript-compile"/"Predef.mls"
90-
semantics.suid.reset // FIXME hack
9190
val isModuleFile = path.segments.contains("mlscript-compile")
9291
if isModuleFile
9392
then

hkmc2/shared/src/main/scala/hkmc2/MLsCompiler.scala

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import utils.*
88
import hkmc2.semantics.MemberSymbol
99
import hkmc2.semantics.Elaborator
1010
import hkmc2.syntax.Keyword.`override`
11+
import semantics.Elaborator.State
1112

1213

1314
class MLsCompiler(preludeFile: os.Path):
@@ -38,13 +39,14 @@ class MLsCompiler(preludeFile: os.Path):
3839
// if showParse.isSet || dbgParsing.isSet then
3940
// output(syntax.Lexer.printTokens(tokens))
4041

41-
val p = new syntax.Parser(origin, tokens, raise, dbg = dbgParsing):
42+
given Elaborator.State = new Elaborator.State
43+
val rules = syntax.ParseRules()
44+
val p = new syntax.Parser(origin, tokens, rules, raise, dbg = dbgParsing):
4245
def doPrintDbg(msg: => Str): Unit =
4346
// if dbg then output(msg)
4447
if dbg then println(msg)
4548
val res = p.parseAll(p.block(allowNewlines = true))
46-
given Elaborator.State = new Elaborator.State
47-
given Elaborator.Ctx = Elaborator.Ctx.init.nest(N)
49+
given Elaborator.Ctx = State.init.nest(N)
4850
val wd = file / os.up
4951
val elab = Elaborator(etl, wd)
5052
val resBlk = new syntax.Tree.Block(res)

hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import hkmc2.Message.MessageContext
88

99
import hkmc2.{semantics => sem}
1010
import hkmc2.semantics.{Term => st}
11+
import semantics.Elaborator.State
1112

1213
import syntax.{Literal, Tree}
1314
import semantics.*
@@ -260,7 +261,7 @@ class Lowering(using TL, Raise, Elaborator.State):
260261
else End()
261262
)
262263
case Split.End =>
263-
Throw(Instantiate(Select(Value.Ref(Elaborator.Ctx.globalThisSymbol), Tree.Ident("Error")),
264+
Throw(Instantiate(Select(Value.Ref(State.globalThisSymbol), Tree.Ident("Error")),
264265
Value.Lit(syntax.Tree.StrLit("match error")) :: Nil)) // TODO add failed-match scrutinee info
265266

266267
if k.isInstanceOf[TailOp] && isIf then go(iftrm.normalized, topLevel = true)

hkmc2/shared/src/main/scala/hkmc2/codegen/js/JSBuilder.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ abstract class CodeBuilder:
2525
type Context
2626

2727

28-
class JSBuilder extends CodeBuilder:
28+
class JSBuilder(using Elaborator.State) extends CodeBuilder:
2929

3030
val builtinOpsBase: Ls[Str] = Ls(
3131
"+", "-", "*", "/", "%",
@@ -425,7 +425,9 @@ object JSBuilder:
425425
end JSBuilder
426426

427427

428-
trait JSBuilderSanityChecks(instrument: Bool) extends JSBuilder:
428+
trait JSBuilderSanityChecks
429+
(instrument: Bool)(using Elaborator.State)
430+
extends JSBuilder:
429431

430432
val functionParamVarargSymbol = semantics.TempSymbol(N, "args")
431433

hkmc2/shared/src/main/scala/hkmc2/codegen/js/Scope.scala

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,23 @@ import hkmc2.semantics.InnerSymbol
1313
import hkmc2.semantics.VarSymbol
1414
import hkmc2.semantics.Elaborator
1515
import hkmc2.semantics.TopLevelSymbol
16+
import semantics.Elaborator.State
1617

1718

1819
/** When `curThis`, it means this scope does not rebind `this`.
1920
* When `curThis` is Some(None), it means the scope rebinds `this`
2021
* to something unknown, following JavaScript's inane `this` handling in `function`s.
2122
* When `curThis` is Some(Some(sym)), it means the scope rebinds `this`
2223
* to an inner symbol (e.g., class or module). */
23-
class Scope(val parent: Opt[Scope], val curThis: Opt[Opt[InnerSymbol]], val bindings: MutMap[Local, Str]):
24+
class Scope
25+
(val parent: Opt[Scope], val curThis: Opt[Opt[InnerSymbol]], val bindings: MutMap[Local, Str])
26+
(using State):
2427

2528
private var thisProxyAccessed = false
2629
lazy val thisProxy =
2730
curThis match
2831
case N | S(N) => die
29-
case S(S(Elaborator.Ctx.globalThisSymbol)) => "globalThis"
32+
case S(S(State.globalThisSymbol)) => "globalThis"
3033
case S(S(thisSym)) =>
3134
thisProxyAccessed = true
3235
allocateName(thisSym, "this$")
@@ -112,8 +115,8 @@ object Scope:
112115

113116
def scope(using scp: Scope): Scope = scp
114117

115-
def empty: Scope =
116-
Scope(N, S(S(Elaborator.Ctx.globalThisSymbol)), MutMap.empty)
118+
def empty(using State): Scope =
119+
Scope(N, S(S(State.globalThisSymbol)), MutMap.empty)
117120

118121
def replaceTicks(str: Str): Str = str.replace('\'', '$')
119122

hkmc2/shared/src/main/scala/hkmc2/semantics/BlockImpl.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import syntax.Tree.*
66
import hkmc2.syntax.TypeOrTermDef
77

88

9-
trait BlockImpl:
9+
trait BlockImpl(using Elaborator.State):
1010
self: Block =>
1111

1212
val desugStmts = stmts.map(_.desugared)

hkmc2/shared/src/main/scala/hkmc2/semantics/Desugarer.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import hkmc2.syntax.Literal
99
import Keyword.{as, and, `else`, is, let, `then`}
1010
import collection.mutable.HashMap
1111
import Elaborator.{ctx, Ctxl}
12-
import hkmc2.semantics.Elaborator.Ctx.globalThisSymbol
1312

1413
object Desugarer:
1514
extension (op: Keyword.Infix)

hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,17 @@ object Elaborator:
7676
def symbol = symOpt
7777
given Conversion[Symbol, Elem] = RefElem(_)
7878
val empty: Ctx = Ctx(N, N, Map.empty)
79-
// val globalThisSymbol = TermSymbol(ImmutVal, N, Ident("globalThis"))
79+
type Ctxl[A] = Ctx ?=> A
80+
def ctx: Ctxl[Ctx] = summon
81+
class State:
82+
given State = this
83+
val suid = new Uid.Symbol.State
8084
val globalThisSymbol = TopLevelSymbol("globalThis")
8185
val seqSymbol = TermSymbol(ImmutVal, N, Ident(";"))
82-
def init(using State): Ctx = empty.copy(env = Map(
86+
def init(using State): Ctx = Ctx.empty.copy(env = Map(
8387
"globalThis" -> globalThisSymbol,
8488
))
85-
type Ctxl[A] = Ctx ?=> A
86-
def ctx: Ctxl[Ctx] = summon
87-
class State
89+
transparent inline def State(using state: State): State = state
8890
import Elaborator.*
8991

9092
class Elaborator(val tl: TraceLogger, val wd: os.Path)

hkmc2/shared/src/main/scala/hkmc2/semantics/Importer.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ class Importer:
5252

5353
val lexer = new syntax.Lexer(origin, dbg = tl.doTrace)
5454
val tokens = lexer.bracketedTokens
55-
val p = new syntax.Parser(origin, tokens, raise, dbg = tl.doTrace):
55+
val rules = syntax.ParseRules()
56+
val p = new syntax.Parser(origin, tokens, rules, raise, dbg = tl.doTrace):
5657
def doPrintDbg(msg: => Str): Unit =
5758
// if dbg then output(msg)
5859
if dbg then tl.log(msg)

hkmc2/shared/src/main/scala/hkmc2/semantics/Symbol.scala

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,15 @@ import scala.collection.mutable.{Set => MutSet}
77
import mlscript.utils.*, shorthands.*
88
import syntax.*
99

10+
import Elaborator.State
1011
import Tree.Ident
1112

1213

13-
// TODO refactor: don't rely on global state!
14-
val suid = new Uid.Symbol.State
15-
16-
17-
abstract class Symbol extends Located:
14+
abstract class Symbol(using State) extends Located:
1815

1916
def nme: Str
20-
val uid: Uid[Symbol] = suid.nextUid
17+
18+
val uid: Uid[Symbol] = State.suid.nextUid
2119

2220
val directRefs: mutable.Buffer[Term.Ref] = mutable.Buffer.empty
2321
def ref(id: Tree.Ident =
@@ -55,7 +53,7 @@ abstract class Symbol extends Located:
5553
end Symbol
5654

5755

58-
class FlowSymbol(label: Str) extends Symbol:
56+
class FlowSymbol(label: Str)(using State) extends Symbol:
5957
def nme: Str = label
6058
def toLoc: Option[Loc] = N // TODO track source trees of flows
6159
import typing.*
@@ -72,26 +70,29 @@ sealed trait NamedSymbol extends Symbol:
7270
def name: Str
7371
def id: Ident
7472

75-
abstract class BlockLocalSymbol(name: Str) extends FlowSymbol(name) with LocalSymbol:
73+
abstract class BlockLocalSymbol(name: Str)(using State) extends FlowSymbol(name) with LocalSymbol:
7674
var decl: Opt[Declaration] = N
7775

78-
class TempSymbol(val trm: Opt[Term], dbgNme: Str = "tmp") extends BlockLocalSymbol(dbgNme):
76+
class TempSymbol(val trm: Opt[Term], dbgNme: Str = "tmp")(using State) extends BlockLocalSymbol(dbgNme):
7977
val nameHints: MutSet[Str] = MutSet.empty
8078
override def toLoc: Option[Loc] = trm.flatMap(_.toLoc)
8179
override def toString: Str = s"$$${super.toString}"
8280

83-
class VarSymbol(val id: Ident) extends BlockLocalSymbol(id.name) with NamedSymbol:
81+
class VarSymbol(val id: Ident)(using State) extends BlockLocalSymbol(id.name) with NamedSymbol:
8482
val name: Str = id.name
8583
// override def toString: Str = s"$name@$uid"
8684

87-
class BuiltinSymbol(val nme: Str, val binary: Bool, val unary: Bool, val nullary: Bool) extends Symbol:
85+
class BuiltinSymbol
86+
(val nme: Str, val binary: Bool, val unary: Bool, val nullary: Bool)(using State)
87+
extends Symbol:
8888
def toLoc: Option[Loc] = N
8989
override def toString: Str = s"builtin:$nme"
9090

9191

9292
/** This is the outside-facing symbol associated to a possibly-overloaded
9393
* definition living in a block – e.g., a module or class. */
94-
class BlockMemberSymbol(val nme: Str, val trees: Ls[Tree]) extends MemberSymbol[Definition]:
94+
class BlockMemberSymbol(val nme: Str, val trees: Ls[Tree])(using State)
95+
extends MemberSymbol[Definition]:
9596

9697
def toLoc: Option[Loc] = Loc(trees)
9798

@@ -114,12 +115,12 @@ class BlockMemberSymbol(val nme: Str, val trees: Ls[Tree]) extends MemberSymbol[
114115
end BlockMemberSymbol
115116

116117

117-
sealed abstract class MemberSymbol[Defn <: Definition] extends Symbol:
118+
sealed abstract class MemberSymbol[Defn <: Definition](using State) extends Symbol:
118119
def nme: Str
119120
var defn: Opt[Defn] = N
120121

121122

122-
class TermSymbol(val k: TermDefKind, val owner: Opt[InnerSymbol], val id: Tree.Ident)
123+
class TermSymbol(val k: TermDefKind, val owner: Opt[InnerSymbol], val id: Tree.Ident)(using State)
123124
extends MemberSymbol[Definition] with LocalSymbol with NamedSymbol:
124125
def nme: Str = id.name
125126
def name: Str = nme
@@ -129,16 +130,16 @@ class TermSymbol(val k: TermDefKind, val owner: Opt[InnerSymbol], val id: Tree.I
129130

130131
sealed trait CtorSymbol extends Symbol
131132

132-
case class Extr(isTop: Bool) extends CtorSymbol:
133+
case class Extr(isTop: Bool)(using State) extends CtorSymbol:
133134
def nme: Str = if isTop then "Top" else "Bot"
134135
def toLoc: Option[Loc] = N
135136
override def toString: Str = nme
136137

137-
case class LitSymbol(lit: Literal) extends CtorSymbol:
138+
case class LitSymbol(lit: Literal)(using State) extends CtorSymbol:
138139
def nme: Str = lit.toString
139140
def toLoc: Option[Loc] = lit.toLoc
140141
override def toString: Str = s"lit:$lit"
141-
case class TupSymbol(arity: Opt[Int]) extends CtorSymbol:
142+
case class TupSymbol(arity: Opt[Int])(using State) extends CtorSymbol:
142143
def nme: Str = s"Tuple#$arity"
143144
def toLoc: Option[Loc] = N
144145
override def toString: Str = s"tup:$arity"
@@ -152,26 +153,26 @@ type TypeSymbol = ClassSymbol | TypeAliasSymbol
152153
* A `Ref(_: InnerSymbol)` represents a `this`-like reference to the current object. */
153154
sealed trait InnerSymbol extends Symbol
154155

155-
class ClassSymbol(val tree: Tree.TypeDef, val id: Tree.Ident)
156+
class ClassSymbol(val tree: Tree.TypeDef, val id: Tree.Ident)(using State)
156157
extends MemberSymbol[ClassDef] with CtorSymbol with InnerSymbol:
157158
def nme = id.name
158159
def toLoc: Option[Loc] = id.toLoc // TODO track source tree of classe here
159160
override def toString: Str = s"class:$nme"
160161
/** Compute the arity. */
161162
def arity: Int = tree.paramLists.headOption.fold(0)(_.fields.length)
162163

163-
class ModuleSymbol(val tree: Tree.TypeDef, val id: Tree.Ident)
164+
class ModuleSymbol(val tree: Tree.TypeDef, val id: Tree.Ident)(using State)
164165
extends MemberSymbol[ModuleDef] with CtorSymbol with InnerSymbol:
165166
def nme = id.name
166167
def toLoc: Option[Loc] = id.toLoc // TODO track source tree of module here
167168
override def toString: Str = s"module:${id.name}"
168169

169-
class TypeAliasSymbol(val id: Tree.Ident) extends MemberSymbol[TypeDef]:
170+
class TypeAliasSymbol(val id: Tree.Ident)(using State) extends MemberSymbol[TypeDef]:
170171
def nme = id.name
171172
def toLoc: Option[Loc] = id.toLoc // TODO track source tree of type alias here
172173
override def toString: Str = s"module:${id.name}"
173174

174-
class TopLevelSymbol(blockNme: Str)
175+
class TopLevelSymbol(blockNme: Str)(using State)
175176
extends MemberSymbol[ModuleDef] with InnerSymbol:
176177
def nme = blockNme
177178
def toLoc: Option[Loc] = N

hkmc2/shared/src/main/scala/hkmc2/syntax/ParseRule.scala

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import sourcecode.{Name, Line}
55
import mlscript.utils.*, shorthands.*
66
import hkmc2.Message._
77
import BracketKind._
8+
import semantics.Elaborator.State
89

910

1011
// * TODO: add lookahead to Expr as a PartialFunction[Ls[Token], Bool]
@@ -49,7 +50,10 @@ class ParseRule[+A](val name: Str, val omitAltsStr: Bool = false)(val alts: Alt[
4950
case str1 :: str2 :: Nil => s"$str1 or $str2"
5051
case strs => strs.init.mkString(", ") + ", or " + strs.last
5152

52-
object ParseRule:
53+
end ParseRule
54+
55+
56+
class ParseRules(using State):
5357
import Keyword.*
5458
import Alt.*
5559
import Tree.*
@@ -352,4 +356,5 @@ object ParseRule:
352356
genInfixRule(`restricts`, (rhs, _: Unit) => lhs => InfixApp(lhs, `restricts`, rhs)),
353357
)
354358

359+
end ParseRules
355360

hkmc2/shared/src/main/scala/hkmc2/syntax/Parser.scala

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ import Parser.*
1212
import scala.annotation.tailrec
1313

1414
import Keyword.`let`
15-
import hkmc2.syntax.ParseRule.prefixRules
16-
import hkmc2.syntax.ParseRule.infixRules
1715
import hkmc2.syntax.Keyword.Ellipsis
1816

17+
import semantics.Elaborator.State
18+
1919

2020
object Parser:
2121

@@ -107,12 +107,15 @@ import Parser._
107107
abstract class Parser(
108108
origin: Origin,
109109
tokens: Ls[TokLoc],
110+
rules: ParseRules,
110111
raiseFun: Diagnostic => Unit,
111112
val dbg: Bool,
112113
// fallbackLoc: Opt[Loc], description: Str = "input",
113-
):
114+
)(using State):
114115
outer =>
115116

117+
import rules.*
118+
116119
protected def doPrintDbg(msg: => Str): Unit
117120
protected def printDbg(msg: => Any): Unit =
118121
doPrintDbg("" * this.indent + msg)
@@ -134,7 +137,7 @@ abstract class Parser(
134137
res
135138

136139
final def rec(tokens: Ls[Stroken -> Loc], fallbackLoc: Opt[Loc], description: Str): Parser =
137-
new Parser(origin, tokens, raiseFun, dbg
140+
new Parser(origin, tokens, rules, raiseFun, dbg
138141
// , fallbackLoc, description
139142
):
140143
def doPrintDbg(msg: => Str): Unit = outer.printDbg("> " + msg)
@@ -458,7 +461,7 @@ abstract class Parser(
458461
// TODO: rm `allowIndentedBlock`? Seems it can always be `true`
459462
def expr(prec: Int, allowIndentedBlock: Bool = true)(using Line): Tree =
460463
parseRule(prec,
461-
if allowIndentedBlock then ParseRule.prefixRulesAllowIndentedBlock else prefixRules
464+
if allowIndentedBlock then prefixRulesAllowIndentedBlock else prefixRules
462465
).getOrElse(errExpr) // * a `None` result means an alread-reported error
463466

464467
def simpleExpr(prec: Int)(using Line): Tree = wrap(prec)(simpleExprImpl(prec))

0 commit comments

Comments
 (0)