diff --git a/README.md b/README.md index 37a6bb7..39608ed 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,11 @@ A work-in-progress programming language. ```pork /* fibonacci sequence */ func fib(n) { - if n == 0 - then 0 - else if n == 1 - then 1 - else fib(n - 1) + fib(n - 2) + if n < 2 { + n + } else { + fib(n - 1) + fib(n - 2) + } } func main() { diff --git a/ast/src/main/ast/pork.yml b/ast/src/main/ast/pork.yml index 461abc2..7b582b5 100644 --- a/ast/src/main/ast/pork.yml +++ b/ast/src/main/ast/pork.yml @@ -117,6 +117,12 @@ types: type: Symbol - name: arguments type: List + ArgumentSpec: + values: + - name: symbol + type: Symbol + - name: multiple + type: Boolean FunctionDefinition: parent: Definition values: @@ -125,7 +131,7 @@ types: - name: symbol type: Symbol - name: arguments - type: List + type: List - name: block type: Block? - name: native diff --git a/ast/src/main/graph/types.dot b/ast/src/main/graph/types.dot index 2fd7de9..6d3fc4a 100644 --- a/ast/src/main/graph/types.dot +++ b/ast/src/main/graph/types.dot @@ -14,6 +14,7 @@ digraph A { type_InfixOperation [shape=box,label="InfixOperation"] type_BooleanLiteral [shape=box,label="BooleanLiteral"] type_FunctionCall [shape=box,label="FunctionCall"] + type_ArgumentSpec [shape=box,label="ArgumentSpec"] type_FunctionDefinition [shape=box,label="FunctionDefinition"] type_If [shape=box,label="If"] type_ImportDeclaration [shape=box,label="ImportDeclaration"] @@ -70,8 +71,10 @@ digraph A { type_InfixOperation -> type_InfixOperator [style=dotted] type_FunctionCall -> type_Symbol [style=dotted] type_FunctionCall -> type_Expression [style=dotted] + type_ArgumentSpec -> type_Symbol [style=dotted] type_FunctionDefinition -> type_DefinitionModifiers [style=dotted] type_FunctionDefinition -> type_Symbol [style=dotted] + type_FunctionDefinition -> type_ArgumentSpec [style=dotted] type_FunctionDefinition -> type_Block [style=dotted] type_FunctionDefinition -> type_Native [style=dotted] type_If -> type_Expression [style=dotted] diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/ArgumentSpec.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/ArgumentSpec.kt new file mode 100644 index 0000000..cf1be91 --- /dev/null +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/ArgumentSpec.kt @@ -0,0 +1,9 @@ +// GENERATED CODE FROM PORK AST CODEGEN +package gay.pizza.pork.ast + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +@SerialName("argumentSpec") +class ArgumentSpec(var symbol: Symbol, var multiple: Boolean) diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/FunctionDefinition.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/FunctionDefinition.kt index bbc3877..0862d80 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/FunctionDefinition.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/FunctionDefinition.kt @@ -6,11 +6,11 @@ import kotlinx.serialization.Serializable @Serializable @SerialName("functionDefinition") -class FunctionDefinition(override val modifiers: DefinitionModifiers, override val symbol: Symbol, val arguments: List, val block: Block?, val native: Native?) : Definition() { +class FunctionDefinition(override val modifiers: DefinitionModifiers, override val symbol: Symbol, val arguments: List, val block: Block?, val native: Native?) : Definition() { override val type: NodeType = NodeType.FunctionDefinition override fun visitChildren(visitor: NodeVisitor): List = - visitor.visitAll(listOf(symbol), arguments, listOf(block), listOf(native)) + visitor.visitAll(listOf(symbol), listOf(block), listOf(native)) override fun visit(visitor: NodeVisitor): T = visitor.visitFunctionDefinition(this) diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/CompilationUnitContext.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/CompilationUnitContext.kt index 7ac02f5..b9b9fa7 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/CompilationUnitContext.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/CompilationUnitContext.kt @@ -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() 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") + ) + ) + } } diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt index 9a3dc16..2d7a903 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt @@ -119,8 +119,8 @@ class EvaluationVisitor(root: Scope) : NodeVisitor { 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 { 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 { } 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 { } } + 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") } diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Evaluator.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Evaluator.kt index 15d60c4..4596b26 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Evaluator.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Evaluator.kt @@ -5,7 +5,7 @@ import gay.pizza.pork.frontend.World class Evaluator(val world: World, val scope: Scope) { private val contexts = mutableMapOf() - private val nativeFunctionProviders = mutableMapOf() + private val nativeProviders = mutableMapOf() 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 } } diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/FunctionContext.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/FunctionContext.kt index ba05df3..cf55229 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/FunctionContext.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/FunctionContext.kt @@ -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) { diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/InternalNativeProvider.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/InternalNativeProvider.kt new file mode 100644 index 0000000..a84750a --- /dev/null +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/InternalNativeProvider.kt @@ -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 + } +} diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/NativeFunctionProvider.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/NativeProvider.kt similarity index 74% rename from evaluator/src/main/kotlin/gay/pizza/pork/evaluator/NativeFunctionProvider.kt rename to evaluator/src/main/kotlin/gay/pizza/pork/evaluator/NativeProvider.kt index 4c385fb..df6e3e7 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/NativeFunctionProvider.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/NativeProvider.kt @@ -1,5 +1,5 @@ package gay.pizza.pork.evaluator -interface NativeFunctionProvider { +interface NativeProvider { fun provideNativeFunction(definition: String): CallableFunction } diff --git a/examples/fib.pork b/examples/fib.pork index 032793f..01c9516 100644 --- a/examples/fib.pork +++ b/examples/fib.pork @@ -1,17 +1,13 @@ /* fibonacci sequence */ func fib(n) { - if n == 0 { - 0 + if n < 2 { + n } else { - if n == 1 { - 1 - } else { - fib(n - 1) + fib(n - 2) - } + fib(n - 1) + fib(n - 2) } } export func main() { - let result = fib(20) + let result = fib(30) println(result) } diff --git a/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaAutogen.kt b/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaAutogen.kt index 4f27916..0a4c1c5 100644 --- a/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaAutogen.kt +++ b/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaAutogen.kt @@ -1,11 +1,6 @@ package gay.pizza.pork.ffi -import gay.pizza.pork.ast.CompilationUnit -import gay.pizza.pork.ast.DefinitionModifiers -import gay.pizza.pork.ast.FunctionDefinition -import gay.pizza.pork.ast.Native -import gay.pizza.pork.ast.StringLiteral -import gay.pizza.pork.ast.Symbol +import gay.pizza.pork.ast.* import java.lang.reflect.Method import java.lang.reflect.Modifier import java.lang.reflect.Parameter @@ -149,7 +144,12 @@ class JavaAutogen(val javaClass: Class<*>) { FunctionDefinition( modifiers = DefinitionModifiers(true), symbol = Symbol("${prefix}_${name}"), - arguments = parameterNames.map { Symbol(it) }, + arguments = parameterNames.map { + ArgumentSpec( + symbol = Symbol(it), + multiple = false + ) + }, native = asNative(functionDefinition), block = null ) diff --git a/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaNativeProvider.kt b/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaNativeProvider.kt index 27b77d7..b845570 100644 --- a/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaNativeProvider.kt +++ b/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaNativeProvider.kt @@ -1,12 +1,12 @@ package gay.pizza.pork.ffi import gay.pizza.pork.evaluator.CallableFunction -import gay.pizza.pork.evaluator.NativeFunctionProvider +import gay.pizza.pork.evaluator.NativeProvider import gay.pizza.pork.evaluator.None import java.lang.invoke.MethodHandles import java.lang.invoke.MethodType -class JavaNativeProvider : NativeFunctionProvider { +class JavaNativeProvider : NativeProvider { private val lookup = MethodHandles.lookup() override fun provideNativeFunction(definition: String): CallableFunction { diff --git a/ffi/src/main/kotlin/gay/pizza/pork/ffi/JnaNativeProvider.kt b/ffi/src/main/kotlin/gay/pizza/pork/ffi/JnaNativeProvider.kt index 63d9b3a..a9003b0 100644 --- a/ffi/src/main/kotlin/gay/pizza/pork/ffi/JnaNativeProvider.kt +++ b/ffi/src/main/kotlin/gay/pizza/pork/ffi/JnaNativeProvider.kt @@ -2,9 +2,9 @@ package gay.pizza.pork.ffi import com.sun.jna.Function import gay.pizza.pork.evaluator.CallableFunction -import gay.pizza.pork.evaluator.NativeFunctionProvider +import gay.pizza.pork.evaluator.NativeProvider -class JnaNativeProvider : NativeFunctionProvider { +class JnaNativeProvider : NativeProvider { override fun provideNativeFunction(definition: String): CallableFunction { val functionDefinition = FfiFunctionDefinition.parse(definition) val function = Function.getFunction(functionDefinition.library, functionDefinition.function) diff --git a/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt b/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt index 71da253..03006fe 100644 --- a/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt +++ b/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt @@ -217,7 +217,7 @@ class Parser(source: PeekableSource, val attribution: NodeAttribution) { private fun readImportDeclaration(): ImportDeclaration = within { expect(TokenType.Import) val form = readSymbolRaw() - val components = oneAndContinuedBy(TokenType.Period) { readSymbolRaw() } + val components = oneAndContinuedBy(TokenType.Dot) { readSymbolRaw() } ImportDeclaration(form, components) } @@ -237,7 +237,12 @@ class Parser(source: PeekableSource, val attribution: NodeAttribution) { val name = readSymbolRaw() expect(TokenType.LeftParentheses) val arguments = collect(TokenType.RightParentheses, TokenType.Comma) { - readSymbolRaw() + val symbol = readSymbolRaw() + var multiple: Boolean = false + if (next(TokenType.DotDotDot)) { + multiple = true + } + ArgumentSpec(symbol, multiple) } expect(TokenType.RightParentheses) diff --git a/parser/src/main/kotlin/gay/pizza/pork/parser/Printer.kt b/parser/src/main/kotlin/gay/pizza/pork/parser/Printer.kt index 31f9443..33c778d 100644 --- a/parser/src/main/kotlin/gay/pizza/pork/parser/Printer.kt +++ b/parser/src/main/kotlin/gay/pizza/pork/parser/Printer.kt @@ -155,7 +155,10 @@ class Printer(buffer: StringBuilder) : NodeVisitor { visit(node.symbol) append("(") for ((index, argument) in node.arguments.withIndex()) { - visit(argument) + visit(argument.symbol) + if (argument.multiple) { + append("...") + } if (index + 1 != node.arguments.size) { append(", ") } diff --git a/parser/src/main/kotlin/gay/pizza/pork/parser/TokenType.kt b/parser/src/main/kotlin/gay/pizza/pork/parser/TokenType.kt index 5ad74bb..c980ff7 100644 --- a/parser/src/main/kotlin/gay/pizza/pork/parser/TokenType.kt +++ b/parser/src/main/kotlin/gay/pizza/pork/parser/TokenType.kt @@ -30,23 +30,25 @@ enum class TokenType(vararg properties: TokenTypeProperty) { LeftParentheses(SingleChar('(')), RightParentheses(SingleChar(')')), Negation(SingleChar('!'), Promotion('=', Inequality), OperatorFamily), - Mod(Keyword("mod"), OperatorFamily), - Rem(Keyword("rem"), OperatorFamily), + Mod(ManyChars("mod"), OperatorFamily), + Rem(ManyChars("rem"), OperatorFamily), Comma(SingleChar(',')), - Period(SingleChar('.')), - False(Keyword("false"), KeywordFamily), - True(Keyword("true"), KeywordFamily), - If(Keyword("if"), KeywordFamily), - Else(Keyword("else"), KeywordFamily), - While(Keyword("while"), KeywordFamily), - Continue(Keyword("continue"), KeywordFamily), - Break(Keyword("break"), KeywordFamily), - Import(Keyword("import"), KeywordFamily), - Export(Keyword("export"), KeywordFamily), - Func(Keyword("func"), KeywordFamily), - Native(Keyword("native"), KeywordFamily), - Let(Keyword("let"), KeywordFamily), - Var(Keyword("var"), KeywordFamily), + DotDotDot(ManyChars("...")), + DotDot(ManyChars(".."), Promotion('.', DotDotDot)), + Dot(SingleChar('.'), Promotion('.', DotDot)), + False(ManyChars("false"), KeywordFamily), + True(ManyChars("true"), KeywordFamily), + If(ManyChars("if"), KeywordFamily), + Else(ManyChars("else"), KeywordFamily), + While(ManyChars("while"), KeywordFamily), + Continue(ManyChars("continue"), KeywordFamily), + Break(ManyChars("break"), KeywordFamily), + Import(ManyChars("import"), KeywordFamily), + Export(ManyChars("export"), KeywordFamily), + Func(ManyChars("func"), KeywordFamily), + Native(ManyChars("native"), KeywordFamily), + Let(ManyChars("let"), KeywordFamily), + Var(ManyChars("var"), KeywordFamily), Whitespace(CharConsumer { it == ' ' || it == '\r' || it == '\n' || it == '\t' }), BlockComment(CommentFamily), LineComment(CommentFamily), @@ -54,8 +56,8 @@ enum class TokenType(vararg properties: TokenTypeProperty) { val promotions: List = properties.filterIsInstance() - val keyword: Keyword? = - properties.filterIsInstance().singleOrNull() + val manyChars: ManyChars? = + properties.filterIsInstance().singleOrNull() val singleChar: SingleChar? = properties.filterIsInstance().singleOrNull() val family: TokenFamily = @@ -67,7 +69,7 @@ enum class TokenType(vararg properties: TokenTypeProperty) { properties.filterIsInstance().singleOrNull() companion object { - val Keywords = entries.filter { item -> item.keyword != null } + val ManyChars = entries.filter { item -> item.manyChars != null } val SingleChars = entries.filter { item -> item.singleChar != null } val CharConsumers = entries.filter { item -> item.charConsumer != null || item.charIndexConsumer != null } diff --git a/parser/src/main/kotlin/gay/pizza/pork/parser/TokenTypeProperty.kt b/parser/src/main/kotlin/gay/pizza/pork/parser/TokenTypeProperty.kt index a9c11b2..3ab799c 100644 --- a/parser/src/main/kotlin/gay/pizza/pork/parser/TokenTypeProperty.kt +++ b/parser/src/main/kotlin/gay/pizza/pork/parser/TokenTypeProperty.kt @@ -3,15 +3,15 @@ package gay.pizza.pork.parser interface TokenTypeProperty { class SingleChar(val char: Char) : TokenTypeProperty class Promotion(val nextChar: Char, val type: TokenType) : TokenTypeProperty - class Keyword(val text: String) : TokenTypeProperty + class ManyChars(val text: String) : TokenTypeProperty class CharConsumer(val isValid: (Char) -> Boolean) : TokenTypeProperty class CharIndexConsumer(val isValid: (Char, Int) -> Boolean) : TokenTypeProperty open class TokenUpgrader(val maybeUpgrade: (Token) -> Token?) : TokenTypeProperty object KeywordUpgrader : TokenUpgrader({ token -> var upgraded: Token? = null - for (item in TokenType.Keywords) { - if (item.keyword != null && token.text == item.keyword.text) { + for (item in TokenType.ManyChars) { + if (item.manyChars != null && token.text == item.manyChars.text) { upgraded = Token(item, token.start, token.text) break } diff --git a/parser/src/main/kotlin/gay/pizza/pork/parser/Tokenizer.kt b/parser/src/main/kotlin/gay/pizza/pork/parser/Tokenizer.kt index b4f3637..5ee25e3 100644 --- a/parser/src/main/kotlin/gay/pizza/pork/parser/Tokenizer.kt +++ b/parser/src/main/kotlin/gay/pizza/pork/parser/Tokenizer.kt @@ -79,13 +79,18 @@ class Tokenizer(val source: CharSource) { var type = item var text = itemChar.toString() - for (promotion in item.promotions) { - if (source.peek() != promotion.nextChar) { - continue + var promoted = true + while (promoted) { + promoted = false + for (promotion in type.promotions) { + if (source.peek() != promotion.nextChar) { + continue + } + val nextChar = source.next() + type = promotion.type + text += nextChar + promoted = true } - val nextChar = source.next() - type = promotion.type - text += nextChar } return Token(type, tokenStart, text) } diff --git a/stdlib/src/main/pork/lang/prelude.pork b/stdlib/src/main/pork/lang/prelude.pork new file mode 100644 index 0000000..bdaba4e --- /dev/null +++ b/stdlib/src/main/pork/lang/prelude.pork @@ -0,0 +1,2 @@ +export func println(messages...) + native internal "println" diff --git a/stdlib/src/main/pork/stdlib.manifest b/stdlib/src/main/pork/stdlib.manifest index cf63f4b..f673d07 100644 --- a/stdlib/src/main/pork/stdlib.manifest +++ b/stdlib/src/main/pork/stdlib.manifest @@ -1,2 +1,3 @@ +lang/prelude.pork ffi/malloc.pork numerics/operator.pork diff --git a/tool/src/main/kotlin/gay/pizza/pork/tool/RunCommand.kt b/tool/src/main/kotlin/gay/pizza/pork/tool/RunCommand.kt index bc0375d..5806388 100644 --- a/tool/src/main/kotlin/gay/pizza/pork/tool/RunCommand.kt +++ b/tool/src/main/kotlin/gay/pizza/pork/tool/RunCommand.kt @@ -19,21 +19,10 @@ class RunCommand : CliktCommand(help = "Run Program", name = "run") { override fun run() { val tool = FileTool(PlatformFsProvider.resolve(path)) val scope = Scope() - scope.define("println", CallableFunction { arguments -> - if (quiet) { - return@CallableFunction None - } - when (arguments.values.count()) { - 0 -> println() - 1 -> println(arguments.values[0]) - else -> println(arguments.values.joinToString(" ")) - } - None - }) - val main = tool.loadMainFunction(scope, setupEvaluator = { - addNativeFunctionProvider("ffi", JnaNativeProvider()) - addNativeFunctionProvider("java", JavaNativeProvider()) + addNativeProvider("internal", InternalNativeProvider(quiet = quiet)) + addNativeProvider("ffi", JnaNativeProvider()) + addNativeProvider("java", JavaNativeProvider()) }) if (dumpScope) { diff --git a/tool/src/main/kotlin/gay/pizza/pork/tool/Tool.kt b/tool/src/main/kotlin/gay/pizza/pork/tool/Tool.kt index b19a887..2407525 100644 --- a/tool/src/main/kotlin/gay/pizza/pork/tool/Tool.kt +++ b/tool/src/main/kotlin/gay/pizza/pork/tool/Tool.kt @@ -5,6 +5,7 @@ import gay.pizza.pork.ast.NodeVisitor import gay.pizza.pork.ast.visit import gay.pizza.pork.evaluator.CallableFunction import gay.pizza.pork.evaluator.Evaluator +import gay.pizza.pork.evaluator.InternalNativeProvider import gay.pizza.pork.evaluator.Scope import gay.pizza.pork.ffi.JavaAutogenContentSource import gay.pizza.pork.frontend.ContentSource