-
-
Save rightfold/73f5057ec6c0ff5ca107 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.rightfold.styx.compiler.semantic | |
import org.rightfold.styx.compiler.Diagnostic | |
import org.rightfold.styx.compiler.parse | |
class Analyzer(emitDiagnostic: Diagnostic => Unit) { | |
case object AnalysisFailed extends Exception | |
sealed abstract class Symbol { | |
def isUnsafe: Boolean | |
} | |
case class Context(parent: Option[Context], symbols: Map[String, Symbol], unsafe: Boolean) { | |
def addSymbol(name: String, symbol: Symbol) = { | |
if (symbols contains name) { | |
emitDiagnostic(Diagnostic(Diagnostic.Error, s"attempt to redefine symbol `$name`")) | |
// TODO: Emit info diagnostic containing position of original symbol | |
throw AnalysisFailed | |
} | |
copy(symbols = symbols + (name -> symbol)) | |
} | |
def findSymbol(name: String): Option[Symbol] = { | |
val result = symbols.get(name) orElse (parent flatMap (_ findSymbol name)) | |
if (!unsafe && result.nonEmpty && result.get.isUnsafe) { | |
emitDiagnostic(Diagnostic(Diagnostic.Error, s"attempt to use unsafe symbol `$name` in a safe context")) | |
throw AnalysisFailed | |
} | |
result | |
} | |
def mustFindSymbol(name: String): Symbol = findSymbol(name) match { | |
case Some(symbol) => symbol | |
case None => | |
emitDiagnostic(Diagnostic(Diagnostic.Error, s"attempt to use undefined symbol `$name`")) | |
throw AnalysisFailed | |
} | |
def makeSafe = copy(unsafe = false) | |
def makeUnsafe = copy(unsafe = true) | |
} | |
def analyzeExpression(context: Context)(expression: parse.Expression): Expression = (expression match { | |
case parse.UnitExpression => UnitExpression | |
case parse.IntExpression(value) => IntExpression(value) | |
case parse.SafeExpression(body) => analyzeExpression(context.makeSafe)(body) | |
case parse.UnsafeExpression(body) => analyzeExpression(context.makeUnsafe)(body) | |
}) ensuring (_.`type`.kind == *) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment