mirror of
				https://github.com/GayPizzaSpecifications/pork.git
				synced 2025-11-03 17:39:38 +00:00 
			
		
		
		
	vm: a functional virtual machine, mostly
This commit is contained in:
		@ -6,5 +6,6 @@ import kotlinx.serialization.Serializable
 | 
				
			|||||||
data class CompiledWorld(
 | 
					data class CompiledWorld(
 | 
				
			||||||
  val constantPool: ConstantPool,
 | 
					  val constantPool: ConstantPool,
 | 
				
			||||||
  val symbolTable: SymbolTable,
 | 
					  val symbolTable: SymbolTable,
 | 
				
			||||||
  val code: List<Op>
 | 
					  val code: List<Op>,
 | 
				
			||||||
 | 
					  val annotations: List<OpAnnotation>
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
				
			|||||||
@ -1,3 +1,21 @@
 | 
				
			|||||||
package gay.pizza.pork.bytecode
 | 
					package gay.pizza.pork.bytecode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Constant(val id: UInt, val value: ByteArray)
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Serializable
 | 
				
			||||||
 | 
					data class Constant(val id: UInt, val tag: ConstantTag, val value: ByteArray) {
 | 
				
			||||||
 | 
					  override fun equals(other: Any?): Boolean {
 | 
				
			||||||
 | 
					    if (this === other) return true
 | 
				
			||||||
 | 
					    other as Constant
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (id != other.id) return false
 | 
				
			||||||
 | 
					    if (!value.contentEquals(other.value)) return false
 | 
				
			||||||
 | 
					    return true
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun hashCode(): Int {
 | 
				
			||||||
 | 
					    var result = id.hashCode()
 | 
				
			||||||
 | 
					    result = 31 * result + value.contentHashCode()
 | 
				
			||||||
 | 
					    return result
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -3,4 +3,4 @@ package gay.pizza.pork.bytecode
 | 
				
			|||||||
import kotlinx.serialization.Serializable
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Serializable
 | 
					@Serializable
 | 
				
			||||||
data class ConstantPool(val constants: List<ByteArray>)
 | 
					data class ConstantPool(val constants: List<Constant>)
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.bytecode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Serializable
 | 
				
			||||||
 | 
					enum class ConstantTag {
 | 
				
			||||||
 | 
					  String
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -3,16 +3,16 @@ package gay.pizza.pork.bytecode
 | 
				
			|||||||
class MutableConstantPool {
 | 
					class MutableConstantPool {
 | 
				
			||||||
  private val pool = mutableListOf<Constant>()
 | 
					  private val pool = mutableListOf<Constant>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun assign(content: ByteArray): UInt {
 | 
					  fun assign(tag: ConstantTag, content: ByteArray): UInt {
 | 
				
			||||||
    for (constant in pool) {
 | 
					    for (constant in pool) {
 | 
				
			||||||
      if (constant.value.contentEquals(content)) {
 | 
					      if (constant.value.contentEquals(content) && tag == constant.tag) {
 | 
				
			||||||
        return constant.id
 | 
					        return constant.id
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    val id = pool.size.toUInt()
 | 
					    val id = pool.size.toUInt()
 | 
				
			||||||
    pool.add(Constant(id, content))
 | 
					    pool.add(Constant(id = id, tag = tag, value = content))
 | 
				
			||||||
    return id
 | 
					    return id
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun all(): List<Constant> = pool
 | 
					  fun build(): ConstantPool = ConstantPool(pool)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.bytecode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Serializable
 | 
				
			||||||
 | 
					data class OpAnnotation(val inst: UInt, val text: String)
 | 
				
			||||||
@ -30,14 +30,16 @@ enum class Opcode(val id: UByte) {
 | 
				
			|||||||
  BinaryAnd(28u),
 | 
					  BinaryAnd(28u),
 | 
				
			||||||
  BinaryOr(29u),
 | 
					  BinaryOr(29u),
 | 
				
			||||||
  BinaryXor(30u),
 | 
					  BinaryXor(30u),
 | 
				
			||||||
  List(31u),
 | 
					  ListMake(31u),
 | 
				
			||||||
  Integer(32u),
 | 
					  ListSize(32u),
 | 
				
			||||||
  Double(33u),
 | 
					  Integer(33u),
 | 
				
			||||||
  Call(34u),
 | 
					  Double(34u),
 | 
				
			||||||
  EuclideanModulo(35u),
 | 
					  Call(35u),
 | 
				
			||||||
  Remainder(36u),
 | 
					  EuclideanModulo(36u),
 | 
				
			||||||
  Index(37u),
 | 
					  Remainder(37u),
 | 
				
			||||||
  ScopeIn(38u),
 | 
					  Index(38u),
 | 
				
			||||||
  ScopeOut(39u),
 | 
					  ScopeIn(39u),
 | 
				
			||||||
 | 
					  ScopeOut(40u),
 | 
				
			||||||
 | 
					  ReturnAddress(41u),
 | 
				
			||||||
  End(255u),
 | 
					  End(255u),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -5,4 +5,13 @@ import kotlinx.serialization.Serializable
 | 
				
			|||||||
@Serializable
 | 
					@Serializable
 | 
				
			||||||
data class SymbolTable(
 | 
					data class SymbolTable(
 | 
				
			||||||
  val symbols: List<SymbolInfo>
 | 
					  val symbols: List<SymbolInfo>
 | 
				
			||||||
)
 | 
					) {
 | 
				
			||||||
 | 
					  fun lookup(inst: UInt): Pair<SymbolInfo, UInt>? {
 | 
				
			||||||
 | 
					    val symbol = symbols.firstOrNull {
 | 
				
			||||||
 | 
					      (inst >= it.offset) && inst < (it.offset + it.size)
 | 
				
			||||||
 | 
					    } ?: return null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val rel = inst - symbol.offset
 | 
				
			||||||
 | 
					    return symbol to rel
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,7 @@ import gay.pizza.pork.bytecode.Opcode
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class CodeBuilder(val symbol: CompilableSymbol) {
 | 
					class CodeBuilder(val symbol: CompilableSymbol) {
 | 
				
			||||||
  private val ops = mutableListOf<StubOp>()
 | 
					  private val ops = mutableListOf<StubOp>()
 | 
				
			||||||
 | 
					  private val annotations = mutableListOf<StubOpAnnotation>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  val localState: LocalState = LocalState(symbol)
 | 
					  val localState: LocalState = LocalState(symbol)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -39,5 +40,9 @@ class CodeBuilder(val symbol: CompilableSymbol) {
 | 
				
			|||||||
    ops.add(PatchSymOp(Op(code, arguments), patches))
 | 
					    ops.add(PatchSymOp(Op(code, arguments), patches))
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun build(): List<StubOp> = ops.toList()
 | 
					  fun annotate(text: String) {
 | 
				
			||||||
 | 
					    annotations.add(StubOpAnnotation(symbol, nextOpInst(), text))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun build(): CompiledSymbolResult = CompiledSymbolResult(ops.toList(), annotations.toList())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -6,12 +6,12 @@ import gay.pizza.pork.ast.gen.visit
 | 
				
			|||||||
import gay.pizza.pork.frontend.scope.ScopeSymbol
 | 
					import gay.pizza.pork.frontend.scope.ScopeSymbol
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CompilableSymbol(val compilableSlab: CompilableSlab, val scopeSymbol: ScopeSymbol) {
 | 
					class CompilableSymbol(val compilableSlab: CompilableSlab, val scopeSymbol: ScopeSymbol) {
 | 
				
			||||||
  val compiledStubOps: List<StubOp> by lazy { compile() }
 | 
					  val compiledStubOps: CompiledSymbolResult by lazy { compile() }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  val usedSymbols: List<ScopeSymbol>
 | 
					  val usedSymbols: List<ScopeSymbol>
 | 
				
			||||||
    get() = scopeSymbol.scope.usedSymbols
 | 
					    get() = scopeSymbol.scope.usedSymbols
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private fun compile(): List<StubOp> {
 | 
					  private fun compile(): CompiledSymbolResult {
 | 
				
			||||||
    val emitter = StubOpEmitter(compilableSlab.compiler, this)
 | 
					    val emitter = StubOpEmitter(compilableSlab.compiler, this)
 | 
				
			||||||
    emitter.enter()
 | 
					    emitter.enter()
 | 
				
			||||||
    val what = if (scopeSymbol.definition is FunctionDefinition) {
 | 
					    val what = if (scopeSymbol.definition is FunctionDefinition) {
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.compiler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CompiledSymbolResult(val ops: List<StubOp>, val annotations: List<StubOpAnnotation>)
 | 
				
			||||||
@ -4,13 +4,16 @@ import gay.pizza.pork.bytecode.*
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class CompiledWorldLayout(val compiler: Compiler) : StubResolutionContext {
 | 
					class CompiledWorldLayout(val compiler: Compiler) : StubResolutionContext {
 | 
				
			||||||
  private val allStubOps = mutableListOf<StubOp>()
 | 
					  private val allStubOps = mutableListOf<StubOp>()
 | 
				
			||||||
 | 
					  private val allStubAnnotations = mutableListOf<StubOpAnnotation>()
 | 
				
			||||||
  private val symbolTable = mutableMapOf<CompilableSymbol, SymbolInfo>()
 | 
					  private val symbolTable = mutableMapOf<CompilableSymbol, SymbolInfo>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun add(symbol: CompilableSymbol) {
 | 
					  fun add(symbol: CompilableSymbol) {
 | 
				
			||||||
    val start = allStubOps.size
 | 
					    val start = allStubOps.size
 | 
				
			||||||
    val stubOps = symbol.compiledStubOps
 | 
					    val result = symbol.compiledStubOps
 | 
				
			||||||
 | 
					    val stubOps = result.ops
 | 
				
			||||||
    symbolTable[symbol] = SymbolInfo(symbol.id, start.toUInt(), stubOps.size.toUInt())
 | 
					    symbolTable[symbol] = SymbolInfo(symbol.id, start.toUInt(), stubOps.size.toUInt())
 | 
				
			||||||
    allStubOps.addAll(stubOps)
 | 
					    allStubOps.addAll(stubOps)
 | 
				
			||||||
 | 
					    allStubAnnotations.addAll(result.annotations)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private fun patch(): List<Op> {
 | 
					  private fun patch(): List<Op> {
 | 
				
			||||||
@ -23,16 +26,24 @@ class CompiledWorldLayout(val compiler: Compiler) : StubResolutionContext {
 | 
				
			|||||||
    return ops
 | 
					    return ops
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun patchAnnotations(): List<OpAnnotation> {
 | 
				
			||||||
 | 
					    val annotations = mutableListOf<OpAnnotation>()
 | 
				
			||||||
 | 
					    for (stub in allStubAnnotations) {
 | 
				
			||||||
 | 
					      val actual = symbolTable[stub.symbol]!!.offset + stub.rel
 | 
				
			||||||
 | 
					      annotations.add(OpAnnotation(actual, stub.text))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return annotations
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun resolveJumpTarget(symbol: CompilableSymbol): UInt {
 | 
					  override fun resolveJumpTarget(symbol: CompilableSymbol): UInt {
 | 
				
			||||||
    return symbolTable[symbol]?.offset ?:
 | 
					    return symbolTable[symbol]?.offset ?:
 | 
				
			||||||
      throw RuntimeException("Unable to resolve jump target: ${symbol.scopeSymbol.symbol.id}")
 | 
					      throw RuntimeException("Unable to resolve jump target: ${symbol.scopeSymbol.symbol.id}")
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun layoutCompiledWorld(): CompiledWorld {
 | 
					  fun build(): CompiledWorld = CompiledWorld(
 | 
				
			||||||
    val constantPool = mutableListOf<ByteArray>()
 | 
					    constantPool = compiler.constantPool.build(),
 | 
				
			||||||
    for (item in compiler.constantPool.all()) {
 | 
					    symbolTable = SymbolTable(symbolTable.values.toList()),
 | 
				
			||||||
      constantPool.add(item.value)
 | 
					    code = patch(),
 | 
				
			||||||
    }
 | 
					    annotations = patchAnnotations()
 | 
				
			||||||
    return CompiledWorld(ConstantPool(constantPool), SymbolTable(symbolTable.values.toList()), patch())
 | 
					  )
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -42,6 +42,6 @@ class Compiler {
 | 
				
			|||||||
    for (used in usedSymbolSet) {
 | 
					    for (used in usedSymbolSet) {
 | 
				
			||||||
      layout.add(used)
 | 
					      layout.add(used)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return layout.layoutCompiledWorld()
 | 
					    return layout.build()
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -31,6 +31,13 @@ class LocalState(val symbol: CompilableSymbol) {
 | 
				
			|||||||
    return variable
 | 
					    return variable
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun createAnonymousLocal(): StubVar {
 | 
				
			||||||
 | 
					    val scope = variables.last()
 | 
				
			||||||
 | 
					    val variable = StubVar(localVarIndex++)
 | 
				
			||||||
 | 
					    scope.add(variable)
 | 
				
			||||||
 | 
					    return variable
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun pushScope() {
 | 
					  fun pushScope() {
 | 
				
			||||||
    variables.add(mutableListOf())
 | 
					    variables.add(mutableListOf())
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.compiler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					data class StubOpAnnotation(val symbol: CompilableSymbol, val rel: UInt, val text: String)
 | 
				
			||||||
@ -2,11 +2,12 @@ package gay.pizza.pork.compiler
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import gay.pizza.pork.ast.FunctionLevelVisitor
 | 
					import gay.pizza.pork.ast.FunctionLevelVisitor
 | 
				
			||||||
import gay.pizza.pork.ast.gen.*
 | 
					import gay.pizza.pork.ast.gen.*
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.ConstantTag
 | 
				
			||||||
import gay.pizza.pork.bytecode.MutableRel
 | 
					import gay.pizza.pork.bytecode.MutableRel
 | 
				
			||||||
import gay.pizza.pork.bytecode.Opcode
 | 
					import gay.pizza.pork.bytecode.Opcode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class StubOpEmitter(val compiler: Compiler, val symbol: CompilableSymbol) : FunctionLevelVisitor<Unit>() {
 | 
					class StubOpEmitter(val compiler: Compiler, val symbol: CompilableSymbol) : FunctionLevelVisitor<Unit>() {
 | 
				
			||||||
  val code = CodeBuilder(symbol)
 | 
					  val code: CodeBuilder = CodeBuilder(symbol)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun allocateOuterScope(definition: FunctionDefinition) {
 | 
					  fun allocateOuterScope(definition: FunctionDefinition) {
 | 
				
			||||||
    val allNormalArguments = definition.arguments.takeWhile { !it.multiple }
 | 
					    val allNormalArguments = definition.arguments.takeWhile { !it.multiple }
 | 
				
			||||||
@ -55,7 +56,35 @@ class StubOpEmitter(val compiler: Compiler, val symbol: CompilableSymbol) : Func
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun visitForIn(node: ForIn) {
 | 
					  override fun visitForIn(node: ForIn) {
 | 
				
			||||||
    TODO("ForIn is currently unsupported")
 | 
					    val listLocalVar = code.localState.createAnonymousLocal()
 | 
				
			||||||
 | 
					    val sizeLocalVar = code.localState.createAnonymousLocal()
 | 
				
			||||||
 | 
					    val currentIndexVar = code.localState.createAnonymousLocal()
 | 
				
			||||||
 | 
					    val currentValueVar = code.localState.createLocal(node.item.symbol)
 | 
				
			||||||
 | 
					    node.expression.visit(this)
 | 
				
			||||||
 | 
					    code.emit(Opcode.StoreLocal, listOf(listLocalVar.index))
 | 
				
			||||||
 | 
					    load(Loadable(stubVar = listLocalVar))
 | 
				
			||||||
 | 
					    code.emit(Opcode.ListSize)
 | 
				
			||||||
 | 
					    code.emit(Opcode.StoreLocal, listOf(sizeLocalVar.index))
 | 
				
			||||||
 | 
					    code.emit(Opcode.Integer, listOf(0u))
 | 
				
			||||||
 | 
					    code.emit(Opcode.StoreLocal, listOf(currentIndexVar.index))
 | 
				
			||||||
 | 
					    val endOfLoop = MutableRel(0u)
 | 
				
			||||||
 | 
					    val startOfLoop = code.nextOpInst()
 | 
				
			||||||
 | 
					    code.localState.startLoop(startOfLoop, endOfLoop)
 | 
				
			||||||
 | 
					    load(Loadable(stubVar = currentIndexVar))
 | 
				
			||||||
 | 
					    load(Loadable(stubVar = sizeLocalVar))
 | 
				
			||||||
 | 
					    code.emit(Opcode.CompareGreaterEqual)
 | 
				
			||||||
 | 
					    code.patch(Opcode.JumpIf, listOf(0u), 0, symbol, endOfLoop)
 | 
				
			||||||
 | 
					    load(Loadable(stubVar = currentIndexVar))
 | 
				
			||||||
 | 
					    load(Loadable(stubVar = listLocalVar))
 | 
				
			||||||
 | 
					    code.emit(Opcode.Index)
 | 
				
			||||||
 | 
					    code.emit(Opcode.StoreLocal, listOf(currentValueVar.index))
 | 
				
			||||||
 | 
					    node.block.visit(this)
 | 
				
			||||||
 | 
					    code.emit(Opcode.LoadLocal, listOf(currentIndexVar.index))
 | 
				
			||||||
 | 
					    code.emit(Opcode.Integer, listOf(1u))
 | 
				
			||||||
 | 
					    code.emit(Opcode.Add)
 | 
				
			||||||
 | 
					    code.emit(Opcode.StoreLocal, listOf(currentIndexVar.index))
 | 
				
			||||||
 | 
					    code.patch(Opcode.Jump, listOf(0u), 0, symbol, startOfLoop)
 | 
				
			||||||
 | 
					    endOfLoop.rel = code.nextOpInst()
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun visitFunctionCall(node: FunctionCall) {
 | 
					  override fun visitFunctionCall(node: FunctionCall) {
 | 
				
			||||||
@ -64,10 +93,12 @@ class StubOpEmitter(val compiler: Compiler, val symbol: CompilableSymbol) : Func
 | 
				
			|||||||
    val targetSymbol = compiler.resolve(targetScopeSymbol)
 | 
					    val targetSymbol = compiler.resolve(targetScopeSymbol)
 | 
				
			||||||
    val functionDefinition = targetSymbol.scopeSymbol.definition as FunctionDefinition
 | 
					    val functionDefinition = targetSymbol.scopeSymbol.definition as FunctionDefinition
 | 
				
			||||||
    val retRel = MutableRel(0u)
 | 
					    val retRel = MutableRel(0u)
 | 
				
			||||||
    code.patch(Opcode.Integer, listOf(0u), 0, symbol, retRel)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    val normalArguments = mutableListOf<Expression>()
 | 
					    val normalArguments = mutableListOf<Expression>()
 | 
				
			||||||
    var variableArguments: List<Expression>? = null
 | 
					    var variableArguments: List<Expression>? = null
 | 
				
			||||||
 | 
					    if (functionDefinition.arguments.any { it.multiple }) {
 | 
				
			||||||
 | 
					      variableArguments = emptyList()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for ((index, item) in functionDefinition.arguments.zip(node.arguments).withIndex()) {
 | 
					    for ((index, item) in functionDefinition.arguments.zip(node.arguments).withIndex()) {
 | 
				
			||||||
      val (spec, value) = item
 | 
					      val (spec, value) = item
 | 
				
			||||||
      if (spec.multiple) {
 | 
					      if (spec.multiple) {
 | 
				
			||||||
@ -83,14 +114,15 @@ class StubOpEmitter(val compiler: Compiler, val symbol: CompilableSymbol) : Func
 | 
				
			|||||||
      for (item in variableArguments.reversed()) {
 | 
					      for (item in variableArguments.reversed()) {
 | 
				
			||||||
        item.visit(this)
 | 
					        item.visit(this)
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      code.emit(Opcode.List, listOf(variableArguments.size.toUInt()))
 | 
					      code.emit(Opcode.ListMake, listOf(variableArguments.size.toUInt()))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (item in normalArguments.reversed()) {
 | 
					    for (item in normalArguments.reversed()) {
 | 
				
			||||||
      visit(item)
 | 
					      visit(item)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    retRel.rel = code.nextOpInst() + 1u
 | 
					    retRel.rel = code.nextOpInst() + 2u
 | 
				
			||||||
 | 
					    code.patch(Opcode.ReturnAddress, listOf(0u), 0, symbol, retRel)
 | 
				
			||||||
    code.patch(Opcode.Call, listOf(0u), mapOf(0 to targetSymbol))
 | 
					    code.patch(Opcode.Call, listOf(0u), mapOf(0 to targetSymbol))
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -154,7 +186,7 @@ class StubOpEmitter(val compiler: Compiler, val symbol: CompilableSymbol) : Func
 | 
				
			|||||||
    for (item in node.items) {
 | 
					    for (item in node.items) {
 | 
				
			||||||
      item.visit(this)
 | 
					      item.visit(this)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    code.emit(Opcode.List, listOf(count.toUInt()))
 | 
					    code.emit(Opcode.ListMake, listOf(count.toUInt()))
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun visitLongLiteral(node: LongLiteral) {
 | 
					  override fun visitLongLiteral(node: LongLiteral) {
 | 
				
			||||||
@ -190,7 +222,7 @@ class StubOpEmitter(val compiler: Compiler, val symbol: CompilableSymbol) : Func
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  override fun visitStringLiteral(node: StringLiteral) {
 | 
					  override fun visitStringLiteral(node: StringLiteral) {
 | 
				
			||||||
    val bytes = node.text.toByteArray()
 | 
					    val bytes = node.text.toByteArray()
 | 
				
			||||||
    val constant = compiler.constantPool.assign(bytes)
 | 
					    val constant = compiler.constantPool.assign(ConstantTag.String, bytes)
 | 
				
			||||||
    code.emit(Opcode.Constant, listOf(constant))
 | 
					    code.emit(Opcode.Constant, listOf(constant))
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -243,10 +275,10 @@ class StubOpEmitter(val compiler: Compiler, val symbol: CompilableSymbol) : Func
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  override fun visitNativeFunctionDescriptor(node: NativeFunctionDescriptor) {
 | 
					  override fun visitNativeFunctionDescriptor(node: NativeFunctionDescriptor) {
 | 
				
			||||||
    for (def in node.definitions) {
 | 
					    for (def in node.definitions) {
 | 
				
			||||||
      val defConstant = compiler.constantPool.assign(def.text.toByteArray())
 | 
					      val defConstant = compiler.constantPool.assign(ConstantTag.String, def.text.toByteArray())
 | 
				
			||||||
      code.emit(Opcode.Constant, listOf(defConstant))
 | 
					      code.emit(Opcode.Constant, listOf(defConstant))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    val formConstant = compiler.constantPool.assign(node.form.id.toByteArray())
 | 
					    val formConstant = compiler.constantPool.assign(ConstantTag.String, node.form.id.toByteArray())
 | 
				
			||||||
    code.emit(Opcode.Native, listOf(formConstant, node.definitions.size.toUInt()))
 | 
					    code.emit(Opcode.Native, listOf(formConstant, node.definitions.size.toUInt()))
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -4,5 +4,5 @@ import gay.pizza.pork.ast.gen.Symbol
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class StubVar(
 | 
					class StubVar(
 | 
				
			||||||
  val index: UInt,
 | 
					  val index: UInt,
 | 
				
			||||||
  val symbol: Symbol
 | 
					  val symbol: Symbol? = null
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,7 @@ import com.intellij.navigation.ItemPresentation
 | 
				
			|||||||
import gay.pizza.pork.idea.psi.PorkElementHelpers
 | 
					import gay.pizza.pork.idea.psi.PorkElementHelpers
 | 
				
			||||||
import javax.swing.Icon
 | 
					import javax.swing.Icon
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NativeElement(node: ASTNode) : PorkElement(node) {
 | 
					class NativeFunctionDescriptorElement(node: ASTNode) : PorkElement(node) {
 | 
				
			||||||
  override fun getIcon(flags: Int): Icon? =
 | 
					  override fun getIcon(flags: Int): Icon? =
 | 
				
			||||||
    PorkElementHelpers.iconOf(this)
 | 
					    PorkElementHelpers.iconOf(this)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -40,7 +40,7 @@ object PorkElementFactory {
 | 
				
			|||||||
      NodeType.Break -> BreakElement(node)
 | 
					      NodeType.Break -> BreakElement(node)
 | 
				
			||||||
      NodeType.Continue -> ContinueElement(node)
 | 
					      NodeType.Continue -> ContinueElement(node)
 | 
				
			||||||
      NodeType.NoneLiteral -> NoneLiteralElement(node)
 | 
					      NodeType.NoneLiteral -> NoneLiteralElement(node)
 | 
				
			||||||
      NodeType.Native -> NativeElement(node)
 | 
					      NodeType.NativeFunctionDescriptor -> NativeFunctionDescriptorElement(node)
 | 
				
			||||||
      NodeType.IndexedBy -> IndexedByElement(node)
 | 
					      NodeType.IndexedBy -> IndexedByElement(node)
 | 
				
			||||||
      else -> ASTWrapperPsiElement(node)
 | 
					      else -> ASTWrapperPsiElement(node)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -24,7 +24,12 @@ class CompileCommand : CliktCommand(help = "Compile Pork to Bytecode", name = "c
 | 
				
			|||||||
      val code = compiledWorld.code.subList(symbol.offset.toInt(), (symbol.offset + symbol.size).toInt())
 | 
					      val code = compiledWorld.code.subList(symbol.offset.toInt(), (symbol.offset + symbol.size).toInt())
 | 
				
			||||||
      println(symbol.id)
 | 
					      println(symbol.id)
 | 
				
			||||||
      for ((index, op) in code.withIndex()) {
 | 
					      for ((index, op) in code.withIndex()) {
 | 
				
			||||||
        println("  ${symbol.offset + index.toUInt()} ${op.code.name} ${op.args.joinToString(" ")}")
 | 
					        var annotation = ""
 | 
				
			||||||
 | 
					        val annotations = compiledWorld.annotations.filter { it.inst == (symbol.offset + index.toUInt()) }
 | 
				
			||||||
 | 
					        if (annotations.isNotEmpty()) {
 | 
				
			||||||
 | 
					          annotation = " ; ${annotations.joinToString(", ") { it.text}}"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        println("  ${symbol.offset + index.toUInt()} ${op.code.name} ${op.args.joinToString(" ")}${annotation}")
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    val vm = VirtualMachine(compiledWorld)
 | 
					    val vm = VirtualMachine(compiledWorld)
 | 
				
			||||||
 | 
				
			|||||||
@ -20,7 +20,7 @@ class ScopeAnalysisCommand : CliktCommand(help = "Run Scope Analysis", name = "s
 | 
				
			|||||||
        "symbol ${visibleScopeSymbol.scopeSymbol.symbol.id} " +
 | 
					        "symbol ${visibleScopeSymbol.scopeSymbol.symbol.id} " +
 | 
				
			||||||
        "type=${visibleScopeSymbol.scopeSymbol.definition.type.name} " +
 | 
					        "type=${visibleScopeSymbol.scopeSymbol.definition.type.name} " +
 | 
				
			||||||
        "internal=${visibleScopeSymbol.isInternalSymbol} " +
 | 
					        "internal=${visibleScopeSymbol.isInternalSymbol} " +
 | 
				
			||||||
        "slab=${visibleScopeSymbol.scopeSymbol.slab.location.commonFriendlyName}"
 | 
					        "slab=${visibleScopeSymbol.scopeSymbol.slabScope.slab.location.commonFriendlyName}"
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
package gay.pizza.pork.vm
 | 
					package gay.pizza.pork.vm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import gay.pizza.pork.bytecode.CompiledWorld
 | 
					import gay.pizza.pork.bytecode.CompiledWorld
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.ConstantTag
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class InternalMachine(val world: CompiledWorld, val handlers: List<OpHandler>) {
 | 
					class InternalMachine(val world: CompiledWorld, val handlers: List<OpHandler>) {
 | 
				
			||||||
  private val inlined = world.code.map { op ->
 | 
					  private val inlined = world.code.map { op ->
 | 
				
			||||||
@ -10,10 +11,12 @@ class InternalMachine(val world: CompiledWorld, val handlers: List<OpHandler>) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private var inst: UInt = 0u
 | 
					  private var inst: UInt = 0u
 | 
				
			||||||
  private val stack = mutableListOf<Any>(EndOfCode)
 | 
					  private val stack = mutableListOf<Any>()
 | 
				
			||||||
  private val locals = mutableListOf<MutableMap<UInt, Any>>(
 | 
					  private val locals = mutableListOf<MutableMap<UInt, Any>>(
 | 
				
			||||||
    mutableMapOf()
 | 
					    mutableMapOf()
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
 | 
					  private val callStack = mutableListOf(0u)
 | 
				
			||||||
 | 
					  private val returnAddressStack = mutableListOf<UInt>()
 | 
				
			||||||
  private var autoNextInst = true
 | 
					  private var autoNextInst = true
 | 
				
			||||||
  private var exitFlag = false
 | 
					  private var exitFlag = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -36,7 +39,11 @@ class InternalMachine(val world: CompiledWorld, val handlers: List<OpHandler>) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun loadConstant(id: UInt) {
 | 
					  fun loadConstant(id: UInt) {
 | 
				
			||||||
    push(world.constantPool.constants[id.toInt()])
 | 
					    val constant = world.constantPool.constants[id.toInt()]
 | 
				
			||||||
 | 
					    when (constant.tag) {
 | 
				
			||||||
 | 
					      ConstantTag.String -> push(String(constant.value))
 | 
				
			||||||
 | 
					      else -> throw VirtualMachineException("Unknown Constant Tag: ${constant.tag.name}")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun loadLocal(id: UInt) {
 | 
					  fun loadLocal(id: UInt) {
 | 
				
			||||||
@ -48,7 +55,7 @@ class InternalMachine(val world: CompiledWorld, val handlers: List<OpHandler>) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  fun storeLocal(id: UInt) {
 | 
					  fun storeLocal(id: UInt) {
 | 
				
			||||||
    val localSet = locals.last()
 | 
					    val localSet = locals.last()
 | 
				
			||||||
    val value = pop()
 | 
					    val value = popAnyValue()
 | 
				
			||||||
    localSet[id] = value
 | 
					    localSet[id] = value
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -57,24 +64,47 @@ class InternalMachine(val world: CompiledWorld, val handlers: List<OpHandler>) {
 | 
				
			|||||||
    autoNextInst = false
 | 
					    autoNextInst = false
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun pushReturnAddress(value: UInt) {
 | 
				
			||||||
 | 
					    returnAddressStack.add(value)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun pushCallStack(value: UInt) {
 | 
				
			||||||
 | 
					    callStack.add(value)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun popCallStack() {
 | 
				
			||||||
 | 
					    callStack.removeLast()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun armReturnAddressIfSet() {
 | 
				
			||||||
 | 
					    val returnAddress = returnAddressStack.removeLastOrNull()
 | 
				
			||||||
 | 
					    if (returnAddress != null) {
 | 
				
			||||||
 | 
					      setNextInst(returnAddress)
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      exit()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun push(item: Any) {
 | 
					  fun push(item: Any) {
 | 
				
			||||||
    stack.add(item)
 | 
					    stack.add(item)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun pop(): Any = stack.removeLast()
 | 
					  fun popAnyValue(): Any = stack.removeLast()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  inline fun <reified T> pop(): T = popAnyValue() as T
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun exit() {
 | 
					  fun exit() {
 | 
				
			||||||
    exitFlag = true
 | 
					    exitFlag = true
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun reset() {
 | 
					  fun reset() {
 | 
				
			||||||
    stack.clear()
 | 
					    stack.clear()
 | 
				
			||||||
    stack.add(EndOfCode)
 | 
					    callStack.clear()
 | 
				
			||||||
 | 
					    callStack.add(0u)
 | 
				
			||||||
    locals.clear()
 | 
					    locals.clear()
 | 
				
			||||||
    locals.add(mutableMapOf())
 | 
					    locals.add(mutableMapOf())
 | 
				
			||||||
    inst = 0u
 | 
					    inst = 0u
 | 
				
			||||||
    exitFlag = false
 | 
					    exitFlag = false
 | 
				
			||||||
    autoNextInst = true
 | 
					    autoNextInst = true
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					 | 
				
			||||||
  data object EndOfCode
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -12,10 +12,18 @@ class VirtualMachine(world: CompiledWorld) : ExecutionContext {
 | 
				
			|||||||
    TrueOpHandler,
 | 
					    TrueOpHandler,
 | 
				
			||||||
    FalseOpHandler,
 | 
					    FalseOpHandler,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ListOpHandler,
 | 
					    ListMakeOpHandler,
 | 
				
			||||||
 | 
					    ListSizeOpHandler,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    IndexOpHandler,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    AndOpHandler,
 | 
				
			||||||
 | 
					    OrOpHandler,
 | 
				
			||||||
 | 
					    NotOpHandler,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    CompareEqualOpHandler,
 | 
					    CompareEqualOpHandler,
 | 
				
			||||||
    CompareLesserEqualOpHandler,
 | 
					    CompareLesserEqualOpHandler,
 | 
				
			||||||
 | 
					    CompareGreaterEqualOpHandler,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    AddOpHandler,
 | 
					    AddOpHandler,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -25,13 +33,16 @@ class VirtualMachine(world: CompiledWorld) : ExecutionContext {
 | 
				
			|||||||
    LoadLocalOpHandler,
 | 
					    LoadLocalOpHandler,
 | 
				
			||||||
    StoreLocalOpHandler,
 | 
					    StoreLocalOpHandler,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ReturnAddressOpHandler,
 | 
				
			||||||
    CallOpHandler,
 | 
					    CallOpHandler,
 | 
				
			||||||
    RetOpHandler,
 | 
					    ReturnOpHandler,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    NativeOpHandler,
 | 
					    NativeOpHandler,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ScopeInOpHandler,
 | 
					    ScopeInOpHandler,
 | 
				
			||||||
    ScopeOutOpHandler
 | 
					    ScopeOutOpHandler,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    EndOpHandler
 | 
				
			||||||
  ))
 | 
					  ))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun execute() {
 | 
					  override fun execute() {
 | 
				
			||||||
 | 
				
			|||||||
@ -4,16 +4,11 @@ import gay.pizza.pork.bytecode.Op
 | 
				
			|||||||
import gay.pizza.pork.bytecode.Opcode
 | 
					import gay.pizza.pork.bytecode.Opcode
 | 
				
			||||||
import gay.pizza.pork.vm.InternalMachine
 | 
					import gay.pizza.pork.vm.InternalMachine
 | 
				
			||||||
import gay.pizza.pork.vm.OpHandler
 | 
					import gay.pizza.pork.vm.OpHandler
 | 
				
			||||||
import gay.pizza.pork.vm.VirtualMachineException
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
object AddOpHandler : OpHandler(Opcode.Add) {
 | 
					object AddOpHandler : OpHandler(Opcode.Add) {
 | 
				
			||||||
  override fun handle(machine: InternalMachine, op: Op) {
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
    val left = machine.pop()
 | 
					    val left = machine.pop<Int>()
 | 
				
			||||||
    val right = machine.pop()
 | 
					    val right = machine.pop<Int>()
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (left !is Int || right !is Int) {
 | 
					 | 
				
			||||||
      throw VirtualMachineException("Bad types.")
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    machine.push(left + right)
 | 
					    machine.push(left + right)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										14
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/AndOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/AndOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.vm.ops
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.Op
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.Opcode
 | 
				
			||||||
 | 
					import gay.pizza.pork.vm.InternalMachine
 | 
				
			||||||
 | 
					import gay.pizza.pork.vm.OpHandler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object AndOpHandler : OpHandler(Opcode.And) {
 | 
				
			||||||
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
 | 
					    val left = machine.pop<Boolean>()
 | 
				
			||||||
 | 
					    val right = machine.pop<Boolean>()
 | 
				
			||||||
 | 
					    machine.push(left && right)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -8,6 +8,7 @@ import gay.pizza.pork.vm.OpHandler
 | 
				
			|||||||
object CallOpHandler : OpHandler(Opcode.Call) {
 | 
					object CallOpHandler : OpHandler(Opcode.Call) {
 | 
				
			||||||
  override fun handle(machine: InternalMachine, op: Op) {
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
    machine.setNextInst(op.args[0])
 | 
					    machine.setNextInst(op.args[0])
 | 
				
			||||||
 | 
					    machine.pushCallStack(op.args[0])
 | 
				
			||||||
    machine.pushScope()
 | 
					    machine.pushScope()
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -7,6 +7,6 @@ import gay.pizza.pork.vm.OpHandler
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
object CompareEqualOpHandler : OpHandler(Opcode.CompareEqual) {
 | 
					object CompareEqualOpHandler : OpHandler(Opcode.CompareEqual) {
 | 
				
			||||||
  override fun handle(machine: InternalMachine, op: Op) {
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
    machine.push(machine.pop() == machine.pop())
 | 
					    machine.push(machine.popAnyValue() == machine.popAnyValue())
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.vm.ops
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.Op
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.Opcode
 | 
				
			||||||
 | 
					import gay.pizza.pork.vm.InternalMachine
 | 
				
			||||||
 | 
					import gay.pizza.pork.vm.OpHandler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object CompareGreaterEqualOpHandler : OpHandler(Opcode.CompareGreaterEqual) {
 | 
				
			||||||
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
 | 
					    val right = machine.pop<Int>()
 | 
				
			||||||
 | 
					    val left = machine.pop<Int>()
 | 
				
			||||||
 | 
					    machine.push(left >= right)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -4,16 +4,11 @@ import gay.pizza.pork.bytecode.Op
 | 
				
			|||||||
import gay.pizza.pork.bytecode.Opcode
 | 
					import gay.pizza.pork.bytecode.Opcode
 | 
				
			||||||
import gay.pizza.pork.vm.InternalMachine
 | 
					import gay.pizza.pork.vm.InternalMachine
 | 
				
			||||||
import gay.pizza.pork.vm.OpHandler
 | 
					import gay.pizza.pork.vm.OpHandler
 | 
				
			||||||
import gay.pizza.pork.vm.VirtualMachineException
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
object CompareLesserEqualOpHandler : OpHandler(Opcode.CompareLesserEqual) {
 | 
					object CompareLesserEqualOpHandler : OpHandler(Opcode.CompareLesserEqual) {
 | 
				
			||||||
  override fun handle(machine: InternalMachine, op: Op) {
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
    val right = machine.pop()
 | 
					    val right = machine.pop<Int>()
 | 
				
			||||||
    val left = machine.pop()
 | 
					    val left = machine.pop<Int>()
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (left !is Int || right !is Int) {
 | 
					 | 
				
			||||||
      throw VirtualMachineException("Bad types.")
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    machine.push(left <= right)
 | 
					    machine.push(left <= right)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										12
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/EndOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/EndOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.vm.ops
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.Op
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.Opcode
 | 
				
			||||||
 | 
					import gay.pizza.pork.vm.InternalMachine
 | 
				
			||||||
 | 
					import gay.pizza.pork.vm.OpHandler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object EndOpHandler : OpHandler(Opcode.End) {
 | 
				
			||||||
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
 | 
					    machine.exit()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										14
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/IndexOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/IndexOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.vm.ops
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.Op
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.Opcode
 | 
				
			||||||
 | 
					import gay.pizza.pork.vm.InternalMachine
 | 
				
			||||||
 | 
					import gay.pizza.pork.vm.OpHandler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object IndexOpHandler : OpHandler(Opcode.Index) {
 | 
				
			||||||
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
 | 
					    val list = machine.pop<List<*>>()
 | 
				
			||||||
 | 
					    val index = machine.pop<Number>().toInt()
 | 
				
			||||||
 | 
					    machine.push(list[index] as Any)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -8,11 +8,7 @@ import gay.pizza.pork.vm.VirtualMachineException
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
object JumpIfOpHandler : OpHandler(Opcode.JumpIf) {
 | 
					object JumpIfOpHandler : OpHandler(Opcode.JumpIf) {
 | 
				
			||||||
  override fun handle(machine: InternalMachine, op: Op) {
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
    val value = machine.pop()
 | 
					    val value = machine.pop<Boolean>()
 | 
				
			||||||
    if (value !is Boolean) {
 | 
					 | 
				
			||||||
      throw VirtualMachineException("JumpIf expects a boolean value on the stack.")
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (value) {
 | 
					    if (value) {
 | 
				
			||||||
      machine.setNextInst(op.args[0])
 | 
					      machine.setNextInst(op.args[0])
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -5,12 +5,12 @@ import gay.pizza.pork.bytecode.Opcode
 | 
				
			|||||||
import gay.pizza.pork.vm.InternalMachine
 | 
					import gay.pizza.pork.vm.InternalMachine
 | 
				
			||||||
import gay.pizza.pork.vm.OpHandler
 | 
					import gay.pizza.pork.vm.OpHandler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
object ListOpHandler : OpHandler(Opcode.List) {
 | 
					object ListMakeOpHandler : OpHandler(Opcode.ListMake) {
 | 
				
			||||||
  override fun handle(machine: InternalMachine, op: Op) {
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
    val count = op.args[0]
 | 
					    val count = op.args[0]
 | 
				
			||||||
    val list = mutableListOf<Any>()
 | 
					    val list = mutableListOf<Any>()
 | 
				
			||||||
    for (i in 1u..count) {
 | 
					    for (i in 1u..count) {
 | 
				
			||||||
      val item = machine.pop()
 | 
					      val item = machine.popAnyValue()
 | 
				
			||||||
      list.add(item)
 | 
					      list.add(item)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    machine.push(list.reversed())
 | 
					    machine.push(list.reversed())
 | 
				
			||||||
@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.vm.ops
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.Op
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.Opcode
 | 
				
			||||||
 | 
					import gay.pizza.pork.vm.InternalMachine
 | 
				
			||||||
 | 
					import gay.pizza.pork.vm.OpHandler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object ListSizeOpHandler : OpHandler(Opcode.ListSize) {
 | 
				
			||||||
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
 | 
					    val list = machine.pop<List<*>>()
 | 
				
			||||||
 | 
					    machine.push(list.size)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -10,7 +10,7 @@ object NativeOpHandler : OpHandler(Opcode.Native) {
 | 
				
			|||||||
    val countOfNativeDefs = op.args[1].toInt()
 | 
					    val countOfNativeDefs = op.args[1].toInt()
 | 
				
			||||||
    val defs = mutableListOf<Any>()
 | 
					    val defs = mutableListOf<Any>()
 | 
				
			||||||
    for (i in 0 until countOfNativeDefs) {
 | 
					    for (i in 0 until countOfNativeDefs) {
 | 
				
			||||||
      defs.add(String(machine.pop() as ByteArray))
 | 
					      defs.add(machine.pop() as String)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										12
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/NotOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/NotOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.vm.ops
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.Op
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.Opcode
 | 
				
			||||||
 | 
					import gay.pizza.pork.vm.InternalMachine
 | 
				
			||||||
 | 
					import gay.pizza.pork.vm.OpHandler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object NotOpHandler : OpHandler(Opcode.Not) {
 | 
				
			||||||
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
 | 
					    machine.push(!machine.pop<Boolean>())
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										14
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/OrOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/OrOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.vm.ops
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.Op
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.Opcode
 | 
				
			||||||
 | 
					import gay.pizza.pork.vm.InternalMachine
 | 
				
			||||||
 | 
					import gay.pizza.pork.vm.OpHandler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object OrOpHandler : OpHandler(Opcode.Or) {
 | 
				
			||||||
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
 | 
					    val left = machine.pop<Boolean>()
 | 
				
			||||||
 | 
					    val right = machine.pop<Boolean>()
 | 
				
			||||||
 | 
					    machine.push(left || right)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.vm.ops
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.Op
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.Opcode
 | 
				
			||||||
 | 
					import gay.pizza.pork.vm.InternalMachine
 | 
				
			||||||
 | 
					import gay.pizza.pork.vm.OpHandler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object ReturnAddressOpHandler : OpHandler(Opcode.ReturnAddress) {
 | 
				
			||||||
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
 | 
					    machine.pushReturnAddress(op.args[0])
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -5,14 +5,10 @@ import gay.pizza.pork.bytecode.Opcode
 | 
				
			|||||||
import gay.pizza.pork.vm.InternalMachine
 | 
					import gay.pizza.pork.vm.InternalMachine
 | 
				
			||||||
import gay.pizza.pork.vm.OpHandler
 | 
					import gay.pizza.pork.vm.OpHandler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
object RetOpHandler : OpHandler(Opcode.Return) {
 | 
					object ReturnOpHandler : OpHandler(Opcode.Return) {
 | 
				
			||||||
  override fun handle(machine: InternalMachine, op: Op) {
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
    val last = machine.pop()
 | 
					 | 
				
			||||||
    if (last == InternalMachine.EndOfCode) {
 | 
					 | 
				
			||||||
      machine.exit()
 | 
					 | 
				
			||||||
      return
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    machine.popScope()
 | 
					    machine.popScope()
 | 
				
			||||||
    machine.setNextInst((last as Int).toUInt())
 | 
					    machine.armReturnAddressIfSet()
 | 
				
			||||||
 | 
					    machine.popCallStack()
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user