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