Skip to content

Commit

Permalink
rewriting WanderValue to be a enum, closes #409
Browse files Browse the repository at this point in the history
  • Loading branch information
almibe committed May 8, 2023
1 parent 62515bb commit b45a043
Show file tree
Hide file tree
Showing 10 changed files with 145 additions and 148 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@

package dev.ligature.wander

import dev.ligature.wander.{Name, ScriptError, WanderValue}
import dev.ligature.wander.NativeFunction
import dev.ligature.wander.{ScriptError, WanderValue}

case class Bindings(scopes: List[Map[Name, WanderValue]] = List((Map()))) {
case class Bindings(scopes: List[Map[WanderValue.Name, WanderValue]] = List((Map()))) {
def newScope(): Bindings = Bindings(this.scopes.appended(Map()))

def bindVariable(
name: Name,
name: WanderValue.Name,
wanderValue: WanderValue
): Either[ScriptError, Bindings] = {
val currentScope = this.scopes.last
Expand All @@ -27,7 +26,7 @@ case class Bindings(scopes: List[Map[Name, WanderValue]] = List((Map()))) {
}
}

def read(name: Name): Either[ScriptError, WanderValue] = {
def read(name: WanderValue.Name): Either[ScriptError, WanderValue] = {
var currentScopeOffset = this.scopes.length - 1
while (currentScopeOffset >= 0) {
val currentScope = this.scopes(currentScopeOffset)
Expand Down
43 changes: 21 additions & 22 deletions wander/shared/src/main/scala/dev/ligature/wander/Modes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,22 @@
package dev.ligature.wander

import dev.ligature.wander.WanderValue
import dev.ligature.wander.{Name, NativeFunction, Parameter, BooleanValue, ScriptResult, ScriptError}
import dev.ligature.wander.{Parameter, ScriptResult, ScriptError}

import dev.ligature.{Ligature, Dataset}
import dev.ligature.wander.WanderType
import dev.ligature.wander.LigatureValue
import dev.ligature.Identifier

def instanceMode(instance: Ligature): Bindings = {
var bindings = common()

bindings = bindings.bindVariable(Name("datasets"), NativeFunction(
bindings = bindings.bindVariable(WanderValue.Name("datasets"), WanderValue.NativeFunction(
List(),
(arguments: Seq[Term], binding: Bindings) => Right(LigatureValue(Identifier.fromString("test").getOrElse(???)))
(arguments: Seq[Term], binding: Bindings) => Right(WanderValue.LigatureValue(Identifier.fromString("test").getOrElse(???)))
)).getOrElse(???)

bindings = bindings.bindVariable(Name("addDataset"), NativeFunction(
List(Parameter(Name("message"), WanderType.String)),
bindings = bindings.bindVariable(WanderValue.Name("addDataset"), WanderValue.NativeFunction(
List(Parameter(WanderValue.Name("message"), WanderType.String)),
(arguments: Seq[Term], binding: Bindings) => ???
)).getOrElse(???)

Expand Down Expand Up @@ -59,37 +58,37 @@ def common(): Bindings = {

stdLib = stdLib
.bindVariable(
Name("not"),
NativeFunction(
List(Parameter(Name("bool"), WanderType.Boolean)),
WanderValue.Name("not"),
WanderValue.NativeFunction(
List(Parameter(WanderValue.Name("bool"), WanderType.Boolean)),
(arguments: Seq[Term], bindings: Bindings) =>
if arguments.size != 1 then
Left(ScriptError("`not` function requires 1 argument."))
else
val evaledArgs = arguments.map(evalTerm(_, bindings))
evaledArgs.headOption match
case Some(Right(EvalResult(b: BooleanValue, _))) => Right(BooleanValue(!b.value))
case Some(Right(EvalResult(b: WanderValue.BooleanValue, _))) => Right(WanderValue.BooleanValue(!b.value))
case _ => Left(ScriptError("`not` function requires 1 boolean argument."))
)
)
.getOrElse(???)

stdLib = stdLib
.bindVariable(
Name("and"),
NativeFunction(
WanderValue.Name("and"),
WanderValue.NativeFunction(
List(
Parameter(Name("boolLeft"), WanderType.Boolean),
Parameter(Name("boolRight"), WanderType.Boolean)
Parameter(WanderValue.Name("boolLeft"), WanderType.Boolean),
Parameter(WanderValue.Name("boolRight"), WanderType.Boolean)
),
(arguments: Seq[Term], bindings: Bindings) =>
if arguments.length == 2 then
val evaledArgs = arguments.map(evalTerm(_, bindings))
val left = evaledArgs(0) //bindings.read(Name("boolLeft"))
val right = evaledArgs(1) //bindings.read(Name("boolRight"))
(left, right) match {
case (Right(EvalResult(l: BooleanValue, _)), Right(EvalResult(r: BooleanValue, _))) =>
Right(BooleanValue(l.value && r.value))
case (Right(EvalResult(l: WanderValue.BooleanValue, _)), Right(EvalResult(r: WanderValue.BooleanValue, _))) =>
Right(WanderValue.BooleanValue(l.value && r.value))
case _ => Left(ScriptError("`and` function requires two booleans"))
}
else
Expand All @@ -100,20 +99,20 @@ def common(): Bindings = {

stdLib = stdLib
.bindVariable(
Name("or"),
NativeFunction(
WanderValue.Name("or"),
WanderValue.NativeFunction(
List(
Parameter(Name("boolLeft"), WanderType.Boolean),
Parameter(Name("boolRight"), WanderType.Boolean)
Parameter(WanderValue.Name("boolLeft"), WanderType.Boolean),
Parameter(WanderValue.Name("boolRight"), WanderType.Boolean)
),
(arguments: Seq[Term], bindings: Bindings) =>
if arguments.length == 2 then
val evaledArgs = arguments.map(evalTerm(_, bindings))
val left = evaledArgs(0) // bindings.read(Name("boolLeft"))
val right = evaledArgs(1) //bindings.read(Name("boolRight"))
(left, right) match {
case (Right(EvalResult(l: BooleanValue, _)), Right(EvalResult(r: BooleanValue, _))) =>
Right(BooleanValue(l.value || r.value))
case (Right(EvalResult(l: WanderValue.BooleanValue, _)), Right(EvalResult(r: WanderValue.BooleanValue, _))) =>
Right(WanderValue.BooleanValue(l.value || r.value))
case _ => Left(ScriptError("`or` function requires two booleans"))
}
else
Expand Down
14 changes: 7 additions & 7 deletions wander/shared/src/main/scala/dev/ligature/wander/Parser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,21 @@ enum Term:

def evalTerm(term: Term, bindings: Bindings): Either[ScriptError, EvalResult] =
term match
case Term.BooleanLiteral(value) => Right(EvalResult(BooleanValue(value), bindings))
case Term.IdentifierLiteral(value) => Right(EvalResult(LigatureValue(value), bindings))
case Term.IntegerLiteral(value) => Right(EvalResult(LigatureValue(LigatureLiteral.IntegerLiteral(value)), bindings))
case Term.StringLiteral(value) => Right(EvalResult(LigatureValue(LigatureLiteral.StringLiteral(value)), bindings))
case Term.BooleanLiteral(value) => Right(EvalResult(WanderValue.BooleanValue(value), bindings))
case Term.IdentifierLiteral(value) => Right(EvalResult(WanderValue.LigatureValue(value), bindings))
case Term.IntegerLiteral(value) => Right(EvalResult(WanderValue.LigatureValue(LigatureLiteral.IntegerLiteral(value)), bindings))
case Term.StringLiteral(value) => Right(EvalResult(WanderValue.LigatureValue(LigatureLiteral.StringLiteral(value)), bindings))
case Term.Name(value) => ???
case Term.FunctionCall(name, arguments) =>
//TODO val evaldArgs = evalArguments(arguments)
bindings.read(Name(name.value)) match {
bindings.read(WanderValue.Name(name.value)) match {
case Left(value) => Left(value)
case Right(value) =>
value match {
case NativeFunction(parameters, body, output) => {
case WanderValue.NativeFunction(parameters, body, output) => {
body(arguments, bindings).map { value => EvalResult(value, bindings) }
}
case WanderFunction(parameters, body, output) => ???
case WanderValue.WanderFunction(parameters, body, output) => ???
case _ => ???
}
}
Expand Down
162 changes: 83 additions & 79 deletions wander/shared/src/main/scala/dev/ligature/wander/Syntax.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,75 +14,89 @@ import cats.Eval

/** Represents the union of Statements and Expressions
*/
sealed trait Element {
def eval(bindings: Bindings): Either[ScriptError, EvalResult]
}
// sealed trait Element {
// def eval(bindings: Bindings): Either[ScriptError, EvalResult]
// }

/** An element of a Wander program that can be evaluated for a value.
*/
sealed trait Expression extends Element

/** Represents a Value in the Wander language.
*/
sealed trait WanderValue extends Expression
//sealed trait Expression extends Element

case class ScriptError(message: String)
case class ScriptResult(result: WanderValue)
case class EvalResult(result: WanderValue, bindings: Bindings)

/** Represents a Value in the Wander language.
*/
enum WanderValue:
case Name(name: String)
case LigatureValue(value: Value)
case BooleanValue(value: Boolean)
case Nothing
case NativeFunction(
parameters: List[Parameter],
body: (arguments: Seq[Term], bindings: Bindings) => Either[ScriptError, WanderValue],
output: WanderType = null)
case WanderFunction(
parameters: List[Parameter],
output: WanderType,
body: Scope)
case Scope(elements: List[Term])


/** Represents a Name in the Wander language.
*/
final case class Name(name: String) extends Expression {
override def eval(bindings: Bindings) =
bindings.read(this) match {
case Left(err) => Left(err)
case Right(value) => Right(EvalResult(value, bindings))
}
}
// final case class Name(name: String) extends Expression {
// override def eval(bindings: Bindings) =
// bindings.read(this) match {
// case Left(err) => Left(err)
// case Right(value) => Right(EvalResult(value, bindings))
// }
// }

sealed trait FunctionDefinition(val parameters: List[Parameter]) extends WanderValue
//sealed trait FunctionDefinition(val parameters: List[Parameter]) extends WanderValue

case class LigatureValue(value: Value) extends WanderValue {
override def eval(bindings: Bindings) = Right(
EvalResult(LigatureValue(value), bindings)
)
}
// case class LigatureValue(value: Value) extends WanderValue {
// override def eval(bindings: Bindings) = Right(
// EvalResult(LigatureValue(value), bindings)
// )
// }

case class BooleanValue(value: Boolean) extends WanderValue {
override def eval(bindings: Bindings) = Right(
EvalResult(BooleanValue(value), bindings)
)
}
// case class BooleanValue(value: Boolean) extends WanderValue {
// override def eval(bindings: Bindings) = Right(
// EvalResult(BooleanValue(value), bindings)
// )
// }

object Nothing extends WanderValue {
override def eval(bindings: Bindings) = Right(EvalResult(Nothing, bindings))
}
// object Nothing extends WanderValue {
// override def eval(bindings: Bindings) = Right(EvalResult(Nothing, bindings))
// }

case class ResultStream(stream: Stream[IO, WanderValue]) extends WanderValue {
override def eval(binding: Bindings) = ???
}
// case class ResultStream(stream: Stream[IO, WanderValue]) extends WanderValue {
// override def eval(binding: Bindings) = ???
// }

/** Holds a reference to a function defined in Scala that can be called from
* Wander.
*/
case class NativeFunction(
override val parameters: List[Parameter],
body: (arguments: Seq[Term], bindings: Bindings) => Either[ScriptError, WanderValue],
output: WanderType = null
) extends FunctionDefinition(parameters) { // TODO eventually remove the default null value
override def eval(binding: Bindings) =
// body(binding) match {
// case Left(err) => Left(err)
// case Right(res) => Right(EvalResult(binding, res))
// }
Right(EvalResult(this, binding))
}
// case class NativeFunction(
// override val parameters: List[Parameter],
// body: (arguments: Seq[Term], bindings: Bindings) => Either[ScriptError, WanderValue],
// output: WanderType = null
// ) extends FunctionDefinition(parameters) { // TODO eventually remove the default null value
// override def eval(binding: Bindings) =
// // body(binding) match {
// // case Left(err) => Left(err)
// // case Right(res) => Right(EvalResult(binding, res))
// // }
// Right(EvalResult(this, binding))
// }

/** Represents a full script that can be eval'd.
*/
case class Script(val terms: Seq[Term]) {
def eval(bindings: Bindings): Either[ScriptError, ScriptResult] = {
var result: WanderValue = Nothing
var result: WanderValue = WanderValue.Nothing
var currentBindings: Bindings = bindings
terms.foreach { term =>
evalTerm(term,currentBindings) match {
Expand All @@ -99,21 +113,21 @@ case class Script(val terms: Seq[Term]) {
/** Represents a scope in Wander that can be eval'd and can contain it's own
* bindings.
*/
case class Scope(val elements: List[Term]) extends Expression {
def eval(bindings: Bindings) = {
var currentBindings = bindings.newScope()
var result: WanderValue = Nothing
elements.foreach { element =>
evalTerm(element, currentBindings) match {
case Left(err) => return Left(err)
case Right(res) =>
result = res.result
currentBindings = res.bindings
}
}
Right(EvalResult(result, bindings))
}
}
// case class Scope(val elements: List[Term]) extends Expression {
// def eval(bindings: Bindings) = {
// var currentBindings = bindings.newScope()
// var result: WanderValue = Nothing
// elements.foreach { element =>
// evalTerm(element, currentBindings) match {
// case Left(err) => return Left(err)
// case Right(res) =>
// result = res.result
// currentBindings = res.bindings
// }
// }
// Right(EvalResult(result, bindings))
// }
// }

enum WanderType {
case Value
Expand All @@ -125,20 +139,20 @@ enum WanderType {
}

case class Parameter(
name: Name,
name: WanderValue.Name,
parameterType: WanderType
)

/** Holds a reference to a function defined in Wander.
*/
case class WanderFunction(
override val parameters: List[Parameter],
output: WanderType,
body: Scope
) extends FunctionDefinition(parameters) {
override def eval(bindings: Bindings) =
Right(EvalResult(this, bindings))
}
// case class WanderFunction(
// override val parameters: List[Parameter],
// output: WanderType,
// body: Scope
// ) extends FunctionDefinition(parameters) {
// override def eval(bindings: Bindings) =
// Right(EvalResult(this, bindings))
// }

// case class FunctionCall(val name: Name, val parameters: List[Expression]) extends Expression {
// def eval(bindings: Bindings) = {
Expand Down Expand Up @@ -224,13 +238,3 @@ case class WanderFunction(
// // }
// // }
// }

// case class ElseIf(val condition: Expression, val body: Expression) {
// def eval(bindings: Bindings) = // TODO is this needed?
// ???
// }

// case class Else(val body: Expression) {
// def eval(bindings: Bindings) = // TODO is this needed?
// ???
// }
Loading

0 comments on commit b45a043

Please sign in to comment.