Skip to content

Commit

Permalink
Support raising a does-not-have-properties exception
Browse files Browse the repository at this point in the history
  • Loading branch information
melvic-ybanez committed Nov 11, 2023
1 parent 4cf0c5e commit bcf90a1
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ object Exceptions {
.defineWith(InvalidOperands.name, DException(InvalidOperands, _))
.defineWith(NotCallable.name, DException(NotCallable, _))
.defineWith(IncorrectArity.name, DException(IncorrectArity, _))
.defineWith(DoesNotHaveProperties.name, DException(DoesNotHaveProperties, _))

private def raise(env: Env): Callable = Callable.withLineNo(1, env) { line =>
def invalidArgument(got: Value): Result[Value] =
Expand All @@ -32,12 +33,13 @@ object Exceptions {
error(Token.fromLine(line), message).fail

DException.Kind.of(exception).fold(invalidArgument(exception)) {
case DivisionByZero.name => fail(RuntimeError.divisionByZero)
case UndefinedVariable.name => fail(RuntimeError.undefinedVariable)
case InvalidOperand.name => fail(RuntimeError.invalidOperand)
case InvalidOperands.name => fail(RuntimeError.invalidOperands)
case NotCallable.name => fail(RuntimeError.notCallable)
case IncorrectArity.name => fail(RuntimeError.incorrectArity)
case DivisionByZero.name => fail(RuntimeError.divisionByZero)
case UndefinedVariable.name => fail(RuntimeError.undefinedVariable)
case InvalidOperand.name => fail(RuntimeError.invalidOperand)
case InvalidOperands.name => fail(RuntimeError.invalidOperands)
case NotCallable.name => fail(RuntimeError.notCallable)
case IncorrectArity.name => fail(RuntimeError.incorrectArity)
case DoesNotHaveProperties.name => fail(RuntimeError.doesNotHaveProperties)
}
case arg :: _ => invalidArgument(arg)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ object DException {
case object InvalidOperands extends Kind
case object NotCallable extends Kind
case object IncorrectArity extends Kind
case object DoesNotHaveProperties extends Kind

def apply(kind: Kind, env: Env): DException =
new DException(kind, env)
Expand Down
26 changes: 14 additions & 12 deletions src/main/scala/com/melvic/dry/result/Failure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ object Failure {
final case class UndefinedVariable(token: Token, message: String) extends RuntimeError
final case class NotCallable(token: Token, message: String) extends RuntimeError
final case class IncorrectArity(token: Token, message: String) extends RuntimeError
final case class DoesNotHaveProperties(obj: Expr, token: Token) extends RuntimeError
final case class DoesNotHaveProperties(token: Token, message: String) extends RuntimeError
final case class UndefinedProperty(token: Token) extends RuntimeError
final case class UndefinedKey(key: Expr, token: Token) extends RuntimeError
final case class CanNotApplyIndexOperator(obj: Expr, token: Token) extends RuntimeError
Expand Down Expand Up @@ -111,8 +111,11 @@ object Failure {
def incorrectArity(token: Token, expected: Int, got: Int): RuntimeError =
incorrectArity(token, s"Incorrect arity. Expected: $expected. Got: $got")

def doesNotHaveProperties(token: Token, message: String): RuntimeError =
DoesNotHaveProperties(token, message)

def doesNotHaveProperties(obj: Expr, token: Token): RuntimeError =
DoesNotHaveProperties(obj, token)
doesNotHaveProperties(token, show"$obj does not have properties or fields.")

def undefinedProperty(token: Token): RuntimeError =
UndefinedProperty(token)
Expand All @@ -137,16 +140,15 @@ object Failure {

// TODO: Once all runtime errors get their own message fields, refactor this
def show: Show[RuntimeError] = {
case DivisionByZero(token, msg) => errorMsg(token, msg)
case InvalidOperand(token, message) => errorMsg(token, message)
case InvalidOperands(token, message) => errorMsg(token, message)
case UndefinedVariable(token, msg) => errorMsg(token, msg)
case NotCallable(token, message) => errorMsg(token, message)
case IncorrectArity(token, message) => errorMsg(token, message)
case DoesNotHaveProperties(obj, token) =>
errorMsg(token, show"$obj does not have properties or fields.")
case UndefinedProperty(token) => errorMsg(token, show"Undefined property: $token")
case UndefinedKey(key, token) => errorMsg(token, show"Undefined key: $key")
case DivisionByZero(token, msg) => errorMsg(token, msg)
case InvalidOperand(token, message) => errorMsg(token, message)
case InvalidOperands(token, message) => errorMsg(token, message)
case UndefinedVariable(token, msg) => errorMsg(token, msg)
case NotCallable(token, message) => errorMsg(token, message)
case IncorrectArity(token, message) => errorMsg(token, message)
case DoesNotHaveProperties(token, message) => errorMsg(token, message)
case UndefinedProperty(token) => errorMsg(token, show"Undefined property: $token")
case UndefinedKey(key, token) => errorMsg(token, show"Undefined key: $key")
case CanNotApplyIndexOperator(obj, token) =>
errorMsg(token, show"Can not apply [] operator to $obj")
case IndexOutOfBounds(index, line) =>
Expand Down
4 changes: 4 additions & 0 deletions src/test/scala/com/melvic/dry/tests/ExceptionsSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ class ExceptionsSpec extends AnyFlatSpec with should.Matchers with ScalaCheckPro
checkException("IncorrectArity")(RuntimeError.incorrectArity)
}

"Raising a DoesNotHaveProperties exception" should "return a runtime error" in {
checkException("DoesNotHaveProperties")(RuntimeError.doesNotHaveProperties)
}

def checkException(exception: String)(error: (Token, String) => RuntimeError): Unit = {
val errorMsg = "No money for you!"

Expand Down

0 comments on commit bcf90a1

Please sign in to comment.