Created
November 7, 2011 15:56
-
-
Save jbilcke/1345341 to your computer and use it in GitHub Desktop.
Push.coffee
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
#/***************************************************************************** | |
# * * | |
# * PushScript * | |
# * Copyright (C) 2008-2010 Jonathan Klein * | |
# * * | |
# * This program is free software; you can redistribute it and/or modify * | |
# * it under the terms of the GNU General Public License as published by * | |
# * the Free Software Foundation; either version 2 of the License, or * | |
# * (at your option) any later version. * | |
# * * | |
# * This program is distributed in the hope that it will be useful, * | |
# * but WITHOUT ANY WARRANTY; without even the implied warranty of * | |
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |
# * GNU General Public License for more details. * | |
# * * | |
# * You should have received a copy of the GNU General Public License * | |
# * along with this program; if not, write to the Free Software * | |
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * | |
# *****************************************************************************/ | |
# | |
# Push types | |
# | |
# slight modification to built-in types to lets us compare them like program | |
pushFloat = (inValue) -> | |
@_value = inValue | |
@toString = -> | |
decimal = /\./ | |
unless decimal.test(@_value) | |
@_value + ".0" | |
else | |
@_value | |
@equals = (inOther) -> | |
isPushFloat(inOther) and @_value == inOther._value | |
pushInt = (inValue) -> | |
@_value = inValue | |
@toString = -> | |
@_value | |
@equals = (inOther) -> | |
isPushInt(inOther) and @_value == inOther._value | |
pushInstruction = (inStack, inFunction) -> | |
@_function = inFunction | |
@_stack = inStack | |
@call = (inInterpreter) -> | |
@_function inInterpreter, @_stack | |
pushDefine = (inStack, inValue) -> | |
@_value = inValue | |
@_stack = inStack | |
@call = (inInterpreter) -> | |
@_stack.push @_value | |
isPushProgram = (inObject) -> | |
typeof (inObject) == "object" and inObject["_isPushProgram"] == true | |
isPushFloat = (inObject) -> | |
typeof (inObject) == "object" and inObject.constructor == pushFloat | |
isPushInt = (inObject) -> | |
typeof (inObject) == "object" and inObject.constructor == pushInt | |
isPushInstruction = (inObject) -> | |
typeof (inObject) == "object" and inObject.constructor == pushInstruction | |
isPushDefine = (inObject) -> | |
typeof (inObject) == "object" and inObject.constructor == pushDefine | |
pushInstructionRandomBool = (inInterpreter, inStack) -> | |
inStack.push Math.random() > 0.5 | |
pushInstructionRandomNumber = (inInterpreter, inStack) -> | |
inStack.push Math.random() * 10 | |
pushInstructionRandomName = (inInterpreter, inStack) -> | |
inStack.push "n" + inInterpreter._nameCounter++ | |
pushInstructionRandomBoundName = (inInterpreter, inStack) -> | |
pushInstructionAnd = (inInterpreter, inStack) -> | |
if inStack.length > 1 | |
o1 = inStack.pop() | |
o2 = inStack.pop() | |
inInterpreter.boolStack.push o2 and o1 | |
pushInstructionOr = (inInterpreter, inStack) -> | |
if inStack.length > 1 | |
o1 = inStack.pop() | |
o2 = inStack.pop() | |
inInterpreter.boolStack.push o2 or o1 | |
pushInstructionNot = (inInterpreter, inStack) -> | |
inInterpreter.boolStack.push not inStack.pop() if inStack.length > 0 | |
pushInstructionFromInteger = (inInterpreter, inStack) -> | |
inStack.push inInterpreter.intStack.pop() if inStack.length > 0 | |
pushInstructionFromFloat = (inInterpreter, inStack) -> | |
inStack.push inInterpreter.floatStack.pop() if inStack.length > 0 | |
pushInstructionFromBoolean = (inInterpreter, inStack) -> | |
if inStack.length > 0 | |
num = 0 | |
num = 1 if inInterpreter.boolStack.pop() == true | |
inStack.push num | |
pushInstructionQuote = (inInterpreter, inStack) -> | |
inStack.push inInterpreter.execStack.pop() if inInterpreter.execStack.length > 0 | |
pushInstructionCar = (inInterpreter, inStack) -> | |
if inStack.length > 0 | |
top = inStack.pop() | |
if isPushProgram(top) | |
inStack.push top.shift() | |
else | |
inStack.push top | |
pushInstructionCdr = (inInterpreter, inStack) -> | |
if inStack.length > 0 | |
top = inStack.pop() | |
if isPushProgram(top) | |
top.shift() | |
inStack.push top | |
else | |
inStack.push new Array() | |
pushInstructionNth = (inInterpreter, inStack) -> | |
if inStack.length > 0 and inInterpreter.intStack.length > 0 | |
top = inStack.pop() | |
index = inInterpreter.intStack.pop() | |
if isPushProgram(top) | |
index %= top.length | |
inStack.push top[(top.length - 1) - index] | |
else | |
inStack.push top | |
pushInstructionContains = (inInterpreter, inStack) -> | |
if inStack.length > 1 | |
program = inStack.pop() | |
sub = inStack.pop() | |
i = 0 | |
while i < program.length | |
if program[i].equals(sub) | |
inInterpreter.boolStack.push true | |
return | |
i++ | |
inInterpreter.boolStack.push false | |
pushInstructionList = (inInterpreter, inStack) -> | |
if inStack.length > 1 | |
o1 = inStack.pop() | |
o2 = inStack.pop() | |
newCode = new Array() | |
newCode.push o2 | |
newCode.push o1 | |
inStack.push newCode | |
pushInstructionCons = (inInterpreter, inStack) -> | |
if inStack.length > 1 | |
cdr = inStack.pop() | |
car = inStack.pop() | |
unless isPushProgram(cdr) | |
program = new Array() | |
program.push cdr | |
cdr = program | |
cdr.unshift car | |
inStack.push cdr | |
pushInstructionNoop = (inInterpreter, inStack) -> | |
pushInstructionDo = (inInterpreter, inStack) -> | |
if inInterpreter.codeStack.length > 0 | |
inInterpreter.execStack.push "CODE.POP" | |
inInterpreter.execStack.push inInterpreter.codeStack[inInterpreter.codeStack.length - 1] | |
pushInstructionDoStar = (inInterpreter, inStack) -> | |
inInterpreter.execStack.push inInterpreter.codeStack.pop() if inInterpreter.codeStack.length > 0 | |
pushInstructionDoCount = (inInterpreter, inStack) -> | |
if inStack.length > 0 and inInterpreter.intStack.length > 0 | |
count = inInterpreter.intStack.pop() | |
return if count < 1 | |
code = inStack.pop() | |
program = new Array() | |
program.push new pushInt(0) | |
program.push new pushInt(count - 1) | |
program.push "EXEC.DO*RANGE" | |
program.push code | |
inInterpreter.execStack.push program | |
pushInstructionDoTimes = (inInterpreter, inStack) -> | |
if inStack.length > 0 and inInterpreter.intStack.length > 1 | |
code = inStack.pop() | |
unless isPushProgram(code) | |
program = new Array() | |
program.push code | |
code = program | |
code.splice 0, 0, "INTEGER.POP" | |
inStack.push code | |
pushInstructionDoRange inInterpreter, inStack | |
pushInstructionDoRange = (inInterpreter, inStack) -> | |
if inStack.length > 0 and inInterpreter.intStack.length > 1 | |
end = inInterpreter.intStack.pop() | |
start = inInterpreter.intStack.pop() | |
code = inStack.pop() | |
inc = 1 | |
inc = -1 if end > start | |
i = end | |
while i != start + inc | |
inInterpreter.execStack.push code | |
inInterpreter.execStack.push new pushInt(i) | |
i += inc | |
pushInstructionIf = (inInterpreter, inStack) -> | |
if inStack.length > 1 and inInterpreter.boolStack.length > 0 | |
cond = inInterpreter.boolStack.pop() | |
ifFalse = inStack.pop() | |
ifTrue = inStack.pop() | |
if cond | |
inInterpreter.execStack.push ifTrue | |
else | |
inInterpreter.execStack.push ifFalse | |
pushInstructionLength = (inInterpreter, inStack) -> | |
if inStack.length > 0 | |
code = inStack.pop() | |
inInterpreter.intStack.push code.length | |
pushInstructionNull = (inInterpreter, inStack) -> | |
if inStack.length > 0 | |
code = inStack.pop() | |
inInterpreter.boolStack.push isPushProgram(code) and code.length == 0 | |
pushInstructionAtom = (inInterpreter, inStack) -> | |
inInterpreter.boolStack.push not isPushProgram(inStack.pop()) if inStack.length > 0 | |
pushInstructionK = (inInterpreter, inStack) -> | |
inStack.splice inStack.length - 1, 1 if inStack.length > 1 | |
pushInstructionS = (inInterpreter, inStack) -> | |
if inStack.length > 2 | |
a = inStack.pop() | |
b = inStack.pop() | |
c = inStack.pop() | |
list = new Array() | |
list.push b | |
list.push c | |
inStack.push list | |
inStack.push c | |
inStack.push a | |
pushInstructionY = (inInterpreter, inStack) -> | |
if inStack.length > 0 | |
top = inStack.pop() | |
list = new Array() | |
list.push "EXEC.Y" | |
list.push top | |
pushInstructionGreaterThan = (inInterpreter, inStack) -> | |
if inStack.length > 1 | |
o1 = inStack.pop() | |
o2 = inStack.pop() | |
inInterpreter.boolStack.push o2 > o1 | |
pushInstructionLessThan = (inInterpreter, inStack) -> | |
if inStack.length > 1 | |
o1 = inStack.pop() | |
o2 = inStack.pop() | |
inInterpreter.boolStack.push o2 < o1 | |
pushInstructionEquals = (inInterpreter, inStack) -> | |
if inStack.length > 1 | |
o1 = inStack.pop() | |
o2 = inStack.pop() | |
inInterpreter.boolStack.push o2.equals(o1) | |
pushInstructionAdd = (inInterpreter, inStack) -> | |
if inStack.length > 1 | |
o1 = inStack.pop() | |
o2 = inStack.pop() | |
inStack.push o2 + o1 | |
pushInstructionSubtract = (inInterpreter, inStack) -> | |
if inStack.length > 1 | |
o1 = inStack.pop() | |
o2 = inStack.pop() | |
inStack.push o2 - o1 | |
pushInstructionCos = (inInterpreter, inStack) -> | |
inStack.push Math.cos(inStack.pop()) if inStack.length > 0 | |
pushInstructionSin = (inInterpreter, inStack) -> | |
inStack.push Math.sin(inStack.pop()) if inStack.length > 0 | |
pushInstructionTan = (inInterpreter, inStack) -> | |
inStack.push Math.tan(inStack.pop()) if inStack.length > 0 | |
pushInstructionMultiply = (inInterpreter, inStack) -> | |
if inStack.length > 1 | |
o1 = inStack.pop() | |
o2 = inStack.pop() | |
inStack.push o2 * o1 | |
pushInstructionDivide = (inInterpreter, inStack) -> | |
if inStack.length > 1 | |
o1 = inStack.pop() | |
if o1 == 0.0 | |
inStack.push o1 | |
return | |
o2 = inStack.pop() | |
inStack.push o2 / o1 | |
pushInstructionModulus = (inInterpreter, inStack) -> | |
if inStack.length > 1 | |
o1 = inStack.pop() | |
o2 = inStack.pop() | |
inStack.push o2 % o1 | |
pushInstructionMin = (inInterpreter, inStack) -> | |
if inStack.length > 1 | |
o1 = inStack.pop() | |
o2 = inStack.pop() | |
inStack.push Math.min(o1, o2) | |
pushInstructionMax = (inInterpreter, inStack) -> | |
if inStack.length > 1 | |
o1 = inStack.pop() | |
o2 = inStack.pop() | |
inStack.push Math.max(o1, o2) | |
pushInstructionPop = (inInterpreter, inStack) -> | |
inStack.pop() if inStack.length > 0 | |
pushInstructionStackdepth = (inInterpreter, inStack) -> | |
inInterpreter.intStack.push inStack.length | |
pushInstructionDup = (inInterpreter, inStack) -> | |
inStack.push inStack[inStack.length - 1] if inStack.length > 0 | |
pushInstructionDefine = (inInterpreter, inStack) -> | |
inInterpreter[inInterpreter.nameStack.pop()] = new pushDefine(inStack, inStack.pop()) if inStack.length > 0 and inInterpreter.nameStack.length > 0 | |
pushInstructionYank = (inInterpreter, inStack) -> | |
intReq = 1 | |
intReq = 2 if inStack == inInterpreter.intStack | |
if inInterpreter.intStack.length >= intReq and inStack.length > 0 | |
index = inInterpreter.intStack.pop() | |
inStack.push inStack.splice(inStack.length - (index + 1), 1)[0] if index < inStack.length | |
pushInstructionYankDup = (inInterpreter, inStack) -> | |
intReq = 1 | |
intReq = 2 if inStack == inInterpreter.intStack | |
if inInterpreter.intStack.length >= intReq and inStack.length > 0 | |
index = inInterpreter.intStack.pop() | |
inStack.push inStack[inStack.length - (index + 1)] if index < inStack.length | |
pushInstructionShove = (inInterpreter, inStack) -> | |
intReq = 1 | |
intReq = 2 if inStack == inInterpreter.intStack | |
if inInterpreter.intStack.length >= intReq and inStack.length > 0 | |
index = inInterpreter.intStack.pop() | |
if index < inStack.length | |
replace = inStack.pop() | |
inStack.splice inStack.length - index, 0, replace | |
pushInstructionSwap = (inInterpreter, inStack) -> | |
if inStack.length > 1 | |
o1 = inStack.pop() | |
o2 = inStack.pop() | |
inStack.push o1 | |
inStack.push o2 | |
pushInstructionRot = (inInterpreter, inStack) -> | |
if inStack.length > 2 | |
index = inStack.length - 3 | |
inStack.push inStack.splice(index, 1)[0] | |
pushInstructionFlush = (inInterpreter, inStack) -> | |
inStack.splice 0, inStack.length | |
float_input = (inInterpreter) -> | |
inInterpreter.floatStack.push inInterpreter["inputValue"] | |
inInterpreter.intStack.push inInterpreter["inputValue"] | |
pushInterpreter = -> | |
@floatStack = [] | |
@execStack = [] | |
@codeStack = [] | |
@intStack = [] | |
@boolStack = [] | |
@nameStack = [] | |
@_nameCounter = 0 | |
@intStack.push = (inValue) -> | |
@parentpush = Array::push | |
@parentpush parseInt(inValue) | |
@boolStack.push = (inValue) -> | |
@parentpush = Array::push | |
@parentpush inValue != 0 | |
@codeStack.push = (inValue) -> | |
@parentpush = Array::push | |
inValue = inValue.copy() if isPushProgram(inValue) | |
@parentpush inValue | |
@execStack.push = (inValue) -> | |
@parentpush = Array::push | |
inValue = inValue.copy() if isPushProgram(inValue) | |
@parentpush inValue | |
@clearStacks = -> | |
@floatStack.splice 0, @floatStack.length | |
@execStack.splice 0, @execStack.length | |
@codeStack.splice 0, @codeStack.length | |
@intStack.splice 0, @intStack.length | |
@boolStack.splice 0, @boolStack.length | |
@nameStack.splice 0, @nameStack.length | |
@toString = -> | |
text = "Float stack contents: " + @floatStack + "<br>" | |
text += "Int stack contents: " + @intStack + "<br>" | |
text += "Bool stack contents: " + @boolStack + "<br>" | |
text += "Name stack contents: " + @nameStack + "<br>" | |
text += "Code stack contents: " + @codeStack + "<br>" | |
text += "Exec stack contents: " + @execStack + "<br>" | |
text | |
@floatStackTop = -> | |
@floatStack[@floatStack.length - 1] | |
@intStackTop = -> | |
@intStack[@intStack.length - 1] | |
@boolStackTop = -> | |
@boolStack[@boolStack.length - 1] | |
@nameStackTop = -> | |
@boolStack[@nameStack.length - 1] | |
@execStackTop = -> | |
@execStack[@execStack.length - 1] | |
@codeStackTop = -> | |
@codeStack[@codeStack.length - 1] | |
this["INTEGER.FROMFLOAT"] = new pushInstruction(@intStack, pushInstructionFromFloat) | |
this["BOOLEAN.FROMFLOAT"] = new pushInstruction(@boolStack, pushInstructionFromFloat) | |
this["FLOAT.FROMINTEGER"] = new pushInstruction(@floatStack, pushInstructionFromInteger) | |
this["BOOLEAN.FROMINTEGER"] = new pushInstruction(@boolStack, pushInstructionFromInteger) | |
this["FLOAT.FROMBOOLEAN"] = new pushInstruction(@floatStack, pushInstructionFromBoolean) | |
this["INTEGER.FROMBOOLEAN"] = new pushInstruction(@integerStack, pushInstructionFromBoolean) | |
this["FLOAT.COS"] = new pushInstruction(@floatStack, pushInstructionCos) | |
this["FLOAT.SIN"] = new pushInstruction(@floatStack, pushInstructionSin) | |
this["FLOAT.TAN"] = new pushInstruction(@floatStack, pushInstructionTan) | |
this["INTEGER.>"] = new pushInstruction(@intStack, pushInstructionGreaterThan) | |
this["FLOAT.>"] = new pushInstruction(@floatStack, pushInstructionGreaterThan) | |
this["INTEGER.<"] = new pushInstruction(@intStack, pushInstructionLessThan) | |
this["FLOAT.<"] = new pushInstruction(@floatStack, pushInstructionLessThan) | |
this["INTEGER.="] = new pushInstruction(@intStack, pushInstructionEquals) | |
this["FLOAT.="] = new pushInstruction(@floatStack, pushInstructionEquals) | |
this["BOOLEAN.="] = new pushInstruction(@boolStack, pushInstructionEquals) | |
this["NAME.="] = new pushInstruction(@nameStack, pushInstructionEquals) | |
this["EXEC.="] = new pushInstruction(@execStack, pushInstructionEquals) | |
this["CODE.="] = new pushInstruction(@codeStack, pushInstructionEquals) | |
this["INTEGER.+"] = new pushInstruction(@intStack, pushInstructionAdd) | |
this["FLOAT.+"] = new pushInstruction(@floatStack, pushInstructionAdd) | |
this["INTEGER.-"] = new pushInstruction(@intStack, pushInstructionSubtract) | |
this["FLOAT.-"] = new pushInstruction(@floatStack, pushInstructionSubtract) | |
this["INTEGER./"] = new pushInstruction(@intStack, pushInstructionDivide) | |
this["FLOAT./"] = new pushInstruction(@floatStack, pushInstructionDivide) | |
this["INTEGER.*"] = new pushInstruction(@intStack, pushInstructionMultiply) | |
this["FLOAT.*"] = new pushInstruction(@floatStack, pushInstructionMultiply) | |
this["INTEGER.%"] = new pushInstruction(@intStack, pushInstructionModulus) | |
this["FLOAT.%"] = new pushInstruction(@floatStack, pushInstructionModulus) | |
this["INTEGER.MIN"] = new pushInstruction(@intStack, pushInstructionMin) | |
this["FLOAT.MIN"] = new pushInstruction(@floatStack, pushInstructionMin) | |
this["INTEGER.MAX"] = new pushInstruction(@intStack, pushInstructionMax) | |
this["FLOAT.MAX"] = new pushInstruction(@floatStack, pushInstructionMax) | |
this["FLOAT.DEFINE"] = new pushInstruction(@floatStack, pushInstructionDefine) | |
this["INTEGER.DEFINE"] = new pushInstruction(@intStack, pushInstructionDefine) | |
this["CODE.DEFINE"] = new pushInstruction(@codeStack, pushInstructionDefine) | |
this["EXEC.DEFINE"] = new pushInstruction(@execStack, pushInstructionDefine) | |
this["BOOLEAN.DEFINE"] = new pushInstruction(@boolStack, pushInstructionDefine) | |
this["FLOAT.POP"] = new pushInstruction(@floatStack, pushInstructionPop) | |
this["INTEGER.POP"] = new pushInstruction(@intStack, pushInstructionPop) | |
this["CODE.POP"] = new pushInstruction(@codeStack, pushInstructionPop) | |
this["EXEC.POP"] = new pushInstruction(@execStack, pushInstructionPop) | |
this["BOOLEAN.POP"] = new pushInstruction(@boolStack, pushInstructionPop) | |
this["NAME.POP"] = new pushInstruction(@nameStack, pushInstructionPop) | |
this["FLOAT.DUP"] = new pushInstruction(@floatStack, pushInstructionDup) | |
this["INTEGER.DUP"] = new pushInstruction(@intStack, pushInstructionDup) | |
this["CODE.DUP"] = new pushInstruction(@codeStack, pushInstructionDup) | |
this["EXEC.DUP"] = new pushInstruction(@execStack, pushInstructionDup) | |
this["BOOLEAN.DUP"] = new pushInstruction(@boolStack, pushInstructionDup) | |
this["NAME.DUP"] = new pushInstruction(@nameStack, pushInstructionDup) | |
this["FLOAT.YANK"] = new pushInstruction(@floatStack, pushInstructionYank) | |
this["INTEGER.YANK"] = new pushInstruction(@intStack, pushInstructionYank) | |
this["CODE.YANK"] = new pushInstruction(@codeStack, pushInstructionYank) | |
this["EXEC.YANK"] = new pushInstruction(@execStack, pushInstructionYank) | |
this["BOOLEAN.YANK"] = new pushInstruction(@boolStack, pushInstructionYank) | |
this["NAME.YANK"] = new pushInstruction(@nameStack, pushInstructionYank) | |
this["FLOAT.YANKDUP"] = new pushInstruction(@floatStack, pushInstructionYankDup) | |
this["INTEGER.YANKDUP"] = new pushInstruction(@intStack, pushInstructionYankDup) | |
this["CODE.YANKDUP"] = new pushInstruction(@codeStack, pushInstructionYankDup) | |
this["EXEC.YANKDUP"] = new pushInstruction(@execStack, pushInstructionYankDup) | |
this["BOOLEAN.YANKDUP"] = new pushInstruction(@boolStack, pushInstructionYankDup) | |
this["NAME.YANKDUP"] = new pushInstruction(@nameStack, pushInstructionYankDup) | |
this["FLOAT.SHOVE"] = new pushInstruction(@floatStack, pushInstructionShove) | |
this["INTEGER.SHOVE"] = new pushInstruction(@intStack, pushInstructionShove) | |
this["CODE.SHOVE"] = new pushInstruction(@codeStack, pushInstructionShove) | |
this["EXEC.SHOVE"] = new pushInstruction(@execStack, pushInstructionShove) | |
this["BOOLEAN.SHOVE"] = new pushInstruction(@boolStack, pushInstructionShove) | |
this["NAME.SHOVE"] = new pushInstruction(@nameStack, pushInstructionShove) | |
this["FLOAT.ROT"] = new pushInstruction(@floatStack, pushInstructionRot) | |
this["INTEGER.ROT"] = new pushInstruction(@intStack, pushInstructionRot) | |
this["CODE.ROT"] = new pushInstruction(@codeStack, pushInstructionRot) | |
this["EXEC.ROT"] = new pushInstruction(@execStack, pushInstructionRot) | |
this["BOOLEAN.ROT"] = new pushInstruction(@boolStack, pushInstructionRot) | |
this["NAME.ROT"] = new pushInstruction(@nameStack, pushInstructionRot) | |
this["FLOAT.STACKDEPTH"] = new pushInstruction(@floatStack, pushInstructionStackdepth) | |
this["INTEGER.STACKDEPTH"] = new pushInstruction(@intStack, pushInstructionStackdepth) | |
this["CODE.STACKDEPTH"] = new pushInstruction(@codeStack, pushInstructionStackdepth) | |
this["EXEC.STACKDEPTH"] = new pushInstruction(@execStack, pushInstructionStackdepth) | |
this["BOOLEAN.STACKDEPTH"] = new pushInstruction(@boolStack, pushInstructionStackdepth) | |
this["NAME.STACKDEPTH"] = new pushInstruction(@nameStack, pushInstructionStackdepth) | |
this["FLOAT.SWAP"] = new pushInstruction(@floatStack, pushInstructionSwap) | |
this["INTEGER.SWAP"] = new pushInstruction(@intStack, pushInstructionSwap) | |
this["CODE.SWAP"] = new pushInstruction(@codeStack, pushInstructionSwap) | |
this["EXEC.SWAP"] = new pushInstruction(@execStack, pushInstructionSwap) | |
this["BOOLEAN.SWAP"] = new pushInstruction(@boolStack, pushInstructionSwap) | |
this["NAME.SWAP"] = new pushInstruction(@nameStack, pushInstructionSwap) | |
this["FLOAT.FLUSH"] = new pushInstruction(@floatStack, pushInstructionFlush) | |
this["INTEGER.FLUSH"] = new pushInstruction(@intStack, pushInstructionFlush) | |
this["CODE.FLUSH"] = new pushInstruction(@codeStack, pushInstructionFlush) | |
this["EXEC.FLUSH"] = new pushInstruction(@execStack, pushInstructionFlush) | |
this["BOOLEAN.FLUSH"] = new pushInstruction(@boolStack, pushInstructionFlush) | |
this["NAME.FLUSH"] = new pushInstruction(@nameStack, pushInstructionFlush) | |
this["BOOLEAN.AND"] = new pushInstruction(@boolStack, pushInstructionAnd) | |
this["BOOLEAN.OR"] = new pushInstruction(@boolStack, pushInstructionOr) | |
this["BOOLEAN.NOT"] = new pushInstruction(@boolStack, pushInstructionNot) | |
this["CODE.QUOTE"] = new pushInstruction(@codeStack, pushInstructionQuote) | |
this["CODE.CAR"] = new pushInstruction(@codeStack, pushInstructionCar) | |
this["CODE.CDR"] = new pushInstruction(@codeStack, pushInstructionCdr) | |
this["CODE.CONTAINS"] = new pushInstruction(@codeStack, pushInstructionContains) | |
this["CODE.NTH"] = new pushInstruction(@codeStack, pushInstructionNth) | |
this["CODE.LIST"] = new pushInstruction(@codeStack, pushInstructionList) | |
this["CODE.CONS"] = new pushInstruction(@codeStack, pushInstructionCons) | |
this["CODE.DO"] = new pushInstruction(@codeStack, pushInstructionDo) | |
this["CODE.DO*"] = new pushInstruction(@codeStack, pushInstructionDoStar) | |
this["CODE.DO*RANGE"] = new pushInstruction(@codeStack, pushInstructionDoRange) | |
this["CODE.DO*COUNT"] = new pushInstruction(@codeStack, pushInstructionDoCount) | |
this["CODE.DO*TIMES"] = new pushInstruction(@codeStack, pushInstructionDoTimes) | |
this["CODE.IF"] = new pushInstruction(@codeStack, pushInstructionIf) | |
this["CODE.NULL"] = new pushInstruction(@codeStack, pushInstructionNull) | |
this["CODE.ATOM"] = new pushInstruction(@codeStack, pushInstructionAtom) | |
this["CODE.LENGTH"] = new pushInstruction(@codeStack, pushInstructionLength) | |
this["CODE.NOOP"] = new pushInstruction(@codeStack, pushInstructionNoop) | |
this["EXEC.DO*RANGE"] = new pushInstruction(@execStack, pushInstructionDoRange) | |
this["EXEC.DO*TIMES"] = new pushInstruction(@execStack, pushInstructionDoTimes) | |
this["EXEC.DO*COUNT"] = new pushInstruction(@execStack, pushInstructionDoCount) | |
this["EXEC.IF"] = new pushInstruction(@execStack, pushInstructionIf) | |
this["EXEC.S"] = new pushInstruction(@execStack, pushInstructionS) | |
this["EXEC.K"] = new pushInstruction(@execStack, pushInstructionK) | |
this["EXEC.Y"] = new pushInstruction(@execStack, pushInstructionY) | |
this["BOOLEAN.RAND"] = new pushInstruction(@boolStack, pushInstructionRandomBool) | |
this["INTEGER.RAND"] = new pushInstruction(@intStack, pushInstructionRandomNumber) | |
this["FLOAT.RAND"] = new pushInstruction(@floatStack, pushInstructionRandomNumber) | |
this["NAME.RAND"] = new pushInstruction(@nameStack, pushInstructionRandomName) | |
this["TRUE"] = new pushDefine(@boolStack, true) | |
this["FALSE"] = new pushDefine(@boolStack, false) | |
this["INPUT"] = float_input | |
pushRunProgram = (inInterpreter, inProgramArray) -> | |
inInterpreter._effort = 0 | |
test = new Array() | |
inInterpreter.codeStack.push inProgramArray | |
inInterpreter.execStack.push inProgramArray | |
while inInterpreter.execStack.length > 0 | |
atom = inInterpreter.execStack.pop() | |
if isPushProgram(atom) | |
while atom.length > 0 | |
inInterpreter.execStack.push atom.pop() | |
else if isPushFloat(atom) | |
inInterpreter.floatStack.push atom._value | |
else if isPushInt(atom) | |
inInterpreter.intStack.push atom._value | |
else | |
func = inInterpreter[atom] | |
unless func? | |
inInterpreter.nameStack.push atom | |
else if isPushInstruction(func) or isPushDefine(func) | |
func.call inInterpreter | |
else | |
func inInterpreter | |
inInterpreter._effort++ | |
if inInterpreter._effort > 1000 | |
inInterpreter._errorMessage = "Hardcoded effort limit reached (1000 instructions)" | |
inInterpreter._error = 1 | |
return -1 | |
0 | |
pushSetInputValue = (inInterpreter, inValue) -> | |
inInterpreter["inputValue"] = inValue | |
pushFloatStackPush = (inInterpreter, inValue) -> | |
inInterpreter.floatStack.push inValue | |
pushIntStackPush = (inInterpreter, inValue) -> | |
inInterpreter.intStack.push inValue | |
pushParseString = (inString) -> | |
parens = /[\(\)]/ | |
inString = " ( " + inString + " ) " unless parens.test(inString) | |
inString = inString.replace(/([\(\)])/g, " $1 ") | |
inString = inString.replace(/[\r\n]/g, " ") | |
tokens = inString.split(" ") | |
listStack = new Array() | |
currentList = null | |
lastList = null | |
spaces = /\ +/ | |
decimal = /\./ | |
num = 0 | |
i = 0 | |
while i < tokens.length | |
unless spaces.test(tokens[i]) | |
if tokens[i] == "(" | |
listStack.push new Array() | |
currentList = listStack[listStack.length - 1] | |
else if tokens[i] == ")" | |
return null if listStack.length < 1 | |
newList = listStack.pop() | |
lastList = newList | |
currentList = listStack[listStack.length - 1] | |
currentList.push newList if currentList? | |
else if (num = parseFloat(tokens[i])) == tokens[i] | |
return null unless currentList? | |
if decimal.test(tokens[i]) | |
currentList.push new pushFloat(num) | |
else | |
currentList.push new pushInt(num) | |
else unless tokens[i] == "" | |
return null unless currentList? | |
currentList.push tokens[i] | |
i++ | |
return null if listStack.length > 0 | |
lastList | |
# | |
# Parses a string into a program and executes the program with a new interpreter | |
# | |
# @return The string state of the interpreter | |
# | |
pushRunString = (inProgram) -> | |
program = pushParseString(inProgram) | |
interpreter = new pushInterpreter() | |
info = pushRunProgram(interpreter, program) | |
interpreter.toString() | |
String::equals = (inOther) -> | |
inOther == this | |
Boolean::equals = (inOther) -> | |
inOther == this | |
Number::equals = (inOther) -> | |
inOther == this | |
Array::_isPushProgram = true | |
Array::toString = -> | |
str = "" | |
i = 0 | |
while i < @length | |
str += this[i] + " " | |
i++ | |
"( " + str + ")" | |
Array::copy = -> | |
newCopy = new Array() | |
i = 0 | |
while i < @length | |
if isPushProgram(this[i]) | |
newCopy.push this[i].copy() | |
else | |
newCopy.push this[i] | |
i++ | |
newCopy | |
Array::equals = (inOther) -> | |
return false unless isPushProgram(inOther) | |
return false unless inOther.length == @length | |
i = 0 | |
while i < @length | |
return false unless this[i].equals(inOther[i]) | |
i++ | |
true |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment