Revised structure

Started integrating with UI
Updated Views to use new language
Added builder object to make runtime generation of code easier
Replaced StackPushCard with ConstantCard
Added convenience functions for directly getting bytecode from CodeContext object
Added bytecode signature
Minor changes/fixes
This commit is contained in:
Gabriel Tofvesson 2017-07-18 01:26:35 +02:00
parent bf749f838a
commit 989897ca29
10 changed files with 286 additions and 98 deletions

View File

@ -6,7 +6,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.0.0-alpha5' classpath 'com.android.tools.build:gradle:3.0.0-alpha6'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong

View File

@ -1,3 +1,5 @@
@file:Suppress("unused")
package net.tofvesson.coloursbycontrol package net.tofvesson.coloursbycontrol
import java.lang.reflect.Method import java.lang.reflect.Method
@ -6,26 +8,167 @@ import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
import kotlin.collections.HashMap import kotlin.collections.HashMap
import kotlin.experimental.and import kotlin.experimental.and
import kotlin.experimental.or
class CodeCtx(ctxName: String, const: Array<String>, code: ByteArray): Operation{
val name = ctxName class ContextNotFoundException(message: String?) : Exception(message)
class ContextAlreadyLoadedException(message: String?) : RuntimeException(message)
class CodeMismatchException(message: String?) : RuntimeException(message)
class ValidationException(message: String?): Exception(message)
fun ByteArray.subSequence(start: Int, end: Int): ByteArray = ByteArray(end-start, {this[it+start]})
inline fun <reified T> Array<T>.subSequence(start: Int, end: Int): Array<T> = Array(end-start, {this[it+start]})
inline fun <reified T> Array<T>.editElement(index: Int, action: (T) -> T) { this[index] = action(this[index]) }
inline fun <reified T> Array<T>.lastElement(): T = this[this.lastIndex]
inline fun <reified T> ArrayList<T>.lastElement(): T = this[this.lastIndex]
fun String.splitExcept(ignore: String, regex: String): Array<String>{
val refined = ArrayList<String>()
val beforeRGX = ignore.indexOf(regex)
this.split(regex).forEach {
if(!refined.isEmpty() && (refined.lastElement().substring(refined.lastElement().length-beforeRGX) + regex + it).startsWith(ignore)) refined[refined.lastIndex] = refined[refined.lastIndex] + regex + it
else refined.add(it)
}
return refined.toTypedArray()
}
inline fun <reified T> Array<T>.forEachUpdate(action: (T) -> T){
for(i in this.indices) this[i] = action(this[i])
}
class CodeBuilder(hasReturn: Boolean, paramSize: Byte, internal val name: String, vararg constants: String){
constructor(hasReturn: Boolean, paramSize: Int, name: String, vararg constants: String): this(hasReturn, paramSize.toByte(), name, *constants)
constructor(hasReturn: Boolean, name: String, vararg constants: String): this(hasReturn, 0.toByte(), name, *constants)
constructor(paramSize: Byte, name: String, vararg constants: String): this(false, paramSize, name, *constants)
constructor(paramSize: Int, name: String, vararg constants: String): this(false, paramSize.toByte(), name, *constants)
constructor(name: String, vararg constants: String): this(false, 0.toByte(), name, *constants)
var signature: Byte = ((if(hasReturn) 0b10000000 else 0) or (paramSize.toInt() and 0b01111111)).toByte()
internal val code = ArrayList<Byte>()
internal val constantPool = ArrayList<String>()
init{ constants.forEach { constantPool.add(it) } }
fun add(operation: Byte, vararg pairedValues: Byte): CodeBuilder {
if(operation<0 || operation>=Operations.values().size) throw ValidationException("Operation $operation is out of range!")
var pairCount = -1
code.add(operation)
while(++pairCount<Operations.values()[operation.toInt()].getPairCount()) code.add(if(pairCount>=pairedValues.size) 0 else pairedValues[pairCount])
return this
}
fun add(operation: Operations, vararg pairedValues: Byte): CodeBuilder = add(operation.ordinal.toByte(), *pairedValues)
fun add(operation: Byte, vararg pairedValues: Int) = add(operation, *ByteArray(pairedValues.size, { pairedValues[it].toByte() }))
fun add(operation: Operations, vararg pairedValues: Int) = add(operation, *ByteArray(pairedValues.size, { pairedValues[it].toByte() }))
fun setHasReturn(hasReturn: Boolean){ signature = (signature and 0b01111111) or (if(hasReturn) 0b10000000 else 0).toByte() }
fun setParamCount(paramCount: Byte){ signature = (signature and -128) or (paramCount and 0b01111111) }
fun addConstant(const: String): Int {
val v: Int = constantPool.indices.firstOrNull { constantPool[it]==const } ?: -1
if(v==-1) constantPool.add(const)
return if(v==-1) constantPool.size-1 else v
}
}
open class ContextPool(superContextPool: ContextPool?) {
companion object {
internal val signature = ByteArray(8, {
if(it==0) 1.toByte()
else if(it<3) 3.toByte()
else if(it==3) 7.toByte()
else if(it==4) 116.toByte()
else if(it==5) 108.toByte()
else if(it==6) 110.toByte()
else 103.toByte()
})
fun getSignature(): ByteArray = signature.clone()
internal fun sign(code: ArrayList<Byte>) = getSignature().forEachIndexed { index, byte -> code.add(index, byte) }
internal fun addPool(code: ArrayList<Byte>, name: String, vararg constants: String){
val offset = if(isSigned(code)) 8 else 0
var consts = ""
for(s in constants) consts += s.replace("%", "\\%") + "%"
(consts+name+";").toByteArray().forEachIndexed({index, byte -> code.add(index+offset, byte) })
}
internal fun addCode(codeTarget: ArrayList<Byte>, code: ByteArray) = code.forEach{ codeTarget.add(it) }
internal fun addCode(codeTarget: ArrayList<Byte>, code: ArrayList<Byte>) = codeTarget.addAll(code)
private fun isSigned(code: List<Byte>): Boolean{
if(code.size<8) return false
signature.forEachIndexed({ index, byte -> if(code[index]!=byte) return false })
return true
}
}
constructor() : this(null)
protected val superPool: ContextPool? = superContextPool
protected val pool = ArrayList<CodeContext>()
@Throws(ContextAlreadyLoadedException::class, CodeMismatchException::class)
fun load(code: ByteArray): CodeContext {
getSignature().forEachIndexed { index, byte -> if(code[index] != byte) throw CodeMismatchException("Invalid signature!") }
val codeIdx: Int =
code.indices.firstOrNull {
code[it]==0x3b.toByte() && (it==0 || code[it-1]!='\\'.toByte())
} ?: throw CodeMismatchException("Constant pool not delimited!")
val constants: Array<String> = String(code.subSequence(8, codeIdx)).splitExcept("\\%", "%")
if(constants.isEmpty()) throw CodeMismatchException("No context name supplied!")
constants.forEachUpdate { it.replace("\\%", "%") }
try{
lookup(constants.lastElement())
throw ContextAlreadyLoadedException("Cannot load context "+constants.lastElement())
}catch(e: ContextNotFoundException){}
val v = _loadAfter(_loadBefore(constants.lastElement(), code.subSequence(codeIdx+1, code.size), constants.subSequence(0, constants.lastIndex)))
pool.add(v)
return v
}
fun load(code: List<Byte>): CodeContext = load(ByteArray(code.size, { code[it] }))
fun load(code: CodeBuilder): CodeContext{
val collected = ArrayList<Byte>()
sign(collected)
addPool(collected, code.name, *code.constantPool.toTypedArray())
collected.add(code.signature)
addCode(collected, code.code)
return load(collected)
}
fun load(context: CodeContext): CodeContext {
try{
lookup(context.name)
throw ContextAlreadyLoadedException("Cannot load context "+context.name)
}catch(e: ContextNotFoundException){ }
pool.add(context)
return context
}
@Throws(ContextNotFoundException::class)
fun lookup(name: String): CodeContext {
return _lookup(name) ?: superPool?.lookup(name) ?: throw ContextNotFoundException(name)
}
protected open fun _lookup(name: String): CodeContext?{
pool.filter { it.name==name }.forEach { return it }
return null
}
protected open fun _loadBefore(name: String, code: ByteArray, constants: Array<String>): CodeContext { return CodeContext(name, constants, code, this) }
protected open fun _loadAfter(ctx: CodeContext): CodeContext = ctx
}
open class CodeContext : Operation{
val name: String
val vars = HashMap<String, Any?>() val vars = HashMap<String, Any?>()
val pairedCalls = ArrayList<Pair<Int, Byte>>() val pairedCalls = ArrayList<Pair<Int, Byte>>()
val operands = Stack<Any?>() val operands = Stack<Any?>()
val operators = ArrayList<Operations>() val operators = ArrayList<Operations>()
val hasReturn = !(code.isEmpty() || ((code[0] and -128).toInt() ushr 7) == 0) val hasReturn: Boolean
val paramCount = if(code.isEmpty()) 0 else code[0] and 0b01111111 val paramCount: Byte
val constants = const val constants: Array<String>
var stackPointer = -1 var stackPointer = -1
var popFlag = false var popFlag = false
var isRunning = false var isRunning = false
protected val ctxPool: ContextPool
private constructor(ctxName: String, const: Array<String>, op: ArrayList<Operations>, pC: ArrayList<Pair<Int, Byte>>) : this(ctxName, const, kotlin.ByteArray(0)) { @Throws(ValidationException::class)
operators.addAll(op) internal constructor(ctxName: String, constants: Array<String>, code: ByteArray, ctxPool: ContextPool){
for((i, b) in pC) pairedCalls.add(Pair(i, b)) name = if(ctxName.contains("%") || ctxName.contains(";")) throw ValidationException("Invalid context name: "+ctxName) else ctxName
} constants.filter { it.contains("%") || it.contains(";") }.forEach { throw ValidationException("Invalid constant name: "+it) }
hasReturn = !(code.isEmpty() || ((code[0] and -128).toInt() ushr 7) == 0)
init{ paramCount = if(code.isEmpty()) 0 else code[0] and 0b01111111
this.constants = constants
this.ctxPool = ctxPool
var first = true var first = true
var paired = 0 var paired = 0
for(b in code){ for(b in code){
@ -45,18 +188,43 @@ class CodeCtx(ctxName: String, const: Array<String>, code: ByteArray): Operation
while(--v!=0) vars.put(v.toString(), null) while(--v!=0) vars.put(v.toString(), null)
} }
private constructor(ctxName: String, const: Array<String>, op: ArrayList<Operations>, pC: ArrayList<Pair<Int, Byte>>, ctxPool: ContextPool) : this(ctxName, const, kotlin.ByteArray(0), ctxPool) {
operators.addAll(op)
for((i, b) in pC) pairedCalls.add(Pair(i, b))
}
fun toBytes(): ByteArray {
val emptyStack = Stack<CodeContext>()
val build = ArrayList<Byte>()
var constants = ""
ContextPool.getSignature().forEach { build.add(it) }
for(s in this.constants) constants+=s.replace("%", "\\%")+"%"
constants+=name+";"
constants.toByteArray().forEach { build.add(it) }
build.add((paramCount and 0b01111111) or if(hasReturn) 0b10000000.toByte() else 0)
for(i in operators.indices){
build.add(operators[i].ordinal.toByte())
val max = operators[i].getPairCount()
var v = -1
while(++v<max) build.add(loadPairedVal(emptyStack, v, i))
}
return ByteArray(build.size, { build[it] })
}
override fun hasReturnValue(): Boolean = hasReturn override fun hasReturnValue(): Boolean = hasReturn
override fun getParamCount(): Int = paramCount.toInt() override fun getParamCount(): Int = paramCount.toInt()
override fun eval(stack: Stack<CodeCtx>, params: Array<Any?>): Any? { override fun eval(stack: Stack<CodeContext>, vararg params: Any?): Any? {
if(isRunning) return loadContext(stack, name).eval(stack, params) // Prevent errors with multi-threading or self-referencing code if(isRunning) return loadContext(stack, name).eval(stack, *params) // Prevent errors with multi-threading or self-referencing code
isRunning = true isRunning = true
stack.push(this) stack.push(this)
if(params.size > paramCount) throw exception(stack, "Context given too many parameters!") if(params.size > paramCount) throw exception(stack, "Context given too many parameters!")
params.forEachIndexed { index, it -> vars[index.toString()] = it } params.forEachIndexed { index, it -> vars[index.toString()] = it }
while (stackPointer<operators.size-1){ while (stackPointer<operators.size-1){
val o = operators[++stackPointer] val o = operators[++stackPointer]
val a = o.eval(stack, loadOperands(stack, o)) val a = o.eval(stack, *(loadOperands(stack, o)))
if(o.hasReturnValue()) operands.push(a) if(o.hasReturnValue()) operands.push(a)
if(popFlag) operands.pop() if(popFlag) operands.pop()
popFlag = false popFlag = false
@ -69,14 +237,14 @@ class CodeCtx(ctxName: String, const: Array<String>, code: ByteArray): Operation
return v return v
} }
private fun loadOperands(stack: Stack<CodeCtx>, op: Operations): Array<Any?> { private fun loadOperands(stack: Stack<CodeContext>, op: Operations): Array<Any?> {
if(op.getParamCount()>operands.size) throw exception(stack, "Operand stack underflow!") if(op.getParamCount()>operands.size) throw exception(stack, "Operand stack underflow!")
return Array(op.getParamCount() + op.getPairCount(), { return Array(op.getParamCount() + op.getPairCount(), {
if(it<op.getParamCount()) operands.pop() else loadPairedVal(stack, it-op.getParamCount(), stackPointer) if(it<op.getParamCount()) operands.pop() else loadPairedVal(stack, it-op.getParamCount(), stackPointer)
}) })
} }
private fun loadPairedVal(stack: Stack<CodeCtx>, which: Int, atStack: Int): Byte{ private fun loadPairedVal(stack: Stack<CodeContext>, which: Int, atStack: Int): Byte{
var count = 0 var count = 0
for((first, second) in pairedCalls) for((first, second) in pairedCalls)
if(first == atStack){ if(first == atStack){
@ -86,10 +254,11 @@ class CodeCtx(ctxName: String, const: Array<String>, code: ByteArray): Operation
throw exception(stack, "Can't load paired call value $which from $atStack!") throw exception(stack, "Can't load paired call value $which from $atStack!")
} }
fun loadContext(stack: Stack<CodeCtx>, ctxName: String): CodeCtx { fun loadContext(stack: Stack<CodeContext>, ctxName: String): CodeContext {
// TODO: Make better 'n load from files 'n other stuff if(ctxName == name) return CodeContext(name, constants, operators, pairedCalls, ctxPool)
if(ctxName == name) return CodeCtx(name, constants, operators, pairedCalls) try {
else throw exception(stack, "Could not find any context called \"$ctxName\"!") // TODO: Do search for other contexts return ctxPool.lookup(ctxName)
}catch(e: Exception){ throw exception(stack, e.message) }
} }
override fun toString(): String = "Context{name=$name, pointer=$stackPointer ("+operators[stackPointer].name+")}" override fun toString(): String = "Context{name=$name, pointer=$stackPointer ("+operators[stackPointer].name+")}"
} }
@ -97,15 +266,15 @@ class CodeCtx(ctxName: String, const: Array<String>, code: ByteArray): Operation
interface Operation{ interface Operation{
fun hasReturnValue(): Boolean fun hasReturnValue(): Boolean
fun getParamCount(): Int fun getParamCount(): Int
fun eval(stack: Stack<CodeCtx>, params: Array<Any?>): Any? fun eval(stack: Stack<CodeContext>, vararg params: Any?): Any?
} }
infix fun <K, V> HashMap<K, V>.containsKeyI(key: K) = containsKey(key) infix fun <K, V> HashMap<K, V>.containsKeyI(key: K): Boolean = containsKey(key)
fun Any?.asBoolean(): Boolean = fun Any?.asBoolean(): Boolean =
if(this==null) false else this as? Boolean ?: if((this.toString() == "true") or (this.toString() == "false")) this.toString().toBoolean() else !((this.toString()=="0") or (this.toString()=="0.0")) if(this==null) false else this as? Boolean ?: if((this.toString() == "true") or (this.toString() == "false")) this.toString().toBoolean() else !((this.toString()=="0") or (this.toString()=="0.0"))
fun Any?.asDouble(): Double = if(this==null) 0.0 else (this as? Number ?: try{ this.toString().toDouble() }catch(e: NumberFormatException){ 0.0 }).toDouble() fun Any?.asDouble(): Double = if(this==null) 0.0 else (this as? Number ?: try{ this.toString().toDouble() }catch(e: NumberFormatException){ 0.0 }).toDouble()
fun exception(stack: Stack<CodeCtx>, reason: String?): RuntimeException = fun exception(stack: Stack<CodeContext>, reason: String?): RuntimeException =
RuntimeException((reason ?: "")+" Trace: "+Arrays.toString(stack.toArray())+ RuntimeException((reason ?: "")+" Trace: "+Arrays.toString(stack.toArray())+
(if(stack.size>0) " at "+stack[stack.size-1].operators[stack[stack.size-1].stackPointer].ordinal+" ("+stack[stack.size-1].operators[stack[stack.size-1].stackPointer].name+")" else "")) (if(stack.size>0) " at "+stack[stack.size-1].operators[stack[stack.size-1].stackPointer].ordinal+" ("+stack[stack.size-1].operators[stack[stack.size-1].stackPointer].name+")" else ""))
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
@ -122,7 +291,7 @@ enum class Operations: Operation{
LDV{ // Load variable LDV{ // Load variable
override fun hasReturnValue(): Boolean = true override fun hasReturnValue(): Boolean = true
override fun getParamCount(): Int = 1 override fun getParamCount(): Int = 1
override fun eval(stack: Stack<CodeCtx>, params: Array<Any?>): Any? { override fun eval(stack: Stack<CodeContext>, vararg params: Any?): Any? {
var i = stack.size-1 var i = stack.size-1
while(i!=-1){ while(i!=-1){
if(stack[i].vars containsKeyI params[0].toString()){ if(stack[i].vars containsKeyI params[0].toString()){
@ -137,7 +306,7 @@ enum class Operations: Operation{
STV{ // Store variable STV{ // Store variable
override fun hasReturnValue(): Boolean = false override fun hasReturnValue(): Boolean = false
override fun getParamCount(): Int = 2 override fun getParamCount(): Int = 2
override fun eval(stack: Stack<CodeCtx>, params: Array<Any?>): String? { override fun eval(stack: Stack<CodeContext>, vararg params: Any?): String? {
var i = stack.size var i = stack.size
while(i!=-1){ while(i!=-1){
if(stack[i].vars containsKeyI params[0].toString()){ if(stack[i].vars containsKeyI params[0].toString()){
@ -153,13 +322,13 @@ enum class Operations: Operation{
LDC{ // Load constant LDC{ // Load constant
override fun hasReturnValue(): Boolean = true override fun hasReturnValue(): Boolean = true
override fun getParamCount(): Int = 0 override fun getParamCount(): Int = 0
override fun eval(stack: Stack<CodeCtx>, params: Array<Any?>): String? = stack[stack.size-1].constants[params[0].asDouble().toInt()] override fun eval(stack: Stack<CodeContext>, vararg params: Any?): String? = stack[stack.size-1].constants[params[0].asDouble().toInt()]
override fun getPairCount(): Int = 1 override fun getPairCount(): Int = 1
}, },
EXT{ // Call external EXT{ // Call external
override fun hasReturnValue(): Boolean = true override fun hasReturnValue(): Boolean = true
override fun getParamCount(): Int = 2 override fun getParamCount(): Int = 2
override fun eval(stack: Stack<CodeCtx>, params: Array<Any?>): Any? { override fun eval(stack: Stack<CodeContext>, vararg params: Any?): Any? {
val caller = stack[stack.size-1] val caller = stack[stack.size-1]
val c = Class.forName(params[0].toString()) val c = Class.forName(params[0].toString())
if(params[2].toString().toInt() > caller.operands.size) throw exception(stack, "Operand stack underflow! Required parameter count: "+params[2].toString()) if(params[2].toString().toInt() > caller.operands.size) throw exception(stack, "Operand stack underflow! Required parameter count: "+params[2].toString())
@ -170,7 +339,7 @@ enum class Operations: Operation{
callParams = arrayOf(caller.operands.pop(), *callParams) callParams = arrayOf(caller.operands.pop(), *callParams)
} }
caller.popFlag = callMethod.returnType==Void.TYPE caller.popFlag = callMethod.returnType==Void.TYPE
val v = invoke(callMethod, callParams) val v = invoke(callMethod, *callParams)
return v return v
} }
override fun getPairCount(): Int = 1 override fun getPairCount(): Int = 1
@ -178,13 +347,13 @@ enum class Operations: Operation{
POP{ // Pop one operand POP{ // Pop one operand
override fun hasReturnValue(): Boolean = false override fun hasReturnValue(): Boolean = false
override fun getParamCount(): Int = 1 override fun getParamCount(): Int = 1
override fun eval(stack: Stack<CodeCtx>, params: Array<Any?>): String? = null override fun eval(stack: Stack<CodeContext>, vararg params: Any?): String? = null
override fun getPairCount(): Int = 0 override fun getPairCount(): Int = 0
}, },
DCV{ // Declare variable DCV{ // Declare variable
override fun hasReturnValue(): Boolean = false override fun hasReturnValue(): Boolean = false
override fun getParamCount(): Int = 2 override fun getParamCount(): Int = 2
override fun eval(stack: Stack<CodeCtx>, params: Array<Any?>): Any? { override fun eval(stack: Stack<CodeContext>, vararg params: Any?): Any? {
if(stack[stack.size-1].vars containsKeyI params[0].toString()) return null if(stack[stack.size-1].vars containsKeyI params[0].toString()) return null
stack[stack.size-1].vars.put(params[0].toString(), params[1]) stack[stack.size-1].vars.put(params[0].toString(), params[1])
return null return null
@ -194,31 +363,31 @@ enum class Operations: Operation{
CMP{ // Compare CMP{ // Compare
override fun hasReturnValue(): Boolean = true override fun hasReturnValue(): Boolean = true
override fun getParamCount(): Int = 2 override fun getParamCount(): Int = 2
override fun eval(stack: Stack<CodeCtx>, params: Array<Any?>): Any? = (params[0].toString() == params[1].toString()) or (if(params[0]==null) params[1]==null else params[0]?.equals(params[1]) as Boolean) override fun eval(stack: Stack<CodeContext>, vararg params: Any?): Any? = (params[0].toString() == params[1].toString()) or (if(params[0]==null) params[1]==null else params[0]?.equals(params[1]) as Boolean)
override fun getPairCount(): Int = 0 override fun getPairCount(): Int = 0
}, },
LNT{ // Logical NOT LNT{ // Logical NOT
override fun hasReturnValue(): Boolean = true override fun hasReturnValue(): Boolean = true
override fun getParamCount(): Int = 1 override fun getParamCount(): Int = 1
override fun eval(stack: Stack<CodeCtx>, params: Array<Any?>): Any? = !params[0].asBoolean() override fun eval(stack: Stack<CodeContext>, vararg params: Any?): Any? = !params[0].asBoolean()
override fun getPairCount(): Int = 0 override fun getPairCount(): Int = 0
}, },
LOR{ // Logical OR LOR{ // Logical OR
override fun hasReturnValue(): Boolean = true override fun hasReturnValue(): Boolean = true
override fun getParamCount(): Int = 2 override fun getParamCount(): Int = 2
override fun eval(stack: Stack<CodeCtx>, params: Array<Any?>): Any? = params[0].asBoolean() or params[1].asBoolean() override fun eval(stack: Stack<CodeContext>, vararg params: Any?): Any? = params[0].asBoolean() or params[1].asBoolean()
override fun getPairCount(): Int = 0 override fun getPairCount(): Int = 0
}, },
CND{ // Conditional Jump (false = jump 2, true = no jump) CND{ // Conditional Jump (false = jump 2, true = no jump)
override fun hasReturnValue(): Boolean = false override fun hasReturnValue(): Boolean = false
override fun getParamCount(): Int = 1 override fun getParamCount(): Int = 1
override fun eval(stack: Stack<CodeCtx>, params: Array<Any?>): Any? = if(!params[0].asBoolean()) stack[stack.size-1].stackPointer+=2 else 0 override fun eval(stack: Stack<CodeContext>, vararg params: Any?): Any? = if(!params[0].asBoolean()) stack[stack.size-1].stackPointer+=2 else 0
override fun getPairCount(): Int = 0 override fun getPairCount(): Int = 0
}, },
JMP{ // Unconditional jump (1 operand) JMP{ // Unconditional jump (1 operand)
override fun hasReturnValue(): Boolean = false override fun hasReturnValue(): Boolean = false
override fun getParamCount(): Int = 2 override fun getParamCount(): Int = 2
override fun eval(stack: Stack<CodeCtx>, params: Array<Any?>): Any?{ override fun eval(stack: Stack<CodeContext>, vararg params: Any?): Any?{
stack[stack.size-1].stackPointer = (if(params[0].asBoolean()) stack[stack.size-1].stackPointer else 0) + params[1].asDouble().toInt() stack[stack.size-1].stackPointer = (if(params[0].asBoolean()) stack[stack.size-1].stackPointer else 0) + params[1].asDouble().toInt()
return null return null
} }
@ -227,25 +396,25 @@ enum class Operations: Operation{
CALL{ // Call context CALL{ // Call context
override fun hasReturnValue(): Boolean = true override fun hasReturnValue(): Boolean = true
override fun getParamCount(): Int = 1 override fun getParamCount(): Int = 1
override fun eval(stack: Stack<CodeCtx>, params: Array<Any?>): Any? { override fun eval(stack: Stack<CodeContext>, vararg params: Any?): Any? {
val caller = stack[stack.size-1] val caller = stack[stack.size-1]
val ctx = caller.loadContext(stack, params[0].toString()) val ctx = caller.loadContext(stack, params[0].toString())
if(ctx.getParamCount() > caller.operands.size) throw exception(stack, "Operand stack underflow! Required parameter count: "+ctx.getParamCount()) if(ctx.getParamCount() > caller.operands.size) throw exception(stack, "Operand stack underflow! Required parameter count: "+ctx.getParamCount())
caller.popFlag = !ctx.hasReturn caller.popFlag = !ctx.hasReturn
return ctx.eval(stack, Array(ctx.getParamCount(), { caller.operands.pop() })) return ctx.eval(stack, *Array(ctx.getParamCount(), { caller.operands.pop() }))
} }
override fun getPairCount(): Int = 0 override fun getPairCount(): Int = 0
}, },
LDN{ // Load constant number LDN{ // Load constant number
override fun hasReturnValue(): Boolean = true override fun hasReturnValue(): Boolean = true
override fun getParamCount(): Int = 0 override fun getParamCount(): Int = 0
override fun eval(stack: Stack<CodeCtx>, params: Array<Any?>): Any? = params[0] override fun eval(stack: Stack<CodeContext>, vararg params: Any?): Any? = params[0]
override fun getPairCount(): Int = 1 override fun getPairCount(): Int = 1
}, },
CJP{ // Constant jump (unconditional, no operands) CJP{ // Constant jump (unconditional, no operands)
override fun hasReturnValue(): Boolean = false override fun hasReturnValue(): Boolean = false
override fun getParamCount(): Int = 0 override fun getParamCount(): Int = 0
override fun eval(stack: Stack<CodeCtx>, params: Array<Any?>): Any? { override fun eval(stack: Stack<CodeContext>, vararg params: Any?): Any? {
stack[stack.size-1].stackPointer += params[0].asDouble().toInt() stack[stack.size-1].stackPointer += params[0].asDouble().toInt()
return null return null
} }
@ -254,31 +423,31 @@ enum class Operations: Operation{
VLD{ // Constant load from variable (load constant based on value of variable) VLD{ // Constant load from variable (load constant based on value of variable)
override fun hasReturnValue(): Boolean = true override fun hasReturnValue(): Boolean = true
override fun getParamCount(): Int = 1 override fun getParamCount(): Int = 1
override fun eval(stack: Stack<CodeCtx>, params: Array<Any?>): Any? = stack[stack.size-1].constants[params[0].asDouble().toInt()] override fun eval(stack: Stack<CodeContext>, vararg params: Any?): Any? = stack[stack.size-1].constants[params[0].asDouble().toInt()]
override fun getPairCount(): Int = 0 override fun getPairCount(): Int = 0
}, },
NOP{ // No operation NOP{ // No operation
override fun hasReturnValue(): Boolean = false override fun hasReturnValue(): Boolean = false
override fun getParamCount(): Int = 0 override fun getParamCount(): Int = 0
override fun eval(stack: Stack<CodeCtx>, params: Array<Any?>): Any? = null override fun eval(stack: Stack<CodeContext>, vararg params: Any?): Any? = null
override fun getPairCount(): Int = 0 override fun getPairCount(): Int = 0
}, },
INC{ // Increment variable INC{ // Increment variable
override fun hasReturnValue(): Boolean = true override fun hasReturnValue(): Boolean = true
override fun getParamCount(): Int = 1 override fun getParamCount(): Int = 1
override fun eval(stack: Stack<CodeCtx>, params: Array<Any?>): Any? = params[0].asDouble() + 1 override fun eval(stack: Stack<CodeContext>, vararg params: Any?): Any? = params[0].asDouble() + 1
override fun getPairCount(): Int = 0 override fun getPairCount(): Int = 0
}, },
DEC { // Decrement variable DEC { // Decrement variable
override fun hasReturnValue(): Boolean = true override fun hasReturnValue(): Boolean = true
override fun getParamCount(): Int = 1 override fun getParamCount(): Int = 1
override fun eval(stack: Stack<CodeCtx>, params: Array<Any?>): Any? = params[0].asDouble() - 1 override fun eval(stack: Stack<CodeContext>, vararg params: Any?): Any? = params[0].asDouble() - 1
override fun getPairCount(): Int = 0 override fun getPairCount(): Int = 0
}, },
LOP{ // Logical operation LOP{ // Logical operation
override fun hasReturnValue(): Boolean = true override fun hasReturnValue(): Boolean = true
override fun getParamCount(): Int = 2 override fun getParamCount(): Int = 2
override fun eval(stack: Stack<CodeCtx>, params: Array<Any?>): Any? = override fun eval(stack: Stack<CodeContext>, vararg params: Any?): Any? =
if(params[2]==0) params[0].asDouble() + params[1].asDouble() if(params[2]==0) params[0].asDouble() + params[1].asDouble()
else if(params[2]==1) params[0].asDouble() - params[1].asDouble() else if(params[2]==1) params[0].asDouble() - params[1].asDouble()
else if(params[2]==2) params[0].asDouble() * params[1].asDouble() else if(params[2]==2) params[0].asDouble() * params[1].asDouble()
@ -290,7 +459,7 @@ enum class Operations: Operation{
DUP{ // Duplicate top operand DUP{ // Duplicate top operand
override fun hasReturnValue(): Boolean = true override fun hasReturnValue(): Boolean = true
override fun getParamCount(): Int = 1 override fun getParamCount(): Int = 1
override fun eval(stack: Stack<CodeCtx>, params: Array<Any?>): Any? = stack[stack.size-1].operands.push(params[0]) override fun eval(stack: Stack<CodeContext>, vararg params: Any?): Any? = stack[stack.size-1].operands.push(params[0])
override fun getPairCount(): Int = 0 override fun getPairCount(): Int = 0
}; };
abstract fun getPairCount(): Int abstract fun getPairCount(): Int
@ -338,13 +507,13 @@ fun getMethod(params: Array<Any?>, name: String, owner: Class<*>, searchMask: In
return match return match
} }
fun invoke(call: Method, params: Array<Any?>): Any? { fun invoke(call: Method, vararg params: Any?): Any? {
try{ try{
call.isAccessible = true call.isAccessible = true
val isStatic = Modifier.isStatic(call.modifiers) val isStatic = Modifier.isStatic(call.modifiers)
val callParams = Array(if(call.parameterTypes.isNotEmpty()) call.parameterTypes.size - (if(isStatic) 0 else 1) else 0, val callParams = Array(if(call.parameterTypes.isNotEmpty()) call.parameterTypes.size - (if(isStatic) 0 else 1) else 0,
{ {
if(it + (if(isStatic) 0 else 1)>=params.size) null if((it + if(isStatic) 0 else 1)>=params.size) null
else getOrCreate(call.parameterTypes[it], params[it + (if(isStatic) 0 else 1)], true, true) else getOrCreate(call.parameterTypes[it], params[it + (if(isStatic) 0 else 1)], true, true)
}) })
return call.invoke(if(isStatic) null else params[0], *callParams) return call.invoke(if(isStatic) null else params[0], *callParams)

View File

@ -8,14 +8,19 @@ import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.widget.EditText; import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import net.tofvesson.coloursbycontrol.CodeCtx; import net.tofvesson.coloursbycontrol.CodeBuilder;
import net.tofvesson.coloursbycontrol.CodeContext;
import net.tofvesson.coloursbycontrol.ContextPool;
import net.tofvesson.coloursbycontrol.R; import net.tofvesson.coloursbycontrol.R;
import net.tofvesson.coloursbycontrol.view.StackPushCard; import net.tofvesson.coloursbycontrol.view.ConstantCard;
import net.tofvesson.coloursbycontrol.view.FunctionCard;
import net.tofvesson.coloursbycontrol.view.LinearActionLayout;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Stack; import java.util.Stack;
import static net.tofvesson.coloursbycontrol.Operations.*;
public class ScrollingActivity extends AppCompatActivity { public class ScrollingActivity extends AppCompatActivity {
@ -45,29 +50,36 @@ public class ScrollingActivity extends AppCompatActivity {
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
final CodeCtx ctx = new CodeCtx("RunMe", CodeBuilder RunMe = new CodeBuilder(true, 1, "RunMe", "getToast", "makeText", Toast.class.getName(), "show");
new String[]{ "Hello World", "makeText", Toast.class.getName(), "show" }, // Constant pool RunMe // Operations: | Consumption | | Addition | | Delta | |Definite|
new byte[] // Instructions .add(LDN /*, 0*/) // Load 0 to the stack (consumes 0 operand(s)) (adds 1 operand(s)) (impact: 1) (stack: 1)
{ .add(LDC /*, 0*/) // Load constant at index 0 to the stack: "getToast" (consumes 0 operand(s)) (adds 1 operand(s)) (impact: 1) (stack: 2)
-127 , // 10000001 (Return: true, Params: 1) .add(CALL) // Call context "getToast" (consumes 1 operand(s)) (adds 1 operand(s)) (impact: 0) (stack: 2)
12, 0, .add(LDN /*, 0*/) // Load 0 to the stack (consumes 0 operand(s)) (adds 1 operand(s)) (impact: 1) (stack: 3)
2, 0, .add(LDV) // Load a variable to the stack: <Application context> (variable 0 is the first and only parameter) (consumes 1 operand(s)) (adds 1 operand(s)) (impact: 0) (stack: 3)
12, 0, .add(LDC, 1) // Load constant at index 1 to the stack: "makeText" (consumes 0 operand(s)) (adds 1 operand(s)) (impact: 1) (stack: 4)
0, .add(LDC, 2) // Load constant at index 2 to the stack: "android.widget.Toast" (consumes 0 operand(s)) (adds 1 operand(s)) (impact: 1) (stack: 5)
2, 1, .add(EXT, 3) // Call external (Java) code: Toast.makeText(<Application context>, "Hello World", 0) (consumes 5 operand(s)) (adds 1 operand(s)) (impact: -4) (stack: 1)
2, 2, .add(LDC, 3) // Load constant at index 3 to the stack: "show" (consumes 0 operand(s)) (adds 1 operand(s)) (impact: 1) (stack: 2)
3, 3, .add(LDC, 2) // Load constant at index 2 to the stack: "android.widget.Toast" (consumes 0 operand(s)) (adds 1 operand(s)) (impact: 1) (stack: 3)
2, 3, .add(EXT /*, 0*/) // Call external (Java) code: <Toast Object>.show() (consumes 3 operand(s)) (adds 0 operand(s)) (impact: -3) (stack: 0)
2, 2, .add(LDC /*, 0*/); // Load constant at index 0 to the stack: "Hello World" (consumes 0 operand(s)) (adds 1 operand(s)) (impact: 1) (stack: 1)
3, 0, /* implicit return */ // Return from this subroutine to the super-routine (caller) (consumes 1 operand[s]) (adds 0 operand(s)) (impact: -1) (stack: 0)
2, 0
}
);
System.out.println(ctx.eval(new Stack<>(), new Object[]{ this }));
CodeBuilder getToast = new CodeBuilder(true, 0, "getToast", "Hey, World!");
getToast.add(LDC);
CodeBuilder toast = new CodeBuilder(false, 2, Toast.class.getName(), "show", "makeText");
//TODO: Make CodeContext for showing toast
final StackPushCard cnst = (StackPushCard) findViewById(R.id.stackPush); ContextPool pool = new ContextPool();// Create a new pool (sandbox for execution)
CodeContext ctx = pool.load(RunMe); // Load context "RunMe" to pool
pool.load(getToast); // Load context "getToast" to pool
System.out.println(ctx.eval(new Stack<>(), this)); // Execute "RunMe"
final ConstantCard cnst = (ConstantCard) findViewById(R.id.stackPush);
cnst.push = "Hello World"; cnst.push = "Hello World";
cnst.setOnClickListener(v -> { cnst.setOnClickListener(v -> {
final Dialog d = new Dialog(new android.view.ContextThemeWrapper(ScrollingActivity.this, R.style.AppThemeLight)); final Dialog d = new Dialog(new android.view.ContextThemeWrapper(ScrollingActivity.this, R.style.AppThemeLight));
@ -76,20 +88,19 @@ public class ScrollingActivity extends AppCompatActivity {
if(cnst.push!=null) ((EditText) d.findViewById(R.id.newConst)).setText(String.valueOf(cnst.push)); if(cnst.push!=null) ((EditText) d.findViewById(R.id.newConst)).setText(String.valueOf(cnst.push));
d.findViewById(R.id.cancel_action).setOnClickListener(v12 -> d.dismiss()); d.findViewById(R.id.cancel_action).setOnClickListener(v12 -> d.dismiss());
d.findViewById(R.id.confirm_action).setOnClickListener(v1 -> { d.findViewById(R.id.confirm_action).setOnClickListener(v1 -> {
cnst.push = ((EditText) d.findViewById(R.id.newConst)).getText(); cnst.push = ((EditText) d.findViewById(R.id.newConst)).getText().toString();
d.dismiss(); d.dismiss();
}); });
d.show(); d.show();
}); });
((FunctionCard)findViewById(R.id.test)).instruction = "toast";
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(view -> { fab.setOnClickListener(view -> {
CodeBuilder builder = new CodeBuilder(false, 1, "exec");
LinearActionLayout lal = (LinearActionLayout) findViewById(R.id.instructions);
for(int i = 0; i<lal.getChildCount(); ++i) lal.getChildAt(i).processInstructions(builder);
pool.load(builder).eval(new Stack<>(), this);
}); });
findViewById(R.id.fab1).setOnClickListener(v -> Toast.makeText(getApplicationContext(), "I'm going to analyze the defined stack to check whether or not there will be and error on execution", Toast.LENGTH_LONG).show()); findViewById(R.id.fab1).setOnClickListener(v -> Toast.makeText(getApplicationContext(), "I'm going to analyze the defined stack to check whether or not there will be and error on execution", Toast.LENGTH_LONG).show());
} }
private static void toast(Object o){ ExternalData d = (ExternalData) o; Toast.makeText(d.ctx, d.message, Toast.LENGTH_SHORT).show(); }
private static void snackbar(Object o){ ExternalData d = (ExternalData) o; Snackbar.make(d.ctx.findViewById(android.R.id.content), d.message, Snackbar.LENGTH_LONG).show(); }
static class ExternalData{ public String message; public Activity ctx; }
} }

View File

@ -6,6 +6,8 @@ import android.graphics.Paint;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View; import android.view.View;
import net.tofvesson.coloursbycontrol.CodeBuilder;
import net.tofvesson.coloursbycontrol.R; import net.tofvesson.coloursbycontrol.R;
import net.tofvesson.libtlang.Routine; import net.tofvesson.libtlang.Routine;
@ -35,6 +37,6 @@ public abstract class ActionView extends View {
} }
} }
public abstract void processInstructions(Routine<?> r); public abstract void processInstructions(CodeBuilder c);
public abstract void onDraw(android.graphics.Canvas canvas); public abstract void onDraw(android.graphics.Canvas canvas);
} }

View File

@ -7,34 +7,32 @@ import android.os.Build;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi; import android.support.annotation.RequiresApi;
import android.util.AttributeSet; import android.util.AttributeSet;
import net.tofvesson.coloursbycontrol.CodeBuilder;
import net.tofvesson.coloursbycontrol.Operations;
import net.tofvesson.libtlang.Routine; public class ConstantCard extends ActionCard {
import net.tofvesson.libtlang.StackPush;
public class StackPushCard extends ActionCard {
protected static final String name = "Constant", help = "Click to edit..."; protected static final String name = "Constant", help = "Click to edit...";
public Object push; public String push;
private final Rect tMeasure = new Rect(); private final Rect tMeasure = new Rect();
public StackPushCard(Context c) { public ConstantCard(Context c) {
super(c); super(c);
} }
public StackPushCard(Context c, @Nullable AttributeSet a) { public ConstantCard(Context c, @Nullable AttributeSet a) {
super(c, a); super(c, a);
} }
public StackPushCard(Context c, @Nullable AttributeSet a, int d) { public ConstantCard(Context c, @Nullable AttributeSet a, int d) {
super(c, a, d); super(c, a, d);
} }
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public StackPushCard(Context c, @Nullable AttributeSet a, int s, int r) { public ConstantCard(Context c, @Nullable AttributeSet a, int s, int r) {
super(c, a, s, r); super(c, a, s, r);
} }
@Override @Override public void processInstructions(CodeBuilder c) { c.add(Operations.LDC, c.addConstant(push==null?"null":push)); }
public void processInstructions(Routine<?> r) { r.add(new StackPush(push)); }
@Override @Override
protected void drawItems(Canvas canvas) { protected void drawItems(Canvas canvas) {

View File

@ -6,6 +6,8 @@ import android.graphics.Rect;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.AttributeSet; import android.util.AttributeSet;
import net.tofvesson.coloursbycontrol.CodeBuilder;
import net.tofvesson.coloursbycontrol.Operations;
import net.tofvesson.libtlang.Routine; import net.tofvesson.libtlang.Routine;
import net.tofvesson.coloursbycontrol.R; import net.tofvesson.coloursbycontrol.R;
@ -13,7 +15,7 @@ import net.tofvesson.coloursbycontrol.R;
public class FunctionCard extends ActionCard { public class FunctionCard extends ActionCard {
private static final String func = "Function", inputs = "Inputs: ", out = "Output: ", n = "Name: "; private static final String func = "Function", inputs = "Inputs: ", out = "Output: ", n = "Name: ";
protected String name; protected String name;
public Routine<?> instruction; public String instruction;
public boolean inline = false; public boolean inline = false;
private final Rect tMeasure = new Rect(); private final Rect tMeasure = new Rect();
@ -33,10 +35,9 @@ public class FunctionCard extends ActionCard {
public void setName(String name){ if(name==null || name.length()==0) return; this.name = name; } public void setName(String name){ if(name==null || name.length()==0) return; this.name = name; }
public String getName(){ return name; } public String getName(){ return name; }
@Override public void processInstructions(Routine<?> r) { @Override public void processInstructions(CodeBuilder c) {
if(instruction == null) return; if(instruction == null) return;
if(inline) r.inline(instruction); c.add(Operations.LDC, c.addConstant(instruction));
else r.add(instruction);
} }
@Override @Override
@ -46,10 +47,14 @@ public class FunctionCard extends ActionCard {
textColor.getTextBounds(func, 0, func.length(), tMeasure); textColor.getTextBounds(func, 0, func.length(), tMeasure);
canvas.drawText(func, canvas.getWidth()/2 - tMeasure.exactCenterX(), -tMeasure.exactCenterY() * 4, textColor); canvas.drawText(func, canvas.getWidth()/2 - tMeasure.exactCenterX(), -tMeasure.exactCenterY() * 4, textColor);
textColor.setTextSize((float) Math.sqrt(canvas.getWidth()*canvas.getHeight())/12F); textColor.setTextSize((float) Math.sqrt(canvas.getWidth()*canvas.getHeight())/12F);
/*
textColor.getTextBounds(s=inputs + (instruction==null?"0":instruction.getParamTypes().length), 0, s.length(), tMeasure); textColor.getTextBounds(s=inputs + (instruction==null?"0":instruction.getParamTypes().length), 0, s.length(), tMeasure);
canvas.drawText(s, canvas.getWidth()/2 - tMeasure.exactCenterX(), canvas.getHeight()*2F/3F - tMeasure.exactCenterY() * 3, textColor); canvas.drawText(s, canvas.getWidth()/2 - tMeasure.exactCenterX(), canvas.getHeight()*2F/3F - tMeasure.exactCenterY() * 3, textColor);
textColor.getTextBounds(s=out+(instruction==null || instruction.getReturnType()==Void.class?"No":"Yes"), 0, s.length(), tMeasure); textColor.getTextBounds(s=out+(instruction==null || instruction.getReturnType()==Void.class?"No":"Yes"), 0, s.length(), tMeasure);
canvas.drawText(s, canvas.getWidth()/2 - tMeasure.exactCenterX(), canvas.getHeight()+tMeasure.exactCenterY() * 4, textColor); canvas.drawText(s, canvas.getWidth()/2 - tMeasure.exactCenterX(), canvas.getHeight()+tMeasure.exactCenterY() * 4, textColor);
*/
textColor.setTextSize((float) Math.sqrt(canvas.getWidth()*canvas.getHeight())/14F); textColor.setTextSize((float) Math.sqrt(canvas.getWidth()*canvas.getHeight())/14F);
if (name.length()>20) s = n+name.substring(0, 20)+"..."; if (name.length()>20) s = n+name.substring(0, 20)+"...";
else s = n+name; else s = n+name;

View File

@ -4,6 +4,7 @@ import android.content.Context;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.AttributeSet; import android.util.AttributeSet;
import net.tofvesson.coloursbycontrol.CodeBuilder;
import net.tofvesson.libtlang.Routine; import net.tofvesson.libtlang.Routine;
public class GOTOCard extends ActionCard { public class GOTOCard extends ActionCard {
@ -12,7 +13,7 @@ public class GOTOCard extends ActionCard {
public GOTOCard(Context c, @Nullable AttributeSet a, int d) { super(c, a, d); } public GOTOCard(Context c, @Nullable AttributeSet a, int d) { super(c, a, d); }
@android.support.annotation.RequiresApi(api = android.os.Build.VERSION_CODES.LOLLIPOP) public GOTOCard(Context c, @Nullable AttributeSet a, int s, int r) { super(c, a, s, r); } @android.support.annotation.RequiresApi(api = android.os.Build.VERSION_CODES.LOLLIPOP) public GOTOCard(Context c, @Nullable AttributeSet a, int s, int r) { super(c, a, s, r); }
@Override public void processInstructions(Routine<?> r) { } @Override public void processInstructions(CodeBuilder c) { }
@Override @Override
public void drawItems(android.graphics.Canvas canvas) { public void drawItems(android.graphics.Canvas canvas) {

View File

@ -4,6 +4,7 @@ import android.content.Context;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.AttributeSet; import android.util.AttributeSet;
import net.tofvesson.coloursbycontrol.CodeBuilder;
import net.tofvesson.libtlang.Routine; import net.tofvesson.libtlang.Routine;
@ -13,7 +14,7 @@ public class OperationCard extends ActionCard {
public OperationCard(Context c, @Nullable AttributeSet a, int d) { super(c, a, d); } public OperationCard(Context c, @Nullable AttributeSet a, int d) { super(c, a, d); }
@android.support.annotation.RequiresApi(api = android.os.Build.VERSION_CODES.LOLLIPOP) public OperationCard(Context c, @Nullable AttributeSet a, int s, int r) { super(c, a, s, r); } @android.support.annotation.RequiresApi(api = android.os.Build.VERSION_CODES.LOLLIPOP) public OperationCard(Context c, @Nullable AttributeSet a, int s, int r) { super(c, a, s, r); }
@Override public void processInstructions(Routine<?> r) { } @Override public void processInstructions(CodeBuilder c) { }
@Override @Override
public void drawItems(android.graphics.Canvas canvas) { public void drawItems(android.graphics.Canvas canvas) {

View File

@ -4,6 +4,7 @@ import android.content.Context;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.AttributeSet; import android.util.AttributeSet;
import net.tofvesson.coloursbycontrol.CodeBuilder;
import net.tofvesson.libtlang.Routine; import net.tofvesson.libtlang.Routine;
public class VarDeclareCard extends ActionCard { public class VarDeclareCard extends ActionCard {
@ -12,7 +13,7 @@ public class VarDeclareCard extends ActionCard {
public VarDeclareCard(Context c, @Nullable AttributeSet a, int d) { super(c, a, d); } public VarDeclareCard(Context c, @Nullable AttributeSet a, int d) { super(c, a, d); }
@android.support.annotation.RequiresApi(api = android.os.Build.VERSION_CODES.LOLLIPOP) public VarDeclareCard(Context c, @Nullable AttributeSet a, int s, int r) { super(c, a, s, r); } @android.support.annotation.RequiresApi(api = android.os.Build.VERSION_CODES.LOLLIPOP) public VarDeclareCard(Context c, @Nullable AttributeSet a, int s, int r) { super(c, a, s, r); }
@Override public void processInstructions(Routine<?> r) { } @Override public void processInstructions(CodeBuilder c) { }
@Override @Override
public void drawItems(android.graphics.Canvas canvas) { public void drawItems(android.graphics.Canvas canvas) {

View File

@ -26,7 +26,7 @@
app:color="?colorPrimary" app:color="?colorPrimary"
app:backgroundColor="?colorPrimaryDark" app:backgroundColor="?colorPrimaryDark"
app:textColor="?colorAccent"/> app:textColor="?colorAccent"/>
<net.tofvesson.coloursbycontrol.view.StackPushCard <net.tofvesson.coloursbycontrol.view.ConstantCard
android:id="@+id/stackPush" android:id="@+id/stackPush"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"