language: prelude and internal functions, and varargs support

This commit is contained in:
2023-09-10 19:27:59 -04:00
parent 1cfb197a7f
commit e8c984f2dc
24 changed files with 166 additions and 104 deletions

View File

@ -1,9 +1,6 @@
package gay.pizza.pork.evaluator
import gay.pizza.pork.ast.CompilationUnit
import gay.pizza.pork.ast.Definition
import gay.pizza.pork.ast.FunctionDefinition
import gay.pizza.pork.ast.ImportDeclaration
import gay.pizza.pork.ast.*
import gay.pizza.pork.frontend.ImportLocator
class CompilationUnitContext(
@ -45,6 +42,7 @@ class CompilationUnitContext(
}
private fun processAllImports() {
processPreludeImport()
val imports = compilationUnit.declarations.filterIsInstance<ImportDeclaration>()
for (import in imports) {
processImport(import)
@ -57,4 +55,18 @@ class CompilationUnitContext(
val evaluationContext = evaluator.context(importLocator)
internalScope.inherit(evaluationContext.externalScope)
}
private fun processPreludeImport() {
processImport(preludeImport)
}
companion object {
private val preludeImport = ImportDeclaration(
Symbol("std"),
listOf(
Symbol("lang"),
Symbol("prelude")
)
)
}
}

View File

@ -119,8 +119,8 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
subtract = { a, b -> a - b },
multiply = { a, b -> a * b },
divide = { a, b -> a / b },
euclideanModulo = { _, _ -> throw RuntimeException("Can't perform integer modulo between floating point types") },
remainder = { _, _ -> throw RuntimeException("Can't perform integer remainder between floating point types") },
euclideanModulo = { _, _ -> floatingPointTypeError("integer modulo") },
remainder = { _, _ -> floatingPointTypeError("integer remainder") },
lesser = { a, b -> a < b },
greater = { a, b -> a > b },
lesserEqual = { a, b -> a <= b },
@ -138,8 +138,8 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
subtract = { a, b -> a - b },
multiply = { a, b -> a * b },
divide = { a, b -> a / b },
euclideanModulo = { _, _ -> throw RuntimeException("Can't perform integer modulo between floating point types") },
remainder = { _, _ -> throw RuntimeException("Can't perform integer remainder between floating point types") },
euclideanModulo = { _, _ -> floatingPointTypeError("integer modulo") },
remainder = { _, _ -> floatingPointTypeError("integer remainder") },
lesser = { a, b -> a < b },
greater = { a, b -> a > b },
lesserEqual = { a, b -> a <= b },
@ -228,31 +228,19 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
}
override fun visitFunctionDefinition(node: FunctionDefinition): Any {
throw RuntimeException(
"Function declarations cannot be visited in an EvaluationVisitor. " +
"Utilize a FunctionContext."
)
topLevelUsedError("FunctionDefinition", "FunctionContext")
}
override fun visitImportDeclaration(node: ImportDeclaration): Any {
throw RuntimeException(
"Import declarations cannot be visited in an EvaluationVisitor. " +
"Utilize an CompilationUnitContext."
)
topLevelUsedError("ImportDeclaration", "CompilationUnitContext")
}
override fun visitCompilationUnit(node: CompilationUnit): Any {
throw RuntimeException(
"Compilation units cannot be visited in an EvaluationVisitor. " +
"Utilize an CompilationUnitContext."
)
topLevelUsedError("CompilationUnit", "CompilationUnitContext")
}
override fun visitNative(node: Native): Any {
throw RuntimeException(
"Native definition cannot be visited in an EvaluationVisitor. " +
"Utilize an FunctionContext."
)
topLevelUsedError("Native", "FunctionContext")
}
override fun visitContinue(node: Continue): Any = ContinueMarker
@ -266,6 +254,17 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
}
}
private fun floatingPointTypeError(operation: String): Nothing {
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 ContinueMarker: RuntimeException("Continue Marker")
}

View File

@ -5,7 +5,7 @@ import gay.pizza.pork.frontend.World
class Evaluator(val world: World, val scope: Scope) {
private val contexts = mutableMapOf<String, CompilationUnitContext>()
private val nativeFunctionProviders = mutableMapOf<String, NativeFunctionProvider>()
private val nativeProviders = mutableMapOf<String, NativeProvider>()
fun evaluate(locator: ImportLocator): Scope =
context(locator).externalScope
@ -20,12 +20,12 @@ class Evaluator(val world: World, val scope: Scope) {
return context
}
fun nativeFunctionProvider(form: String): NativeFunctionProvider {
return nativeFunctionProviders[form] ?:
fun nativeFunctionProvider(form: String): NativeProvider {
return nativeProviders[form] ?:
throw RuntimeException("Unknown native function form: $form")
}
fun addNativeFunctionProvider(form: String, nativeFunctionProvider: NativeFunctionProvider) {
nativeFunctionProviders[form] = nativeFunctionProvider
fun addNativeProvider(form: String, nativeProvider: NativeProvider) {
nativeProviders[form] = nativeProvider
}
}

View File

@ -20,8 +20,14 @@ class FunctionContext(val compilationUnitContext: CompilationUnitContext, val no
}
val scope = compilationUnitContext.internalScope.fork()
for ((index, argumentSymbol) in node.arguments.withIndex()) {
scope.define(argumentSymbol.id, arguments.values[index])
for ((index, spec) in node.arguments.withIndex()) {
if (spec.multiple) {
val list = arguments.values.subList(index, arguments.values.size - 1)
scope.define(spec.symbol.id, list)
break
} else {
scope.define(spec.symbol.id, arguments.values[index])
}
}
if (node.block == null) {

View File

@ -0,0 +1,23 @@
package gay.pizza.pork.evaluator
class InternalNativeProvider(val quiet: Boolean = false) : NativeProvider {
private val functions = mutableMapOf(
"println" to CallableFunction(::printLine)
)
override fun provideNativeFunction(definition: String): CallableFunction {
return functions[definition] ?: throw RuntimeException("Unknown Internal Function: $definition")
}
private fun printLine(arguments: Arguments): Any {
if (quiet) {
return None
}
when (arguments.values.count()) {
0 -> println()
1 -> println(arguments.values[0])
else -> println(arguments.values.joinToString(" "))
}
return None
}
}

View File

@ -1,5 +1,5 @@
package gay.pizza.pork.evaluator
interface NativeFunctionProvider {
interface NativeProvider {
fun provideNativeFunction(definition: String): CallableFunction
}