mirror of
				https://github.com/GayPizzaSpecifications/pork.git
				synced 2025-11-03 17:39:38 +00:00 
			
		
		
		
	vm: very basic virtual machine
This commit is contained in:
		@ -0,0 +1,42 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.ast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.gen.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					abstract class FunctionLevelVisitor<T> : NodeVisitor<T> {
 | 
				
			||||||
 | 
					  override fun visitForInItem(node: ForInItem): T =
 | 
				
			||||||
 | 
					    throw RuntimeException("Visiting ForInItem is not supported.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitSymbol(node: Symbol): T =
 | 
				
			||||||
 | 
					    throw RuntimeException("Visiting Symbol is not supported.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitLetDefinition(node: LetDefinition): T {
 | 
				
			||||||
 | 
					    topLevelUsedError("LetDefinition")
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitArgumentSpec(node: ArgumentSpec): T =
 | 
				
			||||||
 | 
					    throw RuntimeException("Visiting ArgumentSpec is not supported.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitFunctionDefinition(node: FunctionDefinition): T {
 | 
				
			||||||
 | 
					    topLevelUsedError("FunctionDefinition")
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitImportDeclaration(node: ImportDeclaration): T {
 | 
				
			||||||
 | 
					    topLevelUsedError("ImportDeclaration")
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitImportPath(node: ImportPath): T {
 | 
				
			||||||
 | 
					    topLevelUsedError("ImportPath")
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitCompilationUnit(node: CompilationUnit): T {
 | 
				
			||||||
 | 
					    topLevelUsedError("CompilationUnit")
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitNativeFunctionDescriptor(node: NativeFunctionDescriptor): T {
 | 
				
			||||||
 | 
					    topLevelUsedError("NativeFunctionDescriptor")
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun topLevelUsedError(name: String): Nothing {
 | 
				
			||||||
 | 
					    throw RuntimeException("$name cannot be visited in a FunctionVisitor.")
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										7
									
								
								bytecode/build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								bytecode/build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					plugins {
 | 
				
			||||||
 | 
					  id("gay.pizza.pork.module")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dependencies {
 | 
				
			||||||
 | 
					  implementation(project(":common"))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.bytecode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Serializable
 | 
				
			||||||
 | 
					data class CompiledWorld(
 | 
				
			||||||
 | 
					  val constantPool: ConstantPool,
 | 
				
			||||||
 | 
					  val symbolTable: SymbolTable,
 | 
				
			||||||
 | 
					  val code: List<Op>
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.bytecode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Constant(val id: UInt, val value: ByteArray)
 | 
				
			||||||
@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.bytecode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Serializable
 | 
				
			||||||
 | 
					data class ConstantPool(val constants: List<ByteArray>)
 | 
				
			||||||
@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.bytecode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MutableConstantPool {
 | 
				
			||||||
 | 
					  private val pool = mutableListOf<Constant>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun assign(content: ByteArray): UInt {
 | 
				
			||||||
 | 
					    for (constant in pool) {
 | 
				
			||||||
 | 
					      if (constant.value.contentEquals(content)) {
 | 
				
			||||||
 | 
					        return constant.id
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    val id = pool.size.toUInt()
 | 
				
			||||||
 | 
					    pool.add(Constant(id, content))
 | 
				
			||||||
 | 
					    return id
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun all(): List<Constant> = pool
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.bytecode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MutableRel(var rel: UInt)
 | 
				
			||||||
							
								
								
									
										6
									
								
								bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Op.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Op.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.bytecode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Serializable
 | 
				
			||||||
 | 
					data class Op(val code: Opcode, val args: List<UInt>)
 | 
				
			||||||
							
								
								
									
										43
									
								
								bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Opcode.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Opcode.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.bytecode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class Opcode(val id: UByte) {
 | 
				
			||||||
 | 
					  Constant(1u),
 | 
				
			||||||
 | 
					  None(2u),
 | 
				
			||||||
 | 
					  False(3u),
 | 
				
			||||||
 | 
					  True(4u),
 | 
				
			||||||
 | 
					  Pop(5u),
 | 
				
			||||||
 | 
					  Jump(6u),
 | 
				
			||||||
 | 
					  JumpIf(7u),
 | 
				
			||||||
 | 
					  Not(8u),
 | 
				
			||||||
 | 
					  UnaryPlus(9u),
 | 
				
			||||||
 | 
					  UnaryMinus(10u),
 | 
				
			||||||
 | 
					  BinaryNot(11u),
 | 
				
			||||||
 | 
					  And(20u),
 | 
				
			||||||
 | 
					  Native(24u),
 | 
				
			||||||
 | 
					  Return(10u),
 | 
				
			||||||
 | 
					  StoreLocal(16u),
 | 
				
			||||||
 | 
					  LoadLocal(17u),
 | 
				
			||||||
 | 
					  Add(18u),
 | 
				
			||||||
 | 
					  Subtract(19u),
 | 
				
			||||||
 | 
					  Multiply(20u),
 | 
				
			||||||
 | 
					  Divide(21u),
 | 
				
			||||||
 | 
					  CompareEqual(22u),
 | 
				
			||||||
 | 
					  CompareLesser(23u),
 | 
				
			||||||
 | 
					  CompareGreater(24u),
 | 
				
			||||||
 | 
					  CompareLesserEqual(25u),
 | 
				
			||||||
 | 
					  CompareGreaterEqual(26u),
 | 
				
			||||||
 | 
					  Or(27u),
 | 
				
			||||||
 | 
					  BinaryAnd(28u),
 | 
				
			||||||
 | 
					  BinaryOr(29u),
 | 
				
			||||||
 | 
					  BinaryXor(30u),
 | 
				
			||||||
 | 
					  List(31u),
 | 
				
			||||||
 | 
					  Integer(32u),
 | 
				
			||||||
 | 
					  Double(33u),
 | 
				
			||||||
 | 
					  Call(34u),
 | 
				
			||||||
 | 
					  EuclideanModulo(35u),
 | 
				
			||||||
 | 
					  Remainder(36u),
 | 
				
			||||||
 | 
					  Index(37u),
 | 
				
			||||||
 | 
					  ScopeIn(38u),
 | 
				
			||||||
 | 
					  ScopeOut(39u),
 | 
				
			||||||
 | 
					  End(255u),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										3
									
								
								bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Ops.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Ops.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.bytecode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Ops(val ops: List<Op>)
 | 
				
			||||||
@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.bytecode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Serializable
 | 
				
			||||||
 | 
					data class SymbolInfo(
 | 
				
			||||||
 | 
					  val id: String,
 | 
				
			||||||
 | 
					  val offset: UInt,
 | 
				
			||||||
 | 
					  val size: UInt
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.bytecode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Serializable
 | 
				
			||||||
 | 
					data class SymbolTable(
 | 
				
			||||||
 | 
					  val symbols: List<SymbolInfo>
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.common
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object ByteRepresentation {
 | 
				
			||||||
 | 
					  fun encode(value: Int): ByteArray {
 | 
				
			||||||
 | 
					    val buffer = ByteArray(4)
 | 
				
			||||||
 | 
					    encode(value, buffer, 0)
 | 
				
			||||||
 | 
					    return buffer
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun encode(value: Long): ByteArray {
 | 
				
			||||||
 | 
					    val buffer = ByteArray(8)
 | 
				
			||||||
 | 
					    encode(value, buffer, 0)
 | 
				
			||||||
 | 
					    return buffer
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun encode(value: Double): ByteArray =
 | 
				
			||||||
 | 
					    encode(value.toRawBits())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun encode(value: Int, buffer: ByteArray, offset: Int) {
 | 
				
			||||||
 | 
					    buffer[offset + 0] = (value shr 0).toByte()
 | 
				
			||||||
 | 
					    buffer[offset + 1] = (value shr 8).toByte()
 | 
				
			||||||
 | 
					    buffer[offset + 2] = (value shr 16).toByte()
 | 
				
			||||||
 | 
					    buffer[offset + 3] = (value shr 24).toByte()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun encode(value: Long, buffer: ByteArray, offset: Int) {
 | 
				
			||||||
 | 
					    buffer[offset + 0] = (value shr 0).toByte()
 | 
				
			||||||
 | 
					    buffer[offset + 1] = (value shr 8).toByte()
 | 
				
			||||||
 | 
					    buffer[offset + 2] = (value shr 16).toByte()
 | 
				
			||||||
 | 
					    buffer[offset + 3] = (value shr 24).toByte()
 | 
				
			||||||
 | 
					    buffer[offset + 4] = (value shr 32).toByte()
 | 
				
			||||||
 | 
					    buffer[offset + 5] = (value shr 40).toByte()
 | 
				
			||||||
 | 
					    buffer[offset + 6] = (value shr 48).toByte()
 | 
				
			||||||
 | 
					    buffer[offset + 7] = (value shr 56).toByte()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun encode(value: Double, buffer: ByteArray, offset: Int) {
 | 
				
			||||||
 | 
					    encode(value.toRawBits(), buffer, offset)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										11
									
								
								compiler/build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								compiler/build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					plugins {
 | 
				
			||||||
 | 
					  id("gay.pizza.pork.module")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dependencies {
 | 
				
			||||||
 | 
					  api(project(":ast"))
 | 
				
			||||||
 | 
					  api(project(":bytecode"))
 | 
				
			||||||
 | 
					  api(project(":parser"))
 | 
				
			||||||
 | 
					  api(project(":frontend"))
 | 
				
			||||||
 | 
					  implementation(project(":common"))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.compiler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.gen.Symbol
 | 
				
			||||||
 | 
					import gay.pizza.pork.frontend.Slab
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CompilableSlab(val compiler: Compiler, val slab: Slab) {
 | 
				
			||||||
 | 
					  val compilableSymbols: List<CompilableSymbol> by lazy {
 | 
				
			||||||
 | 
					    slab.scope.internalSymbols.map { symbol ->
 | 
				
			||||||
 | 
					      CompilableSymbol(this, symbol)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun compilableSymbolOf(symbol: Symbol): CompilableSymbol? = compilableSymbols.firstOrNull {
 | 
				
			||||||
 | 
					    it.scopeSymbol.symbol == symbol
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.compiler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.gen.FunctionDefinition
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.gen.LetDefinition
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.gen.visit
 | 
				
			||||||
 | 
					import gay.pizza.pork.frontend.scope.ScopeSymbol
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CompilableSymbol(val compilableSlab: CompilableSlab, val scopeSymbol: ScopeSymbol) {
 | 
				
			||||||
 | 
					  val compiledStubOps: List<StubOp> by lazy { compile() }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val usedSymbols: List<ScopeSymbol>
 | 
				
			||||||
 | 
					    get() = scopeSymbol.scope.usedSymbols
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun compile(): List<StubOp> {
 | 
				
			||||||
 | 
					    val emitter = StubOpEmitter(compilableSlab.compiler, this)
 | 
				
			||||||
 | 
					    emitter.enter()
 | 
				
			||||||
 | 
					    val what = if (scopeSymbol.definition is FunctionDefinition) {
 | 
				
			||||||
 | 
					      val functionDefinition = scopeSymbol.definition as FunctionDefinition
 | 
				
			||||||
 | 
					      emitter.allocateOuterScope(functionDefinition)
 | 
				
			||||||
 | 
					      functionDefinition.block ?: functionDefinition.nativeFunctionDescriptor!!
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      val letDefinition = scopeSymbol.definition as LetDefinition
 | 
				
			||||||
 | 
					      letDefinition.value
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    emitter.visit(what)
 | 
				
			||||||
 | 
					    emitter.exit()
 | 
				
			||||||
 | 
					    return emitter.ops()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val id: String
 | 
				
			||||||
 | 
					    get() = "${compilableSlab.slab.location.commonFriendlyName} ${scopeSymbol.symbol.id}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun toString(): String = "${compilableSlab.slab.location.commonFriendlyName} ${scopeSymbol.symbol.id}"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.compiler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CompiledWorldLayout(val compiler: Compiler) : StubResolutionContext {
 | 
				
			||||||
 | 
					  private val allStubOps = mutableListOf<StubOp>()
 | 
				
			||||||
 | 
					  private val symbolTable = mutableMapOf<CompilableSymbol, SymbolInfo>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun add(symbol: CompilableSymbol) {
 | 
				
			||||||
 | 
					    val start = allStubOps.size
 | 
				
			||||||
 | 
					    val stubOps = symbol.compiledStubOps
 | 
				
			||||||
 | 
					    symbolTable[symbol] = SymbolInfo(symbol.id, start.toUInt(), stubOps.size.toUInt())
 | 
				
			||||||
 | 
					    allStubOps.addAll(stubOps)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun patch(): List<Op> {
 | 
				
			||||||
 | 
					    val ops = mutableListOf<Op>()
 | 
				
			||||||
 | 
					    for (stub in allStubOps) {
 | 
				
			||||||
 | 
					      val actualArguments = stub.op.args.toMutableList()
 | 
				
			||||||
 | 
					      stub.patch(this, actualArguments)
 | 
				
			||||||
 | 
					      ops.add(Op(stub.op.code, actualArguments))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return ops
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun resolveJumpTarget(symbol: CompilableSymbol): UInt {
 | 
				
			||||||
 | 
					    return symbolTable[symbol]?.offset ?:
 | 
				
			||||||
 | 
					      throw RuntimeException("Unable to resolve jump target: ${symbol.scopeSymbol.symbol.id}")
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun layoutCompiledWorld(): CompiledWorld {
 | 
				
			||||||
 | 
					    val constantPool = mutableListOf<ByteArray>()
 | 
				
			||||||
 | 
					    for (item in compiler.constantPool.all()) {
 | 
				
			||||||
 | 
					      constantPool.add(item.value)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return CompiledWorld(ConstantPool(constantPool), SymbolTable(symbolTable.values.toList()), patch())
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										47
									
								
								compiler/src/main/kotlin/gay/pizza/pork/compiler/Compiler.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								compiler/src/main/kotlin/gay/pizza/pork/compiler/Compiler.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.compiler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.CompiledWorld
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.MutableConstantPool
 | 
				
			||||||
 | 
					import gay.pizza.pork.frontend.Slab
 | 
				
			||||||
 | 
					import gay.pizza.pork.frontend.scope.ScopeSymbol
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Compiler {
 | 
				
			||||||
 | 
					  val constantPool: MutableConstantPool = MutableConstantPool()
 | 
				
			||||||
 | 
					  val compilableSlabs: ComputableState<Slab, CompilableSlab> = ComputableState { slab ->
 | 
				
			||||||
 | 
					    CompilableSlab(this, slab)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun resolveOrNull(scopeSymbol: ScopeSymbol): CompilableSymbol? {
 | 
				
			||||||
 | 
					    val compiledSlab = compilableSlabs.of(scopeSymbol.slabScope.slab)
 | 
				
			||||||
 | 
					    return compiledSlab.compilableSymbolOf(scopeSymbol.symbol)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun resolve(scopeSymbol: ScopeSymbol): CompilableSymbol = resolveOrNull(scopeSymbol) ?:
 | 
				
			||||||
 | 
					    throw RuntimeException(
 | 
				
			||||||
 | 
					      "Unable to resolve scope symbol: " +
 | 
				
			||||||
 | 
					      "${scopeSymbol.slabScope.slab.location.commonFriendlyName} ${scopeSymbol.symbol.id}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun contributeCompiledSymbols(
 | 
				
			||||||
 | 
					    into: MutableSet<CompilableSymbol>,
 | 
				
			||||||
 | 
					    symbol: ScopeSymbol,
 | 
				
			||||||
 | 
					    resolved: CompilableSymbol = resolve(symbol)
 | 
				
			||||||
 | 
					  ) {
 | 
				
			||||||
 | 
					    if (!into.add(resolved)) {
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (used in resolved.usedSymbols) {
 | 
				
			||||||
 | 
					      contributeCompiledSymbols(into, used)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun compile(entryPointSymbol: CompilableSymbol): CompiledWorld {
 | 
				
			||||||
 | 
					    val usedSymbolSet = mutableSetOf<CompilableSymbol>()
 | 
				
			||||||
 | 
					    contributeCompiledSymbols(usedSymbolSet, entryPointSymbol.scopeSymbol, entryPointSymbol)
 | 
				
			||||||
 | 
					    val layout = CompiledWorldLayout(this)
 | 
				
			||||||
 | 
					    for (used in usedSymbolSet) {
 | 
				
			||||||
 | 
					      layout.add(used)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return layout.layoutCompiledWorld()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.compiler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ComputableState<X, T>(val computation: (X) -> T) {
 | 
				
			||||||
 | 
					  private val state = StoredState<X, T>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun of(key: X): T = state.computeIfAbsent(key, computation)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.compiler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.MutableRel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LoopState(
 | 
				
			||||||
 | 
					  val startOfLoop: UInt,
 | 
				
			||||||
 | 
					  val exitJumpTarget: MutableRel,
 | 
				
			||||||
 | 
					  val body: MutableRel,
 | 
				
			||||||
 | 
					  val scopeDepth: Int,
 | 
				
			||||||
 | 
					  val enclosing: LoopState? = null
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.compiler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.MutableRel
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.Op
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PatchRelOp(op: Op, val index: Int, val symbol: CompilableSymbol, val rel: MutableRel) : StubOp(op) {
 | 
				
			||||||
 | 
					  override fun patch(context: StubResolutionContext, arguments: MutableList<UInt>) {
 | 
				
			||||||
 | 
					    arguments[index] = context.resolveJumpTarget(symbol) + rel.rel
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun toString(): String = "PatchRelOp(${op}, ${index}, ${symbol}, ${rel})"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.compiler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.Op
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PatchSymOp(op: Op, val patches: Map<Int, CompilableSymbol>) : StubOp(op) {
 | 
				
			||||||
 | 
					  override fun patch(context: StubResolutionContext, arguments: MutableList<UInt>) {
 | 
				
			||||||
 | 
					    for ((index, symbol) in patches) {
 | 
				
			||||||
 | 
					      arguments[index] = context.resolveJumpTarget(symbol)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun toString(): String = "PatchSymOp(${op}, ${patches})"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.compiler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.Op
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class StaticOp(op: Op) : StubOp(op) {
 | 
				
			||||||
 | 
					  override fun toString(): String = "StaticOp(${op})"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.compiler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class StoredState<X, T> {
 | 
				
			||||||
 | 
					  private val state = mutableMapOf<X, T>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun computeIfAbsent(key: X, computation: (X) -> T): T = state.computeIfAbsent(key, computation)
 | 
				
			||||||
 | 
					  fun of(key: X): T? = state[key]
 | 
				
			||||||
 | 
					  fun put(key: X, value: T) {
 | 
				
			||||||
 | 
					    state[key] = value
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.compiler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.Op
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					abstract class StubOp(val op: Op) {
 | 
				
			||||||
 | 
					  open fun patch(context: StubResolutionContext, arguments: MutableList<UInt>) {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,336 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.compiler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.FunctionLevelVisitor
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.gen.*
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.MutableRel
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.Op
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.Opcode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class StubOpEmitter(val compiler: Compiler, val symbol: CompilableSymbol) : FunctionLevelVisitor<Unit>() {
 | 
				
			||||||
 | 
					  private val ops = mutableListOf<StubOp>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private var loopState: LoopState? = null
 | 
				
			||||||
 | 
					  private val localVariables = mutableListOf<MutableList<StubVar>>()
 | 
				
			||||||
 | 
					  private var localVarIndex = 0u
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private val requiredLoopState: LoopState
 | 
				
			||||||
 | 
					    get() {
 | 
				
			||||||
 | 
					      if (loopState != null) {
 | 
				
			||||||
 | 
					        return loopState!!
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      throw RuntimeException("loopState expected but was not found.")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun allocateLocalVariable(symbol: Symbol): StubVar {
 | 
				
			||||||
 | 
					    val scope = localVariables.last()
 | 
				
			||||||
 | 
					    val variable = StubVar(localVarIndex++, symbol)
 | 
				
			||||||
 | 
					    scope.add(variable)
 | 
				
			||||||
 | 
					    return variable
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun resolveSymbol(symbol: Symbol): CallOrStubVar {
 | 
				
			||||||
 | 
					    for (scope in localVariables.reversed()) {
 | 
				
			||||||
 | 
					      val found = scope.firstOrNull { it.symbol == symbol }
 | 
				
			||||||
 | 
					      if (found != null) {
 | 
				
			||||||
 | 
					        return CallOrStubVar(stubVar = found)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    val found = this.symbol.compilableSlab.compilableSymbolOf(symbol)
 | 
				
			||||||
 | 
					    if (found != null) {
 | 
				
			||||||
 | 
					      return CallOrStubVar(call = found)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    throw RuntimeException("Unable to resolve symbol: ${symbol.id}")
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun pushScope() {
 | 
				
			||||||
 | 
					    emit(Opcode.ScopeIn)
 | 
				
			||||||
 | 
					    localVariables.add(mutableListOf())
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun popScope() {
 | 
				
			||||||
 | 
					    emit(Opcode.ScopeOut)
 | 
				
			||||||
 | 
					    localVariables.removeLast()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun enter() {
 | 
				
			||||||
 | 
					    pushScope()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun allocateOuterScope(definition: FunctionDefinition) {
 | 
				
			||||||
 | 
					    val allNormalArguments = definition.arguments.takeWhile { !it.multiple }
 | 
				
			||||||
 | 
					    val varArgument = definition.arguments.firstOrNull { it.multiple }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (arg in allNormalArguments.reversed()) {
 | 
				
			||||||
 | 
					      val functionLocal = allocateLocalVariable(arg.symbol)
 | 
				
			||||||
 | 
					      emit(Opcode.StoreLocal, listOf(functionLocal.index))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (varArgument != null) {
 | 
				
			||||||
 | 
					      val functionLocal = allocateLocalVariable(varArgument.symbol)
 | 
				
			||||||
 | 
					      emit(Opcode.StoreLocal, listOf(functionLocal.index))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun exit() {
 | 
				
			||||||
 | 
					    popScope()
 | 
				
			||||||
 | 
					    emit(Opcode.Return)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitBlock(node: Block) {
 | 
				
			||||||
 | 
					    pushScope()
 | 
				
			||||||
 | 
					    node.visitChildren(this)
 | 
				
			||||||
 | 
					    popScope()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitBooleanLiteral(node: BooleanLiteral) {
 | 
				
			||||||
 | 
					    emit(if (node.value) Opcode.True else Opcode.False)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitBreak(node: Break) {
 | 
				
			||||||
 | 
					    patch(Opcode.Jump, listOf(0u), 0, symbol, requiredLoopState.exitJumpTarget)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitContinue(node: Continue) {
 | 
				
			||||||
 | 
					    patch(Opcode.Jump, listOf(0u), 0, symbol, requiredLoopState.startOfLoop)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitDoubleLiteral(node: DoubleLiteral) {
 | 
				
			||||||
 | 
					    emit(Opcode.Integer, listOf(node.value.toUInt()))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitForIn(node: ForIn) {
 | 
				
			||||||
 | 
					    TODO("ForIn is currently unsupported")
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitFunctionCall(node: FunctionCall) {
 | 
				
			||||||
 | 
					    val targetScopeSymbol = symbol.scopeSymbol.scope.resolve(node.symbol) ?:
 | 
				
			||||||
 | 
					      throw RuntimeException("Unable to resolve symbol: ${node.symbol.id}")
 | 
				
			||||||
 | 
					    val targetSymbol = compiler.resolve(targetScopeSymbol)
 | 
				
			||||||
 | 
					    val functionDefinition = targetSymbol.scopeSymbol.definition as FunctionDefinition
 | 
				
			||||||
 | 
					    val retRel = MutableRel(0u)
 | 
				
			||||||
 | 
					    patch(Opcode.Integer, listOf(0u), 0, symbol, retRel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val normalArguments = mutableListOf<Expression>()
 | 
				
			||||||
 | 
					    var variableArguments: List<Expression>? = null
 | 
				
			||||||
 | 
					    for ((index, item) in functionDefinition.arguments.zip(node.arguments).withIndex()) {
 | 
				
			||||||
 | 
					      val (spec, value) = item
 | 
				
			||||||
 | 
					      if (spec.multiple) {
 | 
				
			||||||
 | 
					        val remaining = node.arguments.drop(index)
 | 
				
			||||||
 | 
					        variableArguments = remaining
 | 
				
			||||||
 | 
					        break
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        normalArguments.add(value)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (variableArguments != null) {
 | 
				
			||||||
 | 
					      for (item in variableArguments.reversed()) {
 | 
				
			||||||
 | 
					        item.visit(this)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      emit(Opcode.List, listOf(variableArguments.size.toUInt()))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (item in normalArguments.reversed()) {
 | 
				
			||||||
 | 
					      visit(item)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    retRel.rel = (ops.size + 1).toUInt()
 | 
				
			||||||
 | 
					    patch(Opcode.Call, listOf(0u), mapOf(0 to targetSymbol))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitIf(node: If) {
 | 
				
			||||||
 | 
					    val thenRel = MutableRel(0u)
 | 
				
			||||||
 | 
					    val endRel = MutableRel(0u)
 | 
				
			||||||
 | 
					    node.condition.visit(this)
 | 
				
			||||||
 | 
					    patch(Opcode.JumpIf, listOf(0u), 0, symbol, thenRel)
 | 
				
			||||||
 | 
					    node.elseBlock?.visit(this)
 | 
				
			||||||
 | 
					    patch(Opcode.Jump, listOf(0u), 0, symbol, endRel)
 | 
				
			||||||
 | 
					    thenRel.rel = ops.size.toUInt()
 | 
				
			||||||
 | 
					    node.thenBlock.visit(this)
 | 
				
			||||||
 | 
					    endRel.rel = ops.size.toUInt()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitIndexedBy(node: IndexedBy) {
 | 
				
			||||||
 | 
					    node.expression.visit(this)
 | 
				
			||||||
 | 
					    node.index.visit(this)
 | 
				
			||||||
 | 
					    emit(Opcode.Index)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitInfixOperation(node: InfixOperation) {
 | 
				
			||||||
 | 
					    node.left.visit(this)
 | 
				
			||||||
 | 
					    node.right.visit(this)
 | 
				
			||||||
 | 
					    when (node.op) {
 | 
				
			||||||
 | 
					      InfixOperator.Plus -> emit(Opcode.Add)
 | 
				
			||||||
 | 
					      InfixOperator.Minus -> emit(Opcode.Subtract)
 | 
				
			||||||
 | 
					      InfixOperator.Multiply -> emit(Opcode.Multiply)
 | 
				
			||||||
 | 
					      InfixOperator.Divide -> emit(Opcode.Divide)
 | 
				
			||||||
 | 
					      InfixOperator.Equals -> emit(Opcode.CompareEqual)
 | 
				
			||||||
 | 
					      InfixOperator.NotEquals -> {
 | 
				
			||||||
 | 
					        emit(Opcode.CompareEqual)
 | 
				
			||||||
 | 
					        emit(Opcode.Not)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      InfixOperator.EuclideanModulo -> emit(Opcode.EuclideanModulo)
 | 
				
			||||||
 | 
					      InfixOperator.Remainder -> emit(Opcode.Remainder)
 | 
				
			||||||
 | 
					      InfixOperator.Lesser -> emit(Opcode.CompareLesser)
 | 
				
			||||||
 | 
					      InfixOperator.Greater -> emit(Opcode.CompareGreater)
 | 
				
			||||||
 | 
					      InfixOperator.GreaterEqual -> emit(Opcode.CompareGreaterEqual)
 | 
				
			||||||
 | 
					      InfixOperator.LesserEqual -> emit(Opcode.CompareLesserEqual)
 | 
				
			||||||
 | 
					      InfixOperator.BooleanAnd -> emit(Opcode.And)
 | 
				
			||||||
 | 
					      InfixOperator.BooleanOr -> emit(Opcode.Or)
 | 
				
			||||||
 | 
					      InfixOperator.BinaryAnd -> emit(Opcode.BinaryAnd)
 | 
				
			||||||
 | 
					      InfixOperator.BinaryOr -> emit(Opcode.BinaryOr)
 | 
				
			||||||
 | 
					      InfixOperator.BinaryExclusiveOr -> emit(Opcode.BinaryXor)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitIntegerLiteral(node: IntegerLiteral) {
 | 
				
			||||||
 | 
					    emit(Opcode.Integer, listOf(node.value.toUInt()))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitLetAssignment(node: LetAssignment) {
 | 
				
			||||||
 | 
					    val variable = allocateLocalVariable(node.symbol)
 | 
				
			||||||
 | 
					    node.value.visit(this)
 | 
				
			||||||
 | 
					    emit(Opcode.StoreLocal, listOf(variable.index))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitListLiteral(node: ListLiteral) {
 | 
				
			||||||
 | 
					    val count = node.items.size
 | 
				
			||||||
 | 
					    for (item in node.items) {
 | 
				
			||||||
 | 
					      item.visit(this)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    emit(Opcode.List, listOf(count.toUInt()))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitLongLiteral(node: LongLiteral) {
 | 
				
			||||||
 | 
					    emit(Opcode.Integer, listOf(node.value.toUInt()))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitNoneLiteral(node: NoneLiteral) {
 | 
				
			||||||
 | 
					    emit(Opcode.None)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitParentheses(node: Parentheses) {
 | 
				
			||||||
 | 
					    node.expression.visit(this)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitPrefixOperation(node: PrefixOperation) {
 | 
				
			||||||
 | 
					    node.expression.visit(this)
 | 
				
			||||||
 | 
					    when (node.op) {
 | 
				
			||||||
 | 
					      PrefixOperator.BooleanNot -> emit(Opcode.Not)
 | 
				
			||||||
 | 
					      PrefixOperator.UnaryPlus -> emit(Opcode.UnaryPlus)
 | 
				
			||||||
 | 
					      PrefixOperator.UnaryMinus -> emit(Opcode.UnaryMinus)
 | 
				
			||||||
 | 
					      PrefixOperator.BinaryNot -> emit(Opcode.BinaryNot)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitSetAssignment(node: SetAssignment) {
 | 
				
			||||||
 | 
					    val stubVarOrCall = resolveSymbol(node.symbol)
 | 
				
			||||||
 | 
					    if (stubVarOrCall.stubVar == null) {
 | 
				
			||||||
 | 
					      throw RuntimeException("Invalid set assignment.")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    node.value.visit(this)
 | 
				
			||||||
 | 
					    emit(Opcode.StoreLocal, listOf(stubVarOrCall.stubVar.index))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitStringLiteral(node: StringLiteral) {
 | 
				
			||||||
 | 
					    val bytes = node.text.toByteArray()
 | 
				
			||||||
 | 
					    val constant = compiler.constantPool.assign(bytes)
 | 
				
			||||||
 | 
					    emit(Opcode.Constant, listOf(constant))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitSuffixOperation(node: SuffixOperation) {
 | 
				
			||||||
 | 
					    val stubVarOrCall = resolveSymbol(node.reference.symbol)
 | 
				
			||||||
 | 
					    if (stubVarOrCall.stubVar == null) {
 | 
				
			||||||
 | 
					      throw RuntimeException("Invalid suffix operation.")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    load(stubVarOrCall)
 | 
				
			||||||
 | 
					    when (node.op) {
 | 
				
			||||||
 | 
					      SuffixOperator.Increment -> {
 | 
				
			||||||
 | 
					        emit(Opcode.Integer, listOf(1u))
 | 
				
			||||||
 | 
					        emit(Opcode.Add, emptyList())
 | 
				
			||||||
 | 
					        emit(Opcode.StoreLocal, listOf(stubVarOrCall.stubVar.index))
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      SuffixOperator.Decrement -> {
 | 
				
			||||||
 | 
					        emit(Opcode.Integer, listOf(1u))
 | 
				
			||||||
 | 
					        emit(Opcode.Subtract, emptyList())
 | 
				
			||||||
 | 
					        emit(Opcode.StoreLocal, listOf(stubVarOrCall.stubVar.index))
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitSymbolReference(node: SymbolReference) {
 | 
				
			||||||
 | 
					    val variable = resolveSymbol(node.symbol)
 | 
				
			||||||
 | 
					    load(variable)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitVarAssignment(node: VarAssignment) {
 | 
				
			||||||
 | 
					    val variable = allocateLocalVariable(node.symbol)
 | 
				
			||||||
 | 
					    node.value.visit(this)
 | 
				
			||||||
 | 
					    emit(Opcode.StoreLocal, listOf(variable.index))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitWhile(node: While) {
 | 
				
			||||||
 | 
					    val startOfBody = MutableRel(0u)
 | 
				
			||||||
 | 
					    val endOfLoop = MutableRel(0u)
 | 
				
			||||||
 | 
					    val currentLoopState = LoopState(
 | 
				
			||||||
 | 
					      startOfLoop = ops.size.toUInt(),
 | 
				
			||||||
 | 
					      exitJumpTarget = endOfLoop,
 | 
				
			||||||
 | 
					      body = startOfBody,
 | 
				
			||||||
 | 
					      scopeDepth = (loopState?.scopeDepth ?: 0) + 1,
 | 
				
			||||||
 | 
					      enclosing = loopState
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    loopState = currentLoopState
 | 
				
			||||||
 | 
					    node.condition.visit(this)
 | 
				
			||||||
 | 
					    patch(Opcode.JumpIf, listOf(0u), 0, symbol, startOfBody)
 | 
				
			||||||
 | 
					    patch(Opcode.Jump, listOf(0u), 0, symbol, endOfLoop)
 | 
				
			||||||
 | 
					    startOfBody.rel = ops.size.toUInt()
 | 
				
			||||||
 | 
					    node.block.visit(this)
 | 
				
			||||||
 | 
					    patch(Opcode.Jump, listOf(0u), 0, symbol, currentLoopState.startOfLoop)
 | 
				
			||||||
 | 
					    endOfLoop.rel = ops.size.toUInt()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitNativeFunctionDescriptor(node: NativeFunctionDescriptor) {
 | 
				
			||||||
 | 
					    for (def in node.definitions) {
 | 
				
			||||||
 | 
					      val defConstant = compiler.constantPool.assign(def.text.toByteArray())
 | 
				
			||||||
 | 
					      emit(Opcode.Constant, listOf(defConstant))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    val formConstant = compiler.constantPool.assign(node.form.id.toByteArray())
 | 
				
			||||||
 | 
					    emit(Opcode.Native, listOf(formConstant, node.definitions.size.toUInt()))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun emit(code: Opcode) {
 | 
				
			||||||
 | 
					    emit(code, emptyList())
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun emit(code: Opcode, arguments: List<UInt>) {
 | 
				
			||||||
 | 
					    ops.add(StaticOp(Op(code, arguments)))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun patch(code: Opcode, arguments: List<UInt>, index: Int, symbol: CompilableSymbol, rel: MutableRel) {
 | 
				
			||||||
 | 
					    ops.add(PatchRelOp(Op(code, arguments), index, symbol, rel))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun patch(code: Opcode, arguments: List<UInt>, index: Int, symbol: CompilableSymbol, rel: UInt) {
 | 
				
			||||||
 | 
					    ops.add(PatchRelOp(Op(code, arguments), index, symbol, MutableRel(rel)))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun patch(code: Opcode, arguments: List<UInt>, patches: Map<Int, CompilableSymbol>) {
 | 
				
			||||||
 | 
					    ops.add(PatchSymOp(Op(code, arguments), patches))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun ops(): List<StubOp> = ops
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun load(callOrStubVar: CallOrStubVar) {
 | 
				
			||||||
 | 
					    if (callOrStubVar.stubVar != null) {
 | 
				
			||||||
 | 
					      emit(Opcode.LoadLocal, listOf(callOrStubVar.stubVar.index))
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      emit(Opcode.Integer, listOf(ops.size.toUInt() + 2u))
 | 
				
			||||||
 | 
					      patch(Opcode.Call, listOf(0u), mapOf(0 to callOrStubVar.call!!))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private class CallOrStubVar(
 | 
				
			||||||
 | 
					    val call: CompilableSymbol? = null,
 | 
				
			||||||
 | 
					    val stubVar: StubVar? = null
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.compiler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface StubResolutionContext {
 | 
				
			||||||
 | 
					  fun resolveJumpTarget(symbol: CompilableSymbol): UInt
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.compiler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.gen.Symbol
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class StubVar(
 | 
				
			||||||
 | 
					  val index: UInt,
 | 
				
			||||||
 | 
					  val symbol: Symbol
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
@ -4,6 +4,7 @@ plugins {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
dependencies {
 | 
					dependencies {
 | 
				
			||||||
  api(project(":ast"))
 | 
					  api(project(":ast"))
 | 
				
			||||||
 | 
					  api(project(":execution"))
 | 
				
			||||||
  api(project(":frontend"))
 | 
					  api(project(":frontend"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  implementation(project(":common"))
 | 
					  implementation(project(":common"))
 | 
				
			||||||
 | 
				
			|||||||
@ -1,78 +0,0 @@
 | 
				
			|||||||
package gay.pizza.pork.evaluator
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import gay.pizza.pork.ast.gen.*
 | 
					 | 
				
			||||||
import gay.pizza.pork.frontend.ImportLocator
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class CompilationUnitContext(
 | 
					 | 
				
			||||||
  val compilationUnit: CompilationUnit,
 | 
					 | 
				
			||||||
  val evaluator: Evaluator,
 | 
					 | 
				
			||||||
  rootScope: Scope,
 | 
					 | 
				
			||||||
  val name: String = "unknown"
 | 
					 | 
				
			||||||
) {
 | 
					 | 
				
			||||||
  val internalScope = rootScope.fork("internal $name")
 | 
					 | 
				
			||||||
  val externalScope = rootScope.fork("external $name")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private var initialized = false
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  fun initIfNeeded() {
 | 
					 | 
				
			||||||
    if (initialized) {
 | 
					 | 
				
			||||||
      return
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    initialized = true
 | 
					 | 
				
			||||||
    processAllImports()
 | 
					 | 
				
			||||||
    processAllDefinitions()
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private fun processAllDefinitions() {
 | 
					 | 
				
			||||||
    for (definition in compilationUnit.definitions) {
 | 
					 | 
				
			||||||
      processDefinition(definition)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private fun processDefinition(definition: Definition) {
 | 
					 | 
				
			||||||
    val internalValue = definitionValue(definition)
 | 
					 | 
				
			||||||
    internalScope.define(definition.symbol.id, internalValue)
 | 
					 | 
				
			||||||
    if (definition.modifiers.export) {
 | 
					 | 
				
			||||||
      externalScope.define(definition.symbol.id, internalValue)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private fun definitionValue(definition: Definition): Any = when (definition) {
 | 
					 | 
				
			||||||
    is FunctionDefinition -> FunctionContext(this, definition)
 | 
					 | 
				
			||||||
    is LetDefinition -> {
 | 
					 | 
				
			||||||
      EvaluationVisitor(internalScope.fork("let ${definition.symbol.id}"), CallStack())
 | 
					 | 
				
			||||||
        .visit(definition.value)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private fun processAllImports() {
 | 
					 | 
				
			||||||
    processPreludeImport()
 | 
					 | 
				
			||||||
    val imports = compilationUnit.declarations.filterIsInstance<ImportDeclaration>()
 | 
					 | 
				
			||||||
    for (import in imports) {
 | 
					 | 
				
			||||||
      processImport(import)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private fun processImport(import: ImportDeclaration) {
 | 
					 | 
				
			||||||
    val importPath = import.path.components.joinToString("/") { it.id } + ".pork"
 | 
					 | 
				
			||||||
    val importLocator = ImportLocator(import.form.id, importPath)
 | 
					 | 
				
			||||||
    val evaluationContext = evaluator.context(importLocator)
 | 
					 | 
				
			||||||
    internalScope.inherit(evaluationContext.externalScope)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private fun processPreludeImport() {
 | 
					 | 
				
			||||||
    processImport(preludeImport)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  companion object {
 | 
					 | 
				
			||||||
    private val preludeImport = ImportDeclaration(
 | 
					 | 
				
			||||||
      Symbol("std"),
 | 
					 | 
				
			||||||
      ImportPath(
 | 
					 | 
				
			||||||
        listOf(
 | 
					 | 
				
			||||||
          Symbol("lang"),
 | 
					 | 
				
			||||||
          Symbol("prelude")
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,10 +1,11 @@
 | 
				
			|||||||
package gay.pizza.pork.evaluator
 | 
					package gay.pizza.pork.evaluator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.FunctionLevelVisitor
 | 
				
			||||||
import gay.pizza.pork.ast.gen.*
 | 
					import gay.pizza.pork.ast.gen.*
 | 
				
			||||||
import kotlin.math.abs
 | 
					import kotlin.math.abs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Suppress("JavaIoSerializableObjectMustHaveReadResolve")
 | 
					@Suppress("JavaIoSerializableObjectMustHaveReadResolve")
 | 
				
			||||||
class EvaluationVisitor(root: Scope, val stack: CallStack) : NodeVisitor<Any> {
 | 
					class EvaluationVisitor(root: Scope, val stack: CallStack) : FunctionLevelVisitor<Any>() {
 | 
				
			||||||
  private var currentScope: Scope = root
 | 
					  private var currentScope: Scope = root
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun visitIntegerLiteral(node: IntegerLiteral): Any = node.value
 | 
					  override fun visitIntegerLiteral(node: IntegerLiteral): Any = node.value
 | 
				
			||||||
@ -66,10 +67,6 @@ class EvaluationVisitor(root: Scope, val stack: CallStack) : NodeVisitor<Any> {
 | 
				
			|||||||
    return value
 | 
					    return value
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun visitLetDefinition(node: LetDefinition): Any {
 | 
					 | 
				
			||||||
    topLevelUsedError("LetDefinition", "CompilationUnitContext")
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  override fun visitSymbolReference(node: SymbolReference): Any =
 | 
					  override fun visitSymbolReference(node: SymbolReference): Any =
 | 
				
			||||||
    currentScope.value(node.symbol.id)
 | 
					    currentScope.value(node.symbol.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -383,18 +380,6 @@ class EvaluationVisitor(root: Scope, val stack: CallStack) : NodeVisitor<Any> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun visitFunctionDefinition(node: FunctionDefinition): Any {
 | 
					 | 
				
			||||||
    topLevelUsedError("FunctionDefinition", "FunctionContext")
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  override fun visitImportDeclaration(node: ImportDeclaration): Any {
 | 
					 | 
				
			||||||
    topLevelUsedError("ImportDeclaration", "CompilationUnitContext")
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  override fun visitImportPath(node: ImportPath): Any {
 | 
					 | 
				
			||||||
    topLevelUsedError("ImportPath", "CompilationUnitContext")
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  override fun visitIndexedBy(node: IndexedBy): Any {
 | 
					  override fun visitIndexedBy(node: IndexedBy): Any {
 | 
				
			||||||
    val value = node.expression.visit(this)
 | 
					    val value = node.expression.visit(this)
 | 
				
			||||||
    val index = node.index.visit(this)
 | 
					    val index = node.index.visit(this)
 | 
				
			||||||
@ -410,14 +395,6 @@ class EvaluationVisitor(root: Scope, val stack: CallStack) : NodeVisitor<Any> {
 | 
				
			|||||||
    throw RuntimeException("Failed to index '${value}' by '${index}': Unsupported types used.")
 | 
					    throw RuntimeException("Failed to index '${value}' by '${index}': Unsupported types used.")
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun visitCompilationUnit(node: CompilationUnit): Any {
 | 
					 | 
				
			||||||
    topLevelUsedError("CompilationUnit", "CompilationUnitContext")
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  override fun visitNativeFunctionDescriptor(node: NativeFunctionDescriptor): Any {
 | 
					 | 
				
			||||||
    topLevelUsedError("NativeFunctionDescriptor", "FunctionContext")
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  override fun visitNoneLiteral(node: NoneLiteral): Any = None
 | 
					  override fun visitNoneLiteral(node: NoneLiteral): Any = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun visitContinue(node: Continue): Any = ContinueMarker
 | 
					  override fun visitContinue(node: Continue): Any = ContinueMarker
 | 
				
			||||||
@ -445,13 +422,6 @@ class EvaluationVisitor(root: Scope, val stack: CallStack) : NodeVisitor<Any> {
 | 
				
			|||||||
    throw RuntimeException("Can't perform $operation between floating point types")
 | 
					    throw RuntimeException("Can't perform $operation between floating point types")
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private fun topLevelUsedError(name: String, alternative: String): Nothing {
 | 
					 | 
				
			||||||
    throw RuntimeException(
 | 
					 | 
				
			||||||
      "$name cannot be visited in an EvaluationVisitor. " +
 | 
					 | 
				
			||||||
        "Utilize an $alternative instead."
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private object BreakMarker : RuntimeException("Break Marker")
 | 
					  private object BreakMarker : RuntimeException("Break Marker")
 | 
				
			||||||
  private object ContinueMarker: RuntimeException("Continue Marker")
 | 
					  private object ContinueMarker: RuntimeException("Continue Marker")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,25 +1,33 @@
 | 
				
			|||||||
package gay.pizza.pork.evaluator
 | 
					package gay.pizza.pork.evaluator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.gen.Symbol
 | 
				
			||||||
 | 
					import gay.pizza.pork.execution.ExecutionContext
 | 
				
			||||||
 | 
					import gay.pizza.pork.execution.ExecutionContextProvider
 | 
				
			||||||
import gay.pizza.pork.frontend.ImportLocator
 | 
					import gay.pizza.pork.frontend.ImportLocator
 | 
				
			||||||
 | 
					import gay.pizza.pork.frontend.Slab
 | 
				
			||||||
import gay.pizza.pork.frontend.World
 | 
					import gay.pizza.pork.frontend.World
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Evaluator(val world: World, val scope: Scope) {
 | 
					class Evaluator(val world: World) : ExecutionContextProvider {
 | 
				
			||||||
  private val contexts = mutableMapOf<String, CompilationUnitContext>()
 | 
					  private val scope = Scope.root()
 | 
				
			||||||
 | 
					  private val contexts = mutableMapOf<Slab, SlabContext>()
 | 
				
			||||||
  private val nativeProviders = mutableMapOf<String, NativeProvider>()
 | 
					  private val nativeProviders = mutableMapOf<String, NativeProvider>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun evaluate(locator: ImportLocator): Scope =
 | 
					  fun evaluate(locator: ImportLocator): Scope {
 | 
				
			||||||
    context(locator).externalScope
 | 
					    val slabContext = context(locator)
 | 
				
			||||||
 | 
					    slabContext.finalizeScope()
 | 
				
			||||||
 | 
					    return slabContext.externalScope
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun context(locator: ImportLocator): CompilationUnitContext {
 | 
					  fun context(slab: Slab): SlabContext {
 | 
				
			||||||
    val unit = world.load(locator)
 | 
					    val slabContext = contexts.computeIfAbsent(slab) {
 | 
				
			||||||
    val identity = world.stableIdentity(locator)
 | 
					      SlabContext(slab, this, scope)
 | 
				
			||||||
    val context = contexts.computeIfAbsent(identity) {
 | 
					 | 
				
			||||||
      CompilationUnitContext(unit, this, scope, name = "${locator.form} ${locator.path}")
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    context.initIfNeeded()
 | 
					    slabContext.ensureImportedContextsExist()
 | 
				
			||||||
    return context
 | 
					    return slabContext
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun context(locator: ImportLocator): SlabContext = context(world.load(locator))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun nativeFunctionProvider(form: String): NativeProvider {
 | 
					  fun nativeFunctionProvider(form: String): NativeProvider {
 | 
				
			||||||
    return nativeProviders[form] ?:
 | 
					    return nativeProviders[form] ?:
 | 
				
			||||||
      throw RuntimeException("Unknown native function form: $form")
 | 
					      throw RuntimeException("Unknown native function form: $form")
 | 
				
			||||||
@ -28,4 +36,10 @@ class Evaluator(val world: World, val scope: Scope) {
 | 
				
			|||||||
  fun addNativeProvider(form: String, nativeProvider: NativeProvider) {
 | 
					  fun addNativeProvider(form: String, nativeProvider: NativeProvider) {
 | 
				
			||||||
    nativeProviders[form] = nativeProvider
 | 
					    nativeProviders[form] = nativeProvider
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun prepare(importLocator: ImportLocator, entryPointSymbol: Symbol): ExecutionContext {
 | 
				
			||||||
 | 
					    val slab = context(importLocator)
 | 
				
			||||||
 | 
					    slab.finalizeScope()
 | 
				
			||||||
 | 
					    return EvaluatorExecutionContext(this, slab, entryPointSymbol)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.evaluator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.gen.Symbol
 | 
				
			||||||
 | 
					import gay.pizza.pork.execution.ExecutionContext
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class EvaluatorExecutionContext(val evaluator: Evaluator, val slab: SlabContext, val entryPointSymbol: Symbol) : ExecutionContext {
 | 
				
			||||||
 | 
					  private val function: CallableFunction by lazy {
 | 
				
			||||||
 | 
					    val value = slab.externalScope.value(entryPointSymbol.id)
 | 
				
			||||||
 | 
					    if (value !is CallableFunction) {
 | 
				
			||||||
 | 
					      throw RuntimeException("Symbol '${entryPointSymbol.id}' resolves to a non-function.")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    value
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun execute() {
 | 
				
			||||||
 | 
					    function.call(emptyList(), CallStack())
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -2,16 +2,16 @@ package gay.pizza.pork.evaluator
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import gay.pizza.pork.ast.gen.FunctionDefinition
 | 
					import gay.pizza.pork.ast.gen.FunctionDefinition
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FunctionContext(val compilationUnitContext: CompilationUnitContext, val node: FunctionDefinition) : CallableFunction {
 | 
					class FunctionContext(val slabContext: SlabContext, val node: FunctionDefinition) : CallableFunction {
 | 
				
			||||||
  val name: String = "${compilationUnitContext.name} ${node.symbol.id}"
 | 
					  val name: String by lazy { "${slabContext.slab.location.commonFriendlyName} ${node.symbol.id}" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private fun resolveMaybeNative(): CallableFunction? = if (node.nativeFunctionDescriptor == null) {
 | 
					  private fun resolveMaybeNative(): CallableFunction? = if (node.nativeFunctionDescriptor == null) {
 | 
				
			||||||
    null
 | 
					    null
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    val native = node.nativeFunctionDescriptor!!
 | 
					    val native = node.nativeFunctionDescriptor!!
 | 
				
			||||||
    val nativeFunctionProvider =
 | 
					    val nativeFunctionProvider =
 | 
				
			||||||
      compilationUnitContext.evaluator.nativeFunctionProvider(native.form.id)
 | 
					      slabContext.evaluator.nativeFunctionProvider(native.form.id)
 | 
				
			||||||
    nativeFunctionProvider.provideNativeFunction(native.definitions.map { it.text }, node.arguments, compilationUnitContext)
 | 
					    nativeFunctionProvider.provideNativeFunction(native.definitions.map { it.text }, node.arguments, slabContext)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private val nativeCached by lazy { resolveMaybeNative() }
 | 
					  private val nativeCached by lazy { resolveMaybeNative() }
 | 
				
			||||||
@ -21,7 +21,7 @@ class FunctionContext(val compilationUnitContext: CompilationUnitContext, val no
 | 
				
			|||||||
      return nativeCached!!.call(arguments, stack)
 | 
					      return nativeCached!!.call(arguments, stack)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val scope = compilationUnitContext.internalScope.fork(node.symbol.id)
 | 
					    val scope = slabContext.internalScope.fork(node.symbol.id)
 | 
				
			||||||
    for ((index, spec) in node.arguments.withIndex()) {
 | 
					    for ((index, spec) in node.arguments.withIndex()) {
 | 
				
			||||||
      if (spec.multiple) {
 | 
					      if (spec.multiple) {
 | 
				
			||||||
        val list = arguments.subList(index, arguments.size - 1)
 | 
					        val list = arguments.subList(index, arguments.size - 1)
 | 
				
			||||||
 | 
				
			|||||||
@ -18,7 +18,7 @@ class InternalNativeProvider(val quiet: Boolean = false) : NativeProvider {
 | 
				
			|||||||
  override fun provideNativeFunction(
 | 
					  override fun provideNativeFunction(
 | 
				
			||||||
    definitions: List<String>,
 | 
					    definitions: List<String>,
 | 
				
			||||||
    arguments: List<ArgumentSpec>,
 | 
					    arguments: List<ArgumentSpec>,
 | 
				
			||||||
    inside: CompilationUnitContext
 | 
					    inside: SlabContext
 | 
				
			||||||
  ): CallableFunction {
 | 
					  ): CallableFunction {
 | 
				
			||||||
    val definition = definitions[0]
 | 
					    val definition = definitions[0]
 | 
				
			||||||
    return functions[definition] ?: throw RuntimeException("Unknown Internal Function: $definition")
 | 
					    return functions[definition] ?: throw RuntimeException("Unknown Internal Function: $definition")
 | 
				
			||||||
 | 
				
			|||||||
@ -3,5 +3,5 @@ package gay.pizza.pork.evaluator
 | 
				
			|||||||
import gay.pizza.pork.ast.gen.ArgumentSpec
 | 
					import gay.pizza.pork.ast.gen.ArgumentSpec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface NativeProvider {
 | 
					interface NativeProvider {
 | 
				
			||||||
  fun provideNativeFunction(definitions: List<String>, arguments: List<ArgumentSpec>, inside: CompilationUnitContext): CallableFunction
 | 
					  fun provideNativeFunction(definitions: List<String>, arguments: List<ArgumentSpec>, inside: SlabContext): CallableFunction
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.evaluator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.gen.Definition
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.gen.FunctionDefinition
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.gen.LetDefinition
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.gen.visit
 | 
				
			||||||
 | 
					import gay.pizza.pork.frontend.Slab
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SlabContext(val slab: Slab, val evaluator: Evaluator, rootScope: Scope) {
 | 
				
			||||||
 | 
					  val internalScope = rootScope.fork("internal ${slab.location.commonFriendlyName}")
 | 
				
			||||||
 | 
					  val externalScope = rootScope.fork("external ${slab.location.commonFriendlyName}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  init {
 | 
				
			||||||
 | 
					    processAllDefinitions()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun ensureImportedContextsExist() {
 | 
				
			||||||
 | 
					    for (importedSlab in slab.importedSlabs) {
 | 
				
			||||||
 | 
					      evaluator.context(importedSlab)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private var initializedFinalScope = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun finalizeScope() {
 | 
				
			||||||
 | 
					    if (initializedFinalScope) {
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    initializedFinalScope = true
 | 
				
			||||||
 | 
					    processFinalImportScopes()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun processAllDefinitions() {
 | 
				
			||||||
 | 
					    for (definition in slab.compilationUnit.definitions) {
 | 
				
			||||||
 | 
					      processDefinition(definition)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun processDefinition(definition: Definition) {
 | 
				
			||||||
 | 
					    val internalValue = definitionValue(definition)
 | 
				
			||||||
 | 
					    internalScope.define(definition.symbol.id, internalValue)
 | 
				
			||||||
 | 
					    if (definition.modifiers.export) {
 | 
				
			||||||
 | 
					      externalScope.define(definition.symbol.id, internalValue)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun definitionValue(definition: Definition): Any = when (definition) {
 | 
				
			||||||
 | 
					    is FunctionDefinition -> FunctionContext(this, definition)
 | 
				
			||||||
 | 
					    is LetDefinition -> {
 | 
				
			||||||
 | 
					      EvaluationVisitor(internalScope.fork("let ${definition.symbol.id}"), CallStack())
 | 
				
			||||||
 | 
					        .visit(definition.value)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun processFinalImportScopes() {
 | 
				
			||||||
 | 
					    for (importedSlab in slab.importedSlabs) {
 | 
				
			||||||
 | 
					      val importedSlabContext = evaluator.context(importedSlab)
 | 
				
			||||||
 | 
					      importedSlabContext.processFinalImportScopes()
 | 
				
			||||||
 | 
					      internalScope.inherit(importedSlabContext.externalScope)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,9 +1,11 @@
 | 
				
			|||||||
let count = 5
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export func main() {
 | 
					export func main() {
 | 
				
			||||||
  var x = 1
 | 
					  var x = 1
 | 
				
			||||||
  while x <= count {
 | 
					  while x <= 5 {
 | 
				
			||||||
    println(x)
 | 
					    if x == 3 {
 | 
				
			||||||
 | 
					      println("The value is 3")
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      println("The value is not 3")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    x++
 | 
					    x++
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										8
									
								
								execution/build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								execution/build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					plugins {
 | 
				
			||||||
 | 
					  id("gay.pizza.pork.module")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dependencies {
 | 
				
			||||||
 | 
					  api(project(":frontend"))
 | 
				
			||||||
 | 
					  implementation(project(":common"))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.execution
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface ExecutionContext {
 | 
				
			||||||
 | 
					  fun execute()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.execution
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.gen.Symbol
 | 
				
			||||||
 | 
					import gay.pizza.pork.frontend.ImportLocator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface ExecutionContextProvider {
 | 
				
			||||||
 | 
					  fun prepare(importLocator: ImportLocator, entryPointSymbol: Symbol): ExecutionContext
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -25,7 +25,7 @@ class FfiNativeProvider : NativeProvider {
 | 
				
			|||||||
  override fun provideNativeFunction(
 | 
					  override fun provideNativeFunction(
 | 
				
			||||||
    definitions: List<String>,
 | 
					    definitions: List<String>,
 | 
				
			||||||
    arguments: List<ArgumentSpec>,
 | 
					    arguments: List<ArgumentSpec>,
 | 
				
			||||||
    inside: CompilationUnitContext
 | 
					    inside: SlabContext
 | 
				
			||||||
  ): CallableFunction {
 | 
					  ): CallableFunction {
 | 
				
			||||||
    if (definitions[0] == "internal") {
 | 
					    if (definitions[0] == "internal") {
 | 
				
			||||||
      val internal = internalFunctions[definitions[1]] ?:
 | 
					      val internal = internalFunctions[definitions[1]] ?:
 | 
				
			||||||
@ -73,7 +73,7 @@ class FfiNativeProvider : NativeProvider {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private fun addStructDefs(ffiTypeRegistry: FfiTypeRegistry, types: List<String>, inside: CompilationUnitContext) {
 | 
					  private fun addStructDefs(ffiTypeRegistry: FfiTypeRegistry, types: List<String>, inside: SlabContext) {
 | 
				
			||||||
    for (parameter in types) {
 | 
					    for (parameter in types) {
 | 
				
			||||||
      if (!parameter.startsWith("struct ")) {
 | 
					      if (!parameter.startsWith("struct ")) {
 | 
				
			||||||
        continue
 | 
					        continue
 | 
				
			||||||
 | 
				
			|||||||
@ -15,5 +15,5 @@ object JavaAutogenContentSource : ContentSource {
 | 
				
			|||||||
    return StringCharSource(content)
 | 
					    return StringCharSource(content)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun stableContentIdentity(path: String): String = path
 | 
					  override fun stableContentPath(path: String): String = path
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,7 @@ package gay.pizza.pork.ffi
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import gay.pizza.pork.ast.gen.ArgumentSpec
 | 
					import gay.pizza.pork.ast.gen.ArgumentSpec
 | 
				
			||||||
import gay.pizza.pork.evaluator.CallableFunction
 | 
					import gay.pizza.pork.evaluator.CallableFunction
 | 
				
			||||||
import gay.pizza.pork.evaluator.CompilationUnitContext
 | 
					import gay.pizza.pork.evaluator.SlabContext
 | 
				
			||||||
import gay.pizza.pork.evaluator.NativeProvider
 | 
					import gay.pizza.pork.evaluator.NativeProvider
 | 
				
			||||||
import gay.pizza.pork.evaluator.None
 | 
					import gay.pizza.pork.evaluator.None
 | 
				
			||||||
import java.lang.invoke.MethodHandles
 | 
					import java.lang.invoke.MethodHandles
 | 
				
			||||||
@ -14,7 +14,7 @@ class JavaNativeProvider : NativeProvider {
 | 
				
			|||||||
  override fun provideNativeFunction(
 | 
					  override fun provideNativeFunction(
 | 
				
			||||||
    definitions: List<String>,
 | 
					    definitions: List<String>,
 | 
				
			||||||
    arguments: List<ArgumentSpec>,
 | 
					    arguments: List<ArgumentSpec>,
 | 
				
			||||||
    inside: CompilationUnitContext
 | 
					    inside: SlabContext
 | 
				
			||||||
  ): CallableFunction {
 | 
					  ): CallableFunction {
 | 
				
			||||||
    val functionDefinition = JavaFunctionDefinition.parse(definitions)
 | 
					    val functionDefinition = JavaFunctionDefinition.parse(definitions)
 | 
				
			||||||
    val javaClass = lookupClass(functionDefinition.type)
 | 
					    val javaClass = lookupClass(functionDefinition.type)
 | 
				
			||||||
 | 
				
			|||||||
@ -4,5 +4,5 @@ import gay.pizza.pork.tokenizer.CharSource
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
interface ContentSource {
 | 
					interface ContentSource {
 | 
				
			||||||
  fun loadAsCharSource(path: String): CharSource
 | 
					  fun loadAsCharSource(path: String): CharSource
 | 
				
			||||||
  fun stableContentIdentity(path: String): String
 | 
					  fun stableContentPath(path: String): String
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
package gay.pizza.pork.frontend
 | 
					package gay.pizza.pork.frontend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DynamicImportSource : ImportSource {
 | 
					class DynamicImportSource : ImportSource {
 | 
				
			||||||
  private val providers = mutableMapOf<String,ContentSource>()
 | 
					  private val providers = mutableMapOf<String, ContentSource>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun provideContentSource(form: String): ContentSource {
 | 
					  override fun provideContentSource(form: String): ContentSource {
 | 
				
			||||||
    return providers[form] ?:
 | 
					    return providers[form] ?:
 | 
				
			||||||
 | 
				
			|||||||
@ -10,7 +10,7 @@ class FsContentSource(val root: FsPath) : ContentSource {
 | 
				
			|||||||
  override fun loadAsCharSource(path: String): CharSource =
 | 
					  override fun loadAsCharSource(path: String): CharSource =
 | 
				
			||||||
    StringCharSource(asFsPath(path).readString())
 | 
					    StringCharSource(asFsPath(path).readString())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun stableContentIdentity(path: String): String =
 | 
					  override fun stableContentPath(path: String): String =
 | 
				
			||||||
    asFsPath(path).fullPathString
 | 
					    asFsPath(path).fullPathString
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private fun asFsPath(path: String): FsPath {
 | 
					  private fun asFsPath(path: String): FsPath {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										12
									
								
								frontend/src/main/kotlin/gay/pizza/pork/frontend/Slab.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								frontend/src/main/kotlin/gay/pizza/pork/frontend/Slab.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.frontend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.gen.CompilationUnit
 | 
				
			||||||
 | 
					import gay.pizza.pork.frontend.scope.SlabScope
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Slab(val world: World, val location: SourceLocation, val compilationUnit: CompilationUnit) {
 | 
				
			||||||
 | 
					  val importedSlabs: List<Slab> by lazy {
 | 
				
			||||||
 | 
					    world.resolveAllImports(this)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val scope: SlabScope by lazy { world.scope.index(this) }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.frontend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.tokenizer.SourceIndex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					data class SourceLocation(val form: String, val filePath: String, val index: SourceIndex? = null) {
 | 
				
			||||||
 | 
					  val commonFriendlyName: String by lazy { "$form $filePath" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun withSourceIndex(index: SourceIndex): SourceLocation =
 | 
				
			||||||
 | 
					    SourceLocation(form, filePath, index)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.frontend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					data class StableSourceKey(val form: String, val path: String) {
 | 
				
			||||||
 | 
					  fun asSourceLocation(): SourceLocation = SourceLocation(form, path)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,22 +1,25 @@
 | 
				
			|||||||
package gay.pizza.pork.frontend
 | 
					package gay.pizza.pork.frontend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import gay.pizza.pork.ast.gen.CompilationUnit
 | 
					 | 
				
			||||||
import gay.pizza.pork.ast.gen.ImportDeclaration
 | 
					import gay.pizza.pork.ast.gen.ImportDeclaration
 | 
				
			||||||
 | 
					import gay.pizza.pork.frontend.scope.WorldScope
 | 
				
			||||||
import gay.pizza.pork.parser.DiscardNodeAttribution
 | 
					import gay.pizza.pork.parser.DiscardNodeAttribution
 | 
				
			||||||
import gay.pizza.pork.parser.Parser
 | 
					import gay.pizza.pork.parser.Parser
 | 
				
			||||||
import gay.pizza.pork.tokenizer.Tokenizer
 | 
					import gay.pizza.pork.tokenizer.Tokenizer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class World(val importSource: ImportSource) {
 | 
					class World(val importSource: ImportSource) {
 | 
				
			||||||
  private val internalUnits = mutableMapOf<String, CompilationUnit>()
 | 
					  private val preludeImportLocator = ImportLocator("std", "lang/prelude.pork")
 | 
				
			||||||
  private val importedUnits = mutableMapOf<CompilationUnit, Set<CompilationUnit>>()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  val units: List<CompilationUnit>
 | 
					  private val internalSlabs = mutableMapOf<StableSourceKey, Slab>()
 | 
				
			||||||
    get() = internalUnits.values.toList()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private fun loadOneUnit(importLocator: ImportLocator): CompilationUnit {
 | 
					  val slabs: List<Slab>
 | 
				
			||||||
 | 
					    get() = internalSlabs.values.toList()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val scope: WorldScope by lazy { WorldScope(this) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun loadOneSlab(importLocator: ImportLocator): Slab {
 | 
				
			||||||
    val contentSource = pickContentSource(importLocator.form)
 | 
					    val contentSource = pickContentSource(importLocator.form)
 | 
				
			||||||
    val stableKey = stableIdentity(importLocator, contentSource = contentSource)
 | 
					    val stableKey = stableSourceKey(importLocator, contentSource = contentSource)
 | 
				
			||||||
    val cached = internalUnits[stableKey]
 | 
					    val cached = internalSlabs[stableKey]
 | 
				
			||||||
    if (cached != null) {
 | 
					    if (cached != null) {
 | 
				
			||||||
      return cached
 | 
					      return cached
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -24,40 +27,39 @@ class World(val importSource: ImportSource) {
 | 
				
			|||||||
    val tokenizer = Tokenizer(charSource)
 | 
					    val tokenizer = Tokenizer(charSource)
 | 
				
			||||||
    val parser = Parser(tokenizer, DiscardNodeAttribution)
 | 
					    val parser = Parser(tokenizer, DiscardNodeAttribution)
 | 
				
			||||||
    val unit = parser.parseCompilationUnit()
 | 
					    val unit = parser.parseCompilationUnit()
 | 
				
			||||||
    internalUnits[stableKey] = unit
 | 
					    val slab = Slab(world = this, location = stableKey.asSourceLocation(), compilationUnit = unit)
 | 
				
			||||||
    return unit
 | 
					    internalSlabs[stableKey] = slab
 | 
				
			||||||
 | 
					    return slab
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private fun resolveAllImports(unit: CompilationUnit): Set<CompilationUnit> {
 | 
					  internal fun resolveAllImports(slab: Slab): List<Slab> {
 | 
				
			||||||
    val units = mutableSetOf<CompilationUnit>()
 | 
					    val slabs = mutableListOf<Slab>()
 | 
				
			||||||
    for (declaration in unit.declarations.filterIsInstance<ImportDeclaration>()) {
 | 
					    if (slab.location.form != preludeImportLocator.form &&
 | 
				
			||||||
 | 
					      slab.location.filePath != preludeImportLocator.path) {
 | 
				
			||||||
 | 
					      slabs.add(loadOneSlab(preludeImportLocator))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (declaration in slab.compilationUnit.declarations.filterIsInstance<ImportDeclaration>()) {
 | 
				
			||||||
      val importPath = declaration.path.components.joinToString("/") { it.id } + ".pork"
 | 
					      val importPath = declaration.path.components.joinToString("/") { it.id } + ".pork"
 | 
				
			||||||
      val importLocator = ImportLocator(declaration.form.id, importPath)
 | 
					      val importLocator = ImportLocator(declaration.form.id, importPath)
 | 
				
			||||||
      val importedUnit = loadOneUnit(importLocator)
 | 
					      val importedModule = loadOneSlab(importLocator)
 | 
				
			||||||
      units.add(importedUnit)
 | 
					      slabs.add(importedModule)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    importedUnits[unit] = units
 | 
					    return slabs
 | 
				
			||||||
    return units
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun load(importLocator: ImportLocator): CompilationUnit {
 | 
					  fun load(importLocator: ImportLocator): Slab {
 | 
				
			||||||
    val unit = loadOneUnit(importLocator)
 | 
					    return loadOneSlab(importLocator)
 | 
				
			||||||
    resolveAllImports(unit)
 | 
					 | 
				
			||||||
    return unit
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun importedBy(unit: CompilationUnit): Set<CompilationUnit> =
 | 
					 | 
				
			||||||
    importedUnits[unit] ?: emptySet()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private fun pickContentSource(form: String): ContentSource =
 | 
					  private fun pickContentSource(form: String): ContentSource =
 | 
				
			||||||
    importSource.provideContentSource(form)
 | 
					    importSource.provideContentSource(form)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun stableIdentity(
 | 
					  fun stableSourceKey(
 | 
				
			||||||
    importLocator: ImportLocator,
 | 
					    importLocator: ImportLocator,
 | 
				
			||||||
    contentSource: ContentSource = pickContentSource(importLocator.form)
 | 
					    contentSource: ContentSource = pickContentSource(importLocator.form)
 | 
				
			||||||
  ): String {
 | 
					  ): StableSourceKey {
 | 
				
			||||||
    val formKey = importLocator.form
 | 
					    val formKey = importLocator.form
 | 
				
			||||||
    val stableIdentity = contentSource.stableContentIdentity(importLocator.path)
 | 
					    val stableContentPath = contentSource.stableContentPath(importLocator.path)
 | 
				
			||||||
    return "[${formKey}][${stableIdentity}]"
 | 
					    return StableSourceKey(formKey, stableContentPath)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,36 +0,0 @@
 | 
				
			|||||||
package gay.pizza.pork.frontend.scope
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import gay.pizza.pork.ast.gen.CompilationUnit
 | 
					 | 
				
			||||||
import gay.pizza.pork.ast.gen.Symbol
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class CompilationUnitScope(val worldScope: WorldScope, val unit: CompilationUnit) {
 | 
					 | 
				
			||||||
  val externalSymbols = mutableSetOf<ScopeSymbol>()
 | 
					 | 
				
			||||||
  val internalSymbols = mutableSetOf<ScopeSymbol>()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  fun index() {
 | 
					 | 
				
			||||||
    for (definition in unit.definitions) {
 | 
					 | 
				
			||||||
      val scopeSymbol = ScopeSymbol(unit, definition)
 | 
					 | 
				
			||||||
      if (definition.modifiers.export) {
 | 
					 | 
				
			||||||
        externalSymbols.add(scopeSymbol)
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      internalSymbols.add(scopeSymbol)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  fun findInternallyVisibleSymbols(): Set<VisibleScopeSymbol> {
 | 
					 | 
				
			||||||
    val allSymbols = mutableMapOf<Symbol, VisibleScopeSymbol>()
 | 
					 | 
				
			||||||
    val imports = worldScope.world.importedBy(unit)
 | 
					 | 
				
			||||||
    for (import in imports) {
 | 
					 | 
				
			||||||
      val scope = worldScope.index(import)
 | 
					 | 
				
			||||||
      for (importedSymbol in scope.externalSymbols) {
 | 
					 | 
				
			||||||
        allSymbols[importedSymbol.symbol] = VisibleScopeSymbol(unit, importedSymbol)
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (internalSymbol in internalSymbols) {
 | 
					 | 
				
			||||||
      allSymbols[internalSymbol.symbol] = VisibleScopeSymbol(unit, internalSymbol)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return allSymbols.values.toSet()
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.frontend.scope
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.gen.Definition
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.gen.Symbol
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.gen.visit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DefinitionScope(val slabScope: SlabScope, val definition: Definition) {
 | 
				
			||||||
 | 
					  val usedSymbols: List<ScopeSymbol> by lazy {
 | 
				
			||||||
 | 
					    val symbols = mutableListOf<ScopeSymbol>()
 | 
				
			||||||
 | 
					    val analyzer = ExternalSymbolUsageAnalyzer()
 | 
				
			||||||
 | 
					    analyzer.visit(definition)
 | 
				
			||||||
 | 
					    for (symbol in analyzer.usedSymbols) {
 | 
				
			||||||
 | 
					      val resolved = slabScope.resolve(symbol)
 | 
				
			||||||
 | 
					        ?: throw RuntimeException("Unable to resolve symbol: ${symbol.id}")
 | 
				
			||||||
 | 
					      symbols.add(resolved)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    symbols
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun resolve(symbol: Symbol): ScopeSymbol? = slabScope.resolve(symbol)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,135 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.frontend.scope
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.FunctionLevelVisitor
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.gen.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ExternalSymbolUsageAnalyzer : FunctionLevelVisitor<Unit>() {
 | 
				
			||||||
 | 
					  private val symbols = mutableSetOf<Symbol>()
 | 
				
			||||||
 | 
					  private val internalSymbols = mutableListOf<MutableSet<Symbol>>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val usedSymbols: Set<Symbol>
 | 
				
			||||||
 | 
					    get() = symbols
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitFunctionDefinition(node: FunctionDefinition) {
 | 
				
			||||||
 | 
					    internalSymbols.add(node.arguments.map { it.symbol }.toMutableSet())
 | 
				
			||||||
 | 
					    node.block?.visit(this)
 | 
				
			||||||
 | 
					    internalSymbols.removeLast()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitLetDefinition(node: LetDefinition) {
 | 
				
			||||||
 | 
					    node.value.visit(this)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitBlock(node: Block) {
 | 
				
			||||||
 | 
					    internalSymbols.add(mutableSetOf())
 | 
				
			||||||
 | 
					    node.visitChildren(this)
 | 
				
			||||||
 | 
					    internalSymbols.removeLast()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitBooleanLiteral(node: BooleanLiteral) {
 | 
				
			||||||
 | 
					    node.visitChildren(this)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitBreak(node: Break) {
 | 
				
			||||||
 | 
					    node.visitChildren(this)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitContinue(node: Continue) {
 | 
				
			||||||
 | 
					    node.visitChildren(this)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitDoubleLiteral(node: DoubleLiteral) {
 | 
				
			||||||
 | 
					    node.visitChildren(this)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitForIn(node: ForIn) {
 | 
				
			||||||
 | 
					    node.expression.visit(this)
 | 
				
			||||||
 | 
					    internalSymbols.add(mutableSetOf(node.item.symbol))
 | 
				
			||||||
 | 
					    node.block.visit(this)
 | 
				
			||||||
 | 
					    internalSymbols.removeLast()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitFunctionCall(node: FunctionCall) {
 | 
				
			||||||
 | 
					    checkAndContribute(node.symbol)
 | 
				
			||||||
 | 
					    for (argument in node.arguments) {
 | 
				
			||||||
 | 
					      visit(argument)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitIf(node: If) {
 | 
				
			||||||
 | 
					    node.condition.visit(this)
 | 
				
			||||||
 | 
					    node.thenBlock.visit(this)
 | 
				
			||||||
 | 
					    node.elseBlock?.visit(this)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitIndexedBy(node: IndexedBy) {
 | 
				
			||||||
 | 
					    node.visitChildren(this)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitInfixOperation(node: InfixOperation) {
 | 
				
			||||||
 | 
					    node.visitChildren(this)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitIntegerLiteral(node: IntegerLiteral) {
 | 
				
			||||||
 | 
					    node.visitChildren(this)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitLetAssignment(node: LetAssignment) {
 | 
				
			||||||
 | 
					    internalSymbols.last().add(node.symbol)
 | 
				
			||||||
 | 
					    node.value.visit(this)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitListLiteral(node: ListLiteral) {
 | 
				
			||||||
 | 
					    node.visitChildren(this)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitLongLiteral(node: LongLiteral) {
 | 
				
			||||||
 | 
					    node.visitChildren(this)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitNoneLiteral(node: NoneLiteral) {
 | 
				
			||||||
 | 
					    node.visitChildren(this)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitParentheses(node: Parentheses) {
 | 
				
			||||||
 | 
					    node.visitChildren(this)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitPrefixOperation(node: PrefixOperation) {
 | 
				
			||||||
 | 
					    node.visitChildren(this)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitSetAssignment(node: SetAssignment) {
 | 
				
			||||||
 | 
					    node.visitChildren(this)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitStringLiteral(node: StringLiteral) {
 | 
				
			||||||
 | 
					    node.visitChildren(this)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitSuffixOperation(node: SuffixOperation) {
 | 
				
			||||||
 | 
					    node.visitChildren(this)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitSymbolReference(node: SymbolReference) {
 | 
				
			||||||
 | 
					    checkAndContribute(node.symbol)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitVarAssignment(node: VarAssignment) {
 | 
				
			||||||
 | 
					    internalSymbols.last().add(node.symbol)
 | 
				
			||||||
 | 
					    node.value.visit(this)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitWhile(node: While) {
 | 
				
			||||||
 | 
					    node.condition.visit(this)
 | 
				
			||||||
 | 
					    internalSymbols.add(mutableSetOf())
 | 
				
			||||||
 | 
					    node.block.visit(this)
 | 
				
			||||||
 | 
					    internalSymbols.removeLast()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun checkAndContribute(symbol: Symbol) {
 | 
				
			||||||
 | 
					    if (internalSymbols.none { it.contains(symbol) }) {
 | 
				
			||||||
 | 
					      symbols.add(symbol)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,11 +1,9 @@
 | 
				
			|||||||
package gay.pizza.pork.frontend.scope
 | 
					package gay.pizza.pork.frontend.scope
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import gay.pizza.pork.ast.gen.Definition
 | 
					import gay.pizza.pork.ast.gen.Definition
 | 
				
			||||||
import gay.pizza.pork.ast.gen.Node
 | 
					import gay.pizza.pork.ast.gen.Symbol
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ScopeSymbol(
 | 
					class ScopeSymbol(val slabScope: SlabScope, val definition: Definition) {
 | 
				
			||||||
  val compilationUnit: Node,
 | 
					  val symbol: Symbol = definition.symbol
 | 
				
			||||||
  val definition: Definition
 | 
					  val scope: DefinitionScope by lazy { DefinitionScope(slabScope, definition) }
 | 
				
			||||||
) {
 | 
					 | 
				
			||||||
  val symbol = definition.symbol
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.frontend.scope
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.gen.Symbol
 | 
				
			||||||
 | 
					import gay.pizza.pork.frontend.Slab
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SlabScope(val worldScope: WorldScope, val slab: Slab) {
 | 
				
			||||||
 | 
					  private val externalSymbolsList = mutableSetOf<ScopeSymbol>()
 | 
				
			||||||
 | 
					  private val internalSymbolsList = mutableSetOf<ScopeSymbol>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val externalSymbols: Set<ScopeSymbol>
 | 
				
			||||||
 | 
					    get() = externalSymbolsList
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val internalSymbols: Set<ScopeSymbol>
 | 
				
			||||||
 | 
					    get() = internalSymbolsList
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val internallyVisibleSymbols: List<VisibleScopeSymbol> by lazy { findInternallyVisibleSymbols() }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun index() {
 | 
				
			||||||
 | 
					    for (definition in slab.compilationUnit.definitions) {
 | 
				
			||||||
 | 
					      val scopeSymbol = ScopeSymbol(this, definition)
 | 
				
			||||||
 | 
					      if (definition.modifiers.export) {
 | 
				
			||||||
 | 
					        externalSymbolsList.add(scopeSymbol)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      internalSymbolsList.add(scopeSymbol)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun findInternallyVisibleSymbols(): List<VisibleScopeSymbol> {
 | 
				
			||||||
 | 
					    val allSymbols = mutableMapOf<Symbol, VisibleScopeSymbol>()
 | 
				
			||||||
 | 
					    val imports = slab.importedSlabs
 | 
				
			||||||
 | 
					    for (import in imports) {
 | 
				
			||||||
 | 
					      val scope = worldScope.index(import)
 | 
				
			||||||
 | 
					      for (importedSymbol in scope.externalSymbols) {
 | 
				
			||||||
 | 
					        allSymbols[importedSymbol.symbol] = VisibleScopeSymbol(slab, importedSymbol)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (internalSymbol in internalSymbols) {
 | 
				
			||||||
 | 
					      allSymbols[internalSymbol.symbol] = VisibleScopeSymbol(slab, internalSymbol)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return allSymbols.values.toList()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun resolve(symbol: Symbol): ScopeSymbol? = internallyVisibleSymbols.firstOrNull {
 | 
				
			||||||
 | 
					    it.scopeSymbol.symbol == symbol
 | 
				
			||||||
 | 
					  }?.scopeSymbol
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
package gay.pizza.pork.frontend.scope
 | 
					package gay.pizza.pork.frontend.scope
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import gay.pizza.pork.ast.gen.CompilationUnit
 | 
					import gay.pizza.pork.frontend.Slab
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class VisibleScopeSymbol(val visibleToUnit: CompilationUnit, val scopeSymbol: ScopeSymbol) {
 | 
					class VisibleScopeSymbol(val visibleToSlab: Slab, val scopeSymbol: ScopeSymbol) {
 | 
				
			||||||
  val isInternalSymbol: Boolean
 | 
					  val isInternalSymbol: Boolean
 | 
				
			||||||
    get() = visibleToUnit == scopeSymbol.compilationUnit
 | 
					    get() = visibleToSlab == scopeSymbol.slabScope.slab
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,24 +1,24 @@
 | 
				
			|||||||
package gay.pizza.pork.frontend.scope
 | 
					package gay.pizza.pork.frontend.scope
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import gay.pizza.pork.ast.gen.CompilationUnit
 | 
					 | 
				
			||||||
import gay.pizza.pork.frontend.World
 | 
					import gay.pizza.pork.frontend.World
 | 
				
			||||||
 | 
					import gay.pizza.pork.frontend.Slab
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class WorldScope(val world: World) {
 | 
					class WorldScope(val world: World) {
 | 
				
			||||||
  private val compilationUnitScopes = mutableMapOf<CompilationUnit, CompilationUnitScope>()
 | 
					  private val slabScopes = mutableMapOf<Slab, SlabScope>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun indexAll() {
 | 
					  fun indexAll() {
 | 
				
			||||||
    for (unit in world.units) {
 | 
					    for (module in world.slabs) {
 | 
				
			||||||
      index(unit)
 | 
					      index(module)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun index(unit: CompilationUnit): CompilationUnitScope =
 | 
					  fun index(slab: Slab): SlabScope =
 | 
				
			||||||
    scope(unit).apply {
 | 
					    scope(slab).apply {
 | 
				
			||||||
      index()
 | 
					      index()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun scope(unit: CompilationUnit): CompilationUnitScope =
 | 
					  fun scope(slab: Slab): SlabScope =
 | 
				
			||||||
    compilationUnitScopes.computeIfAbsent(unit) {
 | 
					    slabScopes.computeIfAbsent(slab) {
 | 
				
			||||||
      CompilationUnitScope(this, unit)
 | 
					      SlabScope(this, slab)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -36,16 +36,16 @@ abstract class Tool {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  fun <T> visit(visitor: NodeVisitor<T>): T = visitor.visit(parse())
 | 
					  fun <T> visit(visitor: NodeVisitor<T>): T = visitor.visit(parse())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun loadMainFunction(scope: Scope, setupEvaluator: Evaluator.() -> Unit = {}): CallableFunction {
 | 
					  fun loadMainFunction(setupEvaluator: Evaluator.() -> Unit = {}): CallableFunction {
 | 
				
			||||||
    val world = buildWorld()
 | 
					    val world = buildWorld()
 | 
				
			||||||
    val evaluator = Evaluator(world, scope)
 | 
					    val evaluator = Evaluator(world)
 | 
				
			||||||
    setupEvaluator(evaluator)
 | 
					    setupEvaluator(evaluator)
 | 
				
			||||||
    val resultingScope = evaluator.evaluate(rootImportLocator)
 | 
					    val resultingScope = evaluator.evaluate(rootImportLocator)
 | 
				
			||||||
    return resultingScope.value("main") as CallableFunction
 | 
					    return resultingScope.value("main") as CallableFunction
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun loadMainFunctionStandard(scope: Scope, quiet: Boolean = false): CallableFunction =
 | 
					  fun loadMainFunctionStandard(quiet: Boolean = false): CallableFunction =
 | 
				
			||||||
    loadMainFunction(scope, setupEvaluator = {
 | 
					    loadMainFunction(setupEvaluator = {
 | 
				
			||||||
      addNativeProvider("internal", InternalNativeProvider(quiet = quiet))
 | 
					      addNativeProvider("internal", InternalNativeProvider(quiet = quiet))
 | 
				
			||||||
      addNativeProvider("ffi", FfiNativeProvider())
 | 
					      addNativeProvider("ffi", FfiNativeProvider())
 | 
				
			||||||
      addNativeProvider("java", JavaNativeProvider())
 | 
					      addNativeProvider("java", JavaNativeProvider())
 | 
				
			||||||
@ -60,8 +60,8 @@ abstract class Tool {
 | 
				
			|||||||
    return World(dynamicImportSource)
 | 
					    return World(dynamicImportSource)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun run(scope: Scope, quiet: Boolean = false) {
 | 
					  fun run(quiet: Boolean = false) {
 | 
				
			||||||
    val main = loadMainFunctionStandard(scope, quiet = quiet)
 | 
					    val main = loadMainFunctionStandard(quiet = quiet)
 | 
				
			||||||
    main.call(emptyList(), CallStack())
 | 
					    main.call(emptyList(), CallStack())
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -11,5 +11,5 @@ fun main(args: Array<String>) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
  val path = PlatformFsProvider.resolve(args[0])
 | 
					  val path = PlatformFsProvider.resolve(args[0])
 | 
				
			||||||
  val tool = FileTool(path)
 | 
					  val tool = FileTool(path)
 | 
				
			||||||
  tool.run(Scope.root())
 | 
					  tool.run()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -6,8 +6,12 @@ include(
 | 
				
			|||||||
  ":common",
 | 
					  ":common",
 | 
				
			||||||
  ":tokenizer",
 | 
					  ":tokenizer",
 | 
				
			||||||
  ":ast",
 | 
					  ":ast",
 | 
				
			||||||
 | 
					  ":bytecode",
 | 
				
			||||||
  ":parser",
 | 
					  ":parser",
 | 
				
			||||||
  ":frontend",
 | 
					  ":frontend",
 | 
				
			||||||
 | 
					  ":compiler",
 | 
				
			||||||
 | 
					  ":execution",
 | 
				
			||||||
 | 
					  ":vm",
 | 
				
			||||||
  ":evaluator",
 | 
					  ":evaluator",
 | 
				
			||||||
  ":stdlib",
 | 
					  ":stdlib",
 | 
				
			||||||
  ":ffi",
 | 
					  ":ffi",
 | 
				
			||||||
 | 
				
			|||||||
@ -34,7 +34,7 @@ object PorkStdlib : ContentSource {
 | 
				
			|||||||
    return StringCharSource(readPorkFile(path))
 | 
					    return StringCharSource(readPorkFile(path))
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun stableContentIdentity(path: String): String {
 | 
					  override fun stableContentPath(path: String): String {
 | 
				
			||||||
    return path
 | 
					    return path
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
export func ffiStructDefine(items...)
 | 
					export func ffiStructDefine(items...)
 | 
				
			||||||
  native ffi "internal" "ffiStructDefine"
 | 
					  native ffi "internal" "ffiStructDefine"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export func ffiStructAllocate(struct)
 | 
					export func ffiStructAllocate(def)
 | 
				
			||||||
  native ffi "internal" "ffiStructAllocate"
 | 
					  native ffi "internal" "ffiStructAllocate"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export func ffiStructValue(def, field, value)
 | 
					export func ffiStructValue(def, field, value)
 | 
				
			||||||
 | 
				
			|||||||
@ -76,7 +76,6 @@ enum class TokenType(vararg val properties: TokenTypeProperty) {
 | 
				
			|||||||
  ))),
 | 
					  ))),
 | 
				
			||||||
  BlockComment(CharConsume(MatchedCharConsumer("/*", "*/")), CommentFamily),
 | 
					  BlockComment(CharConsume(MatchedCharConsumer("/*", "*/")), CommentFamily),
 | 
				
			||||||
  LineComment(CharConsume(MatchedCharConsumer("//", "\n", AllowEofTermination)), CommentFamily),
 | 
					  LineComment(CharConsume(MatchedCharConsumer("//", "\n", AllowEofTermination)), CommentFamily),
 | 
				
			||||||
  Struct(ManyChars("struct"), KeywordFamily),
 | 
					 | 
				
			||||||
  EndOfFile;
 | 
					  EndOfFile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  val promotions: List<Promotion> =
 | 
					  val promotions: List<Promotion> =
 | 
				
			||||||
 | 
				
			|||||||
@ -7,6 +7,8 @@ plugins {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
dependencies {
 | 
					dependencies {
 | 
				
			||||||
  api(project(":minimal"))
 | 
					  api(project(":minimal"))
 | 
				
			||||||
 | 
					  api(project(":compiler"))
 | 
				
			||||||
 | 
					  api(project(":vm"))
 | 
				
			||||||
  api("com.github.ajalt.clikt:clikt:4.2.0")
 | 
					  api("com.github.ajalt.clikt:clikt:4.2.0")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  implementation(project(":common"))
 | 
					  implementation(project(":common"))
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										33
									
								
								tool/src/main/kotlin/gay/pizza/pork/tool/CompileCommand.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								tool/src/main/kotlin/gay/pizza/pork/tool/CompileCommand.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.tool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.github.ajalt.clikt.core.CliktCommand
 | 
				
			||||||
 | 
					import com.github.ajalt.clikt.parameters.arguments.argument
 | 
				
			||||||
 | 
					import gay.pizza.dough.fs.PlatformFsProvider
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.gen.Symbol
 | 
				
			||||||
 | 
					import gay.pizza.pork.compiler.Compiler
 | 
				
			||||||
 | 
					import gay.pizza.pork.minimal.FileTool
 | 
				
			||||||
 | 
					import gay.pizza.pork.vm.VirtualMachine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CompileCommand : CliktCommand(help = "Compile Pork to Bytecode", name = "compile") {
 | 
				
			||||||
 | 
					  val path by argument("file")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun run() {
 | 
				
			||||||
 | 
					    val tool = FileTool(PlatformFsProvider.resolve(path))
 | 
				
			||||||
 | 
					    val world = tool.buildWorld()
 | 
				
			||||||
 | 
					    val compiler = Compiler()
 | 
				
			||||||
 | 
					    val slab = world.load(tool.rootImportLocator)
 | 
				
			||||||
 | 
					    val compiledSlab = compiler.compilableSlabs.of(slab)
 | 
				
			||||||
 | 
					    val compiledMain = compiledSlab.compilableSymbolOf(Symbol("main"))
 | 
				
			||||||
 | 
					      ?: throw RuntimeException("'main' function not found.")
 | 
				
			||||||
 | 
					    val compiledWorld = compiler.compile(compiledMain)
 | 
				
			||||||
 | 
					    for (symbol in compiledWorld.symbolTable.symbols) {
 | 
				
			||||||
 | 
					      val code = compiledWorld.code.subList(symbol.offset.toInt(), (symbol.offset + symbol.size).toInt())
 | 
				
			||||||
 | 
					      println(symbol.id)
 | 
				
			||||||
 | 
					      for ((index, op) in code.withIndex()) {
 | 
				
			||||||
 | 
					        println("  ${symbol.offset + index.toUInt()} ${op.code.name} ${op.args.joinToString(" ")}")
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    val vm = VirtualMachine(compiledWorld)
 | 
				
			||||||
 | 
					    vm.execute()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -17,7 +17,8 @@ class RootCommand : CliktCommand(
 | 
				
			|||||||
      AstCommand(),
 | 
					      AstCommand(),
 | 
				
			||||||
      AttributeCommand(),
 | 
					      AttributeCommand(),
 | 
				
			||||||
      ScopeAnalysisCommand(),
 | 
					      ScopeAnalysisCommand(),
 | 
				
			||||||
      CopyStdlibCommand()
 | 
					      CopyStdlibCommand(),
 | 
				
			||||||
 | 
					      CompileCommand()
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -6,8 +6,6 @@ import com.github.ajalt.clikt.parameters.options.flag
 | 
				
			|||||||
import com.github.ajalt.clikt.parameters.options.option
 | 
					import com.github.ajalt.clikt.parameters.options.option
 | 
				
			||||||
import gay.pizza.dough.fs.PlatformFsProvider
 | 
					import gay.pizza.dough.fs.PlatformFsProvider
 | 
				
			||||||
import gay.pizza.pork.evaluator.*
 | 
					import gay.pizza.pork.evaluator.*
 | 
				
			||||||
import gay.pizza.pork.ffi.FfiNativeProvider
 | 
					 | 
				
			||||||
import gay.pizza.pork.ffi.JavaNativeProvider
 | 
					 | 
				
			||||||
import gay.pizza.pork.minimal.FileTool
 | 
					import gay.pizza.pork.minimal.FileTool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class RunCommand : CliktCommand(help = "Run Program", name = "run") {
 | 
					class RunCommand : CliktCommand(help = "Run Program", name = "run") {
 | 
				
			||||||
@ -19,12 +17,11 @@ class RunCommand : CliktCommand(help = "Run Program", name = "run") {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  override fun run() {
 | 
					  override fun run() {
 | 
				
			||||||
    val tool = FileTool(PlatformFsProvider.resolve(path))
 | 
					    val tool = FileTool(PlatformFsProvider.resolve(path))
 | 
				
			||||||
    val scope = Scope.root()
 | 
					    val main = tool.loadMainFunctionStandard(quiet = quiet)
 | 
				
			||||||
    val main = tool.loadMainFunctionStandard(scope, quiet = quiet)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (dumpScope) {
 | 
					    if (dumpScope) {
 | 
				
			||||||
      val functionContext = main as FunctionContext
 | 
					      val functionContext = main as FunctionContext
 | 
				
			||||||
      val internalScope = functionContext.compilationUnitContext.internalScope
 | 
					      val internalScope = functionContext.slabContext.internalScope
 | 
				
			||||||
      internalScope.crawlScopePath { key, path ->
 | 
					      internalScope.crawlScopePath { key, path ->
 | 
				
			||||||
        println("[scope] $key [${path.joinToString(" -> ")}]")
 | 
					        println("[scope] $key [${path.joinToString(" -> ")}]")
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
				
			|||||||
@ -15,12 +15,12 @@ class ScopeAnalysisCommand : CliktCommand(help = "Run Scope Analysis", name = "s
 | 
				
			|||||||
    val root = world.load(tool.rootImportLocator)
 | 
					    val root = world.load(tool.rootImportLocator)
 | 
				
			||||||
    val scope = WorldScope(world).apply { index(root) }
 | 
					    val scope = WorldScope(world).apply { index(root) }
 | 
				
			||||||
    val rootScope = scope.scope(root)
 | 
					    val rootScope = scope.scope(root)
 | 
				
			||||||
    val visibleScopeSymbols = rootScope.findInternallyVisibleSymbols()
 | 
					    for (visibleScopeSymbol in rootScope.internallyVisibleSymbols) {
 | 
				
			||||||
    for (visibleScopeSymbol in visibleScopeSymbols) {
 | 
					 | 
				
			||||||
      println(
 | 
					      println(
 | 
				
			||||||
        "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}"
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										11
									
								
								vm/build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								vm/build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					plugins {
 | 
				
			||||||
 | 
					  id("gay.pizza.pork.module")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dependencies {
 | 
				
			||||||
 | 
					  api(project(":execution"))
 | 
				
			||||||
 | 
					  api(project(":bytecode"))
 | 
				
			||||||
 | 
					  api(project(":compiler"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  implementation(project(":common"))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										80
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/InternalMachine.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/InternalMachine.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,80 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.vm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.CompiledWorld
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InternalMachine(val world: CompiledWorld, val handlers: List<OpHandler>) {
 | 
				
			||||||
 | 
					  private val inlined = world.code.map { op ->
 | 
				
			||||||
 | 
					    val handler = handlers.firstOrNull { it.code == op.code } ?:
 | 
				
			||||||
 | 
					      throw VirtualMachineException("Opcode ${op.code.name} does not have a handler.")
 | 
				
			||||||
 | 
					    op to handler
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private var inst: UInt = 0u
 | 
				
			||||||
 | 
					  private val stack = mutableListOf<Any>(EndOfCode)
 | 
				
			||||||
 | 
					  private val locals = mutableListOf<MutableMap<UInt, Any>>(
 | 
				
			||||||
 | 
					    mutableMapOf()
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					  private var autoNextInst = true
 | 
				
			||||||
 | 
					  private var exitFlag = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun step(): Boolean {
 | 
				
			||||||
 | 
					    val (op, handler) = inlined[inst.toInt()]
 | 
				
			||||||
 | 
					    handler.handle(this, op)
 | 
				
			||||||
 | 
					    if (autoNextInst) {
 | 
				
			||||||
 | 
					      inst++
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    autoNextInst = true
 | 
				
			||||||
 | 
					    return !exitFlag
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun pushScope() {
 | 
				
			||||||
 | 
					    locals.add(mutableMapOf())
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun popScope() {
 | 
				
			||||||
 | 
					    locals.removeLast()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun loadConstant(id: UInt) {
 | 
				
			||||||
 | 
					    push(world.constantPool.constants[id.toInt()])
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun loadLocal(id: UInt) {
 | 
				
			||||||
 | 
					    val localSet = locals.last()
 | 
				
			||||||
 | 
					    val local = localSet[id]
 | 
				
			||||||
 | 
					      ?: throw VirtualMachineException("Attempted to load local $id but it was not stored.")
 | 
				
			||||||
 | 
					    push(local)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun storeLocal(id: UInt) {
 | 
				
			||||||
 | 
					    val localSet = locals.last()
 | 
				
			||||||
 | 
					    val value = pop()
 | 
				
			||||||
 | 
					    localSet[id] = value
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun setNextInst(value: UInt) {
 | 
				
			||||||
 | 
					    inst = value
 | 
				
			||||||
 | 
					    autoNextInst = false
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun push(item: Any) {
 | 
				
			||||||
 | 
					    stack.add(item)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun pop(): Any = stack.removeLast()
 | 
				
			||||||
 | 
					  fun exit() {
 | 
				
			||||||
 | 
					    exitFlag = true
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun reset() {
 | 
				
			||||||
 | 
					    stack.clear()
 | 
				
			||||||
 | 
					    stack.add(EndOfCode)
 | 
				
			||||||
 | 
					    locals.clear()
 | 
				
			||||||
 | 
					    locals.add(mutableMapOf())
 | 
				
			||||||
 | 
					    inst = 0u
 | 
				
			||||||
 | 
					    exitFlag = false
 | 
				
			||||||
 | 
					    autoNextInst = true
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  data object EndOfCode
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										8
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/OpHandler.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/OpHandler.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.vm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.Op
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.Opcode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					abstract class OpHandler(val code: Opcode) {
 | 
				
			||||||
 | 
					  abstract fun handle(machine: InternalMachine, op: Op)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										45
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/VirtualMachine.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/VirtualMachine.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.vm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.bytecode.CompiledWorld
 | 
				
			||||||
 | 
					import gay.pizza.pork.execution.ExecutionContext
 | 
				
			||||||
 | 
					import gay.pizza.pork.vm.ops.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class VirtualMachine(world: CompiledWorld) : ExecutionContext {
 | 
				
			||||||
 | 
					  private val internal = InternalMachine(world, listOf(
 | 
				
			||||||
 | 
					    IntegerOpHandler,
 | 
				
			||||||
 | 
					    ConstantOpHandler,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TrueOpHandler,
 | 
				
			||||||
 | 
					    FalseOpHandler,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ListOpHandler,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CompareEqualOpHandler,
 | 
				
			||||||
 | 
					    CompareLesserEqualOpHandler,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    AddOpHandler,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    JumpOpHandler,
 | 
				
			||||||
 | 
					    JumpIfOpHandler,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    LoadLocalOpHandler,
 | 
				
			||||||
 | 
					    StoreLocalOpHandler,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CallOpHandler,
 | 
				
			||||||
 | 
					    RetOpHandler,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    NativeOpHandler,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ScopeInOpHandler,
 | 
				
			||||||
 | 
					    ScopeOutOpHandler
 | 
				
			||||||
 | 
					  ))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun execute() {
 | 
				
			||||||
 | 
					    while (true) {
 | 
				
			||||||
 | 
					      if (!internal.step()) {
 | 
				
			||||||
 | 
					        break
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    internal.reset()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.vm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class VirtualMachineException(message: String) : RuntimeException(message)
 | 
				
			||||||
@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.vm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.gen.Symbol
 | 
				
			||||||
 | 
					import gay.pizza.pork.compiler.Compiler
 | 
				
			||||||
 | 
					import gay.pizza.pork.execution.ExecutionContext
 | 
				
			||||||
 | 
					import gay.pizza.pork.execution.ExecutionContextProvider
 | 
				
			||||||
 | 
					import gay.pizza.pork.frontend.ImportLocator
 | 
				
			||||||
 | 
					import gay.pizza.pork.frontend.World
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class VirtualMachineProvider(val world: World) : ExecutionContextProvider {
 | 
				
			||||||
 | 
					  override fun prepare(importLocator: ImportLocator, entryPointSymbol: Symbol): ExecutionContext {
 | 
				
			||||||
 | 
					    val compiler = Compiler()
 | 
				
			||||||
 | 
					    val slab = world.load(importLocator)
 | 
				
			||||||
 | 
					    val compilableSlab = compiler.compilableSlabs.of(slab)
 | 
				
			||||||
 | 
					    val compilableSymbol = compilableSlab.compilableSymbolOf(entryPointSymbol) ?:
 | 
				
			||||||
 | 
					      throw RuntimeException("Unable to find compilable symbol for entry point '${entryPointSymbol.id}'")
 | 
				
			||||||
 | 
					    val compiledWorld = compiler.compile(compilableSymbol)
 | 
				
			||||||
 | 
					    return VirtualMachine(compiledWorld)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										19
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/AddOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/AddOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					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
 | 
				
			||||||
 | 
					import gay.pizza.pork.vm.VirtualMachineException
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object AddOpHandler : OpHandler(Opcode.Add) {
 | 
				
			||||||
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
 | 
					    val left = machine.pop()
 | 
				
			||||||
 | 
					    val right = machine.pop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (left !is Int || right !is Int) {
 | 
				
			||||||
 | 
					      throw VirtualMachineException("Bad types.")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    machine.push(left + right)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										13
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/CallOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/CallOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							@ -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 CallOpHandler : OpHandler(Opcode.Call) {
 | 
				
			||||||
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
 | 
					    machine.setNextInst(op.args[0])
 | 
				
			||||||
 | 
					    machine.pushScope()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -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 CompareEqualOpHandler : OpHandler(Opcode.CompareEqual) {
 | 
				
			||||||
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
 | 
					    machine.push(machine.pop() == machine.pop())
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					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
 | 
				
			||||||
 | 
					import gay.pizza.pork.vm.VirtualMachineException
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object CompareLesserEqualOpHandler : OpHandler(Opcode.CompareLesserEqual) {
 | 
				
			||||||
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
 | 
					    val right = machine.pop()
 | 
				
			||||||
 | 
					    val left = machine.pop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (left !is Int || right !is Int) {
 | 
				
			||||||
 | 
					      throw VirtualMachineException("Bad types.")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    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 ConstantOpHandler : OpHandler(Opcode.Constant) {
 | 
				
			||||||
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
 | 
					    machine.loadConstant(op.args[0])
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										12
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/FalseOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/FalseOpHandler.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 FalseOpHandler : OpHandler(Opcode.False) {
 | 
				
			||||||
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
 | 
					    machine.push(false)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										12
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/IntegerOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/IntegerOpHandler.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 IntegerOpHandler : OpHandler(Opcode.Integer) {
 | 
				
			||||||
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
 | 
					    machine.push(op.args[0].toInt())
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										20
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/JumpIfOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/JumpIfOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					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
 | 
				
			||||||
 | 
					import gay.pizza.pork.vm.VirtualMachineException
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object JumpIfOpHandler : OpHandler(Opcode.JumpIf) {
 | 
				
			||||||
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
 | 
					    val value = machine.pop()
 | 
				
			||||||
 | 
					    if (value !is Boolean) {
 | 
				
			||||||
 | 
					      throw VirtualMachineException("JumpIf expects a boolean value on the stack.")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (value) {
 | 
				
			||||||
 | 
					      machine.setNextInst(op.args[0])
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										12
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/JumpOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/JumpOpHandler.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 JumpOpHandler : OpHandler(Opcode.Jump) {
 | 
				
			||||||
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
 | 
					    machine.setNextInst(op.args[0])
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										18
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/ListOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/ListOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					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 ListOpHandler : OpHandler(Opcode.List) {
 | 
				
			||||||
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
 | 
					    val count = op.args[0]
 | 
				
			||||||
 | 
					    val list = mutableListOf<Any>()
 | 
				
			||||||
 | 
					    for (i in 1u..count) {
 | 
				
			||||||
 | 
					      val item = machine.pop()
 | 
				
			||||||
 | 
					      list.add(item)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    machine.push(list.reversed())
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -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 LoadLocalOpHandler : OpHandler(Opcode.LoadLocal) {
 | 
				
			||||||
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
 | 
					    machine.loadLocal(op.args[0])
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										16
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/NativeOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/NativeOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					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 NativeOpHandler : OpHandler(Opcode.Native) {
 | 
				
			||||||
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
 | 
					    val countOfNativeDefs = op.args[1].toInt()
 | 
				
			||||||
 | 
					    val defs = mutableListOf<Any>()
 | 
				
			||||||
 | 
					    for (i in 0 until countOfNativeDefs) {
 | 
				
			||||||
 | 
					      defs.add(String(machine.pop() as ByteArray))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										18
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/RetOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/RetOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					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 RetOpHandler : OpHandler(Opcode.Return) {
 | 
				
			||||||
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
 | 
					    val last = machine.pop()
 | 
				
			||||||
 | 
					    if (last == InternalMachine.EndOfCode) {
 | 
				
			||||||
 | 
					      machine.exit()
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    machine.popScope()
 | 
				
			||||||
 | 
					    machine.setNextInst((last as Int).toUInt())
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										10
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/ScopeInOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/ScopeInOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					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 ScopeInOpHandler : OpHandler(Opcode.ScopeIn) {
 | 
				
			||||||
 | 
					  override fun handle(machine: InternalMachine, op: Op) {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					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 ScopeOutOpHandler : OpHandler(Opcode.ScopeOut) {
 | 
				
			||||||
 | 
					  override fun handle(machine: InternalMachine, op: Op) {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -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 StoreLocalOpHandler : OpHandler(Opcode.StoreLocal) {
 | 
				
			||||||
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
 | 
					    machine.storeLocal(op.args[0])
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										12
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/TrueOpHandler.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								vm/src/main/kotlin/gay/pizza/pork/vm/ops/TrueOpHandler.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 TrueOpHandler : OpHandler(Opcode.True) {
 | 
				
			||||||
 | 
					  override fun handle(machine: InternalMachine, op: Op) {
 | 
				
			||||||
 | 
					    machine.push(true)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user