-
-
Save hawkw/36d354c634d0e5e4eb14 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
/** | |
* USL - Useless Stack Language | |
*/ | |
import scala.collection.mutable | |
object USL { | |
/******************** | |
* Handling USL Data | |
********************/ | |
abstract class Dat | |
case class Number(n: Float) extends Dat { | |
override def toString(): String = { | |
return s"$n" | |
} | |
} | |
case class Ident(s: String) extends Dat { | |
override def toString(): String = { | |
return s | |
} | |
} | |
case class Obj(contents: List[Dat]) extends Dat | |
val DatStack = mutable.Stack[Dat]() | |
type IStream = List[Dat] | |
val Definitions = mutable.Map[Ident, Dat]() | |
/** | |
* Not functional (as in FP) at ALL. | |
* This is an Imperative Function; there's probably a better way to do this. | |
* @param strings The strings to iterate over, starting with the string '{' | |
* @return The location of the first matching closing brace for the top level brace at index 0 in strings | |
*/ | |
def matchbrace(strings: Array[String]): Int = { | |
var depth: Int = 0 | |
var i: Int = 0 | |
for(s <- strings) { | |
i += 1 | |
if(s == "{") depth += 1 | |
if(s == "}") depth -= 1 | |
if(depth == 0) return i | |
} | |
return -1 //whoops? | |
} | |
//also the worst approach | |
def mkStream(s: String): List[Dat] = { | |
if(s.length() < 1) return List[Dat]() | |
val q: Array[String] = s.split("\\s+") | |
if(q(0) == "{") { | |
val d: Int = matchbrace(q) | |
return Obj(q.slice(1,d-1).map(Ident(_)).toList) :: mkStream(q.slice(d,q.length).mkString(" ")) ::: Nil | |
} else if(q(0).matches("\\d+\\.?\\d*")) { | |
return Number(java.lang.Float.parseFloat(q(0))) :: mkStream(q.slice(1,q.length).mkString(" ")) ::: Nil | |
} else { | |
return Ident(q(0)) :: mkStream(q.slice(1,q.length).mkString(" ")) ::: Nil | |
} | |
} | |
def evalOne(): Boolean = { | |
if(DatStack.isEmpty) return false | |
DatStack.top match { | |
case Ident("+") => { | |
DatStack.pop() | |
val a = DatStack.pop().asInstanceOf[Number] | |
val b = DatStack.pop().asInstanceOf[Number] | |
DatStack.push(Number(a.n + b.n)) | |
true | |
} | |
case Ident("-") => { | |
DatStack.pop() | |
val b = DatStack.pop().asInstanceOf[Number] | |
val a = DatStack.pop().asInstanceOf[Number] | |
DatStack.push(Number(a.n - b.n)) | |
true | |
} | |
case Ident("fl") => { | |
DatStack.pop() | |
val a = DatStack.pop() | |
val b = DatStack.pop() | |
DatStack.push(a) | |
DatStack.push(b) | |
true | |
} | |
case Ident("lup") => { | |
DatStack.pop() | |
if(DatStack.top.isInstanceOf[Ident]) { | |
val i = DatStack.pop().asInstanceOf[Ident] | |
Definitions.get(i) match { | |
case Some(g) => DatStack.push(g) | |
case None => DatStack.push(i) | |
} | |
true | |
} else if(DatStack.top.isInstanceOf[Obj]) { | |
val o = DatStack.pop().asInstanceOf[Obj] | |
o.contents.reverse.foreach(DatStack.push(_)) | |
true | |
} else { | |
true | |
} | |
} | |
case Ident("dup") => { | |
DatStack.pop() | |
DatStack.push(DatStack.top) | |
true | |
} | |
case Ident("ident?") => { | |
DatStack.pop() | |
if(DatStack.pop().isInstanceOf[Ident]) { | |
DatStack.push(Number(1)) | |
} else { | |
DatStack.push(Number(0)) | |
} | |
true | |
} | |
case Ident("obj?") => { | |
DatStack.pop() | |
if(DatStack.pop().isInstanceOf[Obj]) { | |
DatStack.push(Number(1)) | |
} else { | |
DatStack.push(Number(0)) | |
} | |
true | |
} | |
case Ident("if") => { | |
DatStack.pop() | |
val test = DatStack.pop() | |
val falsey = DatStack.pop().asInstanceOf[Obj] | |
val truthy = DatStack.pop().asInstanceOf[Obj] | |
val put = test match { | |
case Number(0) => falsey | |
case _ => truthy | |
} | |
put.contents.reverse.foreach({ | |
DatStack.push(_) | |
}) | |
true | |
} | |
case Ident("undef") => { | |
DatStack.pop() | |
val l = DatStack.pop().asInstanceOf[Obj] | |
l.contents.reverse.foreach({ | |
case s: Ident => Definitions.remove(s) | |
case _ => | |
}) | |
true | |
} | |
case Ident("print") => { | |
DatStack.pop() | |
println(DatStack.top) | |
true | |
} | |
case Ident("drop") => { | |
DatStack.pop() | |
DatStack.pop() | |
true | |
} | |
case Ident("clear") => { | |
DatStack.clear() | |
false | |
} | |
case Ident("def") => { | |
DatStack.pop() | |
val bind = DatStack.pop() | |
val name = DatStack.pop().asInstanceOf[Ident] | |
Definitions.put(name, bind) | |
true | |
} | |
case _ => false | |
} | |
} | |
def run(s: IStream): Unit = { | |
if(s.length == 0) { | |
println("> " + DatStack) | |
return | |
} | |
val top = s.head | |
if(top.isInstanceOf[Ident] && Definitions.contains(top.asInstanceOf[Ident])) { | |
val pack = Definitions.get(top.asInstanceOf[Ident]).get | |
pack match { | |
case Obj(l) => run(l ::: s.tail) | |
case _ => run(Definitions.get(top.asInstanceOf[Ident]).get :: s.tail) | |
} | |
} else { | |
DatStack.push(top) | |
while (evalOne()) {} | |
if(!DatStack.isEmpty && DatStack.top.isInstanceOf[Ident] && Definitions.contains(DatStack.top.asInstanceOf[Ident])) { | |
run(Definitions.get(DatStack.pop().asInstanceOf[Ident]).get :: s.tail) | |
} else { | |
run(s.tail) | |
} | |
} | |
} | |
def main(args: Array[String]): Unit = { | |
var v = "" | |
while(v != "exit") { | |
v = Console.in.readLine() | |
try { | |
run(mkStream(v)) | |
} catch { | |
case e: Throwable => println(e) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment