Skip to content

Instantly share code, notes, and snippets.

@ArcticLight
Last active August 29, 2015 14:08
Show Gist options
  • Save ArcticLight/48936602869e470e272d to your computer and use it in GitHub Desktop.
Save ArcticLight/48936602869e470e272d to your computer and use it in GitHub Desktop.
USL
/**
* 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)
}
}
}
}
@hawkw
Copy link

hawkw commented Nov 4, 2014

I also really like how mkStream returns a List[Dat] and not, you know, a Stream[Dat] or something. :P

@ArcticLight
Copy link
Author

it's almost a programming language now! (if only { would nest deeper....)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment