mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-02 12:50:55 +00:00
add debug mode
This commit is contained in:
parent
8d8866c26c
commit
ff2aaabd93
@ -3,14 +3,15 @@ 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.execution.ExecutionOptions
|
||||
import gay.pizza.pork.execution.NativeRegistry
|
||||
import gay.pizza.pork.frontend.ImportLocator
|
||||
import gay.pizza.pork.frontend.World
|
||||
|
||||
class EvaluatorProvider(val world: World) : ExecutionContextProvider {
|
||||
override fun prepare(importLocator: ImportLocator, entryPointSymbol: Symbol, nativeRegistry: NativeRegistry): ExecutionContext {
|
||||
override fun prepare(importLocator: ImportLocator, entryPointSymbol: Symbol, options: ExecutionOptions): ExecutionContext {
|
||||
val evaluator = Evaluator(world)
|
||||
nativeRegistry.forEachProvider { form, provider ->
|
||||
options.nativeRegistry.forEachProvider { form, provider ->
|
||||
if (provider is ExpandedNativeProvider) {
|
||||
evaluator.addNativeProvider(form, provider)
|
||||
} else {
|
||||
|
15
examples/bad.pork
Normal file
15
examples/bad.pork
Normal file
@ -0,0 +1,15 @@
|
||||
func depth(i: int32) {
|
||||
println("Depth: ", i)
|
||||
}
|
||||
|
||||
export func main() {
|
||||
if true {
|
||||
false
|
||||
}
|
||||
|
||||
if false {
|
||||
true
|
||||
}
|
||||
|
||||
return println("uhm, bad")
|
||||
}
|
@ -4,5 +4,5 @@ import gay.pizza.pork.ast.gen.Symbol
|
||||
import gay.pizza.pork.frontend.ImportLocator
|
||||
|
||||
interface ExecutionContextProvider {
|
||||
fun prepare(importLocator: ImportLocator, entryPointSymbol: Symbol, nativeRegistry: NativeRegistry): ExecutionContext
|
||||
fun prepare(importLocator: ImportLocator, entryPointSymbol: Symbol, options: ExecutionOptions): ExecutionContext
|
||||
}
|
||||
|
@ -0,0 +1,6 @@
|
||||
package gay.pizza.pork.execution
|
||||
|
||||
class ExecutionOptions(
|
||||
val nativeRegistry: NativeRegistry,
|
||||
val debug: Boolean = false,
|
||||
)
|
@ -7,6 +7,7 @@ import gay.pizza.pork.ast.gen.visit
|
||||
import gay.pizza.pork.evaluator.*
|
||||
import gay.pizza.pork.execution.ExecutionContext
|
||||
import gay.pizza.pork.execution.ExecutionContextProvider
|
||||
import gay.pizza.pork.execution.ExecutionOptions
|
||||
import gay.pizza.pork.execution.InternalNativeProvider
|
||||
import gay.pizza.pork.execution.NativeRegistry
|
||||
import gay.pizza.pork.ffi.FfiNativeProvider
|
||||
@ -44,9 +45,9 @@ abstract class Tool {
|
||||
fun createExecutionContextProvider(type: ExecutionType): ExecutionContextProvider =
|
||||
type.create(buildWorld())
|
||||
|
||||
fun createExecutionContext(type: ExecutionType, symbol: Symbol, nativeRegistry: NativeRegistry): ExecutionContext {
|
||||
fun createExecutionContext(type: ExecutionType, symbol: Symbol, options: ExecutionOptions): ExecutionContext {
|
||||
val executionContextProvider = createExecutionContextProvider(type)
|
||||
return executionContextProvider.prepare(rootImportLocator, symbol, nativeRegistry)
|
||||
return executionContextProvider.prepare(rootImportLocator, symbol, options)
|
||||
}
|
||||
|
||||
fun buildWorld(): World {
|
||||
|
@ -3,6 +3,7 @@ package gay.pizza.pork.minimal
|
||||
import gay.pizza.dough.fs.PlatformFsProvider
|
||||
import gay.pizza.pork.ast.gen.Symbol
|
||||
import gay.pizza.pork.evaluator.Scope
|
||||
import gay.pizza.pork.execution.ExecutionOptions
|
||||
import gay.pizza.pork.execution.InternalNativeProvider
|
||||
import gay.pizza.pork.execution.NativeRegistry
|
||||
import kotlin.system.exitProcess
|
||||
@ -19,7 +20,7 @@ fun main(args: Array<String>) {
|
||||
val main = tool.createExecutionContext(
|
||||
ExecutionType.Evaluator,
|
||||
Symbol("main"),
|
||||
nativeRegistry
|
||||
ExecutionOptions(nativeRegistry = nativeRegistry)
|
||||
)
|
||||
main.execute()
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import gay.pizza.pork.ast.gen.Node
|
||||
import gay.pizza.pork.ast.gen.NodeType
|
||||
import gay.pizza.pork.parser.ParseError
|
||||
import gay.pizza.pork.parser.ParserNodeAttribution
|
||||
import gay.pizza.pork.tokenizer.ExpectedTokenError
|
||||
|
||||
class PsiBuilderMarkAttribution(val builder: PsiBuilder) : ParserNodeAttribution() {
|
||||
override fun <T : Node> produce(type: NodeType, block: () -> T): T {
|
||||
@ -19,6 +20,12 @@ class PsiBuilderMarkAttribution(val builder: PsiBuilder) : ParserNodeAttribution
|
||||
builder.advanceLexer()
|
||||
}
|
||||
throw PorkParser.ExitParser()
|
||||
} catch (e: ExpectedTokenError) {
|
||||
marker.error("${e.message}")
|
||||
while (!builder.eof()) {
|
||||
builder.advanceLexer()
|
||||
}
|
||||
throw PorkParser.ExitParser()
|
||||
} catch (e: ParseError) {
|
||||
marker.error(e.error)
|
||||
while (!builder.eof()) {
|
||||
|
@ -177,7 +177,8 @@ object PorkReferenceResolution {
|
||||
for (file in getRelevantFiles(containingFile)) {
|
||||
val definitions = PsiTreeUtil.collectElements(file.file) { element ->
|
||||
element is FunctionDefinitionElement ||
|
||||
element is LetDefinitionElement
|
||||
element is LetDefinitionElement ||
|
||||
element is TypeDefinitionElement
|
||||
}.filterIsInstance<PorkNamedElement>()
|
||||
if (name != null) {
|
||||
val fileFoundDefinition = definitions.firstOrNull {
|
||||
|
@ -9,6 +9,7 @@ import com.github.ajalt.clikt.parameters.options.option
|
||||
import com.github.ajalt.clikt.parameters.types.enum
|
||||
import gay.pizza.dough.fs.PlatformFsProvider
|
||||
import gay.pizza.pork.ast.gen.Symbol
|
||||
import gay.pizza.pork.execution.ExecutionOptions
|
||||
import gay.pizza.pork.execution.InternalNativeProvider
|
||||
import gay.pizza.pork.execution.NativeRegistry
|
||||
import gay.pizza.pork.ffi.FfiNativeProvider
|
||||
@ -20,6 +21,7 @@ class RunCommand : CliktCommand("run") {
|
||||
val loop by option("--loop", help = "Loop Program").flag()
|
||||
val measure by option("--measure", help = "Measure Time").flag()
|
||||
val quiet by option("--quiet", help = "Silence Prints").flag()
|
||||
val debug by option("--debug", help = "Debug Mode").flag()
|
||||
val executionType by option("--execution-type", "-E")
|
||||
.enum<ExecutionType> { it.id }
|
||||
.default(ExecutionType.VirtualMachine)
|
||||
@ -33,7 +35,10 @@ class RunCommand : CliktCommand("run") {
|
||||
nativeRegistry.add("internal", InternalNativeProvider(quiet = quiet))
|
||||
nativeRegistry.add("java", JavaNativeProvider())
|
||||
nativeRegistry.add("ffi", FfiNativeProvider())
|
||||
val main = tool.createExecutionContext(executionType, Symbol("main"), nativeRegistry)
|
||||
val main = tool.createExecutionContext(executionType, Symbol("main"), ExecutionOptions(
|
||||
nativeRegistry = nativeRegistry,
|
||||
debug = debug,
|
||||
))
|
||||
maybeLoopAndMeasure(loop, measure) {
|
||||
main.execute()
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import gay.pizza.pork.bytecode.CompiledWorld
|
||||
import gay.pizza.pork.bytecode.ConstantTag
|
||||
import gay.pizza.pork.execution.NativeRegistry
|
||||
|
||||
class InternalMachine(val world: CompiledWorld, val nativeRegistry: NativeRegistry, val handlers: List<OpHandler>) {
|
||||
class InternalMachine(val world: CompiledWorld, val nativeRegistry: NativeRegistry, val handlers: List<OpHandler>, val debug: Boolean = false) {
|
||||
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.")
|
||||
@ -23,6 +23,11 @@ class InternalMachine(val world: CompiledWorld, val nativeRegistry: NativeRegist
|
||||
|
||||
fun step(): Boolean {
|
||||
val (op, handler) = inlined[inst.toInt()]
|
||||
if (debug) {
|
||||
val frame = frame(inst)
|
||||
println("vm: step: in ${frame?.symbolInfo?.commonSymbolIdentity ?: "unknown"}: $inst ${op.code}${if (op.args.isEmpty()) "" else " " + op.args.joinToString(" ")}")
|
||||
}
|
||||
|
||||
handler.handle(this, op)
|
||||
if (autoNextInst) {
|
||||
inst++
|
||||
@ -32,19 +37,29 @@ class InternalMachine(val world: CompiledWorld, val nativeRegistry: NativeRegist
|
||||
}
|
||||
|
||||
fun pushScope() {
|
||||
if (debug) {
|
||||
println(" vm: push scope")
|
||||
}
|
||||
locals.add(LocalSlots())
|
||||
}
|
||||
|
||||
fun popScope() {
|
||||
if (debug) {
|
||||
println(" vm: pop scope")
|
||||
}
|
||||
locals.removeLast()
|
||||
}
|
||||
|
||||
fun loadConstant(id: UInt) {
|
||||
val constant = world.constantPool.constants[id.toInt()]
|
||||
when (constant.tag) {
|
||||
ConstantTag.String -> push(String(constant.value))
|
||||
val value = when (constant.tag) {
|
||||
ConstantTag.String -> String(constant.value)
|
||||
else -> throw VirtualMachineException("Unknown constant tag: ${constant.tag.name}")
|
||||
}
|
||||
if (debug) {
|
||||
println(" vm: load constant: ${constant.id} ${constant.tag.name} $value")
|
||||
}
|
||||
push(value)
|
||||
}
|
||||
|
||||
fun localAt(id: UInt): Any {
|
||||
@ -53,35 +68,57 @@ class InternalMachine(val world: CompiledWorld, val nativeRegistry: NativeRegist
|
||||
}
|
||||
|
||||
fun loadLocal(id: UInt) {
|
||||
push(localAt(id))
|
||||
val value = localAt(id)
|
||||
if (debug) {
|
||||
println(" vm: load local: $id $value")
|
||||
}
|
||||
push(value)
|
||||
}
|
||||
|
||||
fun storeLocal(id: UInt) {
|
||||
val localSet = locals.last()
|
||||
val value = popAnyValue()
|
||||
if (debug) {
|
||||
println(" vm: store local: $id = $value")
|
||||
}
|
||||
localSet.store(id, value)
|
||||
}
|
||||
|
||||
fun setNextInst(value: UInt) {
|
||||
inst = value
|
||||
autoNextInst = false
|
||||
if (debug) {
|
||||
println(" vm: next instruction: $value")
|
||||
}
|
||||
}
|
||||
|
||||
fun pushReturnAddress(value: UInt) {
|
||||
if (debug) {
|
||||
println(" vm: push return address: $value")
|
||||
}
|
||||
returnAddressStack.add(value)
|
||||
}
|
||||
|
||||
fun pushCallStack(value: UInt) {
|
||||
if (debug) {
|
||||
println(" vm: push call stack: $value")
|
||||
}
|
||||
callStack.add(value)
|
||||
}
|
||||
|
||||
fun popCallStack() {
|
||||
callStack.removeLast()
|
||||
val call = callStack.removeLast()
|
||||
if (debug) {
|
||||
println(" vm: pop call stack: $call")
|
||||
}
|
||||
}
|
||||
|
||||
fun armReturnAddressIfSet() {
|
||||
val returnAddress = returnAddressStack.removeLastOrNull()
|
||||
if (returnAddress != null) {
|
||||
if (debug) {
|
||||
println(" vm: arm return address: $returnAddress")
|
||||
}
|
||||
setNextInst(returnAddress)
|
||||
} else {
|
||||
exit()
|
||||
@ -89,18 +126,33 @@ class InternalMachine(val world: CompiledWorld, val nativeRegistry: NativeRegist
|
||||
}
|
||||
|
||||
fun push(item: Any) {
|
||||
if (debug) {
|
||||
println(" vm: push stack: $item")
|
||||
}
|
||||
stack.add(item)
|
||||
}
|
||||
|
||||
fun popAnyValue(): Any = stack.removeLast()
|
||||
fun popAnyValue(): Any {
|
||||
val value = stack.removeLast()
|
||||
if (debug) {
|
||||
println(" vm: pop stack: $value")
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
inline fun <reified T> pop(): T = popAnyValue() as T
|
||||
|
||||
fun exit() {
|
||||
if (debug) {
|
||||
println(" vm: exit")
|
||||
}
|
||||
exitFlag = true
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
if (debug) {
|
||||
println("vm: reset")
|
||||
}
|
||||
stack.clear()
|
||||
callStack.clear()
|
||||
callStack.add(0u)
|
||||
|
@ -4,11 +4,12 @@ import gay.pizza.pork.bytecode.CompiledWorld
|
||||
import gay.pizza.pork.execution.ExecutionContext
|
||||
import gay.pizza.pork.execution.NativeRegistry
|
||||
|
||||
class VirtualMachine(world: CompiledWorld, nativeRegistry: NativeRegistry) : ExecutionContext {
|
||||
class VirtualMachine(world: CompiledWorld, nativeRegistry: NativeRegistry, debug: Boolean = false) : ExecutionContext {
|
||||
private val internal = InternalMachine(
|
||||
world = world,
|
||||
nativeRegistry = nativeRegistry,
|
||||
handlers = StandardOpHandlers
|
||||
handlers = StandardOpHandlers,
|
||||
debug = debug,
|
||||
)
|
||||
|
||||
override fun execute() {
|
||||
|
@ -4,18 +4,18 @@ 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.execution.NativeRegistry
|
||||
import gay.pizza.pork.execution.ExecutionOptions
|
||||
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, nativeRegistry: NativeRegistry): ExecutionContext {
|
||||
override fun prepare(importLocator: ImportLocator, entryPointSymbol: Symbol, options: ExecutionOptions): ExecutionContext {
|
||||
val compiler = Compiler(world)
|
||||
val slab = world.load(importLocator)
|
||||
val compilableSlab = compiler.compilableSlabs.of(slab)
|
||||
val compilableSymbol = compilableSlab.resolve(entryPointSymbol) ?:
|
||||
throw RuntimeException("Unable to find compilable symbol for entry point '${entryPointSymbol.id}'")
|
||||
val compiledWorld = compiler.compile(compilableSymbol)
|
||||
return VirtualMachine(compiledWorld, nativeRegistry)
|
||||
return VirtualMachine(world = compiledWorld, nativeRegistry = options.nativeRegistry, debug = options.debug)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user