Last active
August 29, 2015 14:08
-
-
Save ArcticLight/48936602869e470e272d to your computer and use it in GitHub Desktop.
USL
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
it's almost a programming language now! (if only { would nest deeper....)