diff --git a/common/src/commonMain/kotlin/lang/temper/common/SplitLines.kt b/common/src/commonMain/kotlin/lang/temper/common/SplitLines.kt new file mode 100644 index 00000000..48d4cd03 --- /dev/null +++ b/common/src/commonMain/kotlin/lang/temper/common/SplitLines.kt @@ -0,0 +1,21 @@ +package lang.temper.common + +private val crlfOrLfPattern = Regex("""\r\n?|\n""") + +fun CharSequence.splitLinesPreservingTerminators(): List { + val matches = crlfOrLfPattern.findAll(this) + var pos = 0 + var listBuilder: MutableList? = null + for (match in matches) { + val lines = listBuilder ?: (mutableListOf().also { listBuilder = it }) + val endExclusive = match.range.last + 1 + lines.add(substring(pos, endExclusive)) + pos = endExclusive + } + return if (listBuilder == null) { + listOf(this.toString()) + } else { + listBuilder.add(substring(pos, length)) + listBuilder.toList() + } +} diff --git a/common/src/commonMain/kotlin/lang/temper/common/json/JsonNestedObjectBuilder.kt b/common/src/commonMain/kotlin/lang/temper/common/json/JsonNestedObjectBuilder.kt new file mode 100644 index 00000000..5bbbba1e --- /dev/null +++ b/common/src/commonMain/kotlin/lang/temper/common/json/JsonNestedObjectBuilder.kt @@ -0,0 +1,82 @@ +package lang.temper.common.json + +import lang.temper.common.structure.Hints +import kotlin.math.min + +class JsonNestedObjectBuilder { + private val chainsToLeaves = mutableListOf, JsonValue>>() + + fun property(propertyChain: List, value: JsonValue) { + chainsToLeaves.add(propertyChain to value) + } + + fun toJsonObject(): JsonObject { + // sort the property chains in lexicographic order + // Perhaps we have these once we're ordered: + // - ["a", "b"] + // - ["a", "c", "d"] + // - ["a", "c", "e"] + // - ["f", "g"] + // At depth 0, we can identify a run of "a" and a run of "f", + // so we know for one JsonObject, what it's properties are. + // Then at depth 1 for the "a" object, we have a run of one "b" and one "c". + // So simple linear search lets us build objects. + chainsToLeaves.sortWith { (a), (b) -> + lexicographicTupleComparison(a, b) + } + + fun build(range: IntRange, depth: Int): JsonObject = JsonObject( + buildList { + var i = range.first + val limit = range.last + while (i <= limit) { + val (chainI, valueI) = chainsToLeaves[i] + val propertyName = chainI.getOrNull(depth) + if (propertyName == null) { + i += 1 + continue + } + // Find the i.. Unit, +): JsonObject { + val builder = JsonNestedObjectBuilder() + builder.body() + return builder.toJsonObject() +} + +private fun lexicographicTupleComparison(a: List, b: List): Int { + val aSize = a.size + val bSize = b.size + val minSize = min(aSize, bSize) + for (i in 0...mergedNamingContext(mergedLoc: ModuleLocation): NamingContext { diff --git a/frontend/src/commonTest/kotlin/lang/temper/frontend/AssertModuleAtStage.kt b/frontend/src/commonTest/kotlin/lang/temper/frontend/AssertModuleAtStage.kt index 521676a5..e79aa0ca 100644 --- a/frontend/src/commonTest/kotlin/lang/temper/frontend/AssertModuleAtStage.kt +++ b/frontend/src/commonTest/kotlin/lang/temper/frontend/AssertModuleAtStage.kt @@ -1,23 +1,31 @@ package lang.temper.frontend import lang.temper.ast.TreeVisit +import lang.temper.common.Either import lang.temper.common.ListBackedLogSink import lang.temper.common.Log import lang.temper.common.OpenOrClosed +import lang.temper.common.RFailure +import lang.temper.common.RResult +import lang.temper.common.RSuccess import lang.temper.common.asciiUnTitleCase import lang.temper.common.assertStructure import lang.temper.common.buildListMultimap import lang.temper.common.console +import lang.temper.common.ignore import lang.temper.common.json.JsonObject +import lang.temper.common.json.JsonString import lang.temper.common.json.JsonValue import lang.temper.common.json.JsonValueBuilder +import lang.temper.common.json.buildJsonNestedObject import lang.temper.common.putMultiList +import lang.temper.common.splitLinesPreservingTerminators import lang.temper.common.structure.Hints import lang.temper.common.structure.PropertySink import lang.temper.common.structure.StructureHint import lang.temper.common.structure.StructureSink import lang.temper.common.structure.Structured -import lang.temper.common.testCodeLocation +import lang.temper.common.structure.reconcileStructure import lang.temper.common.testModuleName import lang.temper.common.toStringViaBuilder import lang.temper.env.Export @@ -25,20 +33,18 @@ import lang.temper.format.ValueSimplifyingLogSink import lang.temper.frontend.staging.ModuleAdvancer import lang.temper.frontend.staging.ModuleConfig import lang.temper.frontend.staging.ModuleCustomizeHook +import lang.temper.fs.Url import lang.temper.lexer.Genre -import lang.temper.lexer.LanguageConfig -import lang.temper.lexer.StandaloneLanguageConfig +import lang.temper.lexer.languageConfigForExtension import lang.temper.log.FilePath -import lang.temper.log.FilePathSegment +import lang.temper.log.FilePath.Companion.join import lang.temper.log.LogEntry import lang.temper.log.LogSink import lang.temper.log.MessageTemplate import lang.temper.log.MessageTemplateI -import lang.temper.log.ParentPseudoFilePathSegment import lang.temper.log.Position import lang.temper.log.Positioned -import lang.temper.log.SameDirPseudoFilePathSegment -import lang.temper.log.UNIX_FILE_SEGMENT_SEPARATOR +import lang.temper.log.filePath import lang.temper.name.BuiltinName import lang.temper.name.DashedIdentifier import lang.temper.name.ModuleName @@ -47,6 +53,9 @@ import lang.temper.name.ResolvedName import lang.temper.name.Symbol import lang.temper.name.TemperName import lang.temper.stage.Stage +import lang.temper.testdir.TestFileBundle +import lang.temper.testdir.readTestDir +import lang.temper.testdir.regenerateFiles import lang.temper.type.Abstractness import lang.temper.type.MethodKind import lang.temper.type.NominalType @@ -67,45 +76,48 @@ import lang.temper.value.Tree import lang.temper.value.Value import lang.temper.value.staticTypeContained import lang.temper.value.staySymbol +import kotlin.test.fail -/** See input parameter to [assertModuleAtStage] */ -const val TEST_INPUT_MODULE_BREAK = "////!module:" +/** + * A directory path relative to the directory containing `frontend/commonTest/.../README-stage-tests.md` + * that specifies test inputs and outputs. See that README file for details on the test structure. + * + * This string is also used to filter test-file regeneration. If [shouldRegenerateStageTest] returns `true` + * for it then [assertModuleAtStage] will write the expected outputs to output files instead of reading + * and comparing which allows using `git diff` to understand the consequences of a change to details of + * the frontend's intermediate representation. + */ +data class StageTestDir(val url: Url) { + init { + check(!url.isAbsolute && url.path != null && url.authority == null) { "$url" } + } + constructor(str: String) : this(Url.create(str)) +} + +private fun shouldRegenerateStageTest( + stageTestDir: StageTestDir, + isEmpty: Boolean, +): Boolean { + // ignore() to suppress unused parameter warnings because in git this should just return false. + ignore(stageTestDir) + ignore(isEmpty) + + return false +} + +/** The URL for reading test resource files. A `file:` URL which allows enumerating resources. */ +internal expect val stageTestDirFileRoot: Url + +/** The `file:` URL under which to write changes when regenerating test resource files. */ +internal expect val stageTestDirFileSourceRoot: Url /** * A test harness that advances a module until a specific stage, capturing snapshots of the * AST so that we can compare them selectively against a desired output. */ -fun assertModuleAtStage( - want: String = "", - /** - * The temper text that is parsed using [languageConfig]. - * - * If the string [TEST_INPUT_MODULE_BREAK] occurs in the text, then this input - * will be split up into multiple different modules which may import one another. - * - * This is useful for defining one main module to test, which is the first chunk, - * but having it import other files whose gory details do not show up in [want]. - * - * [TEST_INPUT_MODULE_BREAK] should be followed by a '/' separated path relative - * to [testCodeLocation]'s parent directory. - * That path will be used to derive the module name for the subsidiary modules. - * By directory-module convention, source files will be grouped by the containing - * directory. - * - * For example: - * - * ```temper inert - * let { foo } = import("./foo"); - * console.log("Main module code goes here"); - * console.log(foo); - * - * ////!module: ./foo/foo.temper - * export let foo = "FOO"; - * ``` - * - */ - input: String, - stage: Stage, +internal fun assertModuleAtStage( + stageTestDir: StageTestDir, + stage: Stage? = null, genre: Genre = Genre.Library, pseudoCodeDetail: PseudoCodeDetail = PseudoCodeDetail.default, manualCheck: ((JsonObject) -> Unit)? = null, @@ -114,76 +126,22 @@ fun assertModuleAtStage( loc: ModuleName? = null, stagingFlags: Set = emptySet(), stackTracesForErrors: Boolean = false, - languageConfig: LanguageConfig = StandaloneLanguageConfig, logEntryWanted: (LogEntry) -> Boolean = { it.level >= Log.Warn }, -) = assertModuleAtStage( - want = want, - stage = stage, - genre = genre, - pseudoCodeDetail = pseudoCodeDetail, - manualCheck = manualCheck, - nameSimplifying = nameSimplifying, - moduleResultNeeded = moduleResultNeeded, - loc = loc, - stagingFlags = stagingFlags, - stackTracesForErrors = stackTracesForErrors, - logEntryWanted = logEntryWanted, -) { module, moduleAdvancer -> - val chunks = buildList { - var path: FilePath = testCodeLocation - val contentBuilder = StringBuilder() - for (line in input.lines()) { - if (line.startsWith(TEST_INPUT_MODULE_BREAK)) { - add(path to "$contentBuilder") - contentBuilder.clear() - var pathStr = line.substring(TEST_INPUT_MODULE_BREAK.length) - var isDir = false - if (pathStr.endsWith(UNIX_FILE_SEGMENT_SEPARATOR)) { - isDir = true - pathStr = pathStr.dropLast(UNIX_FILE_SEGMENT_SEPARATOR.length) - } - val relPath = pathStr.trim().split(UNIX_FILE_SEGMENT_SEPARATOR).map { - when (it) { - "." -> SameDirPseudoFilePathSegment - ".." -> ParentPseudoFilePathSegment - else -> FilePathSegment(it) - } - } - path = testCodeLocation.resolvePseudo(relPath, isDir = isDir) ?: error(line) - } else { - contentBuilder.append(line).append('\n') - } - } - add(path to "$contentBuilder") - } - - val inputsByDir = buildListMultimap { - for ((path, content) in chunks) { - val dir = if (path.isDir) { - path - } else { - path.dirName() - } - putMultiList(dir, path to content) - } - } - - for ((dir, inputs) in inputsByDir) { - val moduleName = testModuleName.copy(sourceFile = dir) - val moduleToProvision = if (moduleName == testModuleName) { - module - } else { - moduleAdvancer.createModule(moduleName, module.console) - } - for ((filePath, content) in inputs) { - moduleToProvision.deliverContent( - ModuleSource( - filePath = filePath, - fetchedContent = content, - languageConfig = languageConfig, - ), - ) - } +) { + assertModuleAtStage( + stageTestDir = stageTestDir, + stage = stage, + genre = genre, + pseudoCodeDetail = pseudoCodeDetail, + manualCheck = manualCheck, + nameSimplifying = nameSimplifying, + moduleResultNeeded = moduleResultNeeded, + loc = loc, + stagingFlags = stagingFlags, + stackTracesForErrors = stackTracesForErrors, + logEntryWanted = logEntryWanted, + ) { module, moduleAdvancer, testDir -> + provisionModuleForStageTest(testDir, module, moduleAdvancer) } } @@ -191,9 +149,9 @@ fun assertModuleAtStage( * A test harness that advances a module until a specific stage, capturing snapshots of the * AST so that we can compare them selectively against a desired output. */ -fun assertModuleAtStage( - want: String = "", - stage: Stage, +internal fun assertModuleAtStage( + stageTestDir: StageTestDir, + stage: Stage? = null, genre: Genre = Genre.Library, pseudoCodeDetail: PseudoCodeDetail = PseudoCodeDetail.default, loc: ModuleName? = null, @@ -203,8 +161,10 @@ fun assertModuleAtStage( stagingFlags: Set = emptySet(), stackTracesForErrors: Boolean = false, logEntryWanted: (LogEntry) -> Boolean = { it.level >= Log.Warn }, - provisionModule: (Module, ModuleAdvancer) -> Unit, + provisionModule: (Module, ModuleAdvancer, TestFileBundle) -> Unit, ) { + val testDir = readTestDir(stageTestDirFileRoot.resolve(stageTestDir.url)) + var thousandsOfStepsLeft = 100 val continueCondition = { if (thousandsOfStepsLeft > 0) { @@ -215,6 +175,34 @@ fun assertModuleAtStage( } } + // Figure out which stage we need to advance to. + var stageNeeded = stage ?: Stage.Parse + // Inspect the expect/... data files to assemble a bundle of JSON to + // diff against the got bundle. + val wantJson = buildJsonNestedObject { + for ((relPath, content) in testDir.files) { + if (relPath.segments.firstOrNull()?.fullName != "expect") { + // Not relevant to expectations + continue + } + // The file relationship knows how to process the file into requirements in the + // "wanted" JSON bundle. + val rel = testResourceFileRelationships[relPath] + ?: fail("Unrecognized test data file `${stageTestDir.url}//$relPath`") + val relStage = rel.stage + if (stage == null && relStage != null && relStage > stageNeeded) { + stageNeeded = relStage + } + when (val jsonResult = rel.converter.fromFileContent(content)) { + is RFailure<*> -> throw IllegalArgumentException( + "Malformed test data file `${stageTestDir.url}//$relPath`", + jsonResult.failure, + ) + is RSuccess<*, *> -> property(rel.jsonProperties, jsonResult.result) + } + } + } + val outputsByStage = mutableMapOf() var exitKind: ExitKind = ExitKind.Normal var isTestModule: (Module) -> Boolean = { _ -> false } // reassigned @@ -222,23 +210,24 @@ fun assertModuleAtStage( if (isTestModule(module)) { val outputTree = module.treeForDebug?.copy(copyInferences = true) val stageDone = module.stageCompleted - outputsByStage[stageDone] = when (stageDone) { - Stage.Parse -> ParseStageSnapshot( - outputTree, - module.appendix, - pseudoCodeDetail, - exitKind, - ) + if (stageDone != Stage.Run) { // Run is handled at the end + outputsByStage[stageDone] = when (stageDone) { + Stage.Parse -> ParseStageSnapshot( + outputTree, + module.appendix, + pseudoCodeDetail, + exitKind, + ) - Stage.Run -> RunStageSnapshot(module.runResult, exitKind) - else -> TreeStageSnapshot( - outputTree, - outputTree?.typeDefinitions, - module.exports, - module.ok, - pseudoCodeDetail, - exitKind, - ) + else -> TreeStageSnapshot( + outputTree, + outputTree?.typeDefinitions, + module.exports, + module.ok, + pseudoCodeDetail, + exitKind, + ) + } } } } @@ -272,9 +261,9 @@ fun assertModuleAtStage( if (allStagingFlags.isNotEmpty()) { module.addEnvironmentBindings(allStagingFlags.associateWith { TBoolean.valueTrue }) } - provisionModule(module, moduleAdvancer) + provisionModule(module, moduleAdvancer, testDir) - val stopBeforeForMainModule = Stage.after(stage) + val stopBeforeForMainModule = Stage.after(stageNeeded) val stopBefore = { m: Module -> when { stopBeforeForMainModule == null -> null @@ -300,6 +289,10 @@ fun assertModuleAtStage( module.failLog.logReasonForFailure() } + if (stageNeeded >= Stage.Run) { + outputsByStage[Stage.Run] = RunStageSnapshot(module.runResult, exitKind) + } + val stdout = toStringViaBuilder { outputBuffer -> listBackedLogSink.allEntries.forEach { logEntry -> if (logEntry.template == MessageTemplate.StandardOut) { @@ -312,15 +305,15 @@ fun assertModuleAtStage( object : Structured { override fun destructure(structureSink: StructureSink) = structureSink.obj { val stageCompleted = module.stageCompleted - key("stageCompleted", isDefault = stageCompleted == stage) { + key("stageCompleted", isDefault = stageCompleted == stageNeeded) { value(stageCompleted) } val ok = module.ok - key("ok", isDefault = ok) { value(ok) } + key("ok", Hints.u) { value(ok) } for ((stageRun, parts) in outputsByStage) { key( (stageRun?.name ?: "nullStage").asciiUnTitleCase(), - if (stageRun != stage) { Hints.u } else { Hints.empty }, + if (stageRun != stageNeeded) { Hints.u } else { Hints.empty }, ) { this.value(parts) } @@ -334,14 +327,89 @@ fun assertModuleAtStage( ) if (manualCheck != null) { - val renumbered = PseudoCodeNameRenumberer.newStructurePostProcessor()(got) - manualCheck(JsonValueBuilder.build(emptyMap()) { value(renumbered) } as JsonObject) + val renumberer = PseudoCodeNameRenumberer.newStructurePostProcessor() + val gotRenumbered = renumberer(got) + manualCheck(JsonValueBuilder.build(emptyMap()) { value(gotRenumbered) } as JsonObject) } else { - assertStructure( - expectedJson = want, - input = got, - postProcessor = { s -> PseudoCodeNameRenumberer.newStructurePostProcessor()(s) }, - ) + var passed = false + val (wantReconciled, gotReconciled) = reconcileStructure(wantJson, got) + try { + assertStructure( + PseudoCodeNameRenumberer.newStructurePostProcessor()(wantReconciled), + PseudoCodeNameRenumberer.newStructurePostProcessor()(gotReconciled), + ) + passed = true + } finally { + if (!passed && shouldRegenerateStageTest(stageTestDir, isEmpty = testDir.isEmpty())) { + console.info("assertModuleAtStage is regenerating test files under ${stageTestDir.url}") + val regeneratedFiles = testDir.files.mapNotNull { (relPath) -> + val gotJson = run { + val b = JsonValueBuilder() + gotReconciled.destructure(b) + b.getRoot() + } + testResourceFileRelationships[relPath]?.let { rel -> + var value: JsonValue? = gotJson + for (prop in rel.jsonProperties) { + value = (value as? JsonObject)?.getOrNull(prop) + } + value?.let { + rel.converter.toFileContent(it).result?.let { content -> + Url(rel.relFilePath.join()) to Either.Left(content) + } + } + } + } + regenerateFiles( + stageTestDirFileSourceRoot.resolve("${stageTestDir.url}/"), + regeneratedFiles, + ) + } + } + } +} + +internal fun provisionModuleForStageTest( + testFileBundle: TestFileBundle, + module: Module, + moduleAdvancer: ModuleAdvancer, +) { + val chunks = buildList { + for ((relPath, content) in testFileBundle.files) { + if (relPath.segments.first().fullName == "work") { + add(relPath.copy(segments = relPath.segments.drop(1)) to content) + } + } + } + + val inputsByDir = buildListMultimap { + for ((path, content) in chunks) { + val dir = if (path.isDir) { + path + } else { + path.dirName() + } + putMultiList(dir, path to content) + } + } + + for ((dir, inputs) in inputsByDir) { + val moduleName = testModuleName.copy(sourceFile = dir) + val moduleToProvision = if (moduleName == testModuleName) { + module + } else { + moduleAdvancer.createModule(moduleName, module.console) + } + for ((filePath, content) in inputs) { + val languageConfig = languageConfigForExtension(filePath.segments.lastOrNull()?.extension) + moduleToProvision.deliverContent( + ModuleSource( + filePath = filePath, + fetchedContent = content, + languageConfig = languageConfig, + ), + ) + } } } @@ -736,3 +804,140 @@ internal class DumpStackTracesForThoseErrors(private val logSink: LogSink) : Log logSink.log(level, template, pos, values, fyi) } } + +/** Converts between test data file content and JSONValues in both directions. */ +private interface DataFileConverter { + fun fromFileContent(content: String): RResult + fun toFileContent(value: JsonValue): RResult +} + +private object FileContentStringConverter : DataFileConverter { + override fun fromFileContent(content: String): RResult { + var adjustedContent = content + // If the file contains ## lines, and the rest are indented, remove the ## comments. + val lines = content.splitLinesPreservingTerminators() + if ( + lines.any { it.startsWith("##") } && + lines.all { it.isBlank() || it.startsWith("##") || it.startsWith(" ") } + ) { + adjustedContent = lines.joinToString("") { + when { + it.startsWith(" ") -> it.drop(2) + it.startsWith("##") -> "" + else -> it + } + } + } + return RSuccess(JsonString(adjustedContent)) + } + + override fun toFileContent(value: JsonValue): RResult = + RResult.of(ClassCastException::class) { (value as JsonString).s } +} + +private object ParseJsonTolerantConverter : DataFileConverter { + override fun fromFileContent(content: String): RResult = + JsonValue.parse(content, tolerant = true) + + override fun toFileContent(value: JsonValue): RResult = + RSuccess(value.toJsonString(extensions = true)) +} + +private data class TestResourceFileRelationship( + val stage: Stage?, + val jsonProperties: List, + val relFilePath: FilePath, + val converter: DataFileConverter, +) + +private val testResourceFileRelationships: Map = + buildMap { + fun put(rel: TestResourceFileRelationship) { + this[rel.relFilePath] = rel + } + for (stage in Stage.entries) { + if (stage >= Stage.Parse && stage < Stage.Run) { + val stageLower = stage.name.asciiUnTitleCase() + + // AST forms + put( + TestResourceFileRelationship( + stage, + listOf(stageLower, "body", "code"), + filePath("expect", "$stageLower.temper"), + FileContentStringConverter, + ), + ) + put( + TestResourceFileRelationship( + stage, + listOf(stageLower, "body", "tree"), + filePath("expect", "$stageLower.lispy"), + ParseJsonTolerantConverter, + ), + ) + + // metadata + put( + TestResourceFileRelationship( + stage, + listOf(stageLower, "appendix"), + filePath("expect", "$stageLower-appendix.json"), + ParseJsonTolerantConverter, + ), + ) + put( + TestResourceFileRelationship( + stage, + listOf(stageLower, "types"), + filePath("expect", "$stageLower-types.json"), + ParseJsonTolerantConverter, + ), + ) + put( + TestResourceFileRelationship( + stage, + listOf(stageLower, "exports"), + filePath("expect", "$stageLower-exports.json"), + ParseJsonTolerantConverter, + ), + ) + } + } + + // Run stage outputs + put( + TestResourceFileRelationship( + Stage.Run, + listOf("run"), + filePath("expect", "run-result.json"), + ParseJsonTolerantConverter, + ), + ) + put( + TestResourceFileRelationship( + Stage.Run, + listOf("stdout"), + filePath("expect", "stdout.txt"), + FileContentStringConverter, + ), + ) + + // Overall outputs + put( + TestResourceFileRelationship( + null, + listOf("errors"), + filePath("expect", "errors.json"), + ParseJsonTolerantConverter, + ), + ) + put( + TestResourceFileRelationship( + null, + listOf("stageCompleted"), + filePath("expect", "stage-completed.json"), + ParseJsonTolerantConverter, + ), + ) + } diff --git a/frontend/src/commonTest/kotlin/lang/temper/frontend/DefineStageTest.kt b/frontend/src/commonTest/kotlin/lang/temper/frontend/DefineStageTest.kt index 4f66859e..a9c24200 100644 --- a/frontend/src/commonTest/kotlin/lang/temper/frontend/DefineStageTest.kt +++ b/frontend/src/commonTest/kotlin/lang/temper/frontend/DefineStageTest.kt @@ -6,10 +6,8 @@ import lang.temper.builtin.BuiltinFuns import lang.temper.common.ListBackedLogSink import lang.temper.common.Log import lang.temper.common.assertStructure -import lang.temper.common.stripDoubleHashCommentLinesToPutCommentsInlineBelow import lang.temper.common.structure.StructureSink import lang.temper.common.structure.Structured -import lang.temper.common.testCodeLocation import lang.temper.common.withCapturingConsole import lang.temper.env.InterpMode import lang.temper.frontend.staging.ModuleAdvancer @@ -21,7 +19,6 @@ import lang.temper.log.filePath import lang.temper.name.BuiltinName import lang.temper.name.DashedIdentifier import lang.temper.name.ModuleName -import lang.temper.stage.Stage import lang.temper.type2.Signature2 import lang.temper.value.BuiltinStatelessMacroValue import lang.temper.value.Document @@ -30,7 +27,6 @@ import lang.temper.value.NamedBuiltinFun import lang.temper.value.NotYet import lang.temper.value.PartialResult import lang.temper.value.PseudoCodeDetail -import lang.temper.value.TBoolean import lang.temper.value.TInt import lang.temper.value.Value import lang.temper.value.unholeBuiltinName @@ -41,21 +37,8 @@ import kotlin.test.assertFalse class DefineStageTest { @Test fun callToMethod() = assertModuleAtStage( - stage = Stage.Define, + stageTestDir = StageTestDir("define/call-to-method"), stagingFlags = setOf(StagingFlags.skipImportCore), - input = """ - |subject.verb(arg) - """.trimMargin(), - want = """ - |{ - | define: { - | body: ``` - | do_call_verb(subject, arg) - | - | ```, - | } - |} - """.trimMargin(), ) /** @@ -64,1241 +47,110 @@ class DefineStageTest { */ @Test fun dotOperationDesugaring() = assertModuleAtStage( - stage = Stage.Define, - input = """ - interface I { - next; - } - class C(private i = 0) extends I { - public f() { i } - public get next() { return f() + 1 } - private set next(newVal) { this.i = newVal - 1 } - } - let c = new C(); - console.log(c.i, c.x, c.x, c.f()); - c.next = 42 - """, + stageTestDir = StageTestDir("define/dot-operation-desugaring"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - { - define: { - body: - ``` - let console#0; - console#0 = doPure(@stay fn: Console { - getConsole() - }); - I__0 extends AnyValue; - @property(\next) @stay @fromType(I__0) let next__7; - @typeDecl(I__0) @stay let I__0; - I__0 = type (I__0); - @typeDecl(C__1) @stay let C__1; - C__1 = type (C__1); - interface(\word, \I, \concrete, false, @typeDefined(I__0) fn { - do {}; - do {} - }); - C__1 extends I__0; - @constructorProperty @property(\i) @visibility(\private) @stay @fromType(C__1) let i__9; - @method(\f) @visibility(\public) @fn @stay @fromType(C__1) let f__10; - f__10 = fn f(@impliedThis(C__1) this__2: C__1) { - fn__11: do { - getp(i__9, this__2) - } - }; - @property(\next) @visibility(\public) @stay @fromType(C__1) let next__12; - @method(\next) @getter @visibility(\public) @fn @stay @fromType(C__1) let nym`get.next__13`; - nym`get.next__13` = fn nym`get.next`(@impliedThis(C__1) this__3: C__1) /* return__14 */{ - fn__15: do { - do { - return__14 = do_icall_f(type (C__1), this__3) + 1; - break(\label, fn__15) - } - } - }; - @method(\next) @setter @visibility(\private) @fn @stay @fromType(C__1) let nym`set.next__16`; - nym`set.next__16` = fn nym`set.next`(@impliedThis(C__1) this__4: C__1, newVal__17 /* aka newVal */) /* return__1 */: Void { - fn__18: do { - do { - let t#0; - setp(i__9, this__4, t#0 = newVal__17 - 1); - t#0 - } - } - }; - @fn @method(\constructor) @visibility(\public) @stay @fromType(C__1) let constructor__19; - constructor__19 = fn constructor(@impliedThis(C__1) this__20: C__1, @optional(true) i__1 /* aka i */) /* return__2 */: Void { - let i__21 /* aka i */; - i__21 = if(isNull(i__1), fn { - 0 - }, \else, fn (f#0) { - f#0(fn { - i__1 - }) - }); - void; - do { - let t#1; - setp(i__9, this__20, t#1 = i__21); - t#1 - }; - }; - class(\word, \C, \concrete, true, @typeDefined(C__1) fn { - do {}; - do {}; - do {}; - do {}; - do {}; - do {}; - do {} - }); - let c__22; - c__22 = new C__1(); - do_call_log(console#0, do_get_i(c__22), do_get_x(c__22), do_get_x(c__22), do_call_f(c__22)); - do { - do_set_next(c__22, 42); - 42 - } - - ```, - types: { - "AnyValue": { abstract: true }, - "C": { - supers: ["I__0"], - properties: [ - { - name: "next__12", - abstract: true, - getter: "get.next__13", - setter: "set.next__16", - visibility: "public" - }, - { name: "i__9", abstract: false, visibility: "private" }, - ], - methods: [ - { name: "get.next__13", - symbol: "next", open: false, visibility: "public", kind: "Getter" }, - { name: "set.next__16", - symbol: "next", open: false, visibility: "private", kind: "Setter" }, - { name: "f__10", open: false, visibility: "public" }, - { name: "constructor__19", - open: false, visibility: "public", kind: "Constructor" }, - ] - }, - "I": { - abstract: true, - supers: ["AnyValue__0"], - properties: [ - { name: "next__7", abstract: true, visibility: "public" } - ], - }, - "Void": { supers: [] }, - "Console": "__DO_NOT_CARE__", - } - } - } - """, ) @Test fun charTag() = assertModuleAtStage( - stage = Stage.Define, - input = """ - |char'-' - """.trimMargin(), - want = """ - |{ - | import: { - | body: ``` - | stringExpr(char, true, "-") - | - | ```, - | }, - | define: { - | body: ``` - | 45 - | - | ```, - | }, - |} - """.trimMargin(), + stageTestDir = StageTestDir("define/char-tag"), moduleResultNeeded = true, ) @Test fun internalVersusExternalBackedPropertyAccess() = assertModuleAtStage( - stage = Stage.Define, - input = """ - class C(private i) { - private f() { i = 1 } - } - (new C()).i = 2 - """, + stageTestDir = StageTestDir("define/internal-versus-external-backed-property-access"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - { - define: { - body: - ``` - C__0 extends AnyValue; - @constructorProperty @property(\i) @visibility(\private) @stay @fromType(C__0) let i__4; - @method(\f) @visibility(\private) @fn @stay @fromType(C__0) let f__5; - f__5 = fn f(@impliedThis(C__0) this__1: C__0) { - fn__6: do { - do { - setp(i__4, this__1, 1); - 1 - } - } - }; - @fn @method(\constructor) @visibility(\public) @stay @fromType(C__0) let constructor__7; - constructor__7 = fn constructor(@impliedThis(C__0) this__8: C__0, i__9 /* aka i */) /* return__0 */: Void { - do { - let t#0; - setp(i__4, this__8, t#0 = i__9); - t#0 - }; - }; - @typeDecl(C__0) @stay let C__0; - C__0 = type (C__0); - class(\word, \C, \concrete, true, @typeDefined(C__0) fn { - do {}; - do {}; - do {}; - do {} - }); - do { - do_set_i(new C__0(), 2); - 2 - } - - ```, - types: { - "AnyValue": { abstract: true }, - "C": { - supers: ["AnyValue__0"], - properties: [ - { name: "i__4", abstract: false, visibility: "private" }, - ], - methods: [ - { name: "f__5", open: false, visibility: "private" }, - { name: "constructor__7", - open: false, visibility: "public", kind: "Constructor" }, - ] - }, - "Void": { supers: [] }, - } - } - } - """, ) @Test fun constantFolding() = assertModuleAtStage( - stage = Stage.Define, - input = "1 + 1", + stageTestDir = StageTestDir("define/constant-folding"), stagingFlags = setOf(StagingFlags.skipImportCore), - want = """ - { - define: { - body: [ "Block", [ [ "Value", "2: Int32" ] ] ] - } - } - """, ) @Test fun constantFoldingViaConstExpression() = assertModuleAtStage( - stage = Stage.Define, - input = "let one = 1; one + one", + stageTestDir = StageTestDir("define/constant-folding-via-const-expression"), moduleResultNeeded = true, - want = """ - { - syntaxMacro: { - // Before define stage, one is not a resolved name, so we are cautious about - // inlining referents. - body: - ``` - let one__0 = 1; - one__0 + one__0 - - ``` - }, - define: { - body: { - code: - ``` - let one__0; - one__0 = 1; - 2 - - ```, - tree: - [ "Block", [ - [ "Decl", [ - [ "LeftName", "one__0" ], - [ "Value", "\\QName: Symbol" ], - [ "Value", "\"test-code.one\": String" ], - [ "Value", "\\ssa: Symbol" ], - [ "Value", "void: Void" ] - ] - ], - [ "Call", [ - [ "Value", "nym`=`: Function" ], - [ "LeftName", "one__0" ], - [ "Value", "1: Int32" ] - ] - ], - [ "Value", "2: Int32" ] - ] - ] - } - } - } - """, ) @Test fun nonConstReferentNotFoldedIntoConstExpression() = assertModuleAtStage( - stage = Stage.Define, - input = """ - var one = 1; - if (falseOpaquePredicate) { - one = 0; - } - one + one - """.trimIndent(), + stageTestDir = StageTestDir("define/non-const-referent-not-folded-into-const-expression"), moduleResultNeeded = true, - want = """ - { - syntaxMacro: { - body: - ``` - var one__0 = 1; - if(falseOpaquePredicate, fn { - one__0 = 0; - }); - one__0 + one__0 - - ``` - }, - define: { - body: - ``` - var one__0; - one__0 = 1; - if(falseOpaquePredicate, fn { - one__0 = 0; - }); - one__0 + one__0 - - ```, - } - } - """, ) @Test fun userDefinedPureFunctionsInlined() = assertModuleAtStage( - stage = Stage.Define, - input = """ - let adj = 6; - let factorMinusAdj(x: Int, y: Int): Int { x * y - adj } - factorMinusAdj(6, 8) - """.trimIndent(), + stageTestDir = StageTestDir("define/user-defined-pure-functions-inlined"), moduleResultNeeded = true, - want = """ - { - define: { - body: - ``` - @fn let factorMinusAdj__1, adj__0; - adj__0 = 6; - factorMinusAdj__1 = (@stay fn factorMinusAdj(x__2 /* aka x */: Int32, y__3 /* aka y */: Int32)${ - "" - } /* return__0 */: Int32 { - fn__4: do { - x__2 * y__3 - 6 - } - }); - 42 - - ``` - } - } - """, ) // Test that type definition values get inlined. @Test fun typeAliasing() = assertModuleAtStage( - stage = Stage.Define, - input = """ - class C {} - let alias = C; // Reified types via aliases should be inlined. - let o: C; - let p: alias; - """.trimIndent(), - want = """ - { - syntaxMacro: { - body: - [ "Block", [ - [ "Decl", [ - ["LeftName", "C__0"], - ["Value", "\\init: Symbol"], - ["Value", "C__0: Type"], - ["Value", "\\typeDecl: Symbol"], - ["Value", "C__0: Type"], - ["Value", "\\stay: Symbol"], - ["Stay", "kotlin.Unit"], - ["Value", "\\QName: Symbol"], - ["Value", "\"test-code.type C\": String"], - ] - ], - ["Call", [ - ["RightName", "class"], - ["Value", "\\word: Symbol"], ["Value", "\\C: Symbol"], - ["Value", "\\concrete: Symbol"], ["Value", "true: Boolean"], - ["Fun", [ - ["Value", "\\typeDefined: Symbol"], ["Value", "C__0: Type"], - ["Block", [ - ["Call", [ - [ "Value", "extends: Function" ], - [ "Value", "C__0: Type" ], - [ "Value", "AnyValue: Type" ], - ] - ], - ["Decl", [ - ["LeftName", "constructor__3"], - ["Value", "\\init: Symbol"], - ["Fun", [ - ["Decl", [ - ["LeftName", "this__4"], - ["Value", "\\type: Symbol"], - ["Value", "C__0: Type"], - ["Value", "\\impliedThis: Symbol"], - ["Value", "C__0: Type"], - ["Value", "\\QName: Symbol"], - ["Value", "\"test-code.type C.constructor().(this)\": String"], - ] - ], - ["Value", "\\word: Symbol"], - ["Value", "\\constructor: Symbol"], - ["Value", "\\returnDecl: Symbol"], - ["Decl", [ - ["LeftName", "return__0"], - ["Value", "\\type: Symbol"], - ["Value", "Void: Type"], - ["Value", "\\QName: Symbol"], - ["Value", "\"test-code.type C.constructor().return=\": String"], - ] - ], - ["Value", "\\QName: Symbol"], - ["Value", "\"test-code.type C.constructor()\": String"], - ["Block", [ - ] - ], - ] - ], - ["Value", "\\method: Symbol"], - ["Value", "\\constructor: Symbol"], - ["Value", "\\visibility: Symbol"], - ["Value", "\\public: Symbol"], - ["Value", "\\QName: Symbol"], - ["Value", "\"test-code.type C.constructor()\": String"], - ] - ] - ] - ] - ] - ] - ] - ], - [ "Decl", [ - ["LeftName", "alias__5"], - ["Value", "\\init: Symbol"], ["RightName", "C__0"], - ["Value", "\\QName: Symbol"], - ["Value", "\"test-code.alias\": String"], - ] - ], - [ "Call", [ - [ "Value", "REM: Function" ], - [ "Value", "\"Reified types via aliases should be inlined.\": String" ], - [ "Value", "null: Null" ], - [ "Value", "false: Boolean" ], - ] - ], - [ "Decl", [ - ["LeftName", "o__6"], - ["Value", "\\type: Symbol"], ["RightName", "C__0"], - ["Value", "\\QName: Symbol"], - ["Value", "\"test-code.o\": String"], - ] - ], - [ "Decl", [ - ["LeftName", "p__7"], - ["Value", "\\type: Symbol"], ["RightName", "alias__5"], - ["Value", "\\QName: Symbol"], - ["Value", "\"test-code.p\": String"], - ] - ], - [ "Value", "void: Void" ], - ] - ], - types: { - "AnyValue": { abstract: true }, - "C": { - methods: [ - { name: "constructor", visibility: "public", open: false, kind: "Constructor" } - ], - supers: [ "AnyValue__0" ] - }, - "Void": { supers: [] }, - } - }, - define: { - body: - [ "Block", [ - ["Call", [ - ["Value", "extends: Function"], - ["Value", "C__0: Type"], - ["Value", "AnyValue: Type"], - ] - ], - ["Decl", [ - ["LeftName", "constructor__3"], - ["Value", "\\fn: Symbol"], - ["Value", "void: Void"], - ["Value", "\\method: Symbol"], - ["Value", "\\constructor: Symbol"], - ["Value", "\\visibility: Symbol"], - ["Value", "\\public: Symbol"], - ["Value", "\\QName: Symbol"], - ["Value", "\"test-code.type C.constructor()\": String"], - ["Value", "\\ssa: Symbol"], - ["Value", "void: Void"], - ["Value", "\\stay: Symbol"], - ["Stay"], - ["Value", "\\parameterNameSymbolsList: Symbol"], - ["Value", "[null]: List"], - ["Value", "\\fromType: Symbol"], - ["Value", "C__0: Type"], - ] - ], - [ "Call", [ - ["Value", "nym`=`: Function"], - ["LeftName", "constructor__3"], - ["Fun", [ - ["Decl", [ - ["LeftName", "this__4"], - ["Value", "\\type: Symbol"], - ["Value", "C__0: Type"], - ["Value", "\\impliedThis: Symbol"], - ["Value", "C__0: Type"], - ["Value", "\\QName: Symbol"], - ["Value", "\"test-code.type C.constructor().(this)\": String"], - ] - ], - ["Value", "\\word: Symbol"], - ["Value", "\\constructor: Symbol"], - ["Value", "\\returnDecl: Symbol"], - ["Decl", [ - ["LeftName", "return__0"], - ["Value", "\\type: Symbol"], - ["Value", "Void: Type"], - ["Value", "\\QName: Symbol"], - ["Value", "\"test-code.type C.constructor().return=\": String"], - ["Value", "\\ssa: Symbol"], - ["Value", "void: Void"], - ] - ], - ["Value", "\\QName: Symbol"], - ["Value", "\"test-code.type C.constructor()\": String"], - ["Value", "\\stay: Symbol"], ["Stay"], - ["Block", [ - ] - ], - ] - ], - ] - ], - [ "Decl", [ - ["LeftName", "C__0"], - [ "Value", "\\typeDecl: Symbol" ], - [ "Value", "C__0: Type" ], - [ "Value", "\\stay: Symbol" ], - [ "Stay", "kotlin.Unit" ], - [ "Value", "\\QName: Symbol" ], - [ "Value", "\"test-code.type C\": String" ], - [ "Value", "\\ssa: Symbol" ], - [ "Value", "void: Void" ], - ] - ], - [ "Call", [ - ["Value", "nym`=`: Function"], - ["LeftName", "C__0"], - ["Value", "C__0: Type"] - ] - ], - ["Call", [ - ["Value", "class: Function"], - ["Value", "\\word: Symbol"], ["Value", "\\C: Symbol"], - ["Value", "\\concrete: Symbol"], ["Value", "true: Boolean"], - ["Fun", [ - ["Value", "\\typeDefined: Symbol"], ["Value", "C__0: Type"], - ["Block", [ - ["Block", []], - ["Block", []], - ] - ] - ] - ], - ] - ], - [ "Decl", [ - [ "LeftName", "alias__5" ], - [ "Value", "\\QName: Symbol" ], - [ "Value", "\"test-code.alias\": String" ], - [ "Value", "\\ssa: Symbol" ], - [ "Value", "void: Void" ] - ] - ], - [ "Call", [ - [ "Value", "nym`=`: Function" ], - [ "LeftName", "alias__5"], - [ "Value", "C__0: Type" ], - ] - ], - [ "Value", "void: Void" ], - [ "Decl", [ - [ "LeftName", "o__6" ], - [ "Value", "\\type: Symbol" ], - [ "Value", "C__0: Type" ], // Type has been inlined - [ "Value", "\\QName: Symbol" ], - [ "Value", "\"test-code.o\": String" ], - [ "Value", "\\ssa: Symbol" ], - [ "Value", "void: Void" ] - ] - ], - [ "Decl", [ - [ "LeftName", "p__7" ], - [ "Value", "\\type: Symbol" ], - [ "Value", "C__0: Type" ], // Type has been inlined - [ "Value", "\\QName: Symbol" ], - [ "Value", "\"test-code.p\": String" ], - [ "Value", "\\ssa: Symbol" ], - [ "Value", "void: Void" ] - ] - ], - ["Value", "void: Void"], - ] - ], - types: { - "AnyValue": { abstract: true }, - "C": { - methods: [ - { name: "constructor__3", visibility: "public", open: false, kind: "Constructor" } - ], - supers: [ "AnyValue__0" ], - }, - "Void": { supers: [] }, - } - }, - } - """, + stageTestDir = StageTestDir("define/type-aliasing"), ) @Test fun inheritedReassignability() = assertModuleAtStage( - stage = Stage.Define, - input = """ - |interface I { - | var m; - | p; - |} - |interface J { - | set n() {} - |} - |interface K extends I, J { - | m; n; o; - | p; q; - | set o() {} - |} - """.trimMargin(), + stageTestDir = StageTestDir("define/inherited-reassignability"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - { - define: { - body: - ``` - I__0 extends AnyValue; - @property(\m) @stay @fromType(I__0) var m__7; - @property(\p) @stay @fromType(I__0) let p__8; - @typeDecl(I__0) @stay let I__0; - I__0 = type (I__0); - @typeDecl(J__1) @stay let J__1; - J__1 = type (J__1); - @typeDecl(K__2) @stay let K__2; - K__2 = type (K__2); - interface(\word, \I, \concrete, false, @typeDefined(I__0) fn { - do {}; - do {}; - do {} - }); - J__1 extends AnyValue; - @property(\n) @visibility(\public) @stay @fromType(J__1) let n__10; - @method(\n) @setter @fn @stay @fromType(J__1) let nym`set.n__11`; - nym`set.n__11` = (@stay fn nym`set.n`(@impliedThis(J__1) this__3: J__1) /* return__0 */: Void { - fn__12: do {} - }); - interface(\word, \J, \concrete, false, @typeDefined(J__1) fn { - do {}; - do {}; - do {} - }); - K__2 extends I__0; - K__2 extends J__1; - @property(\m) @stay @fromType(K__2) var m__14; - @property(\n) @stay @fromType(K__2) var n__15; - @property(\o) @stay @fromType(K__2) var o__16; - @property(\p) @stay @fromType(K__2) let p__17; - @property(\q) @stay @fromType(K__2) let q__18; - @method(\o) @setter @fn @stay @fromType(K__2) let nym`set.o__19`; - nym`set.o__19` = (@stay fn nym`set.o`(@impliedThis(K__2) this__4: K__2) /* return__1 */: Void { - fn__20: do {} - }); - interface(\word, \K, \concrete, false, @typeDefined(K__2) fn { - do {}; - do {}; - do {}; - do {}; - do {}; - do {}; - do {}; - do {} - }); - type (K__2) - - ``` - } - } - """, ) @Test fun functionalInterfaceAbbreviatedSyntax() = assertModuleAtStage( - stage = Stage.Define, - input = """ - |export @fun interface MyFunction(x: Int): Boolean; - """.trimMargin(), - want = """ - |{ - | define: { - | body: - | ``` - | @typeDecl(MyFunction) @stay @functionalInterface let `test//`.MyFunction; - | `test//`.MyFunction = type (MyFunction); - | do {}; - | MyFunction extends AnyValue; - | @fn @stay @fromType(MyFunction) let apply__0; - |## No `this` parameter on functional interface apply methods. - | apply__0 = fn apply(x__0 /* aka x */: Int32) /* return__0 */: Boolean { - | fn__0: do { - | pureVirtual() - | } - | }; - | interface(\word, \MyFunction, void, void, void, \concrete, false, @typeDefined(MyFunction) fn { - | do {}; - | do {} - | }); - | - | ``` - | } - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), + stageTestDir = StageTestDir("define/functional-interface-abbreviated-syntax"), ) @Test fun functionalInterfaceGeneric() = assertModuleAtStage( - stage = Stage.Define, - input = """ - |export @fun interface MyFunction(x: T, y: U): Boolean; - """.trimMargin(), - want = """ - |{ - | define: { - | body: - | ``` - | @typeDecl(MyFunction) @stay @functionalInterface let `test//`.MyFunction; - | `test//`.MyFunction = type (MyFunction); - | do {}; - | @typeFormal(\T) @typeDefined(T__0) @fromType(MyFunction) let T__0; - | T__0 = type (T__0); - | @typeFormal(\U) @typeDefined(U__0) @fromType(MyFunction) let U__0; - | U__0 = type (U__0); - | MyFunction extends AnyValue; - | @fn @stay @fromType(MyFunction) let apply__0; - | apply__0 = fn apply(x__0 /* aka x */: T__0, y__0 /* aka y */: U__0) /* return__0 */: Boolean { - | fn__0: do { - | pureVirtual() - | } - | }; - | interface(\word, \MyFunction, void, void, void, void, \concrete, false, @typeDefined(MyFunction) fn { - | do {}; - | do {}; - | do {}; - | do {} - | }); - | - | ``` - | } - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), + stageTestDir = StageTestDir("define/functional-interface-generic"), ) @Test fun coalesce() = assertModuleAtStage( - stage = Stage.Define, - input = """ - |export let prod(i: Int, j: Int?): Int { i * (j ?? 1) } - |export let prodWrap(i: Int, j: List): Int { i * (j[0] ?? 1) } - """.trimMargin(), - want = """ - |{ - | define: { - | body: - | ``` - | @fn let `test//`.prod, @fn `test//`.prodWrap; - | `test//`.prod = (@stay fn prod(i__0 /* aka i */: Int32, j__0 /* aka j */: Int32?) /* return__0 */: Int32 { - | fn__0: do { - | i__0 * { - | if (isNull(j__0)) { - | 1 - | } else { - | j__0 - | } - | } - | } - | }); - | `test//`.prodWrap = (@stay fn prodWrap(i__1 /* aka i */: Int32, j__1 /* aka j */: List) /* return__1 */: Int32 { - | fn__1: do { - | i__1 * do { - | let subject#0; - | subject#0 = do_call_get(j__1, 0); - | { - | if (isNull(subject#0)) { - | 1 - | } else { - | subject#0 - | } - | } - | } - | } - | }); - | - | ``` - | }, - |} - """.trimMargin(), + stageTestDir = StageTestDir("define/coalesce"), ) @Test fun optionalParametersNotInlined() = assertModuleAtStage( - stage = Stage.Run, - input = $$""" - let f(i: Int = 42): Int { i }; - console.log("f( )=${f().toString()}"); - console.log("f(1)=${f(1).toString()}"); - """.trimIndent(), - want = """{ - define: { - body: - ``` - let console#0; - console#0 = doPure(@stay fn: Console { - getConsole() - }); - @fn let f__0; - f__0 = (@stay fn f(@optional(true) i__0 /* aka i */: Int32?) /* return__0 */: Int32 { - fn__0: do { - let i__1 /* aka i */: Int32; - i__1 = if(isNull(i__0), fn { - 42 - }, \else, fn (f#0) { - f#0(fn { - i__0 - }) - }); - void; - i__1 - } - }); - do_call_log(console#0, cat("f( )=", str(do_call_toString(42)))); - do_call_log(console#0, cat("f(1)=", str(do_call_toString(1)))); - - ``` - }, - stdout: "f( )=42\nf(1)=1\n", - run: "void: Void" - } - """, + stageTestDir = StageTestDir("define/optional-parameters-not-inlined"), ) @Test fun conditionallyAssignedConstNotInlined() = assertModuleAtStage( - stage = Stage.Run, - input = $$""" - let f(b: Boolean): Int { - let i: Int; - if (b) { i = -1 } else { i = 1 } - i - }; - console.log("f(true )=${f(true)}"); - console.log("f(false)=${f(false)}"); - """.trimIndent(), - want = """{ - define: { - body: - ``` - let console#0; - console#0 = doPure(@stay fn: Console { - getConsole() - }); - @fn let f__1; - f__1 = fn f(b__2 /* aka b */: Boolean) /* return__0 */: Int32 { - fn__3: do { - let i__4: Int32; - if(b__2, fn { - i__4 = -1 - }, \else, fn (f#0) { - f#0(fn { - i__4 = 1 - }) - }); - i__4 - } - }; - do_call_log(console#0, cat("f(true )=", str(f__1(true)))); - do_call_log(console#0, cat("f(false)=", str(f__1(false)))); - - ``` - }, - stdout: "f(true )=-1\nf(false)=1\n", - run: "void: Void" - } - """, + stageTestDir = StageTestDir("define/conditionally-assigned-const-not-inlined"), ) @Test fun classesWithDisclosures() = assertModuleAtStage( - stage = Stage.Define, - input = """ - |let f(x) { - | class ClosesOverNothing {} - | - | interface ClosesOverX { - | get p() { x } - | } - | - | do { - | let y = x + 1; - | - | class ClosesOverY extends ClosesOverX { - | public get q() { y } - | } - | new ClosesOverY() - | } - | - | new ClosesOverNothing(); - |} - """.trimMargin(), + stageTestDir = StageTestDir("define/classes-with-disclosures"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - { - define: { - body: - ``` - @fn let f__6; - ClosesOverNothing__0 extends AnyValue; - @fn @method(\constructor) @visibility(\public) @stay @fromType(ClosesOverNothing__0) let constructor__10; - constructor__10 = (@stay fn constructor(@impliedThis(ClosesOverNothing__0) this__11: ClosesOverNothing__0) /* return__0 */: Void {}); - ClosesOverX__1 extends AnyValue; - @property(\p) @visibility(\public) @stay @fromType(ClosesOverX__1) let p__13; - @method(\p) @getter @fn @stay @fromType(ClosesOverX__1) let nym`get.p__14`; - nym`get.p__14` = fn nym`get.p`(@impliedThis(ClosesOverX__1) this__3: ClosesOverX__1) { - fn__15: do { - getCR(getp(cr__23, this__3), 0) - } - }; - @property(\cr__23) @visibility(\protected) @stay @synthetic @fromType(ClosesOverX__1) let cr__23: ClosRec; - ClosesOverY__2 extends ClosesOverX__1; - @property(\q) @visibility(\public) @stay @fromType(ClosesOverY__2) let q__18; - @method(\q) @getter @visibility(\public) @fn @stay @fromType(ClosesOverY__2) let nym`get.q__19`; - nym`get.q__19` = fn nym`get.q`(@impliedThis(ClosesOverY__2) this__4: ClosesOverY__2) { - fn__20: do { - getCR(getp(cr__24, this__4), 0) - } - }; - @fn @method(\constructor) @visibility(\public) @stay @fromType(ClosesOverY__2) let constructor__21; - constructor__21 = (@stay fn constructor(@impliedThis(ClosesOverY__2) this__22: ClosesOverY__2, cr__25: ClosRec, cr__26: ClosRec) /* return__1 */: Void { - setp(cr__27, this__22, cr__25); - setp(cr__24, this__22, cr__26) - }); - @property(\cr__27) @visibility(\private) @stay @synthetic @fromType(ClosesOverY__2) let cr__27: ClosRec; - @property(\cr__23) @visibility(\private) @stay @synthetic @fromType(ClosesOverY__2) let cr__28: ClosRec; - @method(\cr__23) @getter @visibility(\protected) @stay @synthetic @fn @fromType(ClosesOverY__2) let nym`get.cr__29`; - nym`get.cr__29` = fn (@impliedThis(ClosesOverY__2) this__30: ClosesOverY__2) { - getp(cr__27, this__30) - }; - @property(\cr__24) @visibility(\private) @stay @synthetic @fromType(ClosesOverY__2) let cr__24: ClosRec; - f__6 = fn f(x__7 /* aka x */) { - fn__8: do { - let cr#31; - cr#31 = makeCR(\word, x__7, \setter, fn (v#32) { - x__7 = v#32 - }); - @typeDecl(ClosesOverNothing__0) @stay let ClosesOverNothing__0; - ClosesOverNothing__0 = type (ClosesOverNothing__0); - @typeDecl(ClosesOverX__1) @stay let ClosesOverX__1; - ClosesOverX__1 = type (ClosesOverX__1); - class(\word, \ClosesOverNothing, \concrete, true, @typeDefined(ClosesOverNothing__0) fn { - do {}; - do {} - }); - interface(\word, \ClosesOverX, \concrete, false, @typeDefined(ClosesOverX__1) fn { - do {}; - do {}; - do {}; - do {} - }); - do (fn { - let cr#33; - cr#33 = makeCR(\word, y__16, \setter, fn (v#34) { - y__16 = v#34 - }); - @typeDecl(ClosesOverY__2) @stay let ClosesOverY__2; - ClosesOverY__2 = type (ClosesOverY__2); - let y__16; - y__16 = x__7 + 1; - class(\word, \ClosesOverY, \concrete, true, @typeDefined(ClosesOverY__2) fn { - do {}; - do {}; - do {}; - do {}; - do {}; - do {}; - do {}; - do {} - }); - new ClosesOverY__2(cr#31, cr#33) - }); - new ClosesOverNothing__0(); - } - }; - - ``` - } - } - """, ) @Test fun impliedGettersAndSetters() = assertModuleAtStage( - stage = Stage.Define, - input = """ - |class C(public var j, public k) extends I {} - """.trimMargin(), + stageTestDir = StageTestDir("define/implied-getters-and-setters"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - { - define: { - body: ``` - C__0 extends I; - @constructorProperty @property(\j) @visibility(\public) @stay @fromType(C__0) var j__2; - @constructorProperty @property(\k) @visibility(\public) @stay @fromType(C__0) let k__3; - @fn @method(\constructor) @visibility(\public) @stay @fromType(C__0) let constructor__4; - constructor__4 = fn constructor(@impliedThis(C__0) this__5: C__0, j__6 /* aka j */, k__7 /* aka k */) /* return__0 */: Void { - do { - let t#0; - setp(j__2, this__5, t#0 = j__6); - t#0 - }; - do { - let t#1; - setp(k__3, this__5, t#1 = k__7); - t#1 - }; - }; - @getter @method(\j) @fn @visibility(\public) @stay @fromType(C__0) let getj__8; - getj__8 = fn (@impliedThis(C__0) this__9: C__0) /* return__10 */{ - return__10 = getp(j__2, this__9) - }; - @setter @method(\j) @fn @visibility(\public) @stay @fromType(C__0) let setj__11; - setj__11 = fn (@impliedThis(C__0) this__12: C__0, newJ__13) /* return__14 */: Void { - setp(j__2, this__12, newJ__13); - return__14 = void - }; - @getter @method(\k) @fn @visibility(\public) @stay @fromType(C__0) let getk__12; - getk__12 = fn (@impliedThis(C__0) this__13: C__0) /* return__15 */{ - return__15 = getp(k__3, this__13) - }; - @typeDecl(C__0) @stay let C__0; - C__0 = type (C__0); - class(\word, \C, \concrete, true, @typeDefined(C__0) fn { - do {}; - do {}; - do {}; - do {}; - do {}; - do {}; - do {} - }); - type (C__0) - - ```, - types: { - // Implied getters and setters show up in the member list. - "C": { - properties: [ - { - name: "j__2", visibility: "public", abstract: false, - getter: "getj__8", setter: "setj__11", - metadata: { - "var": ["void: Void"], - } - }, - { name: "k__3", abstract: false, visibility: "public", getter: "getk__12" }, - ], - methods: [ - { - name: "getj__8", symbol: "j", - visibility: "public", kind: "Getter", open: false - }, - { - name: "setj__11", symbol: "j", - visibility: "public", kind: "Setter", open: false - }, - { - name: "getk__12", symbol: "k", - visibility: "public", kind: "Getter", open: false - }, - { - name: "constructor__4", - visibility: "public", kind: "Constructor", open: false - }, - ] - }, - "Void": { supers: [] }, - } - } - } - """, ) @Test fun propertyOnlyInterface() = assertModuleAtStage( - stage = Stage.Define, - input = """ - |interface I { public p; } - """.trimMargin(), + stageTestDir = StageTestDir("define/property-only-interface"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - |{ - | define: { - | body: - | ``` - | I__0 extends AnyValue; - | @property(\p) @visibility(\public) @stay @fromType(I__0) let p__3; - | @typeDecl(I__0) @stay let I__0; - | I__0 = type (I__0); - | interface(\word, \I, \concrete, false, @typeDefined(I__0) fn { - | do {}; - | do {} - | }); - | type (I__0) - | - | ``` - | } - |} - """.trimMargin(), ) @Test fun exportedNamePropagates() = assertModuleAtStage( - stage = Stage.Define, - input = """ - |let t = AnyValue; - |let x: t = 42; - """.trimMargin(), - want = """ - |{ - | define: { - | body: { - | tree: [ "Block", [ - | [ "Decl", [ - | [ "LeftName", "t__2" ], - | [ "Value", "\\QName: Symbol" ], - | [ "Value", "\"test-code.t\": String" ], - | [ "Value", "\\ssa: Symbol" ], [ "Value", "void: Void" ], - | ] - | ], - | [ "Call", [ - | [ "Value", "nym`=`: Function" ], - | [ "LeftName", "t__2" ], - | [ "Value", "AnyValue: Type" ], - | ] - | ], - | [ "Decl", [ - | [ "LeftName", "x__3" ], - | [ "Value", "\\type: Symbol" ], [ "Value", "AnyValue: Type" ], - | [ "Value", "\\QName: Symbol" ], - | [ "Value", "\"test-code.x\": String" ], - | [ "Value", "\\ssa: Symbol" ], [ "Value", "void: Void" ], - | ] - | ], - | [ "Call", [ - | [ "Value", "nym`=`: Function" ], - | [ "LeftName", "x__3" ], - | [ "Value", "42: Int32" ], - | ] - | ], - | [ "Value", "void: Void" ], - | ] - | ], - | - | code: - | ``` - | let t__2; - | t__2 = type (AnyValue); - | let x__3: AnyValue; - | x__3 = 42; - | - | ``` - | } - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("define/exported-name-propagates"), ) @Test fun macrosInEscapes() { var doNotCallWasCalled = false - assertModuleAtStage( - stage = Stage.Define, - want = """ - |{ - | stageCompleted: "Define", - | define: { - | body: - | ``` - | \(doNotCall(1 + 1, unhole(2))) - | - | ``` - | } - |} - """.trimMargin(), - ) { module, _ -> + assertModuleAtStage(StageTestDir("define/macros-in-escapers")) { module: Module, _, _ -> // The idea for escapes is that macros that take escapes can progressively turn // CST elements into AST elements and then use some `eval` builtin to unescape the // result. @@ -1348,805 +200,53 @@ class DefineStageTest { @Test fun parameterizedConstructorReference() = assertModuleAtStage( - stage = Stage.Define, - input = """ - |class C {} - |let f(): C {} - """.trimMargin(), + stageTestDir = StageTestDir("define/parameterized-constructor-reference"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - |{ - | define: { - | body: { - | tree: [ "Block", [ - | [ "Decl", [ - | [ "LeftName", "C__0" ], - | [ "Value", "\\typeDecl: Symbol" ], - | [ "Value", "C__0: Type" ], - | [ "Value", "\\stay: Symbol" ], - | [ "Stay", "kotlin.Unit" ], - | [ "Value", "\\QName: Symbol" ], - | [ "Value", "\"test-code.type C\": String" ], - | [ "Value", "\\ssa: Symbol" ], - | [ "Value", "void: Void" ], - | ] - | ], - | [ "Call", [ - | [ "Value", "nym`=`: Function" ], - | [ "LeftName", "C__0" ], - | [ "Value", "C__0: Type" ], - | ] - | ], - | [ "Decl", [ - | [ "LeftName", "f__0" ], - | [ "Value", "\\fn: Symbol" ], - | [ "Value", "void: Void" ], - | [ "Value", "\\QName: Symbol" ], - | [ "Value", "\"test-code.f()\": String" ], - | [ "Value", "\\ssa: Symbol" ], - | [ "Value", "void: Void" ], - | ] - | ], - | [ "Decl", [ - | [ "LeftName", "T__0" ], - | [ "Value", "\\typeFormal: Symbol" ], - | [ "Value", "\\T: Symbol" ], - | [ "Value", "\\memberTypeFormal: Symbol" ], - | [ "Value", "\\T: Symbol" ], - | [ "Value", "\\typeDefined: Symbol" ], - | [ "Value", "T__0: Type" ], - | [ "Value", "\\QName: Symbol" ], - | [ "Value", "\"test-code.type C.\": String" ], - | [ "Value", "\\ssa: Symbol" ], - | [ "Value", "void: Void" ], - | [ "Value", "\\fromType: Symbol" ], - | [ "Value", "C__0: Type" ], - | ] - | ], - | [ "Call", [ - | [ "Value", "nym`=`: Function" ], - | [ "LeftName", "T__0" ], - | [ "Value", "T__0: Type" ], - | ] - | ], - | [ "Call", [ - | [ "Value", "extends: Function" ], - | [ "Value", "C__0: Type" ], - | [ "Value", "AnyValue: Type" ], - | ] - | ], - | [ "Decl", [ - | [ "LeftName", "constructor__0" ], - | ["Value", "\\fn: Symbol"], - | ["Value", "void: Void"], - | [ "Value", "\\method: Symbol" ], - | [ "Value", "\\constructor: Symbol" ], - | [ "Value", "\\visibility: Symbol" ], - | [ "Value", "\\public: Symbol" ], - | [ "Value", "\\QName: Symbol" ], - | [ "Value", "\"test-code.type C.constructor()\": String" ], - | [ "Value", "\\ssa: Symbol" ], - | [ "Value", "void: Void" ], - | [ "Value", "\\stay: Symbol" ], - | [ "Stay" ], - | [ "Value", "\\parameterNameSymbolsList: Symbol" ], - | [ "Value", "[null]: List" ], - | [ "Value", "\\fromType: Symbol" ], - | [ "Value", "C__0: Type" ], - | ] - | ], - | [ "Call", [ - | [ "Value", "nym`=`: Function" ], - | [ "LeftName", "constructor__0" ], - | [ "Fun", [ - | [ "Decl", [ - | [ "LeftName", "this__0" ], - | [ "Value", "\\type: Symbol" ], - | [ "Value", "C__0: Type" ], - | [ "Value", "\\impliedThis: Symbol" ], - | [ "Value", "C__0: Type" ], - | [ "Value", "\\QName: Symbol" ], - | [ "Value", "\"test-code.type C.constructor().(this)\": String" ], - | ] - | ], - | [ "Value", "\\word: Symbol" ], - | [ "Value", "\\constructor: Symbol" ], - | [ "Value", "\\returnDecl: Symbol" ], - | [ "Decl", [ - | [ "LeftName", "return__0" ], - | [ "Value", "\\type: Symbol" ], - | [ "Value", "Void: Type" ], - | [ "Value", "\\QName: Symbol" ], - | [ "Value", "\"test-code.type C.constructor().return=\": String" ], - | [ "Value", "\\ssa: Symbol" ], - | [ "Value", "void: Void" ], - | ] - | ], - | [ "Value", "\\QName: Symbol" ], - | [ "Value", "\"test-code.type C.constructor()\": String" ], - | [ "Value", "\\stay: Symbol" ], - | [ "Stay" ], - | [ "Block", [ - | ] - | ] - | ] - | ] - | ] - | ], - | [ "Call", [ - | [ "Value", "class: Function" ], - | [ "Value", "\\word: Symbol" ], - | [ "Value", "\\C: Symbol" ], - | [ "Value", "\\concrete: Symbol" ], - | [ "Value", "true: Boolean" ], - | [ "Fun", [ - | [ "Value", "\\typeDefined: Symbol" ], - | [ "Value", "C__0: Type" ], - | [ "Block", [ - | [ "Block", [] ], - | [ "Block", [] ], - | [ "Block", [] ], - | ] - | ] - | ] - | ] - | ] - | ], - | [ "Decl", [ - | [ "LeftName", "U__0" ], - | [ "Value", "\\typeFormal: Symbol" ], - | [ "Value", "\\U: Symbol" ], - | [ "Value", "\\typeDecl: Symbol" ], - | [ "Value", "U__0: Type" ], - | [ "Value", "\\QName: Symbol" ], - | [ "Value", "\"test-code.f().\": String" ], - | [ "Value", "\\ssa: Symbol" ], - | [ "Value", "void: Void" ], - | ] - | ], - | [ "Call", [ - | [ "Value", "nym`=`: Function" ], - | [ "LeftName", "U__0" ], - | [ "Value", "U__0: Type" ], - | ] - | ], - | [ "Call", [ - | [ "Value", "nym`=`: Function" ], - | [ "LeftName", "f__0" ], - | [ "Fun", [ - | [ "Value", "\\returnDecl: Symbol" ], - | [ "Decl", [ - | [ "LeftName", "return__1" ], - | [ "Value", "\\type: Symbol" ], - | [ "Value", "C__0: Type" ], - | [ "Value", "\\QName: Symbol" ], - | [ "Value", "\"test-code.f().return=\": String" ], - | [ "Value", "\\ssa: Symbol" ], - | [ "Value", "void: Void" ], - | ] - | ], - | [ "Value", "\\returnedFrom: Symbol" ], - | [ "Value", "true: Boolean" ], - | [ "Value", "\\word: Symbol" ], - | [ "Value", "\\f: Symbol" ], - | [ "Value", "\\typeFormal: Symbol" ], - | [ "Value", "U__0: Type" ], - | [ "Value", "\\QName: Symbol" ], - | [ "Value", "\"test-code.f()\": String" ], - | [ "Value", "\\stay: Symbol" ], - | [ "Stay" ], - | [ "Block", [ - | [ "Value", "\\label: Symbol" ], - | [ "LeftName", "fn__0" ], - | ] - | ] - | ] - | ] - | ] - | ], - | [ "Value", "void: Void" ], - | ] - | ], - | code: ``` - | @typeDecl(C__0) @stay let C__0; - | C__0 = type (C__0); - | @fn let f__0; - | @typeFormal(\T) @memberTypeFormal(\T) @typeDefined(T__0) @fromType(C__0) let T__0; - | T__0 = type (T__0); - | C__0 extends AnyValue; - | @fn @method(\constructor) @visibility(\public) @stay @fromType(C__0) let constructor__0; - | constructor__0 = (@stay fn constructor(@impliedThis(C__0) this__0: C__0) /* return__0 */: Void {}); - | class(\word, \C, \concrete, true, @typeDefined(C__0) fn { - | do {}; - | do {}; - | do {} - | }); - | @typeFormal(\U) @typeDecl(U__0) let U__0; - | U__0 = type (U__0); - | f__0 = (@stay fn f /* return__1 */: (C__0) { - | fn__0: do {} - | }); - | - | ``` - | } - | } - |} - """.trimMargin(), ) @Test fun staticRead() = assertModuleAtStage( - stage = Stage.Run, - input = """ - |class C { - | public static foo = "FOO"; - |} - |C.foo - """.trimMargin(), + stageTestDir = StageTestDir("define/static-read"), moduleResultNeeded = true, pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - |{ - | define: { - | body: ``` - | C__0 extends AnyValue; - | @staticProperty(\foo) @static @visibility(\public) @stay @fromType(C__0) let foo__0; - | foo__0 = "FOO"; - | @fn @method(\constructor) @visibility(\public) @stay @fromType(C__0) let constructor__0; - | constructor__0 = (@stay fn constructor(@impliedThis(C__0) this__0: C__0) /* return__0 */: Void {}); - | @typeDecl(C__0) @stay let C__0; - | C__0 = type (C__0); - | class(\word, \C, \concrete, true, @typeDefined(C__0) fn { - | do {}; - | do {}; - | do {} - | }); - | getStatic(C__0, \foo) - | - | ````, - | types: { - | "AnyValue": { abstract: true }, - | "C": { - | supers: ["AnyValue__0"], - | methods: [ - | { name: "constructor__0", - | visibility: "public", kind: "Constructor", open: false }, - | ], - | staticProperties: [ - | { - | name: "foo__0", - | visibility: "public" - | } - | ] - | }, - | "Void": { supers: [] }, - | } - | }, - | run: "\"FOO\": String", - |} - """.trimMargin(), ) @Test fun complexTypeAliases() = assertModuleAtStage( - stage = Stage.Define, - input = """ - |let Sn = String?; - |let Ds = Deque; - |let Dn = Ds?; - |let s: Sn; - |let d: Dn; - """.trimMargin(), - want = """ - |{ - | define: { - | body: { - | tree: [ "Block", [ - | [ "Decl", [ - | [ "LeftName", "Sn__0" ], - | [ "Value", "\\QName: Symbol" ], - | [ "Value", "\"test-code.Sn\": String" ], - | [ "Value", "\\ssa: Symbol" ], - | [ "Value", "void: Void" ], - | ] - | ], - | [ "Call", [ - | [ "Value", "nym`=`: Function" ], - | [ "LeftName", "Sn__0" ], - | [ "Value", "String?: Type" ], - | ] - | ], - | [ "Decl", [ - | [ "LeftName", "Ds__0" ], - | [ "Value", "\\QName: Symbol" ], - | [ "Value", "\"test-code.Ds\": String" ], - | [ "Value", "\\ssa: Symbol" ], - | [ "Value", "void: Void" ], - | ] - | ], - | [ "Call", [ - | [ "Value", "nym`=`: Function" ], - | [ "LeftName", "Ds__0" ], - | [ "Value", "Deque: Type" ], - | ] - | ], - | [ "Decl", [ - | [ "LeftName", "Dn__0" ], - | [ "Value", "\\QName: Symbol" ], - | [ "Value", "\"test-code.Dn\": String" ], - | [ "Value", "\\ssa: Symbol" ], - | [ "Value", "void: Void" ], - | ] - | ], - | [ "Call", [ - | [ "Value", "nym`=`: Function" ], - | [ "LeftName", "Dn__0" ], - | [ "Value", "Deque?: Type" ], - | ] - | ], - | [ "Decl", [ - | [ "LeftName", "s__0" ], - | [ "Value", "\\type: Symbol" ], - | [ "Value", "String?: Type" ], - | [ "Value", "\\QName: Symbol" ], - | [ "Value", "\"test-code.s\": String" ], - | [ "Value", "\\ssa: Symbol" ], - | [ "Value", "void: Void" ], - | ] - | ], - | [ "Decl", [ - | [ "LeftName", "d__0" ], - | [ "Value", "\\type: Symbol" ], - | [ "Value", "Deque?: Type" ], - | [ "Value", "\\QName: Symbol" ], - | [ "Value", "\"test-code.d\": String" ], - | [ "Value", "\\ssa: Symbol" ], - | [ "Value", "void: Void" ], - | ] - | ], - | [ "Value", "void: Void" ], - | ] - | ], - | code: ``` - | let Sn__0; - | Sn__0 = type (String?); - | let Ds__0; - | Ds__0 = type (Deque); - | let Dn__0; - | Dn__0 = type (Deque?); - | let s__0: String?, d__0: Deque?; - | - | ``` - | } - | }, - |} - """.trimMargin(), + stageTestDir = StageTestDir("define/complex-type-aliases"), ) @Test fun typeArgsKept() = assertModuleAtStage( - stage = Stage.Define, - input = """ - |class What( - | public ints: List, - | public things: List, - |) { - | public work(that: Thing): Void { - | let another: What = this; - | let more: List = things; - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("define/type-args-kept"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - |{ - | disAmbiguate: { - | body: - | ``` - | @typeDecl(What__0) @hoistLeft(true) @resolution(What__0) @stay let What = type (What__0); - | class(\word, What, \concrete, true, @typeDefined(What__0) fn { - | @typeFormal(\Thing) @memberTypeFormal(\Thing) @typeDefined(Thing__0) @resolution(Thing__0) let Thing = type (Thing__0); - | What__0 extends AnyValue; - | @constructorProperty @property(\ints) @maybeVar @visibility(\public) let ints /* aka ints */: List; - | @constructorProperty @property(\things) @maybeVar @visibility(\public) let things /* aka things */: List; - | @method(\work) @visibility(\public) let work = fn(\word, work, @impliedThis(What__0) let this__0: What__0, let that /* aka that */: Thing, \outType, Void, fn { - | let another: What = this(What__0), more: List = things; - | }); - | }); - | What - | - | ```, - | }, - | syntaxMacro: { - | body: - | ``` - | @typeDecl(What__0) @stay let What__0 = type (What__0); - | class(\word, \What, \concrete, true, @typeDefined(What__0) fn { - | @typeFormal(\Thing) @memberTypeFormal(\Thing) @typeDefined(Thing__0) let Thing__0 = type (Thing__0); - | What__0 extends AnyValue; - | let typeof_ints#0 = List; - | @constructorProperty @property(\ints) @maybeVar @visibility(\public) let ints__0: typeof_ints#0; - | let typeof_things#0 = List; - | @constructorProperty @property(\things) @maybeVar @visibility(\public) let things__0: typeof_things#0; - | @method(\work) @visibility(\public) @fn let work__0 = fn work(@impliedThis(What__0) this__0: What__0, that__0 /* aka that */: Thing__0) /* return__0 */: (Void) { - | fn__0: do { - | let another__0: What__0 = this(What__0), more__0: List = do_iget_things(type (What__0), this(What__0)); - | } - | }; - | @method(\constructor) @visibility(\public) let constructor__0 = fn constructor(@impliedThis(What__0) this__1: What__0, ints__1 /* aka ints */: typeof_ints#0, things__1 /* aka things */: typeof_things#0) /* return__1 */: Void { - | do { - | let t#0; - | do_iset_ints(type (What__0), this(What__0), t#0 = ints__1); - | t#0 - | }; - | do { - | let t#1; - | do_iset_things(type (What__0), this(What__0), t#1 = things__1); - | t#1 - | }; - | }; - | }); - | What__0 - | - | ```, - | }, - | define: { - | body: - | ``` - | @typeFormal(\Thing) @memberTypeFormal(\Thing) @typeDefined(Thing__0) @fromType(What__0) let Thing__0; - | Thing__0 = type (Thing__0); - | What__0 extends AnyValue; - | let typeof_ints#0; - | typeof_ints#0 = type (List); - | @constructorProperty @property(\ints) @visibility(\public) @stay @fromType(What__0) let ints__0: List; - | let typeof_things#0; - | typeof_things#0 = type (List); - | @constructorProperty @property(\things) @visibility(\public) @stay @fromType(What__0) let things__0: List; - | @method(\work) @visibility(\public) @fn @stay @fromType(What__0) let work__0; - | work__0 = fn work(@impliedThis(What__0) this__0: What__0, that__0 /* aka that */: Thing__0) /* return__0 */: Void { - | fn__0: do { - | let another__0: What__0; - | another__0 = this__0; - | let more__0: List; - | more__0 = getp(things__0, this__0); - | } - | }; - | @fn @method(\constructor) @visibility(\public) @stay @fromType(What__0) let constructor__0; - | constructor__0 = fn constructor(@impliedThis(What__0) this__1: What__0, ints__1 /* aka ints */: List, things__1 /* aka things */: List) /* return__1 */: Void { - | do { - | let t#0; - | setp(ints__0, this__1, t#0 = ints__1); - | t#0 - | }; - | do { - | let t#1; - | setp(things__0, this__1, t#1 = things__1); - | t#1 - | }; - | }; - | @getter @method(\ints) @fn @visibility(\public) @stay @fromType(What__0) let getints__0; - | getints__0 = fn (@impliedThis(What__0) this__2: What__0) /* return__2 */: (List) { - | return__2 = getp(ints__0, this__2) - | }; - | @getter @method(\things) @fn @visibility(\public) @stay @fromType(What__0) let getthings__0; - | getthings__0 = fn (@impliedThis(What__0) this__3: What__0) /* return__3 */: (List) { - | return__3 = getp(things__0, this__3) - | }; - | @typeDecl(What__0) @stay let What__0; - | What__0 = type (What__0); - | class(\word, \What, \concrete, true, @typeDefined(What__0) fn { - | do {}; - | do {}; - | do {}; - | do {}; - | do {}; - | do {}; - | do {}; - | do {}; - | do {}; - | do {} - | }); - | type (What__0) - | - | ```, - | }, - |} - """.trimMargin(), ) @Test fun functionTypesInline() = assertModuleAtStage( - stage = Stage.Type, - input = """ - |let f: fn(List): List = never(); - """.trimMargin(), - want = """ - |{ - | define: { - | body: { - | tree: [ "Block", [ - | [ "Decl", [ - | [ "LeftName", "f__0" ], - | [ "Value", "\\type: Symbol" ], - | [ "Block", [ - | [ "Decl", [ - | [ "LeftName", "T__0" ], - | [ "Value", "\\typeFormal: Symbol" ], - | [ "Value", "\\T: Symbol" ], - | [ "Value", "\\typeDecl: Symbol" ], - | [ "Value", "T__0: Type" ], - | [ "Value", "\\QName: Symbol" ], - | [ "Value", "\"test-code.f.\": String" ], - | [ "Value", "\\ssa: Symbol" ], - | [ "Value", "void: Void" ], - | ] - | ], - | [ "Call", [ - | [ "Value", "nym`=`: Function" ], - | [ "LeftName", "T__0" ], - | [ "Value", "T__0: Type" ], - | ] - | ], - | [ "Value", "Fn__0, List>: Type" ] - | ] - | ], - | [ "Value", "\\QName: Symbol" ], - | [ "Value", "\"test-code.f\": String" ], - | [ "Value", "\\ssa: Symbol" ], - | [ "Value", "void: Void" ], - | ] - | ], - | [ "Call", [ - | [ "Value", "nym`=`: Function" ], - | [ "LeftName", "f__0" ], - | [ "Call", [ - | [ "RightName", "never" ] - | ] - | ] - | ] - | ], - | [ "Value", "void: Void" ], - | ] - | ], - | code: ``` - | let f__0: do { - | @typeFormal(\T) @typeDecl(T__0) let T__0; - | T__0 = type (T__0); - | type (fn(List): List) - | }; - | f__0 = never(); - | - | ``` - | } - | }, - | - | type: { - | body: ``` - | @typeFormal(\T) @typeDecl(T__0) let T__0; - | T__0 = type (T__0); - | let f__0: (fn(List): List); - | f__0 = never(); - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("define/function-types-inline"), ) @Test fun nestedEmptyType() = assertModuleAtStage( - input = """ - |let functionThatNestsAType(): Void { - | interface EmptyHelper {} // <-- needs a placeholder at the top level - | // See the comments in TmpLControlFlow and ClosureConvertClasses - |} - """.trimMargin(), - want = """ - |{ - | define: { - | body: ``` - | @fn let functionThatNestsAType__0; - | EmptyHelper__0 extends AnyValue; - | @typePlaceholder(EmptyHelper__0) let typePlaceholder#0: Empty; - | typePlaceholder#0 = {class: Empty__0}; - | functionThatNestsAType__0 = fn functionThatNestsAType /* return__0 */: Void { - | fn__0: do { - | @typeDecl(EmptyHelper__0) @stay let EmptyHelper__0; - | EmptyHelper__0 = type (EmptyHelper__0); - | interface(\word, \EmptyHelper, \concrete, false, @typeDefined(EmptyHelper__0) fn { - | do {} - | }); - | type (EmptyHelper__0) - | } - | }; - | - | ``` - | } - |} - """.trimMargin(), - stage = Stage.Define, + stageTestDir = StageTestDir("define/nested-empty-type"), ) @Test fun whenBlock() = assertModuleAtStage( - stage = Stage.Define, + stageTestDir = StageTestDir("define/when-block"), // Test both valid content and error content together. - input = """ - |interface A { } - |class B extends A { } - |let b = new B(); - |let f(a: A): A { - | when (a) { - | b -> a; - | // Comments are fine, but unrelated statements aren't. - | wordYall(); - | is B -> a; - | (fancyExpression + 4) -> a; - | 4, is C -> a; - | else -> a; - | // Case after default is also bad, as is missing value. - | c ->; - | d -> a; - | e -> - | } - |} - """.trimMargin(), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - |{ - | define: { - | body: ``` - | @typeDecl(A__0) @stay let A__0; - | A__0 = type (A__0); - | @typeDecl(B__0) @stay let B__0; - | B__0 = type (B__0); - | @fn let f__0; - | A__0 extends AnyValue; - | @typePlaceholder(A__0) let typePlaceholder#0: Empty; - | typePlaceholder#0 = {class: Empty__0}; - | interface(\word, \A, \concrete, false, @typeDefined(A__0) fn { - | do {} - | }); - | B__0 extends A__0; - | @fn @method(\constructor) @visibility(\public) @stay @fromType(B__0) let constructor__0; - | constructor__0 = (@stay fn constructor(@impliedThis(B__0) this__0: B__0) /* return__0 */: Void {}); - | class(\word, \B, \concrete, true, @typeDefined(B__0) fn { - | do {}; - | do {} - | }); - | let b__0; - | b__0 = new B__0(); - | f__0 = fn f(a__0 /* aka a */: A__0) /* return__1 */: A__0 { - | fn__0: do { - | do { - | if(a__0 == b__0, fn { - | a__0 - | }, \else_if, fn (f#0) { - | f#0(a__0 is B__0, fn { - | a__0 - | }, \else_if, fn (f#1) { - | f#1(a__0 == fancyExpression + 4, fn { - | a__0 - | }, \else_if, fn (f#2) { - | f#2(if(a__0 == 4, @stay fn { - | true - | }, \else, fn (f#3) { - | f#3(fn { - | a__0 is C - | }) - | }), fn { - | a__0 - | }, \else, fn (f#4) { - | f#4(fn { - | a__0 - | }) - | }) - | }) - | }) - | }) - | } - | } - | }; - | - | ``` - | }, - | errors: [ - | "Operator ThinArrow expects at least 2 operands but got 1!", - | "Operator ThinArrow expects at least 2 operands but got 1!", - | "Expected a TopLevel here!", - | "Expected a TopLevel here!", - | "Invalid block content!", - | "Invalid block content!", - | "Other cases are invalid after else!", - | "Invalid block content!" - | ], - |} - """.trimMargin(), ) @Test fun whenGeneric() = assertModuleAtStage( - stage = Stage.Define, - input = """ - |let f(maybe: List?): String { - | when (maybe) { - | is List -> "yep"; - | else -> "nope"; - | } - |} - """.trimMargin(), - want = """ - |{ - | define: { - | body: ``` - | @fn let f__0; - | f__0 = fn f(maybe__0 /* aka maybe */: List?) /* return__0 */: String { - | fn__0: do { - | do { - | if(maybe__0 is List, @stay fn { - | "yep" - | }, \else, fn (f#0) { - | f#0(@stay fn { - | "nope" - | }) - | }) - | } - | } - | }; - | - | ``` - | }, - |} - """.trimMargin(), + stageTestDir = StageTestDir("define/when-generic"), ) @Test fun castingCall() = assertModuleAtStage( - stage = Stage.Define, - input = """ - |// Prelude on ensuring that it's rename inside property bags. - |let { a as b } = c; - |// Now on to the casting call. - |1 as Int; - |2 as Mystery; - |3 as List; - |4 as; - |5.as(Int); - |6.as(Mystery); - |7.as(); - |8.as; - |[9][0] as Int; - |10.toString() as String; - """.trimMargin(), - want = """ - |{ - | define: { - | body: ``` - | void; - | let t#0; - | t#0 = c; - | let b__0; - | b__0 = do_get_a(t#0); - | void; - | 1 as Int32; - | 2 as Mystery; - | 3 as type (List); - | error (list("`(Leaf`", "4", "`Leaf)`", "as")); - | do_call_as(5, type (Int32)); - | do_call_as(6, Mystery); - | do_call_as(7); - | do_get_as(8); - | do_call_get(list(9), 0) as Int32; - | do_call_toString(10) as String; - | - | ``` - | }, - | errors: [ - | "Operator As expects at least 2 operands but got 1!", - | "Expected a TopLevel here!", - | ] - |} - """.trimMargin(), + stageTestDir = StageTestDir("define/casting-call"), ) @Test @@ -2185,551 +285,56 @@ class DefineStageTest { assertEquals("", consoleOutput) assertModuleAtStage( + stageTestDir = StageTestDir("define/instantiate-test-harnesses"), // For `temper test` integration, we need to add instructions to // create instances of each concrete test fixture type when there // is a particular marker. - stage = Stage.Define, - want = """ - |{ - | define: { - | body: ``` - | @stay @imported(\(`std//testing/`.runTestCases)) @connected let runTestCases__0; - | runTestCases__0 = `std//testing/`.runTestCases; - | @implicit @imported(\(`std//testing/`.Test)) let Test__0; - | Test__0 = type (Test); - | @implicit @imported(\(`std//testing/`.runTestCases)) @fn let runTestCases__1; - | runTestCases__1 = (fn runTestCases); - | @stay @imported(\(`std//testing/`.Test)) let Test__1; - | Test__1 = type (Test); - | @fn @test("- a test case -") let aTestCase__0; - | aTestCase__0 = (@stay fn aTestCase(test#0: Test) /* return__0 */: (Void | Bubble) {}); - | @stay let `test//`.temper__testReport; - | `test//`.temper__testReport = runTestCases__0(list(new Pair("- a test case -", aTestCase__0))); - | - | ```, - | } - |} - """.trimMargin(), - ) { module, _ -> - module.deliverContent( - ModuleSource( - filePath = testCodeLocation, - fetchedContent = """ - |test("- a test case -") { - | // do something - |} - """.trimMargin(), - languageConfig = StandaloneLanguageConfig, - ), - ) - module.addEnvironmentBindings( - mapOf( - StagingFlags.defineStageHookCreateAndRunClasses to TBoolean.valueTrue, - ), - ) + stagingFlags = setOf(StagingFlags.defineStageHookCreateAndRunClasses), + + ) { module, moduleAdvancer, td -> module.addImplicitImports(fakeStdTestModuleExports) + provisionModuleForStageTest(td, module, moduleAdvancer) } } @Test fun badTests() = assertModuleAtStage( - stage = Stage.Define, - input = """ - |test(); - |test("hi"); - |test("") {} - |test(1) {} - |test("hi", 2); - |test(hi) {} - |test("hi") { hi: String => assert(true) { "nope" } } - """.trimMargin(), - want = """ - |{ - | define: { - | body: ``` - | @stay @imported(\(`std//testing/`.Test)) let Test__0; - | Test__0 = type (Test); - | test(); - | test("hi"); - | test("", @stay fn (test#0: Test) /* return__0 */: (Void | Bubble) {}); - | test(1, @stay fn (test#1: Test) /* return__1 */: (Void | Bubble) {}); - | test("hi", 2); - | test(hi, @stay fn (test#2: Test) /* return__2 */: (Void | Bubble) {}); - | @fn @test("hi") let hi__0; - | hi__0 = fn hi(hi__1 /* aka hi */: String) /* return__3 */: (Void | Bubble) { - | assert(true, @stay fn { - | "nope" - | }) - | }; - | - | ``` - | }, - | errors: [ - | "Wrong number of arguments. Expected 2!", - | "Wrong number of arguments. Expected 2!", - | "Expected function type, but got Int32!", - | "Wrong number of arguments. Expected 2!", - | "Wrong number of arguments. Expected 2!", - | "Expected a name!", - | "Expected value of type String not Int32!", - | "Expected function type, but got Int32!", - | "Unable to evaluate!", - | "Invalid block content!", - | ] - |} - """.trimMargin(), + stageTestDir = StageTestDir("define/bad-tests"), ) @Test fun goodTests() = assertModuleAtStage( - stage = Stage.Define, - input = """ - |test("- does / this : work?") { assert(true) { "or what?" } } - |test("does\tthis\nwork") { test => assert(false) { "or that" } } - |test("again") { t => assert(true) { "whatever" } } - """.trimMargin(), - want = """ - |{ - | define: { - | body: ``` - | @stay @imported(\(`std//testing/`.Test)) let Test__0; - | Test__0 = type (Test); - | @fn @test("- does / this : work?") let doesThisWork__0; - | doesThisWork__0 = fn doesThisWork(test#0: Test) /* return__0 */: (Void | Bubble) { - | do_call_assert(test#0, true, @stay fn { - | "or what?" - | }) - | }; - | @fn @test("does\tthis\nwork") let doesThisWork__1; - | doesThisWork__1 = fn doesThisWork(test__0 /* aka test */: Test) /* return__1 */: (Void | Bubble) { - | do_call_assert(test__0, false, @stay fn { - | "or that" - | }) - | }; - | @fn @test("again") let again__0; - | again__0 = fn again(t__0 /* aka t */: Test) /* return__2 */: (Void | Bubble) { - | do_call_assert(t__0, true, @stay fn { - | "whatever" - | }) - | }; - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("define/good-tests"), ) @Test fun autoAssertMessage() = assertModuleAtStage( - stage = Stage.Define, - input = """ - |test("hi") { let num = 4; assert(num == 3); } - |test("ha") { let condition = false; assert(condition); } - """.trimMargin(), - want = """ - |{ - | define: { - | body: ``` - | @stay @imported(\(`std//testing/`.Test)) let Test__0; - | Test__0 = type (Test); - | @fn @test("hi") let hi__0; - | hi__0 = fn hi(test#0: Test) /* return__0 */: (Void | Bubble) { - | let num__0; - | num__0 = 4; - | do { - | let actual#0; - | actual#0 = 4; - | let expected#0; - | expected#0 = 3; - | do_call_assert(test#0, false, @stay fn { - | cat("expected num == (", do_call_toString(3), ") not (", do_call_toString(4), ")") - | }) - | }; - | }; - | @fn @test("ha") let ha__0; - | ha__0 = fn ha(test#1: Test) /* return__1 */: (Void | Bubble) { - | let condition__0; - | condition__0 = false; - | do_call_assert(test#1, false, @stay fn { - | "expected condition" - | }); - | }; - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("define/auto-assert-message"), ) @Test fun classExtendsClass() = assertModuleAtStage( - stage = Stage.Define, - input = """ - |class Apple {} - |class Banana {} - |interface Cherry {} - |class Durian extends Apple, Banana & Cherry {} - """.trimMargin(), + stageTestDir = StageTestDir("define/class-extends-class"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - |{ - | define: { - | body: ``` - | Apple__0 extends AnyValue; - | @fn @method(\constructor) @visibility(\public) @stay @fromType(Apple__0) let constructor__0; - | constructor__0 = (@stay fn constructor(@impliedThis(Apple__0) this__0: Apple__0) /* return__0 */: Void {}); - | @typeDecl(Apple__0) @stay let Apple__0; - | Apple__0 = type (Apple__0); - | @typeDecl(Banana__0) @stay let Banana__0; - | Banana__0 = type (Banana__0); - | @typeDecl(Cherry__0) @stay let Cherry__0; - | Cherry__0 = type (Cherry__0); - | @typeDecl(Durian__0) @stay let Durian__0; - | Durian__0 = type (Durian__0); - | class(\word, \Apple, \concrete, true, @typeDefined(Apple__0) fn { - | do {}; - | do {} - | }); - | Banana__0 extends AnyValue; - | @fn @method(\constructor) @visibility(\public) @stay @fromType(Banana__0) let constructor__1; - | constructor__1 = (@stay fn constructor(@impliedThis(Banana__0) this__1: Banana__0) /* return__1 */: Void {}); - | class(\word, \Banana, \concrete, true, @typeDefined(Banana__0) fn { - | do {}; - | do {} - | }); - | Cherry__0 extends AnyValue; - | @typePlaceholder(Cherry__0) let typePlaceholder#0: Empty; - | typePlaceholder#0 = {class: Empty__0}; - | interface(\word, \Cherry, \concrete, false, @typeDefined(Cherry__0) fn { - | do {} - | }); - | Durian__0 extends Apple__0; - | Durian__0 extends ([Banana__0, Cherry__0]); - | @fn @method(\constructor) @visibility(\public) @stay @fromType(Durian__0) let constructor__2; - | constructor__2 = (@stay fn constructor(@impliedThis(Durian__0) this__2: Durian__0) /* return__2 */: Void {}); - | class(\word, \Durian, \concrete, true, @typeDefined(Durian__0) fn { - | do {}; - | do {}; - | do {} - | }); - | type (Durian__0) - | - | ``` - | }, - | errors: [ - | "Cannot extend concrete type(s) Apple!", - | "Cannot extend concrete type(s) Banana!", - | ], - |} - """.trimMargin(), ) @Test fun missingVisibilityOnClassMembers() = assertModuleAtStage( - stage = Stage.Define, - input = """ - |class C(p: Int) { - | q: Int = p + 1; - | private r: Int = p - 1; - | f(): Int { r } - |} - """.trimMargin(), - want = """ - |{ - | define: { - | body: ``` - | C__0 extends AnyValue; - | @constructorProperty @stay @fromType(C__0) let p__0: Int32; - | @stay @fromType(C__0) let q__0: Int32; - | @visibility(\private) @stay @fromType(C__0) let r__0: Int32; - | @fn @stay @fromType(C__0) let f__0; - | f__0 = fn f(@impliedThis(C__0) this__0: C__0) /* return__0 */: Int32 { - | fn__0: do { - | getp(r__0, this__0) - | } - | }; - | @fn @visibility(\public) @stay @fromType(C__0) let constructor__0; - | constructor__0 = fn constructor(@impliedThis(C__0) this__1: C__0, p__1 /* aka p */: Int32) /* return__1 */: Void { - | do { - | let t#0; - | setp(p__0, this__1, t#0 = p__1); - | t#0 - | }; - | do { - | let t#1; - | setp(q__0, this__1, t#1 = p__1 + 1); - | t#1 - | }; - | do { - | let t#2; - | setp(r__0, this__1, t#2 = p__1 - 1); - | t#2 - | }; - | }; - | @fn @visibility(\public) @stay @fromType(C__0) let getp__0; - | getp__0 = fn (@impliedThis(C__0) this__2: C__0) /* return__2 */: Int32 { - | return__2 = getp(p__0, this__2) - | }; - | @fn @visibility(\public) @stay @fromType(C__0) let getq__0; - | getq__0 = fn (@impliedThis(C__0) this__3: C__0) /* return__3 */: Int32 { - | return__3 = getp(q__0, this__3) - | }; - | @typeDecl(C__0) @stay let C__0; - | C__0 = type (C__0); - | class(\word, \C, \concrete, true, @typeDefined(C__0) fn { - | do {}; - | do {}; - | do {}; - | do {}; - | do {}; - | do {}; - | do {}; - | do {} - | }); - | type (C__0) - | - | ``` - | }, - | errors: [ - | "Members of class C__0 require explicit visibility: [.p, .q, .f(...)]!" - | ], - |} - """.trimMargin(), + stageTestDir = StageTestDir("define/missing-visibility-on-class-members"), ) @Test fun regexLiteral() = assertModuleAtStage( - // These changes currently are applied in SyntaxMacroStage, but it's - // easier to see the formatting later. - stage = Stage.Define, - // Some tests below: - // - Interpolated string value next to another interpolation. Also test a disappearing empty hole. - // - Simple interpolated string value since we can't evaluate regex objects at compile time yet. - input = $$""" - |let r1 = /a.b*/; - |let r2 = /a.${b}*/; - |let r3 = /a.b*/g; - |let b = r3; - |let r4 = rgx"a.${b}*"; - |let r5 = rgx"a${"."}${b}*${}?"; - |let r6 = rgx"a${"."}*"; - |let r7 = new Sequence([ - | new CodePoints("a"), - | Dot, - | new Repeat(new CodePoints("b"), 0, null), - |]).compiled(); - |let s = "[a]"; - |let r8 = rgx".${s}."; - """.trimMargin(), - want = """ - |{ - | parse: { - | body: ``` - | let ${ - listOf( - """r1 = rgx(list("a.b*"), list())""", - """r2 = rgx(list("a.\u{24}{b}*"), list())""", - // We don't actually support the following flag syntax at the moment. - // That's one of the syntax error messages. - """r3 = rgx(list("(?/g)a.b*"), list())""", - """b = r3""", - // And we have a brief interpolation representation from Grammar that's easyish to build. - // It gets changed later. - """r4 = stringExpr(rgx, true, "a.", \interpolate, b, "*")""", - """r5 = stringExpr(rgx, true, "a", \interpolate, ".", \interpolate, b, "*?")""", - """r6 = stringExpr(rgx, true, "a", \interpolate, ".", "*")""", - """r7 = new Sequence(list(new CodePoints("a"), Dot, new Repeat(new CodePoints("b"), 0, null))).compiled()""", - """s = "[a]"""", - """r8 = stringExpr(rgx, true, ".", \interpolate, s, ".")""", - ).joinToString(", ") - }; - | - | ``` - | }, - | disAmbiguate: { - | body: ``` - | @stay @imported(\(`std//regex/`.Sequence)) let Sequence__0 = type (Sequence), ${ - "" - }@imported(\(`std//regex/`.CodePoints)) CodePoints__0 = type (CodePoints), ${ - "" - }@imported(\(`std//regex/`.Dot)) Dot__0 = `std//regex/`.Dot, ${ - "" - }@imported(\(`std//regex/`.Repeat)) Repeat__0 = type (Repeat), ${ - "" - }@imported(\(`std//regex/`.End)) End__0 = `std//regex/`.End, ${ - listOf( - // r1 = rgx(list("a.b*"), list()) - """r1 = do_call_compiled(new Sequence(list(new CodePoints("a"), Dot__0, new Repeat(new CodePoints("b"), 0, null, false))))""", - // r2 = rgx(list("a.\u{24}{b}*"), list()) - """r2 = do_call_compiled(new Sequence(list(new CodePoints("a"), Dot__0, End__0, new CodePoints("{b"), new Repeat(new CodePoints("}"), 0, null, false))))""", - """r3 = rgx(list("(?/g)a.b*"), list())""", - """b = r3""", - // Here, r4 and r5 interpolate regex objects, but we don't support those yet. - // These are the other two syntax errors. - """r4 = stringExpr(rgx, true, "a.", \interpolate, b, "*")""", - """r5 = stringExpr(rgx, true, "a", \interpolate, ".", \interpolate, b, "*?")""", - // But we do support interpolated string values already, so this one is ok. - // TODO Wrap stable string values in `new CodePoints` calls if we want to support runtime building. - """r6 = stringExpr(rgx, true, "a", \interpolate, ".", "*")""", - // This one uses Sequence instead of Sequence__0 since it was hand-coded and - // remains unaffected by the auto-import used above. - """r7 = new Sequence(list(new CodePoints("a"), Dot, new Repeat(new CodePoints("b"), 0, null))).compiled()""", - """s = "[a]"""", - """r8 = stringExpr(rgx, true, ".", \interpolate, s, ".")""", - ).joinToString(", ") - }; - | - | ``` - | }, - | define: { - | body: ``` - |## Here are the auto-imports - | @stay @imported(\(`std//regex/`.Sequence)) let Sequence__0; - | Sequence__0 = type (Sequence); - | @imported(\(`std//regex/`.CodePoints)) let CodePoints__0; - | CodePoints__0 = type (CodePoints); - | @imported(\(`std//regex/`.Dot)) let Dot__0; - | Dot__0 = `std//regex/`.Dot; - | @imported(\(`std//regex/`.Repeat)) let Repeat__0; - | Repeat__0 = type (Repeat); - | @imported(\(`std//regex/`.End)) let End__0; - | End__0 = `std//regex/`.End; - | let r1__0; - |## Types have been inlined into `new` operators - | r1__0 = do_call_compiled(new Sequence(list(new CodePoints("a"), Dot__0, new Repeat(new CodePoints("b"), 0, null, false)))); - | let r2__0; - | r2__0 = do_call_compiled(new Sequence(list(new CodePoints("a"), Dot__0, End__0, new CodePoints("{b"), new Repeat(new CodePoints("}"), 0, null, false)))); - | let r3__0; - |## (/g) unrecognized in rgx(list("(?/g)a.b*"), list()); - | r3__0 = error (UnrecognizedToken); - | let b__0; - | b__0 = r3__0; - | let r4__0; - |## interpolation of b__0 not supported yet in r4 or r5 - | r4__0 = error (UnrecognizedToken); - | let r5__0; - | r5__0 = error (UnrecognizedToken); - | let r6__0; - | r6__0 = do_call_compiled(new Sequence__0(list(new CodePoints__0("a"), new Repeat__0(new CodePoints__0("."), 0, null, false)))); - | let r7__0; - | r7__0 = do_call_compiled(new Sequence(list(new CodePoints("a"), Dot, new Repeat(new CodePoints("b"), 0, null)))); - | let s__0; - | s__0 = "[a]"; - | let r8__0; - | r8__0 = do_call_compiled(new Sequence__0(list(Dot__0, new CodePoints__0("[a]"), Dot__0))); - | - | ``` - | }, - | errors: [ - | "Syntax error!", - | "Syntax error!", - | "Syntax error!", - | ], - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), + stageTestDir = StageTestDir("define/regex-literal"), ) @Test fun fullyQualifiedNamesAllocated() = assertModuleAtStage( - stage = Stage.Define, + stageTestDir = StageTestDir("define/fully-qualified-names-allocated"), pseudoCodeDetail = PseudoCodeDetail.default.copy( showTypeMemberMetadata = true, showQNames = true, ), - input = """ - |let x = 1; - |let x = 2; - |export let e = x; - |let f(x: Int, y: F): Int { - | let local = x; - | let helper(z: Int): Int { local + z } - | helper(1) - |} - |interface I { - | public x: T; - | public get y(): Int; - | public set y(newY: Int): Void; - | public method(): Void; - | public static staticMethod(i: I): Void { } - |} - | - """.trimMargin(), - want = """ - |{ - | define: { - | body: ``` - | @fn @QName("test-code.f()") let f__0; - | @typeDecl(I__0) @stay @QName("test-code.type I") let I__0; - | I__0 = type (I__0); - | @QName("test-code.x#0") let x__0; - | x__0 = 1; - | @QName("test-code.x#1") let x__1; - | x__1 = 2; - | @QName("test-code.e") let `test//`.e; - | `test//`.e = 2; - | @typeFormal(\F) @typeDecl(F__0) @QName("test-code.f().") let F__0; - | F__0 = type (F__0); - | f__0 = (@QName("test-code.f()") fn f(@QName("test-code.f().(x)") x__2 /* aka x */: Int32, @QName("test-code.f().(y)") y__0 /* aka y */: F__0) /* return__0 */: Int32 { - | fn__0: do { - | @fn @QName("test-code.f().helper()") let helper__0, @QName("test-code.f().local=") local__0; - | local__0 = x__2; - | helper__0 = (@QName("test-code.f().helper()") fn helper(@QName("test-code.f().helper().(z)") z__0 /* aka z */: Int32) /* return__1 */: Int32 { - | fn__1: do { - | local__0 + z__0 - | } - | }); - | helper__0(1) - | } - | }); - | @typeFormal(\T) @memberTypeFormal(\T) @typeDefined(T__0) @QName("test-code.type I.") @fromType(I__0) let T__0; - | T__0 = type (T__0); - | I__0 extends AnyValue; - | @property(\x) @visibility(\public) @QName("test-code.type I.x") @stay @fromType(I__0) let x__3: T__0; - | @property(\y) @visibility(\public) @QName("test-code.type I.y") @stay @fromType(I__0) let y__1; - | @method(\y) @getter @visibility(\public) @fn @QName("test-code.type I.get y()") @stay @fromType(I__0) let nym`get.y__0`; - | nym`get.y__0` = (@QName("test-code.type I.get y()") fn nym`get.y`(@impliedThis(I__0) @QName("test-code.type I.get y().(this)") this__0: I__0) /* return__2 */: Int32 { - | fn__2: do { - | pureVirtual() - | } - | }); - | @method(\y) @setter @visibility(\public) @fn @QName("test-code.type I.set y()") @stay @fromType(I__0) let nym`set.y__0`; - | nym`set.y__0` = (@QName("test-code.type I.set y()") fn nym`set.y`(@impliedThis(I__0) @QName("test-code.type I.set y().(this)") this__1: I__0, @QName("test-code.type I.set y().(newY)") newY__0 /* aka newY */: Int32) /* return__3 */: Void { - | fn__3: do { - | pureVirtual() - | } - | }); - | @method(\method) @visibility(\public) @fn @QName("test-code.type I.method()") @stay @fromType(I__0) let method__0; - | method__0 = (@QName("test-code.type I.method()") fn method(@impliedThis(I__0) @QName("test-code.type I.method().(this)") this__2: I__0) /* return__4 */: Void { - | fn__4: do { - | pureVirtual() - | } - | }); - | @staticProperty(\staticMethod) @fn @static @visibility(\public) @QName("test-code.type I.staticMethod()") @stay @fromType(I__0) let staticMethod__0; - | @typeFormal(\T) @typeDecl(T__1) @QName("test-code.type I.staticMethod().") let T__1; - | T__1 = type (T__1); - | staticMethod__0 = (@QName("test-code.type I.staticMethod()") @stay fn staticMethod(@QName("test-code.type I.staticMethod().(i)") i__0 /* aka i */: I__0) /* return__5 */: Void { - | fn__5: do {} - | }); - | void; - | interface(\word, \I, \concrete, false, @typeDefined(I__0) fn { - | do {}; - | do {}; - | do {}; - | do {}; - | do {}; - | do {}; - | do {}; - | do {}; - | do {}; - | do {}; - | do {} - | }); - | type (I__0) - | - | ``` - | } - |} - """.trimMargin(), ) @Test @@ -2870,687 +475,52 @@ class DefineStageTest { @Test fun sealedSubtypesRejectNewTypeParams() = assertModuleAtStage( - stage = Stage.Define, - input = """ - |sealed interface Something {} - |// Sealed subtypes can't introduce type params. - |class Subversive extends Something {} - |// But we can (must?) keep type params from parent. And check with a changed name, for bonus fun. - |interface Simple extends Something {} - |// And types further down the line can introduce new type params, since we can't cast to them anyway. - |class Satisfying extends Simple {} - """.trimMargin(), - want = """ - |{ - | define: { - | body: ``` - | @typeDecl(Something__0) @stay @sealedType let Something__0; - | Something__0 = type (Something__0); - | @typeDecl(Subversive__0) @stay let Subversive__0; - | Subversive__0 = type (Subversive__0); - | @typeDecl(Simple__0) @stay let Simple__0; - | Simple__0 = type (Simple__0); - | @typeDecl(Satisfying__0) @stay let Satisfying__0; - | Satisfying__0 = type (Satisfying__0); - | do {}; - | @typeFormal(\T) @typeDefined(T__0) @fromType(Something__0) let T__0; - | T__0 = type (T__0); - | Something__0 extends AnyValue; - | interface(\word, \Something, \concrete, false, @typeDefined(Something__0) fn { - | do {}; - | do {} - | }); - | void; - | @typeFormal(\T) @typeDefined(T__1) @fromType(Subversive__0) let T__1; - | T__1 = type (T__1); - | @typeFormal(\U) @typeDefined(U__0) @fromType(Subversive__0) let U__0; - | U__0 = type (U__0); - | Subversive__0 extends Something__0; - | @fn @visibility(\public) @stay @fromType(Subversive__0) let constructor__0; - | constructor__0 = (@stay fn constructor(@impliedThis(Subversive__0) this__0: Subversive__0) /* return__0 */: Void {}); - | class(\word, \Subversive, \concrete, true, @typeDefined(Subversive__0) fn { - | do {}; - | do {}; - | do {}; - | do {} - | }); - | void; - | @typeFormal(\V) @typeDefined(V__0) @fromType(Simple__0) let V__0; - | V__0 = type (V__0); - | Simple__0 extends Something__0; - | interface(\word, \Simple, \concrete, false, @typeDefined(Simple__0) fn { - | do {}; - | do {} - | }); - | void; - | @typeFormal(\T) @typeDefined(T__2) @fromType(Satisfying__0) let T__2; - | T__2 = type (T__2); - | @typeFormal(\U) @typeDefined(U__1) @fromType(Satisfying__0) let U__1; - | U__1 = type (U__1); - | Satisfying__0 extends Simple__0; - | @fn @visibility(\public) @stay @fromType(Satisfying__0) let constructor__1; - | constructor__1 = (@stay fn constructor(@impliedThis(Satisfying__0) this__1: Satisfying__0) /* return__1 */: Void {}); - | class(\word, \Satisfying, \concrete, true, @typeDefined(Satisfying__0) fn { - | do {}; - | do {}; - | do {}; - | do {} - | }); - | type (Satisfying__0) - | - | ``` - | }, - | errors: [ - | "Cannot introduce type parameters in sealed subtype Subversive__0!", - | ], - |} - """.trimMargin(), + stageTestDir = StageTestDir("define/sealed-subtypes-reject-new-type-params"), ) @Test fun resolutionsStoredWithPostponedCaseCases() = assertModuleAtStage( - stage = Stage.Define, - input = """ - |let y = 123; - |when (x) { - | case f(let y) -> handleIt(); - | else -> fallback(); - |} - """.trimMargin(), - want = """ - |{ - | define: { - | body: ``` - | let y__0; - | y__0 = 123; - | do { - | if(postponedCase(([\f, "(", \let, \y, ")"]), x, \y, y__0), fn { - | handleIt() - | }, \else, fn (f#0) { - | f#0(fn { - | fallback() - | }) - | }) - | } - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("define/resolutions-stored-with-postponed-case-cases"), ) @Test fun jsonInteropMixedIn() = assertModuleAtStage( - stage = Stage.Define, - input = $$""" - |@json class Point( - | public let x: Int, - | public let y: Int, - |) { - | public toString(): String { "(${x}, ${y})" } - |} - """.trimMargin(), + stageTestDir = StageTestDir("define/json-interop-mixed-in"), // ## lines below are stripped, explanatory comments. - want = """ - |{ - | define: { - | types: { - | "AnyValue": "__DO_NOT_CARE__", - | "Int32": "__DO_NOT_CARE__", - | "InterchangeContext": "__DO_NOT_CARE__", - | "JsonAdapter": "__DO_NOT_CARE__", - | "JsonNumeric": "__DO_NOT_CARE__", - | "JsonObject": "__DO_NOT_CARE__", - | "JsonProducer": "__DO_NOT_CARE__", - | "JsonSyntaxTree": "__DO_NOT_CARE__", - | "Point": { - | supers: [ - | "AnyValue__0", - | ], - | methods: [ - | { - | name: "getx__0", - | symbol: "x", - | visibility: "public", - | kind: "Getter", - | open: false, - | }, - | { - | name: "gety__0", - | symbol: "y", - | visibility: "public", - | kind: "Getter", - | open: false, - | }, - | { - | name: "toString__0", - | visibility: "public", - | open: false, - | }, - | { - | name: "constructor__1", - | visibility: "public", - | open: false, - | kind: "Constructor", - | }, - | { - | name: "encodeToJson__1", - | visibility: "public", - | open: false, - | }, - | ], - | properties: [ - | { - | name: "x__0", - | visibility: "public", - | abstract: false, - | getter: "getx__0", - | }, - | { - | name: "y__0", - | visibility: "public", - | abstract: false, - | getter: "gety__0", - | }, - | ], - | staticProperties: [ - | { - | name: "decodeFromJson__1", - | visibility: "public", - | }, - | { - | name: "jsonAdapter__0", - | visibility: "public", - | }, - | ], - | metadata: { - | "json": ["void: Void"], - | "QName": ["\"test-code.type Point\": String"], - | } - | }, - | "PointJsonAdapter": { - | supers: [ - | [ - | "Nominal", - | "std//json/.JsonAdapter", - | "Point__0", - | ], - | ], - | methods: [ - | { - | name: "encodeToJson__0", - | visibility: "public", - | open: false, - | }, - | { - | name: "decodeFromJson__0", - | visibility: "public", - | open: false, - | }, - | { - | name: "constructor__0", - | visibility: "public", - | open: false, - | kind: "Constructor", - | }, - | ], - | }, - | "String": "__DO_NOT_CARE__", - | "Void": "__DO_NOT_CARE__", - | }, - | body: ``` - |## Here are members for the generated JSON adapter class - | PointJsonAdapter__0 extends JsonAdapter; - | @visibility(\public) @fn @stay @fromType(PointJsonAdapter__0) let encodeToJson__0; - | encodeToJson__0 = (@stay fn (@impliedThis(PointJsonAdapter__0) this__0: PointJsonAdapter__0, x__1: Point__0, p__0: JsonProducer) /* return__0 */: Void { - | do_call_encodeToJson(x__1, p__0) - | }); - | @visibility(\public) @fn @stay @fromType(PointJsonAdapter__0) let decodeFromJson__0; - | decodeFromJson__0 = fn (@impliedThis(PointJsonAdapter__0) this__1: PointJsonAdapter__0, t__0: JsonSyntaxTree, ic__0: InterchangeContext) /* return__1 */: (Point__0 | Bubble) { - | getStatic(Point__0, \decodeFromJson)(t__0, ic__0) - | }; - |## It's got an implied constructor even though that wasn't mentioned in the JsonInteropPass - | @fn @visibility(\public) @stay @fromType(PointJsonAdapter__0) let constructor__0; - | constructor__0 = (@stay fn constructor(@impliedThis(PointJsonAdapter__0) this__2: PointJsonAdapter__0) /* return__2 */: Void {}); - | @typeDecl(PointJsonAdapter__0) @stay let PointJsonAdapter__0; - | PointJsonAdapter__0 = type (PointJsonAdapter__0); - |## Here's the declaration for the non-generated point type - | @typeDecl(Point__0) @stay @json let Point__0; - | Point__0 = type (Point__0); - | class (\word, \PointJsonAdapter, \concrete, true, @typeDefined(PointJsonAdapter__0) fn { - | do {}; - | do {}; - | do {}; - | do {} - | }); - | do {}; - |## Here's the explicitly declared point class type variable - | Point__0 extends AnyValue; - | @constructorProperty @visibility(\public) @stay @fromType(Point__0) let x__0: Int32; - | @constructorProperty @visibility(\public) @stay @fromType(Point__0) let y__0: Int32; - | @visibility(\public) @fn @stay @fromType(Point__0) let toString__0; - | toString__0 = fn toString(@impliedThis(Point__0) this__3: Point__0) /* return__3 */: String { - | fn__0: do { - | cat("(", str(getp(x__0, this__3)), ", ", str(getp(y__0, this__3)), ")") - | } - | }; - | @fn @visibility(\public) @stay @fromType(Point__0) let constructor__1; - | constructor__1 = fn constructor(@impliedThis(Point__0) this__4: Point__0, x__2 /* aka x */: Int32, y__1 /* aka y */: Int32) /* return__4 */: Void { - | do { - | let t#0; - | setp(x__0, this__4, t#0 = x__2); - | t#0 - | }; - | do { - | let t#1; - | setp(y__0, this__4, t#1 = y__1); - | t#1 - | }; - | }; - | @fn @visibility(\public) @stay @fromType(Point__0) let getx__0; - | getx__0 = fn (@impliedThis(Point__0) this__5: Point__0) /* return__5 */: Int32 { - | return__5 = getp(x__0, this__5) - | }; - | @fn @visibility(\public) @stay @fromType(Point__0) let gety__0; - | gety__0 = fn (@impliedThis(Point__0) this__6: Point__0) /* return__6 */: Int32 { - | return__6 = getp(y__0, this__6) - | }; - |## Here is the encodeToJson method added to point. - | @visibility(\public) @fn @stay @fromType(Point__0) let encodeToJson__1; - | encodeToJson__1 = fn (@impliedThis(Point__0) this__7: Point__0, p__1: JsonProducer) /* return__7 */: Void { - | do_call_startObject(p__1); - | do_call_objectKey(p__1, "x"); - |## `this` in the generated expression `this.x` got rewritten to `this__7`, after - |## the regular type processing pass adds that implied parameter. - | do_call_int32Value(p__1, getp(x__0, this__7)); - | do_call_objectKey(p__1, "y"); - | do_call_int32Value(p__1, getp(y__0, this__7)); - | do_call_endObject(p__1); - | }; - | @static @visibility(\public) @fn @stay @fromType(Point__0) let decodeFromJson__1; - | decodeFromJson__1 = (@stay fn (t__1: JsonSyntaxTree, ic__1: InterchangeContext) /* return__8 */: (Point__0 | Bubble) { - | let obj__0; - | obj__0 = t__1 as JsonObject; - | let x__3: Int32, y__2: Int32; - | x__3 = do_call_asInt32(do_call_propertyValueOrBubble(obj__0, "x") as JsonNumeric); - | y__2 = do_call_asInt32(do_call_propertyValueOrBubble(obj__0, "y") as JsonNumeric); - | new Point__0(x__3, y__2) - | }); - | @static @visibility(\public) @fn @stay @fromType(Point__0) let jsonAdapter__0; - | jsonAdapter__0 = (@stay fn /* return__9 */: (JsonAdapter) { - | new PointJsonAdapter__0() - | }); - | class(\word, \Point, \concrete, true, @typeDefined(Point__0) fn { - | do {}; - | do {}; - | do {}; - | do {}; - | do {}; - | do {}; - | do {}; - | do {}; - | do {}; - | do {} - | }); - |## The terminal expression is not affected. - | type (Point__0) - | - | ``` - | }, - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), ) @Test fun nullableTypesResolved() = assertModuleAtStage( - stage = Stage.Define, - input = """ - |let intOrNull: Int?; - """.trimMargin(), - want = """ - |{ - | define: { - | body: { - | tree: [ "Block", [ - | [ "Decl", [ - | [ "LeftName", "intOrNull__0" ], - | [ "Value", "\\type: Symbol" ], - | [ "Value", "Int32?: Type" ], - | [ "Value", "\\QName: Symbol" ], - | [ "Value", "\"test-code.intOrNull\": String" ], - | [ "Value", "\\ssa: Symbol" ], - | [ "Value", "void: Void" ], - | ] - | ], - | [ "Value", "void: Void" ], - | ] - | ], - | code: ``` - | let intOrNull__0: Int32?; - | - | ``` - | } - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("define/nullable-types-resolved"), ) @Test fun propertyBagsDesugarToPositionalParameters() = assertModuleAtStage( - stage = Stage.Define, - input = """ - |let { Point } = import("./point"); - |export let p = { x: 1, y: 2 }; - |export let q = { y: p.y, x: p.x }; - | - |$TEST_INPUT_MODULE_BREAK ./point/point.temper - |export class Point(public x: Int, public y: Int) {} - """.trimMargin(), - want = """ - |{ - | define: { - | body: ``` - | @stay @imported(\(`test//point/`.Point)) let Point__0; - | Point__0 = type (Point); - | let `test//`.p; - |## Here's a reworked property bag that we don't muck with, much. - | `test//`.p = new Point(1, 2); - | let `test//`.q; - |## This one becomes a do-block because we need to preserve OoO. - | `test//`.q = do { - | let y#0; - | y#0 = do_get_y(`test//`.p); - | let x#0; - | x#0 = do_get_x(`test//`.p); - | new Point(x#0, y#0) - | }; - | - | ```` - | } - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), + stageTestDir = StageTestDir("define/property-bags-desugar-to-positional-parameters"), ) @Test fun propertyBagsDesugaringWithOptionalParameters() = assertModuleAtStage( - stage = Stage.Define, - input = """ - |let { C } = import("./c"); - |export let c = { x: 1, z: 2 } - | - |$TEST_INPUT_MODULE_BREAK ./c/c.temper - |export class C(public x: Int, public y: Int = 0, public z: Int = 0) {} - """.trimMargin(), - want = """ - |{ - | define: { - | body: ``` - | @stay @imported(\(`test//c/`.C)) let C__0; - | C__0 = type (C); - | let `test//`.c; - |## Here's a reworked property bag that we don't muck with, much. - | `test//`.c = new C(1, null, 2); - | - | ```` - | } - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), + stageTestDir = StageTestDir("define/property-bags-desugaring-with-optional-parameters"), ) @Test fun accumulatorTypeUse() = assertModuleAtStage( - stage = Stage.Define, - input = $$""" - |let { theCount } = import("./the-count"); - | - |theCount$${"\"\"\""} - | "Zero: ${0} - | // ↑ Starting at zero, because the Count is not a monster. - | "One: ${1} - | : for (let n of [2, 3, 4]) { - | ~ ${n} - | : } - | "! - | ~Five: ${5} - | ; - | - |theCount"${6}, ${7}" - | - |$$TEST_INPUT_MODULE_BREAK ./the-count/the-count.temper - |class TheCount { - | public append(i: Int): Void { - | console.log("${i}! Ha Ha Ha!"); - | } - | public appendSafe(s: String): Void {} - | - | public get accumulated(): Void { - | console.log("I am the Count who loves to count!"); - | } - |} - | - |export let theCount = TheCount; - """.trimMargin(), - want = """ - |{ - | define: { - | body: ``` - | @stay @imported(\(`test//the-count/`.theCount)) let theCount__0; - | theCount__0 = type (TheCount__0); - | do { - | let accumulator#0; - |## The tag is used to create an accumulator - | accumulator#0 = new TheCount__0(); - |## We inlined the body here. - | do { - | do_call_appendSafe(accumulator#0, "Zero: "); - |## Unsafe interpolations become regular appends. - | do_call_append(accumulator#0, 0); - | do_call_appendSafe(accumulator#0, "\nOne: "); - | do_call_append(accumulator#0, 1); - | do_call_appendSafe(accumulator#0, "\n"); - |## The loop becomes just a regular forEach application and the content are appends. - | do_call_forEach(list(2, 3, 4), fn (n__0) { - | do_call_appendSafe(accumulator#0, " "); - | do_call_append(accumulator#0, n__0); - | }); - | do_call_appendSafe(accumulator#0, "!\nFive: "); - | do_call_append(accumulator#0, 5); - | }; - |## We inject a `.accumulated` fetch for the block result - | do_get_accumulated(accumulator#0) - | }; - | do { - | let accumulator#1; - | accumulator#1 = new TheCount__0(); - | do { - | do_call_append(accumulator#1, 6); - | do_call_appendSafe(accumulator#1, ", "); - | do_call_append(accumulator#1, 7) - | }; - | do_get_accumulated(accumulator#1) - | } - | - | ``` - | } - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), + stageTestDir = StageTestDir("define/accumulator-type-use"), ) @Test fun accumulatorTypeUseNoStmt() = assertModuleAtStage( - stage = Stage.Define, - input = $$""" - |let { theCount } = import("./the-count"); - | - |theCount$${"\"\"\""} - | "Zero: ${0} - | "One: ${1} - | "Two: ${2} - | "Three: ${3} - | "F\our: ${4} - | "Five: ${5} - | ; - | - |theCount"${6}, ${7}" - | - |$$TEST_INPUT_MODULE_BREAK ./the-count/the-count.temper - |class TheCount { - | public append(i: Int): Void { - | console.log("${i}! Ha Ha Ha!"); - | } - | public appendSafe(s: String): Void {} - | - | public get accumulated(): Void { - | console.log("I am the Count who loves to count!"); - | } - |} - | - |export let theCount = TheCount; - """.trimMargin(), - want = """ - |{ - | define: { - | body: ``` - | @stay @imported(\(`test//the-count/`.theCount)) let theCount__0; - | theCount__0 = type (TheCount__0); - | do { - | let accumulator#0; - |## The tag is used to create an accumulator - | accumulator#0 = new TheCount__0(); - |## We inlined the body here. - | do { - | do_call_appendSafe(accumulator#0, "Zero: "); - |## Unsafe interpolations become regular appends. - | do_call_append(accumulator#0, 0); - | do_call_appendSafe(accumulator#0, "\nOne: "); - | do_call_append(accumulator#0, 1); - | do_call_appendSafe(accumulator#0, "\nTwo: "); - | do_call_append(accumulator#0, 2); - | do_call_appendSafe(accumulator#0, "\nThree: "); - | do_call_append(accumulator#0, 3); - | do_call_appendSafe(accumulator#0, "\nF\\our: "); - | do_call_append(accumulator#0, 4); - | do_call_appendSafe(accumulator#0, "\nFive: "); - | do_call_append(accumulator#0, 5); - | do_call_appendSafe(accumulator#0, "\n") - | }; - |## We inject a `.accumulated` fetch for the block result - | do_get_accumulated(accumulator#0) - | }; - | do { - | let accumulator#1; - | accumulator#1 = new TheCount__0(); - | do { - | do_call_append(accumulator#1, 6); - | do_call_appendSafe(accumulator#1, ", "); - | do_call_append(accumulator#1, 7) - | }; - | do_get_accumulated(accumulator#1) - | } - | - | ``` - | } - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), + stageTestDir = StageTestDir("define/accumulator-type-use-no-stmt"), ) @Test fun escapeSequenceGrouping() = assertModuleAtStage( - stage = Stage.Define, - input = $$""" - |let { html } = import ("./html"); - |html"" - |$$TEST_INPUT_MODULE_BREAK ./html/html.temper - |export class HtmlBuilder {} - |export let html = HtmlBuilder; - """.trimMargin(), - want = """ - |{ - | define: { - | body: ``` - | @stay @imported(\(`test//html/`.html)) let html__0; - | html__0 = type (HtmlBuilder); - | do { - | let accumulator#0; - | accumulator#0 = new HtmlBuilder(); - | do { - | do_call_appendSafe(accumulator#0, raw "") - | }; - | do_get_accumulated(accumulator#0) - | } - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("define/escape-sequence-grouping"), ) @Test fun operatorDecoratorArityInference() = assertModuleAtStage( - stage = Stage.Define, - input = """ - |@operator("+") - |let mixedAdd(a: Int, b: Boolean): Int { - | if (b) { a + 1 } else { a } - |} - | - |class C { - | @operator("+") - | public f(other: C): C { this } - | - | @operator("+") - | public static unary(c: C): C { c } - |} - """.trimMargin(), - want = """ - |{ - | define: { - | body: ``` - |## mixedAdd has arity 2 so gets an infix operator specifier - | @fn @operator("_+_") let mixedAdd__0; - | @typeDecl(C__0) @stay let C__0; - | C__0 = type (C__0); - | mixedAdd__0 = fn mixedAdd(a__0 /* aka a */: Int32, b__0 /* aka b */: Boolean) /* return__0 */: Int32 { - | fn__0: do { - | if(b__0, fn { - | a__0 + 1 - | }, \else, fn (f#0) { - | f#0(fn { - | a__0 - | }) - | }) - | } - | }; - | C__0 extends AnyValue; - |## The instance method has an implied `this` so also gets an infix operator specifier - | @visibility(\public) @fn @operator("_+_") @stay @fromType(C__0) let f__0; - | f__0 = fn f(@impliedThis(C__0) this__0: C__0, other__0 /* aka other */: C__0) /* return__1 */: C__0 { - | fn__1: do { - | this__0 - | } - | }; - |## The static method has no implied `this` so gets a prefix operator specifier - | @fn @static @visibility(\public) @operator("+_") @stay @fromType(C__0) let unary__0; - | unary__0 = (@stay fn unary(c__0 /* aka c */: C__0) /* return__2 */: C__0 { - | fn__2: do { - | c__0 - | } - | }); - | @fn @visibility(\public) @stay @fromType(C__0) let constructor__0; - | constructor__0 = (@stay fn constructor(@impliedThis(C__0) this__1: C__0) /* return__3 */: Void {}); - | class(\word, \C, \concrete, true, @typeDefined(C__0) fn { - | do {}; - | do {}; - | do {}; - | do {} - | }); - | type (C__0) - | - | ``` - | } - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), + stageTestDir = StageTestDir("define/operator-decorator-arity-inference"), ) } diff --git a/frontend/src/commonTest/kotlin/lang/temper/frontend/DisAmbiguateStageTest.kt b/frontend/src/commonTest/kotlin/lang/temper/frontend/DisAmbiguateStageTest.kt index 4d006291..31d3111d 100644 --- a/frontend/src/commonTest/kotlin/lang/temper/frontend/DisAmbiguateStageTest.kt +++ b/frontend/src/commonTest/kotlin/lang/temper/frontend/DisAmbiguateStageTest.kt @@ -3,14 +3,10 @@ package lang.temper.frontend import lang.temper.common.Freq3 -import lang.temper.common.testCodeLocation import lang.temper.interp.MetadataDecorator import lang.temper.lexer.Genre -import lang.temper.lexer.StandaloneLanguageConfig -import lang.temper.log.MessageTemplate import lang.temper.name.BuiltinName import lang.temper.name.Symbol -import lang.temper.stage.Stage import lang.temper.value.PseudoCodeDetail import lang.temper.value.Value import lang.temper.value.void @@ -19,833 +15,109 @@ import kotlin.test.Test class DisAmbiguateStageTest { @Test fun unknownFunctionWithFormalGetsError() = assertModuleAtStage( - stage = Stage.DisAmbiguate, - // ↓↓↓ ↓↓↓↓↓ ↓↓↓ - input = "foo f(a = 1, b: Int) { g(a = 1, b) }", - // 0123456789012345678901234567890123456 - // 1 2 3 - want = """ - { - "disAmbiguate": { - body: - [ "Block", [ - [ "Call", [ - [ "RightName", "foo" ], - [ "Value", [ "word", "Symbol" ] ], - [ "LeftName", "f" ], - // Named actuals forbidden. - [ "Call", [ [ "Value", ["error", "Function"] ] ] ], - // Formal stuff discarded. - [ "RightName", "b" ], - - [ "Fun", [ - [ "Block", [ - [ "Call", [ - [ "RightName", "g" ], - [ "Call", [ [ "Value", ["error", "Function"] ] ] ], - [ "RightName", "b" ], - ] - ] - ] - ] - ] - ] - ] - ] - ] - ], - }, - errors: [ - { - template: "NamedActual", - values: [], - left: 25, - right: 28 - }, - { - template: "NamedActual", - values: [], - left: 6, - right: 9 - }, - { - template: "MalformedActual", - values: [], - left: 14, - right: 19 - }, - ] - } - """, + stageTestDir = StageTestDir("dis-ambiguate/unknown-function-with-formal-gets-error"), ) @Test fun formalsFormalizedAndActualsActualized() = assertModuleAtStage( - stage = Stage.DisAmbiguate, - input = "let f(a = 1, b: Int) { g(a = 1, b) }", - // 0123456789012345678901234567890123456 - // 1 2 3 - want = """ - { - disAmbiguate: { - body: - [ "Block", [ - [ "Call", [ - [ "RightName", "let" ], - [ "Value", [ "word", "Symbol" ] ], - [ "LeftName", "f" ], - // First formalized formal - [ "Decl", [ - [ "LeftName", "a" ], - [ "Value", [ "default", "Symbol" ] ], - [ "Value", [ 1, "Int32" ] ], - [ "Value", [ "word", "Symbol" ] ], - [ "Value", [ "a", "Symbol" ] ] - ] - ], - [ "Decl", [ - [ "LeftName", "b" ], - [ "Value", [ "type", "Symbol" ] ], - [ "RightName", "Int" ], - [ "Value", [ "word", "Symbol" ] ], - [ "Value", [ "b", "Symbol" ] ] - ] - ], - [ "Fun", [ - [ "Block", [ - [ "Call", [ - [ "RightName", "g" ], - [ "Call", [ [ "Value", ["error", "Function"] ] ] ], - [ "RightName", "b" ], - ] - ] - ] - ] - ] - ] - ] - ] - ] - ] - }, - errors: [ - "${MessageTemplate.NamedActual.formatString}!" - ] - } - """, + stageTestDir = StageTestDir("dis-ambiguate/formals-formalized-and-actuals-actualized"), ) @Test fun formalsAndActualsWithEmbeddedComments() = assertModuleAtStage( - stage = Stage.DisAmbiguate, - input = "let f(/** docs */ a: Int) { g(/** here too? */ 1) }", - want = """ - |{ - | disAmbiguate: { - | body: - | [ "Block", [ - | [ "Call", [ - | [ "RightName", "let" ], - | [ "Value", [ "word", "Symbol" ] ], - | [ "LeftName", "f" ], - | - | [ "Decl", [ - | [ "LeftName", "a" ], - | [ "Value", [ "type", "Symbol" ] ], - | [ "RightName", "Int" ], - | [ "Value", [ "word", "Symbol" ] ], - | [ "Value", [ "a", "Symbol" ] ], - | [ "Value", [ "docString", "Symbol" ] ], - | [ "Value", [ "[\"docs\", \"docs\", \"test/test.temper\"]", "List" ] ], - | ] - | ], - | [ "Fun", [ - | [ "Block", [ - | [ "Call", [ - | [ "RightName", "g" ], - | [ "Value", [ 1, "Int32" ] ], - | ] - | ] - | ] - | ] - | ] - | ] - | ] - | ] - | ] - | ] - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("dis-ambiguate/formals-and-actuals-with-embedded-comments"), ) @Test fun annotatedFormal() = assertModuleAtStage( - stage = Stage.DisAmbiguate, - input = "fn f(@A @B x) {}", - want = """ - { - disAmbiguate: { - body: - [ "Block", [ - [ "Call", [ - [ "RightName", "fn" ], - [ "Value", "\\word: Symbol" ], - [ "LeftName", "f" ], - [ "Call", [ - [ "RightName", "@A" ], - [ "Call", [ - [ "RightName", "@B" ], - [ "Decl", [ - [ "LeftName", "x" ], - [ "Value", "\\word: Symbol" ], - [ "Value", "\\x: Symbol" ] - ] - ] - ] - ] - ] - ], - [ "Fun", [ [ "Block", [] ] ] ] - ] - ] - ] - ], - } - } - """, + stageTestDir = StageTestDir("dis-ambiguate/annotated-formal"), ) @Test fun stagingAnnotation() = assertModuleAtStage( - stage = Stage.DisAmbiguate, - input = "@(A..S) fn (x) {}", + stageTestDir = StageTestDir("dis-ambiguate/staging-annotation"), stagingFlags = setOf(StagingFlags.skipImportCore), - want = """ - { - disAmbiguate: { - body: - [ "Block", [ - [ "Call", [ - [ "Call", [ // @ distributed over .. - // Application of this doesn't happen until syntax stage where declaration - // macros desugar. - [ "RightName", ".." ], - [ "RightName", "@A" ], - [ "RightName", "@S" ] - ] - ], - [ "Call", [ - [ "RightName", "fn" ], - [ "Decl", [ - [ "LeftName", "x" ], - [ "Value", [ "word", "Symbol" ] ], - [ "Value", [ "x", "Symbol" ] ] - ] - ], - [ "Fun", [ - [ "Block", [] ] - ] - ] - ] - ] - ] - ] - ] - ] - }, - /* TODO: actual application of @A..S to the function. - syntax: { - body: [ "Decl", [ - [ "Value", "\\liveness: Symbol" ], - [ "Value", [ "@(A..S)", "StageRange" ] ], - ] - ] - } - */ - } - """, ) @Test fun bunchOfStuff() = assertModuleAtStage( - stage = Stage.DisAmbiguate, - input = $$""" - a + b * c; - - 42; - - let x = 1; - - // What is going on here? - console.log("foo ${"bar ${"qux ${xyzzy}"}"} baz" ); - - // comment - """.trimIndent(), - want = """ - { - disAmbiguate: { - body: - ``` - a + b * c; - 42; - let x = 1; - REM("What is going on here?", null, false); - console.log(cat("foo ", str(cat("bar ", str(cat("qux ", str(xyzzy))))), " baz")); - - ``` - } - } - """, + stageTestDir = StageTestDir("dis-ambiguate/bunch-of-stuff"), ) @Test fun blockFormals() = assertModuleAtStage( - stage = Stage.DisAmbiguate, - input = """ - f { x: Int, y: Int => x + y } - """, - want = """ - { - disAmbiguate: { - body: { - tree: - [ "Block", [ - [ "Call", [ - [ "RightName", "f" ], - [ "Fun", [ - [ "Decl", [ - [ "LeftName", "x" ], - [ "Value", "\\type: Symbol" ], - [ "RightName", "Int" ], - [ "Value", "\\word: Symbol" ], - [ "Value", "\\x: Symbol" ] - ] - ], - [ "Decl", [ - [ "LeftName", "y" ], - [ "Value", "\\type: Symbol" ], - [ "RightName", "Int" ], - [ "Value", "\\word: Symbol" ], - [ "Value", "\\y: Symbol" ] - ] - ], - [ "Block", [ - [ "Call", [ - [ "Value", "nym`do_call__+_`[PlusIntInt, PlusIntInt64, PlusFltFlt]: Function" ], - [ "RightName", "x" ], - [ "RightName", "y" ] - ] - ] - ] - ] - ] - ] - ] - ] - ] - ], - - "code": - ``` - f(fn (x /* aka x */: Int, y /* aka y */: Int) { - x + y - }) - - ``` - } - } - } - """, + stageTestDir = StageTestDir("dis-ambiguate/block-formals"), ) @Test fun classBodyAmbiguityReduction() = assertModuleAtStage( - stage = Stage.DisAmbiguate, - input = """ - class C { // This is a class body - var decl = 0; - let cDecl; - property0; - public property1: T; - property2 = initial; - property3: T = initial; - method1() { 123 } - method2(): T { 123 } - method3(x: U = 123) { 123 } - let method4(x: V) { 123 } - get p(@Foo this): T { property1 } - set p(x) { this.property1 = x } - } - do { // This is not a class body, and the parts about properties/methods are ALL LIES! - var decl = 0; - let cDecl; - property0; - public property1: T; - property2 = initial; - property3: T = initial; - method1() { 123 } - method2(): T { 123 } - method3(x: U = 123) { 123 } // Error on line 24 - let method4(x: V) { 123 } - get p(@Foo this): T { property1 } - set p(x) { this.property1 = x } - } - """.trimIndent(), + stageTestDir = StageTestDir("dis-ambiguate/class-body-ambiguity-reduction"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - { - disAmbiguate: { - body: - ``` - @typeDecl(C__0) @hoistLeft(true) @resolution(C__0) @stay let C = type (C__0); - class(\word, C, \concrete, true, @typeDefined(C__0) fn { - C__0 extends AnyValue; - REM("This is a class body", null, false); - @property(\decl) var decl = 0; - @property(\cDecl) let cDecl; - @property(\property0) @maybeVar let property0; - @property(\property1) @maybeVar @visibility(\public) let property1: T; - @property(\property2) @maybeVar let property2 = initial; - @property(\property3) @maybeVar let property3: T = initial; - @method(\method1) let method1 = fn(\word, method1, @impliedThis(C__0) let this__1: C__0, fn { - 123 - }); - @method(\method2) let method2 = fn(\word, method2, @impliedThis(C__0) let this__2: C__0, \outType, T, fn { - 123 - }); - @method(\method3) let method3 = fn(\word, method3, @impliedThis(C__0) let this__3: C__0, @default(123) let x /* aka x */: U, fn { - 123 - }); - @method(\method4) let method4 = fn(\word, method4, @impliedThis(C__0) let this__4: C__0, let x /* aka x */: V, fn { - 123 - }); - @method(\p) @getter let nym`get.p` = fn(\word, nym`get.p`, nym`@Foo`(@impliedThis(C__0) let this__5: C__0), \outType, T, fn { - property1 - }); - @method(\p) @setter let nym`set.p` = fn(\word, nym`set.p`, @impliedThis(C__0) let this__6: C__0, let x /* aka x */, \outType, type (Void), fn { - this(C__0).property1 = x - }); - }); - do(fn { - REM("This is not a class body, and the parts about properties/methods are ALL LIES!", null, false); - var decl = 0; - let cDecl; - property0; - nym`@public`((property1) : (T)); - property2 = initial; - ((property3) : (T)) = initial; - method1(fn { - 123 - }); - method2(\outType, T, fn { - 123 - }); - method3(error (), fn { - 123 - }); - REM("Error on line 24", null, false); - let(\word, method4, let x /* aka x */: V, fn { - 123 - }); - get(\word, p, nym`@Foo`(this()), \outType, T, fn { - property1 - }); - set(\word, p, x, fn { - this().property1 = x - }) - }) - - ```, - types: { - AnyValue: { - abstract: true - }, - C: { - word: "C" - }, - Void: { - supers: [] - }, - }, - }, - errors: [ - "${MessageTemplate.MalformedActual.formatString}!", - "${MessageTemplate.NamedActual.formatString}!", - ] - } - """, ) @Test fun typeFormalsOnClassDeclaration() = assertModuleAtStage( - stage = Stage.DisAmbiguate, - input = """ - |class C extends A, B {} - """.trimMargin(), + stageTestDir = StageTestDir("dis-ambiguate/type-formals-on-class-declaration"), stagingFlags = setOf(StagingFlags.skipImportCore), - want = """ - |{ - | disAmbiguate: { - | body: - | ``` - | @typeDecl(C__0) @hoistLeft(true) @resolution(C__0) @stay let C = type (C__0); - | class(\word, C, \concrete, true, @typeDefined(C__0) fn { - | @typeFormal(\T) @typeDefined(T__1) @resolution(T__1) let T = type (T__1); - | @typeFormal(\U) @typeDefined(U__2) @resolution(U__2) let U = type (U__2); - | @typeFormal(\V) @typeDefined(V__3) @resolution(V__3) @stay @variance(1) let V = type (V__3); - | @typeFormal(\W) @typeDefined(W__4) @resolution(W__4) @stay @variance(-1) let W = type (W__4); - | U extends D; - | C__0 extends A; - | C__0 extends B - | }); - | C - | - | ```, - | types: { - | C: { - | word: "C", - | typeParameters: [ - | { name: "T__1" }, - | { name: "U__2" }, - | { name: "V__3" }, - | { name: "W__4" }, - | ] - | }, - | T: { name: "T__1", word: "T" }, - | U: { name: "U__2", word: "U", upperBounds: [] }, // UpperBound D should fill in later - | V: { name: "V__3", word: "V", variance: "Covariant" }, - | W: { name: "W__4", word: "W", variance: "Contravariant" }, - | } - | } - |} - """.trimMargin(), ) @Test fun genericFnWithComplexTypeFormal() = assertModuleAtStage( - stage = Stage.DisAmbiguate, + stageTestDir = StageTestDir("dis-ambiguate/generic-fn-with-complex-type-formal"), stagingFlags = setOf(StagingFlags.skipImportCore), - input = """ - |let f<@in T extends MapKey>(x: T): Void {} - """.trimMargin(), - want = """ - |{ - | disAmbiguate: { - | body: - | ``` - | let(\word, f, \typeFormal, do { - | @resolution(T__0) @typeFormal(\T) @typeDecl(T__0) @stay let T = type (T__0); - | T__0 extends MapKey; - | type (T__0) - | }, let x /* aka x */: T, \outType, Void, fn {}) - | - | ``` - | } - |} - """.trimMargin(), ) @Test fun moreDecoratedTypeFormals() = assertModuleAtStage( - stage = Stage.DisAmbiguate, + stageTestDir = StageTestDir("dis-ambiguate/more-decorated-type-formals"), // No, `@partialImu` doesn't make sense here, but it allows for testing multiple decorators. - input = """ - |class C<@in @imu T> {} - |class D<@imu @in T> {} - |let f<@imu @partialImu T>(t: T): Void {} - """.trimMargin(), - want = """ - |{ - | disAmbiguate: { - | body: - | ``` - | @typeDecl(C__0) @hoistLeft(true) @resolution(C__0) @stay let C = type (C__0); - | class(\word, C, \concrete, true, @typeDefined(C__0) fn { - | @typeFormal(\T) @typeDefined(T__0) @resolution(T__0) @stay @variance(-1) @imu let T = type (T__0); - | C__0 extends AnyValue - | }); - | @typeDecl(D__0) @hoistLeft(true) @resolution(D__0) @stay let D = type (D__0); - | class(\word, D, \concrete, true, @typeDefined(D__0) fn { - | @typeFormal(\T) @typeDefined(T__1) @resolution(T__1) @stay @variance(-1) @imu let T = type (T__1); - | D__0 extends AnyValue - | }); - | let(\word, f, \typeFormal, do { - | @resolution(T__2) @typeFormal(\T) @typeDecl(T__2) @stay @partialImu @imu let T = type (T__2); - | type (T__2) - | }, let t /* aka t */: T, \outType, Void, fn {}) - | - | ``` - | } - |} - """.trimMargin(), ) @Test fun genericMethodsDisallowedInInterface() = assertModuleAtStage( - stage = Stage.DisAmbiguate, + stageTestDir = StageTestDir("dis-ambiguate/generic-methods-disallowed-in-interface"), stagingFlags = setOf(StagingFlags.skipImportCore), // Generic instance methods should be reported. Variety here is just to be sure about internal forms. // Static methods in interfaces can be generic if they want. - input = """ - |interface Whatever { - | blather(a: A): A; - | public let bling(b: B, c: C): B { b } - | static blot(d: D): D; - |} - """.trimMargin(), - want = """ - |{ - | disAmbiguate: { - | body: ``` - | @typeDecl(Whatever__0) @hoistLeft(true) @resolution(Whatever__0) @stay let Whatever = type (Whatever__0); - | interface(\word, Whatever, \concrete, false, @typeDefined(Whatever__0) fn { - | Whatever__0 extends AnyValue; - | let blather = fn(\word, blather, \typeFormal, do { - | @resolution(A__0) @typeFormal(\A) @typeDecl(A__0) let A = type (A__0); - | type (A__0) - | }, @impliedThis(Whatever__0) let this__0: Whatever__0, let a /* aka a */: A, \outType, A, fn { - | pureVirtual() - | }); - | @visibility(\public) let bling = fn(\word, bling, \typeFormal, do { - | @resolution(B__0) @typeFormal(\B) @typeDecl(B__0) let B = type (B__0); - | type (B__0) - | }, \typeFormal, do { - | @resolution(C__0) @typeFormal(\C) @typeDecl(C__0) let C = type (C__0); - | C__0 extends Whatever; - | type (C__0) - | }, @impliedThis(Whatever__0) let this__1: Whatever__0, let b /* aka b */: B, let c /* aka c */: C, \outType, B, fn { - | b - | }); - | @fn @static let blot = fn(\word, blot, \typeFormal, do { - | @resolution(T__1) @typeFormal(\T) @typeDecl(T__1) let T = type (T__1); - | type (T__1) - | }, let d /* aka d */: D, \outType, D, fn { - | pureVirtual() - | }); - | }); - | Whatever - | - | ``` - | }, - | errors: [ - | "Illegal type parameter A. Overridable methods don't allow generics!", - | "Illegal type parameter B. Overridable methods don't allow generics!", - | "Illegal type parameter C. Overridable methods don't allow generics!", - | ], - |} - """.trimMargin(), ) @Test fun multipleKeywordAnnotationsAllFire() = assertModuleAtStage( - stage = Stage.DisAmbiguate, - input = "public static let x", - want = """ - { - disAmbiguate: { - body: - [ "Block", [ - [ "Decl", [ - [ "LeftName", "x" ], - [ "Value", "\\static: Symbol" ], - [ "Value", "void: Void" ], - [ "Value", "\\visibility: Symbol" ], - [ "Value", "\\public: Symbol" ], - ] - ] - ] - ] - } - } - """, + stageTestDir = StageTestDir("dis-ambiguate/multiple-keyword-annotations-all-fire"), ) @Test fun unrecognizedDecorationsPreservedForLater() = assertModuleAtStage( - stage = Stage.DisAmbiguate, - input = "@foo @bar let x", - want = """ - { - disAmbiguate: { - body: "nym`@foo`(nym`@bar`(let x))\n" - }, - } - """, + stageTestDir = StageTestDir("dis-ambiguate/unrecognized-decorations-preserved-for-later"), ) @Test fun decoratedArgument() = assertModuleAtStage( - stage = Stage.DisAmbiguate, - input = "let f(@foo(1) x: T) {}", - want = """ - { - disAmbiguate: { - body: ``` - let(\word, f, nym`@foo`(let x /* aka x */: T, 1), fn {}) - - ``` - }, - } - """, + stageTestDir = StageTestDir("dis-ambiguate/decorated-argument"), ) @Test - fun everyTypeButCoreHasASuperType() { - assertModuleAtStage( - stage = Stage.DisAmbiguate, - input = "interface I {}", - want = """ - |{ - | disAmbiguate: { - | body: - | ``` - | @typeDecl(I__0) @hoistLeft(true) @resolution(I__0) @stay let I = type (I__0); - | interface(\word, I, \concrete, false, @typeDefined(I__0) fn { - | I__0 extends AnyValue - | }); - | I - | - | ```, - | - | types: { - | I: { name: "I__0", abstract: true }, - | AnyValue: { abstract: true }, - | } - | } - |} - """.trimMargin(), - ) - } + fun everyTypeButCoreHasASuperType() = assertModuleAtStage( + stageTestDir = StageTestDir("dis-ambiguate/every-type-but-core-has-a-super-type"), + ) @Test fun annotationsOnFormals() = assertModuleAtStage( - stage = Stage.DisAmbiguate, + stageTestDir = StageTestDir("dis-ambiguate/annotations-on-formals"), // annotations on x do not apply to y as would be the case if `@foo var x = 0, y` were // to appear as a top-level, not a function formal parameter - input = "fn (@foo var x = 0, y) {}", - want = """ - { - disAmbiguate: { - body: "fn(nym`@foo`(@default(0) var x /* aka x */), let y /* aka y */, fn {})\n" - } - } - """, ) @Test fun genericMethod() = assertModuleAtStage( - stage = Stage.DisAmbiguate, - input = """ - |class C { - | public let f(x: T): T { x } - |} - """.trimMargin(), + stageTestDir = StageTestDir("dis-ambiguate/generic-method"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - |{ - | disAmbiguate: { - | body: - | ``` - | @typeDecl(C__0) @hoistLeft(true) @resolution(C__0) @stay let C = type (C__0); - | class(\word, C, \concrete, true, @typeDefined(C__0) fn { - | C__0 extends AnyValue; - | @method(\f) @visibility(\public) let f = fn(\word, f, \typeFormal, do { - | @resolution(T__0) @typeFormal(\T) @typeDecl(T__0) let T = type (T__0); - | type (T__0) - | }, @impliedThis(C__0) let this__0: C__0, let x /* aka x */: T,${ - "" - } \outType, T, fn { - | x - | }); - | }); - | C - | - | ``` - | } - |} - """.trimMargin(), ) @Test fun typeDecoratorCanAccessTypeAndDeclaration() = assertModuleAtStage( - stage = Stage.Define, - want = """ - { - "disAmbiguate": { - // At the end of disambiguate, the decorator applies to the declaration - "body": - ``` - do {}; - nym`@foo`(@typeDecl(I__0) @hoistLeft(true) @resolution(I__0) @stay let I = type (I__0)); - interface(\word, I, \concrete, false, @typeDefined(I__0) fn { - I__0 extends AnyValue - }); - I - - ``` - }, - "define": { - // By the end of define, the decorator has successfully applied itself, and added - // metadata to the type shape. - "body": - ``` - @typeDecl(I__0) @stay @TypeDecoratedByFoo let I__0; - I__0 = type (I__0); - do {}; - I__0 extends AnyValue; - @typePlaceholder(I__0) let typePlaceholder#0: Empty; - typePlaceholder#0 = {class: Empty__0}; - interface(\word, \I, \concrete, false, @typeDefined(I__0) fn { - do {} - }); - type (I__0) - - ```, - "types": { - AnyValue: { abstract: true }, - I: { - name: "I__0", - word: "I", - abstract: true, - metadata: { - "TypeDecoratedByFoo": [ "void: Void" ], - }, - supers: [ - { - module: "core", - abbrev: "AnyValue__0", - uid: 0 - } - ] - }, - Empty: { - supers: ["AnyValue__0", "Equatable__0"], - methods: [ - { - name: "constructor__0", - visibility: "private", - kind: "Constructor", - open: false - }, - ], - metadata: { - connected: ["void: Void"], - imu: ["void: Void"], - } - }, - } - } - } - """, - ) { module, _ -> - module.deliverContent( - ModuleSource( - filePath = testCodeLocation, - fetchedContent = """@foo interface I {}""", - languageConfig = StandaloneLanguageConfig, - ), - ) + stageTestDir = StageTestDir("dis-ambiguate/type-decorator-can-access-type-and-declaration"), + ) { module, moduleAdvancer, td -> module.addEnvironmentBindings( mapOf( BuiltinName("@foo") to Value( @@ -853,337 +125,72 @@ class DisAmbiguateStageTest { ), ), ) + provisionModuleForStageTest(td, module, moduleAdvancer) } @Test fun enumDesugaring() = assertModuleAtStage( - stage = Stage.DisAmbiguate, - input = """ - |enum E { A, B, C } - """.trimMargin(), + stageTestDir = StageTestDir("dis-ambiguate/enum-desugaring"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - |{ - | disAmbiguate: { - | body: ``` - | @typeDecl(E__0) @hoistLeft(true) @resolution(E__0) @stay let E = type (E__0); - | class(\word, E, \concrete, true, @enumType @typeDefined(E__0) fn { - | E__0 extends AnyValue; - | @constructorProperty @visibility(\public) @property(\ordinal) let ordinal: Int32; - | @constructorProperty @visibility(\public) @property(\name) let name: String; - | @visibility(\public) @enumMember @staticProperty(\A) @static let A = new E(0, "A"); - | @visibility(\public) @enumMember @staticProperty(\B) @static let B = new E(1, "B"); - | @visibility(\public) @enumMember @staticProperty(\C) @static let C = new E(2, "C"); - | }); - | E - | - | ``` - | } - |} - """.trimMargin(), ) @Test fun squareBracketDesugaring() = assertModuleAtStage( - stage = Stage.DisAmbiguate, - input = """ - |a[i] = b[j]; - """.trimMargin(), - want = """ - |{ - | disAmbiguate: { - | body: ``` - | a.set(i, b.get(j)); - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("dis-ambiguate/square-bracket-desugaring"), ) @Test fun multiDeclDecoratorApplication() = assertModuleAtStage( - stage = Stage.DisAmbiguate, - input = """ - |@foo var x, y; - """.trimMargin(), - want = """ - |{ - | disAmbiguate: { - | body: ``` - | nym`@foo`(var x); - | nym`@foo`(var y); - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("dis-ambiguate/multi-decl-decorator-application"), ) @Test fun multiInit() = assertModuleAtStage( - stage = Stage.DisAmbiguate, - input = "@foo let { a is S, b, c as d is T }: U = f();", - want = """ - |{ - | disAmbiguate: { - | body: ``` - | nym`@foo`(let t#0: U = f()); - | nym`@foo`(let a: S = t#0.a); - | nym`@foo`(let b = t#0.b); - | nym`@foo`(let d: T = t#0.c); - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("dis-ambiguate/multi-init"), ) @Test fun multiInitMultiRenameError() = assertModuleAtStage( - stage = Stage.DisAmbiguate, - input = "let { a as b as c as d } = f();", - want = """ - |{ - | disAmbiguate: { - | body: ``` - | let t#0 = f(), b = t#0.a; - | - | ``` - | }, - | errors: [ - | "${MessageTemplate.MultipleRenames.formatString}!", - | "${MessageTemplate.MultipleRenames.formatString}!", - | ] - |} - """.trimMargin(), + stageTestDir = StageTestDir("dis-ambiguate/multi-init-multi-rename-error"), ) @Test fun wildcardDestructureError() = assertModuleAtStage( - stage = Stage.DisAmbiguate, - input = "let { ... } = f()", - want = """ - |{ - | disAmbiguate: { - | body: ``` - | let t#0 = f(); - | - | ``` - | }, - | errors: [ - | "${MessageTemplate.WildcardWithoutImport.formatString}!", - | ] - |} - """.trimMargin(), + stageTestDir = StageTestDir("dis-ambiguate/wildcard-destructure-error"), ) @Test fun multiInitErrorInClass() = assertModuleAtStage( - stage = Stage.DisAmbiguate, - input = "class Something { let { a, b } = f(); }", + stageTestDir = StageTestDir("dis-ambiguate/multi-init-error-in-class"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - |{ - | disAmbiguate: { - | body: ``` - | @typeDecl(Something__0) @hoistLeft(true) @resolution(Something__0) @stay let Something = type (Something__0); - | class(\word, Something, \concrete, true, @typeDefined(Something__0) fn { - | Something__0 extends AnyValue; - | let t#0 = f(); - | @property(\a) let a = t#0.a; - | @property(\b) let b = t#0.b; - | }); - | Something - | - | ``` - | }, - | errors: ["Declaration is malformed!"] - |} - """.trimMargin(), ) @Test fun commentInDocTypeDefinition() = assertModuleAtStage( - stage = Stage.DisAmbiguate, + stageTestDir = StageTestDir("dis-ambiguate/comment-in-doc-type-definition"), genre = Genre.Documentation, - input = """ - |class C { - | // Comment in type definition - | public x: Int; - |} - """.trimMargin(), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - |{ - | disAmbiguate: { - | body: ``` - | @typeDecl(C__0) @hoistLeft(true) @resolution(C__0) @stay let C = type (C__0); - | class(\word, C, \concrete, true, @typeDefined(C__0) fn { - | C__0 extends AnyValue; - | REM("Comment in type definition", null, false); - | @property(\x) @maybeVar @visibility(\public) let x: Int; - | }); - | identityForDocGen(C) - | - | ``` - | } - |} - """.trimMargin(), ) @Test fun exportedClassesHaveExportedNames() = assertModuleAtStage( - stage = Stage.DisAmbiguate, - input = """ - |export class C {} - """.trimMargin(), - want = """ - |{ - | disAmbiguate: { - | body: ``` - | do {}; - | @typeDecl(C) @hoistLeft(true) @resolution(`test//`.C) @stay let `test//`.C = type (C); - | class(\word, C, \concrete, true, @typeDefined(C) fn { - | C extends AnyValue - | }); - | C - | - | ```, - | types: { - | C: { - | name: { - | type: "ExportedName", - | module: "test//", - | baseName: "C", - | }, - | }, - | AnyValue: { - | abstract: true, - | }, - | } - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("dis-ambiguate/exported-classes-have-exported-names"), ) @Test fun exportedClassesWithExtraDecoratorsHaveExportedNames() = assertModuleAtStage( - stage = Stage.DisAmbiguate, - input = """ - | export @bar class C {} - | @foo(1) export interface D {} - | @foo() export @bar class E {} - """.trimMargin(), - want = """ - |{ - | disAmbiguate: { - | body: ``` - | do {}; - | nym`@export`(nym`@bar`(@typeDecl(C) @hoistLeft(true) @resolution(`test//`.C) @stay let C = type (C))); - | class(\word, C, \concrete, true, @typeDefined(C) fn { - | C extends AnyValue - | }); - | do {}; - | nym`@foo`(@typeDecl(D) @hoistLeft(true) @resolution(`test//`.D) @stay let `test//`.D = type (D), 1); - | interface(\word, D, \concrete, false, @typeDefined(D) fn { - | D extends AnyValue - | }); - | do {}; - | nym`@foo`(nym`@export`(nym`@bar`(@typeDecl(E) @hoistLeft(true) @resolution(`test//`.E) @stay let E = type (E)))); - | class(\word, E, \concrete, true, @typeDefined(E) fn { - | E extends AnyValue - | }); - | E - | - | ```, - | types: { - | AnyValue: { - | abstract: true, - | }, - | C: { - | name: { - | type: "ExportedName", - | module: "test//", - | baseName: "C", - | }, - | }, - | D: { - | name: { - | type: "ExportedName", - | module: "test//", - | baseName: "D", - | }, - | abstract: true, - | }, - | E: { - | name: { - | type: "ExportedName", - | module: "test//", - | baseName: "E", - | }, - | }, - | } - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("dis-ambiguate/exported-classes-with-extra-decorators-have-exported-names"), ) @Test fun classesCanDeclarePropertiesInParenthetical() = assertModuleAtStage( - stage = Stage.DisAmbiguate, - input = """ - |class Point( - | public let x: Float64, - | public let y: Float64, - |) extends AntValue { - | public let distanceFromOrigin: Float64 = (x * x + y * y).sqrt(); - |} - """.trimMargin(), - want = """ - |{ - | disAmbiguate: { - | body: ``` - | @typeDecl(Point__0) @hoistLeft(true) @resolution(Point__0) @stay let Point = type (Point__0); - | class(\word, Point, \concrete, true, @typeDefined(Point__0) fn { - | Point__0 extends AntValue; - | @constructorProperty @maybeVar @visibility(\public) let x /* aka x */: Float64; - | @constructorProperty @maybeVar @visibility(\public) let y /* aka y */: Float64; - | @visibility(\public) let distanceFromOrigin: Float64 = (x * x + y * y).sqrt(); - | }); - | Point - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("dis-ambiguate/classes-can-declare-properties-in-parenthetical"), ) @Test fun incrementInDoBlock() = assertModuleAtStage( - stage = Stage.DisAmbiguate, + stageTestDir = StageTestDir("dis-ambiguate/increment-in-do-block"), pseudoCodeDetail = PseudoCodeDetail(resugarDotHelpers = Freq3.Never), stagingFlags = setOf(StagingFlags.skipImportCore), - input = """ - |do { - | var x = 0; - | x += 1; - | console.log(x); - |} - """.trimMargin(), - want = """ - |{ - | disAmbiguate: { - | body: ``` - | do(fn { - | var x = 0; - | x = (nym`do_call__+_`[PlusIntInt, PlusIntInt64, PlusFltFlt])(x, 1); - | console.log(x); - | }) - | - | ```, - | } - |} - """.trimMargin(), ) } diff --git a/frontend/src/commonTest/kotlin/lang/temper/frontend/EndToEndTest.kt b/frontend/src/commonTest/kotlin/lang/temper/frontend/EndToEndTest.kt deleted file mode 100644 index 019da927..00000000 --- a/frontend/src/commonTest/kotlin/lang/temper/frontend/EndToEndTest.kt +++ /dev/null @@ -1,52 +0,0 @@ -package lang.temper.frontend - -import lang.temper.stage.Stage -import kotlin.test.Ignore -import kotlin.test.Test - -// TODO: turn these into functional tests and run the functional test suite via runtime-emulation -class EndToEndTest { - @Ignore // multiAssign not implemented - @Test - fun multiAssign() = assertModuleAtStage( - stage = Stage.Run, - input = """ - let f(a, b, c) { - let d = a + b; - let e = c + 1; - return [d, e]; - } - let [x, y] = f(3, 4, 5); - x * y - """.trimIndent(), - moduleResultNeeded = true, - want = """ - { - stageCompleted: "Runtime", - runtime: [ - "42: Int32" - ] - } - """, - ) - - @Test - fun optionalArgumentPassing() = assertModuleAtStage( - stage = Stage.Run, - // %{...} -> ${...} - input = """ - |let f(a: Int = 0, b: Int = 1): String { "a=%{a.toString()}, b=%{b.toString()}" }; - |"%{ f(2) }; %{ f(null, 2) }; %{ f(3, 2) }" - """.trimMargin().replace('%', '$'), - moduleResultNeeded = true, - want = """ - |{ - | stageCompleted: "Run", - | run: - | ``` - | "a=2, b=1; a=0, b=2; a=3, b=2": String - | ``` - |} - """.trimMargin(), - ) -} diff --git a/frontend/src/commonTest/kotlin/lang/temper/frontend/FunctionMacroStageTest.kt b/frontend/src/commonTest/kotlin/lang/temper/frontend/FunctionMacroStageTest.kt index a96e6d29..ef64ea46 100644 --- a/frontend/src/commonTest/kotlin/lang/temper/frontend/FunctionMacroStageTest.kt +++ b/frontend/src/commonTest/kotlin/lang/temper/frontend/FunctionMacroStageTest.kt @@ -24,33 +24,9 @@ import kotlin.test.assertTrue class FunctionMacroStageTest { @Test fun compileLogExecutionOrder() = assertModuleAtStage( + stageTestDir = StageTestDir("function-macro/compile-log-execution-order"), stage = Stage.FunctionMacro, - want = """ - { - functionMacro: { - body: - ``` - compilelog("1", @F); - if (c) { - compilelog("2", @F) - } else { - compilelog("3", @F) - }; - compilelog("4", @F) - - ``` - }, - stdout: - ``` - clog:F: 1 - clog:F: 2 - clog:F: 3 - clog:F: 4 - - ``` - } - """, - ) { module, _ -> + ) { module, _, _ -> val loc = testCodeLocation val doc = Document(module) val pos = Position(loc, 0, 0) @@ -116,15 +92,13 @@ class FunctionMacroStageTest { root.replaceFlow(StructuredFlow(controlFlow)) - module.deliverContent( - root, - ) + module.deliverContent(root) } @Test fun multiInitErrorInClass() = assertModuleAtStage( + stageTestDir = StageTestDir("function-macro/multi-init-error-in-class"), stage = Stage.FunctionMacro, - input = "class Aha(private hmm: Int) {}; class Boo { let { hmm } = new Aha(1) }", manualCheck = { got -> val errors = (got["errors"] as JsonArray).map { (((it as JsonObject)["formatted"]) as JsonString).content diff --git a/frontend/src/commonTest/kotlin/lang/temper/frontend/GenerateCodeStageTest.kt b/frontend/src/commonTest/kotlin/lang/temper/frontend/GenerateCodeStageTest.kt index 378ad64f..1a84fa83 100644 --- a/frontend/src/commonTest/kotlin/lang/temper/frontend/GenerateCodeStageTest.kt +++ b/frontend/src/commonTest/kotlin/lang/temper/frontend/GenerateCodeStageTest.kt @@ -3,18 +3,12 @@ package lang.temper.frontend import lang.temper.common.Log -import lang.temper.common.stripDoubleHashCommentLinesToPutCommentsInlineBelow -import lang.temper.common.temperEscaper -import lang.temper.common.testCodeLocation import lang.temper.env.InterpMode import lang.temper.interp.MetadataDecorator -import lang.temper.lexer.MarkdownLanguageConfig -import lang.temper.lexer.StandaloneLanguageConfig import lang.temper.log.MessageTemplate import lang.temper.name.BuiltinName import lang.temper.name.Symbol import lang.temper.name.TemperName -import lang.temper.stage.Stage import lang.temper.type.WellKnownTypes import lang.temper.type2.Signature2 import lang.temper.value.ActualValues @@ -32,1096 +26,163 @@ import kotlin.test.Test class GenerateCodeStageTest { @Test fun simpleDoNothingLoop() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = """ - |// This example is interesting because the infer result pass actually adds two assignments - |// to gather results from terminal expression. - |// - |// This may be a bug, but in the meantime, it leads to a nested assignment of temporaries: - |// `t#0 = t#1 = hs(fail#2, i < 3)` - |// - |// The generate code stage needs to unnest this assignment before the TmpL backend can - |// translate it. If the TmpL backend were to try to handle this by creating temporaries, - |// those would miss type information. - |var i = 0; - |while (i < 3) { ++i; } - """.trimMargin(), - want = """ - |{ - | "type": { - | "body": - | ``` - | var i__0; - | i__0 = 0; - | while (i__0 < 3) { - | i__0 = i__0 + 1; - | } - | - | ``` - | }, - | "generateCode": { - | "body": - | ``` - | var i__0; - | i__0 = 0; - | while (i__0 < 3) { - | i__0 = i__0 + 1 - | } - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/simple-do-nothing-loop"), ) @Test fun sealedWhen() = assertModuleAtStage( - stage = Stage.GenerateCode, + stageTestDir = StageTestDir("generate-code/sealed-when"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showInferredTypes = true), - input = """ - |export interface Geometric {} - |export class Ray extends Geometric {} - |export sealed interface Shape extends Geometric {} - |export class Circle() extends Shape {} - |export class Square() extends Shape {} - |export let describeGeometric(g: Geometric): String { - | when (g) { - | is Circle -> "circle"; - | is Square -> "square"; - | // defaults to void here because it starts above the sealed type - | } - |} - |export let describeShape(s: Shape): String { - | when (s) { - | is Circle -> "circle"; - | is Square -> "square"; - | // defaults to panic here because those are exhaustive for Shape - | } - |} - """.trimMargin(), - want = """ - |{ - | generateCode: { - | body: - | ``` - | @typeDecl(Geometric) @stay let `test//`.Geometric ⦂ Type; - | `test//`.Geometric = type (Geometric); - | @typeDecl(Ray) @stay let `test//`.Ray ⦂ Type; - | `test//`.Ray = type (Ray); - | @typeDecl(Shape) @stay @sealedType let `test//`.Shape ⦂ Type; - | `test//`.Shape = type (Shape); - | @typeDecl(Circle) @stay let `test//`.Circle ⦂ Type; - | `test//`.Circle = type (Circle); - | @typeDecl(Square) @stay let `test//`.Square ⦂ Type; - | `test//`.Square = type (Square); - | @fn let `test//`.describeGeometric ⦂(fn (Geometric): String), @fn `test//`.describeShape ⦂(fn (Shape): String), @typePlaceholder(Geometric) typePlaceholder#0: Empty; - | typePlaceholder#0 = {class: Empty__0}; - | @fn @visibility(\public) @stay @fromType(Ray) let constructor__0 ⦂(fn (Ray): Void); - | constructor__0 = (@stay fn constructor(@impliedThis(Ray) this__0: Ray) /* return__0 */: Void { - | return__0 = void - | }); - | @typePlaceholder(Shape) let typePlaceholder#1: Empty; - | typePlaceholder#1 = {class: Empty__0}; - | @fn @visibility(\public) @stay @fromType(Circle) let constructor__1 ⦂(fn (Circle): Void); - | constructor__1 = (@stay fn constructor(@impliedThis(Circle) this__1: Circle) /* return__1 */: Void { - | return__1 = void - | }); - | @fn @visibility(\public) @stay @fromType(Square) let constructor__2 ⦂(fn (Square): Void); - | constructor__2 = (@stay fn constructor(@impliedThis(Square) this__2: Square) /* return__2 */: Void { - | return__2 = void - | }); - | `test//`.describeGeometric = (@stay fn describeGeometric(g__0 /* aka g */: Geometric) /* return__3 */: String { - | if (g__0 is Circle) { - | return__3 = "circle" - | } else if (g__0 is Square) { - | return__3 = "square" - | } else { - | return__3 = void - | } - | }); - | `test//`.describeShape = (@stay fn describeShape(s__0 /* aka s */: Shape) /* return__4 */: String { - | if (s__0 is Circle) { - | return__4 = "circle" - | } else if (s__0 is Square) { - | return__4 = "square" - | } else { - | return__4 = panic ⋖ String ⋗() - | } - | }) - | - | ``` - | }, - | errors: [ - | "Cannot assign to String from Void!", - | "Expected subtype of String, but got Void!", - | "Void expressions cannot be used as values!", - | ] - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), ) @Test fun assignmentsToTypedReturnAreChecked() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = """ - fn f(x): Int { x } - """.trimIndent(), + stageTestDir = StageTestDir("generate-code/assignments-to-typed-return-are-checked"), moduleResultNeeded = true, - want = """ - { - generateCode: { - body: ``` - let return__4, @fn f__0; - f__0 = (@stay fn f(x__0 /* aka x */) /* return__1 */: Int32 { - return__1 = x__0 - }); - return__4 = (fn f) - - ```, - }, - errors: [ - "Cannot assign to Int32 from AnyValue!", - "Expected subtype of Int32, but got AnyValue!" - ] - } - """, ) @Test fun docCommentInData() = assertModuleAtStage( - stage = Stage.GenerateCode, - languageConfig = MarkdownLanguageConfig(), - input = """ - | /** Is this a doc comment? */ - | export let hi = List.of( - | 1, - | - |Here is some text, don't you know. - | - | 2, - | /** How about this? */ - | 3, - | ); - | export let f(/** docs */ a: Int): Int { g(/** here too? */ 1) } - | let g(b: Int): Int { b } - """.trimMargin(), - want = """ - |{ - | generateCode: { - | body: ``` - | @fn let `test//`.f, @fn @reach(\none) g__0, `test//`.hi; - | `test//`.hi = list(1, 2, 3); - | g__0 = (@stay fn g(b__0 /* aka b */: Int32) /* return__0 */: Int32 { - | return__0 = b__0 - | }); - | `test//`.f = (@stay fn f(a__0 /* aka a */: Int32) /* return__1 */: Int32 { - | return__1 = 1 - | }) - | - | ```, - | exports: { - | f: "fn f: Function", - | hi: null, - | }, - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/doc-comment-in-data"), ) @Test fun doWhileContinuesToFalseCondition() = assertModuleAtStage( - input = """ - |do { - | console.log("Done once"); - | continue; - | console.log("Not done"); - |} while (false); - """.trimMargin(), - stage = Stage.Run, + stageTestDir = StageTestDir("generate-code/do-while-continues-to-false-condition"), moduleResultNeeded = true, - want = """ - |{ - | run: "void: Void", - | generateCode: { - | body: ``` - | let return__0; - | do_call_log(getConsole(), "Done once"); - | return__0 = void - | - | ``` - | }, - | stdout: ``` - | Done once - | - | ``` - |} - """.trimMargin(), ) @Test fun exportedNames() = assertModuleAtStage( - stage = Stage.Run, - input = "export let answer = 42; answer", + stageTestDir = StageTestDir("generate-code/exported-names"), moduleResultNeeded = true, - want = """{ - run: "42: Int32", - generateCode: { - body: ``` - let return__0, `test//`.answer; - `test//`.answer = 42; - return__0 = 42 - - ```, - exports: { - answer: "42: Int32", - } - }, - export: { - body: ``` - let return__0, `test//`.answer; - `test//`.answer = 42; - return__0 = 42 - - ```, - exports: { - answer: "42: Int32", - } - }, - } - """, ) @Test fun simpleMethodCall() = assertModuleAtStage( - input = """ - |1.toString() - """.trimMargin(), - stage = Stage.Run, + stageTestDir = StageTestDir("generate-code/simple-method-call"), moduleResultNeeded = true, - want = """ - |{ - | run: ["1", "String"], - |} - """.trimMargin(), ) - @Suppress("SpellCheckingInspection") // getprop/setprop @Test fun getterSettersFinal() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = """ - |class C(public var prop: Int) {} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/getter-setters-final"), moduleResultNeeded = true, pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - |{ - | generateCode: { - | body: - | ``` - | let return__0; - | @constructorProperty @property(\prop) @visibility(\public) @stay @fromType(C__0) var prop__0: Int32; - | @fn @method(\constructor) @visibility(\public) @stay @fromType(C__0) let constructor__0; - | constructor__0 = (@stay fn constructor(@impliedThis(C__0) this__0: C__0, prop__1 /* aka prop */: Int32) /* return__1 */: Void { - | setp(prop__0, this__0, prop__1); - | return__1 = void - | }); - | @getter @method(\prop) @fn @visibility(\public) @stay @fromType(C__0) let getprop__0; - | getprop__0 = (@stay fn (@impliedThis(C__0) this__1: C__0) /* return__2 */: Int32 { - | return__2 = getp(prop__0, this__1) - | }); - | @setter @method(\prop) @fn @visibility(\public) @stay @fromType(C__0) let setprop__0; - | setprop__0 = (@stay fn (@impliedThis(C__0) this__2: C__0, newProp__0: Int32) /* return__3 */: Void { - | setp(prop__0, this__2, newProp__0); - | return__3 = void - | }); - | @typeDecl(C__0) @stay let C__0; - | C__0 = type (C__0); - | return__0 = type (C__0) - | - | ``` - | } - |} - """.trimMargin(), ) - @Suppress("SpellCheckingInspection") // getprop/setprop @Test fun getterSettersVarOrNot() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = """ - |export interface I { - | public get superGetter(): Int { 10 } - | public set superSetter(i: Int): Void { } - |} - |export class C extends I { - | public propNotVar: Int; - | public var propVar: Int; - | public constructor() { - | // These are both legal. - | propNotVar = 1; - | propVar = 2; - | // Seeing if explicity `this` is different. - | this.propVar = 3; - | // Check an entirely missing property, which needs explicit this. - | this.wrong = 4; - | // Go both ways on good and bad here. Even in constructor, wrong way should fail. - | // Some of the errors are confusing, but at least we get errors. - | extraGetter = extraSetter; - | extraSetter = extraGetter; - | extraSetter = superGetter; - | superGetter = propNotVar; - | // Check setter defined only in supertype. - | superSetter = propNotVar; - | } - | public update(i: Int): Void { - | // Update of propNotVar illegal. - | propNotVar = i; - | // Assign bad type. - | propVar = "hi"; - | } - | public set extraSetter(k: Int): Void { - | propVar = k; - | } - | public get extraGetter(): Int { - | propVar - | } - |} - |export let alsoUpdate(c: C, j: Int): Void { - | // Again, update of propNotVar illegal. - | c.propNotVar = j; - | c.propVar = j; - | c.propVar = "bye"; - | // c.propVar += j; // <-- Generates bad tree code! - | // Check more good and bad. - | c.extraSetter = j; - | c.extraGetter = j; - | c.extraWrong = j; - | // From outside, check setter defined only in supertype. - | c.superSetter = j; - |} - """.trimMargin(), - want = """ - |{ - | generateCode: { - | body: - | ``` - | @typeDecl(I) @stay let `test//`.I; - | `test//`.I = type (I); - | @typeDecl(C) @stay let `test//`.C; - | `test//`.C = type (C); - | @fn let `test//`.alsoUpdate; - | @visibility(\public) @stay @fromType(I) let superGetter__0; - | @visibility(\public) @fn @stay @fromType(I) let nym`get.superGetter__1`; - | nym`get.superGetter__1` = (@stay fn nym`get.superGetter`(@impliedThis(I) this__0: I) /* return__0 */: Int32 { - | return__0 = 10 - | }); - | @visibility(\public) @stay @fromType(I) let superSetter__0; - | @visibility(\public) @fn @stay @fromType(I) let nym`set.superSetter__1`; - | nym`set.superSetter__1` = (@stay fn nym`set.superSetter`(@impliedThis(I) this__1: I, i__0 /* aka i */: Int32) /* return__1 */: Void { - | return__1 = void - | }); - | @visibility(\public) @stay @fromType(C) let propNotVar__0: Int32; - | @visibility(\public) @stay @fromType(C) var propVar__0: Int32; - | @visibility(\public) @fn @stay @fromType(C) let constructor__0; - | constructor__0 = (@stay fn constructor(@impliedThis(C) this__2: C) /* return__2 */: Void { - | var t#0, t#1, t#2, t#3, t#4; - | setp(propNotVar__0, this__2, 1); - | setp(propVar__0, this__2, 2); - | setp(propVar__0, this__2, 3); - | do_iset_wrong(type (C), this__2, 4); - | t#0 = do_iget_extraSetter(type (C), this__2); - | do_iset_extraGetter(type (C), this__2, t#0); - | t#1 = do_iget_extraGetter(type (C), this__2); - | do_iset_extraSetter(type (C), this__2, t#1); - | t#2 = do_iget_superGetter(type (C), this__2); - | do_iset_extraSetter(type (C), this__2, t#2); - | t#3 = getp(propNotVar__0, this__2); - | do_iset_superGetter(type (C), this__2, t#3); - | t#4 = getp(propNotVar__0, this__2); - | do_iset_superSetter(type (C), this__2, t#4); - | return__2 = void - | }); - | @visibility(\public) @fn @stay @fromType(C) let update__0; - | update__0 = (@stay fn update(@impliedThis(C) this__3: C, i__1 /* aka i */: Int32) /* return__3 */: Void { - | setp(propNotVar__0, this__3, i__1); - | setp(propVar__0, this__3, "hi"); - | return__3 = void - | }); - | @visibility(\public) @stay @fromType(C) let extraSetter__0; - | @visibility(\public) @fn @stay @fromType(C) let nym`set.extraSetter__1`; - | nym`set.extraSetter__1` = (@stay fn nym`set.extraSetter`(@impliedThis(C) this__4: C, k__0 /* aka k */: Int32) /* return__4 */: Void { - | setp(propVar__0, this__4, k__0); - | return__4 = void - | }); - | @visibility(\public) @stay @fromType(C) let extraGetter__0; - | @visibility(\public) @fn @stay @fromType(C) let nym`get.extraGetter__1`; - | nym`get.extraGetter__1` = (@stay fn nym`get.extraGetter`(@impliedThis(C) this__5: C) /* return__5 */: Int32 { - | return__5 = getp(propVar__0, this__5) - | }); - | @fn @visibility(\public) @stay @fromType(C) let getpropNotVar__0; - | getpropNotVar__0 = (@stay fn (@impliedThis(C) this__6: C) /* return__6 */: Int32 { - | return__6 = getp(propNotVar__0, this__6) - | }); - | @fn @visibility(\public) @stay @fromType(C) let getpropVar__0; - | getpropVar__0 = (@stay fn (@impliedThis(C) this__7: C) /* return__7 */: Int32 { - | return__7 = getp(propVar__0, this__7) - | }); - | @fn @visibility(\public) @stay @fromType(C) let setpropVar__0; - | setpropVar__0 = (@stay fn (@impliedThis(C) this__8: C, newPropVar__0: Int32) /* return__8 */: Void { - | setp(propVar__0, this__8, newPropVar__0); - | return__8 = void - | }); - | `test//`.alsoUpdate = (@stay fn alsoUpdate(c__0 /* aka c */: C, j__0 /* aka j */: Int32) /* return__9 */: Void { - | var t#5, t#6, t#7, t#8; - | let t#9; - | t#9 = j__0; - | do_set_propNotVar(c__0, t#9); - | t#5 = j__0; - | do_set_propVar(c__0, t#5); - | do_set_propVar(c__0, "bye"); - | t#6 = j__0; - | do_set_extraSetter(c__0, t#6); - | t#7 = j__0; - | do_set_extraGetter(c__0, t#7); - | t#8 = j__0; - | do_set_extraWrong(c__0, t#8); - | do_set_superSetter(c__0, j__0); - | return__9 = void - | }) - | - | ```, - | exports: { - | C: "C: Type", - | alsoUpdate: "fn alsoUpdate: Function", - | "I": "I: Type", - | }, - | }, - | errors: [ - | "No member wrong in C | I!", - | "Wrong number of arguments. Expected 2!", - | "Expected subtype of Type, but got C!", - | "Member extraGetter defined in C | I incompatible with usage!", - | "Member superGetter defined in C | I incompatible with usage!", - | "Member propNotVar defined in C incompatible with usage!", - | "Expected subtype of Int32, but got String!", - | "Member propNotVar defined in C | I incompatible with usage!", - | "Expected subtype of Int32, but got String!", - | "Member extraGetter defined in C | I incompatible with usage!", - | "No member extraWrong in C | I!", - | ], - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/getter-setters-var-or-not"), ) @Test fun fnType() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = """ - |let f: fn (Int): Int = fn (x: Int): Int { x + 1 }; - |f(41) - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/fn-type"), moduleResultNeeded = true, - want = """ - |{ - | "generateCode": { - | "body": - | ``` - | let return__0, @fn @reach(\none) f__0: (fn (Int32): Int32); - | f__0 = (@stay fn f(x__0 /* aka x */: Int32) /* return__1 */: Int32 { - | return__1 = x__0 + 1 - | }); - | return__0 = 42 - | - | ``` - | } - |} - """.trimMargin(), ) @Test fun catsAreNice() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = """ - |let f(s: String): Void { - | cat(s); - | cat(s, s); - | cat(s, s, s); - | cat(s, s, s, s); - |} - """.trimMargin(), - want = """ - |{ - | generateCode: { - | body: - | ``` - | @fn @reach(\none) let f__0 ⦂(fn (String): Void); - | f__0 = (@stay fn f(s__0 /* aka s */: String) /* return__1 */: Void { - | cat(s__0); - | cat(s__0, s__0); - | cat(s__0, s__0, s__0); - | cat(s__0, s__0, s__0, s__0); - | return__1 = void - | }) - | - | ``` - | }, - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/cats-are-nice"), pseudoCodeDetail = PseudoCodeDetail(showInferredTypes = true), ) @Test fun catsAreRadActually() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = $$""" - |let f(s: String): Void { - | "${0}"; - | "${s}${0}"; - | "${s}${0}${s}"; - | "${s}${s}${0}${s}"; - |} - """.trimMargin(), - want = """ - |{ - | generateCode: { - | body: - | ``` - | @fn @reach(\none) let f__0; - | f__0 = (@stay fn f(s__0 /* aka s */: String) /* return__1 */: Void { - | var t#0, t#1, t#2; - | cat(do_call_toString(0)); - | t#0 = do_call_toString(0); - | cat(s__0, t#0); - | t#1 = do_call_toString(0); - | cat(s__0, t#1, s__0); - | t#2 = do_call_toString(0); - | cat(s__0, s__0, t#2, s__0); - | return__1 = void - | }) - | - | ``` - | }, - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/cats-are-rad-actually"), ) @Test fun catsPlayWithStringAndNull() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = $$""" - |let f(s: String, a: Int?): String { - | "${s}${a}${a ?? -1}" - |} - """.trimMargin(), - want = """ - |{ - | generateCode: { - | body: - | ``` - | @fn @reach(\none) let f__0; - | f__0 = (@stay fn f(s__0 /* aka s */: String, a__0 /* aka a */: Int32?) /* return__1 */: String { - | var t#0, t#1, t#2; - | if (isNull(a__0)) { - | t#0 = "null" - | } else { - | t#0 = do_call_toString(notNull(a__0)) - | }; - | if (isNull(a__0)) { - | t#2 = -1 - | } else { - | t#2 = notNull(a__0) - | }; - | t#1 = do_call_toString(t#2); - | return__1 = cat(s__0, t#0, t#1) - | }) - | - | ``` - | }, - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/cats-play-with-string-and-null"), ) /** No cats were harmed in the making of this test. */ @Test fun rawCatsGetCooked() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = $$""" - |let f(s: String): Void { - | raw"${s}"; - | // Also a call that will fail, so we make sure to test that. - | raw"${what}"; - |} - """.trimMargin(), - want = """ - |{ - | define: { - | body: - | ``` - | @fn let f__0; - | f__0 = fn f(s__0 /* aka s */: String) /* return__1 */: Void { - | fn__0: do { - | cat(s__0); - | void; - | cat(what); - | } - | }; - | - | ``` - | }, - | generateCode: { - | body: - | ``` - | @fn @reach(\none) let f__0; - | f__0 = (@stay fn f(s__0 /* aka s */: String) /* return__1 */: Void { - | cat(s__0); - | cat(what); - | return__1 = void - | }) - | - | ``` - | }, - | errors: [ - | "No declaration for what!", - | ], - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/raw-cats-get-cooked"), ) @Ignore // TODO(mikesamuel): Fix typing of generic methods with explicit actuals @Test fun mapTypeArg() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = """ - |let ls: List = [1, 2]; - |ls.map { (x: Int): String => x.toString(10) } - """.trimMargin(), - want = """ - |{ - | type: { - | body: ``` - | - | ``` - | }, - | generateCode: { - | body: ``` - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/map-type-arg"), pseudoCodeDetail = PseudoCodeDetail(showInferredTypes = true), ) @Ignore @Test fun banExportNotAtTopLevel() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = "let f(x) { export let y = x; }", - want = """ - { - errors: [ "TODO" ] - } - """, + stageTestDir = StageTestDir("generate-code/ban-export-not-at-top-level"), ) @Ignore @Test fun banExportsThatAreReAssignable() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = "export var i = 1; i = 2", - want = """ - { - errors: [ "TODO" ] - } - """, + stageTestDir = StageTestDir("generate-code/ban-exports-that-are-re-assignable"), ) @Ignore @Test fun banExportInLoops() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = "var i = 0; while (i <= 2) { export let x = i; i += 1 }", - want = """ - { - errors: [ "TODO" ] - } - """, + stageTestDir = StageTestDir("generate-code/ban-export-in-loops"), ) @Test fun banExportsExposingNonExported() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = """ - |interface Hidden {} - |export class Exported(x: A, t: T, i: I): T; } - |class C extends I { protected f(x: B, u: U, i: I): U { u } } - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/hide-override-method-generic"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - |{ - | generateCode: { - | body: ``` - | @typeFormal(\T) @memberTypeFormal(\T) @typeDefined(T__0) @fromType(I__0) @reach(\none) let T__0; - | T__0 = type (T__0); - | @method(\f) @visibility(\public) @fn @stay @fromType(I__0) @reach(\none) let f__0; - | @typeFormal(\A) @typeDecl(A__0) @reach(\none) let A__0; - | A__0 = type (A__0); - | f__0 = (@stay fn f(@impliedThis(I__0) this__0: I__0, x__0 /* aka x */: A__0, t__0 /* aka t */: T__0, i__0 /* aka i */: I__0) /* return__1 */: T__0 { - | pureVirtual() - | }); - | @typeDecl(I__0) @stay @reach(\none) let I__0; - | I__0 = type (I__0); - | @typeDecl(C__0) @stay @reach(\none) let C__0; - | C__0 = type (C__0); - | @typeFormal(\U) @memberTypeFormal(\U) @typeDefined(U__0) @fromType(C__0) @reach(\none) let U__0; - | U__0 = type (U__0); - | @method(\f) @visibility(\protected) @fn @stay @fromType(C__0) @reach(\none) let f__1; - | @typeFormal(\B) @typeDecl(B__0) @reach(\none) let B__0; - | B__0 = type (B__0); - | f__1 = (@stay fn f(@impliedThis(C__0) this__1: C__0, x__1 /* aka x */: B__0, u__0 /* aka u */: U__0, i__1 /* aka i */: I__0) /* return__2 */: U__0 { - | return__2 = u__0 - | }); - | @fn @method(\constructor) @visibility(\public) @stay @fromType(C__0) @reach(\none) let constructor__0; - | constructor__0 = (@stay fn constructor(@impliedThis(C__0) this__2: C__0) /* return__3 */: Void { - | return__3 = void - | }) - | - | ``` - | }, - | errors: [ - | "Illegal type parameter A. Overridable methods don't allow generics!", - | "Override has lower visibility than in I__0!", - | ] - |} - """.trimMargin(), ) /** @@ -1383,2709 +242,388 @@ class GenerateCodeStageTest { */ @Test fun typeParameterCanExtendConcreteType() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = """ - |interface I { public f(s: S): Void; } - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/type-parameter-can-extend-concrete-type"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - |{ - | generateCode: { - | body: ``` - | @method(\f) @visibility(\public) @fn @stay @fromType(I__0) @reach(\none) let f__0; - | @typeFormal(\S) @typeDecl(S__0) @reach(\none) let S__0; - | S__0 = type (S__0); - | f__0 = (@stay fn f(@impliedThis(I__0) this__0: I__0, s__0 /* aka s */: S__0) /* return__0 */: Void { - | pureVirtual() - | }); - | @typeDecl(I__0) @stay @reach(\none) let I__0; - | I__0 = type (I__0) - | - | ``` - | }, - | errors: [ - | "Illegal type parameter S. Overridable methods don't allow generics!", - | ], - |} - """.trimMargin(), ) @Test fun returnTypeRequired() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = """ - |let hi() {} - """.trimMargin(), - want = """ - |{ - | generateCode: { - | body: ``` - | @fn @reach(\none) let hi__0; - | hi__0 = (@stay fn hi /* return__1 */{ - | return__1 = void - | }) - | - | ``` - | }, - | errors: [ - | "Explicit return type required!", - | ] - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/return-type-required"), + ) + + @Test + fun optionalArgumentPassing() = assertModuleAtStage( + stageTestDir = StageTestDir("generate-code/optional-argument-passing"), + moduleResultNeeded = true, ) @Test fun returnTypeOptionalForSomeCases() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = """ - |class Something { - | public constructor() {} // return type implied - | public get blah() { 5 } // return type required but missing - | public set blah(x: Int) {} // return type implied - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/return-type-optional-for-some-cases"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - |{ - | generateCode: { - | body: ``` - | @method(\constructor) @visibility(\public) @fn @stay @fromType(Something__0) @reach(\none) let constructor__0; - | constructor__0 = (@stay fn constructor(@impliedThis(Something__0) this__0: Something__0) /* return__0 */: Void { - | return__0 = void - | }); - | @property(\blah) @visibility(\public) @stay @fromType(Something__0) @reach(\none) let blah__0; - | @method(\blah) @getter @visibility(\public) @fn @stay @fromType(Something__0) @reach(\none) let nym`get.blah__1`; - | nym`get.blah__1` = (@stay fn nym`get.blah`(@impliedThis(Something__0) this__1: Something__0) /* return__1 */{ - | return__1 = 5 - | }); - | @method(\blah) @setter @visibility(\public) @fn @stay @fromType(Something__0) @reach(\none) let nym`set.blah__2`; - | nym`set.blah__2` = (@stay fn nym`set.blah`(@impliedThis(Something__0) this__2: Something__0, x__0 /* aka x */: Int32) /* return__2 */: Void { - | return__2 = void - | }); - | @typeDecl(Something__0) @stay @reach(\none) let Something__0; - | Something__0 = type (Something__0) - | - | ``` - | }, - | errors: [ - | "Explicit return type required!", - | ] - |} - """.trimMargin(), ) @Test fun typeMetadata() = assertModuleAtStage( - stage = Stage.GenerateCode, - want = """ - |{ - | generateCode: { - | body: - | ``` - | @typeDecl(I__0) @stay @foo @reach(\none) let I__0; - | I__0 = type (I__0); - | @typePlaceholder(I__0) @reach(\none) let typePlaceholder#0: Empty; - | typePlaceholder#0 = {class: Empty__0} - | - | ```, - | types: { - | I: { - | name: "I__0", - | abstract: true, - | supers: ["AnyValue__0"], - | metadata: { - | "foo": ["void: Void"], - | "reach": ["\\none: Symbol"], - | } - | }, - | Empty: { - | supers: ["AnyValue__0", "Equatable__0"], - | methods: [ - | { - | name: "constructor__0", - | visibility: "private", - | kind: "Constructor", - | open: false - | }, - | ], - | metadata: { - | connected: ["void: Void"], - | imu: ["void: Void"], - | } - | }, - | }, - | }, - |} - """.trimMargin(), - ) { module, _ -> - val input = """ - |@foo interface I {} - """.trimMargin() - - module.deliverContent( - ModuleSource( - filePath = testCodeLocation, fetchedContent = input, languageConfig = StandaloneLanguageConfig, - ), - ) - + stageTestDir = StageTestDir("generate-code/type-metadata"), + ) { module, moduleAdvancer, td -> module.addEnvironmentBindings( mapOf( BuiltinName("@foo") to Value(MetadataDecorator(Symbol("foo")) { void }), ), ) + + provisionModuleForStageTest(td, module, moduleAdvancer) } @Test fun voidNotAValue() = assertModuleAtStage( - stage = Stage.GenerateCode, + stageTestDir = StageTestDir("generate-code/void-not-a-value"), // Implied and explicit void returns should be fine, but others should be errors. - input = """ - |let a = [b()]; - |let b(): Void { console.log("hi"); } - |let c(d: Void): Void { b() } - |let e = c(a[0]); - |c(void); - """.trimMargin(), - want = """ - |{ - | generateCode: { - | body: - | ``` - | let console#0; - | console#0 = getConsole(); - | @fn let b__0, @fn c__0; - | b__0 = (@stay fn b /* return__0 */: Void { - | do_call_log(console#0, "hi"); - | return__0 = void - | }); - | let a__0; - | b__0(); - | a__0 = list(void); - | c__0 = (@stay fn c(d__0 /* aka d */: Void) /* return__1 */: Void { - | b__0(); - | return__1 = void - | }); - | @reach(\none) let e__0; - | do_call_get(a__0, 0); - | c__0(void); - | e__0 = void; - | c__0(void) - | - | ``` - | }, - | errors: [ - | "Type formal cannot bind to Void which does not fit upper bounds [AnyValue]!", - | "Void expressions cannot be used as values!", - | "Void expressions cannot be used as values!", - | "Void expressions cannot be used as values!", - | "Void expressions cannot be used as values!", - | ], - |} - """.trimMargin(), ) @Test fun voidVsValue() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = """ - |let trick(): Void { 123 } - |let treat(): Int { 456 } - |let trail(): Void { 789; } - """.trimMargin(), - want = """ - |{ - | generateCode: { - | body: - | ``` - | @fn @reach(\none) let trick__0, @fn @reach(\none) treat__0, @fn @reach(\none) trail__0; - | trick__0 = (@stay fn trick /* return__1 */: Void { - | return__1 = 123 - | }); - | treat__0 = (@stay fn treat /* return__2 */: Int32 { - | return__2 = 456 - | }); - | trail__0 = (@stay fn trail /* return__3 */: Void { - | return__3 = void - | }) - | - | ``` - | }, - | errors: [ - | "Cannot assign to Void from Int32!", - | "Expected subtype of Void, but got Int32!", - | ], - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/void-vs-value"), ) @Test fun impliedLambdaReturnType() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = """ - |let f(g: fn (): Int): Int { g() } - |let h(): Void { f { "hi" }; } - """.trimMargin(), - want = """ - |{ - | generateCode: { - | body: - | ``` - | @fn @reach(\none) let f__0, @fn @reach(\none) h__0; - | f__0 = (@stay fn f(g__0 /* aka g */: (fn (): Int32)) /* return__1 */: Int32 { - | return__1 = g__0() - | }); - | h__0 = (@stay fn h /* return__2 */: Void { - | let fn__0; - | fn__0 = (@stay fn /* return__3 */{ - | return__3 = "hi" - | }); - | f__0(fn__0); - | return__2 = void - | }) - | - | ``` - | }, - | errors: [ - | "Expected subtype of Int32, but got String!", - | ], - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/implied-lambda-return-type"), ) @Test fun deadCode() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = """ - |label: do { - | console.log("Logged"); - | break label; - | console.log("Not logged"); - |} - """.trimMargin(), - want = """ - |{ - | generateCode: { - | body: ``` - | do_call_log(getConsole(), "Logged") - | - | ``` - | }, - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/dead-code"), ) @Test fun staticMethods() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = """ - |class C { - | public static let f(i: Int): Int { i + 1 } - |} - |C.f(0) - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/static-methods"), moduleResultNeeded = true, pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - |{ - | generateCode: { - | body: ``` - | let return__0; - | @staticProperty(\f) @fn @static @visibility(\public) @stay @fromType(C__0) @reach(\none) let f__0; - | f__0 = (@stay fn f(i__0 /* aka i */: Int32) /* return__1 */: Int32 { - | return__1 = i__0 + 1 - | }); - | @fn @method(\constructor) @visibility(\public) @stay @fromType(C__0) @reach(\none) let constructor__0; - | constructor__0 = (@stay fn constructor(@impliedThis(C__0) this__0: C__0) /* return__2 */: Void { - | return__2 = void - | }); - | @typeDecl(C__0) @stay @reach(\none) let C__0; - | C__0 = type (C__0); - | return__0 = 1 - | - | ``` - | } - |} - """.trimMargin(), ) @Test fun staticAccessGoodAndBad() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = """ - |class C { - | private static ap: Int = 1; - | public static a: Int = ap + C.ap; - | private bp: Int = 1; - | private b: Int = bp + 1; - | public static f(i: Int): Int { i + a + C.a + ap + C.ap } - | private static fp(i: Int): Int { i + 1 } - | public g(i: Int): Int { 2 * C.f(i) * C.fp(i) * bp * b * this.bp * this.b } - | public h(i: Int): Int { 2 * f(i) * fp(i) * g(i) * this.g(i) } - | public static g2(i: Int): Int { 2 * C.f(i) * C.fp(i) } - | public static h2(i: Int): Int { 2 * f(i) * fp(i) } - |} - |let g3(i: Int): Int { 2 * C.f(i) * new C().g(i) * C.a * C.ap } - """.trimMargin(), - want = """ - |{ - | "syntaxMacro": { - | "body": - | ``` - | @typeDecl(C__0) @stay let C__0 = type (C__0); - | @fn let g3__0; - | class(\word, \C, \concrete, true, @typeDefined(C__0) fn { - | C__0 extends AnyValue; - | @static @visibility(\private) let ap__0: Int = 1; - | @static @visibility(\public) let a__0: Int = ap__0 + igetStatic(C__0, \ap); - | @maybeVar @visibility(\private) let bp__0: Int; - | @maybeVar @visibility(\private) let b__0: Int; - | @fn @static @visibility(\public) let f__0 = fn f(i__0 /* aka i */: Int) /* return__0 */: (Int) { - | fn__0: do { - | i__0 + a__0 + igetStatic(C__0, \a) + ap__0 + igetStatic(C__0, \ap) - | } - | }; - | @fn @static @visibility(\private) let fp__0 = fn fp(i__1 /* aka i */: Int) /* return__1 */: (Int) { - | fn__1: do { - | i__1 + 1 - | } - | }; - | @visibility(\public) @fn let g__0 = fn g(@impliedThis(C__0) this__0: C__0, i__2 /* aka i */: Int) /* return__2 */: (Int) { - | fn__2: do { - | 2 * igetStatic(C__0, \f)(i__2) * igetStatic(C__0, \fp)(i__2) * do_iget_bp(type (C__0), this(C__0)) * do_iget_b(type (C__0), this(C__0)) * do_iget_bp(type (C__0), this(C__0)) * do_iget_b(type (C__0), this(C__0)) - | } - | }; - | @visibility(\public) @fn let h__0 = fn h(@impliedThis(C__0) this__1: C__0, i__3 /* aka i */: Int) /* return__3 */: (Int) { - | fn__3: do { - | 2 * f__0(i__3) * fp__0(i__3) * do_icall_g(type (C__0), this(C__0), i__3) * do_icall_g(type (C__0), this(C__0), i__3) - | } - | }; - | @fn @static @visibility(\public) let g2__0 = fn g2(i__4 /* aka i */: Int) /* return__4 */: (Int) { - | fn__4: do { - | 2 * igetStatic(C__0, \f)(i__4) * igetStatic(C__0, \fp)(i__4) - | } - | }; - | @fn @static @visibility(\public) let h2__0 = fn h2(i__5 /* aka i */: Int) /* return__5 */: (Int) { - | fn__5: do { - | 2 * f__0(i__5) * fp__0(i__5) - | } - | }; - | @visibility(\public) let constructor__0 = fn constructor(@impliedThis(C__0) this__2: C__0) /* return__6 */: Void { - | do { - | do_iset_bp(type (C__0), this(C__0), 1); - | 1 - | }; - | do { - | let t#0; - | do_iset_b(type (C__0), this(C__0), t#0 = do_iget_bp(type (C__0), this(C__0)) + 1); - | t#0 - | }; - | }; - | }); - | g3__0 = fn g3(i__6 /* aka i */: Int) /* return__7 */: (Int) { - | fn__6: do { - | 2 * do_call_f(C__0, i__6) * do_call_g(new C__0(), i__6) * do_get_a(C__0) * do_get_ap(C__0) - | } - | }; - | - | ``` - | }, - | "type": { - | "body": - | ``` - | @typeDecl(C__0) @stay let C__0; - | C__0 = type (C__0); - | @fn let g3__0; - | @static @visibility(\private) @stay @fromType(C__0) let ap__0: Int32; - | ap__0 = 1; - | @static @visibility(\public) @stay @fromType(C__0) let a__0: Int32; - | a__0 = 2; - | @visibility(\private) @stay @fromType(C__0) let bp__0: Int32; - | @visibility(\private) @stay @fromType(C__0) let b__0: Int32; - | @fn @static @visibility(\public) @stay @fromType(C__0) let f__0; - | f__0 = (@stay fn f(i__0 /* aka i */: Int32) /* return__0 */: Int32 { - | void; - | fn__0: do { - | return__0 = i__0 + 2 + igetStatic(C__0, \a) + 1 + igetStatic(C__0, \ap); - | } - | }); - | @fn @static @visibility(\private) @stay @fromType(C__0) let fp__0; - | fp__0 = (@stay fn fp(i__1 /* aka i */: Int32) /* return__1 */: Int32 { - | void; - | fn__1: do { - | return__1 = i__1 + 1; - | } - | }); - | @visibility(\public) @fn @stay @fromType(C__0) let g__0; - | g__0 = fn g(@impliedThis(C__0) this__0: C__0, i__2 /* aka i */: Int32) /* return__2 */: Int32 { - | void; - | fn__2: do { - | return__2 = 2 * igetStatic(C__0, \f)(i__2) * igetStatic(C__0, \fp)(i__2) * getp(bp__0, this__0) * getp(b__0, this__0) * getp(bp__0, this__0) * getp(b__0, this__0); - | } - | }; - | @visibility(\public) @fn @stay @fromType(C__0) let h__0; - | h__0 = (@stay fn h(@impliedThis(C__0) this__1: C__0, i__3 /* aka i */: Int32) /* return__3 */: Int32 { - | void; - | fn__3: do { - | return__3 = 2 * (fn f)(i__3) * (fn fp)(i__3) * do_icall_g(type (C__0), this__1, i__3) * do_icall_g(type (C__0), this__1, i__3); - | } - | }); - | @fn @static @visibility(\public) @stay @fromType(C__0) let g2__0; - | g2__0 = fn g2(i__4 /* aka i */: Int32) /* return__4 */: Int32 { - | void; - | fn__4: do { - | return__4 = 2 * igetStatic(C__0, \f)(i__4) * igetStatic(C__0, \fp)(i__4); - | } - | }; - | @fn @static @visibility(\public) @stay @fromType(C__0) let h2__0; - | h2__0 = (@stay fn h2(i__5 /* aka i */: Int32) /* return__5 */: Int32 { - | void; - | fn__5: do { - | return__5 = 2 * (fn f)(i__5) * (fn fp)(i__5); - | } - | }); - | @fn @visibility(\public) @stay @fromType(C__0) let constructor__0; - | constructor__0 = (@stay fn constructor(@impliedThis(C__0) this__2: C__0) /* return__6 */: Void { - | var t#1; - | setp(bp__0, this__2, 1); - | t#1 = getp(bp__0, this__2) + 1; - | setp(b__0, this__2, t#1); - | return__6 = void - | }); - | g3__0 = (@stay fn g3(i__6 /* aka i */: Int32) /* return__7 */: Int32 { - | void; - | fn__6: do { - | return__7 = 2 * getStatic(C__0, \f)(i__6) * do_call_g(new C__0(), i__6) * getStatic(C__0, \a) * getStatic(C__0, \ap); - | } - | }) - | - | ``` - | }, - | "generateCode": { - | "body": - | ``` - | @typeDecl(C__0) @stay @reach(\none) let C__0; - | C__0 = type (C__0); - | @fn @reach(\none) let g3__0; - | @static @visibility(\private) @stay @fromType(C__0) @reach(\none) let ap__0: Int32; - | ap__0 = 1; - | @static @visibility(\public) @stay @fromType(C__0) @reach(\none) let a__0: Int32; - | a__0 = 2; - | @visibility(\private) @stay @fromType(C__0) @reach(\none) let bp__0: Int32; - | @visibility(\private) @stay @fromType(C__0) @reach(\none) let b__0: Int32; - | @fn @static @visibility(\public) @stay @fromType(C__0) @reach(\none) let f__0; - | f__0 = (@stay fn f(i__0 /* aka i */: Int32) /* return__0 */: Int32 { - | return__0 = i__0 + 2 + igetStatic(C__0, \a) + 1 + igetStatic(C__0, \ap) - | }); - | @fn @static @visibility(\private) @stay @fromType(C__0) @reach(\none) let fp__0; - | fp__0 = (@stay fn fp(i__1 /* aka i */: Int32) /* return__1 */: Int32 { - | return__1 = i__1 + 1 - | }); - | @visibility(\public) @fn @stay @fromType(C__0) @reach(\none) let g__0; - | g__0 = (@stay fn g(@impliedThis(C__0) this__0: C__0, i__2 /* aka i */: Int32) /* return__2 */: Int32 { - | return__2 = 2 * igetStatic(C__0, \f)(i__2) * igetStatic(C__0, \fp)(i__2) * getp(bp__0, this__0) * getp(b__0, this__0) * getp(bp__0, this__0) * getp(b__0, this__0) - | }); - | @visibility(\public) @fn @stay @fromType(C__0) @reach(\none) let h__0; - | h__0 = (@stay fn h(@impliedThis(C__0) this__1: C__0, i__3 /* aka i */: Int32) /* return__3 */: Int32 { - | return__3 = 2 * (fn f)(i__3) * (fn fp)(i__3) * do_icall_g(type (C__0), this__1, i__3) * do_icall_g(type (C__0), this__1, i__3) - | }); - | @fn @static @visibility(\public) @stay @fromType(C__0) @reach(\none) let g2__0; - | g2__0 = (@stay fn g2(i__4 /* aka i */: Int32) /* return__4 */: Int32 { - | return__4 = 2 * igetStatic(C__0, \f)(i__4) * igetStatic(C__0, \fp)(i__4) - | }); - | @fn @static @visibility(\public) @stay @fromType(C__0) @reach(\none) let h2__0; - | h2__0 = (@stay fn h2(i__5 /* aka i */: Int32) /* return__5 */: Int32 { - | return__5 = 2 * (fn f)(i__5) * (fn fp)(i__5) - | }); - | @fn @visibility(\public) @stay @fromType(C__0) @reach(\none) let constructor__0; - | constructor__0 = (@stay fn constructor(@impliedThis(C__0) this__2: C__0) /* return__6 */: Void { - | var t#1; - | setp(bp__0, this__2, 1); - | t#1 = getp(bp__0, this__2) + 1; - | setp(b__0, this__2, t#1); - | return__6 = void - | }); - | g3__0 = (@stay fn g3(i__6 /* aka i */: Int32) /* return__7 */: Int32 { - | return__7 = 2 * getStatic(C__0, \f)(i__6) * do_call_g(new C__0(), i__6) * getStatic(C__0, \a) * getStatic(C__0, \ap) - | }) - | - | ``` - | }, - | errors: [ - | "Type name required for accessing static member!", - | "Type name required for accessing static member!", - | "Type name required for accessing static member!", - | "Type name required for accessing static member!", - | "Type name required for accessing static member!", - | "Type name required for accessing static member!", - | "Type name required for accessing static member!", - | "Member ap defined in C__0 not publicly accessible!" - | ], - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/static-access-good-and-bad"), ) @Test fun noInstantiateInterface() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = """ - |interface Apple {} - |class Banana {} - |new Apple() - |new Banana() - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/no-instantiate-interface"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - |{ - | generateCode: { - | body: ``` - | @typePlaceholder(Apple__0) let typePlaceholder#0: Empty; - | typePlaceholder#0 = {class: Empty__0}; - | @typeDecl(Apple__0) @stay let Apple__0; - | Apple__0 = type (Apple__0); - | @typeDecl(Banana__0) @stay let Banana__0; - | Banana__0 = type (Banana__0); - | @fn @method(\constructor) @visibility(\public) @stay @fromType(Banana__0) let constructor__0; - | constructor__0 = (@stay fn constructor(@impliedThis(Banana__0) this__0: Banana__0) /* return__0 */: Void { - | return__0 = void - | }); - | new Apple__0(); - | new Banana__0() - | - | ``` - | }, - | errors: [ - | "Cannot instantiate abstract type Apple!", - | ], - |} - """.trimMargin(), ) @Test fun exportSome() = assertModuleAtStage( - stage = Stage.GenerateCode, + stageTestDir = StageTestDir("generate-code/export-some"), // Includes examples of different kinds of roots and entities as well as transitive reachability and such. // Also includes an example of something reachable from both export and test roots. - input = """ - |export let exportedInt = 1; - |let unreachableInt = 2; - |export let exportedFunction(b: Boolean): Void { if (b) { conditionallyExportReachable() } } - |let conditionallyExportReachable(): Void { console.log("") } - |let transitivelyTestReachable(): Void { console.log("") } - |let exportAndTestReachable(): Void { console.log("") } - |let initReachable(): Void { transitivelyInitReachable(); console.log("") } - |let transitivelyInitReachable(): Void { console.log("") } - |let unreachableFunction(): Void { console.log("") } - |export class ExportedClass( - | private let propertyOfExportedClass: UsedOnlyAsPropertyType - |) { - | private let methodOfExportedClass(): Void { exportAndTestReachable() } - |} - |class TestReachableClass { - | private let methodOfTestReachable(): Void { transitivelyTestReachable(); exportAndTestReachable() } - |} - |@test("testCase") let testCase(): Void { new TestReachableClass(); } - |class UsedOnlyAsPropertyType {} - |initReachable(); - """.trimMargin(), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - |{ - | generateCode: { - | body: ``` - | let console#0; - | console#0 = getConsole(); - | @fn let `test//`.exportedFunction, @fn conditionallyExportReachable__0, @fn @reach(\test) transitivelyTestReachable__0, @fn exportAndTestReachable__0, @fn initReachable__0, @fn transitivelyInitReachable__0, @fn @reach(\none) unreachableFunction__0; - | @typeDecl(ExportedClass) @stay let `test//`.ExportedClass; - | `test//`.ExportedClass = type (ExportedClass); - | @typeDecl(TestReachableClass__0) @stay @reach(\test) let TestReachableClass__0; - | TestReachableClass__0 = type (TestReachableClass__0); - | @fn @test("testCase") let testCase__0; - | @typeDecl(UsedOnlyAsPropertyType__0) @stay let UsedOnlyAsPropertyType__0; - | UsedOnlyAsPropertyType__0 = type (UsedOnlyAsPropertyType__0); - | let `test//`.exportedInt; - | `test//`.exportedInt = 1; - | @reach(\none) let unreachableInt__0; - | unreachableInt__0 = 2; - | conditionallyExportReachable__0 = (@stay fn conditionallyExportReachable /* return__0 */: Void { - | do_call_log(console#0, ""); - | return__0 = void - | }); - | `test//`.exportedFunction = (@stay fn exportedFunction(b__0 /* aka b */: Boolean) /* return__1 */: Void { - | if (b__0) { - | conditionallyExportReachable__0() - | }; - | return__1 = void - | }); - | transitivelyTestReachable__0 = (@stay fn transitivelyTestReachable /* return__2 */: Void { - | do_call_log(console#0, ""); - | return__2 = void - | }); - | exportAndTestReachable__0 = (@stay fn exportAndTestReachable /* return__3 */: Void { - | do_call_log(console#0, ""); - | return__3 = void - | }); - | transitivelyInitReachable__0 = (@stay fn transitivelyInitReachable /* return__4 */: Void { - | do_call_log(console#0, ""); - | return__4 = void - | }); - | initReachable__0 = (@stay fn initReachable /* return__5 */: Void { - | transitivelyInitReachable__0(); - | do_call_log(console#0, ""); - | return__5 = void - | }); - | unreachableFunction__0 = (@stay fn unreachableFunction /* return__6 */: Void { - | do_call_log(console#0, ""); - | return__6 = void - | }); - | @fn @method(\constructor) @visibility(\public) @stay @fromType(UsedOnlyAsPropertyType__0) let constructor__0; - | constructor__0 = (@stay fn constructor(@impliedThis(UsedOnlyAsPropertyType__0) this__0: UsedOnlyAsPropertyType__0) /* return__7 */: Void { - | return__7 = void - | }); - | @constructorProperty @property(\propertyOfExportedClass) @visibility(\private) @stay @fromType(ExportedClass) let propertyOfExportedClass__0: UsedOnlyAsPropertyType__0; - | @method(\methodOfExportedClass) @visibility(\private) @fn @stay @fromType(ExportedClass) let methodOfExportedClass__0; - | methodOfExportedClass__0 = (@stay fn methodOfExportedClass(@impliedThis(ExportedClass) this__1: ExportedClass) /* return__8 */: Void { - | exportAndTestReachable__0(); - | return__8 = void - | }); - | @fn @method(\constructor) @visibility(\public) @stay @fromType(ExportedClass) let constructor__1; - | constructor__1 = (@stay fn constructor(@impliedThis(ExportedClass) this__2: ExportedClass, propertyOfExportedClass__1 /* aka propertyOfExportedClass */: UsedOnlyAsPropertyType__0) /* return__9 */: Void { - | setp(propertyOfExportedClass__0, this__2, propertyOfExportedClass__1); - | return__9 = void - | }); - | @method(\methodOfTestReachable) @visibility(\private) @fn @stay @fromType(TestReachableClass__0) @reach(\test) let methodOfTestReachable__0; - | methodOfTestReachable__0 = (@stay fn methodOfTestReachable(@impliedThis(TestReachableClass__0) this__3: TestReachableClass__0) /* return__10 */: Void { - | transitivelyTestReachable__0(); - | exportAndTestReachable__0(); - | return__10 = void - | }); - | @fn @method(\constructor) @visibility(\public) @stay @fromType(TestReachableClass__0) @reach(\test) let constructor__2; - | constructor__2 = (@stay fn constructor(@impliedThis(TestReachableClass__0) this__4: TestReachableClass__0) /* return__11 */: Void { - | return__11 = void - | }); - | testCase__0 = (@stay fn testCase /* return__12 */: Void { - | new TestReachableClass__0(); - | return__12 = void - | }); - | initReachable__0() - | - | ```, - | exports: { - | exportedFunction: "fn exportedFunction: Function", - | ExportedClass: "ExportedClass: Type", - | exportedInt: "1: Int32", - | }, - | }, - | errors: [ - | "Export depends publicly on non-exported symbol UsedOnlyAsPropertyType!", - | ], - |} - """.trimMargin(), ) @Test fun initAssignmentReachability() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = """ - |// We don't eliminate var reassignments, so keep associated declarations. - |var hi = 0; - |hi = 1; - |// Non-var for contrast. - |let ha = 2; - """.trimMargin(), - want = """ - |{ - | generateCode: { - | body: ``` - | var hi__0; - | hi__0 = 0; - | hi__0 = 1; - | @reach(\none) let ha__0; - | ha__0 = 2 - | - | ```, - | }, - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/init-assignment-reachability"), ) @Test fun blockLambdaEndToEnd() = assertModuleAtStage( - stage = Stage.Run, + stageTestDir = StageTestDir("generate-code/block-lambda-end-to-end"), moduleResultNeeded = true, - input = """ - |let callIt(f: fn (x: Int): Int): Int { f(1) } - | - |callIt { (x: Int): Int extends Function => - | let y = 41; - | x + y - |} - """.trimMargin(), - want = """ - |{ - | run: "42: Int32" - |} - """.trimMargin(), ) @Test fun generatorInterpreted() = assertModuleAtStage( - stage = Stage.Run, - input = """ - |do { - | // Is thrice still a word? - | let runItThrice(factory: fn (): SafeGenerator): Void { - | let generator: SafeGenerator = factory(); - | generator.next(); - | console.log(","); - | generator.next(); - | console.log(","); - | generator.next(); - | console.log("."); - | } - | - | runItThrice { (): GeneratorResult extends GeneratorFn => - | console.log("First"); - | yield; - | console.log("Second"); - | yield; - | console.log("Third"); - | yield; - | // Not actually reached by runItThrice - | console.log("Fourth"); - | } - |} - """.trimMargin(), - want = """ - |{ - | run: "void: Void", - | type: { - | body: ``` - | let console#0; - | console#0 = doPure(@stay fn /* return__0 */: Console { - | return__0 = getConsole(); - | }); - | @fn let runItThrice__0; - | runItThrice__0 = fn runItThrice(factory__0 /* aka factory */: (fn (): SafeGenerator)) /* return__1 */: Void { - | void; - | fn__0: do { - | let generator__0: SafeGenerator; - | generator__0 = factory__0();${ - "" // Since it's a SafeGenerator, no error checking around do_call_next(...) - } - | do_call_next(generator__0); - | do_call_log(console#0, ","); - | do_call_next(generator__0); - | do_call_log(console#0, ","); - | do_call_next(generator__0); - | do_call_log(console#0, "."); - | return__1 = void - | } - | }; - | runItThrice__0(fn /* return__2 */{${ - "" // Adapt call specialized to adaptGeneratorFnSafe - } - | return__2 = adaptGeneratorFnSafe(@wrappedGeneratorFn fn /* return__3 */: (GeneratorResult) implements GeneratorFn { - | do_call_log(console#0, "First"); - | yield(); - | do_call_log(console#0, "Second"); - | yield(); - | do_call_log(console#0, "Third"); - | yield(); - | do_call_log(console#0, "Fourth"); - | return__3 = core.doneResult() - | }) - | }); - | - | ``` - | }, - | stdout: ``` - | First - | , - | Second - | , - | Third - | . - | - | ``` - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/generator-interpreted"), ) @Test fun generatorInterpretedInLoop() = assertModuleAtStage( - stage = Stage.Run, - input = """ - |do { - | // Is thrice still a word? - | let runItThrice(factory: fn (): SafeGenerator): Void { - | let generator: SafeGenerator = factory(); - | generator.next(); - | console.log("Ran once"); - | generator.next(); - | console.log("Ran twice"); - | generator.next(); - | console.log("Ran thrice"); - | generator.close(); - | } - | - | runItThrice { (): GeneratorResult extends GeneratorFn => - | while (true) { - | console.log("Pausing"); - | yield; - | console.log("Resuming"); - | } - | } - |} - """.trimMargin(), - want = """ - |{ - | run: "void: Void", - | type: { - | body: ``` - | let console#0; - | console#0 = doPure(@stay fn /* return__0 */: Console { - | return__0 = getConsole(); - | }); - | @fn let runItThrice__0; - | runItThrice__0 = fn runItThrice(factory__0 /* aka factory */: (fn (): SafeGenerator)) /* return__1 */: Void { - | void; - | fn__0: do { - | let generator__0: SafeGenerator; - | generator__0 = factory__0(); - |## Since it's a SafeGenerator, no error checking around do_call_next(...) - | do_call_next(generator__0); - | do_call_log(console#0, "Ran once"); - | do_call_next(generator__0); - | do_call_log(console#0, "Ran twice"); - | do_call_next(generator__0); - | do_call_log(console#0, "Ran thrice"); - | do_call_close(generator__0); - | return__1 = void - | } - | }; - | runItThrice__0(fn /* return__2 */{ - |## Adapt call specialized to adaptGeneratorFnSafe - | return__2 = adaptGeneratorFnSafe(@wrappedGeneratorFn fn /* return__3 */: (GeneratorResult) implements GeneratorFn { - | return__3 = core.doneResult(); - |## The interpreter needs to distinguish a legit return result with the result from a yield. - | void; - | while (true) { - | do_call_log(console#0, "Pausing"); - | yield(); - | do_call_log(console#0, "Resuming"); - | } - | }) - | }); - | - | ``` - | }, - | stdout: ``` - | Pausing - | Ran once - | Resuming - | Pausing - | Ran twice - | Resuming - | Pausing - | Ran thrice - | - | ``` - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), + stageTestDir = StageTestDir("generate-code/generator-interpreted-in-loop"), ) @Ignore @Test fun generatorResultsUsed() = assertModuleAtStage( - stage = Stage.Run, - input = $$""" - |do { - | let adNauseam(factory: fn (): SafeGenerator): Void { - | let generator: SafeGenerator = factory(); - | while (true) { - | let x = generator.next(); - | when (x) { - | is DoneResult -> break; - | is ValueResult -> console.log("Received ${ x.value.toString() }"); - | } - | } - | generator.close(); - | console.log("Done"); - | } - | - | adNauseam { (): GeneratorResult extends GeneratorFn => - | yield 1; - | yield 2; - | } - |} - """.trimMargin(), - want = """ - |{ - | run: "void: Void", - | stdout: ``` - | Received 1 - | Received 2 - | Done - | - | ``` - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/generator-results-used"), ) @Test fun forOfExample() = assertModuleAtStage( - stage = Stage.Run, - input = """ - |for (let i of [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) { - | if (i & 1 == 0) { continue } - | if (i == 7) { break } - | console.log(i.toString()); - |} - """.trimMargin(), - want = """ - |{ - | run: "void: Void", - | stdout: ``` - | 1 - | 3 - | 5 - | - | ``` - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/for-of-example"), ) @Test fun awaiting() = assertModuleAtStage( - stage = Stage.Run, + stageTestDir = StageTestDir("generate-code/awaiting"), stagingFlags = setOf(StagingFlags.allowTopLevelAwait), - input = """ - |let pb = new PromiseBuilder(); - |let p = pb.promise; - |async { (): GeneratorResult extends GeneratorFn => - | pb.complete("Hello, World!"); - |} - |console.log(await p); - """.trimMargin(), - want = """ - |{ - | run: "void: Void", - | stdout: ``` - | Hello, World! - | - | ```, - | generateCode: { - | body: ``` - | var t#0, t#1, fail#0; - | t#0 = getConsole(); - | let pb__0; - | pb__0 = new PromiseBuilder(); - | let p__0; - | p__0 = do_get_promise(pb__0); - | let fn__0; - | fn__0 = (@stay fn /* return__0 */{ - | let fn__1; - | fn__1 = (@wrappedGeneratorFn fn /* return__1 */: (GeneratorResult) implements GeneratorFn { - | do_call_complete(pb__0, "Hello, World!"); - | return__1 = (fn doneResult)() - | }); - | return__0 = adaptGeneratorFnSafe(fn__1) - | }); - | async(fn__0); - | t#1 = hs(fail#0, await p__0); - | if (fail#0) { - | bubble() - | }; - | do_call_log(t#0, t#1) - | - | ``` - | } - |} - """.trimMargin(), ) @Test fun invalidRtti() = assertModuleAtStage( - stage = Stage.Run, + stageTestDir = StageTestDir("generate-code/invalid-rtti"), // Check that is T and as T only operate // on types that can be distinguished at runtime. - input = """ - |class UnconnectedUserType {} - | - |let f( - | a: AnyValue, - | s: String, - | son: String?, - | i: Int, - | ion: Int?, - | f: Float64, - | fon: Float64?, - | b: Boolean, - | bon: Boolean?, - | n: Never?, - | k: MapKey, - |): Void throws Bubble { - | // Illegal. Multiple other types could connect to target language string type - | a as String orelse do {}; - | a as Int orelse do {}; - | a as Boolean orelse do {}; - | k as String orelse do {}; - | // Illegal, type formals can't be cast targets. - | a as T orelse do {}; - | // Does nothing. - | s as String orelse do {}; - | b as Boolean orelse do {}; - | i as Int orelse do {}; - | bon as Boolean?; - | n as Never? orelse do {}; - | // Ok. Can always check nullity - | a as Never? orelse do {}; - | son as Never? orelse do {}; - | ion as Never? orelse do {}; - | fon as Never? orelse do {}; - | bon as Never? orelse do {}; - | // Types are statically disjoint - | s as Int orelse do {}; - | i as String orelse do {}; - | b as Never? orelse do {}; - | n as Int orelse do {}; - | k as Float64 orelse do {}; - | k as Int orelse do {}; - | // ok to unconnected class type. - | a as UnconnectedUserType orelse do {}; - | - | // TODO: `is` equivalents of some of the above - |} - """.trimMargin(), logEntryWanted = { it.level >= Log.Warn || // This is a low-level message, but it's specific to these checks. it.template == MessageTemplate.UnnecessaryRttiCheck }, - want = """ - |{ - | run: "void: Void", - | errors: [ - | // a as String; - | "Types marked @mayDowncastTo(false) cannot be targeted with is or as runtime type checks because they may not be distinct on all backends: <[String]> from AnyValue!", - | // a as Int; - | "Types marked @mayDowncastTo(false) cannot be targeted with is or as runtime type checks because they may not be distinct on all backends: <[Int32]> from AnyValue!", - | // a as Boolean; - | "Types marked @mayDowncastTo(false) cannot be targeted with is or as runtime type checks because they may not be distinct on all backends: <[Boolean]> from AnyValue!", - | // k as String; - | "Types marked @mayDowncastTo(false) cannot be targeted with is or as runtime type checks because they may not be distinct on all backends: <[String]> from MapKey!", - | // a as T; - | "Type parameters cannot be targeted with is or as runtime type checks: <[T__1]> from AnyValue!", - | // s as String; - | "Unnecessary type check to String from expression with type String which is a subtype", - | // b as Boolean; - | "Unnecessary type check to Boolean from expression with type Boolean which is a subtype", - | // i as Int; - | "Unnecessary type check to Int32 from expression with type Int32 which is a subtype", - | // s as Int; - | "Runtime type check from String to Int32 can never succeed!", - | // i as String; - | "Runtime type check from Int32 to String can never succeed!", - | // n as Int; - | "Runtime type check from Null to Int32 can never succeed!", - | // k as Float64; - | "Unrelated types cannot be targeted with is or as runtime type checks: <[Float64]> from MapKey!", - | // k as Int; - | "Types marked @mayDowncastTo(false) cannot be targeted with is or as runtime type checks because they may not be distinct on all backends: <[Int32]> from MapKey!", - | ] - |} - """.trimMargin(), ) @Test fun invalidRttiTypeArgs() = assertModuleAtStage( - stage = Stage.Run, - input = """ - |interface Sup {} - |class Sub extends Sup {} - |interface Sup2 extends Sup {} - |class Sub2 extends Sup2 {} // sneak swap the meaning of T - |class Sub3 extends Sup2 {} // weaves T through - |class Sub4 extends Sup {} - |let badCast(value: AnyValue): Sub throws Bubble { - | // Introduces String. - | value as Sub - |} - |let alsoBad(value: Sup): Sub throws Bubble { - | // Presumes known type arg for T. - | value as Sub - |} - |let goodCast(value: Sup): Sub throws Bubble { - | // Keeps the known type arg. - | value as Sub - |} - |let alsoGood(value: Sup): Sub throws Bubble { - | // Also keeps the known type arg, which is also a type param. - | value as Sub - |} - |let butThisIsBad(value: Sup): Sub2 throws Bubble { - | // The T args here aren't actually related. Presumes String as an arg for U. - | value as Sub2 - |} - |let alsoBadBecauseExtra(value: Sup): Sup2 throws Bubble { - | // Introduces T. - | value as Sup2 - |} - |let butThisIsGood(value: Sup): Sup2 throws Bubble { - | // Uses known U for both cases. - | value as Sup2 - |} - |let goodDespiteMiddle(value: Sup): Sub3 throws Bubble { - | // Invents String for Sup2 T, but that doesn't matter because it's not represented. - | value as Sub3 - |} - |let badNonGeneric(value: Sup): Sub4 throws Bubble { - | // Invents String for Sup T without any generics in Sub4 at all. - | value as Sub4 - |} - """.trimMargin(), - want = """ - |{ - | run: "void: Void", - | errors: [ - | "Type arguments cannot be introduced with is or as runtime type checks: <[Sub__0]> from AnyValue!", - | "Unrelated types cannot be targeted with is or as runtime type checks: <[Sub__0]> from Sup__0!", - | "Unrelated types cannot be targeted with is or as runtime type checks: <[Sub2__0]> from Sup__0!", - | "Type arguments cannot be introduced with is or as runtime type checks: <[Sup2__0]> from Sup__0!", - | "Unrelated types cannot be targeted with is or as runtime type checks: <[Sub4__0]> from Sup__0!" - | ] - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/invalid-rtti-type-args"), ) @Test fun invalidRttiNotInlined() = assertModuleAtStage( - stage = Stage.GenerateCode, + stageTestDir = StageTestDir("generate-code/invalid-rtti-not-inlined"), // Check that is T and as T that would be invalid // if translated aren't inlined. - input = """ - |let s: AnyValue = "str"; - |s is String - """.trimMargin(), moduleResultNeeded = true, logEntryWanted = { // UnnecessaryRttiCheck is low level, but relevant inside a REPL. it.level >= Log.Warn || it.template == MessageTemplate.UnnecessaryRttiCheck }, - want = """ - |{ - | generateCode: { - | body: ``` - | let return__0, @reach(\none) s__0: AnyValue; - | s__0 = "str"; - | return__0 = "str" is String - | - | ``` - | }, - | errors: [ - | "Unnecessary type check to String from expression with type String which is a subtype" - | ] - |} - """.trimMargin(), ) @Test fun upcastOk() = assertModuleAtStage( - stage = Stage.Run, + stageTestDir = StageTestDir("generate-code/upcast-ok"), // Use Map here because that was the original motivating example, even though it's not vital to the test. - input = """ - |interface A {} - |class B extends A {} - |class C extends A {} - |// Basic and upcast are fine. No warnings. - |let bVals = new Map([new Pair("a", new B())]); - |let aVals = new Map([new Pair("a", new B() as A)]); - |// Samecast should still get a warning. - |let bbVals = new Map([new Pair("a", new B() as B)]); - |// Upcheck should also get a warning. Here we use a different subtype for clear message distinction. - |let isSub = new C() is A; - """.trimMargin(), logEntryWanted = { // UnnecessaryRttiCheck is low level, but relevant inside a REPL. it.level >= Log.Warn || it.template == MessageTemplate.UnnecessaryRttiCheck }, // Key focus being no errors here. - want = """ - |{ - | run: "void: Void", - | errors: [ - | "Unnecessary type check to B__0 from expression with type B__0 which is a subtype", - | "Unnecessary type check to A__0 from expression with type C__2 which is a subtype", - | ], - |} - """.trimMargin(), ) @Test fun castAwayNullWorksAtRuntime() = assertModuleAtStage( - stage = Stage.Run, - input = $$""" - |let f(x: Float64?): Float64? { (x as Float64) orelse null } - |console.log("f(1.0) = ${ f(1.0) }"); - """.trimMargin(), - want = """ - |{ - | run: "void: Void", - | stdout: "f(1.0) = 1.0\n", - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/cast-away-null-works-at-runtime"), ) @Test fun matchWithCharExprCases() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = """ - |let abcStop(i: Int): String { - | when (i) { - | char 'a', char 'b', char 'c' -> "ok"; - | else -> "stop"; - | } - |} - """.trimMargin(), - want = """ - |{ - | generateCode: { - | body: ``` - | @fn @reach(\none) let abcStop__0; - | abcStop__0 = (@stay fn abcStop(i__0 /* aka i */: Int32) /* return__0 */: String { - | var t#0, t#1; - | if (i__0 == 97) { - | t#1 = true - | } else { - | if (i__0 == 98) { - | t#0 = true - | } else { - | t#0 = i__0 == 99 - | }; - | t#1 = t#0 - | }; - | if (t#1) { - | return__0 = "ok" - | } else { - | return__0 = "stop" - | } - | }) - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/match-with-char-expr-cases"), ) @Test fun sealedConnectedCasts() = assertModuleAtStage( + stageTestDir = StageTestDir("generate-code/sealed-connected-casts"), // comments in the cast checker describe why this is the way it is. // In short, a sealed, connected type must be able to distinguish // its subtypes, so the static expression type matters when casting. - stage = Stage.Run, - provisionModule = { module, _ -> - module.deliverContent( - ModuleSource( - filePath = testCodeLocation, - fetchedContent = """ - |@connected - |export sealed interface S {} - | - |@connected - |class C extends S {} - |@connected - |class D extends S {} - | - |@connected - |interface NS extends S {} - |@connected - |class E extends NS {} - | - |export let f(a: AnyValue, s: S): Void throws Bubble { - | a as C; // BAD: C is connected, and AnyValue is not. - | s as C; // OK. C is a sub-type of S - | s as E; // BAD. E is a sub-type of S, but only via NS which is not-sealed. - |} - """.trimMargin(), - languageConfig = StandaloneLanguageConfig, - ), - ) - }, - want = """ - |{ - | run: "void: Void", - | errors: [ - | "Connected types cannot be targeted with is or as runtime type checks because multiple Temper types are allowed to connect to the same backend type: <[C__1]> from AnyValue!", - | "Connected types cannot be targeted with is or as runtime type checks because multiple Temper types are allowed to connect to the same backend type: <[E__4]> from S!", - | ], - |} - """.trimMargin(), ) @Test fun stringNullEquality() = assertModuleAtStage( - input = """ - |let f(s: String?): Boolean { s == null } - | - |!f("") && f(null) - """.trimMargin(), - stage = Stage.Run, + stageTestDir = StageTestDir("generate-code/string-null-equality"), moduleResultNeeded = true, - want = """ - |{ - | run: "true: Boolean", - |} - """.trimMargin(), ) @Test fun asAndIsSimplification1() = assertModuleAtStage( - input = """ - |let f(i: StringIndexOption?): Int throws Bubble { - | if (i is StringIndex) { - | 0 - | } else { - | 1 - | } - |} - """.trimMargin(), - stage = Stage.GenerateCode, - want = """ - |{ - | generateCode: { - | body: ``` - | @fn @reach(\none) let f__0; - | f__0 = (@stay fn f(i__0 /* aka i */: StringIndexOption?) /* return__0 */: (Int32 | Bubble) { - | var t#0; - | if (!isNull(i__0)) { - | t#0 = i__0 is StringIndex - | } else { - | t#0 = false - | }; - | if (t#0) { - | return__0 = 0 - | } else { - | return__0 = 1 - | } - | }) - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/as-and-is-simplification1"), ) @Test fun asAndIsSimplification2() = assertModuleAtStage( - input = """ - |let f(i: StringIndexOption?): Int throws Bubble { - | if (i is StringIndexOption) { - | 0 - | } else { - | 1 - | } - |} - """.trimMargin(), - stage = Stage.GenerateCode, - want = """ - |{ - | generateCode: { - | body: ``` - | @fn @reach(\none) let f__0; - | f__0 = (@stay fn f(i__0 /* aka i */: StringIndexOption?) /* return__0 */: (Int32 | Bubble) { - | var t#0; - | if (!isNull(i__0)) { - | t#0 = i__0 is StringIndexOption - | } else { - | t#0 = false - | }; - | if (t#0) { - | return__0 = 0 - | } else { - | return__0 = 1 - | } - | }) - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/as-and-is-simplification2"), ) @Test fun asAndIsSimplification3() = assertModuleAtStage( - input = """ - |let f(i: StringIndexOption?): Int throws Bubble { - | do { - | let j = i as StringIndex?; - | 0 - | } orelse 1 - |} - """.trimMargin(), - stage = Stage.GenerateCode, - want = """ - |{ - | generateCode: { - | body: ``` - | @fn @reach(\none) let f__0; - | f__0 = (@stay fn f(i__0 /* aka i */: StringIndexOption?) /* return__0 */: (Int32 | Bubble) { - | var fail#0; - | orelse#0: { - | let j__0; - | if (isNull(i__0)) { - | j__0 = null - | } else { - | j__0 = hs(fail#0, i__0 as StringIndex); - | if (fail#0) { - | break orelse#0; - | } - | }; - | return__0 = 0 - | } orelse { - | return__0 = 1 - | } - | }) - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/as-and-is-simplification3"), ) @Test fun asAndIsSimplification4() = assertModuleAtStage( - input = """ - |let f(i: StringIndexOption?): Int throws Bubble { - | if (i is StringIndex?) { - | let j = i as StringIndex?; - | if (j is StringIndex) { - | 1 - | } else { - | 2 - | } - | } else { - | let n = i as Never?; - | 3 - | } - |} - """.trimMargin(), - stage = Stage.GenerateCode, - want = """ - |{ - | generateCode: { - | body: ``` - | @fn @reach(\none) let f__0; - | f__0 = (@stay fn f(i__0 /* aka i */: StringIndexOption?) /* return__0 */: (Int32 | Bubble) { - | var t#0, t#1, t#2, t#3, fail#0; - | if (isNull(i__0)) { - | t#0 = true - | } else { - | t#0 = i__0 is StringIndex - | }; - | if (t#0) { - | if (isNull(i__0)) { - | t#3 = null - | } else { - | t#3 = assertAs(i__0, StringIndex) - | }; - | let j__0; - | if (isNull(t#3)) { - | j__0 = null - | } else { - | t#1 = hs(fail#0, t#3 as StringIndex); - | if (fail#0) { - | bubble() - | }; - | j__0 = t#1 - | }; - | if (!isNull(j__0)) { - | t#2 = j__0 is StringIndex - | } else { - | t#2 = false - | }; - | if (t#2) { - | return__0 = 1 - | } else { - | return__0 = 2 - | } - | } else { - | let n__0; - | if (!isNull(i__0)) { - | bubble() - | }; - | n__0 = null; - | return__0 = 3 - | } - | }) - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/as-and-is-simplification4"), ) // Complex expressions caught in temporary @Test fun asAndIsSimplification5() = assertModuleAtStage( - input = """ - |let g(s: String): StringIndexOption { - | s.end - |} - |let f(s: String): Boolean { - | g(s) is NoStringIndex - |} - """.trimMargin(), - stage = Stage.GenerateCode, - want = """ - |{ - | generateCode: { - | body: ``` - | @fn @reach(\none) let g__0, @fn @reach(\none) f__0; - | g__0 = (@stay fn g(s__0 /* aka s */: String) /* return__0 */: StringIndexOption { - | return__0 = do_get_end(s__0) - | }); - | f__0 = (@stay fn f(s__1 /* aka s */: String) /* return__1 */: Boolean { - | return__1 = (fn g)(s__1) is NoStringIndex - | }) - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/as-and-is-simplification5"), ) @Test fun nullSimplification() = assertModuleAtStage( - input = """ - |let f(s: String?): Boolean { - | s == null - |} - |let g(s: String?): Boolean { - | s != null - |} - """.trimMargin(), - stage = Stage.GenerateCode, - want = """ - |{ - | generateCode: { - | body: ``` - | @fn @reach(\none) let f__0, @fn @reach(\none) g__0; - | f__0 = (@stay fn f(s__0 /* aka s */: String?) /* return__0 */: Boolean { - | return__0 = isNull(s__0) - | }); - | g__0 = (@stay fn g(s__1 /* aka s */: String?) /* return__1 */: Boolean { - | return__1 = !isNull(s__1) - | }) - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/null-simplification"), ) @Test fun sneakyBubble() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = """ - |class Something(public let haha: Int?) {} - """.trimMargin(), - want = """ - |{ - | generateCode: { - | body: ``` - | @constructorProperty @visibility(\public) @stay @fromType(Something__0) @reach(\none) let haha__0: Int32?; - | @fn @visibility(\public) @stay @fromType(Something__0) @reach(\none) let constructor__0; - | constructor__0 = (@stay fn constructor(@impliedThis(Something__0) this__0: Something__0, haha__1 /* aka haha */: Int32?) /* return__0 */: Void { - | setp(haha__0, this__0, haha__1); - | return__0 = void - | }); - | @fn @visibility(\public) @stay @fromType(Something__0) @reach(\none) let gethaha__0; - | gethaha__0 = (@stay fn (@impliedThis(Something__0) this__1: Something__0) /* return__1 */: (Int32?) { - | return__1 = getp(haha__0, this__1) - | }); - | @typeDecl(Something__0) @stay @reach(\none) let Something__0; - | Something__0 = type (Something__0) - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/sneaky-bubble"), ) @Test fun bubbleOrElseNot() = assertModuleAtStage( - stage = Stage.GenerateCode, + stageTestDir = StageTestDir("generate-code/bubble-or-else-not"), // Explore bubbles both escaping and captured, both explicit and implicit, both builtin and user functions. // Just making sure to explore the space of how we handle things. - input = """ - |let other(i: Int): Int throws Bubble { - | if (i % 2 == 0) { - | // Bubble allowed above. - | bubble() - | } else { - | i - | } - |} - |let something(nums: Map, index: Int): Int { - | // No `| Bubble` above, so bubblies should error. - | if (index < 0) { - | bubble() - | } else if (index == 0) { - | other(index) - | } else if (index == 1) { - | nums[index] - | } else { - | do { - | if (index < nums[index]) { - | index + 1 - | } else if (index > 10) { - | other(index + 1) - | } else { - | bubble() - | } - | } orelse index - | } - |} - """.trimMargin(), - want = """ - |{ - | generateCode: { - | body: ``` - | @fn @reach(\none) let other__0, @fn @reach(\none) something__0; - | other__0 = (@stay fn other(i__0 /* aka i */: Int32) /* return__0 */: (Int32 | Bubble) { - | if (i__0 % 2 == 0) { - | bubble() - | } else { - | return__0 = i__0 - | } - | }); - | something__0 = (@stay fn something(nums__0 /* aka nums */: Map, index__0 /* aka index */: Int32) /* return__1 */: Int32 { - | var t#0, t#1, fail#0, fail#1, fail#2, fail#3; - | if (index__0 < 0) { - | bubble() - | } else if (index__0 == 0) { - | return__1 = hs(fail#0, (fn other)(index__0)); - | if (fail#0) { - | bubble() - | } - | } else if (index__0 == 1) { - | return__1 = hs(fail#1, do_call_get(nums__0, index__0)); - | if (fail#1) { - | bubble() - | } - | } else { - | orelse#0: { - | t#0 = hs(fail#2, do_call_get(nums__0, index__0)); - | if (fail#2) { - | break orelse#0; - | }; - | if (index__0 < t#0) { - | return__1 = index__0 + 1 - | } else if (index__0 > 10) { - | t#1 = hs(fail#3, (fn other)(index__0 + 1)); - | if (fail#3) { - | break orelse#0; - | }; - | return__1 = t#1 - | } else { - | break orelse#0; - | } - | } orelse { - | return__1 = index__0 - | } - | } - | }) - | - | ``` - | }, - | errors: [ - | // Only for the 3 cases that actually bubble. - | "Cannot bubble from a function without Bubble in its return type!", - | "Cannot bubble from a function without Bubble in its return type!", - | "Cannot bubble from a function without Bubble in its return type!", - | ], - |} - """.trimMargin(), ) @Test fun extensionMethodUse() = assertModuleAtStage( - stage = Stage.Run, + stageTestDir = StageTestDir("generate-code/extension-method-use"), moduleResultNeeded = true, - input = """ - |@extension("isPalindrome") - |let stringIsPalindrome(s: String): Boolean { - | var i = String.begin; - | var j = s.end; - | while (i < j) { - | j = s.prev(j); - | if (s[i] != s[j]) { return false } - | i = s.next(i); - | } - | return true - |} - |"step on no pets".isPalindrome() - """.trimMargin(), - want = """ - |{ - | define: { - | body: ``` - | @fn @extension("isPalindrome") let stringIsPalindrome__0; - | stringIsPalindrome__0 = fn stringIsPalindrome(s__0 /* aka s */: String) /* return__0 */: Boolean { - | fn__0: do { - | var i__0; - | i__0 = getStatic(String, \begin); - | var j__0; - | j__0 = do_get_end(s__0); - | while(i__0 < j__0, fn { - | j__0 = do_call_prev(s__0, j__0); - | if(do_call_get(s__0, i__0) != do_call_get(s__0, j__0), fn { - | do { - | return__0 = false; - | break(\label, fn__0) - | } - | }); - | i__0 = do_call_next(s__0, i__0); - | }); - | do { - | return__0 = true; - | break(\label, fn__0) - | } - | } - | }; - | (do_call_isPalindrome[stringIsPalindrome__0])("step on no pets") - | - | ``` - | }, - | type: { - | body: ``` - | let return__1, @fn @extension("isPalindrome") stringIsPalindrome__0; - | stringIsPalindrome__0 = (@stay fn stringIsPalindrome(s__0 /* aka s */: String) /* return__0 */: Boolean { - | void; - | fn__0: do { - | var i__0; - | i__0 = getStatic(String, \begin); - | var j__0; - | j__0 = do_get_end(s__0); - | while (i__0 < j__0) { - | j__0 = do_call_prev(s__0, j__0); - | if (do_call_get(s__0, i__0) != do_call_get(s__0, j__0)) { - | return__0 = false; - | break fn__0; - | }; - | i__0 = do_call_next(s__0, i__0); - | }; - | return__0 = true - | } - | }); - | return__1 = stringIsPalindrome__0("step on no pets");${ - "" // The do_call_isPalindrome got rewritten to the direct function reference - } - | - | ``` - | }, - | run: "true: Boolean" - |} - """.trimMargin(), ) @Test fun jsonAdapterWorks() = assertModuleAtStage( - stage = Stage.Run, + stageTestDir = StageTestDir("generate-code/json-adapter-works"), moduleResultNeeded = true, - input = """ - |@json class C {} - |C.jsonAdapter() - """.trimMargin(), - want = """ - |{ - | run: "{}: CJsonAdapter__0" - |} - """.trimMargin(), ) @Test fun jsonAdapterEncodesSealedTypes() = assertModuleAtStage( - stage = Stage.Run, + stageTestDir = StageTestDir("generate-code/json-adapter-encodes-sealed-types"), moduleResultNeeded = true, - input = """ - |let { - | JsonTextProducer, - | listJsonAdapter, - |} = import("std/json"); - | - |@json sealed interface Animal {} - |@json class Cat(public meowCount: Int) extends Animal {} - |@json class Dog(public hydrantsSniffed: Int) extends Animal {} - | - |let ls: List = [new Cat(11), new Dog(111)]; - | - |let p = new JsonTextProducer(); - |List.jsonAdapter(Animal.jsonAdapter()).encodeToJson(ls, p); - |p.toJsonString() - """.trimMargin(), - want = """ - |{ - | run: "\"[{\\\"meowCount\\\":11},{\\\"hydrantsSniffed\\\":111}]\": String" - |} - """.trimMargin(), ) @Test fun jsonAdapterDecodesSealedTypes() = assertModuleAtStage( - stage = Stage.Run, + stageTestDir = StageTestDir("generate-code/json-adapter-decodes-sealed-types"), moduleResultNeeded = true, - input = """ - |let { - | JsonTextProducer, - | listJsonAdapter, - | parseJson, - | NullInterchangeContext, - |} = import("std/json"); - | - |@json sealed interface Animal {} - |@json class Cat(public meowCount: Int) extends Animal {} - |@json class Dog(public hydrantsSniffed: Int) extends Animal {} - | - |let t = parseJson( - | ${"\"\"\""} - | "[ - | " { "meowCount": 137 }, - | " { "hydrantsSniffed": 1337 } - | "] - |); - | - |List.jsonAdapter(Animal.jsonAdapter()).decodeFromJson(t, NullInterchangeContext.instance) - """.trimMargin(), - want = """ - |{ - | run: "[{meowCount: 137}, {hydrantsSniffed: 1337}]: List" - |} - """.trimMargin(), ) @Test fun nullableJsonField() = assertModuleAtStage( - stage = Stage.Run, + stageTestDir = StageTestDir("generate-code/nullable-json-field"), moduleResultNeeded = true, - input = """ - |let { - | NullInterchangeContext, - | OrNullJsonAdapter, - | booleanJsonAdapter, - | listJsonAdapter, - | parseJson, - |} = import("std/json"); - |let a = List.jsonAdapter(new OrNullJsonAdapter(Boolean.jsonAdapter())); - | - |a.decodeFromJson(parseJson("[null, false, true]"), NullInterchangeContext.instance) - """.trimMargin(), - want = """ - |{ - | run: "[null, false, true]: List", - |} - """.trimMargin(), ) @Test fun jsonInteropForwardsTypeInfoForNullableProps() = assertModuleAtStage( - stage = Stage.Run, + stageTestDir = StageTestDir("generate-code/json-interop-forwards-type-info-for-nullable-props"), moduleResultNeeded = true, - input = """ - |let { NullInterchangeContext, parseJson } = import("std/json"); - | - |@json class C(public i: Int?) {} - | - |C.jsonAdapter().decodeFromJson(parseJson('{"i": null}'), NullInterchangeContext.instance) - """.trimMargin(), - want = """ - |{ - | run: "{i: null}: C__0" - |} - """.trimMargin(), ) @Test fun rgxMacro() = assertModuleAtStage( - stage = Stage.Run, + stageTestDir = StageTestDir("generate-code/rgx-macro"), moduleResultNeeded = true, - input = """ - |let { ... } = import("std/regex"); - | - |rgx"." - """.trimMargin(), - want = """ - |{ - | run: "{data: {}, compiled: ƒ}: `std/regex/`.Regex" - |} - """.trimMargin(), ) @Test fun complexStringExpr() = assertModuleAtStage( - stage = Stage.Run, + stageTestDir = StageTestDir("generate-code/complex-string-expr"), moduleResultNeeded = true, - input = $$""" - |let guests = ["Hilo, HI", "you in the back in the hat"]; - |$${"\"\"\""} - |~Hello, World - |:for (let guest of guests) { - | ~, and ${guest} - |:} - |~! - """.trimMargin(), - want = """ - |{ - | import: { - | body: ``` - | let guests = list("Hilo, HI", "you in the back in the hat"); - | do { - | let accumulator#0: StringBuilder; - | accumulator#0 = new StringBuilder (); - | do { - | do_call_append(accumulator#0, "Hello, World"); - | for((let guest of guests), fn { - | do_call_append(accumulator#0, ", and "); - | do_call_append(accumulator#0, str(guest)); - | }); - | do_call_append(accumulator#0, "!"); - | }; - | do_call_toString(accumulator#0) - | } - | - | ``` - | }, - | run: ["Hello, World, and Hilo, HI, and you in the back in the hat!", "String"], - |} - """.trimMargin(), ) @Test fun complexStringExprWithFormattingHole() = assertModuleAtStage( - stage = Stage.Run, + stageTestDir = StageTestDir("generate-code/complex-string-expr-with-formatting-hole"), moduleResultNeeded = true, - input = $$""" - |$${"\"\"\""} - |~Things: ${} - |:for (var i = 1; i < 100; i *= 2) { - | ~${i}, ${} - | // Comment inside loop after content. - |:} - |~and so on - """.trimMargin(), - want = """ - |{ - | run: ["Things: 1, 2, 4, 8, 16, 32, 64, and so on", "String"], - |} - """.trimMargin(), ) @Test fun complexStringExprWithFormattingHoleAndMore() = assertModuleAtStage( - stage = Stage.Run, + stageTestDir = StageTestDir("generate-code/complex-string-expr-with-formatting-hole-and-more"), moduleResultNeeded = true, - input = $$""" - |$${"\"\"\""} - |:var after = "and such"; - |:for (var i = 1; i < 100; i *= 2) { - | // Comment inside loop before split content. - | // Second comment. - | :let j = i - 1; - | ~${j + 1} - | :after = "and so on"; - | ~, - | :do { - | // And a trailing space inside a nested block. - | ~ ${} - | :} - | // Just some nothings for funsies. - | ~ - | ~ - |:} - |~${after} - """.trimMargin(), - want = """ - |{ - | run: ["1, 2, 4, 8, 16, 32, 64, and so on", "String"], - |} - """.trimMargin(), ) @Test fun explicitBoundedTypeParametersInInterpreter() = assertModuleAtStage( - stage = Stage.Run, - input = """ - |interface I { x: String } - | - |class C(public x: String) extends I {} - | - |let least(a: T?, b: T?): T? { - | if (a != null) { - | if (b != null) { - | if (a.x < b.x) { a } else { b } - | } else { - | a - | } - | } else { - | b - | } - |} - | - |let c = least({ x: "foo" }, { x: "bar" }); - |console.log(c?.x ?? "NULL"); - """.trimMargin(), - want = """ - |{ - | run: "void: Void", - | stdout: "bar\n" - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/explicit-bounded-type-parameters-in-interpreter"), ) @Test fun invalidNonNullCheck() = assertModuleAtStage( - stage = Stage.Run, - input = """ - |export let Act = fn (i: Int): Void; - |export let hi(i: Int, act: Act?): Void { - | if (i == 0 || act != null) { - | // `||` means act could be null here. - | act(i); - | } - |} - """.trimMargin(), - want = """ - |{ - | run: "void: Void", - | errors: ["Expected function type, but got (fn (Int32): Void)?!"], - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/invalid-non-null-check"), ) @Test fun multiImport() = assertModuleAtStage( - input = """ - |let { ... } = import("./nums"); - | - |console.log((a + b + c + d + e).toString()); - | - |$TEST_INPUT_MODULE_BREAK ./nums/nums.temper - |export let a = 1; - |export let b = 2; - |export let c = 3; - |export let d = 4; - |export let e = 5; - """.trimMargin(), - stage = Stage.GenerateCode, - want = """ - |{ - | generateCode: { - | body: ``` - | @stay @imported(\(`test//nums/`.a)) @reach(\none) let a__0; - | a__0 = 1; - | @imported(\(`test//nums/`.b)) @reach(\none) let b__0; - | b__0 = 2; - | @imported(\(`test//nums/`.c)) @reach(\none) let c__0; - | c__0 = 3; - | @imported(\(`test//nums/`.d)) @reach(\none) let d__0; - | d__0 = 4; - | @imported(\(`test//nums/`.e)) @reach(\none) let e__0; - | e__0 = 5; - | do_call_log(getConsole(), do_call_toString(15)) - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/multi-import"), ) @Test fun nullInTestingAssert() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = """ - |let { C } = import("./c"); - | - |test("to be or not to be null") { - | let c0 = { optionalString: "" }; - | assert(c0.optionalString == ""); - |} - | - |$TEST_INPUT_MODULE_BREAK ./c/c.temper - |export class C(public optionalString: String?) {} - """.trimMargin(), - want = """ - |{ - | generateCode: { - | body: - | ``` - | @stay @imported(\(`test//c/`.C)) @reach(\test) let C__0; - | C__0 = type (C); - | @stay @imported(\(`std//testing/`.Test)) @reach(\test) let Test__0; - | Test__0 = type (Test); - | @fn @test("to be or not to be null") let toBeOrNotToBeNull__0; - | toBeOrNotToBeNull__0 = (@stay fn toBeOrNotToBeNull(test#0: Test) /* return__0 */: (Void | Bubble) { - | var t#0; - | let c0__0; - | c0__0 = new C(""); - | let actual#0; - | actual#0 = do_get_optionalString(c0__0); - |## Here's the assertion predicate - | t#0 = actual#0 == ""; - |## Here's a block that computes the failure message if the predicate is false. - | let fn__0; - | fn__0 = (@stay fn /* return__1 */{ - | var t#1; - |## Here we're picking a string representation of the actual expression result - | if (isNull(actual#0)) { - | t#1 = "null" - | } else { - | t#1 = do_call_toString(notNull(actual#0)) - | }; - | return__1 = cat("expected c0.optionalString == (", "", ") not (", t#1, ")") - | }); - | do_call_assert(test#0, t#0, fn__0); - | return__0 = void - | }) - | - | ``` - | } - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), + stageTestDir = StageTestDir("generate-code/null-in-testing-assert"), ) @Test fun longNullChain() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = """ - |let {a} = import("./a"); - |a?.string?.isEmpty?.toString() ?? "NULL" - | - |////!module: ./a/a.temper - |export class A(public string: String) {} - | - |export let a: A? = new A("a"); - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/long-null-chain"), moduleResultNeeded = true, - want = """ - |{ - | syntaxMacro: { - | body: ``` - | @stay @imported(\(`test//a/`.a)) let a__0 = `test//a/`.a; - | { - | let subject#0; - | subject#0 = { - | let subject#1; - | subject#1 = { - | if (isNull(a__0)) { - | null - | } else { - | do_get_string(notNull(a__0)) - | } - | }; - | if (isNull(subject#1)) { - | null - | } else { - | do_get_isEmpty(notNull(subject#1)) - | } - | }; - | if (isNull(subject#0)) { - | null - | } else { - | do_call_toString(notNull(subject#0)) - | } - | } - | ?? "NULL" - | - | ``` - | }, - | generateCode: { - | body: ``` - | let return__0; - | var t#0, t#1, t#2; - | @stay @imported(\(`test//a/`.a)) let a__0; - | a__0 = `test//a/`.a; - | if (isNull(a__0)) { - | t#0 = null - | } else { - | t#0 = do_get_string(notNull(a__0)) - | }; - | if (isNull(t#0)) { - | t#1 = null - | } else { - | t#1 = do_get_isEmpty(notNull(t#0)) - | }; - | if (isNull(t#1)) { - | t#2 = null - | } else { - | t#2 = do_call_toString(notNull(t#1)) - | }; - | if (isNull(t#2)) { - | return__0 = "NULL" - | } else { - | return__0 = notNull(t#2) - | } - | - | ``` - | } - |} - """.trimMargin(), ) @Test fun nonNullInference() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = """ - |let maybeLength(a: String?): Int? { - | // Because of non-null inference, `a.end` is ok here. - | a?.countBetween(String.begin, a.end) - |} - """.trimMargin(), - want = """ - |{ - | generateCode: { - | body: ``` - | @fn @reach(\none) let maybeLength__0; - | maybeLength__0 = (@stay fn maybeLength(a__0 /* aka a */: String?) /* return__0 */: (Int32?) { - | var t#0; - | if (isNull(a__0)) { - | return__0 = null - | } else { - |## In this branch, a is aliased to a#0 and is known to be not null. - | t#0 = notNull(a__0); - | return__0 = do_call_countBetween(t#0, getStatic(String, \begin), do_get_end(t#0)) - | } - | }) - | - | ``` - | } - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), + stageTestDir = StageTestDir("generate-code/non-null-inference"), ) @Test fun complexAssignmentOfVarProperty() = assertModuleAtStage( - stage = Stage.Run, + stageTestDir = StageTestDir("generate-code/complex-assignment-of-var-property"), - input = $$""" - |let { IntBox } = import("./int-box/"); - | - |let ib = { i: -1 }; - |console.log("ib.i = ${ib.i}"); - |ib.i += 11; - |console.log("ib.i = ${ib.i}"); - |ib.i *= 9; - |console.log("ib.i = ${ib.i}"); - |ib.i -= 6; - |console.log("ib.i = ${ib.i}"); - |ib.i /= 2; - |console.log("ib.i = ${ib.i}"); - | - |$$TEST_INPUT_MODULE_BREAK ./int-box/int-box.temper - |export class IntBox(public var i: Int) {} - """.trimMargin(), - - want = """ - |{ - | stdout: ``` - | ib.i = -1 - | ib.i = 10 - | ib.i = 90 - | ib.i = 84 - | ib.i = 42 - | - | ```, - | - | generateCode: { - | body: ``` - | var t#0; - | @stay @imported(\(`test//int-box/`.IntBox)) let IntBox__0; - | IntBox__0 = type (IntBox); - | t#0 = getConsole(); - | let ib__0; - | ib__0 = new IntBox(-1); - | do_call_log(t#0, cat("ib.i = ", do_call_toString(do_get_i(ib__0)))); - | let t#1; - | t#1 = ib__0; - |## set-i of get-i pattern - |## TODO: this might be a good test case for improving temporary elimination. - | do_set_i(t#1, do_get_i(t#1) + 11); - | do_call_log(t#0, cat("ib.i = ", do_call_toString(do_get_i(ib__0)))); - | let t#2; - | t#2 = ib__0; - | do_set_i(t#2, do_get_i(t#2) * 9); - | do_call_log(t#0, cat("ib.i = ", do_call_toString(do_get_i(ib__0)))); - | let t#3; - | t#3 = ib__0; - | do_set_i(t#3, do_get_i(t#3) - 6); - | do_call_log(t#0, cat("ib.i = ", do_call_toString(do_get_i(ib__0)))); - | let t#4; - | t#4 = ib__0; - | do_set_i(t#4, do_get_i(t#4) / 2); - | do_call_log(t#0, cat("ib.i = ", do_call_toString(do_get_i(ib__0)))) - | - | ``` - | }, - | - | run: "void: Void", - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), ) @Test fun complexAssignmentOfGetExpr() = assertModuleAtStage( - stage = Stage.Run, - - input = $$""" - |let ls = new ListBuilder(); - |ls.add(0); - |ls.add(3); - |ls[0] += 10; - |ls[1] *= 2; - | - |console.log("ls = [${ls.toList().join(", ") { (i: Int): String => i.toString(10) }}]"); - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/complex-assignment-of-get-expr"), - want = """ - |{ - | stdout: ``` - | ls = [10, 6] - | - | ```, - | run: "void: Void", - | - | syntaxMacro: { - | body: ``` - | let console#0 = doPure(fn: Console { - | getConsole() - | }), ls__0 = new ListBuilder(); - | do_call_add(ls__0, 0); - | do_call_add(ls__0, 3); - | do { - | let t#0; - | t#0 = ls__0; - |## Here's a call to .set of a call to .get - | do_call_set(t#0, 0, do_call_get(t#0, 0) + 10) - | }; - | do { - | let t#1; - | t#1 = ls__0; - | do_call_set(t#1, 1, do_call_get(t#1, 1) * 2) - | }; - | do_call_log(console#0, cat("ls = [", str(do_call_join(do_call_toList(ls__0), ", ", fn (i__0 /* aka i */: Int) /* return__1 */: (String) { - | do_call_toString(i__0, 10) - | })), "]")); - | - | ``` - | }, - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), ) @Test fun whenElseBubble() = assertModuleAtStage( - stage = Stage.GenerateCode, + stageTestDir = StageTestDir("generate-code/when-else-bubble"), pseudoCodeDetail = PseudoCodeDetail(showInferredTypes = true), - input = """ - |export let something(x: String?): String throws Bubble { - | /** Silly */ - | when (x) { - | is String -> x; - | else -> bubble(); - | } - |} - """.trimMargin(), - want = """ - |{ - | generateCode: { - | body: ``` - | @fn let `test//`.something ⦂(fn (String?): String | Bubble); - | `test//`.something = (@stay fn something(x__0 /* aka x */: String?) /* return__0 */: (String | Bubble) { - | var t#0 ⦂ Boolean; - | if (!isNull ⋖ String ⋗(x__0)) { - | t#0 = x__0 is String - | } else { - | t#0 = false - | }; - | if (t#0) { - | if (isNull ⋖ String ⋗(x__0)) { - | return__0 = panic ⋖ String ⋗() - | } else { - | return__0 = assertAs ⋖ String ⋗(x__0, String) - | } - | } else { - | bubble ⋖ String ⋗() - | } - | }) - | - | ```, - | exports: { - | something: { - | stateVector: "fn something", - | typeTag: "Function", - | abbrev: "fn something: Function" - | } - | } - | } - |} - """.trimMargin(), ) @Test fun veryBigMapConstructor() = assertModuleAtStage( - stage = Stage.Run, - input = buildString { - append("export let numbers: Map = new Map([") - for (i in 0 until 1000) { - append(" new Pair(\"$i\", $i),") - } - append("]);") - }, - want = """ - |{ - | run: "void: Void", - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/very-big-map-constructor"), ) @Test fun doPureRuns() = assertModuleAtStage( - stage = Stage.Run, - input = """ - |let { C } = import("./c"); - | - |let c = doPure { (): C => new C() }; - | - |c - | - |$TEST_INPUT_MODULE_BREAK ./c/c.temper - |export class C {} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/do-pure-runs"), moduleResultNeeded = true, - want = """ - |{ - | generateCode: { - | body: ``` - | let return__0, @stay @imported(\(`test//c/`.C)) C__0; - | C__0 = type (C); - | let c__0; - | c__0 = new C(); - | return__0 = c__0 - | - | ``` - | }, - | run: "{}: `test-code/c/`.C", - |} - """.trimMargin(), ) @Test fun pureVirtualMethodInConcreteClass() = assertModuleAtStage( - stage = Stage.Run, - input = """ - |export interface I { f(x: T): Void; } - |export class C extends I { - | // but does not override f() - |} - """.trimMargin(), - want = """ - |{ - | run: "void: Void", - | errors: ["Type C must implement f from I. Maybe add `public f(x: String): Void`!"] - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/pure-virtual-method-in-concrete-class"), ) @Test fun nullAssignedToNonNullVarDevl() = assertModuleAtStage( - stage = Stage.GenerateCode, + stageTestDir = StageTestDir("generate-code/null-assigned-to-non-null-var-devl"), moduleResultNeeded = true, - input = $$""" - |let f(i: Int32): String { - | var sbOrNull: StringBuilder = null; - | // ^ No `?` - | if (i % 2 == 0) { - | let sbNow = sbOrNull; - | let sb = sbNow ?? new StringBuilder(); - | sb.append("${i}"); - | sbOrNull = sb; - | } - | let finalSb = sbOrNull; - | if (finalSb == null) { - | "" - | } else { - | finalSb.toString() - | } - |} - |f(4) - """.trimMargin(), - want = """ - |{ - | errors: [ - | "Expected subtype of StringBuilder, but got StringBuilder?!", - | ], - | generateCode: { - | body: ``` - | let return__0, @fn f__0; - | f__0 = (@stay fn f(i__0 /* aka i */: Int32) /* return__1 */: String { - | var sbOrNull__0: StringBuilder; - | sbOrNull__0 = null; - | if (i__0 % 2 == 0) { - | let sbNow__0; - | sbNow__0 = sbOrNull__0; - | let sb__0; - | sb__0 = sbNow__0; - | do_call_append(sb__0, cat(do_call_toString(i__0))); - | sbOrNull__0 = sb__0 - | }; - | let finalSb__0; - | finalSb__0 = sbOrNull__0; - | return__1 = do_call_toString(finalSb__0) - | }); - | return__0 = (fn f)(4) - | - | ``` - | }, - |} - """.trimMargin(), ) @Test fun stringCoercionOfRttiCheck() = assertModuleAtStage( - stage = Stage.Run, - input = $$""" - |let f(i: StringIndexOption): Void { - | console.log("Yes ${i is StringIndex}, no ${i is NoStringIndex }"); - |} - | - |f(String.begin) - """.trimMargin(), - want = """ - |{ - | generateCode: { - | body: ``` - | let console#0; - | console#0 = getConsole(); - | @fn let f__0; - | f__0 = (@stay fn f(i__0 /* aka i */: StringIndexOption) /* return__0 */: Void { - | var t#0, t#1; - |## str has erased to a .toString() call here - | t#0 = do_call_toString(i__0 is StringIndex); - | t#1 = do_call_toString(i__0 is NoStringIndex); - | do_call_log(console#0, cat("Yes ", t#0, ", no ", t#1)); - | return__0 = void - | }); - | f__0(getStatic(String, \begin)) - | - | ``` - | }, - | run: "void: Void", - | stdout: "Yes true, no false\n", - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), + stageTestDir = StageTestDir("generate-code/string-coercion-of-rtti-check"), ) @Test fun isAppliedToParameterizedType() = assertModuleAtStage( - stage = Stage.Run, + stageTestDir = StageTestDir("generate-code/is-applied-to-parameterized-type"), moduleResultNeeded = true, - input = """ - |sealed interface I {} - |class A extends I {} - |class B extends I {} - | - |let f(x: I): Boolean { - | x is A - |} - | - |[f(new A()), f(new B())] - """.trimMargin(), - want = """ - |{ - | "run": "[true, false]: List" - |} - """.trimMargin(), ) @Test fun staticWithUnusedExtension() = assertModuleAtStage( - stage = Stage.Run, - input = """ - |@staticExtension(String, "foo") - |let strFoo(): Void { - | console.log("string foo"); - |} - | - |class C { - | public static foo(): Void { - | console.log("C foo"); - | } - |} - | - |C.foo(); - """.trimMargin(), - want = """ - |{ - | run: "void: Void", - | - | stdout: ``` - | C foo - | - | ```, - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/static-with-unused-extension"), ) @Test fun declaringADataFile() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = """ - |dataFile("hello.txt", "text/plain", ${temperEscaper.escape( - buildString { - // This string is long to demonstrate that the data doesn't - // show up in its entirety in the debug form. - append("He") - repeat(1000) { append("ll") } - append("o, World!") - }, - )}); - """.trimMargin(), - want = """ - |{ - | generateCode: { - | body: ``` - | @topLevelMetadata @stay @declareDataFile((["hello.txt", "text/plain", "Hellllllllllllllllll⋯llllllllllllo, World!"])) @reach(\none) let moduleMetadata#0: Empty; - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/declaring-a-data-file"), ) @Test fun missingFunctionBody() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = """ - |let hi(): Void; - """.trimMargin(), - want = """ - |{ - | generateCode: { - | body: - | ``` - | @fn @reach(\none) let hi__0; - | hi__0 = (@stay fn hi /* return__0 */: Void { - | abstractPanic(); - | return__0 = void - | }) - | - | ``` - | }, - | errors: [ - | "Function body required except for virtual methods or connected functions!" - | ], - |} - """.trimMargin(), + stageTestDir = StageTestDir("generate-code/missing-function-body"), ) } diff --git a/frontend/src/commonTest/kotlin/lang/temper/frontend/SyntaxMacroStageTest.kt b/frontend/src/commonTest/kotlin/lang/temper/frontend/SyntaxMacroStageTest.kt index 0ebb4447..caa18a88 100644 --- a/frontend/src/commonTest/kotlin/lang/temper/frontend/SyntaxMacroStageTest.kt +++ b/frontend/src/commonTest/kotlin/lang/temper/frontend/SyntaxMacroStageTest.kt @@ -8,14 +8,10 @@ import lang.temper.common.NoneShortOrLong import lang.temper.common.json.JsonArray import lang.temper.common.json.JsonObject import lang.temper.common.json.JsonString -import lang.temper.common.stripDoubleHashCommentLinesToPutCommentsInlineBelow -import lang.temper.common.testCodeLocation import lang.temper.env.InterpMode import lang.temper.interp.MetadataDecorator import lang.temper.interp.importExport.STANDARD_LIBRARY_NAME import lang.temper.lexer.Genre -import lang.temper.lexer.MarkdownLanguageConfig -import lang.temper.lexer.StandaloneLanguageConfig import lang.temper.log.Position import lang.temper.log.filePath import lang.temper.name.BuiltinName @@ -40,235 +36,19 @@ import kotlin.test.assertTrue class SyntaxMacroStageTest { @Test fun blockScoping() = assertModuleAtStage( - stage = Stage.Run, - input = """ - let a = 1; - (do { - let a = 2; - // Why do I feel compelled to write `let ... in` here? - // I wish I knew how to quit you, OCaml! - a - }) + a - """.trimIndent(), + stageTestDir = StageTestDir("syntax-macro/block-scoping"), moduleResultNeeded = true, - want = """ - { - run: "3: Int32", - syntaxMacro: { - body: { - code: - ``` - let a__0 = 1; - do (fn { - let a__1 = 2; - REM("Why do I feel compelled to write `let ... in` here?\nI wish I knew how to quit you, OCaml!", null, false); - a__1 - }) + a__0 - - ```, - tree: - [ "Block", [ - [ "Decl", [ - [ "LeftName", "a__0" ], - [ "Value", [ "init", "Symbol" ] ], - [ "Value", [ 1, "Int32" ] ], - [ "Value", "\\QName: Symbol" ], - [ "Value", "\"test-code.a\": String" ], - ] - ], - [ "Call", [ - [ "Value", "nym`do_call__+_`[PlusIntInt, PlusIntInt64, PlusFltFlt]: Function" ], - [ "Call", [ - [ "RightName", "do" ], - [ "Fun", [ - [ "Block", [ - [ "Decl", [ - [ "LeftName", "a__1" ], - [ "Value", [ "init", "Symbol" ] ], - [ "Value", [ 2, "Int32" ] ], - [ "Value", "\\QName: Symbol" ], - [ "Value", "\"test-code.a=\": String" ], - ] - ], - [ "Call", [ - [ "Value", "REM: Function" ], - [ "Value", ``` - "Why do I feel compelled to write `let ... in` here?\nI wish I knew how to quit you, OCaml!": String - ``` ], - [ "Value", "null: Null" ], - [ "Value", "false: Boolean" ], - ] - ], - [ "RightName", "a__1" ] - ] - ] - ] - ] - ] - ], - [ "RightName", "a__0" ] - ] - ] - ] - ] - } - } - } - """, ) - /* - In Java and Rust, - { - int i = 0; - { - int i = i; - } - } - is legal since, the `i` used in the initializer binds in a scope that excludes the name being - initialized. So Java treats every initialization - T n = e; - // following statements in the same block - the same as - T temporary = e; - { - T n = temporary; - // following statements in the same block - } - - JavaScript has a temporal dead zone though so - { - let i = 0; - { - let i = i; - } - } - is illegal since the `i` in the initializer binds to the uninitialized inner `let`. - - The Rust and Kotlin communities' experiences with shadowing starting lexically after - initialization show that this feature is widely appreciated. - */ @Test fun useInLetInitializer() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = """ - let i = 0; - do { - let i = i; - f(i); - } - """.trimIndent(), + stageTestDir = StageTestDir("syntax-macro/use-in-let-initializer"), moduleResultNeeded = true, - want = """ - { - syntaxMacro: { - body: [ "Block", [ - [ "Decl", [ - [ "LeftName", "i__0" ], - [ "Value", "\\init: Symbol" ], - [ "Value", "0: Int32" ], - [ "Value", "\\QName: Symbol" ], - [ "Value", "\"test-code.i\": String" ], - ] - ], - [ "Call", [ - [ "RightName", "do" ], - [ "Fun", [ [ "Block", [ - [ "Decl", [ - [ "LeftName", "i__1" ], - [ "Value", "\\init: Symbol" ], - [ "RightName", "i__0" ], - [ "Value", "\\QName: Symbol" ], - [ "Value", "\"test-code.i=\": String" ], - ] - ], - [ "Call", [ - [ "RightName", "f" ], - [ "RightName", "i__1" ], - ] - ], - [ "Value", "void: Void" ], - ] ] ] ] - ] - ] - ] - ] - } - } - """, ) @Test fun backReferenceInFormalInitializer() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = "let f(i = j, j = 42, k = f) {}", - want = """ - { - syntaxMacro: { - body: [ "Block", [ - [ "Decl", [ - [ "LeftName", "f__0" ], - [ "Value", "\\fn: Symbol" ], - [ "Value", "void: Void" ], - [ "Value", "\\QName: Symbol" ], - [ "Value", "\"test-code.f()\": String" ], - ] - ], - [ "Call", [ - [ "Value", "nym`=`: Function" ], - [ "LeftName", "f__0" ], - [ "Fun", [ - [ "Decl", [ - [ "LeftName", "i__1" ], - [ "Value", "\\default: Symbol" ], - [ "RightName", "j__2" ], - [ "Value", "\\word: Symbol" ], - [ "Value", "\\i: Symbol" ], - [ "Value", "\\QName: Symbol" ], - [ "Value", "\"test-code.f().(i)\": String" ], - ] - ], - [ "Decl", [ - [ "LeftName", "j__2" ], - [ "Value", "\\default: Symbol" ], - [ "Value", "42: Int32" ], - [ "Value", "\\word: Symbol" ], - [ "Value", "\\j: Symbol" ], - [ "Value", "\\QName: Symbol" ], - [ "Value", "\"test-code.f().(j)\": String" ], - ] - ], - [ "Decl", [ - [ "LeftName", "k__3" ], - [ "Value", "\\default: Symbol" ], - [ "RightName", "f__0" ], - [ "Value", "\\word: Symbol" ], - [ "Value", "\\k: Symbol" ], - [ "Value", "\\QName: Symbol" ], - [ "Value", "\"test-code.f().(k)\": String" ], - ] - ], - [ "Value", "\\returnedFrom: Symbol" ], - [ "Value", "true: Boolean" ], - [ "Value", "\\word: Symbol" ], - [ "Value", "\\f: Symbol" ], - [ "Value", "\\QName: Symbol" ], - [ "Value", "\"test-code.f()\": String" ], - [ "Block", [ - [ "Value", "\\label: Symbol" ], - [ "LeftName", "fn__4" ] - ] - ] - ] - ] - ] - ], - [ "Value", "void: Void" ] - ] - ] - } - } - """, + stageTestDir = StageTestDir("syntax-macro/back-reference-in-formal-initializer"), ) /** @@ -284,956 +64,148 @@ class SyntaxMacroStageTest { */ @Test fun letOfFn() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = """ - let f = fn (x) {}; - let g = fn g(y) {}; - var h = fn (z) {}; // *var* fn should get neither symbol nor qname - """.trimIndent(), - want = """ - { - syntaxMacro: { - body: - [ "Block", [ - [ "Decl", [ - [ "LeftName", "f__0" ], - [ "Value", "\\init: Symbol" ], - [ "Fun", [ - [ "Decl", [ - [ "LeftName", "x__1" ], - [ "Value", "\\word: Symbol" ], - [ "Value", "\\x: Symbol" ], - [ "Value", "\\QName: Symbol" ], - [ "Value", "\"test-code.f().(x)\": String" ], - ] - ], - [ "Value", "\\returnedFrom: Symbol" ], - [ "Value", "true: Boolean" ], - [ "Value", "\\word: Symbol" ], - [ "Value", "\\f: Symbol" ], - [ "Value", "\\QName: Symbol" ], - [ "Value", "\"test-code.f()\": String" ], - [ "Block", [ - [ "Value", "\\label: Symbol" ], - [ "LeftName", "fn__2" ] - ] - ] - ] - ], - [ "Value", "\\fn: Symbol" ], - [ "Value", "void: Void" ], - [ "Value", "\\QName: Symbol" ], - [ "Value", "\"test-code.f()\": String" ], - ] - ], - - [ "Decl", [ - [ "LeftName", "g__3" ], - [ "Value", "\\init: Symbol" ], - [ "Fun", [ - [ "Decl", [ - [ "LeftName", "y__4" ], - [ "Value", "\\word: Symbol" ], - [ "Value", "\\y: Symbol" ], - [ "Value", "\\QName: Symbol" ], - [ "Value", "\"test-code.g().(y)\": String" ], - ] - ], - [ "Value", "\\returnedFrom: Symbol" ], - [ "Value", "true: Boolean" ], - [ "Value", "\\word: Symbol" ], - [ "Value", "\\g: Symbol" ], - [ "Value", "\\QName: Symbol" ], - [ "Value", "\"test-code.g()\": String" ], - [ "Block", [ - [ "Value", "\\label: Symbol" ], - [ "LeftName", "fn__5" ] - ] - ] - ] - ], - [ "Value", "\\fn: Symbol" ], - [ "Value", "void: Void" ], - [ "Value", "\\QName: Symbol" ], - [ "Value", "\"test-code.g()\": String" ], - ] - ], - - [ "Decl", [ - [ "LeftName", "h__0" ], - [ "Value", "\\init: Symbol" ], - [ "Fun", [ - [ "Decl", [ - [ "LeftName", "z__0" ], - [ "Value", "\\word: Symbol" ], - [ "Value", "\\z: Symbol" ], - [ "Value", "\\QName: Symbol" ], - [ "Value", "\"test-code.h().(z)\": String" ], - ] - ], - [ "Value", "\\returnedFrom: Symbol" ], - [ "Value", "true: Boolean" ], - [ "Block", [ - [ "Value", "\\label: Symbol" ], - [ "LeftName", "fn__0" ] - ] - ] - ] - ], - [ "Value", "\\var: Symbol" ], - [ "Value", "void: Void" ], - [ "Value", "\\QName: Symbol" ], - [ "Value", "\"test-code.h()\": String" ], - ] - ], - - [ "Value", "void: Void" ], - ] - ] - } - } - """, + stageTestDir = StageTestDir("syntax-macro/let-of-fn"), ) @Test fun multiDeclarations() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = "let [a, b is S, c = x]: T = f()", + stageTestDir = StageTestDir("syntax-macro/multi-declarations"), moduleResultNeeded = true, - want = """ - { - syntaxMacro: { - body: - [ "Block", [ - [ "Block", [ - [ "Decl", [ - [ "LeftName", "t#0" ], - [ "Value", "\\init: Symbol" ], - [ "RightName", "S" ] - ] - ], - [ "Decl", [ - [ "LeftName", "t#1" ], - [ "Value", "\\init: Symbol" ], - [ "RightName", "x" ] - ] - ], - [ "Decl", [ - [ "LeftName", "t#2" ], - [ "Value", "\\init: Symbol" ], - [ "RightName", "T" ] - ] - ], - [ "Decl", [ - [ "LeftName", "a__3" ], - [ "Value", "\\type: Symbol" ], - [ "RightName", "t#2" ] - ] - ], - [ "Decl", [ - [ "LeftName", "b__4" ], - [ "Value", "\\type: Symbol" ], - [ "Call", [ - [ "RightName", "&" ], - [ "RightName", "t#0" ], - [ "RightName", "t#2" ] - ] - ] - ] - ], - [ "Decl", [ - [ "LeftName", "c__5" ], - [ "Value", "\\type: Symbol" ], - [ "RightName", "t#2" ] , - [ "Value", "\\init: Symbol" ], - [ "RightName", "t#1" ], - ] - ], - [ "Call", [ - [ "Value", "nym`=`: Function" ], - [ "Call", [ - [ "Value", "nym`,`: Function" ], - [ "LeftName", "a__3" ], - [ "LeftName", "b__4" ], - [ "LeftName", "c__5" ], - ] - ], - [ "Call", [ - [ "RightName", "f" ], - ] - ], - ] - ], - ] - ] - ] - ] - } - } - """, ) @Test fun assignmentsInMultiDeclsResolveProperly() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = "let [x, y] = f(); x + y", + stageTestDir = StageTestDir("syntax-macro/assignments-in-multi-decls-resolve-properly"), moduleResultNeeded = true, - want = """ - { - syntaxMacro: { - body: [ "Block", [ - [ "Block", [ - [ "Decl", [ [ "LeftName", "x__0" ] ] ], - [ "Decl", [ [ "LeftName", "y__1" ] ] ], - [ "Call", [ - [ "Value", "nym`=`: Function" ], - [ "Call", [ - [ "Value", "nym`,`: Function" ], - [ "LeftName", "x__0" ], - [ "LeftName", "y__1" ] - ] - ], - [ "Call", [ - [ "RightName", "f" ] - ] - ] - ] - ] - ] - ], - [ "Call", [ - [ "Value", "nym`do_call__+_`[PlusIntInt, PlusIntInt64, PlusFltFlt]: Function" ], - [ "RightName", "x__0" ], - [ "RightName", "y__1" ] - ] - ] - ] - ] - } - } - """, ) @Test fun quotedNames() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = """ - let nym`x`, y; - f(x, y, nym`x`, nym`y`) - """.trimIndent(), + stageTestDir = StageTestDir("syntax-macro/quoted-names"), moduleResultNeeded = true, - want = """ - { - syntaxMacro: { - body: - ``` - let x__0, y__1; - f(x__0, y__1, x__0, y__1) - - ``` - } - } - """, ) @Test fun thisThisIsOkButThatThisIsNot() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = """ - |class C { private me = this } - |let me = this; - """.trimMargin(), + stageTestDir = StageTestDir("syntax-macro/this-this-is-ok-but-that-this-is-not"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - |{ - | errors: [ - | "`this` may only appear inside a type definition!" - | ], - | disAmbiguate: { - | body: - | ``` - | @typeDecl(C__0) @hoistLeft(true) @resolution(C__0) @stay let C = type (C__0); - | class(\word, C, \concrete, true, @typeDefined(C__0) fn { - | C__0 extends AnyValue; - | @property(\me) @maybeVar @visibility(\private) let me = this(C__0); - | }); - | let me = this(); - | - | ```, - | types: { - | C: { word: "C" }, - | AnyValue: { abstract: true }, - | } - | }, - | syntaxMacro: { - | body: - | ``` - | @typeDecl(C__0) @stay let C__0 = type (C__0); - | class(\word, \C, \concrete, true, @typeDefined(C__0) fn { - | C__0 extends AnyValue; - | @property(\me) @maybeVar @visibility(\private) let me__3; - | @method(\constructor) @visibility(\public) let constructor__4 = fn constructor(@impliedThis(C__0) this__5: C__0) /* return__0 */: Void { - | do { - | let t#0; - | do_iset_me(type (C__0), this(C__0), t#0 = this(C__0)); - | t#0 - | }; - | }; - | }); - | let me__7 = error (); - | - | ```, - | types: { - | AnyValue: { abstract: true }, - | C: { - | word: "C", - | properties: [ - | { name: "me", symbol: "me", abstract: false, visibility: "private" }, - | ], - | methods: [ - | { name: "constructor", kind: "Constructor", visibility: "public", open: false }, - | ], - | supers: [ "AnyValue__0" ], - | }, - | Void: { supers: [] }, - | }, - | } - |} - """.trimMargin(), ) @Test fun makingThisUnambiguous() = assertModuleAtStage( + stageTestDir = StageTestDir("syntax-macro/making-this-unambiguous"), // TODO: IdRenumberer is not used to rewrite inlined values. // That affects the rendering of reified types. - stage = Stage.SyntaxMacro, pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - input = """ - |interface I { - | x; - |} - | - |let x, y, z; - | - |class C(public y) extends I { - | private f() { - | x + y + z // x is inherited, y is locally defined, z is closed over. - | } - |} - """.trimMargin(), - want = """ - |{ - | syntaxMacro: { - | body: - | ``` - | @typeDecl(I__0) @stay let I__0 = type (I__0); - | @typeDecl(C__0) @stay let C__0 = type (C__0); - | interface(\word, \I, \concrete, false, @typeDefined(I__0) fn { - | I__0 extends AnyValue; - | @property(\x) @maybeVar let x__6; - | }); - | let x__7, y__8, z__9; - | class(\word, \C, \concrete, true, @typeDefined(C__0) fn { - | @typeFormal(\T) @memberTypeFormal(\T) @typeDefined(T__2) let T__2 = type (T__2); - | C__0 extends I__0; - | @constructorProperty @property(\y) @maybeVar @visibility(\public) let y__14; - | @method(\f) @visibility(\private) @fn let f__12 = fn f(@impliedThis(C__0) this__2: C__0) { - | fn__13: do { - | do_iget_x(type (C__0), this(C__0)) + do_iget_y(type (C__0), this(C__0)) + z__9 - | } - | }; - | @method(\constructor) @visibility(\public) let constructor__15 = fn constructor(@impliedThis(C__0) this__16: C__0, y__17 /* aka y */) /* return__0 */: Void { - | do { - | let t#0; - | do_iset_y(type (C__0), this(C__0), t#0 = y__17); - | t#0 - | }; - | }; - | }); - | C__0 - | - | ```, - | types: { - | AnyValue: { abstract: true }, - | C: { - | word: "C", - | typeParameters: [ - | { name: "T__2" }, - | ], - | supers: ["I__0"], - | properties: [ - | { name: "y", symbol: "y", abstract: false, visibility: "public" }, - | ], - | methods: [ - | { name: "f", symbol: "f", open: false, visibility: "private" }, - | { name: "constructor", open: false, visibility: "public", - | kind: "Constructor" }, - | ], - | }, - | I: { - | word: "I", - | abstract: true, - | properties: [ - | { name: "x", symbol: "x", abstract: true, visibility: "public" }, // Not resolved until Syntax stage - | ], - | supers: [ "AnyValue__0" ] - | }, - | T: { word: "T" }, - | Void: { supers: [] }, - | } - | } - |} - """.trimMargin(), ) @Test fun dotsToSymbols() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = """ - |let foo = f(), bar; - |foo.bar + bar; - """.trimMargin(), + stageTestDir = StageTestDir("syntax-macro/dots-to-symbols"), moduleResultNeeded = true, - want = """ - |{ - | syntaxMacro: { - | body: { - | code: - | ``` - | let foo__0 = f(), bar__1; - | do_get_bar(foo__0) + bar__1; - | - | ```, - | tree: [ "Block", [ - | [ "Decl", [ - | [ "LeftName", "foo__0" ], - | [ "Value", "\\init: Symbol" ], - | [ "Call", [ - | [ "RightName", "f" ] - | ] - | ], - | [ "Value", "\\QName: Symbol" ], - | [ "Value", "\"test-code.foo\": String" ], - | ] - | ], - | [ "Decl", [ - | [ "LeftName", "bar__1" ], - | [ "Value", "\\QName: Symbol" ], - | [ "Value", "\"test-code.bar\": String" ], - | ] - | ], - | [ "Call", [ - | [ "Value", "nym`do_call__+_`[PlusIntInt, PlusIntInt64, PlusFltFlt]: Function" ], - | [ "Call", [ - | [ "Value", "do_get_bar: Function" ], - | [ "RightName", "foo__0" ], - | ] - | ], - | [ "RightName", "bar__1" ] - | ] - | ], - | [ "Value", "void: Void" ], - | ] - | ] - | } - | } - |} - """.trimMargin(), ) @Test fun getterAndSetterInheritVisibilityFromProperty() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = """ - |class(private _x) { - | public x; - | get x() { _x } - | set x(newValue) { _x = newValue } - |} - """.trimMargin(), + stageTestDir = StageTestDir("syntax-macro/getter-and-setter-inherit-visibility-from-property"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - |{ - | syntaxMacro: { - | body: - | ``` - | @typeDecl(Anon__0) @stay let t#0 = type (Anon__0); - | class(\concrete, true, @typeDefined(Anon__0) fn { - | Anon__0 extends AnyValue; - | @constructorProperty @property(\_x) @maybeVar @visibility(\private) let _x__5; - | @property(\x) @visibility(\public) var x__6; - | @method(\x) @getter @fn let nym`get.x__7` = fn nym`get.x`(@impliedThis(Anon__0) this__2: Anon__0) { - | fn__8: do { - | do_iget__x(type (Anon__0), this(Anon__0)) - | } - | }; - | @method(\x) @setter @fn let nym`set.x__9` = fn nym`set.x`(@impliedThis(Anon__0) this__3: Anon__0, newValue__10 /* aka newValue */) /* return__0 */: Void { - | fn__11: do { - | do { - | let t#1; - | do_iset__x(type (Anon__0), this(Anon__0), t#1 = newValue__10); - | t#1 - | } - | } - | }; - | @method(\constructor) @visibility(\public) let constructor__12 = fn constructor(@impliedThis(Anon__0) this__13: Anon__0, _x__14 /* aka _x */) /* return__1 */: Void { - | do { - | let t#2; - | do_iset__x(type (Anon__0), this(Anon__0), t#2 = _x__14); - | t#2 - | }; - | }; - | }); - | type (Anon__0) - | - | ```, - | types: { - | Anon: { - | properties: [ - | { name: "_x", visibility: "private", abstract: false }, - | { - | name: "x", abstract: true, visibility: "public", - | getter: "get.x", setter: "set.x" - | }, - | ], - | methods: [ - | { name: "get.x", symbol: "x", visibility: "public", open: false, kind: "Getter" }, - | { name: "set.x", symbol: "x", visibility: "public", open: false, kind: "Setter" }, - | { name: "constructor", "visibility": "public", open: false, kind: "Constructor" }, - | ], - | supers: [ "AnyValue__0" ] - | }, - | AnyValue: { abstract: true }, - | Void: { supers: [] }, - | } - | } - |} - """.trimMargin(), ) @Test fun methodWithoutBody() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = """ - interface I { - method(); - } - """, + stageTestDir = StageTestDir("syntax-macro/method-without-body"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - { - syntaxMacro: { - body: - ``` - @typeDecl(I__0) @stay let I__0 = type (I__0); - interface(\word, \I, \concrete, false, @typeDefined(I__0) fn { - I__0 extends AnyValue; - @method(\method) @fn let method__4 = fn method(@impliedThis(I__0) this__1: I__0) { - fn__5: do { - pureVirtual() - } - }; - }); - I__0 - - ``` - } - } - """, ) @Test fun forLoopExtractsDeclarations() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = "for (var i = 0; i < 3; i += 1) { body; }", - want = """ - { - "syntaxMacro": { - "body": - ``` - do { - var i__0 = 0; - for(\__flowInit, {class: Empty__0}, \cond, i__0 < 3, \incr, i__0 = i__0 + 1, fn { - body; - }) - } - - ``` - } - } - """, + stageTestDir = StageTestDir("syntax-macro/for-loop-extracts-declarations"), ) @Test fun forOfLoopVarAvailableInBody() = assertModuleAtStage( + stageTestDir = StageTestDir("syntax-macro/for-of-loop-var-available-in-body"), // for...of loop's loop variable is visible only within the body. // It is scoped to the body, and to allow it to be visible within the // expression right of `of` would lead to confusion. - input = """ - |let x = f(); - |for (let x of x) { - | x - |} - |x - """.trimMargin(), stagingFlags = setOf(StagingFlags.skipImportCore), - stage = Stage.SyntaxMacro, - want = """ - |{ - | syntaxMacro: { - | body: - | ``` - | let x__0 = f(); - | do_call_forEach(x__0, fn (x__1) { - | x__1 - | }); - | x__0 - | - | ``` - | } - |} - """.trimMargin(), ) @Test fun forLoopExtractsMultipleDeclarations() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = "for (var i: Int = 0, x = 3; i < 3; i += 1) { body; }", - want = """ - { - "syntaxMacro": { - "body": - ``` - do { - var i__0: Int = 0, x__1 = 3; - for(\__flowInit, {class: Empty__0}, \cond, i__0 < 3, \incr, i__0 = i__0 + 1, fn { - body; - }) - } - - ``` - } - } - """, + stageTestDir = StageTestDir("syntax-macro/for-loop-extracts-multiple-declarations"), ) @Test fun forLoopKeepsLabel() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = "label: for (var i = 0; i < 3; i += 1) { body; }", - want = """ - { - "syntaxMacro": { - "body": - ``` - do { - var i__0 = 0; - label__0: do { - for(\__flowInit, {class: Empty__0}, \cond, i__0 < 3, \incr, i__0 = i__0 + 1, fn { - body; - }) - } - } - - ``` - } - } - """, + stageTestDir = StageTestDir("syntax-macro/for-loop-keeps-label"), ) @Test fun forLoopExtractsDeclarationsMinimal() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = "for(;;) { body; }", - want = """ - { - "syntaxMacro": { - "body": - ``` - for(fn { - body; - }) - - ``` - } - } - """, + stageTestDir = StageTestDir("syntax-macro/for-loop-extracts-declarations-minimal"), ) @Test fun forLoopExtractsDeclarationsJustInit() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = "for(let i = 0;;) { body; }", - want = """ - { - "syntaxMacro": { - "body": - ``` - do { - let i__0 = 0; - for(\__flowInit, {class: Empty__0}, fn { - body; - }) - } - - ``` - } - } - """, + stageTestDir = StageTestDir("syntax-macro/for-loop-extracts-declarations-just-init"), ) @Test fun forLoopLikeExtractsDeclarations() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = "foo (let i = 0; i < 3; i += 1) { body; }", - want = """ - { - "syntaxMacro": { - "body": - ``` - do { - let i__0 = 0; - foo(\__flowInit, {class: Empty__0}, \cond, i__0 < 3, \incr, i__0 = i__0 + 1, fn { - body; - }) - } - - ``` - } - } - """, + stageTestDir = StageTestDir("syntax-macro/for-loop-like-extracts-declarations"), ) @Test fun namesResolveToExportedNames() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = "export let x = 42; x", + stageTestDir = StageTestDir("syntax-macro/names-resolve-to-exported-names"), moduleResultNeeded = true, - want = """ - { - syntaxMacro: { - body: { - code: ``` - let `test//`.x = 42; - `test//`.x - - ```, - tree: - [ "Block", [ - [ "Decl", [ - [ "LeftName", { type: "ExportedName", baseName: "x" } ], - [ "Value", "\\init: Symbol" ], - [ "Value", "42: Int32" ], - [ "Value", "\\ssa: Symbol" ], - [ "Value", "void: Void" ], - [ "Value", "\\QName: Symbol" ], - [ "Value", "\"test-code.x\": String" ], - ] - ], - [ "RightName", { type: "ExportedName", baseName: "x" } ] - ] - ] - } - } - } - """, ) @Test fun genericFn() = assertModuleAtStage( - stage = Stage.Run, - input = """ - |let identity(x: T): T { x } - |identity(42) - """.trimMargin(), + stageTestDir = StageTestDir("syntax-macro/generic-fn"), moduleResultNeeded = true, - want = """ - |{ - | // By the end of the syntax stage, the function has been rewritten to include the - | // formal declarations, including super-type info. - | syntaxMacro: { - | body: - | ``` - | @fn let identity__0; - | @typeFormal(\T) @typeDecl(T__0) let T__0 = type (T__0); - | T__0 extends AnyValue; - | identity__0 = fn identity(x__0 /* aka x */: T__0) /* return__0 */: (T__0) { - | fn__0: do { - | x__0 - | } - | }; - | identity__0(42) - | - | ```, - | }, - | // By the end of the define stage, additional processing has happened. - | define: { - | body: - | ``` - | @fn let identity__0; - | @typeFormal(\T) @typeDecl(T__0) let T__0; - | T__0 = type (T__0); - | T__0 extends AnyValue; - | identity__0 = (@stay fn identity(x__0 /* aka x */: T__0) /* return__0 */: T__0 { - | fn__0: do { - | x__0 - | } - | }); - | 42 - | - | ```, - | }, - | run: "42: Int32" - |} - """.trimMargin(), ) @Test fun fnFormalArgsDoNotCrossScopes() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = """ - |let T = "T"; - |let f(x: T): T { x } - |let t = T; - """.trimMargin(), - want = """ - |{ - | syntaxMacro: { - | body: - | ``` - | @fn let f__0, T__0 = "T"; - | @typeFormal(\T) @typeDecl(T__1) let T__1 = type (T__1); - | T__1 extends AnyValue; - | f__0 = fn f(x__0 /* aka x */: T__1) /* return__0 */: (T__1) { - | fn__0: do { - | x__0 - | } - | }; - | let t__0 = T__0; - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("syntax-macro/fn-formal-args-do-not-cross-scopes"), ) @Test fun classFormalArgsDoNotCrossScopes() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = """ - |let T = "T"; - |interface I { t: T } - |let t = T; - """.trimMargin(), + stageTestDir = StageTestDir("syntax-macro/class-formal-args-do-not-cross-scopes"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - |{ - | syntaxMacro: { - | body: - | ``` - | @typeDecl(I__0) @stay let I__0 = type (I__0); - | let T__1 = "T"; - | interface(\word, \I, \concrete, false, @typeDefined(I__0) fn { - | @typeFormal(\T) @memberTypeFormal(\T) @typeDefined(T__0) let T__0 = type (T__0); - | I__0 extends AnyValue; - | @property(\t) @maybeVar let t__0: T__0; - | }); - | let t__1 = T__1; - | - | ``` - | } - |} - """.trimMargin(), ) @Test fun letFunctionBodyRequiredButCheckedLater() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = """let f()""", - want = """ - { - "syntaxMacro": { - "body": - ``` - @fn let f__0; - f__0 = fn f { - fn__0: do { - abstractPanic() - } - }; - - ```, - }, - } - """, + stageTestDir = StageTestDir("syntax-macro/let-function-body-required-but-checked-later"), ) @Test fun letFunctionBodyRequiredWithoutName() = assertModuleAtStage( - stage = Stage.SyntaxMacro, + stageTestDir = StageTestDir("syntax-macro/let-function-body-required-without-name"), // Earlier, `let()` and `fn()` both hard crashed. - input = """let()""", - want = """ - { - "syntaxMacro": { - "body": "error (MissingName)\n", - }, - } - """, ) @Test fun letFunctionNameRequired() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = """let() {}""", - want = """ - { - "syntaxMacro": { - "body": "error (MissingName)\n", - }, - } - """, + stageTestDir = StageTestDir("syntax-macro/let-function-name-required"), ) @Test fun objectPunning() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = """ - |let x = 1; - |{ x } - """.trimMargin(), + stageTestDir = StageTestDir("syntax-macro/object-punning"), moduleResultNeeded = true, - want = """ - |{ - | syntaxMacro: { - | "body": ``` - | let x__0 = 1; - | new(\x, x__0) - | - | ``` - | }, - | errors: ["No signature matches!"], - |} - """.trimMargin(), ) @Test fun whoDecoratesTheDecorators() = assertModuleAtStage( - stage = Stage.SyntaxMacro, + stageTestDir = StageTestDir("syntax-macro/who-decorates-the-decorators"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - provisionModule = { module, _ -> - module.deliverContent( - ModuleSource( - filePath = testCodeLocation, - fetchedContent = """ - |// Stack many decorators on a declaration and make sure they eliminate themselves. - |interface I { - | @foo("FOO") public static var thing; - |} - """.trimMargin(), - languageConfig = StandaloneLanguageConfig, - ), - ) + provisionModule = { module, moduleAdvancer, td -> // We need some more decorators to stack. Invent one. val vFoo = Value( MetadataDecorator(Symbol("foo"), argumentTypes = listOf(Types.string)) { @@ -1246,255 +218,35 @@ class SyntaxMacroStageTest { BuiltinName("@foo") to vFoo, ), ) + provisionModuleForStageTest(td, module, moduleAdvancer) }, - want = """ - |{ - | syntaxMacro: { - | body: { - | code: ``` - | @typeDecl(I__0) @stay let I__0 = type (I__0); - | REM("Stack many decorators on a declaration and make sure they eliminate themselves.", null, false); - | interface(\word, \I, \concrete, false, @typeDefined(I__0) fn { - | I__0 extends AnyValue; - | @staticProperty(\thing) @static @visibility(\public)${ - "" - } @foo("FOO") var thing__0; - | }); - | I__0 - | - | ```, - | tree: [ "Block", [ - | [ "Decl", [ - | [ "LeftName", "I__0" ], - | [ "Value", "\\init: Symbol" ], - | [ "Value", "I__0: Type" ], - | [ "Value", "\\typeDecl: Symbol" ], - | [ "Value", "I__0: Type" ], - | [ "Value", "\\stay: Symbol" ], - | [ "Stay", "kotlin.Unit" ], - | [ "Value", "\\QName: Symbol" ], - | [ "Value", "\"test-code.type I\": String" ], - | ] - | ], - | [ "Call", [ - | [ "Value", "REM: Function" ], - | [ "Value", - |"\"Stack many decorators on a declaration and make sure they eliminate themselves.\": String" - | ], - | [ "Value", "null: Null" ], - | [ "Value", "false: Boolean" ], - | ] - | ], - | [ "Call", [ - | [ "RightName", "interface" ], - | [ "Value", "\\word: Symbol" ], - | [ "Value", "\\I: Symbol" ], - | [ "Value", "\\concrete: Symbol" ], - | [ "Value", "false: Boolean" ], - | [ "Fun", [ - | [ "Value", "\\typeDefined: Symbol" ], - | [ "Value", "I__0: Type" ], - | [ "Block", [ - | [ "Call", [ - | [ "Value", "extends: Function" ], - | [ "Value", "I__0: Type" ], - | [ "Value", "AnyValue: Type" ], - | ] - | ], - | [ "Decl", [ - | [ "LeftName", "thing__0" ], - | [ "Value", "\\staticProperty: Symbol" ], - | [ "Value", "\\thing: Symbol" ], - | [ "Value", "\\var: Symbol" ], - | [ "Value", "void: Void" ], - | [ "Value", "\\static: Symbol" ], - | [ "Value", "void: Void" ], - | [ "Value", "\\visibility: Symbol" ], - | [ "Value", "\\public: Symbol" ], - | [ "Value", "\\foo: Symbol" ], - | [ "Value", "\"FOO\": String" ], - | [ "Value", "\\QName: Symbol" ], - | [ "Value", "\"test-code.type I.thing\": String" ], - | ] - | ], - | ] - | ] - | ] - | ], - | ] - | ], - | [ "RightName", "I__0" ], - | ] - | ] - | } - | } - |} - """.trimMargin(), ) @Test fun blockLambda() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = "f { (arg: ArgType): ReturnType => arg }", - want = """ - |{ - | syntaxMacro: { - | body: { - | code: ``` - | f(fn (arg__0 /* aka arg */: ArgType) /* return__0 */: (ReturnType) { - | arg__0 - | }) - | - | ```, - | tree: - | [ "Block", [ - | [ "Call", [ - | [ "RightName", "f" ], - | [ "Fun", [ - | [ "Decl", [ - | [ "LeftName", "arg__0" ], - | [ "Value", "\\type: Symbol" ], - | [ "RightName", "ArgType" ], - | [ "Value", "\\word: Symbol" ], - | [ "Value", "\\arg: Symbol" ], - | [ "Value", "\\QName: Symbol" ], - | [ "Value", "\"test-code.(arg)\": String" ], - | ] - | ], - | [ "Value", "\\returnDecl: Symbol" ], - | [ "Decl", [ - | [ "LeftName", "return__0" ], - | [ "Value", "\\type: Symbol" ], - | [ "RightName", "ReturnType" ], - | ] - | ], - | [ "Block", [ - | [ "RightName", "arg__0" ], - | ] - | ] - | ] - | ] - | ] - | ] - | ] - | ] - | } - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("syntax-macro/block-lambda"), ) @Test fun mutuallyReferencingInterfaceTypes() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = """ - |interface I { j: J } - |interface J { i: I } - """.trimMargin(), + stageTestDir = StageTestDir("syntax-macro/mutually-referencing-interface-types"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - |{ - | syntaxMacro: { - | body: ``` - | @typeDecl(I__0) @stay let I__0 = type (I__0); - | @typeDecl(J__0) @stay let J__0 = type (J__0); - | interface(\word, \J, \concrete, false, @typeDefined(J__0) fn { - | J__0 extends AnyValue; - | @property(\i) @maybeVar let i__0: I__0; - | }); - | interface(\word, \I, \concrete, false, @typeDefined(I__0) fn { - | I__0 extends AnyValue; - | @property(\j) @maybeVar let j__0: J__0; - | }); - | J__0 - | - | ``` - | } - |} - """.trimMargin(), ) @Test fun mutuallyReferencingClassTypes() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = """ - |class C(private d: D?) {} - |class D(private c: C) {} - """.trimMargin(), + stageTestDir = StageTestDir("syntax-macro/mutually-referencing-class-types"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - |{ - | syntaxMacro: { - | body: ``` - | @typeDecl(C__0) @stay let C__0 = type (C__0); - | @typeDecl(D__0) @stay let D__0 = type (D__0); - | class(\word, \D, \concrete, true, @typeDefined(D__0) fn { - | D__0 extends AnyValue; - | @constructorProperty @property(\c) @maybeVar @visibility(\private) let c__0: C__0; - | @method(\constructor) @visibility(\public) let constructor__0 = fn constructor(@impliedThis(D__0) this__1: D__0, c__1 /* aka c */: C__0) /* return__1 */: Void { - | do { - | let t#0; - | do_iset_c(type (D__0), this(D__0), t#0 = c__1); - | t#0 - | }; - | }; - | }); - | class(\word, \C, \concrete, true, @typeDefined(C__0) fn { - | C__0 extends AnyValue; - | let typeof_d#0 = D__0?; - | @constructorProperty @property(\d) @maybeVar @visibility(\private) let d__0: typeof_d#0; - | @method(\constructor) @visibility(\public) let constructor__1 = fn constructor(@impliedThis(C__0) this__0: C__0, d__1 /* aka d */: typeof_d#0) /* return__0 */: Void { - | do { - | let t#1; - | do_iset_d(type (C__0), this(C__0), t#1 = d__1); - | t#1 - | }; - | }; - | }); - | D__0 - | - | ``` - | } - |} - """.trimMargin(), ) @Test fun mutuallyReferencingFunctionDefinition() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = """ - |// These do not converge since neither has a base case, but they demonstrate hoisting. - |let f(x) { g(x / 2) } - |let g(x) { f(x - 1) } - """.trimMargin(), - want = """ - |{ - | syntaxMacro: { - | body: ``` - | @fn let f__0, @fn g__0; - | REM("These do not converge since neither has a base case, but they demonstrate hoisting.", null, false);${ - // Arbitrary order swap here is ok. - "" - } - | g__0 = fn g(x__0 /* aka x */) { - | fn__0: do { - | f__0(x__0 - 1) - | } - | }; - | f__0 = fn f(x__1 /* aka x */) { - | fn__1: do { - | g__0(x__1 / 2) - | } - | }; - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("syntax-macro/mutually-referencing-function-definition"), ) @Test fun rewriteConnectedDecorator() = assertModuleAtStage( + stageTestDir = StageTestDir("syntax-macro/rewrite-connected-decorator"), // Fake std to get access to `@connected`. loc = ModuleName( sourceFile = filePath( @@ -1505,137 +257,35 @@ class SyntaxMacroStageTest { isPreface = false, ), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - stage = Stage.SyntaxMacro, - input = """ - |class Hi { - | @connected - | private there(); - |} - """.trimMargin(), - want = """ - |{ - | syntaxMacro: { - | body: ``` - | @typeDecl(Hi__0) @stay let Hi__0 = type (Hi__0); - | class(\word, \Hi, \concrete, true, @typeDefined(Hi__0) fn { - | Hi__0 extends AnyValue; - | @method(\there) @visibility(\private) @connected @fn let there__0 = (@connected fn there(@impliedThis(Hi__0) this__0: Hi__0) { - | fn__0: do { - | pureVirtual() - | } - | }); - | @method(\constructor) @visibility(\public) let constructor__0 = fn constructor(@impliedThis(Hi__0) this__1: Hi__0) /* return__0 */: Void {}; - | }); - | Hi__0 - | - | ```, - | }, - |} - """.trimMargin(), ) @Test fun reorder() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = """ - | let f(): Int { let i = 4; let g(): Int { i + j }; g() } - | let j = i + 1; - | let i = 1; - """.trimMargin(), - want = """ - |{ - | syntaxMacro: { - | body: ``` - | @fn let f__0, i__0 = 1, j__0 = i__0 + 1; - | f__0 = fn f /* return__0 */: (Int) { - | fn__0: do { - | @fn let g__0, i__1 = 4; - | g__0 = fn g /* return__1 */: (Int) { - | fn__1: do { - | i__1 + j__0 - | } - | }; - | g__0() - | } - | }; - | - | ```, - | }, - |} - """.trimMargin(), + stageTestDir = StageTestDir("syntax-macro/reorder"), ) @Test fun genericFunctionInDocs() = assertModuleAtStage( - stage = Stage.SyntaxMacro, + stageTestDir = StageTestDir("syntax-macro/generic-function-in-docs"), genre = Genre.Documentation, - input = "let f(x: T): U { x }", - want = """ - |{ - | syntaxMacro: { - | body: ``` - | @fn let f__0; - | @typeFormal(\T) @typeDecl(T__0) @withinDocFold let T__0 = type (T__0); - | @typeFormal(\U) @typeDecl(U__0) @withinDocFold let U__0 = type (U__0); - | U__0 extends T__0; - | f__0 = fn f(x__0 /* aka x */: T__0) /* return__0 */: (U__0) { - | x__0 - | }; - | - | ``` - | } - |} - """.trimMargin(), ) @Test fun untypedFunArgs() = assertModuleAtStage( - stage = Stage.SyntaxMacro, + stageTestDir = StageTestDir("syntax-macro/untyped-fun-args"), genre = Genre.Documentation, - input = "hi { (x: Int, y): String => x }", - want = """ - |{ - | syntaxMacro: { - | body: ``` - | hi(fn (x__0 /* aka x */: Int, y__0 /* aka y */) /* return__0 */: (String) { - | x__0 - | }) - | - | ``` - | } - |} - """.trimMargin(), ) @Test fun objectLiteralNoMatches() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = """ - |{ hi: 5 } - """.trimMargin(), + stageTestDir = StageTestDir("syntax-macro/object-literal-no-matches"), moduleResultNeeded = true, - want = """ - |{ - | syntaxMacro: { - | body: - | ``` - | new(\hi, 5) - | - | ``` - | }, - | errors: ["No signature matches!"] - |} - """.trimMargin(), ) @Test fun objectLiteralMultipleMatches() = assertModuleAtStage( + stageTestDir = StageTestDir("syntax-macro/object-literal-multiple-matches"), stage = Stage.SyntaxMacro, - input = """ - |class Apple(public hi: Int) {} - |class Banana(public hi: Int) {} - |{ hi: 5 } - """.trimMargin(), moduleResultNeeded = true, nameSimplifying = true, manualCheck = ::checkObjectLiteralMultipleMatches, @@ -1643,33 +293,8 @@ class SyntaxMacroStageTest { @Test fun staticMethods() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = """ - |class C { - | public static f(i: Int): Int { i + 1 } - |} - """.trimMargin(), + stageTestDir = StageTestDir("syntax-macro/static-methods"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showTypeMemberMetadata = true), - want = """ - |{ - | syntaxMacro: { - | body: ``` - | @typeDecl(C__0) @stay let C__0 = type (C__0); - | class(\word, \C, \concrete, true, @typeDefined(C__0) fn { - | C__0 extends AnyValue; - | @staticProperty(\f) @fn @static @visibility(\public) let f__0 = fn f(i__0 /* aka i */: Int) /* return__0 */: (Int) { - | fn__0: do { - | i__0 + 1 - | } - | }; - | @method(\constructor) @visibility(\public) let constructor__0 = fn constructor(@impliedThis(C__0) this__0: C__0) /* return__1 */: Void {}; - | }); - | C__0 - | - | ``` - | } - |} - """.trimMargin(), ) private fun checkObjectLiteralMultipleMatches(got: JsonObject) { @@ -1684,33 +309,20 @@ class SyntaxMacroStageTest { @Test fun objectLiteralMultipleMatchesNested() = assertModuleAtStage( + stageTestDir = StageTestDir("syntax-macro/object-literal-multiple-matches-nested"), stage = Stage.SyntaxMacro, // The ObjectLiterals functional test checks non-ambiguous cases for nested scopes, so check an ambiguous case // here to prove we still do that. - input = """ - |class Apple(private hi: Int) {} - |let nest(): Void { - | class Banana(private hi: Int, public ha: Int = 0) {} - | { hi: 5 } - |} - """.trimMargin(), nameSimplifying = true, manualCheck = ::checkObjectLiteralMultipleMatches, ) @Test fun objectLiteralOverloads() = assertModuleAtStage( + stageTestDir = StageTestDir("syntax-macro/object-literal-overloads"), stage = Stage.SyntaxMacro, // At time of writing, these overloads fail at later stages but work correctly here. // Also, check usage both before and after type definition. - input = """ - |{ hi: 5 } - |class Thing { - | public constructor(hi: Int) { } - | public constructor(lo: Int) { } - |} - |{ lo: 5 } - """.trimMargin(), manualCheck = { got -> // Check that we transformed both calls. val code = (got.lookup("syntaxMacro", "body", "code") as? JsonString)!!.content @@ -1722,237 +334,31 @@ class SyntaxMacroStageTest { @Suppress("MaxLineLength") @Test fun storingDocStringWithFn() = assertModuleAtStage( - stage = Stage.Define, + stageTestDir = StageTestDir("syntax-macro/storing-doc-string-with-fn"), pseudoCodeDetail = PseudoCodeDetail.default.copy(metadataValueDetail = NoneShortOrLong.Short), - input = """ - |/** - | * tldr, f(x) = x. - | * - | * When x is an Int. - | * - | * ^ _ - | * | /| - | * y = | / - | * f(x) |/ - | * <--0---> - | * /| x - | * / | - | * |/_ v - | * - | * (ASCII art is hard) - | */ - |let f(x: Int): Int { x } - """.trimMargin(), - want = """ - |{ - | syntaxMacro: { - | body: ``` - | @fn let f__0; - | REM("tldr, f(x) = x.\n\nWhen x is an Int.\n\n ^ _\n | /|\n y = | /\n f(x) |/\n <--0--->\n /| x\n / |\n |/_ v\n\n(ASCII art is hard)", true, false); - | f__0 = (@docString(...) fn f(x__0 /* aka x */: Int) /* return__0 */: (Int) { - | fn__0: do { - | x__0 - | } - | }); - | - | ```, - | }, - | define: { - | body: ``` - | @fn let f__0; - | void; - |## And the comment just fades away. - | f__0 = (@docString(...) @stay fn f(x__0 /* aka x */: Int32) /* return__0 */: Int32 { - | fn__0: do { - | x__0 - | } - | }); - | - | ```, - | }, - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), ) @Test fun docStringsFromMarkdown() = assertModuleAtStage( - stage = Stage.SyntaxMacro, + stageTestDir = StageTestDir("syntax-macro/doc-strings-from-markdown"), pseudoCodeDetail = PseudoCodeDetail.default.copy(metadataValueDetail = NoneShortOrLong.Long), - languageConfig = MarkdownLanguageConfig(), - input = """ - |# Geometry - | - |Point represents a two-dimensional point. - | - | class Point( - | - |Point's factory takes two coordinates. TODO: another factory for polar form. - | - |x is the x coordinate. - | - | public x: Float64, - | - |y is the y coordinate. - | - | public y: Float64, - | ) { - | - |magnitude is the distance of this point from the origin. - | - |It is always >= 0. - | - | magnitude(): Float64 { (x * x + y * y).sqrt() } - | - | } - """.trimMargin(), - want = """ - |{ - | syntaxMacro: { - | body: ``` - |## No "Geometry" for the class doc comment - | @typeDecl(Point__0) @stay @docString((["Point represents a two-dimensional point.", "Point represents a two-dimensional point.", "test/test.temper"])) let Point__0 = type (Point__0); - | REM("Point represents a two-dimensional point.", true, true); - | class(\word, \Point, \concrete, true, @typeDefined(Point__0) fn { - | Point__0 extends AnyValue; - |## x's docs don't talk about the factory - | @docString((["x is the x coordinate.", "x is the x coordinate.", "test/test.temper"])) @constructorProperty @maybeVar @visibility(\public) let x__0: Float64; - | @docString((["y is the y coordinate.", "y is the y coordinate.", "test/test.temper"])) @constructorProperty @maybeVar @visibility(\public) let y__0: Float64; - | REM("magnitude is the distance of this point from the origin.", true, true); - | REM("It is always >= 0.", true, true); - |## magnitude has its doc string - | @fn let magnitude__0 = (@docString((["magnitude is the distance of this point from the origin.", "magnitude is the distance of this point from the origin.\n\nIt is always >= 0.", "test/test.temper"])) fn magnitude(@impliedThis(Point__0) this__0: Point__0) /* return__0 */: (Float64) { - | fn__0: do { - | do_call_sqrt(do_iget_x(type (Point__0), this(Point__0)) * do_iget_x(type (Point__0), this(Point__0)) + do_iget_y(type (Point__0), this(Point__0)) * do_iget_y(type (Point__0), this(Point__0))) - | } - | }); - | @visibility(\public) let constructor__0 = fn constructor(@impliedThis(Point__0) this__1: Point__0, x__1 /* aka x */: Float64, y__1 /* aka y */: Float64) /* return__1 */: Void { - | do { - | let t#0; - | do_iset_x(type (Point__0), this(Point__0), t#0 = x__1); - | t#0 - | }; - | do { - | let t#1; - | do_iset_y(type (Point__0), this(Point__0), t#1 = y__1); - | t#1 - | }; - | }; - | }); - | Point__0 - | - | ```, - | }, - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), ) @Test fun storingDocStringWithType() = assertModuleAtStage( - stage = Stage.SyntaxMacro, + stageTestDir = StageTestDir("syntax-macro/storing-doc-string-with-type"), pseudoCodeDetail = PseudoCodeDetail.default.copy(metadataValueDetail = NoneShortOrLong.Long), - input = """ - |/** Foo is a pretty cool type */ - |class Foo {} - |; - """.trimMargin(), - want = """ - |{ - | syntaxMacro: { - | body: ``` - | @typeDecl(Foo__0) @stay @docString((["Foo is a pretty cool type", "Foo is a pretty cool type", "test/test.temper"])) let Foo__0 = type (Foo__0); - | REM("Foo is a pretty cool type", true, false); - | class(\word, \Foo, \concrete, true, @typeDefined(Foo__0) fn { - | Foo__0 extends AnyValue; - | @visibility(\public) let constructor__0 = fn constructor(@impliedThis(Foo__0) this__0: Foo__0) /* return__0 */: Void {}; - | }); - | - | ```, - | }, - |} - """.trimMargin(), ) @Test fun storingDocStringWithExportedType() = assertModuleAtStage( - stage = Stage.SyntaxMacro, + stageTestDir = StageTestDir("syntax-macro/storing-doc-string-with-exported-type"), pseudoCodeDetail = PseudoCodeDetail.default.copy(metadataValueDetail = NoneShortOrLong.Short), - input = """ - |/** I am a pretty cool type */ - |export interface I {} - |; - """.trimMargin(), - want = """ - |{ - | syntaxMacro: { - | body: ``` - | @typeDecl(I) @stay @docString(...) let `test//`.I = type (I); - | do {}; - | REM("I am a pretty cool type", true, false); - | interface(\word, \I, \concrete, false, @typeDefined(I) fn { - | I extends AnyValue - | }); - | - | ```, - | }, - |} - """.trimMargin(), ) @Test fun commentsOnSettersAndGetters() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = """ - |class C { - | /** Returns 1 */ - | public get x(): Int { 1 } - | /** You can set it but it'll still be 1. */ - | public set x(newValue: Int): Void {} - |} - """.trimMargin(), - want = """ - |{ - | disAmbiguate: { - | body: - | ``` - | @typeDecl(C__0) @hoistLeft(true) @resolution(C__0) @stay let C = type (C__0); - | class(\word, C, \concrete, true, @typeDefined(C__0) fn { - | C__0 extends AnyValue; - | REM("Returns 1", true, false); - | @method(\x) @getter @visibility(\public) let nym`get.x` = fn(\word, nym`get.x`, @impliedThis(C__0) let this__0: C__0, \outType, Int, fn { - | 1 - | }); - | REM("You can set it but it'll still be 1.", true, false); - | @method(\x) @setter @visibility(\public) let nym`set.x` = fn(\word, nym`set.x`, @impliedThis(C__0) let this__1: C__0, let newValue /* aka newValue */: Int, \outType, Void, fn {}); - | }); - | C - | - | ``` - | }, - | syntaxMacro: { - | body: - | ``` - | @typeDecl(C__0) @stay let C__0 = type (C__0); - | class(\word, \C, \concrete, true, @typeDefined(C__0) fn { - | C__0 extends AnyValue; - | @property(\x) @visibility(\public) let x__0; - | REM("Returns 1", true, false); - | @method(\x) @getter @visibility(\public) @fn let nym`get.x__1` = (@docString(...) fn nym`get.x`(@impliedThis(C__0) this__0: C__0) /* return__0 */: (Int) { - | fn__0: do { - | 1 - | } - | }); - | REM("You can set it but it'll still be 1.", true, false); - | @method(\x) @setter @visibility(\public) @fn let nym`set.x__2` = (@docString(...) fn nym`set.x`(@impliedThis(C__0) this__1: C__0, newValue__0 /* aka newValue */: Int) /* return__1 */: (Void) { - | fn__1: do {} - | }); - | @method(\constructor) @visibility(\public) let constructor__0 = fn constructor(@impliedThis(C__0) this__2: C__0) /* return__2 */: Void {}; - | }); - | C__0 - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("syntax-macro/comments-on-setters-and-getters"), pseudoCodeDetail = PseudoCodeDetail.default.copy( metadataValueDetail = NoneShortOrLong.Short, showTypeMemberMetadata = true, @@ -1961,194 +367,30 @@ class SyntaxMacroStageTest { @Test fun consoleBound() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = """ - |let console = getConsole("myConsole"); - |console.log("Hi!"); - |builtins.console.log("Bye!"); - """.trimMargin(), - want = """ - |{ - | syntaxMacro: { - | body: ``` - | let console#0 = doPure(fn: Console { - | getConsole() - | }), console__0 = getConsole("myConsole"); - | do_call_log(console__0, "Hi!"); - | do_call_log(console#0, "Bye!"); - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("syntax-macro/console-bound"), ) @Test fun chainNull() = assertModuleAtStage( - stage = Stage.SyntaxMacro, + stageTestDir = StageTestDir("syntax-macro/chain-null"), // Note that we currently can't properly infer `a != null` for `a.string.end` yet. TODO Infer such. - input = """ - |class StringHolder(public string: String) {} - |export let maybeLength(a: StringHolder?, min: Int): Int? { - | a?.string?.countBetween(String.begin, a.string.end)?.max(min) - |} - """.trimMargin(), - want = """ - |{ - | syntaxMacro: { - | body: - | ``` - | @typeDecl(StringHolder__0) @stay let StringHolder__0 = type (StringHolder__0); - | @fn let `test//`.maybeLength; - | class(\word, \StringHolder, \concrete, true, @typeDefined(StringHolder__0) fn { - | StringHolder__0 extends AnyValue; - | @constructorProperty @maybeVar @visibility(\public) let string__0: String; - | @visibility(\public) let constructor__0 = fn constructor(@impliedThis(StringHolder__0) this__0: StringHolder__0, string__1 /* aka string */: String) /* return__0 */: Void { - | do { - | let t#0; - | do_iset_string(type (StringHolder__0), this(StringHolder__0), t#0 = string__1); - | t#0 - | }; - | }; - | }); - | `test//`.maybeLength = fn maybeLength(a__0 /* aka a */: StringHolder__0?, min__0 /* aka min */: Int) /* return__1 */: (Int?) { - | fn__0: do { - | { - | let subject#0; - | subject#0 = { - | let subject#1; - | subject#1 = { - | if (isNull(a__0)) { - | null - | } else { - | do_get_string(notNull(a__0)) - | } - | }; - | if (isNull(subject#1)) { - | null - | } else { - | do_call_countBetween(notNull(subject#1), do_get_begin(String), do_get_end(do_get_string(a__0))) - | } - | }; - | if (isNull(subject#0)) { - | null - | } else { - | do_call_max(notNull(subject#0), min__0) - | } - | } - | } - | }; - | - | ``` - | }, - |} - """.trimMargin(), ) @Test fun nullChainingDesugaring() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = """ - |let { C, g, complexSubject } = import("./c"); - | - |let f(c: C?): Void { - | g(c?.prop); - | g(complexSubject(c)?.prop); - | - | g(c?.method()); - | g(complexSubject(c)?.method()); - |} - | - |$TEST_INPUT_MODULE_BREAK ./c/c.temper - |// A class to null chain to. - |export class C(public prop: String) { - | public method(): String; - |} - | - |// Somewhere to send null chaining uses. - |export let g(x: String?): Void { if (x != null) { console.log(x) }; } - | - |// Calls to complexSubject shouldn't be duplicated - |export let complexSubject(c: C?): C? { c } - """.trimMargin(), - want = """ - |{ - | syntaxMacro: { - | body: ``` - | @stay @imported(\(`test//c/`.C)) let C__0 = type (C), @imported(\(`test//c/`.g)) @fn g__0 = `test//c/`.g, @imported(\(`test//c/`.complexSubject)) @fn complexSubject__0 = (fn complexSubject), @fn f__0; - | f__0 = fn f(c__0 /* aka c */: C__0?) /* return__0 */: (Void) { - | fn__0: do { - | g__0({ - | if (isNull(c__0)) { - | null - | } else { - | do_get_prop(notNull(c__0)) - | } - | }); - | g__0({ - | let subject#0; - | subject#0 = complexSubject__0(c__0); - | if (isNull(subject#0)) { - | null - | } else { - | do_get_prop(notNull(subject#0)) - | } - | }); - | g__0({ - | if (isNull(c__0)) { - | null - | } else { - | do_call_method(notNull(c__0)) - | } - | }); - | g__0({ - | let subject#1; - | subject#1 = complexSubject__0(c__0); - | if (isNull(subject#1)) { - | null - | } else { - | do_call_method(notNull(subject#1)) - | } - | }); - | } - | }; - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("syntax-macro/null-chaining-desugaring"), ) @Test fun consoleUnbound() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = """ - |do { let console = getConsole("myConsole"); } - |console.log("Hi!"); - |builtins.console.log("Bye!"); - """.trimMargin(), - want = """ - |{ - | syntaxMacro: { - | body: ``` - | let console#0 = doPure(fn: Console { - | getConsole() - | }); - | do (fn { - | let console__0 = getConsole("myConsole"); - | }); - | do_call_log(console#0, "Hi!"); - | do_call_log(console#0, "Bye!"); - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("syntax-macro/console-unbound"), ) @Test fun referencedToPreResolvedPropertyNamesRecognizedAsThisReferences() = assertModuleAtStage( - stage = Stage.SyntaxMacro, + stageTestDir = StageTestDir( + "syntax-macro/referenced-to-pre-resolved-property-names-recognized-as-this-references", + ), // Ensure that when a mixin uses a generated, resolved property name // that we infer the `this.` on it. // The generated code looks like the below: @@ -2158,33 +400,7 @@ class SyntaxMacroStageTest { // i__0 // } // } - want = """ - |{ - | syntaxMacro: { - | body: ``` - | @typeDecl(C__0) @stay let C__0 = type (C__0); - | class (\word, \C, \concrete, true, @typeDefined(C__0) fn { - | C__0 extends AnyValue; - | @visibility(\public) @constructorProperty @maybeVar let i__0: Int32; - | @visibility(\public) let f__0 = fn (@impliedThis(C__0) this__0: C__0) /* return__0 */: Int32 { - |## The resolved i reference here turned into a do_iget_i - | do_iget_i(type (C__0), this(C__0)) - | }; - | @visibility(\public) let constructor__0 = fn constructor(@impliedThis(C__0) this__1: C__0, i__1 /* aka i */: Int32) /* return__1 */: Void { - | do { - | let t#0; - | do_iset_i(type (C__0), this(C__0), t#0 = i__1); - | t#0 - | }; - | }; - | }); - | C__0 - | - | ``` - | } - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), - ) { module, _ -> + ) { module, _, _ -> val document = Document(module) val pos = Position(module.loc, 0, 0) val i = document.nameMaker.unusedSourceName(ParsedName("i")) @@ -2224,429 +440,56 @@ class SyntaxMacroStageTest { @Test fun noPropertyConstructorPropertiesInPropertyBag() { - val input = """ - |class C(private x: Int, @noProperty let y: Int) { - | private z: Int = y + 1; - |} - | - |export let cs = [ - | { x: 1, y: 2 }, - | { x: 1, y: 2, z: 3 }, // ERROR: z not allowed here - |] - """.trimMargin() - val problemSubstring = "{ x: 1, y: 2, z: 3 }" - val problemLeft = input.indexOf(problemSubstring) - val problemRight = problemLeft + problemSubstring.length assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = input, - want = """ - |{ - | syntaxMacro: { - | body: ``` - | @typeDecl(C__0) @stay let C__0 = type (C__0); - | class(\word, \C, \concrete, true, @typeDefined(C__0) fn { - | C__0 extends AnyValue; - | @constructorProperty @maybeVar @visibility(\private) let x__0: Int; - | do {}; - | @maybeVar @visibility(\private) let z__0: Int; - | @visibility(\public) let constructor__0 = fn constructor(@impliedThis(C__0) this__0: C__0, x__1 /* aka x */: Int, @constructorProperty y__0 /* aka y */: Int) /* return__0 */: Void { - | do { - | let t#0; - | do_iset_x(type (C__0), this(C__0), t#0 = x__1); - | t#0 - | }; - | do { - | let t#1; - | do_iset_z(type (C__0), this(C__0), t#1 = y__0 + 1); - | t#1 - | }; - | }; - | }); - | let `test//`.cs = list(new C__0(\x, 1, \y, 2), new(\x, 1, \y, 2, \z, 3)); - | - | ``` - | }, - | errors: [ - | { - | template: "NoSignatureMatches", - | values: [], - | left: $problemLeft, - | right: $problemRight, - | }, - | ], - |} - """.trimMargin(), + stageTestDir = StageTestDir("syntax-macro/no-property-constructor-properties-in-property-bag"), ) } @Test fun setterInvocationUsedInExpressionContext() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = """ - |// A chained assignment involving a setter invocation. - |x = o.p = f() - """.trimMargin(), - want = """ - |{ - | syntaxMacro: { - | body: ``` - | REM("A chained assignment involving a setter invocation.", null, false); - | x = do { - | let t#0; - |## Here we capture the right operand in t#0, - |## so the value assigned to x does not depend - |## on any setter's return value. - | do_set_p(o, t#0 = f()); - | t#0 - | } - | - | ``` - | } - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), + stageTestDir = StageTestDir("syntax-macro/setter-invocation-used-in-expression-context"), ) @Test fun malformedNumericLiteralErrors() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = """ - |export let oneTwoThree = 123i6; - """.trimMargin(), - want = """ - |{ - | syntaxMacro: { - | body: ``` - | let `test//`.oneTwoThree = error (list("123i6")); - | - | ``` - | }, - | errors: [ - | "Malformed number!", - | ] - |} - """.trimMargin(), + stageTestDir = StageTestDir("syntax-macro/malformed-numeric-literal-errors"), ) @Test fun desugarCompoundOp() = assertModuleAtStage( - stage = Stage.SyntaxMacro, - input = """ - |var x = 1; - |x += 2; - """.trimMargin(), + stageTestDir = StageTestDir("syntax-macro/desugar-compound-op"), pseudoCodeDetail = PseudoCodeDetail(resugarDotHelpers = Freq3.Never), - want = """ - |{ - | parse: { - | body: ``` - | nym`@`(var, let x = 1); - |## Parse produces a desugar call for `+=` - | desugarOperation (nym`+=`, x, 2); - | - | ``` - | }, - | import: { - | body: ``` - | nym`@`(var, let x = 1); - |## That resolves early to an assignment to x with a desugar call with the builtin variants. - | x = (nym`do_call__+_`[PlusIntInt, PlusIntInt64, PlusFltFlt])(x, 2); - | - | ``` - | }, - | disAmbiguate: { - | body: ``` - |## `let` macro applied - | var x = 1; - | x = (nym`do_call__+_`[PlusIntInt, PlusIntInt64, PlusFltFlt])(x, 2); - | - | ``` - | }, - | syntaxMacro: { - | body: ``` - |## Names resolved - | var x__0 = 1; - | x__0 = (nym`do_call__+_`[PlusIntInt, PlusIntInt64, PlusFltFlt])(x__0, 2); - | - | ``` - | } - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), stagingFlags = setOf(StagingFlags.skipImportCore), ) @Test fun compoundOpsWithGetterAndSetter() = assertModuleAtStage( - stage = Stage.SyntaxMacro, + stageTestDir = StageTestDir("syntax-macro/compound-ops-with-getter-and-setter"), pseudoCodeDetail = PseudoCodeDetail(resugarDotHelpers = Freq3.Never), stagingFlags = setOf(StagingFlags.skipImportCore), - input = """ - |let { C } = import("./c"); - |do { - | let c = new C(); - | c.x += 1; - | c.x *= 2; - | console.log(c.x); - |} - | - |$TEST_INPUT_MODULE_BREAK ./c/c.temper - |export class C { - | public get x(): Int32 { 1 } - | public set x(newX: Int32) { /* ignoring it */ } - |} - """.trimMargin(), - want = """ - |{ - | disAmbiguate: { - | body: ``` - | @stay @imported(\(`test//c/`.C)) let C = type (C); - | do(fn { - | let c = new C(); - | do { - | let t#0; - | t#0 = c; - | leftHandOf(t#0.x, (nym`do_call__+_`[PlusIntInt, PlusIntInt64, PlusFltFlt])(t#0.x, 1)) - | }; - | do { - | let t#1; - | t#1 = c; - | leftHandOf(t#1.x, (nym`do_call__*_`[TimesIntInt, TimesIntInt64, TimesFltFlt])(t#1.x, 2)) - | }; - | console.log(c.x); - | }) - | - | ```, - | }, - | syntaxMacro: { - | body: ``` - | @stay @imported(\(`test//c/`.C)) let C__0 = type (C), console#0 = doPure(fn: Console { - | getConsole() - | }); - | do (fn { - | let c__0 = new C__0(); - | do { - | let t#0; - | t#0 = c__0; - | do { - | let t#2; - | do_set_x(t#0, t#2 = (nym`do_call__+_`[PlusIntInt, PlusIntInt64, PlusFltFlt])(do_get_x(t#0), 1)); - | t#2 - | } - | }; - | do { - | let t#1; - | t#1 = c__0; - | do { - | let t#3; - | do_set_x(t#1, t#3 = (nym`do_call__*_`[TimesIntInt, TimesIntInt64, TimesFltFlt])(do_get_x(t#1), 2)); - | t#3 - | } - | }; - | do_call_log(console#0, do_get_x(c__0)); - | }) - | - | ```, - | }, - |} - """.trimMargin(), ) @Test fun compoundOpsWithIndexedGetAndSet() = assertModuleAtStage( - stage = Stage.SyntaxMacro, + stageTestDir = StageTestDir("syntax-macro/compound-ops-with-indexed-get-and-set"), pseudoCodeDetail = PseudoCodeDetail(resugarDotHelpers = Freq3.Never), stagingFlags = setOf(StagingFlags.skipImportCore), - input = """ - |export let myList = do { - | let b: ListBuilder = [1, 2].toListBuilder(); - | b[0] += 1; - | b[1] *= 2; - | b.toList() - |}; - """.trimMargin(), - want = """ - |{ - | disAmbiguate: { - | body: ``` - | let `test//`.myList = do(fn { - | let b: ListBuilder = list(1, 2).toListBuilder(); - | do { - | let t#0; - | t#0 = b; - | t#0.set(0, (nym`do_call__+_`[PlusIntInt, PlusIntInt64, PlusFltFlt])(t#0.get(0), 1)) - | }; - | do { - | let t#1; - | t#1 = b; - | t#1.set(1, (nym`do_call__*_`[TimesIntInt, TimesIntInt64, TimesFltFlt])(t#1.get(1), 2)) - | }; - | b.toList() - | }); - | - | ```, - | }, - | syntaxMacro: { - | body: ``` - | let `test//`.myList = do (fn { - | let b__0: ListBuilder = do_call_toListBuilder(list(1, 2)); - | do { - | let t#0; - | t#0 = b__0; - | do_call_set(t#0, 0, (nym`do_call__+_`[PlusIntInt, PlusIntInt64, PlusFltFlt])(do_call_get(t#0, 0), 1)) - | }; - | do { - | let t#1; - | t#1 = b__0; - | do_call_set(t#1, 1, (nym`do_call__*_`[TimesIntInt, TimesIntInt64, TimesFltFlt])(do_call_get(t#1, 1), 2)) - | }; - | do_call_toList(b__0) - | }); - | - | ```, - | }, - |} - """.trimMargin(), ) @Test fun nestedArithmetic() = assertModuleAtStage( - input = """ - |export let negStr(x: Int32): String { - | (-1 * x).toString() - |} - """.trimMargin(), - want = """ - |{ - | syntaxMacro: { - | body: ``` - | @fn let `test//`.negStr; - | `test//`.negStr = fn negStr(x__0 /* aka x */: Int32) /* return__0 */: (String) { - | fn__0: do { - | do_call_toString(-1 * x__0) - | } - | }; - | - | ``` - | } - |} - """.trimMargin(), - stage = Stage.SyntaxMacro, + stageTestDir = StageTestDir("syntax-macro/nested-arithmetic"), ) @Test fun desugarPrefixOp() = assertModuleAtStage( - stage = Stage.SyntaxMacro, + stageTestDir = StageTestDir("syntax-macro/desugar-prefix-op"), stagingFlags = setOf(StagingFlags.skipImportCore), - input = """ - |export let f(x: Int32): Int32 { - | var y = x; - | y--; - | ++y - |} - """.trimMargin(), - want = """ - |{ - | import: { - | body: ``` - | nym`@`(export, let(\word, f, do { - | \_complexArg_; - | x; - | \type; - | Int32 - | }, \outType, Int32, fn { - | nym`@`(var, let y = x); - | do { - |## Name allocated to do pre-capture - | let postfixReturn#0 = y; - |## Dot desugaring here in case there are extensions to do succ and pred. - | y = postfixReturn#0.pred(); - | postfixReturn#0 - | }; - | y = y.succ() - | })) - | - | ```, - | }, - | syntaxMacro: { - | body: ``` - | @fn let `test//`.f; - | `test//`.f = fn f(x__0 /* aka x */: Int32) /* return__0 */: (Int32) { - | fn__0: do { - | var y__0 = x__0; - | do { - | let postfixReturn#0 = y__0; - | y__0 = do_call_pred(postfixReturn#0); - | postfixReturn#0 - | }; - | y__0 = do_call_succ(y__0) - | } - | }; - | - | ``` - | } - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), ) @Test fun desugarPrefixOpWithComplexOperand() = assertModuleAtStage( - stage = Stage.SyntaxMacro, + stageTestDir = StageTestDir("syntax-macro/desugar-prefix-op-with-complex-operand"), stagingFlags = setOf(StagingFlags.skipImportCore), - input = """ - |export let f(ls: ListBuilder, j: Int32): Void { - | var i = j; - | ls[i++]--; - | --ls[ls[++i]]; - |} - """.trimMargin(), - want = """ - |{ - | syntaxMacro: { - | body: ``` - | @fn let `test//`.f; - | `test//`.f = fn f(ls__0 /* aka ls */: ListBuilder, j__0 /* aka j */: Int32) /* return__0 */: (Void) { - | fn__0: do { - | var i__0 = j__0; - |## To do `ls[i++]--`, first we need to get the index `i++`. - | do { - | let t#0; - |## `t#0` lets us avoid multiple evaluation of `ls`. - | t#0 = ls__0; - | let t#1; - | t#1 = do { - | let postfixReturn#0 = i__0; - | i__0 = do_call_succ(postfixReturn#0); - | postfixReturn#0 - | }; - |## Now, `t#1` has the post-incremented `i`. - | do { - |## Reading the array. - | let postfixReturn#1 = do_call_get(t#0, t#1); - |## Writing the array. Same array and element. - | do_call_set(t#0, t#1, do_call_pred(postfixReturn#1)); - |## The result is what was read from the array beforehand. - | postfixReturn#1 - | } - | }; - |## Not as much to do for pre-increment and pre-decreemnt. - |## `--ls[ls[++i]]` is what we're handling here. - |## - | do { - | let t#2; - |## Again, we get the subject. The subject is a simple name, - |## but if it were `var`, reading it's property could have the - |## side-effect of setting it. - | t#2 = ls__0; - | let t#3; - | t#3 = do_call_get(ls__0, i__0 = do_call_succ(i__0)); - | do_call_set(t#2, t#3, do_call_pred(do_call_get(t#2, t#3))) - | }; - | } - | }; - | - | ``` - | } - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), ) } diff --git a/frontend/src/commonTest/kotlin/lang/temper/frontend/TypeStageTest.kt b/frontend/src/commonTest/kotlin/lang/temper/frontend/TypeStageTest.kt index 523aa8bb..3745ff35 100644 --- a/frontend/src/commonTest/kotlin/lang/temper/frontend/TypeStageTest.kt +++ b/frontend/src/commonTest/kotlin/lang/temper/frontend/TypeStageTest.kt @@ -4,15 +4,9 @@ package lang.temper.frontend import lang.temper.builtin.PureCallableValue import lang.temper.builtin.Types -import lang.temper.common.stripDoubleHashCommentLinesToPutCommentsInlineBelow -import lang.temper.common.testCodeLocation import lang.temper.env.InterpMode import lang.temper.lexer.Genre -import lang.temper.lexer.StandaloneLanguageConfig -import lang.temper.log.dirPath -import lang.temper.log.filePath import lang.temper.name.BuiltinName -import lang.temper.name.ModuleName import lang.temper.stage.Stage import lang.temper.type.MkType import lang.temper.type.WellKnownTypes @@ -33,1514 +27,254 @@ import kotlin.test.Test class TypeStageTest { @Test fun emptyFile() = assertModuleAtStage( - input = "", - stage = Stage.Type, - want = """ - |{ - | type: { - | body: - | ``` - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("type/empty-file"), ) @Test fun emptyReplChunk() = assertModuleAtStage( - input = "", + stageTestDir = StageTestDir("type/empty-repl-chunk"), moduleResultNeeded = true, - stage = Stage.Type, - want = """ - |{ - | type: { - | body: - | ``` - | let return__0; - | return__0 = void - | - | ``` - | } - |} - """.trimMargin(), ) @Test fun ifTransformed() = assertModuleAtStage( - input = "if (c) { f() } else { g() }", + stageTestDir = StageTestDir("type/if-transformed"), moduleResultNeeded = true, - stage = Stage.Type, - want = """ - { - type: { - body: - ``` - let return__2; - if (c) { - return__2 = f(); - } else { - return__2 = g(); - }; - - ``` - } - } - """, ) @Test fun whileTransformed() = assertModuleAtStage( - input = "while (c) { f() }", - stage = Stage.Type, - want = """ - { - type: { - body: - ``` - void; - while (c) { - f(); - } - - ``` - } - } - """, + stageTestDir = StageTestDir("type/while-transformed"), ) @Test fun whileTransformedInReplContext() = assertModuleAtStage( - input = "while (c) { f() }", + stageTestDir = StageTestDir("type/while-transformed-in-repl-context"), moduleResultNeeded = true, - stage = Stage.Type, - want = """ - { - type: { - body: - ``` - let return__1; - while (c) { - f(); - }; - return__1 = void - - ``` - } - } - """, ) @Test fun doWhileTransformed() = assertModuleAtStage( - input = "do { f() } while (c)", + stageTestDir = StageTestDir("type/do-while-transformed"), moduleResultNeeded = true, - stage = Stage.Type, - want = """ - { - type: { - body: - ``` - let return__2;${ - "" // TODO: don't we need this to be var for the assignment below? - } - do { - return__2 = f(); - } while (c); - - ``` - } - } - """, ) @Test fun doOnceTransformed() = assertModuleAtStage( - input = "(do { f() })", - stage = Stage.Type, + stageTestDir = StageTestDir("type/do-once-transformed"), moduleResultNeeded = true, - want = """ - { - type: { - body: - ``` - let return__0; - return__0 = f(); - - ``` - } - } - """, ) @Test fun nestedFn() = assertModuleAtStage( - input = """ - let g() { do { f() } } - g() - """.trimIndent(), + stageTestDir = StageTestDir("type/nested-fn"), moduleResultNeeded = true, - stage = Stage.Type, - want = """ - { - type: { - body: - ``` - let return__2, @fn g__0; - g__0 = fn g /* return__5 */{ - void; - fn__0: do { - return__5 = f(); - } - }; - return__2 = g__0(); - - ``` - } - } - """, ) @Test fun bareReferenceToOperator() = assertModuleAtStage( - input = " nym`+` ", + stageTestDir = StageTestDir("type/bare-reference-to-operator"), moduleResultNeeded = true, - stage = Stage.GenerateCode, - want = """ - { - syntaxMacro: { - body: [ "Block", [ [ "RightName", "+" ] ] ], - }, - generateCode: { - body: - ``` - let return__0; - return__0 = nym`+` - - ``` - }, - errors: [ - "No declaration for nym`+`!", - ] - } - """, ) @Test fun minimalForTransformed() = assertModuleAtStage( - input = "for (;;) {}", - stage = Stage.Type, - want = """ - { - type: { - body: - ``` - while (true) {} - - ``` - } - } - """, + stageTestDir = StageTestDir("type/minimal-for-transformed"), ) @Test fun forWithExpressionParts() = assertModuleAtStage( - input = "for (init; cond; incr) {}", - stage = Stage.Type, - want = """ - { - type: { - body: - ``` - init; - for (; - cond; - incr) {} - - ``` - } - } - """, + stageTestDir = StageTestDir("type/for-with-expression-parts"), ) @Test fun asCheckWithIncompleteTypeCompleted() = assertModuleAtStage( - input = "export let noStrings(): Listed { [] as Listed }", - stage = Stage.Type, - want = """ - |{ - | type: { - | body: - | ``` - | @fn let `test//`.noStrings; - | `test//`.noStrings = (@stay fn noStrings /* return__0 */: (Listed) { - | void; - | fn__0: do { - | var fail#0; - |## Above, `as Listed`, here `... as Listed` - | return__0 = hs(fail#0, list() as Listed); - | if (fail#0) { - | bubble() - | }; - | } - | }) - | - | ``` - | } - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), + stageTestDir = StageTestDir("type/as-check-with-incomplete-type-completed"), stagingFlags = setOf(StagingFlags.skipImportCore), ) @Test fun jumpToLabel() = assertModuleAtStage( - input = "break foo", + stageTestDir = StageTestDir("type/jump-to-label"), moduleResultNeeded = true, - stage = Stage.Type, - want = """ - { - type: { - body: { - tree: - [ "Block", - [ - [ "Decl", [ - [ "LeftName", "return__0" ], - [ "Value", "\\ssa: Symbol" ], - [ "Value", "void: Void" ], - ] - ], - [ "break", "\\foo", [] ], - ], - "StructuredFlow", - ], - code: - ``` - let return__0; - break foo; - - ``` - } - } - } - """, // TODO: Why does the assignment `return = void` not happen before the jump? ) @Test fun jumpDefaultLabel() = assertModuleAtStage( - input = "continue", + stageTestDir = StageTestDir("type/jump-default-label"), moduleResultNeeded = true, - stage = Stage.Type, - want = """ - { - type: { - body: { - tree: [ "Block", - [ - [ "Decl", [ - [ "LeftName", "return__0" ], - [ "Value", "\\ssa: Symbol" ], - [ "Value", "void: Void" ], - ] - ], - [ "continue", [] ], - ], - "StructuredFlow", - ], - code: - ``` - let return__0; - continue; - - ``` - } - } - } - """, ) @Test fun forWithIfsAndJumpsTransformed() = assertModuleAtStage( - input = """ - for (init; cond; incr) { - if (a) { - f(); - } else if (b) { - break; - } else { - continue - } - } - """.trimIndent(), - - stage = Stage.Type, - want = """ - { - type: { - body: - ``` - init; - for (; - cond; - incr) { - if (a) { - f() - } else if (b) { - break; - } - } - - ``` - } - } - """, + stageTestDir = StageTestDir("type/for-with-ifs-and-jumps-transformed"), + ) @Test fun minimalForOfTransformed() = assertModuleAtStage( - input = """for (let x of ["foo"]) { console.log(x) }""", - stage = Stage.Type, - want = """ - |{ - | define: { - | body: - | ``` - | let console#0; - | console#0 = doPure(@stay fn: Console { - | getConsole() - | }); - | do_call_forEach(list("foo"), @stay fn (x__0) { - | do_call_log(console#0, x__0) - | }) - | - | ``` - | }, - | type: { - | body: - | ``` - | let console#0; - | console#0 = doPure(@stay fn /* return__0 */: Console { - | return__0 = getConsole(); - | }); - |## Start inlined forEach - | let this__0: List; - | this__0 = list("foo"); - | let n__0; - | n__0 = do_get_length(this__0); - | var i__0; - | i__0 = 0; - | while (i__0 < n__0) { - | let el__0: String; - | el__0 = do_call_get(this__0, i__0); - | i__0 = i__0 + 1; - |## Inlined block lambda - | let x__0; - | x__0 = el__0; - | do_call_log(console#0, x__0); - |## End of inlined block lambda - | }; - | - | ``` - | } - |} - """.trimMargin() - .stripDoubleHashCommentLinesToPutCommentsInlineBelow(), + stageTestDir = StageTestDir("type/minimal-for-of-transformed"), ) @Test fun breakInForOf() = repeat(2) { assertModuleAtStage( - input = """ - |for (let x of ["a", "b", "c", "d"]) { - | if (x == "c") { break } - | console.log(x) - |} - """.trimMargin(), - stage = Stage.Run, + stageTestDir = StageTestDir("type/break-in-for-of"), // Showing extra detail helps clarify that `List.forEach`'s gets rebound to String. pseudoCodeDetail = PseudoCodeDetail(showInferredTypes = true), - want = """ - |{ - | type: { - | body: - | ``` - | let console#0 ⦂ Console; - | console#0 = doPure ⋖ Console ⋗(@stay fn /* return__0 */: Console { - | return__0 = getConsole(); - | }); - | let this__0: List; - | this__0 = list ⋖ String ⋗("a", "b", "c", "d"); - |## Here we start the inlined callee body. - | let n__0 ⦂ Int32; - | n__0 = do_get_length(this__0); - | var i__0 ⦂ Int32; - | i__0 = 0; - | while (i__0 < n__0) { - | let el__0: String; - | el__0 = do_call_get(this__0, i__0); - | i__0 = i__0 + 1; - |## Here we start the inlined block lambda parameters. - | let x__0 ⦂ String; - | x__0 = el__0; - |## Here we start the inlined block lambda body. - |## Note the absence of a void-like return declaration. - | if (x__0 == "c") { - | break; - | }; - | do_call_log(console#0, x__0); - |## Did not inline `return__0 = void`. Not ok for local vars. - |## Here's the end of the inlined block lambda. - | }; - |## Here's the end of the inlined callee body. No `return__0 = void` here either. - | - | ``` - | }, - | run: "void: Void", - | stdout: ``` - | a - | b - | - | ``` - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), ) } @Test fun breakFromInnerLoopToOuter() = assertModuleAtStage( - stage = Stage.Type, - input = """ - |do { - | outer: while (true) { - | while (true) { - | break outer; - | } - | console.log("no"); - | } - | console.log("yes"); - |} - """.trimMargin(), + stageTestDir = StageTestDir("type/break-from-inner-loop-to-outer"), // The reason the loops show up below is that // simplifyControlFlow does not try to determine // whether every body path breaks and therefore // the condition is never re-checked. - want = """ - |{ - | type: { - | body: ``` - | outer__0: do { - | body#0: do {} - | }; - | do_call_log(doPure(@stay fn /* return__0 */: Console { - | return__0 = getConsole(); - | }), "yes"); - | - | ``` - | }, - |} - """.trimMargin(), ) @Test fun continueFromInnerLoopToOuter() = assertModuleAtStage( - stage = Stage.Run, - input = """ - |do { - | var i: Int = 0; - | outer: while (i < 5) { - | i += 1; - | while (i < 10) { - | if (i < 6) { - | continue outer; - | } - | i += 10; - | } - | } - | i - |} - """.trimMargin(), + stageTestDir = StageTestDir("type/continue-from-inner-loop-to-outer"), moduleResultNeeded = true, stagingFlags = setOf(StagingFlags.skipImportCore), - want = """ - |{ - | run: [5, "Int32"], - | type: { - | body: ``` - | let return__0; - | var i__0: Int32; - | i__0 = 0; - | outer__0: while (i__0 < 5) { - | i__0 = i__0 + 1; - | void; - | while (i__0 < 10) { - | if (i__0 < 6) { - | continue outer__0; - | }; - | i__0 = i__0 + 10; - | } - | }; - | return__0 = i__0; - | - | ``` - | } - |} - """.trimMargin(), ) @Test fun blockPulledThroughDecl() = assertModuleAtStage( - input = "let x: int = (do { if (a) { 42 } else { 0 } })", - - stage = Stage.Type, - want = """ - { - type: { - body: - ``` - let x__1: int; - if (a) { - x__1 = 42 - } else { - x__1 = 0 - }; - - ``` - } - } - """, + stageTestDir = StageTestDir("type/block-pulled-through-decl"), ) @Test fun desugarPrefixOperators() = assertModuleAtStage( - stage = Stage.Run, - input = "do { var x: Int = 3; ++x; ++x; --x; x }", + stageTestDir = StageTestDir("type/desugar-prefix-operators"), moduleResultNeeded = true, - want = """ - { - run: "4: Int32", - define : { - body: - ``` - do (@stay fn { - var x__0: Int32; - x__0 = 3; - x__0 = do_call_succ(x__0); - x__0 = do_call_succ(x__0); - x__0 = do_call_pred(x__0); - x__0 - }) - - ``` - } - } - """, ) @Test fun desugarPostfixOperators() = assertModuleAtStage( - stage = Stage.Run, + stageTestDir = StageTestDir("type/desugar-postfix-operators"), // The increment from the last one intentionally doesn't show in the result - input = "do { var x: Int = 3; x++; x++; x--; x++ }", moduleResultNeeded = true, - want = """ - { - run: "4: Int32", - define : { - body: - ``` - do (@stay fn { - var x__4: Int32; - x__4 = 3; - do { - let postfixReturn#0; - postfixReturn#0 = x__4; - x__4 = do_call_succ(postfixReturn#0); - postfixReturn#0 - }; - do { - let postfixReturn#1; - postfixReturn#1 = x__4; - x__4 = do_call_succ(postfixReturn#1); - postfixReturn#1 - }; - do { - let postfixReturn#2; - postfixReturn#2 = x__4; - x__4 = do_call_pred(postfixReturn#2); - postfixReturn#2 - }; - do { - let postfixReturn#3; - postfixReturn#3 = x__4; - x__4 = do_call_succ(postfixReturn#3); - postfixReturn#3 - } - }) - - ``` - } - } - """, ) @Test fun desugarCompoundAssignments() = assertModuleAtStage( - stage = Stage.Run, - input = "do { var x: Int = 10; x -= 9; x += 4; x *= 3; x /= 5; x }", + stageTestDir = StageTestDir("type/desugar-compound-assignments"), // 10 1 5 15 3 3 moduleResultNeeded = true, - want = """ - { - "syntaxMacro": { - "body": - ``` - do (fn { - var x__0: Int = 10; - x__0 = x__0 - 9; - x__0 = x__0 + 4; - x__0 = x__0 * 3; - x__0 = x__0 / 5; - x__0 - }) - - ``` - }, - "type": { - "body": - ``` - let return__0; - var t#0, fail#0, x__0: Int32; - x__0 = 10; - x__0 = x__0 - 9; - x__0 = x__0 + 4; - x__0 = x__0 * 3; - t#0 = hs(fail#0, x__0 / 5); - if (fail#0) { - bubble() - }; - x__0 = t#0; - return__0 = x__0; - - ``` - }, - "run": "3: Int32" - } - """, ) @Test fun desugarCompoundAssignmentsComplexRHS() = assertModuleAtStage( - stage = Stage.Run, - input = "var x: Int = 10; var y: Int = 1; x += (y + 1); x", - want = """ - |{ - | run : "12: Int32", - |} - """.trimMargin(), + stageTestDir = StageTestDir("type/desugar-compound-assignments-complex-r-h-s"), moduleResultNeeded = true, ) @Test @Suppress("SpellCheckingInspection") // Fixing "Brahmagupta's" triggers other lint rules fun brahmaguptasRevenge() = assertModuleAtStage( - stage = Stage.Run, - input = "(0 / 0) orelse 0", + stageTestDir = StageTestDir("type/brahmaguptas-revenge"), moduleResultNeeded = true, - want = """ - { - type: { - body: - ``` - let return__0; - var t#1, fail#3; - orelse#1: { - t#1 = hs(fail#3, 0 / 0); - if (fail#3) { - break orelse#1; - }; - return__0 = t#1 - } orelse { - return__0 = 0 - }; - - ``` - }, - run: "0: Int32" - } - """, ) @Test fun returningUntyped() = assertModuleAtStage( - stage = Stage.Type, - input = "fn { return 42 }", + stageTestDir = StageTestDir("type/returning-untyped"), moduleResultNeeded = true, - want = """ - { - disAmbiguate: { - body: - ``` - fn(fn { - return 42 - }) - - ``` - }, - syntaxMacro: { - body: - ``` - fn /* return__0 */{ - fn__1: do { - do { - return__0 = 42; - break(\label, fn__1) - } - } - } - - ``` - }, - type: { - body: - ``` - let return__2; - return__2 = (@stay fn /* return__0 */{ - fn__1: do { - return__0 = 42 - } - }) - - ``` - } - } - """, ) @Test fun returningWithReturnTypeMetadata() = assertModuleAtStage( - stage = Stage.Type, - input = "fn () : Int { return 42 }", + stageTestDir = StageTestDir("type/returning-with-return-type-metadata"), moduleResultNeeded = true, - want = """ - { - disAmbiguate: { - body: - ``` - fn(\outType, Int, fn { - return 42 - }) - - ``` - }, - syntaxMacro: { - body: - ``` - fn /* return__0 */: (Int) { - fn__1: do { - do { - return__0 = 42; - break(\label, fn__1) - } - } - } - - ``` - }, - type: { - body: - ``` - let return__2; - return__2 = (@stay fn /* return__0 */: Int32 { - fn__1: do { - return__0 = 42 - } - }) - - ``` - } - } - """, ) @Test fun returnThatViolatesReturnType() = assertModuleAtStage( - stage = Stage.GenerateCode, - input = "fn () : Boolean { return 42 }", + stageTestDir = StageTestDir("type/return-that-violates-return-type"), moduleResultNeeded = true, - want = """ - { - disAmbiguate: { - body: - ``` - fn(\outType, Boolean, fn { - return 42 - }) - - ``` - }, - syntaxMacro: { - body: - ``` - fn /* return__0 */: (Boolean) { - fn__1: do { - do { - return__0 = 42; - break(\label, fn__1) - } - } - } - - ``` - }, - type: { - body: - ``` - let return__2; - return__2 = (@stay fn /* return__0 */: Boolean { - fn__1: do { - return__0 = 42 - } - }) - - ``` - }, - generateCode: { - body: - ``` - let return__2; - return__2 = (@stay fn /* return__0 */: Boolean { - return__0 = 42 - }) - - ``` - }, - errors: [ - "Cannot assign to Boolean from Int32!", - "Expected subtype of Boolean, but got Int32!", - ] - } - """, ) @Test fun deepStringToString() = assertModuleAtStage( - stage = Stage.Type, + stageTestDir = StageTestDir("type/deep-string-to-string"), // Only one of these toStrings is actually needed. - input = "fn (i: Int): String { i.toString().toString().toString() }", - want = """ - { - type: { - body: - ``` - @stay fn (i__0 /* aka i */: Int32) /* return__0 */: String { - void; - fn__0: do { - return__0 = do_call_toString(do_call_toString(do_call_toString(i__0))); - } - } - - ``` - } - } - """, ) @Test fun fnWithMixedReturnAndImpliedResultPaths() = assertModuleAtStage( - stage = Stage.Type, - input = "fn(b) { if (b) { return 1 } 0 }", + stageTestDir = StageTestDir("type/fn-with-mixed-return-and-implied-result-paths"), moduleResultNeeded = true, - want = """ - { - syntaxMacro: { - body: - ``` - fn (b__0 /* aka b */) /* return__1 */{ - fn__2: do { - if(b__0, fn { - do { - return__1 = 1; - break(\label, fn__2) - } - }); - 0 - } - } - - ``` - }, - type: { - body: - ``` - let return__3; - return__3 = (@stay fn (b__0 /* aka b */) /* return__1 */{ - fn__2: do { - if (b__0) { - return__1 = 1; - break fn__2; - }; - return__1 = 0 - } - }) - - ``` - } - } - """, ) @Test fun yieldsSeparated() = assertModuleAtStage( - stage = Stage.Type, - provisionModule = { module: Module, _ -> - val input = $$""" - |ignore { (): GeneratorResult extends GeneratorFn => - | while (true) { - | "${ 123 }"; - | yield; - | } - |} - """.trimMargin() + stageTestDir = StageTestDir("type/yields-separated"), + provisionModule = { module: Module, moduleAdvancer, td -> module.addEnvironmentBindings( mapOf(BuiltinName(ImpureIgnoreFn.name) to Value(ImpureIgnoreFn)), ) - module.deliverContent( - ModuleSource( - filePath = testCodeLocation, fetchedContent = input, - languageConfig = StandaloneLanguageConfig, - ), - ) + provisionModuleForStageTest(td, module, moduleAdvancer) }, - want = """ - { - type: { - body: { - code: - ``` - ignore(fn /* return__0 */{ - return__0 = adaptGeneratorFnSafe(@wrappedGeneratorFn fn /* return__1 */: (GeneratorResult) implements GeneratorFn { - return__1 = core.doneResult(); - void; - while (true) { - cat(str(123)); - yield() - } - }) - }); - - ```, - - tree: [ "Block", [ - [ "Call", [ - [ "RightName", "ignore" ], - [ "Fun", [ - [ "Value", "\\returnDecl: Symbol" ], - [ "Decl", [ - [ "LeftName", "return__0" ], - [ "Value", "\\ssa: Symbol" ], - [ "Value", "void: Void" ], - ] - ], - - [ "Block", [ - [ "Call", [ - [ "Value", "nym`=`: Function" ], - [ "LeftName", "return__0" ], - - [ "Call", [ - [ "Value", "adaptGeneratorFnSafe: Function" ], - [ "Fun", [ - [ "Value", "\\returnDecl: Symbol" ], - [ "Decl", [ - [ "LeftName", "return__1" ], - [ "Value", "\\type: Symbol" ], - [ "Value", "GeneratorResult: Type" ], - [ "Value", "\\ssa: Symbol" ], - [ "Value", "void: Void" ], - ] - ], - - [ "Value", "\\super: Symbol" ], - [ "Value", "GeneratorFn: Type" ], - - [ "Value", "\\wrappedGeneratorFn: Symbol" ], - [ "Value", "void: Void" ], - - [ "Block", [ - [ "Call", [ - [ "Value", "nym`=`: Function" ], - [ "LeftName", "return__1" ], - [ "Call", [ - [ "Call", [ - [ "Value", "nym`<>`: Function" ], - [ "RightName", "core.doneResult" ], - [ "Value", "Empty: Type" ], - ] - ] - ] - ] - ] - ], - [ "Value", "void: Void" ], - [ "while", - [ "Value", "true: Boolean" ], - [ - [ "stmt-block", [ - [ "Call", [ - [ "Value", "cat: Function" ], - [ "Call", [ - [ "Value", "str: Function" ], - [ "Value", "123: Int32" ], - ] - ], - ] - ], - [ "Call", [ - [ "Value", "yield: Function" ], - ] - ], - ] - ], - [ "stmt-block", [] ], - ] - ], - ], - "StructuredFlow", - ], - ] - ] - ] - ] - ] - ], - ], - "StructuredFlow", - ] - ], - ] - ], - ], - [ "Value", "void: Void" ], - ], - "StructuredFlow", - ], - } - }, - } - """, ) @Test fun functionWithArgumentsAndReturnType() = assertModuleAtStage( - stage = Stage.Type, - input = """ - fn sum2i(x: Int, y: Int): Int { - return x + y; - } - """, + stageTestDir = StageTestDir("type/function-with-arguments-and-return-type"), moduleResultNeeded = true, - want = """ - { - "syntaxMacro": { - "body": - ``` - do { - @fn let sum2i__0; - sum2i__0 = fn sum2i(x__0 /* aka x */: Int, y__0 /* aka y */: Int) /* return__0 */: (Int) { - fn__0: do { - do { - return__0 = x__0 + y__0; - break(\label, fn__0) - }; - } - }; - sum2i__0 - } - - ``` - }, - "type": { - "body": - ``` - let return__1, @fn sum2i__0; - sum2i__0 = (@stay fn sum2i(x__0 /* aka x */: Int32, y__0 /* aka y */: Int32) /* return__0 */: Int32 { - void; - fn__0: do { - return__0 = x__0 + y__0; - } - }); - return__1 = (fn sum2i) - - ``` - } - } - """, ) @Test fun typeMismatchInCall() = assertModuleAtStage( - stage = Stage.Type, - input = """ - |let i(x: Int) { x } - |i("0") orelse console.log("bad"); - """.trimMargin(), + stageTestDir = StageTestDir("type/type-mismatch-in-call"), moduleResultNeeded = true, - want = """ - |{ - | type: { - | body: - | ``` - | let return__0; - | var t#0; - | t#0 = doPure(@stay fn /* return__1 */: Console { - | return__1 = getConsole(); - | }); - | @fn let i__0; - | i__0 = (@stay fn i(x__0 /* aka x */: Int32) /* return__2 */{ - | fn__0: do { - | return__2 = x__0 - | } - | }); - | orelse#0: { - |## We don't inline the below which has a type error even though its - |## body's semantics would result in "0" if x could be bound. - | (fn i)("0") - | } orelse { - | do_call_log(t#0, "bad"); - | }; - | return__0 = void - | - | ``` - | } - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), ) @Test fun ifNotNullMulti() = assertModuleAtStage( - stage = Stage.Type, + stageTestDir = StageTestDir("type/if-not-null-multi"), // TODO Support auto-not-null on multiple conditions. Or after blocks with early exit. Or ... // TODO Meanwhile, this provides some exploration fodder for such work in the future. - input = """ - |export let multi(a: Int?, b: Int?): Int { - | if (a != null && b != null) { return a * b; } - | 0 - |} - |export let post(a: Int?): Int { - | if (a == null) { return 0; } - | 2 * a - |} - """.trimMargin(), moduleResultNeeded = true, - want = """ - |{ - | type: { - | body: - | ``` - | let return__2, @fn `test//`.multi, @fn `test//`.post; - | `test//`.multi = (@stay fn multi(a__0 /* aka a */: Int32?, b__0 /* aka b */: Int32?) /* return__0 */: Int32 { - | var t#0; - | void; - | fn__0: do { - | if (!isNull(a__0)) { - | t#0 = !isNull(b__0) - | } else { - | t#0 = false - | }; - | if (t#0) { - | return__0 = a__0 * b__0; - | void; - | break fn__0; - | }; - | return__0 = 0 - | } - | }); - | `test//`.post = (@stay fn post(a__1 /* aka a */: Int32?) /* return__1 */: Int32 { - | void; - | fn__1: do { - | if (isNull(a__1)) { - | return__1 = 0; - | break fn__1; - | }; - | return__1 = 2 * a__1; - | } - | }); - | return__2 = void - | - | ``` - | }, - |} - """.trimMargin(), ) @Test fun ifVsNestedIf() = assertModuleAtStage( - stage = Stage.Type, - input = """ - |export let useIf(i: Int) { if (i < 0) { -1 } else if (i > 0) { 1 } else { 0 } } - |export let useIfElse(i: Int) { if (i < 0) { -1 } else { if (i > 0) { 1 } else { 0 } } } - |export let a = if (true) { 1 } else { 0 }; - """.trimMargin(), - want = """ - |{ - | define: { - | body: - | ``` - | @fn let `test//`.useIf, @fn `test//`.useIfElse; - | `test//`.useIf = fn useIf(i__0 /* aka i */: Int32) { - | fn__0: do { - | if(i__0 < 0, @stay fn { - | -1 - | }, \else_if, fn (f#0) { - | f#0(i__0 > 0, @stay fn { - | 1 - | }, \else, fn (f#1) { - | f#1(@stay fn { - | 0 - | }) - | }) - | }) - | } - | }; - | `test//`.useIfElse = fn useIfElse(i__1 /* aka i */: Int32) { - | fn__1: do { - | if(i__1 < 0, @stay fn { - | -1 - | }, \else, fn (f#2) { - | f#2(fn { - | if(i__1 > 0, @stay fn { - | 1 - | }, \else, fn (f#3) { - | f#3(@stay fn { - | 0 - | }) - | }) - | }) - | }) - | } - | }; - | let `test//`.a; - | `test//`.a = if(true, @stay fn { - | 1 - | }, \else, fn (f#4) { - | f#4(@stay fn { - | 0 - | }) - | }); - | - | ``` - | }, - | type: { - | body: - | ``` - | @fn let `test//`.useIf, @fn `test//`.useIfElse; - | `test//`.useIf = (@stay fn useIf(i__0 /* aka i */: Int32) /* return__0 */{ - | void; - | fn__0: do { - | if (i__0 < 0) { - | return__0 = -1 - | } else if (i__0 > 0) { - | return__0 = 1 - | } else { - | return__0 = 0 - | }; - | } - | }); - | `test//`.useIfElse = (@stay fn useIfElse(i__1 /* aka i */: Int32) /* return__1 */{ - | void; - | fn__1: do { - | if (i__1 < 0) { - | return__1 = -1 - | } else { - | if (i__1 > 0) { - | return__1 = 1 - | } else { - | return__1 = 0 - | }; - | }; - | } - | }); - | let `test//`.a; - | `test//`.a = 1 - | - | ``` - | }, - |} - """.trimMargin(), + stageTestDir = StageTestDir("type/if-vs-nested-if"), ) @Test fun ifElseResultNeeded() = assertModuleAtStage( - stage = Stage.Type, - input = """ - |if (a == b) { c } else { d } - """.trimMargin(), + stageTestDir = StageTestDir("type/if-else-result-needed"), moduleResultNeeded = true, - want = """ - { - type: { - body: - ``` - let return__0; - if (a == b) { - return__0 = c - } else { - return__0 = d - }; - - ``` - } - } - """, ) @Test fun ifIsNullResultNeeded() = assertModuleAtStage( - stage = Stage.Type, - input = """ - |export let thing(x: Int?): Int { if (x == null) { 0 } else { x + 1 } } - """.trimMargin(), + stageTestDir = StageTestDir("type/if-is-null-result-needed"), moduleResultNeeded = true, - want = """ - { - type: { - body: - ``` - let return__0, @fn `test//`.thing; - `test//`.thing = (@stay fn thing(x__0 /* aka x */: Int32?) /* return__1 */: Int32 { - void; - fn__0: do { - if (isNull(x__0)) { - return__1 = 0 - } else { - return__1 = notNull(x__0) + 1; - }; - } - }); - return__0 = void - - ``` - } - } - """, ) @Test fun staticAccess() = assertModuleAtStage( - stage = Stage.Run, - input = """ - |class C { public static let foo = "foo"; } - |C.foo == "foo" - """.trimMargin(), + stageTestDir = StageTestDir("type/static-access"), moduleResultNeeded = true, - want = """ - |{ - | run: "true: Boolean" - |} - """.trimMargin(), ) @Test fun amazingEvaporatingClasses() = assertModuleAtStage( - stage = Stage.Type, - input = """ - interface I { - method() - } - class C(private property) extends I { - public method { property } - } - """.trimIndent(), + stageTestDir = StageTestDir("type/amazing-evaporating-classes"), moduleResultNeeded = true, - want = """ - { - type: { - body: - ``` - let return__15; - @fn @stay @fromType(I__0) let method__6; - method__6 = fn method(@impliedThis(I__0) this__2: I__0) /* return__16 */{ - fn__0: do { - pureVirtual() - } - }; - @typeDecl(I__0) @stay let I__0; - I__0 = type (I__0); - @typeDecl(C__1) @stay let C__1; - C__1 = type (C__1); - @constructorProperty @visibility(\private) @stay @fromType(C__1) let property__9; - @visibility(\public) @fn @stay @fromType(C__1) let method__10; - method__10 = (@stay fn method(@impliedThis(C__1) this__3: C__1) /* return__17 */{ - fn__1: do { - return__17 = getp(property__9, this__3) - } - }); - @fn @visibility(\public) @stay @fromType(C__1) let constructor__12; - constructor__12 = (@stay fn constructor(@impliedThis(C__1) this__13: C__1, property__14 /* aka property */) /* return__18 */: Void { - setp(property__9, this__13, property__14); - return__18 = void - }); - return__15 = type (C__1) - - ``` - } - } - """, ) @Test fun explicitTypeArgumentsRemainInTree() = assertModuleAtStage( - stage = Stage.Type, - want = """ - { - disAmbiguate: { - body: { - code: - ``` - echo(42) - - ```, - tree: - [ "Block", [ - [ "Call", [ - [ "Call", [ - [ "Value", "nym`<>`: Function" ], - [ "RightName", "echo" ], - [ "RightName", "Int" ], - ] - ], - [ "Value", "42: Int32" ], - ] - ] - ] - ] - } - }, - type: { - body: - // What's important here is that the tree still has the type arguments. - // No intervening stage has inlined the result of the call to 42. - // TODO: Allow the interpreter to collapse calls to generic functions with - // explicit arguments, just do not allow it to inline away the explicit arguments - // but leave the call. - ``` - let return__0; - return__0 = echo(42); - - ``` - } - } - """.trimIndent(), + stageTestDir = StageTestDir("type/explicit-type-arguments-remain-in-tree"), moduleResultNeeded = true, - ) { module, _ -> - module.deliverContent( - ModuleSource( - filePath = testCodeLocation, - fetchedContent = "echo(42)", - languageConfig = StandaloneLanguageConfig, - ), - ) + ) { module, moduleAdvancer, td -> module.addEnvironmentBindings( mapOf( BuiltinName("echo") to Value( @@ -1571,775 +305,100 @@ class TypeStageTest { ), ), ) + provisionModuleForStageTest(td, module, moduleAdvancer) } @Test fun implicitReturnForDocGenre() = assertModuleAtStage( - stage = Stage.Type, + stageTestDir = StageTestDir("type/implicit-return-for-doc-genre"), genre = Genre.Documentation, - input = """ - |let f(): Void {} - |let g(b: Boolean): Int { - | if (b) { 42 } else { 0 } - |} - """.trimMargin(), - want = """ - |{ - | type: { - | body: ``` - | @fn let f__0, @fn g__0; - | f__0 = (@stay fn f /* return__0 */: (preserve(Void, type (Void))) {}); - | g__0 = (@stay fn g(b__0 /* aka b */: preserve(Boolean, type (Boolean))) /* return__1 */: (preserve(Int, type (Int32))) { - | preserve(if, ifForDocGen)(b__0, do { - | returnForDocGen(42) - | }, do { - | returnForDocGen(0) - | }) - | }); - | - | ``` - | } - |} - """.trimMargin(), ) @Test fun skippedAndSwappedArgs() = assertModuleAtStage( - stage = Stage.Type, + stageTestDir = StageTestDir("type/skipped-and-swapped-args"), // Purposely include named args with side effects to show it's ok because temporaries. - input = """ - |class Hi(private a: Int = 1, private b: Int = 2, private c: Int = 3) {} - |var n = 1; - |{ c: do { n += 1; n }, a: n + 1 }; - """.trimMargin(), - want = """ - |{ - | "type": { - | "body": - | ``` - | var t#0; - | @constructorProperty @visibility(\private) @stay @fromType(Hi__0) let a__0: Int32; - | @constructorProperty @visibility(\private) @stay @fromType(Hi__0) let b__0: Int32; - | @constructorProperty @visibility(\private) @stay @fromType(Hi__0) let c__0: Int32; - | @fn @visibility(\public) @stay @fromType(Hi__0) let constructor__0; - | constructor__0 = (@stay fn constructor(@impliedThis(Hi__0) this__0: Hi__0, @optional(true) a__1 /* aka a */: Int32?, @optional(true) b__1 /* aka b */: Int32?, @optional(true) c__1 /* aka c */: Int32?) /* return__0 */: Void { - | let a__2 /* aka a */: Int32; - | if (isNull(a__1)) { - | a__2 = 1 - | } else { - | a__2 = notNull(a__1); - | }; - | let b__2 /* aka b */: Int32; - | if (isNull(b__1)) { - | b__2 = 2 - | } else { - | b__2 = notNull(b__1); - | }; - | let c__2 /* aka c */: Int32; - | if (isNull(c__1)) { - | c__2 = 3 - | } else { - | c__2 = notNull(c__1); - | }; - | setp(a__0, this__0, a__2); - | setp(b__0, this__0, b__2); - | setp(c__0, this__0, c__2); - | return__0 = void - | }); - | @typeDecl(Hi__0) @stay let Hi__0; - | Hi__0 = type (Hi__0); - | var n__0; - | n__0 = 1; - | n__0 = n__0 + 1; - | t#0 = n__0; - | new Hi__0(n__0 + 1, null, t#0); - | - | ``` - | } - |} - """.trimMargin(), ) - @Test - fun deepDefaultMethod() = assertModuleAtStage( // See issue#1305 - stage = Stage.Run, - input = """ - |interface A { public hi(): String { "hello" } } - |interface B extends A {} - |class C extends B {} - |new C().hi() - """.trimMargin(), + @Test // See issue#1305 + fun deepDefaultMethod() = assertModuleAtStage( + stageTestDir = StageTestDir("type/deep-default-method"), moduleResultNeeded = true, - want = """ - |{ - | run: ["hello", "String"] - |} - """.trimMargin(), ) @Test fun bareReturnVoid() = assertModuleAtStage( - stage = Stage.Type, - input = """ - |let f(returnEarly: Boolean): Void { - | if (returnEarly) { return } - | console.log("Did not return early"); - |} - """.trimMargin(), - want = """ - |{ - | type: { - | body: - | ``` - | let console#0; - | console#0 = doPure(@stay fn /* return__0 */: Console { - | return__0 = getConsole(); - | }); - | @fn let f__0; - | f__0 = (@stay fn f(returnEarly__0 /* aka returnEarly */: Boolean) /* return__1 */: Void { - | void; - | fn__0: do { - | if (returnEarly__0) { - | return__1 = void; - | break fn__0; - | }; - | do_call_log(console#0, "Did not return early"); - | return__1 = void - | } - | }) - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("type/bare-return-void"), ) @Test fun makeEmptyExplicitVoid() = assertModuleAtStage( - stage = Stage.Type, - input = """ - |let f(): Void {} - |let g(): Void { f() } - |g(); - """.trimMargin(), - want = """ - |{ - | type: { - | body: - | ``` - | @fn let f__0, @fn g__0; - | f__0 = (@stay fn f /* return__1 */: Void { - | return__1 = void; - | fn__0: do {} - | }); - | g__0 = (@stay fn g /* return__2 */: Void { - | fn__1: do { - | return__2 = void - | } - | }) - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("type/make-empty-explicit-void"), ) @Test fun issue1828MissingReturn() = assertModuleAtStage( - stage = Stage.Type, - input = """ - |let a(i: List): List { - | if (i.length == 0) { return [] }; // One explicit return - | let n = new ListBuilder(); - | n.map { (it): Int => 2 * it } // One implied return - |} - """.trimMargin(), - want = """ - |{ - | type: { - | body: ``` - | @fn let a__0; - | a__0 = (@stay fn a(i__0 /* aka i */: List) /* return__1 */: (List) { - | void; - | fn__0: do { - | if (do_get_length(i__0) == 0) { - | return__1 = list(); - | break fn__0; - | }; - | let n__0; - | n__0 = new ListBuilder(); - | return__1 = do_call_map(n__0, @stay fn (it__0 /* aka it */) /* return__2 */: Int32 { - | return__2 = 2 * it__0; - | }); - | } - | }) - | - | ```, - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("type/issue1828-missing-return"), ) @Test fun extensionHintsResolved() = assertModuleAtStage( - stage = Stage.Type, + stageTestDir = StageTestDir("type/extension-hints-resolved"), moduleResultNeeded = true, - input = """ - |@extension("isZero") - |let isZero(x: Int): Boolean { x == 0 } - |class Zero { - | public let isZero(): Boolean { true } - |} - | - |0.isZero() && new Zero().isZero() - | - """.trimMargin(), - want = """ - |{ - | type: { - | body: ``` - | let return__0, @fn @extension("isZero") isZero__0; - | @typeDecl(Zero__0) @stay let Zero__0; - | Zero__0 = type (Zero__0); - | isZero__0 = (@stay fn isZero(x__0 /* aka x */: Int32) /* return__1 */: Boolean { - | fn__0: do { - | return__1 = x__0 == 0 - | } - | }); - | @visibility(\public) @fn @stay @fromType(Zero__0) let isZero__1; - | isZero__1 = (@stay fn isZero(@impliedThis(Zero__0) this__0: Zero__0) /* return__2 */: Boolean { - | fn__1: do { - | return__2 = true - | } - | }); - | @fn @visibility(\public) @stay @fromType(Zero__0) let constructor__0; - | constructor__0 = (@stay fn constructor(@impliedThis(Zero__0) this__1: Zero__0) /* return__3 */: Void { - | return__3 = void - | }); - | if (isZero__0(0)) { - | return__0 = do_call_isZero(new Zero__0()); - | } else { - | return__0 = false - | }; - | - | ``` - | }, - |} - """.trimMargin(), ) @Test fun staticExtensionHintsResolved() = assertModuleAtStage( - stage = Stage.Type, + stageTestDir = StageTestDir("type/static-extension-hints-resolved"), moduleResultNeeded = true, - input = """ - |@staticExtension(Int, "isZero") - |let isZero(x: Int): Boolean { x == 0 } - | - |Int.isZero(0) && isZero(0) - | - """.trimMargin(), - want = """ - |{ - | define: { - | body: ``` - | @fn @staticExtension({ - | class: Pair__0, key: type (Int32), value: "isZero" - | }) let isZero__0; - | isZero__0 = (@stay fn isZero(x__0 /* aka x */: Int32) /* return__0 */: Boolean { - | fn__0: do { - | x__0 == 0 - | } - | }); - | if((do_call_isZero[static isZero__0])(type (Int32), 0), @stay fn { - | true - | }, \else, fn (f#0) { - | f#0(@stay fn { - | false - | }) - | }) - | - | ```, - | }, - | type: { - | body: ``` - | let return__1, @fn @staticExtension({ - | class: Pair__0, key: type (Int32), value: "isZero" - | }) isZero__0; - | isZero__0 = (@stay fn isZero(x__0 /* aka x */: Int32) /* return__0 */: Boolean { - | fn__0: do { - | return__0 = x__0 == 0 - | } - | }); - | if (isZero__0(0)) { - | return__1 = true - | } else { - | return__1 = false - | }; - | - | ``` - | }, - |} - """.trimMargin(), ) @Test fun bindingCalleesNotPulledOut() = assertModuleAtStage( - input = $$""" - |let f(hi: String): Void { - | let s: String; - | console.log((s = "Hello, ${hi}!")); - | console.log(s); - |} - """.trimMargin(), - stage = Stage.Type, - want = """ - |{ - | type: { - | body: ``` - | let console#0; - | console#0 = doPure(@stay fn /* return__0 */: Console { - | return__0 = getConsole(); - | }); - | @fn let f__0; - | f__0 = (@stay fn f(hi__0 /* aka hi */: String) /* return__1 */: Void { - | var t#0; - | void; - | fn__0: do { - | let s__0: String; - | s__0 = cat("Hello, ", str(hi__0), "!"); - | t#0 = s__0; - | do_call_log(console#0, t#0); - | do_call_log(console#0, s__0); - | return__1 = void - | } - | }) - | - | ``` - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("type/binding-callees-not-pulled-out"), ) @Test fun importedExtensionsUsable() = assertModuleAtStage( - stage = Stage.Type, - want = """ - |{ - | type: { - | body: ``` - | @stay @imported(\(`half//`.intHalf)) @fn @extension("half") let intHalf__0; - | intHalf__0 = (fn intHalf); - | do_call_log(doPure(@stay fn /* return__0 */: Console { - | return__0 = getConsole(); - | }), do_call_toString(intHalf__0(84))); - |## ^^^^^^^^^^ extension resolved across module boundaries - | - | ``` - | } - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), - provisionModule = { module, moduleAdvancer -> - val otherModule = moduleAdvancer.createModule( - ModuleName( - sourceFile = dirPath("half"), - libraryRootSegmentCount = 1, - isPreface = false, - ), - module.console, - ) - otherModule.deliverContent( - ModuleSource( - filePath = filePath("half", "half.temper"), - fetchedContent = """ - |@extension("half") - |export let intHalf(x: Int): Int { - | x / 2 - |} - """.trimMargin(), - languageConfig = StandaloneLanguageConfig, - ), - ) - module.deliverContent( - ModuleSource( - filePath = testCodeLocation, - fetchedContent = """ - |let { intHalf } = import("../half"); - |console.log(84.half().toString()); - """.trimMargin(), - languageConfig = StandaloneLanguageConfig, - ), - ) - }, + stageTestDir = StageTestDir("type/imported-extensions-usable"), ) @Test fun unaryPlusWashesOut() = assertModuleAtStage( - stage = Stage.FunctionMacro, - input = """ - |// For these first two, the unary plus survives to the typer - |// but is then removed so there's one less thing to translate. - |export let fi(i: Int32): Int32 { +i } - |export let ff(f: Float64): Float64 { +f } - |// This use of `+` is illegal so remains in the tree. - |export let fs(s: String): String { +s } - """.trimMargin(), - want = """ - |{ - | type: { - | body: - | ``` - | @fn let `test//`.fi, @fn `test//`.ff, @fn `test//`.fs; - | `test//`.fi = (@stay fn fi(i__0 /* aka i */: Int32) /* return__0 */: Int32 { - | void; - | fn__0: do { - | return__0 = identity(i__0); - | } - | }); - | `test//`.ff = (@stay fn ff(f__0 /* aka f */: Float64) /* return__1 */: Float64 { - | void; - | fn__1: do { - | return__1 = identity(f__0); - | } - | }); - | `test//`.fs = (@stay fn fs(s__0 /* aka s */: String) /* return__2 */: String { - | void; - | fn__2: do { - | return__2 = +s__0; - | } - | }) - | - | ``` - | }, - | functionMacro: { - | body: - | ``` - | @fn let `test//`.fi, @fn `test//`.ff, @fn `test//`.fs; - | `test//`.fi = (@stay fn fi(i__0 /* aka i */: Int32) /* return__0 */: Int32 { - | void; - | fn__0: do { - |## Now it's gone - | return__0 = i__0; - | } - | }); - | `test//`.ff = (@stay fn ff(f__0 /* aka f */: Float64) /* return__1 */: Float64 { - | void; - | fn__1: do { - | return__1 = f__0; - | } - | }); - | `test//`.fs = (@stay fn fs(s__0 /* aka s */: String) /* return__2 */: String { - | void; - | fn__2: do { - |## This stays here so that TypeChecker can flag it as an error later. - | return__2 = +s__0; - | } - | }) - | - | ``` - | } - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), + stageTestDir = StageTestDir("type/unary-plus-washes-out"), ) @Test fun orElsePanic() = assertModuleAtStage( - stage = Stage.Type, + stageTestDir = StageTestDir("type/or-else-panic"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showInferredTypes = true), moduleResultNeeded = true, - input = """ - |export let f(): String throws Bubble { - | bubble() - |} - | - |let x = f() orelse panic(); - | - |x - """.trimMargin(), - want = """ - |{ - | type: { - | body: - | ``` - | let return__0 ⦂ String; - | var t#0 ⦂ String, fail#0 ⦂ Boolean; - | @fn let `test//`.f ⦂(fn (): String | Bubble); - | `test//`.f = (@stay fn f /* return__1 */: (String | Bubble) { - | fn__0: do { - | bubble ⋖ String ⋗() - | } - | }); - | let x__0 ⦂ String; - | orelse#0: { - | t#0 = hs ⋖ String ⋗(fail#0, (fn f)()); - | if (fail#0) { - | break orelse#0; - | }; - | x__0 = t#0 - | } orelse { - | x__0 = panic ⋖ String ⋗() - | }; - | return__0 = x__0 - | - | ``` - | } - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), ) @Test fun taggedString() = assertModuleAtStage( - stage = Stage.Type, + stageTestDir = StageTestDir("type/tagged-string"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showInferredTypes = true), - input = $$""" - |let f(literals: List, values: List): String { - | literals[0] - |} - | - |export let g(there: String): String { - | f"hi${there}" - |} - """.trimMargin(), - want = """ - |{ - | type: { - | body: - | ``` - | @fn let f__0 ⦂(fn (List, List): String), @fn `test//`.g ⦂(fn (String): String); - | f__0 = (@stay fn f(literals__0 /* aka literals */: List, values__0 /* aka values */: List) /* return__0 */: String { - | void; - | fn__0: do { - | return__0 = do_call_get(literals__0, 0); - | } - | }); - | `test//`.g = (@stay fn g(there__0 /* aka there */: String) /* return__1 */: String { - | fn__1: do { - | return__1 = (fn f)(list ⋖ String ⋗("hi", ""), list ⋖ String ⋗(there__0)) - | } - | }) - | - | ``` - | } - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), ) /** Test overload decorations. */ @Test fun overloadedMethods() = assertModuleAtStage( - stage = Stage.Type, + stageTestDir = StageTestDir("type/overloaded-methods"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showInferredTypes = true), - input = """ - |export class IntMaker(public radix: Int32) { - | @overload("toInt") - | public int64ToInt(int: Int64): Int32 throws Bubble { int.toInt32() } - | - | @overload("toInt") - | public stringToInt(string: String): Int32 throws Bubble { string.toInt32(radix) } - | - | @overload("justMe") - | public int32ToInt(int: Int32): Int32 { int } - |} - | - |export let crazySum(intMaker: IntMaker, int: Int64, string: String): Int throws Bubble { - | let intInt = intMaker.toInt(int); - | let stringInt = intMaker.toInt(string); - | intMaker.justMe(intInt + stringInt) - |} - """.trimMargin(), - want = """ - |{ - | type: { - | body: - | ``` - | @typeDecl(IntMaker) @stay let `test//`.IntMaker ⦂ Type; - | `test//`.IntMaker = type (IntMaker); - | @fn let `test//`.crazySum ⦂(fn (IntMaker, Int64, String): Int32 | Bubble); - | @constructorProperty @visibility(\public) @stay @fromType(IntMaker) let radix__0: Int32; - | @visibility(\public) @overload("toInt") @fn @stay @fromType(IntMaker) let int64ToInt__0 ⦂(fn (IntMaker, Int64): Int32 | Bubble); - | int64ToInt__0 = (@stay fn int64ToInt(@impliedThis(IntMaker) this__0: IntMaker, int__0 /* aka int */: Int64) /* return__0 */: (Int32 | Bubble) { - | void; - | fn__0: do { - | var fail#0 ⦂ Boolean; - | return__0 = hs ⋖ Int32 ⋗(fail#0, do_call_toInt32(int__0)); - | if (fail#0) { - | bubble ⋖ Int32 ⋗() - | }; - | } - | }); - | @visibility(\public) @overload("toInt") @fn @stay @fromType(IntMaker) let stringToInt__0 ⦂(fn (IntMaker, String): Int32 | Bubble); - | stringToInt__0 = (@stay fn stringToInt(@impliedThis(IntMaker) this__1: IntMaker, string__0 /* aka string */: String) /* return__1 */: (Int32 | Bubble) { - | void; - | fn__1: do { - | var fail#1 ⦂ Boolean; - | return__1 = hs ⋖ Int32 ⋗(fail#1, do_call_toInt32(string__0, getp(radix__0, this__1))); - | if (fail#1) { - | bubble ⋖ Int32 ⋗() - | }; - | } - | }); - | @visibility(\public) @overload("justMe") @fn @stay @fromType(IntMaker) let int32ToInt__0 ⦂(fn (IntMaker, Int32): Int32); - | int32ToInt__0 = (@stay fn int32ToInt(@impliedThis(IntMaker) this__2: IntMaker, int__1 /* aka int */: Int32) /* return__2 */: Int32 { - | fn__2: do { - | return__2 = int__1 - | } - | }); - | @fn @visibility(\public) @stay @fromType(IntMaker) let constructor__0 ⦂(fn (IntMaker, Int32): Void); - | constructor__0 = (@stay fn constructor(@impliedThis(IntMaker) this__3: IntMaker, radix__1 /* aka radix */: Int32) /* return__3 */: Void { - | setp(radix__0, this__3, radix__1); - | return__3 = void - | }); - | @fn @visibility(\public) @stay @fromType(IntMaker) let getradix__0 ⦂(fn (IntMaker): Int32); - | getradix__0 = (@stay fn (@impliedThis(IntMaker) this__4: IntMaker) /* return__4 */: Int32 { - | return__4 = getp(radix__0, this__4) - | }); - | `test//`.crazySum = (@stay fn crazySum(intMaker__0 /* aka intMaker */: IntMaker, int__2 /* aka int */: Int64, string__1 /* aka string */: String) /* return__5 */: (Int32 | Bubble) { - | var t#0 ⦂ Int32; - | void; - | fn__3: do { - | var fail#2 ⦂ Boolean, fail#3 ⦂ Boolean; - | let intInt__0 ⦂ Int32; - | intInt__0 = hs ⋖ Int32 ⋗(fail#2, do_call_int64ToInt(intMaker__0, int__2)); - | if (fail#2) { - | bubble ⋖ Int32 ⋗() - | }; - | let stringInt__0 ⦂ Int32; - | stringInt__0 = hs ⋖ Int32 ⋗(fail#3, do_call_stringToInt(intMaker__0, string__1)); - | if (fail#3) { - | bubble ⋖ Int32 ⋗() - | }; - | t#0 = intInt__0 + stringInt__0; - | return__5 = do_call_int32ToInt(intMaker__0, t#0); - | } - | }) - | - | ``` - | } - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), ) /** Test overload decorations. */ @Test fun overriddenAndUnoverriddenOverloadedMethods() = assertModuleAtStage( - stage = Stage.Type, + stageTestDir = StageTestDir("type/overridden-and-unoverridden-overloaded-methods"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showInferredTypes = true), - input = $$""" - |let {C} = import("./c"); - | - |export let useC(c: C): Void { - | c.foo(1); - | c.foo(true); - | c.foo(""); - |} - | - |$$TEST_INPUT_MODULE_BREAK ./c/c.temper - | - |export interface I { - | @overload("foo") - | fooInt32(x: Int32): Void { fooString(x.toString()); } - | - | @overload("foo") - | foolean(x: Boolean): Void { fooString(x.toString()); } - | - | @overload("foo") - | fooString(x: String): Void; - |} - | - |export class C extends I { - | @overload("foo") - | public fooInt32(x: Int32): Void { fooString("Int32 $x"); } - | - | // Does not overload foolean - | - | // Implements fooString but does not redeclare metadata - | public fooString(x: String): Void { - | ; - | } - |} - """.trimMargin(), - want = """ - |{ - | type: { - | body: - | ``` - | @stay @imported(\(`test//c/`.C)) let C__0 ⦂ Type; - | C__0 = type (C); - | @fn let `test//`.useC ⦂(fn (C): Void); - | `test//`.useC = (@stay fn useC(c__0 /* aka c */: C) /* return__0 */: Void { - | void; - | fn__0: do { - | do_call_fooInt32(c__0, 1); - | do_call_foolean(c__0, true); - | do_call_fooString(c__0, ""); - | return__0 = void - | } - | }) - | - | ``` - | } - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), ) @Test fun overloadOnGenerics() = assertModuleAtStage( - stage = Stage.Type, + stageTestDir = StageTestDir("type/overload-on-generics"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showInferredTypes = true), - input = $$""" - |export interface Stringer { - | @overload("stringify") - | public stringifyInt32(int: Int32): String; - | - | @overload("stringify") - | public stringifyInt32List(ints: Listed): String; - | - | @overload("stringify") - | public stringifyStringList(string: Listed): String; - |} - | - |// Purposely receive List but use as Listed above. - |export let stringifyLists(stringer: Stringer, int: Int, ints: List, strings: List): String { - | "${stringer.stringify(int)}, ${stringer.stringify(ints)}, ${stringer.stringify(strings)}" - |} - """.trimMargin(), - want = """ - |{ - | type: { - | body: - | ``` - | @typeDecl(Stringer) @stay let `test//`.Stringer ⦂ Type; - | `test//`.Stringer = type (Stringer); - | @fn let `test//`.stringifyLists ⦂(fn (Stringer, Int32, List, List): String); - | @visibility(\public) @overload("stringify") @fn @stay @fromType(Stringer) let stringifyInt32__0 ⦂(fn (Stringer, Int32): String); - | stringifyInt32__0 = fn stringifyInt32(@impliedThis(Stringer) this__0: Stringer, int__0 /* aka int */: Int32) /* return__0 */: String { - | fn__0: do { - | pureVirtual ⋖ String ⋗() - | } - | }; - | @visibility(\public) @overload("stringify") @fn @stay @fromType(Stringer) let stringifyInt32List__0 ⦂(fn (Stringer, Listed): String); - | stringifyInt32List__0 = fn stringifyInt32List(@impliedThis(Stringer) this__1: Stringer, ints__0 /* aka ints */: Listed) /* return__1 */: String { - | fn__1: do { - | pureVirtual ⋖ String ⋗() - | } - | }; - | @visibility(\public) @overload("stringify") @fn @stay @fromType(Stringer) let stringifyStringList__0 ⦂(fn (Stringer, Listed): String); - | stringifyStringList__0 = fn stringifyStringList(@impliedThis(Stringer) this__2: Stringer, string__0 /* aka string */: Listed) /* return__2 */: String { - | fn__2: do { - | pureVirtual ⋖ String ⋗() - | } - | }; - | `test//`.stringifyLists = (@stay fn stringifyLists(stringer__0 /* aka stringer */: Stringer, int__1 /* aka int */: Int32, ints__1 /* aka ints */: List, strings__0 /* aka strings */: List) /* return__3 */: String { - | void; - | fn__3: do { - | return__3 = cat(str(do_call_stringifyInt32(stringer__0, int__1)), ", ", str(do_call_stringifyInt32List(stringer__0, ints__1)), ", ", str(do_call_stringifyStringList(stringer__0, strings__0))) - | } - | }) - | - | ``` - | } - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), ) /** @@ -2348,82 +407,8 @@ class TypeStageTest { */ @Test fun overloadedMethodsWrong() = assertModuleAtStage( - stage = Stage.Type, + stageTestDir = StageTestDir("type/overloaded-methods-wrong"), pseudoCodeDetail = PseudoCodeDetail.default.copy(showInferredTypes = true), - input = """ - |export class IntMaker(public radix: Int32) { - | public toInt(int: Int64): Int32 throws Bubble { int.toInt32() } - | public toInt(string: String): Int32 throws Bubble { string.toInt32(radix) } - |} - | - |export let crazySum(intMaker: IntMaker, int: Int64, string: String): Int throws Bubble { - | let intInt = intMaker.toInt(int); - | let stringInt = intMaker.toInt(string); - | intInt + stringInt - |} - """.trimMargin(), - want = """ - |{ - | type: { - | body: - | ``` - | @typeDecl(IntMaker) @stay let `test//`.IntMaker ⦂ Type; - | `test//`.IntMaker = type (IntMaker); - | @fn let `test//`.crazySum ⦂(fn (IntMaker, Int64, String): Int32 | Bubble); - | @constructorProperty @visibility(\public) @stay @fromType(IntMaker) let radix__0: Int32; - | @visibility(\public) @fn @stay @fromType(IntMaker) let toInt__0 ⦂(fn (IntMaker, Int64): Int32 | Bubble); - | toInt__0 = (@stay fn toInt(@impliedThis(IntMaker) this__0: IntMaker, int__0 /* aka int */: Int64) /* return__0 */: (Int32 | Bubble) { - | void; - | fn__0: do { - | var fail#0 ⦂ Boolean; - | return__0 = hs ⋖ Int32 ⋗(fail#0, do_call_toInt32(int__0)); - | if (fail#0) { - | bubble ⋖ Int32 ⋗() - | }; - | } - | }); - | @visibility(\public) @fn @stay @fromType(IntMaker) let toInt__1 ⦂(fn (IntMaker, String): Int32 | Bubble); - | toInt__1 = (@stay fn toInt(@impliedThis(IntMaker) this__1: IntMaker, string__0 /* aka string */: String) /* return__1 */: (Int32 | Bubble) { - | void; - | fn__1: do { - | var fail#1 ⦂ Boolean; - | return__1 = hs ⋖ Int32 ⋗(fail#1, do_call_toInt32(string__0, getp(radix__0, this__1))); - | if (fail#1) { - | bubble ⋖ Int32 ⋗() - | }; - | } - | }); - | @fn @visibility(\public) @stay @fromType(IntMaker) let constructor__0 ⦂(fn (IntMaker, Int32): Void); - | constructor__0 = (@stay fn constructor(@impliedThis(IntMaker) this__2: IntMaker, radix__1 /* aka radix */: Int32) /* return__2 */: Void { - | setp(radix__0, this__2, radix__1); - | return__2 = void - | }); - | @fn @visibility(\public) @stay @fromType(IntMaker) let getradix__0 ⦂(fn (IntMaker): Int32); - | getradix__0 = (@stay fn (@impliedThis(IntMaker) this__3: IntMaker) /* return__3 */: Int32 { - | return__3 = getp(radix__0, this__3) - | }); - | `test//`.crazySum = (@stay fn crazySum(intMaker__0 /* aka intMaker */: IntMaker, int__1 /* aka int */: Int64, string__1 /* aka string */: String) /* return__4 */: (Int32 | Bubble) { - | void; - | fn__2: do { - | var fail#2 ⦂ Boolean, fail#3 ⦂ Boolean; - | let intInt__0 ⦂ Int32; - | intInt__0 = hs ⋖ Int32 ⋗(fail#2, do_call_toInt(intMaker__0, int__1)); - | if (fail#2) { - | bubble ⋖ Int32 ⋗() - | }; - | let stringInt__0 ⦂ Int32; - | stringInt__0 = hs ⋖ Int32 ⋗(fail#3, do_call_toInt(intMaker__0, string__1)); - | if (fail#3) { - | bubble ⋖ Int32 ⋗() - | }; - | return__4 = intInt__0 + stringInt__0; - | } - | }) - | - | ``` - | } - |} - """.trimMargin().stripDoubleHashCommentLinesToPutCommentsInlineBelow(), ) } diff --git a/frontend/src/commonTest/kotlin/lang/temper/frontend/parse/ParseStageTest.kt b/frontend/src/commonTest/kotlin/lang/temper/frontend/parse/ParseStageTest.kt index 2ccc2419..82f19f3a 100644 --- a/frontend/src/commonTest/kotlin/lang/temper/frontend/parse/ParseStageTest.kt +++ b/frontend/src/commonTest/kotlin/lang/temper/frontend/parse/ParseStageTest.kt @@ -2,214 +2,40 @@ package lang.temper.frontend.parse +import lang.temper.frontend.StageTestDir import lang.temper.frontend.assertModuleAtStage import lang.temper.lexer.Genre -import lang.temper.stage.Stage import kotlin.test.Test class ParseStageTest { @Test fun appendix() = assertModuleAtStage( - stage = Stage.Parse, - input = """ - |foo() - |;;; - |{ - | "foo": ["bar", { "baz": -800 }, false] - |} - """.trimMargin(), - want = """ - |{ - | parse: { - | body: ``` - | foo() - | - | ```, - | appendix: { - | foo: [ - | "bar", - | { baz: -800 }, - | false - | ] - | } - | } - |} - """.trimMargin(), + stageTestDir = StageTestDir("parse/appendix"), ) @Test fun badUnicodeScalarValues() = assertModuleAtStage( - stage = Stage.Parse, - // Purposely do some things that might throw off sloppy position estimation. - // And include regex, even with good escapes, to make sure we handle such. - input = $$""" - |/./; - |/(^|,)\s*/; - |$${'"'}"" - |"wanna${} be pair\: \ud800\udc00 - |~so does that have more pos needs? - |; - |"fine\u0020escape${" "}here\u"; - |"too big: \u{hi,110000}!\u"; - |"space bad: \u{20, 21}"; - |"empty: \u{}"; - |"fine: \u{20}"; - |"also: \u{20,21}"; - |"bad order: \u{,20,,21,22}"; - |raw"\u{}\u{ }"; - |raw"too big: \u{ hi, 110000 }!\u"; - |raw"too big: \u{ hi${" there"}, 110000 }!\u"; - |raw"hi\u{${" t"}}here"; - |"wanna be ${pair} in list:\u{2${}0,d800,dc00}"; - |"interpolate after list not in:\u{20}${"hi"}"; - |"hi"; - |${hi}; - |"${"hi"}"; - |\{hi}; - |"surrogate, not scalar: \ud834!"; - |"wanna be pair: \ud800\udc00"; - """.trimMargin(), - want = """ - |{ - | parse: { - | body: ``` - | rgx(list("."), list()); - | rgx(list(raw "(^|,)\s*"), list()); - | stringExpr(null, false, "wanna be pair", error (list(raw "\:")), " ", error (list(raw "\ud800")), error (list(raw "\udc00")), "\nso does that have more pos needs?"); - | stringExpr(null, false, "fine", " ", "escape", " ", "here", error (list(raw "\u"))); - | stringExpr(null, false, "too big: ", error (list(raw "\u{hi}")), error (list(raw "\u{110000}")), "!", error (list(raw "\u"))); - | stringExpr(null, false, "space bad: ", " ", error (list(raw "\u{ }")), "!"); - | stringExpr(null, false, "empty: "); - | stringExpr(null, false, "fine: ", " "); - | stringExpr(null, false, "also: ", " ", "!"); - | error (list("`(QuotedGroup`", "\"", "`(Leaf`", "bad order: ", "`Leaf)`", "`(UnicodeRun`", raw "\u{", "`(Comma`", ",", "`(Leaf`", "20", "`Leaf)`", ",", ",", "`(Leaf`", "21", "`Leaf)`", ",", "`(Leaf`", "22", "`Leaf)`", "`Comma)`", "}", "`UnicodeRun)`", "\"", "`QuotedGroup)`")); - | stringExpr(raw, true, raw "\u{", "}", raw "\u{", " ", "}"); - | stringExpr(raw, true, "too big: ", raw "\u{", " ", "hi", ",", " ", "110000", " ", "}", "!", raw "\u"); - | stringExpr(raw, true, "too big: ", raw "\u{", " ", "hi", \interpolate, " there", ",", " ", "110000", " ", "}", "!", raw "\u"); - | stringExpr(raw, true, "hi", raw "\u{", \interpolate, " t", "}", "here"); - | stringExpr(null, false, "wanna be ", pair, " in list:", " ", error (list(raw "\u{d800}")), error (list(raw "\u{dc00}"))); - | stringExpr(null, false, "interpolate after list not in:", " ", "hi"); - | "hi"; - | \interpolate; - | hi; - | stringExpr(null, false, "hi"); - | quasiInner(quasiLeaf(\hi)); - | stringExpr(null, false, "surrogate, not scalar: ", error (list(raw "\ud834")), "!"); - | stringExpr(null, false, "wanna be pair: ", error (list(raw "\ud800")), error (list(raw "\udc00"))); - | - | ```, - | }, - | errors: [ - | "Expected a Expression here!", - | ], - |} - """.trimMargin(), + stageTestDir = StageTestDir("parse/bad-unicode-scalar-values"), ) @Test fun callJoinRewrite() = assertModuleAtStage( - stage = Stage.Parse, - input = """ - |if (a) { b } else if (c) { d } else { e } - """.trimMargin(), - want = """ - |{ - | parse: { - | body: ``` - | if(a, fn { - | b - | }, \else_if, fn (f#0) { - | f#0(c, fn { - | d - | }, \else, fn (f#1) { - | f#1(fn { - | e - | }) - | }) - | }) - | - | ```, - | } - } - """.trimMargin(), + stageTestDir = StageTestDir("parse/call-join-rewrite"), ) @Test fun callJoinRewriteForDocs() = assertModuleAtStage( - stage = Stage.Parse, + stageTestDir = StageTestDir("parse/call-join-rewrite-for-docs"), genre = Genre.Documentation, - input = """ - |if (a) { b } else if (c) { d } else { e } - """.trimMargin(), - want = """ - |{ - | parse: { - | body: ``` - | if(a, fn { - | b - | }, \else_if, c, fn { - | d - | }, \else, fn { - | e - | }) - | - | ```, - | } - } - """.trimMargin(), ) @Test fun angleBracketConfusionErrorMessageIsNotSuperTerrible() = assertModuleAtStage( - stage = Stage.Run, - input = """ - |let or(a: Boolean, b: Boolean): Boolean { a || b } - |let a = 1; - |// The below has a use of angle-brackets, not a use - |// of less-than and a use of greater-than. - |or(a< 2, a > 0); - |// ^---- Missing space causes a parse failure. - """.trimMargin(), - want = """ - |{ - | stageCompleted: "GenerateCode", - | errors: [ - | "Expected a TopLevel here!", - | "Interpreter encountered error()!", - | ], - |} - """.trimMargin(), + stageTestDir = StageTestDir("parse/angle-bracket-confusion-error-message-is-not-super-terrible"), ) @Test fun unrepresentableIntegersWarnedOn() = assertModuleAtStage( - stage = Stage.Parse, - input = """ - |let a = 2147483648; - |let b = 2147483647; // ok - |let c = 2147483648i64; // ok - |let d = 0x8000_0000; // ok because idioms - """.trimMargin(), - want = """ - |{ - | stageCompleted: "Parse", - | parse: { - | body: ``` - | let a = -2147483648, b = 2147483647; - | REM("ok", null, false); - | let c = 2147483648; - | REM("ok", null, false); - | let d = -2147483648; - | - | ``` - | }, - | errors: [ - | { - | "template": "Int32OutOfBounds", - | "values": [ 2.147483648e+9 ] - | } - | ], - |} - """.trimMargin(), + stageTestDir = StageTestDir("parse/unrepresentable-integers-warned-on"), ) } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/README-stage-tests.md b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/README-stage-tests.md new file mode 100644 index 00000000..eef71807 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/README-stage-tests.md @@ -0,0 +1,56 @@ +# Stage tests + +Here's an example of a layout of files for use with the +*assertModuleAtStage* test harness that powers most of our +testing of frontend staging. + +```sh +frontend/src/commonTest/kotlin/lang/temper/frontend/stage-tests/ + README-stage-test.md # This file + syntaxMacro/my-test-id/ + README.md # ignored by test harness. Comments for maintainer + work/ # The work root + test/ + README.md # Ignored + test.temper # The source for the main module to process + # Any other temper or temper.md files that the + # module under test might need to import. + expect/ + README.md # Ignored + disAmbiguate.temper # stage output as temper pseudocode + disAmbiguate.lispy # Lispy output + disAmbiguate-types.json # Information about declared types + disAmbiguate-meta.json # JSON snapshot of module metadata + disAmbiguate-appendix.json # JSON snapshot of module metadata + # similarly file groups for other stages + errors.json # Expected error messages + stdout.txt # Expected console output from any run stage + stage-completed.txt # Max stage completed + run-result.json # Expected result from the run stage +``` + +Any files starting with `README` and ending with `.md` are ignored +as if they don't exist. So are emacs droppings like `*~` files. + +A test directory is usable with `StageTestDir("...")`. +A test directory must have subdirectories `work/` and `expect/`. + +The files in the `expect/` subdirectory specify how much staging is +done, and how to compose the JSON-looking bundle that shows up in +JUnit diffs when an *assertModuleAtStage* test fails. + +# Small files under `expect/` + +Here's a listing of the small files under `expect` that are combined to make the diff bundle: + +For each *Stage* element (*Import*, *DisAmbiguate*, *SyntaxMacro*, *Define*, *Type*, *FunctionMacro*, *Export*, *GenerateCode*) you can have files with any or all or none of these extensions: + - `*.lispy` specifies the detailed `Tree.toLispy()` dump of the AST at that stage + - `*.temper` specifies the `Tree.toPseudoCode()` dump of the AST at that stage + - `.meta.json` specifies Module metadata snapshot including metadata about exports and declared types. + +For the runtime emulation stage, *Stage.Run*, there are a few files: + +- `run.txt` is the concatenation of all `console.log` inputs with line breaks added at runtime. +- `run.result.json` is the JSON dump of the module result. + +`errors.json` is required if the log sink includes entries with severity >= *Log.Warn* that are not filtered out by options passed to *assertModuleAtStage*. diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/accumulator-type-use-no-stmt/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/accumulator-type-use-no-stmt/expect/define.temper new file mode 100644 index 00000000..eb4ddcb8 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/accumulator-type-use-no-stmt/expect/define.temper @@ -0,0 +1,36 @@ + @stay @imported(\(`test//the-count/`.theCount)) let theCount__0; + theCount__0 = type (TheCount__0); + do { + let accumulator#0; +## The tag is used to create an accumulator + accumulator#0 = new TheCount__0(); +## We inlined the body here. + do { + do_call_appendSafe(accumulator#0, "Zero: "); +## Unsafe interpolations become regular appends. + do_call_append(accumulator#0, 0); + do_call_appendSafe(accumulator#0, "\nOne: "); + do_call_append(accumulator#0, 1); + do_call_appendSafe(accumulator#0, "\nTwo: "); + do_call_append(accumulator#0, 2); + do_call_appendSafe(accumulator#0, "\nThree: "); + do_call_append(accumulator#0, 3); + do_call_appendSafe(accumulator#0, "\nF\\our: "); + do_call_append(accumulator#0, 4); + do_call_appendSafe(accumulator#0, "\nFive: "); + do_call_append(accumulator#0, 5); + do_call_appendSafe(accumulator#0, "\n") + }; +## We inject a `.accumulated` fetch for the block result + do_get_accumulated(accumulator#0) + }; + do { + let accumulator#1; + accumulator#1 = new TheCount__0(); + do { + do_call_append(accumulator#1, 6); + do_call_appendSafe(accumulator#1, ", "); + do_call_append(accumulator#1, 7) + }; + do_get_accumulated(accumulator#1) + } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/accumulator-type-use-no-stmt/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/accumulator-type-use-no-stmt/work/test/test.temper new file mode 100644 index 00000000..22c11b22 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/accumulator-type-use-no-stmt/work/test/test.temper @@ -0,0 +1,13 @@ +let { theCount } = import("./the-count"); + +theCount""" + "Zero: ${0} + "One: ${1} + "Two: ${2} + "Three: ${3} + "F\our: ${4} + "Five: ${5} + ; + +theCount"${6}, ${7}" + diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/accumulator-type-use-no-stmt/work/test/the-count/the-count.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/accumulator-type-use-no-stmt/work/test/the-count/the-count.temper new file mode 100644 index 00000000..4dccce5c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/accumulator-type-use-no-stmt/work/test/the-count/the-count.temper @@ -0,0 +1,12 @@ +class TheCount { + public append(i: Int): Void { + console.log("${i}! Ha Ha Ha!"); + } + public appendSafe(s: String): Void {} + + public get accumulated(): Void { + console.log("I am the Count who loves to count!"); + } +} + +export let theCount = TheCount; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/accumulator-type-use/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/accumulator-type-use/expect/define.temper new file mode 100644 index 00000000..d71433d0 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/accumulator-type-use/expect/define.temper @@ -0,0 +1,35 @@ + @stay @imported(\(`test//the-count/`.theCount)) let theCount__0; + theCount__0 = type (TheCount__0); + do { + let accumulator#0; +## The tag is used to create an accumulator + accumulator#0 = new TheCount__0(); +## We inlined the body here. + do { + do_call_appendSafe(accumulator#0, "Zero: "); +## Unsafe interpolations become regular appends. + do_call_append(accumulator#0, 0); + do_call_appendSafe(accumulator#0, "\nOne: "); + do_call_append(accumulator#0, 1); + do_call_appendSafe(accumulator#0, "\n"); +## The loop becomes just a regular forEach application and the content are appends. + do_call_forEach(list(2, 3, 4), fn (n__0) { + do_call_appendSafe(accumulator#0, " "); + do_call_append(accumulator#0, n__0); + }); + do_call_appendSafe(accumulator#0, "!\nFive: "); + do_call_append(accumulator#0, 5); + }; +## We inject a `.accumulated` fetch for the block result + do_get_accumulated(accumulator#0) + }; + do { + let accumulator#1; + accumulator#1 = new TheCount__0(); + do { + do_call_append(accumulator#1, 6); + do_call_appendSafe(accumulator#1, ", "); + do_call_append(accumulator#1, 7) + }; + do_get_accumulated(accumulator#1) + } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/accumulator-type-use/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/accumulator-type-use/work/test/test.temper new file mode 100644 index 00000000..c4603709 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/accumulator-type-use/work/test/test.temper @@ -0,0 +1,15 @@ +let { theCount } = import("./the-count"); + +theCount""" + "Zero: ${0} + // ↑ Starting at zero, because the Count is not a monster. + "One: ${1} + : for (let n of [2, 3, 4]) { + ~ ${n} + : } + "! + ~Five: ${5} + ; + +theCount"${6}, ${7}" + diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/accumulator-type-use/work/test/the-count/the-count.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/accumulator-type-use/work/test/the-count/the-count.temper new file mode 100644 index 00000000..4dccce5c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/accumulator-type-use/work/test/the-count/the-count.temper @@ -0,0 +1,12 @@ +class TheCount { + public append(i: Int): Void { + console.log("${i}! Ha Ha Ha!"); + } + public appendSafe(s: String): Void {} + + public get accumulated(): Void { + console.log("I am the Count who loves to count!"); + } +} + +export let theCount = TheCount; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/auto-assert-message/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/auto-assert-message/expect/define.temper new file mode 100644 index 00000000..64f5fe7f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/auto-assert-message/expect/define.temper @@ -0,0 +1,24 @@ +@stay @imported(\(`std//testing/`.Test)) let Test__0; +Test__0 = type (Test); +@fn @test("hi") let hi__0; +hi__0 = fn hi(test#0: Test) /* return__0 */: (Void | Bubble) { + let num__0; + num__0 = 4; + do { + let actual#0; + actual#0 = 4; + let expected#0; + expected#0 = 3; + do_call_assert(test#0, false, @stay fn { + cat("expected num == (", do_call_toString(3), ") not (", do_call_toString(4), ")") + }) + }; +}; +@fn @test("ha") let ha__0; +ha__0 = fn ha(test#1: Test) /* return__1 */: (Void | Bubble) { + let condition__0; + condition__0 = false; + do_call_assert(test#1, false, @stay fn { + "expected condition" + }); +}; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/auto-assert-message/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/auto-assert-message/work/test/test.temper new file mode 100644 index 00000000..11256926 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/auto-assert-message/work/test/test.temper @@ -0,0 +1,2 @@ +test("hi") { let num = 4; assert(num == 3); } +test("ha") { let condition = false; assert(condition); } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/bad-tests/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/bad-tests/expect/define.temper new file mode 100644 index 00000000..ed9f53d6 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/bad-tests/expect/define.temper @@ -0,0 +1,14 @@ +@stay @imported(\(`std//testing/`.Test)) let Test__0; +Test__0 = type (Test); +test(); +test("hi"); +test("", @stay fn (test#0: Test) /* return__0 */: (Void | Bubble) {}); +test(1, @stay fn (test#1: Test) /* return__1 */: (Void | Bubble) {}); +test("hi", 2); +test(hi, @stay fn (test#2: Test) /* return__2 */: (Void | Bubble) {}); +@fn @test("hi") let hi__0; +hi__0 = fn hi(hi__1 /* aka hi */: String) /* return__3 */: (Void | Bubble) { + assert(true, @stay fn { + "nope" + }) +}; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/bad-tests/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/bad-tests/expect/errors.json new file mode 100644 index 00000000..12527263 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/bad-tests/expect/errors.json @@ -0,0 +1,12 @@ +[ + "Wrong number of arguments. Expected 2!", + "Wrong number of arguments. Expected 2!", + "Expected function type, but got Int32!", + "Wrong number of arguments. Expected 2!", + "Wrong number of arguments. Expected 2!", + "Expected a name!", + "Expected value of type String not Int32!", + "Expected function type, but got Int32!", + "Unable to evaluate!", + "Invalid block content!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/bad-tests/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/bad-tests/work/test/test.temper new file mode 100644 index 00000000..1085590d --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/bad-tests/work/test/test.temper @@ -0,0 +1,7 @@ +test(); +test("hi"); +test("") {} +test(1) {} +test("hi", 2); +test(hi) {} +test("hi") { hi: String => assert(true) { "nope" } } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/call-to-method/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/call-to-method/expect/define.temper new file mode 100644 index 00000000..6c31fd25 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/call-to-method/expect/define.temper @@ -0,0 +1 @@ +do_call_verb(subject, arg) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/call-to-method/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/call-to-method/work/test/test.temper new file mode 100644 index 00000000..a9ddf7b3 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/call-to-method/work/test/test.temper @@ -0,0 +1 @@ +subject.verb(arg) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/casting-call/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/casting-call/expect/define.temper new file mode 100644 index 00000000..d456120f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/casting-call/expect/define.temper @@ -0,0 +1,16 @@ +void; +let t#0; +t#0 = c; +let b__0; +b__0 = do_get_a(t#0); +void; +1 as Int32; +2 as Mystery; +3 as type (List); +error (list("`(Leaf`", "4", "`Leaf)`", "as")); +do_call_as(5, type (Int32)); +do_call_as(6, Mystery); +do_call_as(7); +do_get_as(8); +do_call_get(list(9), 0) as Int32; +do_call_toString(10) as String; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/casting-call/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/casting-call/expect/errors.json new file mode 100644 index 00000000..551efe0b --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/casting-call/expect/errors.json @@ -0,0 +1,4 @@ +[ + "Operator As expects at least 2 operands but got 1!", + "Expected a TopLevel here!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/casting-call/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/casting-call/work/test/test.temper new file mode 100644 index 00000000..ff7bcf91 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/casting-call/work/test/test.temper @@ -0,0 +1,13 @@ +// Prelude on ensuring that it's rename inside property bags. +let { a as b } = c; +// Now on to the casting call. +1 as Int; +2 as Mystery; +3 as List; +4 as; +5.as(Int); +6.as(Mystery); +7.as(); +8.as; +[9][0] as Int; +10.toString() as String; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/char-tag/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/char-tag/expect/define.temper new file mode 100644 index 00000000..ea90ee31 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/char-tag/expect/define.temper @@ -0,0 +1 @@ +45 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/char-tag/expect/import.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/char-tag/expect/import.temper new file mode 100644 index 00000000..aa8b5332 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/char-tag/expect/import.temper @@ -0,0 +1 @@ +stringExpr(char, true, "-") diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/char-tag/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/char-tag/work/test/test.temper new file mode 100644 index 00000000..3f6cd446 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/char-tag/work/test/test.temper @@ -0,0 +1 @@ +char'-' diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/class-extends-class/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/class-extends-class/expect/define.temper new file mode 100644 index 00000000..167240a7 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/class-extends-class/expect/define.temper @@ -0,0 +1,38 @@ +Apple__0 extends AnyValue; +@fn @method(\constructor) @visibility(\public) @stay @fromType(Apple__0) let constructor__0; +constructor__0 = (@stay fn constructor(@impliedThis(Apple__0) this__0: Apple__0) /* return__0 */: Void {}); +@typeDecl(Apple__0) @stay let Apple__0; +Apple__0 = type (Apple__0); +@typeDecl(Banana__0) @stay let Banana__0; +Banana__0 = type (Banana__0); +@typeDecl(Cherry__0) @stay let Cherry__0; +Cherry__0 = type (Cherry__0); +@typeDecl(Durian__0) @stay let Durian__0; +Durian__0 = type (Durian__0); +class(\word, \Apple, \concrete, true, @typeDefined(Apple__0) fn { + do {}; + do {} +}); +Banana__0 extends AnyValue; +@fn @method(\constructor) @visibility(\public) @stay @fromType(Banana__0) let constructor__1; +constructor__1 = (@stay fn constructor(@impliedThis(Banana__0) this__1: Banana__0) /* return__1 */: Void {}); +class(\word, \Banana, \concrete, true, @typeDefined(Banana__0) fn { + do {}; + do {} +}); +Cherry__0 extends AnyValue; +@typePlaceholder(Cherry__0) let typePlaceholder#0: Empty; +typePlaceholder#0 = {class: Empty__0}; +interface(\word, \Cherry, \concrete, false, @typeDefined(Cherry__0) fn { + do {} +}); +Durian__0 extends Apple__0; +Durian__0 extends ([Banana__0, Cherry__0]); +@fn @method(\constructor) @visibility(\public) @stay @fromType(Durian__0) let constructor__2; +constructor__2 = (@stay fn constructor(@impliedThis(Durian__0) this__2: Durian__0) /* return__2 */: Void {}); +class(\word, \Durian, \concrete, true, @typeDefined(Durian__0) fn { + do {}; + do {}; + do {} +}); +type (Durian__0) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/class-extends-class/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/class-extends-class/expect/errors.json new file mode 100644 index 00000000..64c47068 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/class-extends-class/expect/errors.json @@ -0,0 +1,4 @@ +[ + "Cannot extend concrete type(s) Apple!", + "Cannot extend concrete type(s) Banana!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/class-extends-class/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/class-extends-class/work/test/test.temper new file mode 100644 index 00000000..7e21c862 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/class-extends-class/work/test/test.temper @@ -0,0 +1,4 @@ +class Apple {} +class Banana {} +interface Cherry {} +class Durian extends Apple, Banana & Cherry {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/classes-with-disclosures/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/classes-with-disclosures/expect/define.temper new file mode 100644 index 00000000..ebb9e5cb --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/classes-with-disclosures/expect/define.temper @@ -0,0 +1,77 @@ +@fn let f__6; +ClosesOverNothing__0 extends AnyValue; +@fn @method(\constructor) @visibility(\public) @stay @fromType(ClosesOverNothing__0) let constructor__10; +constructor__10 = (@stay fn constructor(@impliedThis(ClosesOverNothing__0) this__11: ClosesOverNothing__0) /* return__0 */: Void {}); +ClosesOverX__1 extends AnyValue; +@property(\p) @visibility(\public) @stay @fromType(ClosesOverX__1) let p__13; +@method(\p) @getter @fn @stay @fromType(ClosesOverX__1) let nym`get.p__14`; +nym`get.p__14` = fn nym`get.p`(@impliedThis(ClosesOverX__1) this__3: ClosesOverX__1) { + fn__15: do { + getCR(getp(cr__23, this__3), 0) + } +}; +@property(\cr__23) @visibility(\protected) @stay @synthetic @fromType(ClosesOverX__1) let cr__23: ClosRec; +ClosesOverY__2 extends ClosesOverX__1; +@property(\q) @visibility(\public) @stay @fromType(ClosesOverY__2) let q__18; +@method(\q) @getter @visibility(\public) @fn @stay @fromType(ClosesOverY__2) let nym`get.q__19`; +nym`get.q__19` = fn nym`get.q`(@impliedThis(ClosesOverY__2) this__4: ClosesOverY__2) { + fn__20: do { + getCR(getp(cr__24, this__4), 0) + } +}; +@fn @method(\constructor) @visibility(\public) @stay @fromType(ClosesOverY__2) let constructor__21; +constructor__21 = (@stay fn constructor(@impliedThis(ClosesOverY__2) this__22: ClosesOverY__2, cr__25: ClosRec, cr__26: ClosRec) /* return__1 */: Void { + setp(cr__27, this__22, cr__25); + setp(cr__24, this__22, cr__26) +}); +@property(\cr__27) @visibility(\private) @stay @synthetic @fromType(ClosesOverY__2) let cr__27: ClosRec; +@property(\cr__23) @visibility(\private) @stay @synthetic @fromType(ClosesOverY__2) let cr__28: ClosRec; +@method(\cr__23) @getter @visibility(\protected) @stay @synthetic @fn @fromType(ClosesOverY__2) let nym`get.cr__29`; +nym`get.cr__29` = fn (@impliedThis(ClosesOverY__2) this__30: ClosesOverY__2) { + getp(cr__27, this__30) +}; +@property(\cr__24) @visibility(\private) @stay @synthetic @fromType(ClosesOverY__2) let cr__24: ClosRec; +f__6 = fn f(x__7 /* aka x */) { + fn__8: do { + let cr#31; + cr#31 = makeCR(\word, x__7, \setter, fn (v#32) { + x__7 = v#32 + }); + @typeDecl(ClosesOverNothing__0) @stay let ClosesOverNothing__0; + ClosesOverNothing__0 = type (ClosesOverNothing__0); + @typeDecl(ClosesOverX__1) @stay let ClosesOverX__1; + ClosesOverX__1 = type (ClosesOverX__1); + class(\word, \ClosesOverNothing, \concrete, true, @typeDefined(ClosesOverNothing__0) fn { + do {}; + do {} + }); + interface(\word, \ClosesOverX, \concrete, false, @typeDefined(ClosesOverX__1) fn { + do {}; + do {}; + do {}; + do {} + }); + do (fn { + let cr#33; + cr#33 = makeCR(\word, y__16, \setter, fn (v#34) { + y__16 = v#34 + }); + @typeDecl(ClosesOverY__2) @stay let ClosesOverY__2; + ClosesOverY__2 = type (ClosesOverY__2); + let y__16; + y__16 = x__7 + 1; + class(\word, \ClosesOverY, \concrete, true, @typeDefined(ClosesOverY__2) fn { + do {}; + do {}; + do {}; + do {}; + do {}; + do {}; + do {}; + do {} + }); + new ClosesOverY__2(cr#31, cr#33) + }); + new ClosesOverNothing__0(); + } +}; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/classes-with-disclosures/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/classes-with-disclosures/work/test/test.temper new file mode 100644 index 00000000..7a6efb4b --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/classes-with-disclosures/work/test/test.temper @@ -0,0 +1,18 @@ +let f(x) { + class ClosesOverNothing {} + + interface ClosesOverX { + get p() { x } + } + + do { + let y = x + 1; + + class ClosesOverY extends ClosesOverX { + public get q() { y } + } + new ClosesOverY() + } + + new ClosesOverNothing(); +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/coalesce/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/coalesce/expect/define.temper new file mode 100644 index 00000000..b084f4ec --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/coalesce/expect/define.temper @@ -0,0 +1,27 @@ +@fn let `test//`.prod, @fn `test//`.prodWrap; +`test//`.prod = (@stay fn prod(i__0 /* aka i */: Int32, j__0 /* aka j */: Int32?) /* return__0 */: Int32 { + fn__0: do { + i__0 * { + if (isNull(j__0)) { + 1 + } else { + j__0 + } + } + } +}); +`test//`.prodWrap = (@stay fn prodWrap(i__1 /* aka i */: Int32, j__1 /* aka j */: List) /* return__1 */: Int32 { + fn__1: do { + i__1 * do { + let subject#0; + subject#0 = do_call_get(j__1, 0); + { + if (isNull(subject#0)) { + 1 + } else { + subject#0 + } + } + } + } +}); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/coalesce/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/coalesce/work/test/test.temper new file mode 100644 index 00000000..0f400f84 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/coalesce/work/test/test.temper @@ -0,0 +1,2 @@ +export let prod(i: Int, j: Int?): Int { i * (j ?? 1) } +export let prodWrap(i: Int, j: List): Int { i * (j[0] ?? 1) } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/complex-type-aliases/expect/define.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/complex-type-aliases/expect/define.lispy new file mode 100644 index 00000000..ac2cc922 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/complex-type-aliases/expect/define.lispy @@ -0,0 +1,201 @@ +[ + "Block", + [ + [ + "Decl", + [ + [ + "LeftName", + "Sn__0" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.Sn\u0022: String" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "nym`=`: Function" + ], + [ + "LeftName", + "Sn__0" + ], + [ + "Value", + "String?: Type" + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "Ds__0" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.Ds\u0022: String" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "nym`=`: Function" + ], + [ + "LeftName", + "Ds__0" + ], + [ + "Value", + "Deque\u003cString?\u003e: Type" + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "Dn__0" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.Dn\u0022: String" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "nym`=`: Function" + ], + [ + "LeftName", + "Dn__0" + ], + [ + "Value", + "Deque\u003cString?\u003e?: Type" + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "s__0" + ], + [ + "Value", + "\\type: Symbol" + ], + [ + "Value", + "String?: Type" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.s\u0022: String" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "d__0" + ], + [ + "Value", + "\\type: Symbol" + ], + [ + "Value", + "Deque\u003cString?\u003e?: Type" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.d\u0022: String" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ] + ] + ], + [ + "Value", + "void: Void" + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/complex-type-aliases/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/complex-type-aliases/expect/define.temper new file mode 100644 index 00000000..732bc7e8 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/complex-type-aliases/expect/define.temper @@ -0,0 +1,7 @@ +let Sn__0; +Sn__0 = type (String?); +let Ds__0; +Ds__0 = type (Deque); +let Dn__0; +Dn__0 = type (Deque?); +let s__0: String?, d__0: Deque?; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/complex-type-aliases/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/complex-type-aliases/work/test/test.temper new file mode 100644 index 00000000..0cd52d09 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/complex-type-aliases/work/test/test.temper @@ -0,0 +1,5 @@ +let Sn = String?; +let Ds = Deque; +let Dn = Ds?; +let s: Sn; +let d: Dn; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/conditionally-assigned-const-not-inlined/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/conditionally-assigned-const-not-inlined/expect/define.temper new file mode 100644 index 00000000..b30d1936 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/conditionally-assigned-const-not-inlined/expect/define.temper @@ -0,0 +1,20 @@ +let console#0; +console#0 = doPure(@stay fn: Console { + getConsole() +}); +@fn let f__1; +f__1 = fn f(b__2 /* aka b */: Boolean) /* return__0 */: Int32 { + fn__3: do { + let i__4: Int32; + if(b__2, fn { + i__4 = -1 + }, \else, fn (f#0) { + f#0(fn { + i__4 = 1 + }) + }); + i__4 + } +}; +do_call_log(console#0, cat("f(true )=", str(f__1(true)))); +do_call_log(console#0, cat("f(false)=", str(f__1(false)))); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/conditionally-assigned-const-not-inlined/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/conditionally-assigned-const-not-inlined/expect/run-result.json new file mode 100644 index 00000000..cc7a3b30 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/conditionally-assigned-const-not-inlined/expect/run-result.json @@ -0,0 +1 @@ +"void: Void" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/conditionally-assigned-const-not-inlined/expect/stdout.txt b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/conditionally-assigned-const-not-inlined/expect/stdout.txt new file mode 100644 index 00000000..303058ec --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/conditionally-assigned-const-not-inlined/expect/stdout.txt @@ -0,0 +1,2 @@ +f(true )=-1 +f(false)=1 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/conditionally-assigned-const-not-inlined/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/conditionally-assigned-const-not-inlined/work/test/test.temper new file mode 100644 index 00000000..f345f403 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/conditionally-assigned-const-not-inlined/work/test/test.temper @@ -0,0 +1,7 @@ +let f(b: Boolean): Int { + let i: Int; + if (b) { i = -1 } else { i = 1 } + i +}; +console.log("f(true )=${f(true)}"); +console.log("f(false)=${f(false)}"); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/constant-folding-via-const-expression/expect/define.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/constant-folding-via-const-expression/expect/define.lispy new file mode 100644 index 00000000..7fcfb651 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/constant-folding-via-const-expression/expect/define.lispy @@ -0,0 +1,51 @@ +[ + "Block", + [ + [ + "Decl", + [ + [ + "LeftName", + "one__0" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.one\u0022: String" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "nym`=`: Function" + ], + [ + "LeftName", + "one__0" + ], + [ + "Value", + "1: Int32" + ] + ] + ], + [ + "Value", + "2: Int32" + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/constant-folding-via-const-expression/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/constant-folding-via-const-expression/expect/define.temper new file mode 100644 index 00000000..46a7e41a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/constant-folding-via-const-expression/expect/define.temper @@ -0,0 +1,3 @@ +let one__0; +one__0 = 1; +2 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/constant-folding-via-const-expression/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/constant-folding-via-const-expression/expect/syntaxMacro.temper new file mode 100644 index 00000000..869175e3 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/constant-folding-via-const-expression/expect/syntaxMacro.temper @@ -0,0 +1,2 @@ +let one__0 = 1; +one__0 + one__0 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/constant-folding-via-const-expression/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/constant-folding-via-const-expression/work/test/test.temper new file mode 100644 index 00000000..fda46130 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/constant-folding-via-const-expression/work/test/test.temper @@ -0,0 +1 @@ +let one = 1; one + one diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/constant-folding/expect/define.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/constant-folding/expect/define.lispy new file mode 100644 index 00000000..3c4e4927 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/constant-folding/expect/define.lispy @@ -0,0 +1,9 @@ +[ + "Block", + [ + [ + "Value", + "2: Int32" + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/constant-folding/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/constant-folding/work/test/test.temper new file mode 100644 index 00000000..8d2f0971 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/constant-folding/work/test/test.temper @@ -0,0 +1 @@ +1 + 1 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/dot-operation-desugaring/expect/define-types.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/dot-operation-desugaring/expect/define-types.json new file mode 100644 index 00000000..ce8c2253 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/dot-operation-desugaring/expect/define-types.json @@ -0,0 +1,68 @@ +{ + "AnyValue": { + "abstract": true + }, + "C": { + "supers": [ + "I__0" + ], + "properties": [ + { + "name": "next__12", + "abstract": true, + "getter": "get.next__13", + "setter": "set.next__16", + "visibility": "public" + }, + { + "name": "i__9", + "abstract": false, + "visibility": "private" + } + ], + "methods": [ + { + "name": "get.next__13", + "symbol": "next", + "open": false, + "visibility": "public", + "kind": "Getter" + }, + { + "name": "set.next__16", + "symbol": "next", + "open": false, + "visibility": "private", + "kind": "Setter" + }, + { + "name": "f__10", + "open": false, + "visibility": "public" + }, + { + "name": "constructor__19", + "open": false, + "visibility": "public", + "kind": "Constructor" + } + ] + }, + "I": { + "abstract": true, + "supers": [ + "AnyValue__0" + ], + "properties": [ + { + "name": "next__7", + "abstract": true, + "visibility": "public" + } + ] + }, + "Void": { + "supers": [] + }, + "Console": "__DO_NOT_CARE__" +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/dot-operation-desugaring/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/dot-operation-desugaring/expect/define.temper new file mode 100644 index 00000000..f9a4d1b4 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/dot-operation-desugaring/expect/define.temper @@ -0,0 +1,75 @@ +let console#0; +console#0 = doPure(@stay fn: Console { + getConsole() +}); +I__0 extends AnyValue; +@property(\next) @stay @fromType(I__0) let next__7; +@typeDecl(I__0) @stay let I__0; +I__0 = type (I__0); +@typeDecl(C__1) @stay let C__1; +C__1 = type (C__1); +interface(\word, \I, \concrete, false, @typeDefined(I__0) fn { + do {}; + do {} +}); +C__1 extends I__0; +@constructorProperty @property(\i) @visibility(\private) @stay @fromType(C__1) let i__9; +@method(\f) @visibility(\public) @fn @stay @fromType(C__1) let f__10; +f__10 = fn f(@impliedThis(C__1) this__2: C__1) { + fn__11: do { + getp(i__9, this__2) + } +}; +@property(\next) @visibility(\public) @stay @fromType(C__1) let next__12; +@method(\next) @getter @visibility(\public) @fn @stay @fromType(C__1) let nym`get.next__13`; +nym`get.next__13` = fn nym`get.next`(@impliedThis(C__1) this__3: C__1) /* return__14 */{ + fn__15: do { + do { + return__14 = do_icall_f(type (C__1), this__3) + 1; + break(\label, fn__15) + } + } +}; +@method(\next) @setter @visibility(\private) @fn @stay @fromType(C__1) let nym`set.next__16`; +nym`set.next__16` = fn nym`set.next`(@impliedThis(C__1) this__4: C__1, newVal__17 /* aka newVal */) /* return__1 */: Void { + fn__18: do { + do { + let t#0; + setp(i__9, this__4, t#0 = newVal__17 - 1); + t#0 + } + } +}; +@fn @method(\constructor) @visibility(\public) @stay @fromType(C__1) let constructor__19; +constructor__19 = fn constructor(@impliedThis(C__1) this__20: C__1, @optional(true) i__1 /* aka i */) /* return__2 */: Void { + let i__21 /* aka i */; + i__21 = if(isNull(i__1), fn { + 0 + }, \else, fn (f#0) { + f#0(fn { + i__1 + }) + }); + void; + do { + let t#1; + setp(i__9, this__20, t#1 = i__21); + t#1 + }; +}; +class(\word, \C, \concrete, true, @typeDefined(C__1) fn { + do {}; + do {}; + do {}; + do {}; + do {}; + do {}; + do {} +}); +let c__22; +c__22 = new C__1(); +do_call_log(console#0, do_get_i(c__22), do_get_x(c__22), do_get_x(c__22), do_call_f(c__22)); +do { + do_set_next(c__22, 42); + 42 +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/dot-operation-desugaring/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/dot-operation-desugaring/work/test/test.temper new file mode 100644 index 00000000..c57d45fe --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/dot-operation-desugaring/work/test/test.temper @@ -0,0 +1,13 @@ + + interface I { + next; + } + class C(private i = 0) extends I { + public f() { i } + public get next() { return f() + 1 } + private set next(newVal) { this.i = newVal - 1 } + } + let c = new C(); + console.log(c.i, c.x, c.x, c.f()); + c.next = 42 + diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/escape-sequence-grouping/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/escape-sequence-grouping/expect/define.temper new file mode 100644 index 00000000..3ee9523d --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/escape-sequence-grouping/expect/define.temper @@ -0,0 +1,12 @@ +@stay @imported(\(`test//html/`.html)) let html__0; +html__0 = type (HtmlBuilder); +do { + let accumulator#0; + accumulator#0 = new HtmlBuilder(); + do { + do_call_appendSafe(accumulator#0, raw "") + }; + do_get_accumulated(accumulator#0) +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/escape-sequence-grouping/work/test/html/html.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/escape-sequence-grouping/work/test/html/html.temper new file mode 100644 index 00000000..5bbe6b61 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/escape-sequence-grouping/work/test/html/html.temper @@ -0,0 +1,2 @@ +export class HtmlBuilder {} +export let html = HtmlBuilder; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/escape-sequence-grouping/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/escape-sequence-grouping/work/test/test.temper new file mode 100644 index 00000000..13af0dd3 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/escape-sequence-grouping/work/test/test.temper @@ -0,0 +1,2 @@ +let { html } = import ("./html"); +html"" diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/exported-name-propagates/expect/define.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/exported-name-propagates/expect/define.lispy new file mode 100644 index 00000000..841987e3 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/exported-name-propagates/expect/define.lispy @@ -0,0 +1,101 @@ +[ + "Block", + [ + [ + "Decl", + [ + [ + "LeftName", + "t__2" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.t\u0022: String" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "nym`=`: Function" + ], + [ + "LeftName", + "t__2" + ], + [ + "Value", + "AnyValue: Type" + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "x__3" + ], + [ + "Value", + "\\type: Symbol" + ], + [ + "Value", + "AnyValue: Type" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.x\u0022: String" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "nym`=`: Function" + ], + [ + "LeftName", + "x__3" + ], + [ + "Value", + "42: Int32" + ] + ] + ], + [ + "Value", + "void: Void" + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/exported-name-propagates/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/exported-name-propagates/expect/define.temper new file mode 100644 index 00000000..c34376ac --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/exported-name-propagates/expect/define.temper @@ -0,0 +1,4 @@ +let t__2; +t__2 = type (AnyValue); +let x__3: AnyValue; +x__3 = 42; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/exported-name-propagates/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/exported-name-propagates/work/test/test.temper new file mode 100644 index 00000000..2d4148a2 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/exported-name-propagates/work/test/test.temper @@ -0,0 +1,2 @@ +let t = AnyValue; +let x: t = 42; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/fully-qualified-names-allocated/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/fully-qualified-names-allocated/expect/define.temper new file mode 100644 index 00000000..abd8a5c0 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/fully-qualified-names-allocated/expect/define.temper @@ -0,0 +1,67 @@ +@fn @QName("test-code.f()") let f__0; +@typeDecl(I__0) @stay @QName("test-code.type I") let I__0; +I__0 = type (I__0); +@QName("test-code.x#0") let x__0; +x__0 = 1; +@QName("test-code.x#1") let x__1; +x__1 = 2; +@QName("test-code.e") let `test//`.e; +`test//`.e = 2; +@typeFormal(\F) @typeDecl(F__0) @QName("test-code.f().") let F__0; +F__0 = type (F__0); +f__0 = (@QName("test-code.f()") fn f(@QName("test-code.f().(x)") x__2 /* aka x */: Int32, @QName("test-code.f().(y)") y__0 /* aka y */: F__0) /* return__0 */: Int32 { + fn__0: do { + @fn @QName("test-code.f().helper()") let helper__0, @QName("test-code.f().local=") local__0; + local__0 = x__2; + helper__0 = (@QName("test-code.f().helper()") fn helper(@QName("test-code.f().helper().(z)") z__0 /* aka z */: Int32) /* return__1 */: Int32 { + fn__1: do { + local__0 + z__0 + } + }); + helper__0(1) + } +}); +@typeFormal(\T) @memberTypeFormal(\T) @typeDefined(T__0) @QName("test-code.type I.") @fromType(I__0) let T__0; +T__0 = type (T__0); +I__0 extends AnyValue; +@property(\x) @visibility(\public) @QName("test-code.type I.x") @stay @fromType(I__0) let x__3: T__0; +@property(\y) @visibility(\public) @QName("test-code.type I.y") @stay @fromType(I__0) let y__1; +@method(\y) @getter @visibility(\public) @fn @QName("test-code.type I.get y()") @stay @fromType(I__0) let nym`get.y__0`; +nym`get.y__0` = (@QName("test-code.type I.get y()") fn nym`get.y`(@impliedThis(I__0) @QName("test-code.type I.get y().(this)") this__0: I__0) /* return__2 */: Int32 { + fn__2: do { + pureVirtual() + } +}); +@method(\y) @setter @visibility(\public) @fn @QName("test-code.type I.set y()") @stay @fromType(I__0) let nym`set.y__0`; +nym`set.y__0` = (@QName("test-code.type I.set y()") fn nym`set.y`(@impliedThis(I__0) @QName("test-code.type I.set y().(this)") this__1: I__0, @QName("test-code.type I.set y().(newY)") newY__0 /* aka newY */: Int32) /* return__3 */: Void { + fn__3: do { + pureVirtual() + } +}); +@method(\method) @visibility(\public) @fn @QName("test-code.type I.method()") @stay @fromType(I__0) let method__0; +method__0 = (@QName("test-code.type I.method()") fn method(@impliedThis(I__0) @QName("test-code.type I.method().(this)") this__2: I__0) /* return__4 */: Void { + fn__4: do { + pureVirtual() + } +}); +@staticProperty(\staticMethod) @fn @static @visibility(\public) @QName("test-code.type I.staticMethod()") @stay @fromType(I__0) let staticMethod__0; +@typeFormal(\T) @typeDecl(T__1) @QName("test-code.type I.staticMethod().") let T__1; +T__1 = type (T__1); +staticMethod__0 = (@QName("test-code.type I.staticMethod()") @stay fn staticMethod(@QName("test-code.type I.staticMethod().(i)") i__0 /* aka i */: I__0) /* return__5 */: Void { + fn__5: do {} +}); +void; +interface(\word, \I, \concrete, false, @typeDefined(I__0) fn { + do {}; + do {}; + do {}; + do {}; + do {}; + do {}; + do {}; + do {}; + do {}; + do {}; + do {} +}); +type (I__0) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/fully-qualified-names-allocated/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/fully-qualified-names-allocated/work/test/test.temper new file mode 100644 index 00000000..70ac6d61 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/fully-qualified-names-allocated/work/test/test.temper @@ -0,0 +1,16 @@ +let x = 1; +let x = 2; +export let e = x; +let f(x: Int, y: F): Int { + let local = x; + let helper(z: Int): Int { local + z } + helper(1) +} +interface I { + public x: T; + public get y(): Int; + public set y(newY: Int): Void; + public method(): Void; + public static staticMethod(i: I): Void { } +} + diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/function-types-inline/expect/define.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/function-types-inline/expect/define.lispy new file mode 100644 index 00000000..a0ffa1ac --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/function-types-inline/expect/define.lispy @@ -0,0 +1,127 @@ +[ + "Block", + [ + [ + "Decl", + [ + [ + "LeftName", + "f__0" + ], + [ + "Value", + "\\type: Symbol" + ], + [ + "Block", + [ + [ + "Decl", + [ + [ + "LeftName", + "T__0" + ], + [ + "Value", + "\\typeFormal: Symbol" + ], + [ + "Value", + "\\T: Symbol" + ], + [ + "Value", + "\\typeDecl: Symbol" + ], + [ + "Value", + "T__0: Type" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.f.\u003cT\u003e\u0022: String" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "nym`=`: Function" + ], + [ + "LeftName", + "T__0" + ], + [ + "Value", + "T__0: Type" + ] + ] + ], + [ + "Value", + "Fn__0\u003cList\u003cT__0\u003e, List\u003cT__0\u003e\u003e: Type" + ] + ] + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.f\u0022: String" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "nym`=`: Function" + ], + [ + "LeftName", + "f__0" + ], + [ + "Call", + [ + [ + "RightName", + "never" + ] + ] + ] + ] + ], + [ + "Value", + "void: Void" + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/function-types-inline/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/function-types-inline/expect/define.temper new file mode 100644 index 00000000..6b415381 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/function-types-inline/expect/define.temper @@ -0,0 +1,6 @@ +let f__0: do { + @typeFormal(\T) @typeDecl(T__0) let T__0; + T__0 = type (T__0); + type (fn(List): List) +}; +f__0 = never(); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/function-types-inline/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/function-types-inline/expect/type.temper new file mode 100644 index 00000000..8c14ac7a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/function-types-inline/expect/type.temper @@ -0,0 +1,4 @@ +@typeFormal(\T) @typeDecl(T__0) let T__0; +T__0 = type (T__0); +let f__0: (fn(List): List); +f__0 = never(); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/function-types-inline/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/function-types-inline/work/test/test.temper new file mode 100644 index 00000000..ff7a0741 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/function-types-inline/work/test/test.temper @@ -0,0 +1 @@ +let f: fn(List): List = never(); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/functional-interface-abbreviated-syntax/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/functional-interface-abbreviated-syntax/expect/define.temper new file mode 100644 index 00000000..2b0eb67e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/functional-interface-abbreviated-syntax/expect/define.temper @@ -0,0 +1,15 @@ + @typeDecl(MyFunction) @stay @functionalInterface let `test//`.MyFunction; + `test//`.MyFunction = type (MyFunction); + do {}; + MyFunction extends AnyValue; + @fn @stay @fromType(MyFunction) let apply__0; +## No `this` parameter on functional interface apply methods. + apply__0 = fn apply(x__0 /* aka x */: Int32) /* return__0 */: Boolean { + fn__0: do { + pureVirtual() + } + }; + interface(\word, \MyFunction, void, void, void, \concrete, false, @typeDefined(MyFunction) fn { + do {}; + do {} + }); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/functional-interface-abbreviated-syntax/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/functional-interface-abbreviated-syntax/work/test/test.temper new file mode 100644 index 00000000..5531fe78 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/functional-interface-abbreviated-syntax/work/test/test.temper @@ -0,0 +1 @@ +export @fun interface MyFunction(x: Int): Boolean; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/functional-interface-generic/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/functional-interface-generic/expect/define.temper new file mode 100644 index 00000000..b87f1a5f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/functional-interface-generic/expect/define.temper @@ -0,0 +1,20 @@ +@typeDecl(MyFunction) @stay @functionalInterface let `test//`.MyFunction; +`test//`.MyFunction = type (MyFunction); +do {}; +@typeFormal(\T) @typeDefined(T__0) @fromType(MyFunction) let T__0; +T__0 = type (T__0); +@typeFormal(\U) @typeDefined(U__0) @fromType(MyFunction) let U__0; +U__0 = type (U__0); +MyFunction extends AnyValue; +@fn @stay @fromType(MyFunction) let apply__0; +apply__0 = fn apply(x__0 /* aka x */: T__0, y__0 /* aka y */: U__0) /* return__0 */: Boolean { + fn__0: do { + pureVirtual() + } +}; +interface(\word, \MyFunction, void, void, void, void, \concrete, false, @typeDefined(MyFunction) fn { + do {}; + do {}; + do {}; + do {} +}); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/functional-interface-generic/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/functional-interface-generic/work/test/test.temper new file mode 100644 index 00000000..673808bb --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/functional-interface-generic/work/test/test.temper @@ -0,0 +1 @@ +export @fun interface MyFunction(x: T, y: U): Boolean; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/good-tests/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/good-tests/expect/define.temper new file mode 100644 index 00000000..9e6c50ef --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/good-tests/expect/define.temper @@ -0,0 +1,20 @@ +@stay @imported(\(`std//testing/`.Test)) let Test__0; +Test__0 = type (Test); +@fn @test("- does / this : work?") let doesThisWork__0; +doesThisWork__0 = fn doesThisWork(test#0: Test) /* return__0 */: (Void | Bubble) { + do_call_assert(test#0, true, @stay fn { + "or what?" + }) +}; +@fn @test("does\tthis\nwork") let doesThisWork__1; +doesThisWork__1 = fn doesThisWork(test__0 /* aka test */: Test) /* return__1 */: (Void | Bubble) { + do_call_assert(test__0, false, @stay fn { + "or that" + }) +}; +@fn @test("again") let again__0; +again__0 = fn again(t__0 /* aka t */: Test) /* return__2 */: (Void | Bubble) { + do_call_assert(t__0, true, @stay fn { + "whatever" + }) +}; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/good-tests/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/good-tests/work/test/test.temper new file mode 100644 index 00000000..e90c81b3 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/good-tests/work/test/test.temper @@ -0,0 +1,3 @@ +test("- does / this : work?") { assert(true) { "or what?" } } +test("does\tthis\nwork") { test => assert(false) { "or that" } } +test("again") { t => assert(true) { "whatever" } } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/implied-getters-and-setters/expect/define-types.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/implied-getters-and-setters/expect/define-types.json new file mode 100644 index 00000000..3eb6be3e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/implied-getters-and-setters/expect/define-types.json @@ -0,0 +1,56 @@ +{ + "C": { + "properties": [ + { + "name": "j__2", + "visibility": "public", + "abstract": false, + "getter": "getj__8", + "setter": "setj__11", + "metadata": { + "var": [ + "void: Void" + ] + } + }, + { + "name": "k__3", + "abstract": false, + "visibility": "public", + "getter": "getk__12" + } + ], + "methods": [ + { + "name": "getj__8", + "symbol": "j", + "visibility": "public", + "kind": "Getter", + "open": false + }, + { + "name": "setj__11", + "symbol": "j", + "visibility": "public", + "kind": "Setter", + "open": false + }, + { + "name": "getk__12", + "symbol": "k", + "visibility": "public", + "kind": "Getter", + "open": false + }, + { + "name": "constructor__4", + "visibility": "public", + "kind": "Constructor", + "open": false + } + ] + }, + "Void": { + "supers": [] + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/implied-getters-and-setters/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/implied-getters-and-setters/expect/define.temper new file mode 100644 index 00000000..999138f0 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/implied-getters-and-setters/expect/define.temper @@ -0,0 +1,41 @@ +C__0 extends I; +@constructorProperty @property(\j) @visibility(\public) @stay @fromType(C__0) var j__2; +@constructorProperty @property(\k) @visibility(\public) @stay @fromType(C__0) let k__3; +@fn @method(\constructor) @visibility(\public) @stay @fromType(C__0) let constructor__4; +constructor__4 = fn constructor(@impliedThis(C__0) this__5: C__0, j__6 /* aka j */, k__7 /* aka k */) /* return__0 */: Void { + do { + let t#0; + setp(j__2, this__5, t#0 = j__6); + t#0 + }; + do { + let t#1; + setp(k__3, this__5, t#1 = k__7); + t#1 + }; +}; +@getter @method(\j) @fn @visibility(\public) @stay @fromType(C__0) let getj__8; +getj__8 = fn (@impliedThis(C__0) this__9: C__0) /* return__10 */{ + return__10 = getp(j__2, this__9) +}; +@setter @method(\j) @fn @visibility(\public) @stay @fromType(C__0) let setj__11; +setj__11 = fn (@impliedThis(C__0) this__12: C__0, newJ__13) /* return__14 */: Void { + setp(j__2, this__12, newJ__13); + return__14 = void +}; +@getter @method(\k) @fn @visibility(\public) @stay @fromType(C__0) let getk__12; +getk__12 = fn (@impliedThis(C__0) this__13: C__0) /* return__15 */{ + return__15 = getp(k__3, this__13) +}; +@typeDecl(C__0) @stay let C__0; +C__0 = type (C__0); +class(\word, \C, \concrete, true, @typeDefined(C__0) fn { + do {}; + do {}; + do {}; + do {}; + do {}; + do {}; + do {} +}); +type (C__0) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/implied-getters-and-setters/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/implied-getters-and-setters/work/test/test.temper new file mode 100644 index 00000000..a538c0c0 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/implied-getters-and-setters/work/test/test.temper @@ -0,0 +1 @@ +class C(public var j, public k) extends I {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/inherited-reassignability/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/inherited-reassignability/expect/define.temper new file mode 100644 index 00000000..a2132f0b --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/inherited-reassignability/expect/define.temper @@ -0,0 +1,47 @@ +I__0 extends AnyValue; +@property(\m) @stay @fromType(I__0) var m__7; +@property(\p) @stay @fromType(I__0) let p__8; +@typeDecl(I__0) @stay let I__0; +I__0 = type (I__0); +@typeDecl(J__1) @stay let J__1; +J__1 = type (J__1); +@typeDecl(K__2) @stay let K__2; +K__2 = type (K__2); +interface(\word, \I, \concrete, false, @typeDefined(I__0) fn { + do {}; + do {}; + do {} +}); +J__1 extends AnyValue; +@property(\n) @visibility(\public) @stay @fromType(J__1) let n__10; +@method(\n) @setter @fn @stay @fromType(J__1) let nym`set.n__11`; +nym`set.n__11` = (@stay fn nym`set.n`(@impliedThis(J__1) this__3: J__1) /* return__0 */: Void { + fn__12: do {} +}); +interface(\word, \J, \concrete, false, @typeDefined(J__1) fn { + do {}; + do {}; + do {} +}); +K__2 extends I__0; +K__2 extends J__1; +@property(\m) @stay @fromType(K__2) var m__14; +@property(\n) @stay @fromType(K__2) var n__15; +@property(\o) @stay @fromType(K__2) var o__16; +@property(\p) @stay @fromType(K__2) let p__17; +@property(\q) @stay @fromType(K__2) let q__18; +@method(\o) @setter @fn @stay @fromType(K__2) let nym`set.o__19`; +nym`set.o__19` = (@stay fn nym`set.o`(@impliedThis(K__2) this__4: K__2) /* return__1 */: Void { + fn__20: do {} +}); +interface(\word, \K, \concrete, false, @typeDefined(K__2) fn { + do {}; + do {}; + do {}; + do {}; + do {}; + do {}; + do {}; + do {} +}); +type (K__2) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/inherited-reassignability/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/inherited-reassignability/work/test/test.temper new file mode 100644 index 00000000..29f0c820 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/inherited-reassignability/work/test/test.temper @@ -0,0 +1,12 @@ +interface I { + var m; + p; +} +interface J { + set n() {} +} +interface K extends I, J { + m; n; o; + p; q; + set o() {} +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/instantiate-test-harnesses/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/instantiate-test-harnesses/expect/define.temper new file mode 100644 index 00000000..2f9cbfc5 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/instantiate-test-harnesses/expect/define.temper @@ -0,0 +1,12 @@ +@stay @imported(\(`std//testing/`.runTestCases)) @connected let runTestCases__0; +runTestCases__0 = `std//testing/`.runTestCases; +@implicit @imported(\(`std//testing/`.Test)) let Test__0; +Test__0 = type (Test); +@implicit @imported(\(`std//testing/`.runTestCases)) @fn let runTestCases__1; +runTestCases__1 = (fn runTestCases); +@stay @imported(\(`std//testing/`.Test)) let Test__1; +Test__1 = type (Test); +@fn @test("- a test case -") let aTestCase__0; +aTestCase__0 = (@stay fn aTestCase(test#0: Test) /* return__0 */: (Void | Bubble) {}); +@stay let `test//`.temper__testReport; +`test//`.temper__testReport = runTestCases__0(list(new Pair("- a test case -", aTestCase__0))); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/instantiate-test-harnesses/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/instantiate-test-harnesses/work/test/test.temper new file mode 100644 index 00000000..c1376f17 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/instantiate-test-harnesses/work/test/test.temper @@ -0,0 +1,3 @@ +test("- a test case -") { + // do something +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/internal-versus-external-backed-property-access/expect/define-types.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/internal-versus-external-backed-property-access/expect/define-types.json new file mode 100644 index 00000000..5c44e79c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/internal-versus-external-backed-property-access/expect/define-types.json @@ -0,0 +1,33 @@ +{ + "AnyValue": { + "abstract": true + }, + "C": { + "supers": [ + "AnyValue__0" + ], + "properties": [ + { + "name": "i__4", + "abstract": false, + "visibility": "private" + } + ], + "methods": [ + { + "name": "f__5", + "open": false, + "visibility": "private" + }, + { + "name": "constructor__7", + "open": false, + "visibility": "public", + "kind": "Constructor" + } + ] + }, + "Void": { + "supers": [] + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/internal-versus-external-backed-property-access/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/internal-versus-external-backed-property-access/expect/define.temper new file mode 100644 index 00000000..9e193d49 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/internal-versus-external-backed-property-access/expect/define.temper @@ -0,0 +1,31 @@ +C__0 extends AnyValue; +@constructorProperty @property(\i) @visibility(\private) @stay @fromType(C__0) let i__4; +@method(\f) @visibility(\private) @fn @stay @fromType(C__0) let f__5; +f__5 = fn f(@impliedThis(C__0) this__1: C__0) { + fn__6: do { + do { + setp(i__4, this__1, 1); + 1 + } + } +}; +@fn @method(\constructor) @visibility(\public) @stay @fromType(C__0) let constructor__7; +constructor__7 = fn constructor(@impliedThis(C__0) this__8: C__0, i__9 /* aka i */) /* return__0 */: Void { + do { + let t#0; + setp(i__4, this__8, t#0 = i__9); + t#0 + }; +}; +@typeDecl(C__0) @stay let C__0; +C__0 = type (C__0); +class(\word, \C, \concrete, true, @typeDefined(C__0) fn { + do {}; + do {}; + do {}; + do {} +}); +do { + do_set_i(new C__0(), 2); + 2 +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/internal-versus-external-backed-property-access/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/internal-versus-external-backed-property-access/work/test/test.temper new file mode 100644 index 00000000..6745128d --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/internal-versus-external-backed-property-access/work/test/test.temper @@ -0,0 +1,6 @@ + + class C(private i) { + private f() { i = 1 } + } + (new C()).i = 2 + diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/json-interop-mixed-in/expect/define-types.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/json-interop-mixed-in/expect/define-types.json new file mode 100644 index 00000000..7483c8ae --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/json-interop-mixed-in/expect/define-types.json @@ -0,0 +1,108 @@ +{ + "AnyValue": "__DO_NOT_CARE__", + "Int32": "__DO_NOT_CARE__", + "InterchangeContext": "__DO_NOT_CARE__", + "JsonAdapter": "__DO_NOT_CARE__", + "JsonNumeric": "__DO_NOT_CARE__", + "JsonObject": "__DO_NOT_CARE__", + "JsonProducer": "__DO_NOT_CARE__", + "JsonSyntaxTree": "__DO_NOT_CARE__", + "Point": { + "supers": [ + "AnyValue__0" + ], + "methods": [ + { + "name": "getx__0", + "symbol": "x", + "visibility": "public", + "kind": "Getter", + "open": false + }, + { + "name": "gety__0", + "symbol": "y", + "visibility": "public", + "kind": "Getter", + "open": false + }, + { + "name": "toString__0", + "visibility": "public", + "open": false + }, + { + "name": "constructor__1", + "visibility": "public", + "open": false, + "kind": "Constructor" + }, + { + "name": "encodeToJson__1", + "visibility": "public", + "open": false + } + ], + "properties": [ + { + "name": "x__0", + "visibility": "public", + "abstract": false, + "getter": "getx__0" + }, + { + "name": "y__0", + "visibility": "public", + "abstract": false, + "getter": "gety__0" + } + ], + "staticProperties": [ + { + "name": "decodeFromJson__1", + "visibility": "public" + }, + { + "name": "jsonAdapter__0", + "visibility": "public" + } + ], + "metadata": { + "json": [ + "void: Void" + ], + "QName": [ + "\u0022test-code.type Point\u0022: String" + ] + } + }, + "PointJsonAdapter": { + "supers": [ + [ + "Nominal", + "std//json/.JsonAdapter", + "Point__0" + ] + ], + "methods": [ + { + "name": "encodeToJson__0", + "visibility": "public", + "open": false + }, + { + "name": "decodeFromJson__0", + "visibility": "public", + "open": false + }, + { + "name": "constructor__0", + "visibility": "public", + "open": false, + "kind": "Constructor" + } + ] + }, + "String": "__DO_NOT_CARE__", + "Void": "__DO_NOT_CARE__" +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/json-interop-mixed-in/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/json-interop-mixed-in/expect/define.temper new file mode 100644 index 00000000..dfc4a677 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/json-interop-mixed-in/expect/define.temper @@ -0,0 +1,95 @@ +## Here are members for the generated JSON adapter class + PointJsonAdapter__0 extends JsonAdapter; + @visibility(\public) @fn @stay @fromType(PointJsonAdapter__0) let encodeToJson__0; + encodeToJson__0 = (@stay fn (@impliedThis(PointJsonAdapter__0) this__0: PointJsonAdapter__0, x__1: Point__0, p__0: JsonProducer) /* return__0 */: Void { + do_call_encodeToJson(x__1, p__0) + }); + @visibility(\public) @fn @stay @fromType(PointJsonAdapter__0) let decodeFromJson__0; + decodeFromJson__0 = fn (@impliedThis(PointJsonAdapter__0) this__1: PointJsonAdapter__0, t__0: JsonSyntaxTree, ic__0: InterchangeContext) /* return__1 */: (Point__0 | Bubble) { + getStatic(Point__0, \decodeFromJson)(t__0, ic__0) + }; +## It's got an implied constructor even though that wasn't mentioned in the JsonInteropPass + @fn @visibility(\public) @stay @fromType(PointJsonAdapter__0) let constructor__0; + constructor__0 = (@stay fn constructor(@impliedThis(PointJsonAdapter__0) this__2: PointJsonAdapter__0) /* return__2 */: Void {}); + @typeDecl(PointJsonAdapter__0) @stay let PointJsonAdapter__0; + PointJsonAdapter__0 = type (PointJsonAdapter__0); +## Here's the declaration for the non-generated point type + @typeDecl(Point__0) @stay @json let Point__0; + Point__0 = type (Point__0); + class (\word, \PointJsonAdapter, \concrete, true, @typeDefined(PointJsonAdapter__0) fn { + do {}; + do {}; + do {}; + do {} + }); + do {}; +## Here's the explicitly declared point class type variable + Point__0 extends AnyValue; + @constructorProperty @visibility(\public) @stay @fromType(Point__0) let x__0: Int32; + @constructorProperty @visibility(\public) @stay @fromType(Point__0) let y__0: Int32; + @visibility(\public) @fn @stay @fromType(Point__0) let toString__0; + toString__0 = fn toString(@impliedThis(Point__0) this__3: Point__0) /* return__3 */: String { + fn__0: do { + cat("(", str(getp(x__0, this__3)), ", ", str(getp(y__0, this__3)), ")") + } + }; + @fn @visibility(\public) @stay @fromType(Point__0) let constructor__1; + constructor__1 = fn constructor(@impliedThis(Point__0) this__4: Point__0, x__2 /* aka x */: Int32, y__1 /* aka y */: Int32) /* return__4 */: Void { + do { + let t#0; + setp(x__0, this__4, t#0 = x__2); + t#0 + }; + do { + let t#1; + setp(y__0, this__4, t#1 = y__1); + t#1 + }; + }; + @fn @visibility(\public) @stay @fromType(Point__0) let getx__0; + getx__0 = fn (@impliedThis(Point__0) this__5: Point__0) /* return__5 */: Int32 { + return__5 = getp(x__0, this__5) + }; + @fn @visibility(\public) @stay @fromType(Point__0) let gety__0; + gety__0 = fn (@impliedThis(Point__0) this__6: Point__0) /* return__6 */: Int32 { + return__6 = getp(y__0, this__6) + }; +## Here is the encodeToJson method added to point. + @visibility(\public) @fn @stay @fromType(Point__0) let encodeToJson__1; + encodeToJson__1 = fn (@impliedThis(Point__0) this__7: Point__0, p__1: JsonProducer) /* return__7 */: Void { + do_call_startObject(p__1); + do_call_objectKey(p__1, "x"); +## `this` in the generated expression `this.x` got rewritten to `this__7`, after +## the regular type processing pass adds that implied parameter. + do_call_int32Value(p__1, getp(x__0, this__7)); + do_call_objectKey(p__1, "y"); + do_call_int32Value(p__1, getp(y__0, this__7)); + do_call_endObject(p__1); + }; + @static @visibility(\public) @fn @stay @fromType(Point__0) let decodeFromJson__1; + decodeFromJson__1 = (@stay fn (t__1: JsonSyntaxTree, ic__1: InterchangeContext) /* return__8 */: (Point__0 | Bubble) { + let obj__0; + obj__0 = t__1 as JsonObject; + let x__3: Int32, y__2: Int32; + x__3 = do_call_asInt32(do_call_propertyValueOrBubble(obj__0, "x") as JsonNumeric); + y__2 = do_call_asInt32(do_call_propertyValueOrBubble(obj__0, "y") as JsonNumeric); + new Point__0(x__3, y__2) + }); + @static @visibility(\public) @fn @stay @fromType(Point__0) let jsonAdapter__0; + jsonAdapter__0 = (@stay fn /* return__9 */: (JsonAdapter) { + new PointJsonAdapter__0() + }); + class(\word, \Point, \concrete, true, @typeDefined(Point__0) fn { + do {}; + do {}; + do {}; + do {}; + do {}; + do {}; + do {}; + do {}; + do {}; + do {} + }); +## The terminal expression is not affected. + type (Point__0) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/json-interop-mixed-in/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/json-interop-mixed-in/work/test/test.temper new file mode 100644 index 00000000..e8336d6f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/json-interop-mixed-in/work/test/test.temper @@ -0,0 +1,6 @@ +@json class Point( + public let x: Int, + public let y: Int, +) { + public toString(): String { "(${x}, ${y})" } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/macros-in-escapers/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/macros-in-escapers/expect/define.temper new file mode 100644 index 00000000..87b8740d --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/macros-in-escapers/expect/define.temper @@ -0,0 +1 @@ +\(doNotCall(1 + 1, unhole(2))) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/missing-visibility-on-class-members/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/missing-visibility-on-class-members/expect/define.temper new file mode 100644 index 00000000..a09e49ff --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/missing-visibility-on-class-members/expect/define.temper @@ -0,0 +1,49 @@ +C__0 extends AnyValue; +@constructorProperty @stay @fromType(C__0) let p__0: Int32; +@stay @fromType(C__0) let q__0: Int32; +@visibility(\private) @stay @fromType(C__0) let r__0: Int32; +@fn @stay @fromType(C__0) let f__0; +f__0 = fn f(@impliedThis(C__0) this__0: C__0) /* return__0 */: Int32 { + fn__0: do { + getp(r__0, this__0) + } +}; +@fn @visibility(\public) @stay @fromType(C__0) let constructor__0; +constructor__0 = fn constructor(@impliedThis(C__0) this__1: C__0, p__1 /* aka p */: Int32) /* return__1 */: Void { + do { + let t#0; + setp(p__0, this__1, t#0 = p__1); + t#0 + }; + do { + let t#1; + setp(q__0, this__1, t#1 = p__1 + 1); + t#1 + }; + do { + let t#2; + setp(r__0, this__1, t#2 = p__1 - 1); + t#2 + }; +}; +@fn @visibility(\public) @stay @fromType(C__0) let getp__0; +getp__0 = fn (@impliedThis(C__0) this__2: C__0) /* return__2 */: Int32 { + return__2 = getp(p__0, this__2) +}; +@fn @visibility(\public) @stay @fromType(C__0) let getq__0; +getq__0 = fn (@impliedThis(C__0) this__3: C__0) /* return__3 */: Int32 { + return__3 = getp(q__0, this__3) +}; +@typeDecl(C__0) @stay let C__0; +C__0 = type (C__0); +class(\word, \C, \concrete, true, @typeDefined(C__0) fn { + do {}; + do {}; + do {}; + do {}; + do {}; + do {}; + do {}; + do {} +}); +type (C__0) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/missing-visibility-on-class-members/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/missing-visibility-on-class-members/expect/errors.json new file mode 100644 index 00000000..e089bedd --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/missing-visibility-on-class-members/expect/errors.json @@ -0,0 +1,3 @@ +[ + "Members of class C__0 require explicit visibility: [.p, .q, .f(...)]!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/missing-visibility-on-class-members/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/missing-visibility-on-class-members/work/test/test.temper new file mode 100644 index 00000000..318de508 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/missing-visibility-on-class-members/work/test/test.temper @@ -0,0 +1,5 @@ +class C(p: Int) { + q: Int = p + 1; + private r: Int = p - 1; + f(): Int { r } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/nested-empty-type/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/nested-empty-type/expect/define.temper new file mode 100644 index 00000000..ab029e34 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/nested-empty-type/expect/define.temper @@ -0,0 +1,14 @@ +@fn let functionThatNestsAType__0; +EmptyHelper__0 extends AnyValue; +@typePlaceholder(EmptyHelper__0) let typePlaceholder#0: Empty; +typePlaceholder#0 = {class: Empty__0}; +functionThatNestsAType__0 = fn functionThatNestsAType /* return__0 */: Void { + fn__0: do { + @typeDecl(EmptyHelper__0) @stay let EmptyHelper__0; + EmptyHelper__0 = type (EmptyHelper__0); + interface(\word, \EmptyHelper, \concrete, false, @typeDefined(EmptyHelper__0) fn { + do {} + }); + type (EmptyHelper__0) + } +}; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/nested-empty-type/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/nested-empty-type/work/test/test.temper new file mode 100644 index 00000000..69895ced --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/nested-empty-type/work/test/test.temper @@ -0,0 +1,4 @@ +let functionThatNestsAType(): Void { + interface EmptyHelper {} // <-- needs a placeholder at the top level + // See the comments in TmpLControlFlow and ClosureConvertClasses +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/non-const-referent-not-folded-into-const-expression/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/non-const-referent-not-folded-into-const-expression/expect/define.temper new file mode 100644 index 00000000..7d10e8ac --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/non-const-referent-not-folded-into-const-expression/expect/define.temper @@ -0,0 +1,6 @@ +var one__0; +one__0 = 1; +if(falseOpaquePredicate, fn { + one__0 = 0; +}); +one__0 + one__0 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/non-const-referent-not-folded-into-const-expression/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/non-const-referent-not-folded-into-const-expression/expect/syntaxMacro.temper new file mode 100644 index 00000000..11a2870e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/non-const-referent-not-folded-into-const-expression/expect/syntaxMacro.temper @@ -0,0 +1,5 @@ +var one__0 = 1; +if(falseOpaquePredicate, fn { + one__0 = 0; +}); +one__0 + one__0 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/non-const-referent-not-folded-into-const-expression/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/non-const-referent-not-folded-into-const-expression/work/test/test.temper new file mode 100644 index 00000000..b1abd37b --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/non-const-referent-not-folded-into-const-expression/work/test/test.temper @@ -0,0 +1,5 @@ +var one = 1; +if (falseOpaquePredicate) { + one = 0; +} +one + one diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/nullable-types-resolved/expect/define.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/nullable-types-resolved/expect/define.lispy new file mode 100644 index 00000000..a881243e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/nullable-types-resolved/expect/define.lispy @@ -0,0 +1,42 @@ +[ + "Block", + [ + [ + "Decl", + [ + [ + "LeftName", + "intOrNull__0" + ], + [ + "Value", + "\\type: Symbol" + ], + [ + "Value", + "Int32?: Type" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.intOrNull\u0022: String" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ] + ] + ], + [ + "Value", + "void: Void" + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/nullable-types-resolved/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/nullable-types-resolved/expect/define.temper new file mode 100644 index 00000000..6312b54a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/nullable-types-resolved/expect/define.temper @@ -0,0 +1 @@ +let intOrNull__0: Int32?; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/nullable-types-resolved/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/nullable-types-resolved/work/test/test.temper new file mode 100644 index 00000000..a4eee0d0 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/nullable-types-resolved/work/test/test.temper @@ -0,0 +1 @@ +let intOrNull: Int?; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/operator-decorator-arity-inference/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/operator-decorator-arity-inference/expect/define.temper new file mode 100644 index 00000000..11f70dc9 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/operator-decorator-arity-inference/expect/define.temper @@ -0,0 +1,39 @@ +## mixedAdd has arity 2 so gets an infix operator specifier + @fn @operator("_+_") let mixedAdd__0; + @typeDecl(C__0) @stay let C__0; + C__0 = type (C__0); + mixedAdd__0 = fn mixedAdd(a__0 /* aka a */: Int32, b__0 /* aka b */: Boolean) /* return__0 */: Int32 { + fn__0: do { + if(b__0, fn { + a__0 + 1 + }, \else, fn (f#0) { + f#0(fn { + a__0 + }) + }) + } + }; + C__0 extends AnyValue; +## The instance method has an implied `this` so also gets an infix operator specifier + @visibility(\public) @fn @operator("_+_") @stay @fromType(C__0) let f__0; + f__0 = fn f(@impliedThis(C__0) this__0: C__0, other__0 /* aka other */: C__0) /* return__1 */: C__0 { + fn__1: do { + this__0 + } + }; +## The static method has no implied `this` so gets a prefix operator specifier + @fn @static @visibility(\public) @operator("+_") @stay @fromType(C__0) let unary__0; + unary__0 = (@stay fn unary(c__0 /* aka c */: C__0) /* return__2 */: C__0 { + fn__2: do { + c__0 + } + }); + @fn @visibility(\public) @stay @fromType(C__0) let constructor__0; + constructor__0 = (@stay fn constructor(@impliedThis(C__0) this__1: C__0) /* return__3 */: Void {}); + class(\word, \C, \concrete, true, @typeDefined(C__0) fn { + do {}; + do {}; + do {}; + do {} + }); + type (C__0) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/operator-decorator-arity-inference/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/operator-decorator-arity-inference/work/test/test.temper new file mode 100644 index 00000000..c2225882 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/operator-decorator-arity-inference/work/test/test.temper @@ -0,0 +1,12 @@ +@operator("+") +let mixedAdd(a: Int, b: Boolean): Int { + if (b) { a + 1 } else { a } +} + +class C { + @operator("+") + public f(other: C): C { this } + + @operator("+") + public static unary(c: C): C { c } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/optional-parameters-not-inlined/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/optional-parameters-not-inlined/expect/define.temper new file mode 100644 index 00000000..d87e8af9 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/optional-parameters-not-inlined/expect/define.temper @@ -0,0 +1,21 @@ +let console#0; +console#0 = doPure(@stay fn: Console { + getConsole() +}); +@fn let f__0; +f__0 = (@stay fn f(@optional(true) i__0 /* aka i */: Int32?) /* return__0 */: Int32 { + fn__0: do { + let i__1 /* aka i */: Int32; + i__1 = if(isNull(i__0), fn { + 42 + }, \else, fn (f#0) { + f#0(fn { + i__0 + }) + }); + void; + i__1 + } +}); +do_call_log(console#0, cat("f( )=", str(do_call_toString(42)))); +do_call_log(console#0, cat("f(1)=", str(do_call_toString(1)))); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/optional-parameters-not-inlined/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/optional-parameters-not-inlined/expect/run-result.json new file mode 100644 index 00000000..cc7a3b30 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/optional-parameters-not-inlined/expect/run-result.json @@ -0,0 +1 @@ +"void: Void" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/optional-parameters-not-inlined/expect/stdout.txt b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/optional-parameters-not-inlined/expect/stdout.txt new file mode 100644 index 00000000..37a895e4 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/optional-parameters-not-inlined/expect/stdout.txt @@ -0,0 +1,2 @@ +f( )=42 +f(1)=1 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/optional-parameters-not-inlined/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/optional-parameters-not-inlined/work/test/test.temper new file mode 100644 index 00000000..e0b16964 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/optional-parameters-not-inlined/work/test/test.temper @@ -0,0 +1,3 @@ +let f(i: Int = 42): Int { i }; +console.log("f( )=${f().toString()}"); +console.log("f(1)=${f(1).toString()}"); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/parameterized-constructor-reference/expect/define.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/parameterized-constructor-reference/expect/define.lispy new file mode 100644 index 00000000..004d7843 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/parameterized-constructor-reference/expect/define.lispy @@ -0,0 +1,598 @@ +[ + "Block", + [ + [ + "Decl", + [ + [ + "LeftName", + "C__0" + ], + [ + "Value", + "\\typeDecl: Symbol" + ], + [ + "Value", + "C__0\u003cT__0\u003e: Type" + ], + [ + "Value", + "\\stay: Symbol" + ], + [ + "Stay", + "kotlin.Unit" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.type C\u0022: String" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "nym`=`: Function" + ], + [ + "LeftName", + "C__0" + ], + [ + "Value", + "C__0: Type" + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "f__0" + ], + [ + "Value", + "\\fn: Symbol" + ], + [ + "Value", + "void: Void" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.f()\u0022: String" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "T__0" + ], + [ + "Value", + "\\typeFormal: Symbol" + ], + [ + "Value", + "\\T: Symbol" + ], + [ + "Value", + "\\memberTypeFormal: Symbol" + ], + [ + "Value", + "\\T: Symbol" + ], + [ + "Value", + "\\typeDefined: Symbol" + ], + [ + "Value", + "T__0: Type" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.type C.\u003cT\u003e\u0022: String" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ], + [ + "Value", + "\\fromType: Symbol" + ], + [ + "Value", + "C__0\u003cT__0\u003e: Type" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "nym`=`: Function" + ], + [ + "LeftName", + "T__0" + ], + [ + "Value", + "T__0: Type" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "extends: Function" + ], + [ + "Value", + "C__0\u003cT__0\u003e: Type" + ], + [ + "Value", + "AnyValue: Type" + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "constructor__0" + ], + [ + "Value", + "\\fn: Symbol" + ], + [ + "Value", + "void: Void" + ], + [ + "Value", + "\\method: Symbol" + ], + [ + "Value", + "\\constructor: Symbol" + ], + [ + "Value", + "\\visibility: Symbol" + ], + [ + "Value", + "\\public: Symbol" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.type C.constructor()\u0022: String" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ], + [ + "Value", + "\\stay: Symbol" + ], + [ + "Stay" + ], + [ + "Value", + "\\parameterNameSymbolsList: Symbol" + ], + [ + "Value", + "[null]: List" + ], + [ + "Value", + "\\fromType: Symbol" + ], + [ + "Value", + "C__0\u003cT__0\u003e: Type" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "nym`=`: Function" + ], + [ + "LeftName", + "constructor__0" + ], + [ + "Fun", + [ + [ + "Decl", + [ + [ + "LeftName", + "this__0" + ], + [ + "Value", + "\\type: Symbol" + ], + [ + "Value", + "C__0\u003cT__0\u003e: Type" + ], + [ + "Value", + "\\impliedThis: Symbol" + ], + [ + "Value", + "C__0\u003cT__0\u003e: Type" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.type C.constructor().(this)\u0022: String" + ] + ] + ], + [ + "Value", + "\\word: Symbol" + ], + [ + "Value", + "\\constructor: Symbol" + ], + [ + "Value", + "\\returnDecl: Symbol" + ], + [ + "Decl", + [ + [ + "LeftName", + "return__0" + ], + [ + "Value", + "\\type: Symbol" + ], + [ + "Value", + "Void: Type" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.type C.constructor().return=\u0022: String" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ] + ] + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.type C.constructor()\u0022: String" + ], + [ + "Value", + "\\stay: Symbol" + ], + [ + "Stay" + ], + [ + "Block", + [] + ] + ] + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "class: Function" + ], + [ + "Value", + "\\word: Symbol" + ], + [ + "Value", + "\\C: Symbol" + ], + [ + "Value", + "\\concrete: Symbol" + ], + [ + "Value", + "true: Boolean" + ], + [ + "Fun", + [ + [ + "Value", + "\\typeDefined: Symbol" + ], + [ + "Value", + "C__0\u003cT__0\u003e: Type" + ], + [ + "Block", + [ + [ + "Block", + [] + ], + [ + "Block", + [] + ], + [ + "Block", + [] + ] + ] + ] + ] + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "U__0" + ], + [ + "Value", + "\\typeFormal: Symbol" + ], + [ + "Value", + "\\U: Symbol" + ], + [ + "Value", + "\\typeDecl: Symbol" + ], + [ + "Value", + "U__0: Type" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.f().\u003cU\u003e\u0022: String" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "nym`=`: Function" + ], + [ + "LeftName", + "U__0" + ], + [ + "Value", + "U__0: Type" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "nym`=`: Function" + ], + [ + "LeftName", + "f__0" + ], + [ + "Fun", + [ + [ + "Value", + "\\returnDecl: Symbol" + ], + [ + "Decl", + [ + [ + "LeftName", + "return__1" + ], + [ + "Value", + "\\type: Symbol" + ], + [ + "Value", + "C__0\u003cU__0\u003e: Type" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.f().return=\u0022: String" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ] + ] + ], + [ + "Value", + "\\returnedFrom: Symbol" + ], + [ + "Value", + "true: Boolean" + ], + [ + "Value", + "\\word: Symbol" + ], + [ + "Value", + "\\f: Symbol" + ], + [ + "Value", + "\\typeFormal: Symbol" + ], + [ + "Value", + "U__0: Type" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.f()\u0022: String" + ], + [ + "Value", + "\\stay: Symbol" + ], + [ + "Stay" + ], + [ + "Block", + [ + [ + "Value", + "\\label: Symbol" + ], + [ + "LeftName", + "fn__0" + ] + ] + ] + ] + ] + ] + ], + [ + "Value", + "void: Void" + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/parameterized-constructor-reference/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/parameterized-constructor-reference/expect/define.temper new file mode 100644 index 00000000..8c033f0e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/parameterized-constructor-reference/expect/define.temper @@ -0,0 +1,18 @@ +@typeDecl(C__0) @stay let C__0; +C__0 = type (C__0); +@fn let f__0; +@typeFormal(\T) @memberTypeFormal(\T) @typeDefined(T__0) @fromType(C__0) let T__0; +T__0 = type (T__0); +C__0 extends AnyValue; +@fn @method(\constructor) @visibility(\public) @stay @fromType(C__0) let constructor__0; +constructor__0 = (@stay fn constructor(@impliedThis(C__0) this__0: C__0) /* return__0 */: Void {}); +class(\word, \C, \concrete, true, @typeDefined(C__0) fn { + do {}; + do {}; + do {} +}); +@typeFormal(\U) @typeDecl(U__0) let U__0; +U__0 = type (U__0); +f__0 = (@stay fn f /* return__1 */: (C__0) { + fn__0: do {} +}); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/parameterized-constructor-reference/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/parameterized-constructor-reference/work/test/test.temper new file mode 100644 index 00000000..0e3eb2d3 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/parameterized-constructor-reference/work/test/test.temper @@ -0,0 +1,2 @@ +class C {} +let f(): C {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/property-bags-desugar-to-positional-parameters/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/property-bags-desugar-to-positional-parameters/expect/define.temper new file mode 100644 index 00000000..d91fec17 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/property-bags-desugar-to-positional-parameters/expect/define.temper @@ -0,0 +1,14 @@ + @stay @imported(\(`test//point/`.Point)) let Point__0; + Point__0 = type (Point); + let `test//`.p; +## Here's a reworked property bag that we don't muck with, much. + `test//`.p = new Point(1, 2); + let `test//`.q; +## This one becomes a do-block because we need to preserve OoO. + `test//`.q = do { + let y#0; + y#0 = do_get_y(`test//`.p); + let x#0; + x#0 = do_get_x(`test//`.p); + new Point(x#0, y#0) + }; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/property-bags-desugar-to-positional-parameters/work/test/point/point.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/property-bags-desugar-to-positional-parameters/work/test/point/point.temper new file mode 100644 index 00000000..02ef9e82 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/property-bags-desugar-to-positional-parameters/work/test/point/point.temper @@ -0,0 +1 @@ +export class Point(public x: Int, public y: Int) {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/property-bags-desugar-to-positional-parameters/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/property-bags-desugar-to-positional-parameters/work/test/test.temper new file mode 100644 index 00000000..143d16ce --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/property-bags-desugar-to-positional-parameters/work/test/test.temper @@ -0,0 +1,4 @@ +let { Point } = import("./point"); +export let p = { x: 1, y: 2 }; +export let q = { y: p.y, x: p.x }; + diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/property-bags-desugaring-with-optional-parameters/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/property-bags-desugaring-with-optional-parameters/expect/define.temper new file mode 100644 index 00000000..32e3d6ef --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/property-bags-desugaring-with-optional-parameters/expect/define.temper @@ -0,0 +1,5 @@ + @stay @imported(\(`test//c/`.C)) let C__0; + C__0 = type (C); + let `test//`.c; +## Here's a reworked property bag that we don't muck with, much. + `test//`.c = new C(1, null, 2); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/property-bags-desugaring-with-optional-parameters/work/test/c/c.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/property-bags-desugaring-with-optional-parameters/work/test/c/c.temper new file mode 100644 index 00000000..174d228d --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/property-bags-desugaring-with-optional-parameters/work/test/c/c.temper @@ -0,0 +1 @@ +export class C(public x: Int, public y: Int = 0, public z: Int = 0) {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/property-bags-desugaring-with-optional-parameters/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/property-bags-desugaring-with-optional-parameters/work/test/test.temper new file mode 100644 index 00000000..8fa44764 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/property-bags-desugaring-with-optional-parameters/work/test/test.temper @@ -0,0 +1,3 @@ +let { C } = import("./c"); +export let c = { x: 1, z: 2 } + diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/property-only-interface/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/property-only-interface/expect/define.temper new file mode 100644 index 00000000..d0a6a4f2 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/property-only-interface/expect/define.temper @@ -0,0 +1,9 @@ +I__0 extends AnyValue; +@property(\p) @visibility(\public) @stay @fromType(I__0) let p__3; +@typeDecl(I__0) @stay let I__0; +I__0 = type (I__0); +interface(\word, \I, \concrete, false, @typeDefined(I__0) fn { + do {}; + do {} +}); +type (I__0) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/property-only-interface/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/property-only-interface/work/test/test.temper new file mode 100644 index 00000000..4e5ca85a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/property-only-interface/work/test/test.temper @@ -0,0 +1 @@ +interface I { public p; } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/regex-literal/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/regex-literal/expect/define.temper new file mode 100644 index 00000000..8d34604e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/regex-literal/expect/define.temper @@ -0,0 +1,44 @@ +## The regular expression expansions are applied in SyntaxMacroStage, +## but it's easier to see the formatting later. +## +## Here are the auto-imports + @stay @imported(\(`std//regex/`.Sequence)) let Sequence__0; + Sequence__0 = type (Sequence); + @imported(\(`std//regex/`.CodePoints)) let CodePoints__0; + CodePoints__0 = type (CodePoints); + @imported(\(`std//regex/`.Dot)) let Dot__0; + Dot__0 = `std//regex/`.Dot; + @imported(\(`std//regex/`.Repeat)) let Repeat__0; + Repeat__0 = type (Repeat); + @imported(\(`std//regex/`.End)) let End__0; + End__0 = `std//regex/`.End; + void; + void; + void; + void; + let r1__0; +## Types have been inlined into `new` operators + r1__0 = do_call_compiled(new Sequence(list(new CodePoints("a"), Dot__0, new Repeat(new CodePoints("b"), 0, null, false)))); + void; + let r2__0; + r2__0 = do_call_compiled(new Sequence(list(new CodePoints("a"), Dot__0, End__0, new CodePoints("{b"), new Repeat(new CodePoints("}"), 0, null, false)))); + void; + let r3__0; +## (/g) unrecognized in rgx(list("(?/g)a.b*"), list()); + r3__0 = error (UnrecognizedToken); + let b__0; + b__0 = r3__0; + void; + let r4__0; +## interpolation of b__0 not supported yet in r4 or r5 + r4__0 = error (UnrecognizedToken); + let r5__0; + r5__0 = error (UnrecognizedToken); + let r6__0; + r6__0 = do_call_compiled(new Sequence__0(list(new CodePoints__0("a"), new Repeat__0(new CodePoints__0("."), 0, null, false)))); + let r7__0; + r7__0 = do_call_compiled(new Sequence(list(new CodePoints("a"), Dot, new Repeat(new CodePoints("b"), 0, null)))); + let s__0; + s__0 = "[a]"; + let r8__0; + r8__0 = do_call_compiled(new Sequence__0(list(Dot__0, new CodePoints__0("[a]"), Dot__0))); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/regex-literal/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/regex-literal/expect/disAmbiguate.temper new file mode 100644 index 00000000..ce244cf5 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/regex-literal/expect/disAmbiguate.temper @@ -0,0 +1,18 @@ +## Below, r4 and r5 interpolate regex objects, but we don't support those yet. +## Thats two syntax errors. +## For r6, we do support interpolated string values already, so that one is ok. +## TODO Wrap stable string values in `new CodePoints` calls if we want to support runtime building. +## r7 uses Sequence instead of Sequence__0 since it was hand-coded and +## remains unaffected by the auto-import used above. + @stay @imported(\(`std//regex/`.Sequence)) let Sequence__0 = type (Sequence), @imported(\(`std//regex/`.CodePoints)) CodePoints__0 = type (CodePoints), @imported(\(`std//regex/`.Dot)) Dot__0 = `std//regex/`.Dot, @imported(\(`std//regex/`.Repeat)) Repeat__0 = type (Repeat), @imported(\(`std//regex/`.End)) End__0 = `std//regex/`.End; + REM("Some tests below:", true, true); + REM("Interpolated string value next to another interpolation. Also test a disappearing empty hole.", true, true); + REM("Simple interpolated string value since we can't evaluate regex objects at compile time yet.", true, true); + REM("Starting off with a simple regex", true, true); + let r1 = do_call_compiled(new Sequence(list(new CodePoints("a"), Dot__0, new Repeat(new CodePoints("b"), 0, null, false)))); + REM("b is not in scope here.", true, true); + let r2 = do_call_compiled(new Sequence(list(new CodePoints("a"), Dot__0, End__0, new CodePoints("{b"), new Repeat(new CodePoints("}"), 0, null, false)))); + REM("We don't actually support the following flag syntax at the moment.\nThat's one of the syntax error messages.", true, true); + let r3 = rgx(list("(?/g)a.b*"), list()), b = r3; + REM("And we have a brief interpolation representation from Grammar that's\neasyish to build. It gets changed later.", true, true); + let r4 = stringExpr(rgx, true, "a.", \interpolate, b, "*"), r5 = stringExpr(rgx, true, "a", \interpolate, ".", \interpolate, b, "*?"), r6 = stringExpr(rgx, true, "a", \interpolate, ".", "*"), r7 = new Sequence(list(new CodePoints("a"), Dot, new Repeat(new CodePoints("b"), 0, null))).compiled(), s = "[a]", r8 = stringExpr(rgx, true, ".", \interpolate, s, "."); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/regex-literal/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/regex-literal/expect/errors.json new file mode 100644 index 00000000..5be8edbc --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/regex-literal/expect/errors.json @@ -0,0 +1,5 @@ +[ + "Syntax error!", + "Syntax error!", + "Syntax error!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/regex-literal/expect/parse.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/regex-literal/expect/parse.temper new file mode 100644 index 00000000..c8657c29 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/regex-literal/expect/parse.temper @@ -0,0 +1,11 @@ +REM("Some tests below:", true, true); +REM("Interpolated string value next to another interpolation. Also test a disappearing empty hole.", true, true); +REM("Simple interpolated string value since we can't evaluate regex objects at compile time yet.", true, true); +REM("Starting off with a simple regex", true, true); +let r1 = rgx(list("a.b*"), list()); +REM("b is not in scope here.", true, true); +let r2 = rgx(list("a.\u{24}{b}*"), list()); +REM("We don't actually support the following flag syntax at the moment.\nThat's one of the syntax error messages.", true, true); +let r3 = rgx(list("(?/g)a.b*"), list()), b = r3; +REM("And we have a brief interpolation representation from Grammar that's\neasyish to build. It gets changed later.", true, true); +let r4 = stringExpr(rgx, true, "a.", \interpolate, b, "*"), r5 = stringExpr(rgx, true, "a", \interpolate, ".", \interpolate, b, "*?"), r6 = stringExpr(rgx, true, "a", \interpolate, ".", "*"), r7 = new Sequence(list(new CodePoints("a"), Dot, new Repeat(new CodePoints("b"), 0, null))).compiled(), s = "[a]", r8 = stringExpr(rgx, true, ".", \interpolate, s, "."); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/regex-literal/work/test/test.temper.md b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/regex-literal/work/test/test.temper.md new file mode 100644 index 00000000..43e40a14 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/regex-literal/work/test/test.temper.md @@ -0,0 +1,32 @@ +Some tests below: + +- Interpolated string value next to another interpolation. Also test a disappearing empty hole. +- Simple interpolated string value since we can't evaluate regex objects at compile time yet. + +Starting off with a simple regex + + let r1 = /a.b*/; + +b is not in scope here. + + let r2 = /a.${b}*/; + +We don't actually support the following flag syntax at the moment. +That's one of the syntax error messages. + + let r3 = /a.b*/g; + let b = r3; + +And we have a brief interpolation representation from Grammar that's +easyish to build. It gets changed later. + + let r4 = rgx"a.${b}*"; + let r5 = rgx"a${"."}${b}*${}?"; + let r6 = rgx"a${"."}*"; + let r7 = new Sequence([ + new CodePoints("a"), + Dot, + new Repeat(new CodePoints("b"), 0, null), + ]).compiled(); + let s = "[a]"; + let r8 = rgx".${s}."; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/resolutions-stored-with-postponed-case-cases/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/resolutions-stored-with-postponed-case-cases/expect/define.temper new file mode 100644 index 00000000..c572a73d --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/resolutions-stored-with-postponed-case-cases/expect/define.temper @@ -0,0 +1,11 @@ +let y__0; +y__0 = 123; +do { + if(postponedCase(([\f, "(", \let, \y, ")"]), x, \y, y__0), fn { + handleIt() + }, \else, fn (f#0) { + f#0(fn { + fallback() + }) + }) +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/resolutions-stored-with-postponed-case-cases/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/resolutions-stored-with-postponed-case-cases/work/test/test.temper new file mode 100644 index 00000000..e7fd5cc3 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/resolutions-stored-with-postponed-case-cases/work/test/test.temper @@ -0,0 +1,5 @@ +let y = 123; +when (x) { + case f(let y) -> handleIt(); + else -> fallback(); +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/sealed-subtypes-reject-new-type-params/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/sealed-subtypes-reject-new-type-params/expect/define.temper new file mode 100644 index 00000000..4617e73c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/sealed-subtypes-reject-new-type-params/expect/define.temper @@ -0,0 +1,53 @@ +@typeDecl(Something__0) @stay @sealedType let Something__0; +Something__0 = type (Something__0); +@typeDecl(Subversive__0) @stay let Subversive__0; +Subversive__0 = type (Subversive__0); +@typeDecl(Simple__0) @stay let Simple__0; +Simple__0 = type (Simple__0); +@typeDecl(Satisfying__0) @stay let Satisfying__0; +Satisfying__0 = type (Satisfying__0); +do {}; +@typeFormal(\T) @typeDefined(T__0) @fromType(Something__0) let T__0; +T__0 = type (T__0); +Something__0 extends AnyValue; +interface(\word, \Something, \concrete, false, @typeDefined(Something__0) fn { + do {}; + do {} +}); +void; +@typeFormal(\T) @typeDefined(T__1) @fromType(Subversive__0) let T__1; +T__1 = type (T__1); +@typeFormal(\U) @typeDefined(U__0) @fromType(Subversive__0) let U__0; +U__0 = type (U__0); +Subversive__0 extends Something__0; +@fn @visibility(\public) @stay @fromType(Subversive__0) let constructor__0; +constructor__0 = (@stay fn constructor(@impliedThis(Subversive__0) this__0: Subversive__0) /* return__0 */: Void {}); +class(\word, \Subversive, \concrete, true, @typeDefined(Subversive__0) fn { + do {}; + do {}; + do {}; + do {} +}); +void; +@typeFormal(\V) @typeDefined(V__0) @fromType(Simple__0) let V__0; +V__0 = type (V__0); +Simple__0 extends Something__0; +interface(\word, \Simple, \concrete, false, @typeDefined(Simple__0) fn { + do {}; + do {} +}); +void; +@typeFormal(\T) @typeDefined(T__2) @fromType(Satisfying__0) let T__2; +T__2 = type (T__2); +@typeFormal(\U) @typeDefined(U__1) @fromType(Satisfying__0) let U__1; +U__1 = type (U__1); +Satisfying__0 extends Simple__0; +@fn @visibility(\public) @stay @fromType(Satisfying__0) let constructor__1; +constructor__1 = (@stay fn constructor(@impliedThis(Satisfying__0) this__1: Satisfying__0) /* return__1 */: Void {}); +class(\word, \Satisfying, \concrete, true, @typeDefined(Satisfying__0) fn { + do {}; + do {}; + do {}; + do {} +}); +type (Satisfying__0) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/sealed-subtypes-reject-new-type-params/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/sealed-subtypes-reject-new-type-params/expect/errors.json new file mode 100644 index 00000000..d9bb8bf0 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/sealed-subtypes-reject-new-type-params/expect/errors.json @@ -0,0 +1,3 @@ +[ + "Cannot introduce type parameters in sealed subtype Subversive__0!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/sealed-subtypes-reject-new-type-params/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/sealed-subtypes-reject-new-type-params/work/test/test.temper new file mode 100644 index 00000000..e7cb910f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/sealed-subtypes-reject-new-type-params/work/test/test.temper @@ -0,0 +1,7 @@ +sealed interface Something {} +// Sealed subtypes can't introduce type params. +class Subversive extends Something {} +// But we can (must?) keep type params from parent. And check with a changed name, for bonus fun. +interface Simple extends Something {} +// And types further down the line can introduce new type params, since we can't cast to them anyway. +class Satisfying extends Simple {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/static-read/expect/define-types.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/static-read/expect/define-types.json new file mode 100644 index 00000000..69c2bafb --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/static-read/expect/define-types.json @@ -0,0 +1,27 @@ +{ + "AnyValue": { + "abstract": true + }, + "C": { + "supers": [ + "AnyValue__0" + ], + "methods": [ + { + "name": "constructor__0", + "visibility": "public", + "kind": "Constructor", + "open": false + } + ], + "staticProperties": [ + { + "name": "foo__0", + "visibility": "public" + } + ] + }, + "Void": { + "supers": [] + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/static-read/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/static-read/expect/define.temper new file mode 100644 index 00000000..7e7c31d9 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/static-read/expect/define.temper @@ -0,0 +1,13 @@ +C__0 extends AnyValue; +@staticProperty(\foo) @static @visibility(\public) @stay @fromType(C__0) let foo__0; +foo__0 = "FOO"; +@fn @method(\constructor) @visibility(\public) @stay @fromType(C__0) let constructor__0; +constructor__0 = (@stay fn constructor(@impliedThis(C__0) this__0: C__0) /* return__0 */: Void {}); +@typeDecl(C__0) @stay let C__0; +C__0 = type (C__0); +class(\word, \C, \concrete, true, @typeDefined(C__0) fn { + do {}; + do {}; + do {} +}); +getStatic(C__0, \foo) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/static-read/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/static-read/expect/run-result.json new file mode 100644 index 00000000..70716599 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/static-read/expect/run-result.json @@ -0,0 +1 @@ +"\u0022FOO\u0022: String" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/static-read/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/static-read/work/test/test.temper new file mode 100644 index 00000000..da5655f4 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/static-read/work/test/test.temper @@ -0,0 +1,4 @@ +class C { + public static foo = "FOO"; +} +C.foo diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-aliasing/expect/define-types.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-aliasing/expect/define-types.json new file mode 100644 index 00000000..754e6f8a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-aliasing/expect/define-types.json @@ -0,0 +1,21 @@ +{ + "AnyValue": { + "abstract": true + }, + "C": { + "methods": [ + { + "name": "constructor__3", + "visibility": "public", + "open": false, + "kind": "Constructor" + } + ], + "supers": [ + "AnyValue__0" + ] + }, + "Void": { + "supers": [] + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-aliasing/expect/define.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-aliasing/expect/define.lispy new file mode 100644 index 00000000..b63e34eb --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-aliasing/expect/define.lispy @@ -0,0 +1,434 @@ +[ + "Block", + [ + [ + "Call", + [ + [ + "Value", + "extends: Function" + ], + [ + "Value", + "C__0: Type" + ], + [ + "Value", + "AnyValue: Type" + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "constructor__3" + ], + [ + "Value", + "\\fn: Symbol" + ], + [ + "Value", + "void: Void" + ], + [ + "Value", + "\\method: Symbol" + ], + [ + "Value", + "\\constructor: Symbol" + ], + [ + "Value", + "\\visibility: Symbol" + ], + [ + "Value", + "\\public: Symbol" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.type C.constructor()\u0022: String" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ], + [ + "Value", + "\\stay: Symbol" + ], + [ + "Stay" + ], + [ + "Value", + "\\parameterNameSymbolsList: Symbol" + ], + [ + "Value", + "[null]: List" + ], + [ + "Value", + "\\fromType: Symbol" + ], + [ + "Value", + "C__0: Type" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "nym`=`: Function" + ], + [ + "LeftName", + "constructor__3" + ], + [ + "Fun", + [ + [ + "Decl", + [ + [ + "LeftName", + "this__4" + ], + [ + "Value", + "\\type: Symbol" + ], + [ + "Value", + "C__0: Type" + ], + [ + "Value", + "\\impliedThis: Symbol" + ], + [ + "Value", + "C__0: Type" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.type C.constructor().(this)\u0022: String" + ] + ] + ], + [ + "Value", + "\\word: Symbol" + ], + [ + "Value", + "\\constructor: Symbol" + ], + [ + "Value", + "\\returnDecl: Symbol" + ], + [ + "Decl", + [ + [ + "LeftName", + "return__0" + ], + [ + "Value", + "\\type: Symbol" + ], + [ + "Value", + "Void: Type" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.type C.constructor().return=\u0022: String" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ] + ] + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.type C.constructor()\u0022: String" + ], + [ + "Value", + "\\stay: Symbol" + ], + [ + "Stay" + ], + [ + "Block", + [] + ] + ] + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "C__0" + ], + [ + "Value", + "\\typeDecl: Symbol" + ], + [ + "Value", + "C__0: Type" + ], + [ + "Value", + "\\stay: Symbol" + ], + [ + "Stay", + "kotlin.Unit" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.type C\u0022: String" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "nym`=`: Function" + ], + [ + "LeftName", + "C__0" + ], + [ + "Value", + "C__0: Type" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "class: Function" + ], + [ + "Value", + "\\word: Symbol" + ], + [ + "Value", + "\\C: Symbol" + ], + [ + "Value", + "\\concrete: Symbol" + ], + [ + "Value", + "true: Boolean" + ], + [ + "Fun", + [ + [ + "Value", + "\\typeDefined: Symbol" + ], + [ + "Value", + "C__0: Type" + ], + [ + "Block", + [ + [ + "Block", + [] + ], + [ + "Block", + [] + ] + ] + ] + ] + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "alias__5" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.alias\u0022: String" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "nym`=`: Function" + ], + [ + "LeftName", + "alias__5" + ], + [ + "Value", + "C__0: Type" + ] + ] + ], + [ + "Value", + "void: Void" + ], + [ + "Decl", + [ + [ + "LeftName", + "o__6" + ], + [ + "Value", + "\\type: Symbol" + ], + [ + "Value", + "C__0: Type" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.o\u0022: String" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "p__7" + ], + [ + "Value", + "\\type: Symbol" + ], + [ + "Value", + "C__0: Type" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.p\u0022: String" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ] + ] + ], + [ + "Value", + "void: Void" + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-aliasing/expect/syntaxMacro-types.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-aliasing/expect/syntaxMacro-types.json new file mode 100644 index 00000000..137b8a44 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-aliasing/expect/syntaxMacro-types.json @@ -0,0 +1,21 @@ +{ + "AnyValue": { + "abstract": true + }, + "C": { + "methods": [ + { + "name": "constructor", + "visibility": "public", + "open": false, + "kind": "Constructor" + } + ], + "supers": [ + "AnyValue__0" + ] + }, + "Void": { + "supers": [] + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-aliasing/expect/syntaxMacro.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-aliasing/expect/syntaxMacro.lispy new file mode 100644 index 00000000..83001dee --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-aliasing/expect/syntaxMacro.lispy @@ -0,0 +1,330 @@ +[ + "Block", + [ + [ + "Decl", + [ + [ + "LeftName", + "C__0" + ], + [ + "Value", + "\\init: Symbol" + ], + [ + "Value", + "C__0: Type" + ], + [ + "Value", + "\\typeDecl: Symbol" + ], + [ + "Value", + "C__0: Type" + ], + [ + "Value", + "\\stay: Symbol" + ], + [ + "Stay", + "kotlin.Unit" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.type C\u0022: String" + ] + ] + ], + [ + "Call", + [ + [ + "RightName", + "class" + ], + [ + "Value", + "\\word: Symbol" + ], + [ + "Value", + "\\C: Symbol" + ], + [ + "Value", + "\\concrete: Symbol" + ], + [ + "Value", + "true: Boolean" + ], + [ + "Fun", + [ + [ + "Value", + "\\typeDefined: Symbol" + ], + [ + "Value", + "C__0: Type" + ], + [ + "Block", + [ + [ + "Call", + [ + [ + "Value", + "extends: Function" + ], + [ + "Value", + "C__0: Type" + ], + [ + "Value", + "AnyValue: Type" + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "constructor__3" + ], + [ + "Value", + "\\init: Symbol" + ], + [ + "Fun", + [ + [ + "Decl", + [ + [ + "LeftName", + "this__4" + ], + [ + "Value", + "\\type: Symbol" + ], + [ + "Value", + "C__0: Type" + ], + [ + "Value", + "\\impliedThis: Symbol" + ], + [ + "Value", + "C__0: Type" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.type C.constructor().(this)\u0022: String" + ] + ] + ], + [ + "Value", + "\\word: Symbol" + ], + [ + "Value", + "\\constructor: Symbol" + ], + [ + "Value", + "\\returnDecl: Symbol" + ], + [ + "Decl", + [ + [ + "LeftName", + "return__0" + ], + [ + "Value", + "\\type: Symbol" + ], + [ + "Value", + "Void: Type" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.type C.constructor().return=\u0022: String" + ] + ] + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.type C.constructor()\u0022: String" + ], + [ + "Block", + [] + ] + ] + ], + [ + "Value", + "\\method: Symbol" + ], + [ + "Value", + "\\constructor: Symbol" + ], + [ + "Value", + "\\visibility: Symbol" + ], + [ + "Value", + "\\public: Symbol" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.type C.constructor()\u0022: String" + ] + ] + ] + ] + ] + ] + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "alias__5" + ], + [ + "Value", + "\\init: Symbol" + ], + [ + "RightName", + "C__0" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.alias\u0022: String" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "REM: Function" + ], + [ + "Value", + "\u0022Reified types via aliases should be inlined.\u0022: String" + ], + [ + "Value", + "null: Null" + ], + [ + "Value", + "false: Boolean" + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "o__6" + ], + [ + "Value", + "\\type: Symbol" + ], + [ + "RightName", + "C__0" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.o\u0022: String" + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "p__7" + ], + [ + "Value", + "\\type: Symbol" + ], + [ + "RightName", + "alias__5" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.p\u0022: String" + ] + ] + ], + [ + "Value", + "void: Void" + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-aliasing/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-aliasing/work/test/test.temper new file mode 100644 index 00000000..991ba3a6 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-aliasing/work/test/test.temper @@ -0,0 +1,4 @@ +class C {} +let alias = C; // Reified types via aliases should be inlined. +let o: C; +let p: alias; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-args-kept/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-args-kept/expect/define.temper new file mode 100644 index 00000000..f9ede507 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-args-kept/expect/define.temper @@ -0,0 +1,54 @@ +@typeFormal(\Thing) @memberTypeFormal(\Thing) @typeDefined(Thing__0) @fromType(What__0) let Thing__0; +Thing__0 = type (Thing__0); +What__0 extends AnyValue; +let typeof_ints#0; +typeof_ints#0 = type (List); +@constructorProperty @property(\ints) @visibility(\public) @stay @fromType(What__0) let ints__0: List; +let typeof_things#0; +typeof_things#0 = type (List); +@constructorProperty @property(\things) @visibility(\public) @stay @fromType(What__0) let things__0: List; +@method(\work) @visibility(\public) @fn @stay @fromType(What__0) let work__0; +work__0 = fn work(@impliedThis(What__0) this__0: What__0, that__0 /* aka that */: Thing__0) /* return__0 */: Void { + fn__0: do { + let another__0: What__0; + another__0 = this__0; + let more__0: List; + more__0 = getp(things__0, this__0); + } +}; +@fn @method(\constructor) @visibility(\public) @stay @fromType(What__0) let constructor__0; +constructor__0 = fn constructor(@impliedThis(What__0) this__1: What__0, ints__1 /* aka ints */: List, things__1 /* aka things */: List) /* return__1 */: Void { + do { + let t#0; + setp(ints__0, this__1, t#0 = ints__1); + t#0 + }; + do { + let t#1; + setp(things__0, this__1, t#1 = things__1); + t#1 + }; +}; +@getter @method(\ints) @fn @visibility(\public) @stay @fromType(What__0) let getints__0; +getints__0 = fn (@impliedThis(What__0) this__2: What__0) /* return__2 */: (List) { + return__2 = getp(ints__0, this__2) +}; +@getter @method(\things) @fn @visibility(\public) @stay @fromType(What__0) let getthings__0; +getthings__0 = fn (@impliedThis(What__0) this__3: What__0) /* return__3 */: (List) { + return__3 = getp(things__0, this__3) +}; +@typeDecl(What__0) @stay let What__0; +What__0 = type (What__0); +class(\word, \What, \concrete, true, @typeDefined(What__0) fn { + do {}; + do {}; + do {}; + do {}; + do {}; + do {}; + do {}; + do {}; + do {}; + do {} +}); +type (What__0) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-args-kept/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-args-kept/expect/disAmbiguate.temper new file mode 100644 index 00000000..20d243d3 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-args-kept/expect/disAmbiguate.temper @@ -0,0 +1,11 @@ +@typeDecl(What__0) @hoistLeft(true) @resolution(What__0) @stay let What = type (What__0); +class(\word, What, \concrete, true, @typeDefined(What__0) fn { + @typeFormal(\Thing) @memberTypeFormal(\Thing) @typeDefined(Thing__0) @resolution(Thing__0) let Thing = type (Thing__0); + What__0 extends AnyValue; + @constructorProperty @property(\ints) @maybeVar @visibility(\public) let ints /* aka ints */: List; + @constructorProperty @property(\things) @maybeVar @visibility(\public) let things /* aka things */: List; + @method(\work) @visibility(\public) let work = fn(\word, work, @impliedThis(What__0) let this__0: What__0, let that /* aka that */: Thing, \outType, Void, fn { + let another: What = this(What__0), more: List = things; + }); +}); +What diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-args-kept/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-args-kept/expect/syntaxMacro.temper new file mode 100644 index 00000000..785e4429 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-args-kept/expect/syntaxMacro.temper @@ -0,0 +1,27 @@ +@typeDecl(What__0) @stay let What__0 = type (What__0); +class(\word, \What, \concrete, true, @typeDefined(What__0) fn { + @typeFormal(\Thing) @memberTypeFormal(\Thing) @typeDefined(Thing__0) let Thing__0 = type (Thing__0); + What__0 extends AnyValue; + let typeof_ints#0 = List; + @constructorProperty @property(\ints) @maybeVar @visibility(\public) let ints__0: typeof_ints#0; + let typeof_things#0 = List; + @constructorProperty @property(\things) @maybeVar @visibility(\public) let things__0: typeof_things#0; + @method(\work) @visibility(\public) @fn let work__0 = fn work(@impliedThis(What__0) this__0: What__0, that__0 /* aka that */: Thing__0) /* return__0 */: (Void) { + fn__0: do { + let another__0: What__0 = this(What__0), more__0: List = do_iget_things(type (What__0), this(What__0)); + } + }; + @method(\constructor) @visibility(\public) let constructor__0 = fn constructor(@impliedThis(What__0) this__1: What__0, ints__1 /* aka ints */: typeof_ints#0, things__1 /* aka things */: typeof_things#0) /* return__1 */: Void { + do { + let t#0; + do_iset_ints(type (What__0), this(What__0), t#0 = ints__1); + t#0 + }; + do { + let t#1; + do_iset_things(type (What__0), this(What__0), t#1 = things__1); + t#1 + }; + }; +}); +What__0 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-args-kept/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-args-kept/work/test/test.temper new file mode 100644 index 00000000..751beabe --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/type-args-kept/work/test/test.temper @@ -0,0 +1,9 @@ +class What( + public ints: List, + public things: List, +) { + public work(that: Thing): Void { + let another: What = this; + let more: List = things; + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/user-defined-pure-functions-inlined/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/user-defined-pure-functions-inlined/expect/define.temper new file mode 100644 index 00000000..4ee2a5c8 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/user-defined-pure-functions-inlined/expect/define.temper @@ -0,0 +1,8 @@ +@fn let factorMinusAdj__1, adj__0; +adj__0 = 6; +factorMinusAdj__1 = (@stay fn factorMinusAdj(x__2 /* aka x */: Int32, y__3 /* aka y */: Int32) /* return__0 */: Int32 { + fn__4: do { + x__2 * y__3 - 6 + } +}); +42 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/user-defined-pure-functions-inlined/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/user-defined-pure-functions-inlined/work/test/test.temper new file mode 100644 index 00000000..f81d6629 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/user-defined-pure-functions-inlined/work/test/test.temper @@ -0,0 +1,3 @@ +let adj = 6; +let factorMinusAdj(x: Int, y: Int): Int { x * y - adj } +factorMinusAdj(6, 8) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/when-block/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/when-block/expect/define.temper new file mode 100644 index 00000000..dea3018f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/when-block/expect/define.temper @@ -0,0 +1,51 @@ +@typeDecl(A__0) @stay let A__0; +A__0 = type (A__0); +@typeDecl(B__0) @stay let B__0; +B__0 = type (B__0); +@fn let f__0; +A__0 extends AnyValue; +@typePlaceholder(A__0) let typePlaceholder#0: Empty; +typePlaceholder#0 = {class: Empty__0}; +interface(\word, \A, \concrete, false, @typeDefined(A__0) fn { + do {} +}); +B__0 extends A__0; +@fn @method(\constructor) @visibility(\public) @stay @fromType(B__0) let constructor__0; +constructor__0 = (@stay fn constructor(@impliedThis(B__0) this__0: B__0) /* return__0 */: Void {}); +class(\word, \B, \concrete, true, @typeDefined(B__0) fn { + do {}; + do {} +}); +let b__0; +b__0 = new B__0(); +f__0 = fn f(a__0 /* aka a */: A__0) /* return__1 */: A__0 { + fn__0: do { + do { + if(a__0 == b__0, fn { + a__0 + }, \else_if, fn (f#0) { + f#0(a__0 is B__0, fn { + a__0 + }, \else_if, fn (f#1) { + f#1(a__0 == fancyExpression + 4, fn { + a__0 + }, \else_if, fn (f#2) { + f#2(if(a__0 == 4, @stay fn { + true + }, \else, fn (f#3) { + f#3(fn { + a__0 is C + }) + }), fn { + a__0 + }, \else, fn (f#4) { + f#4(fn { + a__0 + }) + }) + }) + }) + }) + } + } +}; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/when-block/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/when-block/expect/errors.json new file mode 100644 index 00000000..2e97bca2 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/when-block/expect/errors.json @@ -0,0 +1,10 @@ +[ + "Operator ThinArrow expects at least 2 operands but got 1!", + "Operator ThinArrow expects at least 2 operands but got 1!", + "Expected a TopLevel here!", + "Expected a TopLevel here!", + "Invalid block content!", + "Invalid block content!", + "Other cases are invalid after else!", + "Invalid block content!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/when-block/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/when-block/work/test/test.temper new file mode 100644 index 00000000..1efc451e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/when-block/work/test/test.temper @@ -0,0 +1,18 @@ +interface A { } +class B extends A { } +let b = new B(); +let f(a: A): A { + when (a) { + b -> a; + // Comments are fine, but unrelated statements aren't. + wordYall(); + is B -> a; + (fancyExpression + 4) -> a; + 4, is C -> a; + else -> a; + // Case after default is also bad, as is missing value. + c ->; + d -> a; + e -> + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/when-generic/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/when-generic/expect/define.temper new file mode 100644 index 00000000..12655985 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/when-generic/expect/define.temper @@ -0,0 +1,14 @@ +@fn let f__0; +f__0 = fn f(maybe__0 /* aka maybe */: List?) /* return__0 */: String { + fn__0: do { + do { + if(maybe__0 is List, @stay fn { + "yep" + }, \else, fn (f#0) { + f#0(@stay fn { + "nope" + }) + }) + } + } +}; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/when-generic/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/when-generic/work/test/test.temper new file mode 100644 index 00000000..13c5e04f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/define/when-generic/work/test/test.temper @@ -0,0 +1,6 @@ +let f(maybe: List?): String { + when (maybe) { + is List -> "yep"; + else -> "nope"; + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/annotated-formal/expect/disAmbiguate.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/annotated-formal/expect/disAmbiguate.lispy new file mode 100644 index 00000000..9eac00e8 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/annotated-formal/expect/disAmbiguate.lispy @@ -0,0 +1,66 @@ +[ + "Block", + [ + [ + "Call", + [ + [ + "RightName", + "fn" + ], + [ + "Value", + "\\word: Symbol" + ], + [ + "LeftName", + "f" + ], + [ + "Call", + [ + [ + "RightName", + "@A" + ], + [ + "Call", + [ + [ + "RightName", + "@B" + ], + [ + "Decl", + [ + [ + "LeftName", + "x" + ], + [ + "Value", + "\\word: Symbol" + ], + [ + "Value", + "\\x: Symbol" + ] + ] + ] + ] + ] + ] + ], + [ + "Fun", + [ + [ + "Block", + [] + ] + ] + ] + ] + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/annotated-formal/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/annotated-formal/work/test/test.temper new file mode 100644 index 00000000..bf094a21 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/annotated-formal/work/test/test.temper @@ -0,0 +1 @@ +fn f(@A @B x) {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/annotations-on-formals/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/annotations-on-formals/expect/disAmbiguate.temper new file mode 100644 index 00000000..55389f7c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/annotations-on-formals/expect/disAmbiguate.temper @@ -0,0 +1 @@ +fn(nym`@foo`(@default(0) var x /* aka x */), let y /* aka y */, fn {}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/annotations-on-formals/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/annotations-on-formals/work/test/test.temper new file mode 100644 index 00000000..a965039f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/annotations-on-formals/work/test/test.temper @@ -0,0 +1 @@ +fn (@foo var x = 0, y) {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/block-formals/expect/disAmbiguate.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/block-formals/expect/disAmbiguate.lispy new file mode 100644 index 00000000..e4fa42b6 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/block-formals/expect/disAmbiguate.lispy @@ -0,0 +1,91 @@ +[ + "Block", + [ + [ + "Call", + [ + [ + "RightName", + "f" + ], + [ + "Fun", + [ + [ + "Decl", + [ + [ + "LeftName", + "x" + ], + [ + "Value", + "\\type: Symbol" + ], + [ + "RightName", + "Int" + ], + [ + "Value", + "\\word: Symbol" + ], + [ + "Value", + "\\x: Symbol" + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "y" + ], + [ + "Value", + "\\type: Symbol" + ], + [ + "RightName", + "Int" + ], + [ + "Value", + "\\word: Symbol" + ], + [ + "Value", + "\\y: Symbol" + ] + ] + ], + [ + "Block", + [ + [ + "Call", + [ + [ + "Value", + "nym`do_call__+_`[PlusIntInt, PlusIntInt64, PlusFltFlt]: Function" + ], + [ + "RightName", + "x" + ], + [ + "RightName", + "y" + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/block-formals/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/block-formals/expect/disAmbiguate.temper new file mode 100644 index 00000000..274812b5 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/block-formals/expect/disAmbiguate.temper @@ -0,0 +1,3 @@ +f(fn (x /* aka x */: Int, y /* aka y */: Int) { + x + y +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/block-formals/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/block-formals/work/test/test.temper new file mode 100644 index 00000000..31c5b811 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/block-formals/work/test/test.temper @@ -0,0 +1 @@ +f { x: Int, y: Int => x + y } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/bunch-of-stuff/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/bunch-of-stuff/expect/disAmbiguate.temper new file mode 100644 index 00000000..462d3d6c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/bunch-of-stuff/expect/disAmbiguate.temper @@ -0,0 +1,5 @@ +a + b * c; +42; +let x = 1; +REM("What is going on here?", null, false); +console.log(cat("foo ", str(cat("bar ", str(cat("qux ", str(xyzzy))))), " baz")); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/bunch-of-stuff/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/bunch-of-stuff/work/test/test.temper new file mode 100644 index 00000000..0e002c61 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/bunch-of-stuff/work/test/test.temper @@ -0,0 +1,10 @@ +a + b * c; + +42; + +let x = 1; + +// What is going on here? +console.log("foo ${"bar ${"qux ${xyzzy}"}"} baz" ); + +// comment diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/class-body-ambiguity-reduction/expect/disAmbiguate-types.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/class-body-ambiguity-reduction/expect/disAmbiguate-types.json new file mode 100644 index 00000000..82cce762 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/class-body-ambiguity-reduction/expect/disAmbiguate-types.json @@ -0,0 +1,11 @@ +{ + "AnyValue": { + "abstract": true + }, + "C": { + "word": "C" + }, + "Void": { + "supers": [] + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/class-body-ambiguity-reduction/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/class-body-ambiguity-reduction/expect/disAmbiguate.temper new file mode 100644 index 00000000..0504f0af --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/class-body-ambiguity-reduction/expect/disAmbiguate.temper @@ -0,0 +1,57 @@ +@typeDecl(C__0) @hoistLeft(true) @resolution(C__0) @stay let C = type (C__0); +class(\word, C, \concrete, true, @typeDefined(C__0) fn { + C__0 extends AnyValue; + REM("This is a class body", null, false); + @property(\decl) var decl = 0; + @property(\cDecl) let cDecl; + @property(\property0) @maybeVar let property0; + @property(\property1) @maybeVar @visibility(\public) let property1: T; + @property(\property2) @maybeVar let property2 = initial; + @property(\property3) @maybeVar let property3: T = initial; + @method(\method1) let method1 = fn(\word, method1, @impliedThis(C__0) let this__1: C__0, fn { + 123 + }); + @method(\method2) let method2 = fn(\word, method2, @impliedThis(C__0) let this__2: C__0, \outType, T, fn { + 123 + }); + @method(\method3) let method3 = fn(\word, method3, @impliedThis(C__0) let this__3: C__0, @default(123) let x /* aka x */: U, fn { + 123 + }); + @method(\method4) let method4 = fn(\word, method4, @impliedThis(C__0) let this__4: C__0, let x /* aka x */: V, fn { + 123 + }); + @method(\p) @getter let nym`get.p` = fn(\word, nym`get.p`, nym`@Foo`(@impliedThis(C__0) let this__5: C__0), \outType, T, fn { + property1 + }); + @method(\p) @setter let nym`set.p` = fn(\word, nym`set.p`, @impliedThis(C__0) let this__6: C__0, let x /* aka x */, \outType, type (Void), fn { + this(C__0).property1 = x + }); +}); +do(fn { + REM("This is not a class body, and the parts about properties/methods are ALL LIES!", null, false); + var decl = 0; + let cDecl; + property0; + nym`@public`((property1) : (T)); + property2 = initial; + ((property3) : (T)) = initial; + method1(fn { + 123 + }); + method2(\outType, T, fn { + 123 + }); + method3(error (), fn { + 123 + }); + REM("Error on line 24", null, false); + let(\word, method4, let x /* aka x */: V, fn { + 123 + }); + get(\word, p, nym`@Foo`(this()), \outType, T, fn { + property1 + }); + set(\word, p, x, fn { + this().property1 = x + }) +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/class-body-ambiguity-reduction/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/class-body-ambiguity-reduction/expect/errors.json new file mode 100644 index 00000000..ac0c2d7e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/class-body-ambiguity-reduction/expect/errors.json @@ -0,0 +1,4 @@ +[ + "Formal argument where actual expected. `:` only applies to function parameters!", + "Actual arguments cannot be provided by name!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/class-body-ambiguity-reduction/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/class-body-ambiguity-reduction/work/test/test.temper new file mode 100644 index 00000000..6e2138a1 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/class-body-ambiguity-reduction/work/test/test.temper @@ -0,0 +1,28 @@ +class C { // This is a class body + var decl = 0; + let cDecl; + property0; + public property1: T; + property2 = initial; + property3: T = initial; + method1() { 123 } + method2(): T { 123 } + method3(x: U = 123) { 123 } + let method4(x: V) { 123 } + get p(@Foo this): T { property1 } + set p(x) { this.property1 = x } +} +do { // This is not a class body, and the parts about properties/methods are ALL LIES! + var decl = 0; + let cDecl; + property0; + public property1: T; + property2 = initial; + property3: T = initial; + method1() { 123 } + method2(): T { 123 } + method3(x: U = 123) { 123 } // Error on line 24 + let method4(x: V) { 123 } + get p(@Foo this): T { property1 } + set p(x) { this.property1 = x } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/classes-can-declare-properties-in-parenthetical/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/classes-can-declare-properties-in-parenthetical/expect/disAmbiguate.temper new file mode 100644 index 00000000..4836ff04 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/classes-can-declare-properties-in-parenthetical/expect/disAmbiguate.temper @@ -0,0 +1,8 @@ +@typeDecl(Point__0) @hoistLeft(true) @resolution(Point__0) @stay let Point = type (Point__0); +class(\word, Point, \concrete, true, @typeDefined(Point__0) fn { + Point__0 extends AntValue; + @constructorProperty @maybeVar @visibility(\public) let x /* aka x */: Float64; + @constructorProperty @maybeVar @visibility(\public) let y /* aka y */: Float64; + @visibility(\public) let distanceFromOrigin: Float64 = (x * x + y * y).sqrt(); +}); +Point diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/classes-can-declare-properties-in-parenthetical/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/classes-can-declare-properties-in-parenthetical/work/test/test.temper new file mode 100644 index 00000000..0031b46b --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/classes-can-declare-properties-in-parenthetical/work/test/test.temper @@ -0,0 +1,6 @@ +class Point( + public let x: Float64, + public let y: Float64, +) extends AntValue { + public let distanceFromOrigin: Float64 = (x * x + y * y).sqrt(); +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/comment-in-doc-type-definition/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/comment-in-doc-type-definition/expect/disAmbiguate.temper new file mode 100644 index 00000000..3c4bab37 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/comment-in-doc-type-definition/expect/disAmbiguate.temper @@ -0,0 +1,7 @@ +@typeDecl(C__0) @hoistLeft(true) @resolution(C__0) @stay let C = type (C__0); +class(\word, C, \concrete, true, @typeDefined(C__0) fn { + C__0 extends AnyValue; + REM("Comment in type definition", null, false); + @property(\x) @maybeVar @visibility(\public) let x: Int; +}); +identityForDocGen(C) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/comment-in-doc-type-definition/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/comment-in-doc-type-definition/work/test/test.temper new file mode 100644 index 00000000..3f7beea1 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/comment-in-doc-type-definition/work/test/test.temper @@ -0,0 +1,4 @@ +class C { + // Comment in type definition + public x: Int; +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/decorated-argument/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/decorated-argument/expect/disAmbiguate.temper new file mode 100644 index 00000000..b6df2b18 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/decorated-argument/expect/disAmbiguate.temper @@ -0,0 +1 @@ +let(\word, f, nym`@foo`(let x /* aka x */: T, 1), fn {}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/decorated-argument/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/decorated-argument/work/test/test.temper new file mode 100644 index 00000000..949a97db --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/decorated-argument/work/test/test.temper @@ -0,0 +1 @@ +let f(@foo(1) x: T) {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/enum-desugaring/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/enum-desugaring/expect/disAmbiguate.temper new file mode 100644 index 00000000..c10ab8cf --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/enum-desugaring/expect/disAmbiguate.temper @@ -0,0 +1,10 @@ +@typeDecl(E__0) @hoistLeft(true) @resolution(E__0) @stay let E = type (E__0); +class(\word, E, \concrete, true, @enumType @typeDefined(E__0) fn { + E__0 extends AnyValue; + @constructorProperty @visibility(\public) @property(\ordinal) let ordinal: Int32; + @constructorProperty @visibility(\public) @property(\name) let name: String; + @visibility(\public) @enumMember @staticProperty(\A) @static let A = new E(0, "A"); + @visibility(\public) @enumMember @staticProperty(\B) @static let B = new E(1, "B"); + @visibility(\public) @enumMember @staticProperty(\C) @static let C = new E(2, "C"); +}); +E diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/enum-desugaring/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/enum-desugaring/work/test/test.temper new file mode 100644 index 00000000..08cc3a0f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/enum-desugaring/work/test/test.temper @@ -0,0 +1 @@ +enum E { A, B, C } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/every-type-but-core-has-a-super-type/expect/disAmbiguate-types.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/every-type-but-core-has-a-super-type/expect/disAmbiguate-types.json new file mode 100644 index 00000000..54f7a4ff --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/every-type-but-core-has-a-super-type/expect/disAmbiguate-types.json @@ -0,0 +1,9 @@ +{ + "I": { + "name": "I__0", + "abstract": true + }, + "AnyValue": { + "abstract": true + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/every-type-but-core-has-a-super-type/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/every-type-but-core-has-a-super-type/expect/disAmbiguate.temper new file mode 100644 index 00000000..3f46bd01 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/every-type-but-core-has-a-super-type/expect/disAmbiguate.temper @@ -0,0 +1,5 @@ +@typeDecl(I__0) @hoistLeft(true) @resolution(I__0) @stay let I = type (I__0); +interface(\word, I, \concrete, false, @typeDefined(I__0) fn { + I__0 extends AnyValue +}); +I diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/every-type-but-core-has-a-super-type/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/every-type-but-core-has-a-super-type/work/test/test.temper new file mode 100644 index 00000000..5820ccb1 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/every-type-but-core-has-a-super-type/work/test/test.temper @@ -0,0 +1 @@ +interface I {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/exported-classes-have-exported-names/expect/disAmbiguate-types.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/exported-classes-have-exported-names/expect/disAmbiguate-types.json new file mode 100644 index 00000000..459793c0 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/exported-classes-have-exported-names/expect/disAmbiguate-types.json @@ -0,0 +1,12 @@ +{ + "C": { + "name": { + "type": "ExportedName", + "module": "test//", + "baseName": "C" + } + }, + "AnyValue": { + "abstract": true + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/exported-classes-have-exported-names/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/exported-classes-have-exported-names/expect/disAmbiguate.temper new file mode 100644 index 00000000..bea91aa2 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/exported-classes-have-exported-names/expect/disAmbiguate.temper @@ -0,0 +1,6 @@ +do {}; +@typeDecl(C) @hoistLeft(true) @resolution(`test//`.C) @stay let `test//`.C = type (C); +class(\word, C, \concrete, true, @typeDefined(C) fn { + C extends AnyValue +}); +C diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/exported-classes-have-exported-names/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/exported-classes-have-exported-names/work/test/test.temper new file mode 100644 index 00000000..1ec0ebf4 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/exported-classes-have-exported-names/work/test/test.temper @@ -0,0 +1 @@ +export class C {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/exported-classes-with-extra-decorators-have-exported-names/expect/disAmbiguate-types.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/exported-classes-with-extra-decorators-have-exported-names/expect/disAmbiguate-types.json new file mode 100644 index 00000000..b37ac161 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/exported-classes-with-extra-decorators-have-exported-names/expect/disAmbiguate-types.json @@ -0,0 +1,27 @@ +{ + "AnyValue": { + "abstract": true + }, + "C": { + "name": { + "type": "ExportedName", + "module": "test//", + "baseName": "C" + } + }, + "D": { + "name": { + "type": "ExportedName", + "module": "test//", + "baseName": "D" + }, + "abstract": true + }, + "E": { + "name": { + "type": "ExportedName", + "module": "test//", + "baseName": "E" + } + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/exported-classes-with-extra-decorators-have-exported-names/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/exported-classes-with-extra-decorators-have-exported-names/expect/disAmbiguate.temper new file mode 100644 index 00000000..8ea2a460 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/exported-classes-with-extra-decorators-have-exported-names/expect/disAmbiguate.temper @@ -0,0 +1,16 @@ +do {}; +nym`@export`(nym`@bar`(@typeDecl(C) @hoistLeft(true) @resolution(`test//`.C) @stay let C = type (C))); +class(\word, C, \concrete, true, @typeDefined(C) fn { + C extends AnyValue +}); +do {}; +nym`@foo`(@typeDecl(D) @hoistLeft(true) @resolution(`test//`.D) @stay let `test//`.D = type (D), 1); +interface(\word, D, \concrete, false, @typeDefined(D) fn { + D extends AnyValue +}); +do {}; +nym`@foo`(nym`@export`(nym`@bar`(@typeDecl(E) @hoistLeft(true) @resolution(`test//`.E) @stay let E = type (E)))); +class(\word, E, \concrete, true, @typeDefined(E) fn { + E extends AnyValue +}); +E diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/exported-classes-with-extra-decorators-have-exported-names/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/exported-classes-with-extra-decorators-have-exported-names/work/test/test.temper new file mode 100644 index 00000000..7e025f54 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/exported-classes-with-extra-decorators-have-exported-names/work/test/test.temper @@ -0,0 +1,3 @@ + export @bar class C {} + @foo(1) export interface D {} + @foo() export @bar class E {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/formals-and-actuals-with-embedded-comments/expect/disAmbiguate.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/formals-and-actuals-with-embedded-comments/expect/disAmbiguate.lispy new file mode 100644 index 00000000..7715bfb5 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/formals-and-actuals-with-embedded-comments/expect/disAmbiguate.lispy @@ -0,0 +1,99 @@ +[ + "Block", + [ + [ + "Call", + [ + [ + "RightName", + "let" + ], + [ + "Value", + [ + "word", + "Symbol" + ] + ], + [ + "LeftName", + "f" + ], + [ + "Decl", + [ + [ + "LeftName", + "a" + ], + [ + "Value", + [ + "type", + "Symbol" + ] + ], + [ + "RightName", + "Int" + ], + [ + "Value", + [ + "word", + "Symbol" + ] + ], + [ + "Value", + [ + "a", + "Symbol" + ] + ], + [ + "Value", + [ + "docString", + "Symbol" + ] + ], + [ + "Value", + [ + "[\u0022docs\u0022, \u0022docs\u0022, \u0022test/test.temper\u0022]", + "List" + ] + ] + ] + ], + [ + "Fun", + [ + [ + "Block", + [ + [ + "Call", + [ + [ + "RightName", + "g" + ], + [ + "Value", + [ + 1, + "Int32" + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/formals-and-actuals-with-embedded-comments/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/formals-and-actuals-with-embedded-comments/work/test/test.temper new file mode 100644 index 00000000..922ed37b --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/formals-and-actuals-with-embedded-comments/work/test/test.temper @@ -0,0 +1 @@ +let f(/** docs */ a: Int) { g(/** here too? */ 1) } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/formals-formalized-and-actuals-actualized/expect/disAmbiguate.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/formals-formalized-and-actuals-actualized/expect/disAmbiguate.lispy new file mode 100644 index 00000000..f0134c11 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/formals-formalized-and-actuals-actualized/expect/disAmbiguate.lispy @@ -0,0 +1,131 @@ +[ + "Block", + [ + [ + "Call", + [ + [ + "RightName", + "let" + ], + [ + "Value", + [ + "word", + "Symbol" + ] + ], + [ + "LeftName", + "f" + ], + [ + "Decl", + [ + [ + "LeftName", + "a" + ], + [ + "Value", + [ + "default", + "Symbol" + ] + ], + [ + "Value", + [ + 1, + "Int32" + ] + ], + [ + "Value", + [ + "word", + "Symbol" + ] + ], + [ + "Value", + [ + "a", + "Symbol" + ] + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "b" + ], + [ + "Value", + [ + "type", + "Symbol" + ] + ], + [ + "RightName", + "Int" + ], + [ + "Value", + [ + "word", + "Symbol" + ] + ], + [ + "Value", + [ + "b", + "Symbol" + ] + ] + ] + ], + [ + "Fun", + [ + [ + "Block", + [ + [ + "Call", + [ + [ + "RightName", + "g" + ], + [ + "Call", + [ + [ + "Value", + [ + "error", + "Function" + ] + ] + ] + ], + [ + "RightName", + "b" + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/formals-formalized-and-actuals-actualized/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/formals-formalized-and-actuals-actualized/expect/errors.json new file mode 100644 index 00000000..c27870eb --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/formals-formalized-and-actuals-actualized/expect/errors.json @@ -0,0 +1,3 @@ +[ + "Actual arguments cannot be provided by name!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/formals-formalized-and-actuals-actualized/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/formals-formalized-and-actuals-actualized/work/test/test.temper new file mode 100644 index 00000000..d0e33a39 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/formals-formalized-and-actuals-actualized/work/test/test.temper @@ -0,0 +1 @@ +let f(a = 1, b: Int) { g(a = 1, b) } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/generic-fn-with-complex-type-formal/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/generic-fn-with-complex-type-formal/expect/disAmbiguate.temper new file mode 100644 index 00000000..7e3370e7 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/generic-fn-with-complex-type-formal/expect/disAmbiguate.temper @@ -0,0 +1,5 @@ +let(\word, f, \typeFormal, do { + @resolution(T__0) @typeFormal(\T) @typeDecl(T__0) @stay let T = type (T__0); + T__0 extends MapKey; + type (T__0) + }, let x /* aka x */: T, \outType, Void, fn {}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/generic-fn-with-complex-type-formal/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/generic-fn-with-complex-type-formal/work/test/test.temper new file mode 100644 index 00000000..8f930fe8 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/generic-fn-with-complex-type-formal/work/test/test.temper @@ -0,0 +1 @@ +let f<@in T extends MapKey>(x: T): Void {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/generic-method/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/generic-method/expect/disAmbiguate.temper new file mode 100644 index 00000000..894a9cf7 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/generic-method/expect/disAmbiguate.temper @@ -0,0 +1,11 @@ +@typeDecl(C__0) @hoistLeft(true) @resolution(C__0) @stay let C = type (C__0); +class(\word, C, \concrete, true, @typeDefined(C__0) fn { + C__0 extends AnyValue; + @method(\f) @visibility(\public) let f = fn(\word, f, \typeFormal, do { + @resolution(T__0) @typeFormal(\T) @typeDecl(T__0) let T = type (T__0); + type (T__0) + }, @impliedThis(C__0) let this__0: C__0, let x /* aka x */: T, \outType, T, fn { + x + }); +}); +C diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/generic-method/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/generic-method/work/test/test.temper new file mode 100644 index 00000000..7f5b95ad --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/generic-method/work/test/test.temper @@ -0,0 +1,3 @@ +class C { + public let f(x: T): T { x } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/generic-methods-disallowed-in-interface/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/generic-methods-disallowed-in-interface/expect/disAmbiguate.temper new file mode 100644 index 00000000..666a6f40 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/generic-methods-disallowed-in-interface/expect/disAmbiguate.temper @@ -0,0 +1,27 @@ +@typeDecl(Whatever__0) @hoistLeft(true) @resolution(Whatever__0) @stay let Whatever = type (Whatever__0); +interface(\word, Whatever, \concrete, false, @typeDefined(Whatever__0) fn { + Whatever__0 extends AnyValue; + let blather = fn(\word, blather, \typeFormal, do { + @resolution(A__0) @typeFormal(\A) @typeDecl(A__0) let A = type (A__0); + type (A__0) + }, @impliedThis(Whatever__0) let this__0: Whatever__0, let a /* aka a */: A, \outType, A, fn { + pureVirtual() + }); + @visibility(\public) let bling = fn(\word, bling, \typeFormal, do { + @resolution(B__0) @typeFormal(\B) @typeDecl(B__0) let B = type (B__0); + type (B__0) + }, \typeFormal, do { + @resolution(C__0) @typeFormal(\C) @typeDecl(C__0) let C = type (C__0); + C__0 extends Whatever; + type (C__0) + }, @impliedThis(Whatever__0) let this__1: Whatever__0, let b /* aka b */: B, let c /* aka c */: C, \outType, B, fn { + b + }); + @fn @static let blot = fn(\word, blot, \typeFormal, do { + @resolution(T__1) @typeFormal(\T) @typeDecl(T__1) let T = type (T__1); + type (T__1) + }, let d /* aka d */: D, \outType, D, fn { + pureVirtual() + }); +}); +Whatever diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/generic-methods-disallowed-in-interface/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/generic-methods-disallowed-in-interface/expect/errors.json new file mode 100644 index 00000000..265db857 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/generic-methods-disallowed-in-interface/expect/errors.json @@ -0,0 +1,5 @@ +[ + "Illegal type parameter A. Overridable methods don't allow generics!", + "Illegal type parameter B. Overridable methods don't allow generics!", + "Illegal type parameter C. Overridable methods don't allow generics!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/generic-methods-disallowed-in-interface/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/generic-methods-disallowed-in-interface/work/test/test.temper new file mode 100644 index 00000000..ae83dfd9 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/generic-methods-disallowed-in-interface/work/test/test.temper @@ -0,0 +1,5 @@ +interface Whatever { + blather(a: A): A; + public let bling(b: B, c: C): B { b } + static blot(d: D): D; +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/increment-in-do-block/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/increment-in-do-block/expect/disAmbiguate.temper new file mode 100644 index 00000000..b129db29 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/increment-in-do-block/expect/disAmbiguate.temper @@ -0,0 +1,5 @@ +do(fn { + var x = 0; + x = (nym`do_call__+_`[PlusIntInt, PlusIntInt64, PlusFltFlt])(x, 1); + console.log(x); +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/increment-in-do-block/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/increment-in-do-block/work/test/test.temper new file mode 100644 index 00000000..82a1e574 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/increment-in-do-block/work/test/test.temper @@ -0,0 +1,5 @@ +do { + var x = 0; + x += 1; + console.log(x); +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/more-decorated-type-formals/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/more-decorated-type-formals/expect/disAmbiguate.temper new file mode 100644 index 00000000..4b71837f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/more-decorated-type-formals/expect/disAmbiguate.temper @@ -0,0 +1,14 @@ +@typeDecl(C__0) @hoistLeft(true) @resolution(C__0) @stay let C = type (C__0); +class(\word, C, \concrete, true, @typeDefined(C__0) fn { + @typeFormal(\T) @typeDefined(T__0) @resolution(T__0) @stay @variance(-1) @imu let T = type (T__0); + C__0 extends AnyValue +}); +@typeDecl(D__0) @hoistLeft(true) @resolution(D__0) @stay let D = type (D__0); +class(\word, D, \concrete, true, @typeDefined(D__0) fn { + @typeFormal(\T) @typeDefined(T__1) @resolution(T__1) @stay @variance(-1) @imu let T = type (T__1); + D__0 extends AnyValue +}); +let(\word, f, \typeFormal, do { + @resolution(T__2) @typeFormal(\T) @typeDecl(T__2) @stay @partialImu @imu let T = type (T__2); + type (T__2) + }, let t /* aka t */: T, \outType, Void, fn {}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/more-decorated-type-formals/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/more-decorated-type-formals/work/test/test.temper new file mode 100644 index 00000000..04ec2d96 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/more-decorated-type-formals/work/test/test.temper @@ -0,0 +1,3 @@ +class C<@in @imu T> {} +class D<@imu @in T> {} +let f<@imu @partialImu T>(t: T): Void {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-decl-decorator-application/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-decl-decorator-application/expect/disAmbiguate.temper new file mode 100644 index 00000000..009019e2 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-decl-decorator-application/expect/disAmbiguate.temper @@ -0,0 +1,2 @@ +nym`@foo`(var x); +nym`@foo`(var y); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-decl-decorator-application/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-decl-decorator-application/work/test/test.temper new file mode 100644 index 00000000..47e0f60a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-decl-decorator-application/work/test/test.temper @@ -0,0 +1 @@ +@foo var x, y; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-init-error-in-class/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-init-error-in-class/expect/disAmbiguate.temper new file mode 100644 index 00000000..2c16022e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-init-error-in-class/expect/disAmbiguate.temper @@ -0,0 +1,8 @@ +@typeDecl(Something__0) @hoistLeft(true) @resolution(Something__0) @stay let Something = type (Something__0); +class(\word, Something, \concrete, true, @typeDefined(Something__0) fn { + Something__0 extends AnyValue; + let t#0 = f(); + @property(\a) let a = t#0.a; + @property(\b) let b = t#0.b; +}); +Something diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-init-error-in-class/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-init-error-in-class/expect/errors.json new file mode 100644 index 00000000..50064dd7 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-init-error-in-class/expect/errors.json @@ -0,0 +1,3 @@ +[ + "Declaration is malformed!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-init-error-in-class/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-init-error-in-class/work/test/test.temper new file mode 100644 index 00000000..a3cc8222 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-init-error-in-class/work/test/test.temper @@ -0,0 +1 @@ +class Something { let { a, b } = f(); } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-init-multi-rename-error/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-init-multi-rename-error/expect/disAmbiguate.temper new file mode 100644 index 00000000..85752c15 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-init-multi-rename-error/expect/disAmbiguate.temper @@ -0,0 +1 @@ +let t#0 = f(), b = t#0.a; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-init-multi-rename-error/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-init-multi-rename-error/expect/errors.json new file mode 100644 index 00000000..f70dc78b --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-init-multi-rename-error/expect/errors.json @@ -0,0 +1,4 @@ +[ + "Extra rename not allowed!", + "Extra rename not allowed!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-init-multi-rename-error/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-init-multi-rename-error/work/test/test.temper new file mode 100644 index 00000000..9b66bd78 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-init-multi-rename-error/work/test/test.temper @@ -0,0 +1 @@ +let { a as b as c as d } = f(); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-init/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-init/expect/disAmbiguate.temper new file mode 100644 index 00000000..595980b9 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-init/expect/disAmbiguate.temper @@ -0,0 +1,4 @@ +nym`@foo`(let t#0: U = f()); +nym`@foo`(let a: S = t#0.a); +nym`@foo`(let b = t#0.b); +nym`@foo`(let d: T = t#0.c); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-init/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-init/work/test/test.temper new file mode 100644 index 00000000..a1a44536 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multi-init/work/test/test.temper @@ -0,0 +1 @@ +@foo let { a is S, b, c as d is T }: U = f(); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multiple-keyword-annotations-all-fire/expect/disAmbiguate.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multiple-keyword-annotations-all-fire/expect/disAmbiguate.lispy new file mode 100644 index 00000000..3ca3ff8e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multiple-keyword-annotations-all-fire/expect/disAmbiguate.lispy @@ -0,0 +1,30 @@ +[ + "Block", + [ + [ + "Decl", + [ + [ + "LeftName", + "x" + ], + [ + "Value", + "\\static: Symbol" + ], + [ + "Value", + "void: Void" + ], + [ + "Value", + "\\visibility: Symbol" + ], + [ + "Value", + "\\public: Symbol" + ] + ] + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multiple-keyword-annotations-all-fire/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multiple-keyword-annotations-all-fire/work/test/test.temper new file mode 100644 index 00000000..0617e543 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/multiple-keyword-annotations-all-fire/work/test/test.temper @@ -0,0 +1 @@ +public static let x diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/square-bracket-desugaring/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/square-bracket-desugaring/expect/disAmbiguate.temper new file mode 100644 index 00000000..fc528497 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/square-bracket-desugaring/expect/disAmbiguate.temper @@ -0,0 +1 @@ +a.set(i, b.get(j)); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/square-bracket-desugaring/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/square-bracket-desugaring/work/test/test.temper new file mode 100644 index 00000000..f6f0a882 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/square-bracket-desugaring/work/test/test.temper @@ -0,0 +1 @@ +a[i] = b[j]; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/staging-annotation/expect/disAmbiguate.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/staging-annotation/expect/disAmbiguate.lispy new file mode 100644 index 00000000..0914ed0f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/staging-annotation/expect/disAmbiguate.lispy @@ -0,0 +1,68 @@ +[ + "Block", + [ + [ + "Call", + [ + [ + "Call", + [ + [ + "RightName", + ".." + ], + [ + "RightName", + "@A" + ], + [ + "RightName", + "@S" + ] + ] + ], + [ + "Call", + [ + [ + "RightName", + "fn" + ], + [ + "Decl", + [ + [ + "LeftName", + "x" + ], + [ + "Value", + [ + "word", + "Symbol" + ] + ], + [ + "Value", + [ + "x", + "Symbol" + ] + ] + ] + ], + [ + "Fun", + [ + [ + "Block", + [] + ] + ] + ] + ] + ] + ] + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/staging-annotation/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/staging-annotation/work/test/test.temper new file mode 100644 index 00000000..138b7461 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/staging-annotation/work/test/test.temper @@ -0,0 +1 @@ +@(A..S) fn (x) {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/type-decorator-can-access-type-and-declaration/expect/define-types.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/type-decorator-can-access-type-and-declaration/expect/define-types.json new file mode 100644 index 00000000..0be049fd --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/type-decorator-can-access-type-and-declaration/expect/define-types.json @@ -0,0 +1,44 @@ +{ + "AnyValue": { + "abstract": true + }, + "I": { + "name": "I__0", + "word": "I", + "abstract": true, + "metadata": { + "TypeDecoratedByFoo": [ + "void: Void" + ] + }, + "supers": [ + { + "module": "core", + "abbrev": "AnyValue__0", + "uid": 0 + } + ] + }, + "Empty": { + "supers": [ + "AnyValue__0", + "Equatable__0" + ], + "methods": [ + { + "name": "constructor__0", + "visibility": "private", + "kind": "Constructor", + "open": false + } + ], + "metadata": { + "connected": [ + "void: Void" + ], + "imu": [ + "void: Void" + ] + } + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/type-decorator-can-access-type-and-declaration/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/type-decorator-can-access-type-and-declaration/expect/define.temper new file mode 100644 index 00000000..a17c86e9 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/type-decorator-can-access-type-and-declaration/expect/define.temper @@ -0,0 +1,10 @@ +@typeDecl(I__0) @stay @TypeDecoratedByFoo let I__0; +I__0 = type (I__0); +do {}; +I__0 extends AnyValue; +@typePlaceholder(I__0) let typePlaceholder#0: Empty; +typePlaceholder#0 = {class: Empty__0}; +interface(\word, \I, \concrete, false, @typeDefined(I__0) fn { + do {} +}); +type (I__0) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/type-decorator-can-access-type-and-declaration/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/type-decorator-can-access-type-and-declaration/expect/disAmbiguate.temper new file mode 100644 index 00000000..ccdd2adf --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/type-decorator-can-access-type-and-declaration/expect/disAmbiguate.temper @@ -0,0 +1,6 @@ +do {}; +nym`@foo`(@typeDecl(I__0) @hoistLeft(true) @resolution(I__0) @stay let I = type (I__0)); +interface(\word, I, \concrete, false, @typeDefined(I__0) fn { + I__0 extends AnyValue +}); +I diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/type-decorator-can-access-type-and-declaration/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/type-decorator-can-access-type-and-declaration/work/test/test.temper new file mode 100644 index 00000000..e2245746 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/type-decorator-can-access-type-and-declaration/work/test/test.temper @@ -0,0 +1 @@ +@foo interface I {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/type-formals-on-class-declaration/expect/disAmbiguate-types.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/type-formals-on-class-declaration/expect/disAmbiguate-types.json new file mode 100644 index 00000000..bab781b7 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/type-formals-on-class-declaration/expect/disAmbiguate-types.json @@ -0,0 +1,38 @@ +{ + "C": { + "word": "C", + "typeParameters": [ + { + "name": "T__1" + }, + { + "name": "U__2" + }, + { + "name": "V__3" + }, + { + "name": "W__4" + } + ] + }, + "T": { + "name": "T__1", + "word": "T" + }, + "U": { + "name": "U__2", + "word": "U", + "upperBounds": [] + }, + "V": { + "name": "V__3", + "word": "V", + "variance": "Covariant" + }, + "W": { + "name": "W__4", + "word": "W", + "variance": "Contravariant" + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/type-formals-on-class-declaration/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/type-formals-on-class-declaration/expect/disAmbiguate.temper new file mode 100644 index 00000000..d3e61e4c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/type-formals-on-class-declaration/expect/disAmbiguate.temper @@ -0,0 +1,11 @@ +@typeDecl(C__0) @hoistLeft(true) @resolution(C__0) @stay let C = type (C__0); +class(\word, C, \concrete, true, @typeDefined(C__0) fn { + @typeFormal(\T) @typeDefined(T__1) @resolution(T__1) let T = type (T__1); + @typeFormal(\U) @typeDefined(U__2) @resolution(U__2) let U = type (U__2); + @typeFormal(\V) @typeDefined(V__3) @resolution(V__3) @stay @variance(1) let V = type (V__3); + @typeFormal(\W) @typeDefined(W__4) @resolution(W__4) @stay @variance(-1) let W = type (W__4); + U extends D; + C__0 extends A; + C__0 extends B +}); +C diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/type-formals-on-class-declaration/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/type-formals-on-class-declaration/work/test/test.temper new file mode 100644 index 00000000..556c2931 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/type-formals-on-class-declaration/work/test/test.temper @@ -0,0 +1 @@ +class C extends A, B {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/unknown-function-with-formal-gets-error/expect/disAmbiguate.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/unknown-function-with-formal-gets-error/expect/disAmbiguate.lispy new file mode 100644 index 00000000..f08f1b0b --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/unknown-function-with-formal-gets-error/expect/disAmbiguate.lispy @@ -0,0 +1,76 @@ +[ + "Block", + [ + [ + "Call", + [ + [ + "RightName", + "foo" + ], + [ + "Value", + [ + "word", + "Symbol" + ] + ], + [ + "LeftName", + "f" + ], + [ + "Call", + [ + [ + "Value", + [ + "error", + "Function" + ] + ] + ] + ], + [ + "RightName", + "b" + ], + [ + "Fun", + [ + [ + "Block", + [ + [ + "Call", + [ + [ + "RightName", + "g" + ], + [ + "Call", + [ + [ + "Value", + [ + "error", + "Function" + ] + ] + ] + ], + [ + "RightName", + "b" + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/unknown-function-with-formal-gets-error/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/unknown-function-with-formal-gets-error/expect/errors.json new file mode 100644 index 00000000..f74dd80e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/unknown-function-with-formal-gets-error/expect/errors.json @@ -0,0 +1,25 @@ +// ↓↓↓ ↓↓↓↓↓ ↓↓↓ +// "foo f(a = 1, b: Int) { g(a = 1, b) }", +// 0123456789012345678901234567890123456 +// 1 2 3 + +[ + { + "template": "NamedActual", + "values": [], + "left": 25, + "right": 28 + }, + { + "template": "NamedActual", + "values": [], + "left": 6, + "right": 9 + }, + { + "template": "MalformedActual", + "values": [], + "left": 14, + "right": 19 + } +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/unknown-function-with-formal-gets-error/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/unknown-function-with-formal-gets-error/work/test/test.temper new file mode 100644 index 00000000..4988274f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/unknown-function-with-formal-gets-error/work/test/test.temper @@ -0,0 +1 @@ +foo f(a = 1, b: Int) { g(a = 1, b) } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/unrecognized-decorations-preserved-for-later/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/unrecognized-decorations-preserved-for-later/expect/disAmbiguate.temper new file mode 100644 index 00000000..ba8a2105 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/unrecognized-decorations-preserved-for-later/expect/disAmbiguate.temper @@ -0,0 +1 @@ +nym`@foo`(nym`@bar`(let x)) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/unrecognized-decorations-preserved-for-later/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/unrecognized-decorations-preserved-for-later/work/test/test.temper new file mode 100644 index 00000000..873c6829 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/unrecognized-decorations-preserved-for-later/work/test/test.temper @@ -0,0 +1 @@ +@foo @bar let x diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/wildcard-destructure-error/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/wildcard-destructure-error/expect/disAmbiguate.temper new file mode 100644 index 00000000..85f3364d --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/wildcard-destructure-error/expect/disAmbiguate.temper @@ -0,0 +1 @@ +let t#0 = f(); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/wildcard-destructure-error/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/wildcard-destructure-error/expect/errors.json new file mode 100644 index 00000000..16fb1ce4 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/wildcard-destructure-error/expect/errors.json @@ -0,0 +1,3 @@ +[ + "Wildcard destructure allowed only for import!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/wildcard-destructure-error/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/wildcard-destructure-error/work/test/test.temper new file mode 100644 index 00000000..f1bb71e4 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/dis-ambiguate/wildcard-destructure-error/work/test/test.temper @@ -0,0 +1 @@ +let { ... } = f() diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/function-macro/compile-log-execution-order/expect/functionMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/function-macro/compile-log-execution-order/expect/functionMacro.temper new file mode 100644 index 00000000..4b45053b --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/function-macro/compile-log-execution-order/expect/functionMacro.temper @@ -0,0 +1,7 @@ +compilelog("1", @F); +if (c) { + compilelog("2", @F) +} else { + compilelog("3", @F) +}; +compilelog("4", @F) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/function-macro/compile-log-execution-order/expect/stdout.txt b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/function-macro/compile-log-execution-order/expect/stdout.txt new file mode 100644 index 00000000..81eb0d2a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/function-macro/compile-log-execution-order/expect/stdout.txt @@ -0,0 +1,4 @@ +clog:F: 1 +clog:F: 2 +clog:F: 3 +clog:F: 4 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/function-macro/multi-init-error-in-class/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/function-macro/multi-init-error-in-class/work/test/test.temper new file mode 100644 index 00000000..cf20180a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/function-macro/multi-init-error-in-class/work/test/test.temper @@ -0,0 +1 @@ +class Aha(private hmm: Int) {}; class Boo { let { hmm } = new Aha(1) } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification1/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification1/expect/generateCode.temper new file mode 100644 index 00000000..1156f75c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification1/expect/generateCode.temper @@ -0,0 +1,14 @@ +@fn @reach(\none) let f__0; +f__0 = (@stay fn f(i__0 /* aka i */: StringIndexOption?) /* return__0 */: (Int32 | Bubble) { + var t#0; + if (!isNull(i__0)) { + t#0 = i__0 is StringIndex + } else { + t#0 = false + }; + if (t#0) { + return__0 = 0 + } else { + return__0 = 1 + } +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification1/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification1/work/test/test.temper new file mode 100644 index 00000000..e5493b1a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification1/work/test/test.temper @@ -0,0 +1,7 @@ +let f(i: StringIndexOption?): Int throws Bubble { + if (i is StringIndex) { + 0 + } else { + 1 + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification2/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification2/expect/generateCode.temper new file mode 100644 index 00000000..1d51b6c3 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification2/expect/generateCode.temper @@ -0,0 +1,14 @@ +@fn @reach(\none) let f__0; +f__0 = (@stay fn f(i__0 /* aka i */: StringIndexOption?) /* return__0 */: (Int32 | Bubble) { + var t#0; + if (!isNull(i__0)) { + t#0 = i__0 is StringIndexOption + } else { + t#0 = false + }; + if (t#0) { + return__0 = 0 + } else { + return__0 = 1 + } +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification2/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification2/work/test/test.temper new file mode 100644 index 00000000..1854a4fa --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification2/work/test/test.temper @@ -0,0 +1,7 @@ +let f(i: StringIndexOption?): Int throws Bubble { + if (i is StringIndexOption) { + 0 + } else { + 1 + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification3/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification3/expect/generateCode.temper new file mode 100644 index 00000000..868a7c8d --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification3/expect/generateCode.temper @@ -0,0 +1,18 @@ +@fn @reach(\none) let f__0; +f__0 = (@stay fn f(i__0 /* aka i */: StringIndexOption?) /* return__0 */: (Int32 | Bubble) { + var fail#0; + orelse#0: { + let j__0; + if (isNull(i__0)) { + j__0 = null + } else { + j__0 = hs(fail#0, i__0 as StringIndex); + if (fail#0) { + break orelse#0; + } + }; + return__0 = 0 + } orelse { + return__0 = 1 + } +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification3/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification3/work/test/test.temper new file mode 100644 index 00000000..a579ad67 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification3/work/test/test.temper @@ -0,0 +1,6 @@ +let f(i: StringIndexOption?): Int throws Bubble { + do { + let j = i as StringIndex?; + 0 + } orelse 1 +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification4/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification4/expect/generateCode.temper new file mode 100644 index 00000000..0dd5941f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification4/expect/generateCode.temper @@ -0,0 +1,43 @@ +@fn @reach(\none) let f__0; +f__0 = (@stay fn f(i__0 /* aka i */: StringIndexOption?) /* return__0 */: (Int32 | Bubble) { + var t#0, t#1, t#2, t#3, fail#0; + if (isNull(i__0)) { + t#0 = true + } else { + t#0 = i__0 is StringIndex + }; + if (t#0) { + if (isNull(i__0)) { + t#3 = null + } else { + t#3 = assertAs(i__0, StringIndex) + }; + let j__0; + if (isNull(t#3)) { + j__0 = null + } else { + t#1 = hs(fail#0, t#3 as StringIndex); + if (fail#0) { + bubble() + }; + j__0 = t#1 + }; + if (!isNull(j__0)) { + t#2 = j__0 is StringIndex + } else { + t#2 = false + }; + if (t#2) { + return__0 = 1 + } else { + return__0 = 2 + } + } else { + let n__0; + if (!isNull(i__0)) { + bubble() + }; + n__0 = null; + return__0 = 3 + } +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification4/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification4/work/test/test.temper new file mode 100644 index 00000000..84bac08c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification4/work/test/test.temper @@ -0,0 +1,13 @@ +let f(i: StringIndexOption?): Int throws Bubble { + if (i is StringIndex?) { + let j = i as StringIndex?; + if (j is StringIndex) { + 1 + } else { + 2 + } + } else { + let n = i as Never?; + 3 + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification5/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification5/expect/generateCode.temper new file mode 100644 index 00000000..b95db2cf --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification5/expect/generateCode.temper @@ -0,0 +1,7 @@ +@fn @reach(\none) let g__0, @fn @reach(\none) f__0; +g__0 = (@stay fn g(s__0 /* aka s */: String) /* return__0 */: StringIndexOption { + return__0 = do_get_end(s__0) +}); +f__0 = (@stay fn f(s__1 /* aka s */: String) /* return__1 */: Boolean { + return__1 = (fn g)(s__1) is NoStringIndex +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification5/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification5/work/test/test.temper new file mode 100644 index 00000000..bae7c58f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/as-and-is-simplification5/work/test/test.temper @@ -0,0 +1,6 @@ +let g(s: String): StringIndexOption { + s.end +} +let f(s: String): Boolean { + g(s) is NoStringIndex +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/assigned-fn-with-inferred-sig-types/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/assigned-fn-with-inferred-sig-types/expect/generateCode.temper new file mode 100644 index 00000000..3dcc2d86 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/assigned-fn-with-inferred-sig-types/expect/generateCode.temper @@ -0,0 +1,4 @@ +@fn @reach(\none) let funny__0: (fn (Int32): String); +funny__0 = (@stay fn funny(n__0 /* aka n */) /* return__0 */{ + return__0 = do_call_toString(n__0) +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/assigned-fn-with-inferred-sig-types/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/assigned-fn-with-inferred-sig-types/work/test/test.temper new file mode 100644 index 00000000..28435119 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/assigned-fn-with-inferred-sig-types/work/test/test.temper @@ -0,0 +1 @@ +let funny: fn (Int): String = fn (n) { n.toString() }; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/assignments-to-typed-return-are-checked/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/assignments-to-typed-return-are-checked/expect/errors.json new file mode 100644 index 00000000..18221ccd --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/assignments-to-typed-return-are-checked/expect/errors.json @@ -0,0 +1,4 @@ +[ + "Cannot assign to Int32 from AnyValue!", + "Expected subtype of Int32, but got AnyValue!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/assignments-to-typed-return-are-checked/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/assignments-to-typed-return-are-checked/expect/generateCode.temper new file mode 100644 index 00000000..0473e79f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/assignments-to-typed-return-are-checked/expect/generateCode.temper @@ -0,0 +1,5 @@ +let return__4, @fn f__0; +f__0 = (@stay fn f(x__0 /* aka x */) /* return__1 */: Int32 { + return__1 = x__0 +}); +return__4 = (fn f) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/assignments-to-typed-return-are-checked/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/assignments-to-typed-return-are-checked/work/test/test.temper new file mode 100644 index 00000000..4069758c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/assignments-to-typed-return-are-checked/work/test/test.temper @@ -0,0 +1 @@ +fn f(x): Int { x } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/auto-cast-is/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/auto-cast-is/expect/generateCode.temper new file mode 100644 index 00000000..eaabd4c2 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/auto-cast-is/expect/generateCode.temper @@ -0,0 +1,8 @@ +@fn @reach(\none) let some__0; +some__0 = (@stay fn some(maybe__0 /* aka maybe */: StringIndexOption) /* return__0 */: StringIndex { + if (maybe__0 is StringIndex) { + return__0 = assertAs(maybe__0, StringIndex) + } else { + return__0 = getStatic(String, \begin) + } +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/auto-cast-is/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/auto-cast-is/work/test/test.temper new file mode 100644 index 00000000..291b5035 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/auto-cast-is/work/test/test.temper @@ -0,0 +1,7 @@ +let some(maybe: StringIndexOption): StringIndex { + if (maybe is StringIndex) { + maybe + } else { + String.begin + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/auto-cast-when/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/auto-cast-when/expect/generateCode.temper new file mode 100644 index 00000000..eaabd4c2 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/auto-cast-when/expect/generateCode.temper @@ -0,0 +1,8 @@ +@fn @reach(\none) let some__0; +some__0 = (@stay fn some(maybe__0 /* aka maybe */: StringIndexOption) /* return__0 */: StringIndex { + if (maybe__0 is StringIndex) { + return__0 = assertAs(maybe__0, StringIndex) + } else { + return__0 = getStatic(String, \begin) + } +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/auto-cast-when/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/auto-cast-when/work/test/test.temper new file mode 100644 index 00000000..9988be92 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/auto-cast-when/work/test/test.temper @@ -0,0 +1,6 @@ +let some(maybe: StringIndexOption): StringIndex { + when (maybe) { + is StringIndex -> maybe; + else -> String.begin; + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/awaiting/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/awaiting/expect/generateCode.temper new file mode 100644 index 00000000..2b6c3767 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/awaiting/expect/generateCode.temper @@ -0,0 +1,21 @@ +var t#0, t#1, fail#0; +t#0 = getConsole(); +let pb__0; +pb__0 = new PromiseBuilder(); +let p__0; +p__0 = do_get_promise(pb__0); +let fn__0; +fn__0 = (@stay fn /* return__0 */{ + let fn__1; + fn__1 = (@wrappedGeneratorFn fn /* return__1 */: (GeneratorResult) implements GeneratorFn { + do_call_complete(pb__0, "Hello, World!"); + return__1 = (fn doneResult)() + }); + return__0 = adaptGeneratorFnSafe(fn__1) +}); +async(fn__0); +t#1 = hs(fail#0, await p__0); +if (fail#0) { + bubble() +}; +do_call_log(t#0, t#1) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/awaiting/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/awaiting/expect/run-result.json new file mode 100644 index 00000000..cc7a3b30 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/awaiting/expect/run-result.json @@ -0,0 +1 @@ +"void: Void" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/awaiting/expect/stdout.txt b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/awaiting/expect/stdout.txt new file mode 100644 index 00000000..8ab686ea --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/awaiting/expect/stdout.txt @@ -0,0 +1 @@ +Hello, World! diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/awaiting/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/awaiting/work/test/test.temper new file mode 100644 index 00000000..ea49a137 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/awaiting/work/test/test.temper @@ -0,0 +1,6 @@ +let pb = new PromiseBuilder(); +let p = pb.promise; +async { (): GeneratorResult extends GeneratorFn => + pb.complete("Hello, World!"); +} +console.log(await p); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/ban-export-in-loops/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/ban-export-in-loops/expect/errors.json new file mode 100644 index 00000000..523ce1f1 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/ban-export-in-loops/expect/errors.json @@ -0,0 +1 @@ +[ "TODO" ] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/ban-export-in-loops/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/ban-export-in-loops/work/test/test.temper new file mode 100644 index 00000000..be709a71 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/ban-export-in-loops/work/test/test.temper @@ -0,0 +1,5 @@ +var i = 0; +while (i <= 2) { + export let x = i; + i += 1 +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/ban-export-not-at-top-level/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/ban-export-not-at-top-level/expect/errors.json new file mode 100644 index 00000000..523ce1f1 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/ban-export-not-at-top-level/expect/errors.json @@ -0,0 +1 @@ +[ "TODO" ] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/ban-export-not-at-top-level/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/ban-export-not-at-top-level/work/test/test.temper new file mode 100644 index 00000000..40a4adf2 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/ban-export-not-at-top-level/work/test/test.temper @@ -0,0 +1 @@ +let f(x) { export let y = x; } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/ban-exports-exposing-non-exported/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/ban-exports-exposing-non-exported/expect/errors.json new file mode 100644 index 00000000..39c85d7f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/ban-exports-exposing-non-exported/expect/errors.json @@ -0,0 +1,12 @@ +[ + "Export depends publicly on non-exported symbol Hidden!", + "Export depends publicly on non-exported symbol Hidden!", + "Export depends publicly on non-exported symbol Hidden!", + "Export depends publicly on non-exported symbol Hidden!", + "Export depends publicly on non-exported symbol Hidden!", + "Export depends publicly on non-exported symbol Hidden!", + "Export depends publicly on non-exported symbol Hidden!", + "Export depends publicly on non-exported symbol Hidden!", + "Export depends publicly on non-exported symbol Hidden!", + "Export depends publicly on non-exported symbol Hidden!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/ban-exports-exposing-non-exported/expect/generateCode-exports.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/ban-exports-exposing-non-exported/expect/generateCode-exports.json new file mode 100644 index 00000000..10538314 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/ban-exports-exposing-non-exported/expect/generateCode-exports.json @@ -0,0 +1,6 @@ +{ + "Exported": "Exported: Type", + "consider": "fn consider: Function", + "sneak": "fn sneak: Function", + "more": null +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/ban-exports-exposing-non-exported/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/ban-exports-exposing-non-exported/expect/generateCode.temper new file mode 100644 index 00000000..779a9b04 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/ban-exports-exposing-non-exported/expect/generateCode.temper @@ -0,0 +1,46 @@ +@typeDecl(Hidden__0) @stay let Hidden__0; +Hidden__0 = type (Hidden__0); +@typeDecl(Exported) @stay let `test//`.Exported; +`test//`.Exported = type (Exported); +@fn let `test//`.consider, @fn `test//`.sneak, @typePlaceholder(Hidden__0) typePlaceholder#0: Empty; +typePlaceholder#0 = {class: Empty__0}; +let `test//`.more; +`test//`.more = new Map(list()); +@typeFormal(\HI) @typeDefined(HI__0) @fromType(Exported) let HI__0; +HI__0 = type (HI__0); +@constructorProperty @visibility(\public) @stay @fromType(Exported) let hi__0: Hidden__0; +@visibility(\public) @fn @stay @fromType(Exported) let attempt__0; +attempt__0 = (@stay fn attempt(@impliedThis(Exported) this__0: Exported) /* return__0 */: Hidden__0 { + return__0 = getp(hi__0, this__0) +}); +@visibility(\public) @fn @stay @fromType(Exported) let attempt2__0; +@typeFormal(\H) @typeDecl(H__0) let H__0; +H__0 = type (H__0); +attempt2__0 = (@stay fn attempt2(@impliedThis(Exported) this__1: Exported, hmm__0 /* aka hmm */: H__0) /* return__1 */: H__0 { + return__1 = hmm__0 +}); +@fn @static @visibility(\public) @stay @fromType(Exported) let subvert__0; +subvert__0 = (@stay fn subvert /* return__2 */: (Map) { + return__2 = `test//`.more +}); +@visibility(\private) @stay @fromType(Exported) let ha__0: Hidden__0; +@fn @visibility(\public) @stay @fromType(Exported) let constructor__0; +constructor__0 = (@stay fn constructor(@impliedThis(Exported) this__2: Exported, hi__1 /* aka hi */: Hidden__0) /* return__3 */: Void { + let t#0; + t#0 = hi__1; + setp(hi__0, this__2, t#0); + setp(ha__0, this__2, hi__1); + return__3 = void +}); +@fn @visibility(\public) @stay @fromType(Exported) let gethi__0; +gethi__0 = (@stay fn (@impliedThis(Exported) this__3: Exported) /* return__4 */: Hidden__0 { + return__4 = getp(hi__0, this__3) +}); +`test//`.consider = (@stay fn consider(hu__0 /* aka hu */: Hidden__0) /* return__5 */: (Hidden__0?) { + return__5 = hu__0 +}); +@typeFormal(\H) @typeDecl(H__1) let H__1; +H__1 = type (H__1); +`test//`.sneak = (@stay fn sneak(he__0 /* aka he */: H__1) /* return__6 */: H__1 { + return__6 = he__0 +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/ban-exports-exposing-non-exported/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/ban-exports-exposing-non-exported/work/test/test.temper new file mode 100644 index 00000000..d16ae17b --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/ban-exports-exposing-non-exported/work/test/test.temper @@ -0,0 +1,11 @@ +interface Hidden {} +export class Exported(x: A, t: T, i: I): T; } +class C extends I { protected f(x: B, u: U, i: I): U { u } } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/hide-override-method/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/hide-override-method/expect/errors.json new file mode 100644 index 00000000..60b3af93 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/hide-override-method/expect/errors.json @@ -0,0 +1,3 @@ +[ + "Override has lower visibility than in I__0!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/hide-override-method/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/hide-override-method/expect/generateCode.temper new file mode 100644 index 00000000..301eb675 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/hide-override-method/expect/generateCode.temper @@ -0,0 +1,16 @@ +@method(\f) @visibility(\public) @fn @stay @fromType(I__0) @reach(\none) let f__0; +f__0 = (@stay fn f(@impliedThis(I__0) this__0: I__0) /* return__0 */: Int32 { + pureVirtual() +}); +@typeDecl(I__0) @stay @reach(\none) let I__0; +I__0 = type (I__0); +@typeDecl(C__0) @stay @reach(\none) let C__0; +C__0 = type (C__0); +@method(\f) @visibility(\protected) @fn @stay @fromType(C__0) @reach(\none) let f__1; +f__1 = (@stay fn f(@impliedThis(C__0) this__1: C__0) /* return__1 */: Int32 { + return__1 = 1 +}); +@fn @method(\constructor) @visibility(\public) @stay @fromType(C__0) @reach(\none) let constructor__0; +constructor__0 = (@stay fn constructor(@impliedThis(C__0) this__2: C__0) /* return__3 */: Void { + return__3 = void +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/hide-override-method/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/hide-override-method/work/test/test.temper new file mode 100644 index 00000000..7627e967 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/hide-override-method/work/test/test.temper @@ -0,0 +1,2 @@ +interface I { public f(): Int; } +class C extends I { protected f(): Int { 1 } } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/hide-override-property/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/hide-override-property/expect/errors.json new file mode 100644 index 00000000..60b3af93 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/hide-override-property/expect/errors.json @@ -0,0 +1,3 @@ +[ + "Override has lower visibility than in I__0!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/hide-override-property/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/hide-override-property/expect/generateCode.temper new file mode 100644 index 00000000..18f5d5b9 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/hide-override-property/expect/generateCode.temper @@ -0,0 +1,13 @@ +let return__0; +@property(\x) @visibility(\public) @stay @fromType(I__0) let x__0: Int32; +@typeDecl(I__0) @stay let I__0; +I__0 = type (I__0); +@typeDecl(C__0) @stay let C__0; +C__0 = type (C__0); +@constructorProperty @property(\x) @visibility(\protected) @stay @fromType(C__0) let x__1: Int32; +@fn @method(\constructor) @visibility(\public) @stay @fromType(C__0) let constructor__0; +constructor__0 = (@stay fn constructor(@impliedThis(C__0) this__0: C__0, x__2 /* aka x */: Int32) /* return__1 */: Void { + setp(x__1, this__0, x__2); + return__1 = void +}); +return__0 = type (C__0) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/hide-override-property/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/hide-override-property/work/test/test.temper new file mode 100644 index 00000000..f024a6ae --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/hide-override-property/work/test/test.temper @@ -0,0 +1,2 @@ +interface I { public x: Int } +class C(protected x: Int) extends I {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/implied-lambda-return-type/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/implied-lambda-return-type/expect/errors.json new file mode 100644 index 00000000..12563f57 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/implied-lambda-return-type/expect/errors.json @@ -0,0 +1,3 @@ +[ + "Expected subtype of Int32, but got String!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/implied-lambda-return-type/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/implied-lambda-return-type/expect/generateCode.temper new file mode 100644 index 00000000..6caf5191 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/implied-lambda-return-type/expect/generateCode.temper @@ -0,0 +1,12 @@ +@fn @reach(\none) let f__0, @fn @reach(\none) h__0; +f__0 = (@stay fn f(g__0 /* aka g */: (fn (): Int32)) /* return__1 */: Int32 { + return__1 = g__0() +}); +h__0 = (@stay fn h /* return__2 */: Void { + let fn__0; + fn__0 = (@stay fn /* return__3 */{ + return__3 = "hi" + }); + f__0(fn__0); + return__2 = void +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/implied-lambda-return-type/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/implied-lambda-return-type/work/test/test.temper new file mode 100644 index 00000000..d835ac67 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/implied-lambda-return-type/work/test/test.temper @@ -0,0 +1,2 @@ +let f(g: fn (): Int): Int { g() } +let h(): Void { f { "hi" }; } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/init-assignment-reachability/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/init-assignment-reachability/expect/generateCode.temper new file mode 100644 index 00000000..2850ee56 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/init-assignment-reachability/expect/generateCode.temper @@ -0,0 +1,5 @@ +var hi__0; +hi__0 = 0; +hi__0 = 1; +@reach(\none) let ha__0; +ha__0 = 2 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/init-assignment-reachability/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/init-assignment-reachability/work/test/test.temper new file mode 100644 index 00000000..c20ce6fa --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/init-assignment-reachability/work/test/test.temper @@ -0,0 +1,5 @@ +// We don't eliminate var reassignments, so keep associated declarations. +var hi = 0; +hi = 1; +// Non-var for contrast. +let ha = 2; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-non-null-check/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-non-null-check/expect/errors.json new file mode 100644 index 00000000..9b5d02be --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-non-null-check/expect/errors.json @@ -0,0 +1,3 @@ +[ + "Expected function type, but got (fn (Int32): Void)?!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-non-null-check/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-non-null-check/expect/run-result.json new file mode 100644 index 00000000..cc7a3b30 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-non-null-check/expect/run-result.json @@ -0,0 +1 @@ +"void: Void" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-non-null-check/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-non-null-check/work/test/test.temper new file mode 100644 index 00000000..490513ee --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-non-null-check/work/test/test.temper @@ -0,0 +1,7 @@ +export let Act = fn (i: Int): Void; +export let hi(i: Int, act: Act?): Void { + if (i == 0 || act != null) { + // `||` means act could be null here. + act(i); + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti-not-inlined/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti-not-inlined/expect/errors.json new file mode 100644 index 00000000..4f2a1754 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti-not-inlined/expect/errors.json @@ -0,0 +1,3 @@ +[ + "Unnecessary type check to String from expression with type String which is a subtype" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti-not-inlined/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti-not-inlined/expect/generateCode.temper new file mode 100644 index 00000000..e0bcfdc3 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti-not-inlined/expect/generateCode.temper @@ -0,0 +1,3 @@ +let return__0, @reach(\none) s__0: AnyValue; +s__0 = "str"; +return__0 = "str" is String diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti-not-inlined/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti-not-inlined/work/test/test.temper new file mode 100644 index 00000000..df924fab --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti-not-inlined/work/test/test.temper @@ -0,0 +1,2 @@ +let s: AnyValue = "str"; +s is String diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti-type-args/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti-type-args/expect/errors.json new file mode 100644 index 00000000..f99509d4 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti-type-args/expect/errors.json @@ -0,0 +1,7 @@ +[ + "Type arguments cannot be introduced with is or as runtime type checks: \u003c[Sub__0\u003cString\u003e]\u003e from AnyValue!", + "Unrelated types cannot be targeted with is or as runtime type checks: \u003c[Sub__0\u003cString\u003e]\u003e from Sup__0\u003cT__0\u003e!", + "Unrelated types cannot be targeted with is or as runtime type checks: \u003c[Sub2__0\u003cT__1\u003e]\u003e from Sup__0\u003cT__1\u003e!", + "Type arguments cannot be introduced with is or as runtime type checks: \u003c[Sup2__0\u003cT__2, U__0\u003e]\u003e from Sup__0\u003cU__0\u003e!", + "Unrelated types cannot be targeted with is or as runtime type checks: \u003c[Sub4__0]\u003e from Sup__0\u003cT__3\u003e!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti-type-args/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti-type-args/expect/run-result.json new file mode 100644 index 00000000..cc7a3b30 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti-type-args/expect/run-result.json @@ -0,0 +1 @@ +"void: Void" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti-type-args/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti-type-args/work/test/test.temper new file mode 100644 index 00000000..6e1c2229 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti-type-args/work/test/test.temper @@ -0,0 +1,42 @@ +interface Sup {} +class Sub extends Sup {} +interface Sup2 extends Sup {} +class Sub2 extends Sup2 {} // sneak swap the meaning of T +class Sub3 extends Sup2 {} // weaves T through +class Sub4 extends Sup {} +let badCast(value: AnyValue): Sub throws Bubble { + // Introduces String. + value as Sub +} +let alsoBad(value: Sup): Sub throws Bubble { + // Presumes known type arg for T. + value as Sub +} +let goodCast(value: Sup): Sub throws Bubble { + // Keeps the known type arg. + value as Sub +} +let alsoGood(value: Sup): Sub throws Bubble { + // Also keeps the known type arg, which is also a type param. + value as Sub +} +let butThisIsBad(value: Sup): Sub2 throws Bubble { + // The T args here aren't actually related. Presumes String as an arg for U. + value as Sub2 +} +let alsoBadBecauseExtra(value: Sup): Sup2 throws Bubble { + // Introduces T. + value as Sup2 +} +let butThisIsGood(value: Sup): Sup2 throws Bubble { + // Uses known U for both cases. + value as Sup2 +} +let goodDespiteMiddle(value: Sup): Sub3 throws Bubble { + // Invents String for Sup2 T, but that doesn't matter because it's not represented. + value as Sub3 +} +let badNonGeneric(value: Sup): Sub4 throws Bubble { + // Invents String for Sup T without any generics in Sub4 at all. + value as Sub4 +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti/expect/errors.json new file mode 100644 index 00000000..f054cda5 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti/expect/errors.json @@ -0,0 +1,15 @@ +[ + "Types marked @mayDowncastTo(false) cannot be targeted with is or as runtime type checks because they may not be distinct on all backends: \u003c[String]\u003e from AnyValue!", + "Types marked @mayDowncastTo(false) cannot be targeted with is or as runtime type checks because they may not be distinct on all backends: \u003c[Int32]\u003e from AnyValue!", + "Types marked @mayDowncastTo(false) cannot be targeted with is or as runtime type checks because they may not be distinct on all backends: \u003c[Boolean]\u003e from AnyValue!", + "Types marked @mayDowncastTo(false) cannot be targeted with is or as runtime type checks because they may not be distinct on all backends: \u003c[String]\u003e from MapKey!", + "Type parameters cannot be targeted with is or as runtime type checks: \u003c[T__1]\u003e from AnyValue!", + "Unnecessary type check to String from expression with type String which is a subtype", + "Unnecessary type check to Boolean from expression with type Boolean which is a subtype", + "Unnecessary type check to Int32 from expression with type Int32 which is a subtype", + "Runtime type check from String to Int32 can never succeed!", + "Runtime type check from Int32 to String can never succeed!", + "Runtime type check from Null to Int32 can never succeed!", + "Unrelated types cannot be targeted with is or as runtime type checks: \u003c[Float64]\u003e from MapKey!", + "Types marked @mayDowncastTo(false) cannot be targeted with is or as runtime type checks because they may not be distinct on all backends: \u003c[Int32]\u003e from MapKey!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti/expect/run-result.json new file mode 100644 index 00000000..cc7a3b30 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti/expect/run-result.json @@ -0,0 +1 @@ +"void: Void" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti/work/test/test.temper new file mode 100644 index 00000000..e9ed5740 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/invalid-rtti/work/test/test.temper @@ -0,0 +1,46 @@ +class UnconnectedUserType {} + +let f( + a: AnyValue, + s: String, + son: String?, + i: Int, + ion: Int?, + f: Float64, + fon: Float64?, + b: Boolean, + bon: Boolean?, + n: Never?, + k: MapKey, +): Void throws Bubble { + // Illegal. Multiple other types could connect to target language string type + a as String orelse do {}; + a as Int orelse do {}; + a as Boolean orelse do {}; + k as String orelse do {}; + // Illegal, type formals can't be cast targets. + a as T orelse do {}; + // Does nothing. + s as String orelse do {}; + b as Boolean orelse do {}; + i as Int orelse do {}; + bon as Boolean?; + n as Never? orelse do {}; + // Ok. Can always check nullity + a as Never? orelse do {}; + son as Never? orelse do {}; + ion as Never? orelse do {}; + fon as Never? orelse do {}; + bon as Never? orelse do {}; + // Types are statically disjoint + s as Int orelse do {}; + i as String orelse do {}; + b as Never? orelse do {}; + n as Int orelse do {}; + k as Float64 orelse do {}; + k as Int orelse do {}; + // ok to unconnected class type. + a as UnconnectedUserType orelse do {}; + + // TODO: `is` equivalents of some of the above +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/is-applied-to-parameterized-type/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/is-applied-to-parameterized-type/expect/run-result.json new file mode 100644 index 00000000..474d8d71 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/is-applied-to-parameterized-type/expect/run-result.json @@ -0,0 +1 @@ +"[true, false]: List" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/is-applied-to-parameterized-type/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/is-applied-to-parameterized-type/work/test/test.temper new file mode 100644 index 00000000..194067a6 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/is-applied-to-parameterized-type/work/test/test.temper @@ -0,0 +1,9 @@ +sealed interface I {} +class A extends I {} +class B extends I {} + +let f(x: I): Boolean { + x is A +} + +[f(new A()), f(new B())] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/json-adapter-decodes-sealed-types/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/json-adapter-decodes-sealed-types/expect/run-result.json new file mode 100644 index 00000000..611f7478 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/json-adapter-decodes-sealed-types/expect/run-result.json @@ -0,0 +1 @@ +"[{meowCount: 137}, {hydrantsSniffed: 1337}]: List" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/json-adapter-decodes-sealed-types/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/json-adapter-decodes-sealed-types/work/test/test.temper new file mode 100644 index 00000000..7a246809 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/json-adapter-decodes-sealed-types/work/test/test.temper @@ -0,0 +1,20 @@ +let { + JsonTextProducer, + listJsonAdapter, + parseJson, + NullInterchangeContext, +} = import("std/json"); + +@json sealed interface Animal {} +@json class Cat(public meowCount: Int) extends Animal {} +@json class Dog(public hydrantsSniffed: Int) extends Animal {} + +let t = parseJson( + """ + "[ + " { "meowCount": 137 }, + " { "hydrantsSniffed": 1337 } + "] +); + +List.jsonAdapter(Animal.jsonAdapter()).decodeFromJson(t, NullInterchangeContext.instance) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/json-adapter-encodes-sealed-types/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/json-adapter-encodes-sealed-types/expect/run-result.json new file mode 100644 index 00000000..ce77dd3a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/json-adapter-encodes-sealed-types/expect/run-result.json @@ -0,0 +1 @@ +"\u0022[{\\\u0022meowCount\\\u0022:11},{\\\u0022hydrantsSniffed\\\u0022:111}]\u0022: String" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/json-adapter-encodes-sealed-types/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/json-adapter-encodes-sealed-types/work/test/test.temper new file mode 100644 index 00000000..cea3ed5d --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/json-adapter-encodes-sealed-types/work/test/test.temper @@ -0,0 +1,14 @@ +let { + JsonTextProducer, + listJsonAdapter, +} = import("std/json"); + +@json sealed interface Animal {} +@json class Cat(public meowCount: Int) extends Animal {} +@json class Dog(public hydrantsSniffed: Int) extends Animal {} + +let ls: List = [new Cat(11), new Dog(111)]; + +let p = new JsonTextProducer(); +List.jsonAdapter(Animal.jsonAdapter()).encodeToJson(ls, p); +p.toJsonString() diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/json-adapter-works/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/json-adapter-works/expect/run-result.json new file mode 100644 index 00000000..2ba8c66f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/json-adapter-works/expect/run-result.json @@ -0,0 +1 @@ +"{}: CJsonAdapter__0" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/json-adapter-works/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/json-adapter-works/work/test/test.temper new file mode 100644 index 00000000..9a3a3064 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/json-adapter-works/work/test/test.temper @@ -0,0 +1,2 @@ +@json class C {} +C.jsonAdapter() diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/json-interop-forwards-type-info-for-nullable-props/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/json-interop-forwards-type-info-for-nullable-props/expect/run-result.json new file mode 100644 index 00000000..612a3e0e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/json-interop-forwards-type-info-for-nullable-props/expect/run-result.json @@ -0,0 +1 @@ +"{i: null}: C__0" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/json-interop-forwards-type-info-for-nullable-props/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/json-interop-forwards-type-info-for-nullable-props/work/test/test.temper new file mode 100644 index 00000000..c54e8831 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/json-interop-forwards-type-info-for-nullable-props/work/test/test.temper @@ -0,0 +1,5 @@ +let { NullInterchangeContext, parseJson } = import("std/json"); + +@json class C(public i: Int?) {} + +C.jsonAdapter().decodeFromJson(parseJson('{"i": null}'), NullInterchangeContext.instance) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/long-null-chain/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/long-null-chain/expect/generateCode.temper new file mode 100644 index 00000000..407331b3 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/long-null-chain/expect/generateCode.temper @@ -0,0 +1,24 @@ +let return__0; +var t#0, t#1, t#2; +@stay @imported(\(`test//a/`.a)) let a__0; +a__0 = `test//a/`.a; +if (isNull(a__0)) { + t#0 = null +} else { + t#0 = do_get_string(notNull(a__0)) +}; +if (isNull(t#0)) { + t#1 = null +} else { + t#1 = do_get_isEmpty(notNull(t#0)) +}; +if (isNull(t#1)) { + t#2 = null +} else { + t#2 = do_call_toString(notNull(t#1)) +}; +if (isNull(t#2)) { + return__0 = "NULL" +} else { + return__0 = notNull(t#2) +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/long-null-chain/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/long-null-chain/expect/syntaxMacro.temper new file mode 100644 index 00000000..4219348d --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/long-null-chain/expect/syntaxMacro.temper @@ -0,0 +1,25 @@ +@stay @imported(\(`test//a/`.a)) let a__0 = `test//a/`.a; +{ + let subject#0; + subject#0 = { + let subject#1; + subject#1 = { + if (isNull(a__0)) { + null + } else { + do_get_string(notNull(a__0)) + } + }; + if (isNull(subject#1)) { + null + } else { + do_get_isEmpty(notNull(subject#1)) + } + }; + if (isNull(subject#0)) { + null + } else { + do_call_toString(notNull(subject#0)) + } +} +?? "NULL" diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/long-null-chain/work/test/a/a.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/long-null-chain/work/test/a/a.temper new file mode 100644 index 00000000..7216a9d9 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/long-null-chain/work/test/a/a.temper @@ -0,0 +1,3 @@ +export class A(public string: String) {} + +export let a: A? = new A("a"); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/long-null-chain/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/long-null-chain/work/test/test.temper new file mode 100644 index 00000000..00acf448 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/long-null-chain/work/test/test.temper @@ -0,0 +1,3 @@ +let {a} = import("./a"); +a?.string?.isEmpty?.toString() ?? "NULL" + diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/lotsa-lets/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/lotsa-lets/expect/run-result.json new file mode 100644 index 00000000..cc7a3b30 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/lotsa-lets/expect/run-result.json @@ -0,0 +1 @@ +"void: Void" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/lotsa-lets/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/lotsa-lets/work/test/test.temper new file mode 100644 index 00000000..41d7bb84 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/lotsa-lets/work/test/test.temper @@ -0,0 +1,31 @@ +// Issue 1408 +let x1 = 1; +let x2 = 2; +let x3 = 3; +let x4 = 4; +let x5 = 5; +let x6 = 6; +let x7 = 7; +let x8 = 8; +let x9 = 9; +let x10 = 10; +let x11 = 11; +let x12 = 12; +let x13 = 13; +let x14 = 14; +let x15 = 15; +let x16 = 16; +let x17 = 17; +let x18 = 18; +let x19 = 19; +let x20 = 20; +let x21 = 21; +let x22 = 22; +let x23 = 23; +let x24 = 24; +let x25 = 25; +let x26 = 26; +let x27 = 27; +let x28 = 28; +let x29 = 29; +let x30 = 30; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/map-type-arg/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/map-type-arg/work/test/test.temper new file mode 100644 index 00000000..186bed82 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/map-type-arg/work/test/test.temper @@ -0,0 +1,2 @@ +let ls: List = [1, 2]; +ls.map { (x: Int): String => x.toString(10) } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/match-with-char-expr-cases/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/match-with-char-expr-cases/expect/generateCode.temper new file mode 100644 index 00000000..6e686eb2 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/match-with-char-expr-cases/expect/generateCode.temper @@ -0,0 +1,19 @@ +@fn @reach(\none) let abcStop__0; +abcStop__0 = (@stay fn abcStop(i__0 /* aka i */: Int32) /* return__0 */: String { + var t#0, t#1; + if (i__0 == 97) { + t#1 = true + } else { + if (i__0 == 98) { + t#0 = true + } else { + t#0 = i__0 == 99 + }; + t#1 = t#0 + }; + if (t#1) { + return__0 = "ok" + } else { + return__0 = "stop" + } +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/match-with-char-expr-cases/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/match-with-char-expr-cases/work/test/test.temper new file mode 100644 index 00000000..3df8008d --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/match-with-char-expr-cases/work/test/test.temper @@ -0,0 +1,6 @@ +let abcStop(i: Int): String { + when (i) { + char 'a', char 'b', char 'c' -> "ok"; + else -> "stop"; + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/missing-function-body/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/missing-function-body/expect/errors.json new file mode 100644 index 00000000..bd53a76b --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/missing-function-body/expect/errors.json @@ -0,0 +1,3 @@ +[ + "Function body required except for virtual methods or connected functions!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/missing-function-body/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/missing-function-body/expect/generateCode.temper new file mode 100644 index 00000000..21e1461f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/missing-function-body/expect/generateCode.temper @@ -0,0 +1,5 @@ +@fn @reach(\none) let hi__0; +hi__0 = (@stay fn hi /* return__0 */: Void { + abstractPanic(); + return__0 = void +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/missing-function-body/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/missing-function-body/work/test/test.temper new file mode 100644 index 00000000..4968dc53 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/missing-function-body/work/test/test.temper @@ -0,0 +1 @@ +let hi(): Void; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/multi-import/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/multi-import/expect/generateCode.temper new file mode 100644 index 00000000..d131ef87 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/multi-import/expect/generateCode.temper @@ -0,0 +1,11 @@ +@stay @imported(\(`test//nums/`.a)) @reach(\none) let a__0; +a__0 = 1; +@imported(\(`test//nums/`.b)) @reach(\none) let b__0; +b__0 = 2; +@imported(\(`test//nums/`.c)) @reach(\none) let c__0; +c__0 = 3; +@imported(\(`test//nums/`.d)) @reach(\none) let d__0; +d__0 = 4; +@imported(\(`test//nums/`.e)) @reach(\none) let e__0; +e__0 = 5; +do_call_log(getConsole(), do_call_toString(15)) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/multi-import/work/test/nums/nums.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/multi-import/work/test/nums/nums.temper new file mode 100644 index 00000000..181c8130 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/multi-import/work/test/nums/nums.temper @@ -0,0 +1,5 @@ +export let a = 1; +export let b = 2; +export let c = 3; +export let d = 4; +export let e = 5; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/multi-import/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/multi-import/work/test/test.temper new file mode 100644 index 00000000..0fe874e5 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/multi-import/work/test/test.temper @@ -0,0 +1,4 @@ +let { ... } = import("./nums"); + +console.log((a + b + c + d + e).toString()); + diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-assignment-in-result-position/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-assignment-in-result-position/expect/generateCode.temper new file mode 100644 index 00000000..c5eab37a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-assignment-in-result-position/expect/generateCode.temper @@ -0,0 +1,4 @@ +let return__0, a__0, b__0; +b__0 = oneTwoThree(); +a__0 = b__0; +return__0 = a__0 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-assignment-in-result-position/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-assignment-in-result-position/expect/run-result.json new file mode 100644 index 00000000..002d085a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-assignment-in-result-position/expect/run-result.json @@ -0,0 +1 @@ +"123: Int32" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-assignment-in-result-position/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-assignment-in-result-position/work/test/test.temper new file mode 100644 index 00000000..b4e38022 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-assignment-in-result-position/work/test/test.temper @@ -0,0 +1,2 @@ +let a, b; +a = b = oneTwoThree() diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-setp-in-result-position/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-setp-in-result-position/expect/generateCode.temper new file mode 100644 index 00000000..4137387a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-setp-in-result-position/expect/generateCode.temper @@ -0,0 +1,30 @@ +let return__0; +@constructorProperty @property(\x) @visibility(\private) @stay @fromType(C__0) var x__0: Int32; +@constructorProperty @property(\y) @visibility(\private) @stay @fromType(C__0) var y__0: Int32; +@method(\f) @visibility(\public) @fn @stay @fromType(C__0) let f__0; +f__0 = (@stay fn f(@impliedThis(C__0) this__0: C__0) /* return__1 */: Int32 { + return__1 = oneTwoThree(); + setp(y__0, this__0, return__1); + setp(x__0, this__0, return__1) +}); +@fn @method(\constructor) @visibility(\public) @stay @fromType(C__0) let constructor__0; +constructor__0 = (@stay fn constructor(@impliedThis(C__0) this__1: C__0, @optional(true) x__1 /* aka x */: Int32?, @optional(true) y__1 /* aka y */: Int32?) /* return__2 */: Void { + let x__2 /* aka x */: Int32; + if (isNull(x__1)) { + x__2 = 0 + } else { + x__2 = notNull(x__1) + }; + let y__2 /* aka y */: Int32; + if (isNull(y__1)) { + y__2 = 0 + } else { + y__2 = notNull(y__1) + }; + setp(x__0, this__1, x__2); + setp(y__0, this__1, y__2); + return__2 = void +}); +@typeDecl(C__0) @stay let C__0; +C__0 = type (C__0); +return__0 = type (C__0) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-setp-in-result-position/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-setp-in-result-position/expect/run-result.json new file mode 100644 index 00000000..5ab92d17 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-setp-in-result-position/expect/run-result.json @@ -0,0 +1 @@ +"C__0: Type" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-setp-in-result-position/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-setp-in-result-position/work/test/test.temper new file mode 100644 index 00000000..eafb37d0 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-setp-in-result-position/work/test/test.temper @@ -0,0 +1,8 @@ +class C( + private var x: Int = 0, + private var y: Int = 0, +) { + public let f(): Int { + this.x = this.y = oneTwoThree() + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-setter-invocations-in-result-position/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-setter-invocations-in-result-position/expect/generateCode.temper new file mode 100644 index 00000000..61e0d66e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-setter-invocations-in-result-position/expect/generateCode.temper @@ -0,0 +1,21 @@ +let return__0, console#0; +console#0 = getConsole(); +@property(\p) @visibility(\public) @stay @fromType(C__0) let p__0; +@method(\p) @setter @visibility(\public) @fn @stay @fromType(C__0) let nym`set.p__1`; +nym`set.p__1` = (@stay fn nym`set.p`(@impliedThis(C__0) this__0: C__0, newValue__0 /* aka newValue */: Int32) /* return__1 */: Void { + var t#0; + t#0 = do_call_toString(newValue__0, 10); + do_call_log(console#0, cat("Assigned ", t#0)); + return__1 = void +}); +@fn @method(\constructor) @visibility(\public) @stay @fromType(C__0) let constructor__0; +constructor__0 = (@stay fn constructor(@impliedThis(C__0) this__1: C__0) /* return__2 */: Void { + return__2 = void +}); +@typeDecl(C__0) @stay let C__0; +C__0 = type (C__0); +let c__0; +c__0 = new C__0(); +return__0 = oneTwoThree(); +do_set_p(c__0, return__0); +do_set_p(c__0, return__0) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-setter-invocations-in-result-position/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-setter-invocations-in-result-position/expect/run-result.json new file mode 100644 index 00000000..002d085a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-setter-invocations-in-result-position/expect/run-result.json @@ -0,0 +1 @@ +"123: Int32" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-setter-invocations-in-result-position/expect/stdout.txt b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-setter-invocations-in-result-position/expect/stdout.txt new file mode 100644 index 00000000..8c0add1c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-setter-invocations-in-result-position/expect/stdout.txt @@ -0,0 +1,2 @@ +Assigned 123 +Assigned 123 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-setter-invocations-in-result-position/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-setter-invocations-in-result-position/work/test/test.temper new file mode 100644 index 00000000..aae8e8c0 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nested-setter-invocations-in-result-position/work/test/test.temper @@ -0,0 +1,7 @@ +class C { + public set p(newValue: Int) { + console.log("Assigned ${newValue.toString(10)}"); + } +} +let c = new C(); +c.p = c.p = oneTwoThree() diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/no-instantiate-interface/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/no-instantiate-interface/expect/errors.json new file mode 100644 index 00000000..8eb1b16a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/no-instantiate-interface/expect/errors.json @@ -0,0 +1,3 @@ +[ + "Cannot instantiate abstract type Apple!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/no-instantiate-interface/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/no-instantiate-interface/expect/generateCode.temper new file mode 100644 index 00000000..9cf016b5 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/no-instantiate-interface/expect/generateCode.temper @@ -0,0 +1,12 @@ +@typePlaceholder(Apple__0) let typePlaceholder#0: Empty; +typePlaceholder#0 = {class: Empty__0}; +@typeDecl(Apple__0) @stay let Apple__0; +Apple__0 = type (Apple__0); +@typeDecl(Banana__0) @stay let Banana__0; +Banana__0 = type (Banana__0); +@fn @method(\constructor) @visibility(\public) @stay @fromType(Banana__0) let constructor__0; +constructor__0 = (@stay fn constructor(@impliedThis(Banana__0) this__0: Banana__0) /* return__0 */: Void { + return__0 = void +}); +new Apple__0(); +new Banana__0() diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/no-instantiate-interface/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/no-instantiate-interface/work/test/test.temper new file mode 100644 index 00000000..a587751b --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/no-instantiate-interface/work/test/test.temper @@ -0,0 +1,4 @@ +interface Apple {} +class Banana {} +new Apple() +new Banana() diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/non-null-inference/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/non-null-inference/expect/generateCode.temper new file mode 100644 index 00000000..cfeb1672 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/non-null-inference/expect/generateCode.temper @@ -0,0 +1,11 @@ + @fn @reach(\none) let maybeLength__0; + maybeLength__0 = (@stay fn maybeLength(a__0 /* aka a */: String?) /* return__0 */: (Int32?) { + var t#0; + if (isNull(a__0)) { + return__0 = null + } else { +## In this branch, a is aliased to a#0 and is known to be not null. + t#0 = notNull(a__0); + return__0 = do_call_countBetween(t#0, getStatic(String, \begin), do_get_end(t#0)) + } + }) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/non-null-inference/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/non-null-inference/work/test/test.temper new file mode 100644 index 00000000..93b9fd03 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/non-null-inference/work/test/test.temper @@ -0,0 +1,4 @@ +let maybeLength(a: String?): Int? { + // Because of non-null inference, `a.end` is ok here. + a?.countBetween(String.begin, a.end) +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/null-assigned-to-non-null-var-devl/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/null-assigned-to-non-null-var-devl/expect/errors.json new file mode 100644 index 00000000..43ee9a53 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/null-assigned-to-non-null-var-devl/expect/errors.json @@ -0,0 +1,3 @@ +[ + "Expected subtype of StringBuilder, but got StringBuilder?!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/null-assigned-to-non-null-var-devl/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/null-assigned-to-non-null-var-devl/expect/generateCode.temper new file mode 100644 index 00000000..db79193e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/null-assigned-to-non-null-var-devl/expect/generateCode.temper @@ -0,0 +1,17 @@ +let return__0, @fn f__0; +f__0 = (@stay fn f(i__0 /* aka i */: Int32) /* return__1 */: String { + var sbOrNull__0: StringBuilder; + sbOrNull__0 = null; + if (i__0 % 2 == 0) { + let sbNow__0; + sbNow__0 = sbOrNull__0; + let sb__0; + sb__0 = sbNow__0; + do_call_append(sb__0, cat(do_call_toString(i__0))); + sbOrNull__0 = sb__0 + }; + let finalSb__0; + finalSb__0 = sbOrNull__0; + return__1 = do_call_toString(finalSb__0) +}); +return__0 = (fn f)(4) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/null-assigned-to-non-null-var-devl/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/null-assigned-to-non-null-var-devl/work/test/test.temper new file mode 100644 index 00000000..4eb86db4 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/null-assigned-to-non-null-var-devl/work/test/test.temper @@ -0,0 +1,17 @@ +let f(i: Int32): String { + var sbOrNull: StringBuilder = null; + // ^ No `?` + if (i % 2 == 0) { + let sbNow = sbOrNull; + let sb = sbNow ?? new StringBuilder(); + sb.append("${i}"); + sbOrNull = sb; + } + let finalSb = sbOrNull; + if (finalSb == null) { + "" + } else { + finalSb.toString() + } +} +f(4) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/null-in-testing-assert/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/null-in-testing-assert/expect/generateCode.temper new file mode 100644 index 00000000..a000f6af --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/null-in-testing-assert/expect/generateCode.temper @@ -0,0 +1,28 @@ + @stay @imported(\(`test//c/`.C)) @reach(\test) let C__0; + C__0 = type (C); + @stay @imported(\(`std//testing/`.Test)) @reach(\test) let Test__0; + Test__0 = type (Test); + @fn @test("to be or not to be null") let toBeOrNotToBeNull__0; + toBeOrNotToBeNull__0 = (@stay fn toBeOrNotToBeNull(test#0: Test) /* return__0 */: (Void | Bubble) { + var t#0; + let c0__0; + c0__0 = new C(""); + let actual#0; + actual#0 = do_get_optionalString(c0__0); +## Here's the assertion predicate + t#0 = actual#0 == ""; +## Here's a block that computes the failure message if the predicate is false. + let fn__0; + fn__0 = (@stay fn /* return__1 */{ + var t#1; +## Here we're picking a string representation of the actual expression result + if (isNull(actual#0)) { + t#1 = "null" + } else { + t#1 = do_call_toString(notNull(actual#0)) + }; + return__1 = cat("expected c0.optionalString == (", "", ") not (", t#1, ")") + }); + do_call_assert(test#0, t#0, fn__0); + return__0 = void + }) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/null-in-testing-assert/work/test/c/c.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/null-in-testing-assert/work/test/c/c.temper new file mode 100644 index 00000000..c9c577b9 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/null-in-testing-assert/work/test/c/c.temper @@ -0,0 +1 @@ +export class C(public optionalString: String?) {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/null-in-testing-assert/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/null-in-testing-assert/work/test/test.temper new file mode 100644 index 00000000..245ced82 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/null-in-testing-assert/work/test/test.temper @@ -0,0 +1,7 @@ +let { C } = import("./c"); + +test("to be or not to be null") { + let c0 = { optionalString: "" }; + assert(c0.optionalString == ""); +} + diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/null-simplification/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/null-simplification/expect/generateCode.temper new file mode 100644 index 00000000..21193964 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/null-simplification/expect/generateCode.temper @@ -0,0 +1,7 @@ +@fn @reach(\none) let f__0, @fn @reach(\none) g__0; +f__0 = (@stay fn f(s__0 /* aka s */: String?) /* return__0 */: Boolean { + return__0 = isNull(s__0) +}); +g__0 = (@stay fn g(s__1 /* aka s */: String?) /* return__1 */: Boolean { + return__1 = !isNull(s__1) +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/null-simplification/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/null-simplification/work/test/test.temper new file mode 100644 index 00000000..ef79bbba --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/null-simplification/work/test/test.temper @@ -0,0 +1,6 @@ +let f(s: String?): Boolean { + s == null +} +let g(s: String?): Boolean { + s != null +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nullable-json-field/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nullable-json-field/expect/run-result.json new file mode 100644 index 00000000..3ff5cdcf --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nullable-json-field/expect/run-result.json @@ -0,0 +1 @@ +"[null, false, true]: List" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nullable-json-field/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nullable-json-field/work/test/test.temper new file mode 100644 index 00000000..b650b5cc --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/nullable-json-field/work/test/test.temper @@ -0,0 +1,10 @@ +let { + NullInterchangeContext, + OrNullJsonAdapter, + booleanJsonAdapter, + listJsonAdapter, + parseJson, +} = import("std/json"); +let a = List.jsonAdapter(new OrNullJsonAdapter(Boolean.jsonAdapter())); + +a.decodeFromJson(parseJson("[null, false, true]"), NullInterchangeContext.instance) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/optional-argument-passing/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/optional-argument-passing/expect/run-result.json new file mode 100644 index 00000000..83793868 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/optional-argument-passing/expect/run-result.json @@ -0,0 +1 @@ +"\u0022a=2, b=1; a=0, b=2; a=3, b=2\u0022: String" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/optional-argument-passing/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/optional-argument-passing/work/test/test.temper new file mode 100644 index 00000000..6e37363a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/optional-argument-passing/work/test/test.temper @@ -0,0 +1,2 @@ +let f(a: Int = 0, b: Int = 1): String { "a=${a.toString()}, b=${b.toString()}" }; +"${ f(2) }; ${ f(null, 2) }; ${ f(3, 2) }" diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/pure-virtual-method-in-concrete-class/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/pure-virtual-method-in-concrete-class/expect/errors.json new file mode 100644 index 00000000..b2f5239a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/pure-virtual-method-in-concrete-class/expect/errors.json @@ -0,0 +1,3 @@ +[ + "Type C must implement f from I. Maybe add `public f(x: String): Void`!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/pure-virtual-method-in-concrete-class/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/pure-virtual-method-in-concrete-class/expect/run-result.json new file mode 100644 index 00000000..cc7a3b30 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/pure-virtual-method-in-concrete-class/expect/run-result.json @@ -0,0 +1 @@ +"void: Void" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/pure-virtual-method-in-concrete-class/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/pure-virtual-method-in-concrete-class/work/test/test.temper new file mode 100644 index 00000000..3c3d984e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/pure-virtual-method-in-concrete-class/work/test/test.temper @@ -0,0 +1,4 @@ +export interface I { f(x: T): Void; } +export class C extends I { + // but does not override f() +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/raw-cats-get-cooked/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/raw-cats-get-cooked/expect/define.temper new file mode 100644 index 00000000..269e1c97 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/raw-cats-get-cooked/expect/define.temper @@ -0,0 +1,8 @@ +@fn let f__0; +f__0 = fn f(s__0 /* aka s */: String) /* return__1 */: Void { + fn__0: do { + cat(s__0); + void; + cat(what); + } +}; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/raw-cats-get-cooked/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/raw-cats-get-cooked/expect/errors.json new file mode 100644 index 00000000..0ffea786 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/raw-cats-get-cooked/expect/errors.json @@ -0,0 +1,3 @@ +[ + "No declaration for what!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/raw-cats-get-cooked/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/raw-cats-get-cooked/expect/generateCode.temper new file mode 100644 index 00000000..0c542b31 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/raw-cats-get-cooked/expect/generateCode.temper @@ -0,0 +1,6 @@ +@fn @reach(\none) let f__0; +f__0 = (@stay fn f(s__0 /* aka s */: String) /* return__1 */: Void { + cat(s__0); + cat(what); + return__1 = void +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/raw-cats-get-cooked/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/raw-cats-get-cooked/work/test/test.temper new file mode 100644 index 00000000..79a30297 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/raw-cats-get-cooked/work/test/test.temper @@ -0,0 +1,5 @@ +let f(s: String): Void { + raw"${s}"; + // Also a call that will fail, so we make sure to test that. + raw"${what}"; +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/return-type-optional-for-some-cases/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/return-type-optional-for-some-cases/expect/errors.json new file mode 100644 index 00000000..3e9e9f8f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/return-type-optional-for-some-cases/expect/errors.json @@ -0,0 +1,3 @@ +[ + "Explicit return type required!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/return-type-optional-for-some-cases/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/return-type-optional-for-some-cases/expect/generateCode.temper new file mode 100644 index 00000000..62f506e6 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/return-type-optional-for-some-cases/expect/generateCode.temper @@ -0,0 +1,15 @@ +@method(\constructor) @visibility(\public) @fn @stay @fromType(Something__0) @reach(\none) let constructor__0; +constructor__0 = (@stay fn constructor(@impliedThis(Something__0) this__0: Something__0) /* return__0 */: Void { + return__0 = void +}); +@property(\blah) @visibility(\public) @stay @fromType(Something__0) @reach(\none) let blah__0; +@method(\blah) @getter @visibility(\public) @fn @stay @fromType(Something__0) @reach(\none) let nym`get.blah__1`; +nym`get.blah__1` = (@stay fn nym`get.blah`(@impliedThis(Something__0) this__1: Something__0) /* return__1 */{ + return__1 = 5 +}); +@method(\blah) @setter @visibility(\public) @fn @stay @fromType(Something__0) @reach(\none) let nym`set.blah__2`; +nym`set.blah__2` = (@stay fn nym`set.blah`(@impliedThis(Something__0) this__2: Something__0, x__0 /* aka x */: Int32) /* return__2 */: Void { + return__2 = void +}); +@typeDecl(Something__0) @stay @reach(\none) let Something__0; +Something__0 = type (Something__0) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/return-type-optional-for-some-cases/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/return-type-optional-for-some-cases/work/test/test.temper new file mode 100644 index 00000000..2c8eda26 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/return-type-optional-for-some-cases/work/test/test.temper @@ -0,0 +1,5 @@ +class Something { + public constructor() {} // return type implied + public get blah() { 5 } // return type required but missing + public set blah(x: Int) {} // return type implied +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/return-type-required/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/return-type-required/expect/errors.json new file mode 100644 index 00000000..3e9e9f8f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/return-type-required/expect/errors.json @@ -0,0 +1,3 @@ +[ + "Explicit return type required!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/return-type-required/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/return-type-required/expect/generateCode.temper new file mode 100644 index 00000000..f959389a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/return-type-required/expect/generateCode.temper @@ -0,0 +1,4 @@ +@fn @reach(\none) let hi__0; +hi__0 = (@stay fn hi /* return__1 */{ + return__1 = void +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/return-type-required/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/return-type-required/work/test/test.temper new file mode 100644 index 00000000..bdac4f67 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/return-type-required/work/test/test.temper @@ -0,0 +1 @@ +let hi() {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/rgx-macro/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/rgx-macro/expect/run-result.json new file mode 100644 index 00000000..016ed87c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/rgx-macro/expect/run-result.json @@ -0,0 +1 @@ +"{data: {}, compiled: ƒ}: `std/regex/`.Regex" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/rgx-macro/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/rgx-macro/work/test/test.temper new file mode 100644 index 00000000..e9f91209 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/rgx-macro/work/test/test.temper @@ -0,0 +1,3 @@ +let { ... } = import("std/regex"); + +rgx"." diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/sealed-connected-casts/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/sealed-connected-casts/expect/errors.json new file mode 100644 index 00000000..49d2b743 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/sealed-connected-casts/expect/errors.json @@ -0,0 +1,4 @@ +[ + "Connected types cannot be targeted with is or as runtime type checks because multiple Temper types are allowed to connect to the same backend type: \u003c[C__1]\u003e from AnyValue!", + "Connected types cannot be targeted with is or as runtime type checks because multiple Temper types are allowed to connect to the same backend type: \u003c[E__4]\u003e from S!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/sealed-connected-casts/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/sealed-connected-casts/expect/run-result.json new file mode 100644 index 00000000..cc7a3b30 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/sealed-connected-casts/expect/run-result.json @@ -0,0 +1 @@ +"void: Void" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/sealed-connected-casts/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/sealed-connected-casts/work/test/test.temper new file mode 100644 index 00000000..60597e4a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/sealed-connected-casts/work/test/test.temper @@ -0,0 +1,18 @@ +@connected +export sealed interface S {} + +@connected +class C extends S {} +@connected +class D extends S {} + +@connected +interface NS extends S {} +@connected +class E extends NS {} + +export let f(a: AnyValue, s: S): Void throws Bubble { + a as C; // BAD: C is connected, and AnyValue is not. + s as C; // OK. C is a sub-type of S + s as E; // BAD. E is a sub-type of S, but only via NS which is not-sealed. +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/sealed-when/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/sealed-when/expect/errors.json new file mode 100644 index 00000000..26819f4e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/sealed-when/expect/errors.json @@ -0,0 +1,5 @@ +[ + "Cannot assign to String from Void!", + "Expected subtype of String, but got Void!", + "Void expressions cannot be used as values!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/sealed-when/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/sealed-when/expect/generateCode.temper new file mode 100644 index 00000000..0fca0e6b --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/sealed-when/expect/generateCode.temper @@ -0,0 +1,44 @@ +@typeDecl(Geometric) @stay let `test//`.Geometric ⦂ Type; +`test//`.Geometric = type (Geometric); +@typeDecl(Ray) @stay let `test//`.Ray ⦂ Type; +`test//`.Ray = type (Ray); +@typeDecl(Shape) @stay @sealedType let `test//`.Shape ⦂ Type; +`test//`.Shape = type (Shape); +@typeDecl(Circle) @stay let `test//`.Circle ⦂ Type; +`test//`.Circle = type (Circle); +@typeDecl(Square) @stay let `test//`.Square ⦂ Type; +`test//`.Square = type (Square); +@fn let `test//`.describeGeometric ⦂(fn (Geometric): String), @fn `test//`.describeShape ⦂(fn (Shape): String), @typePlaceholder(Geometric) typePlaceholder#0: Empty; +typePlaceholder#0 = {class: Empty__0}; +@fn @visibility(\public) @stay @fromType(Ray) let constructor__0 ⦂(fn (Ray): Void); +constructor__0 = (@stay fn constructor(@impliedThis(Ray) this__0: Ray) /* return__0 */: Void { + return__0 = void +}); +@typePlaceholder(Shape) let typePlaceholder#1: Empty; +typePlaceholder#1 = {class: Empty__0}; +@fn @visibility(\public) @stay @fromType(Circle) let constructor__1 ⦂(fn (Circle): Void); +constructor__1 = (@stay fn constructor(@impliedThis(Circle) this__1: Circle) /* return__1 */: Void { + return__1 = void +}); +@fn @visibility(\public) @stay @fromType(Square) let constructor__2 ⦂(fn (Square): Void); +constructor__2 = (@stay fn constructor(@impliedThis(Square) this__2: Square) /* return__2 */: Void { + return__2 = void +}); +`test//`.describeGeometric = (@stay fn describeGeometric(g__0 /* aka g */: Geometric) /* return__3 */: String { + if (g__0 is Circle) { + return__3 = "circle" + } else if (g__0 is Square) { + return__3 = "square" + } else { + return__3 = void + } +}); +`test//`.describeShape = (@stay fn describeShape(s__0 /* aka s */: Shape) /* return__4 */: String { + if (s__0 is Circle) { + return__4 = "circle" + } else if (s__0 is Square) { + return__4 = "square" + } else { + return__4 = panic ⋖ String ⋗() + } +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/sealed-when/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/sealed-when/work/test/test.temper new file mode 100644 index 00000000..96705eea --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/sealed-when/work/test/test.temper @@ -0,0 +1,19 @@ +export interface Geometric {} +export class Ray extends Geometric {} +export sealed interface Shape extends Geometric {} +export class Circle() extends Shape {} +export class Square() extends Shape {} +export let describeGeometric(g: Geometric): String { + when (g) { + is Circle -> "circle"; + is Square -> "square"; + // defaults to void here because it starts above the sealed type + } +} +export let describeShape(s: Shape): String { + when (s) { + is Circle -> "circle"; + is Square -> "square"; + // defaults to panic here because those are exhaustive for Shape + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/simple-do-nothing-loop/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/simple-do-nothing-loop/expect/generateCode.temper new file mode 100644 index 00000000..5ba0ce22 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/simple-do-nothing-loop/expect/generateCode.temper @@ -0,0 +1,5 @@ +var i__0; +i__0 = 0; +while (i__0 < 3) { + i__0 = i__0 + 1 +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/simple-do-nothing-loop/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/simple-do-nothing-loop/expect/type.temper new file mode 100644 index 00000000..e46f6800 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/simple-do-nothing-loop/expect/type.temper @@ -0,0 +1,5 @@ +var i__0; +i__0 = 0; +while (i__0 < 3) { + i__0 = i__0 + 1; +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/simple-do-nothing-loop/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/simple-do-nothing-loop/work/test/test.temper new file mode 100644 index 00000000..83bc8b6b --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/simple-do-nothing-loop/work/test/test.temper @@ -0,0 +1,11 @@ +// This example is interesting because the infer result pass actually adds two assignments +// to gather results from terminal expression. +// +// This may be a bug, but in the meantime, it leads to a nested assignment of temporaries: +// `t#0 = t#1 = hs(fail#2, i < 3)` +// +// The generate code stage needs to unnest this assignment before the TmpL backend can +// translate it. If the TmpL backend were to try to handle this by creating temporaries, +// those would miss type information. +var i = 0; +while (i < 3) { ++i; } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/simple-method-call/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/simple-method-call/expect/run-result.json new file mode 100644 index 00000000..bd9466c1 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/simple-method-call/expect/run-result.json @@ -0,0 +1,4 @@ +[ + "1", + "String" +] \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/simple-method-call/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/simple-method-call/work/test/test.temper new file mode 100644 index 00000000..e72bde82 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/simple-method-call/work/test/test.temper @@ -0,0 +1 @@ +1.toString() diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/sneaky-bubble/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/sneaky-bubble/expect/generateCode.temper new file mode 100644 index 00000000..a9bb9b16 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/sneaky-bubble/expect/generateCode.temper @@ -0,0 +1,12 @@ +@constructorProperty @visibility(\public) @stay @fromType(Something__0) @reach(\none) let haha__0: Int32?; +@fn @visibility(\public) @stay @fromType(Something__0) @reach(\none) let constructor__0; +constructor__0 = (@stay fn constructor(@impliedThis(Something__0) this__0: Something__0, haha__1 /* aka haha */: Int32?) /* return__0 */: Void { + setp(haha__0, this__0, haha__1); + return__0 = void +}); +@fn @visibility(\public) @stay @fromType(Something__0) @reach(\none) let gethaha__0; +gethaha__0 = (@stay fn (@impliedThis(Something__0) this__1: Something__0) /* return__1 */: (Int32?) { + return__1 = getp(haha__0, this__1) +}); +@typeDecl(Something__0) @stay @reach(\none) let Something__0; +Something__0 = type (Something__0) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/sneaky-bubble/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/sneaky-bubble/work/test/test.temper new file mode 100644 index 00000000..8834fa5e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/sneaky-bubble/work/test/test.temper @@ -0,0 +1 @@ +class Something(public let haha: Int?) {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-access-good-and-bad/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-access-good-and-bad/expect/errors.json new file mode 100644 index 00000000..57be8926 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-access-good-and-bad/expect/errors.json @@ -0,0 +1,10 @@ +[ + "Type name required for accessing static member!", + "Type name required for accessing static member!", + "Type name required for accessing static member!", + "Type name required for accessing static member!", + "Type name required for accessing static member!", + "Type name required for accessing static member!", + "Type name required for accessing static member!", + "Member ap defined in C__0 not publicly accessible!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-access-good-and-bad/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-access-good-and-bad/expect/generateCode.temper new file mode 100644 index 00000000..559c26be --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-access-good-and-bad/expect/generateCode.temper @@ -0,0 +1,44 @@ +@typeDecl(C__0) @stay @reach(\none) let C__0; +C__0 = type (C__0); +@fn @reach(\none) let g3__0; +@static @visibility(\private) @stay @fromType(C__0) @reach(\none) let ap__0: Int32; +ap__0 = 1; +@static @visibility(\public) @stay @fromType(C__0) @reach(\none) let a__0: Int32; +a__0 = 2; +@visibility(\private) @stay @fromType(C__0) @reach(\none) let bp__0: Int32; +@visibility(\private) @stay @fromType(C__0) @reach(\none) let b__0: Int32; +@fn @static @visibility(\public) @stay @fromType(C__0) @reach(\none) let f__0; +f__0 = (@stay fn f(i__0 /* aka i */: Int32) /* return__0 */: Int32 { + return__0 = i__0 + 2 + igetStatic(C__0, \a) + 1 + igetStatic(C__0, \ap) +}); +@fn @static @visibility(\private) @stay @fromType(C__0) @reach(\none) let fp__0; +fp__0 = (@stay fn fp(i__1 /* aka i */: Int32) /* return__1 */: Int32 { + return__1 = i__1 + 1 +}); +@visibility(\public) @fn @stay @fromType(C__0) @reach(\none) let g__0; +g__0 = (@stay fn g(@impliedThis(C__0) this__0: C__0, i__2 /* aka i */: Int32) /* return__2 */: Int32 { + return__2 = 2 * igetStatic(C__0, \f)(i__2) * igetStatic(C__0, \fp)(i__2) * getp(bp__0, this__0) * getp(b__0, this__0) * getp(bp__0, this__0) * getp(b__0, this__0) +}); +@visibility(\public) @fn @stay @fromType(C__0) @reach(\none) let h__0; +h__0 = (@stay fn h(@impliedThis(C__0) this__1: C__0, i__3 /* aka i */: Int32) /* return__3 */: Int32 { + return__3 = 2 * (fn f)(i__3) * (fn fp)(i__3) * do_icall_g(type (C__0), this__1, i__3) * do_icall_g(type (C__0), this__1, i__3) +}); +@fn @static @visibility(\public) @stay @fromType(C__0) @reach(\none) let g2__0; +g2__0 = (@stay fn g2(i__4 /* aka i */: Int32) /* return__4 */: Int32 { + return__4 = 2 * igetStatic(C__0, \f)(i__4) * igetStatic(C__0, \fp)(i__4) +}); +@fn @static @visibility(\public) @stay @fromType(C__0) @reach(\none) let h2__0; +h2__0 = (@stay fn h2(i__5 /* aka i */: Int32) /* return__5 */: Int32 { + return__5 = 2 * (fn f)(i__5) * (fn fp)(i__5) +}); +@fn @visibility(\public) @stay @fromType(C__0) @reach(\none) let constructor__0; +constructor__0 = (@stay fn constructor(@impliedThis(C__0) this__2: C__0) /* return__6 */: Void { + var t#1; + setp(bp__0, this__2, 1); + t#1 = getp(bp__0, this__2) + 1; + setp(b__0, this__2, t#1); + return__6 = void +}); +g3__0 = (@stay fn g3(i__6 /* aka i */: Int32) /* return__7 */: Int32 { + return__7 = 2 * getStatic(C__0, \f)(i__6) * do_call_g(new C__0(), i__6) * getStatic(C__0, \a) * getStatic(C__0, \ap) +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-access-good-and-bad/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-access-good-and-bad/expect/syntaxMacro.temper new file mode 100644 index 00000000..b604922d --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-access-good-and-bad/expect/syntaxMacro.temper @@ -0,0 +1,55 @@ +@typeDecl(C__0) @stay let C__0 = type (C__0); +@fn let g3__0; +class(\word, \C, \concrete, true, @typeDefined(C__0) fn { + C__0 extends AnyValue; + @static @visibility(\private) let ap__0: Int = 1; + @static @visibility(\public) let a__0: Int = ap__0 + igetStatic(C__0, \ap); + @maybeVar @visibility(\private) let bp__0: Int; + @maybeVar @visibility(\private) let b__0: Int; + @fn @static @visibility(\public) let f__0 = fn f(i__0 /* aka i */: Int) /* return__0 */: (Int) { + fn__0: do { + i__0 + a__0 + igetStatic(C__0, \a) + ap__0 + igetStatic(C__0, \ap) + } + }; + @fn @static @visibility(\private) let fp__0 = fn fp(i__1 /* aka i */: Int) /* return__1 */: (Int) { + fn__1: do { + i__1 + 1 + } + }; + @visibility(\public) @fn let g__0 = fn g(@impliedThis(C__0) this__0: C__0, i__2 /* aka i */: Int) /* return__2 */: (Int) { + fn__2: do { + 2 * igetStatic(C__0, \f)(i__2) * igetStatic(C__0, \fp)(i__2) * do_iget_bp(type (C__0), this(C__0)) * do_iget_b(type (C__0), this(C__0)) * do_iget_bp(type (C__0), this(C__0)) * do_iget_b(type (C__0), this(C__0)) + } + }; + @visibility(\public) @fn let h__0 = fn h(@impliedThis(C__0) this__1: C__0, i__3 /* aka i */: Int) /* return__3 */: (Int) { + fn__3: do { + 2 * f__0(i__3) * fp__0(i__3) * do_icall_g(type (C__0), this(C__0), i__3) * do_icall_g(type (C__0), this(C__0), i__3) + } + }; + @fn @static @visibility(\public) let g2__0 = fn g2(i__4 /* aka i */: Int) /* return__4 */: (Int) { + fn__4: do { + 2 * igetStatic(C__0, \f)(i__4) * igetStatic(C__0, \fp)(i__4) + } + }; + @fn @static @visibility(\public) let h2__0 = fn h2(i__5 /* aka i */: Int) /* return__5 */: (Int) { + fn__5: do { + 2 * f__0(i__5) * fp__0(i__5) + } + }; + @visibility(\public) let constructor__0 = fn constructor(@impliedThis(C__0) this__2: C__0) /* return__6 */: Void { + do { + do_iset_bp(type (C__0), this(C__0), 1); + 1 + }; + do { + let t#0; + do_iset_b(type (C__0), this(C__0), t#0 = do_iget_bp(type (C__0), this(C__0)) + 1); + t#0 + }; + }; +}); +g3__0 = fn g3(i__6 /* aka i */: Int) /* return__7 */: (Int) { + fn__6: do { + 2 * do_call_f(C__0, i__6) * do_call_g(new C__0(), i__6) * do_get_a(C__0) * do_get_ap(C__0) + } +}; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-access-good-and-bad/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-access-good-and-bad/expect/type.temper new file mode 100644 index 00000000..ac41e08f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-access-good-and-bad/expect/type.temper @@ -0,0 +1,65 @@ +@typeDecl(C__0) @stay let C__0; +C__0 = type (C__0); +@fn let g3__0; +@static @visibility(\private) @stay @fromType(C__0) let ap__0: Int32; +ap__0 = 1; +@static @visibility(\public) @stay @fromType(C__0) let a__0: Int32; +a__0 = 2; +@visibility(\private) @stay @fromType(C__0) let bp__0: Int32; +@visibility(\private) @stay @fromType(C__0) let b__0: Int32; +@fn @static @visibility(\public) @stay @fromType(C__0) let f__0; +f__0 = (@stay fn f(i__0 /* aka i */: Int32) /* return__0 */: Int32 { + void; + fn__0: do { + return__0 = i__0 + 2 + igetStatic(C__0, \a) + 1 + igetStatic(C__0, \ap); + } +}); +@fn @static @visibility(\private) @stay @fromType(C__0) let fp__0; +fp__0 = (@stay fn fp(i__1 /* aka i */: Int32) /* return__1 */: Int32 { + void; + fn__1: do { + return__1 = i__1 + 1; + } +}); +@visibility(\public) @fn @stay @fromType(C__0) let g__0; +g__0 = fn g(@impliedThis(C__0) this__0: C__0, i__2 /* aka i */: Int32) /* return__2 */: Int32 { + void; + fn__2: do { + return__2 = 2 * igetStatic(C__0, \f)(i__2) * igetStatic(C__0, \fp)(i__2) * getp(bp__0, this__0) * getp(b__0, this__0) * getp(bp__0, this__0) * getp(b__0, this__0); + } +}; +@visibility(\public) @fn @stay @fromType(C__0) let h__0; +h__0 = (@stay fn h(@impliedThis(C__0) this__1: C__0, i__3 /* aka i */: Int32) /* return__3 */: Int32 { + void; + fn__3: do { + return__3 = 2 * (fn f)(i__3) * (fn fp)(i__3) * do_icall_g(type (C__0), this__1, i__3) * do_icall_g(type (C__0), this__1, i__3); + } +}); +@fn @static @visibility(\public) @stay @fromType(C__0) let g2__0; +g2__0 = fn g2(i__4 /* aka i */: Int32) /* return__4 */: Int32 { + void; + fn__4: do { + return__4 = 2 * igetStatic(C__0, \f)(i__4) * igetStatic(C__0, \fp)(i__4); + } +}; +@fn @static @visibility(\public) @stay @fromType(C__0) let h2__0; +h2__0 = (@stay fn h2(i__5 /* aka i */: Int32) /* return__5 */: Int32 { + void; + fn__5: do { + return__5 = 2 * (fn f)(i__5) * (fn fp)(i__5); + } +}); +@fn @visibility(\public) @stay @fromType(C__0) let constructor__0; +constructor__0 = (@stay fn constructor(@impliedThis(C__0) this__2: C__0) /* return__6 */: Void { + var t#1; + setp(bp__0, this__2, 1); + t#1 = getp(bp__0, this__2) + 1; + setp(b__0, this__2, t#1); + return__6 = void +}); +g3__0 = (@stay fn g3(i__6 /* aka i */: Int32) /* return__7 */: Int32 { + void; + fn__6: do { + return__7 = 2 * getStatic(C__0, \f)(i__6) * do_call_g(new C__0(), i__6) * getStatic(C__0, \a) * getStatic(C__0, \ap); + } +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-access-good-and-bad/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-access-good-and-bad/work/test/test.temper new file mode 100644 index 00000000..bbab423a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-access-good-and-bad/work/test/test.temper @@ -0,0 +1,13 @@ +class C { + private static ap: Int = 1; + public static a: Int = ap + C.ap; + private bp: Int = 1; + private b: Int = bp + 1; + public static f(i: Int): Int { i + a + C.a + ap + C.ap } + private static fp(i: Int): Int { i + 1 } + public g(i: Int): Int { 2 * C.f(i) * C.fp(i) * bp * b * this.bp * this.b } + public h(i: Int): Int { 2 * f(i) * fp(i) * g(i) * this.g(i) } + public static g2(i: Int): Int { 2 * C.f(i) * C.fp(i) } + public static h2(i: Int): Int { 2 * f(i) * fp(i) } +} +let g3(i: Int): Int { 2 * C.f(i) * new C().g(i) * C.a * C.ap } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-methods/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-methods/expect/generateCode.temper new file mode 100644 index 00000000..782c3c1c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-methods/expect/generateCode.temper @@ -0,0 +1,12 @@ +let return__0; +@staticProperty(\f) @fn @static @visibility(\public) @stay @fromType(C__0) @reach(\none) let f__0; +f__0 = (@stay fn f(i__0 /* aka i */: Int32) /* return__1 */: Int32 { + return__1 = i__0 + 1 +}); +@fn @method(\constructor) @visibility(\public) @stay @fromType(C__0) @reach(\none) let constructor__0; +constructor__0 = (@stay fn constructor(@impliedThis(C__0) this__0: C__0) /* return__2 */: Void { + return__2 = void +}); +@typeDecl(C__0) @stay @reach(\none) let C__0; +C__0 = type (C__0); +return__0 = 1 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-methods/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-methods/work/test/test.temper new file mode 100644 index 00000000..97f5ef60 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-methods/work/test/test.temper @@ -0,0 +1,4 @@ +class C { + public static let f(i: Int): Int { i + 1 } +} +C.f(0) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-with-unused-extension/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-with-unused-extension/expect/run-result.json new file mode 100644 index 00000000..cc7a3b30 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-with-unused-extension/expect/run-result.json @@ -0,0 +1 @@ +"void: Void" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-with-unused-extension/expect/stdout.txt b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-with-unused-extension/expect/stdout.txt new file mode 100644 index 00000000..3a79ba44 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-with-unused-extension/expect/stdout.txt @@ -0,0 +1 @@ +C foo diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-with-unused-extension/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-with-unused-extension/work/test/test.temper new file mode 100644 index 00000000..9e26f22e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/static-with-unused-extension/work/test/test.temper @@ -0,0 +1,12 @@ +@staticExtension(String, "foo") +let strFoo(): Void { + console.log("string foo"); +} + +class C { + public static foo(): Void { + console.log("C foo"); + } +} + +C.foo(); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/string-coercion-of-rtti-check/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/string-coercion-of-rtti-check/expect/generateCode.temper new file mode 100644 index 00000000..e01e41c8 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/string-coercion-of-rtti-check/expect/generateCode.temper @@ -0,0 +1,12 @@ + let console#0; + console#0 = getConsole(); + @fn let f__0; + f__0 = (@stay fn f(i__0 /* aka i */: StringIndexOption) /* return__0 */: Void { + var t#0, t#1; +## str has erased to a .toString() call here + t#0 = do_call_toString(i__0 is StringIndex); + t#1 = do_call_toString(i__0 is NoStringIndex); + do_call_log(console#0, cat("Yes ", t#0, ", no ", t#1)); + return__0 = void + }); + f__0(getStatic(String, \begin)) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/string-coercion-of-rtti-check/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/string-coercion-of-rtti-check/expect/run-result.json new file mode 100644 index 00000000..cc7a3b30 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/string-coercion-of-rtti-check/expect/run-result.json @@ -0,0 +1 @@ +"void: Void" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/string-coercion-of-rtti-check/expect/stdout.txt b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/string-coercion-of-rtti-check/expect/stdout.txt new file mode 100644 index 00000000..33836bbb --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/string-coercion-of-rtti-check/expect/stdout.txt @@ -0,0 +1 @@ +Yes true, no false diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/string-coercion-of-rtti-check/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/string-coercion-of-rtti-check/work/test/test.temper new file mode 100644 index 00000000..047dfb64 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/string-coercion-of-rtti-check/work/test/test.temper @@ -0,0 +1,5 @@ +let f(i: StringIndexOption): Void { + console.log("Yes ${i is StringIndex}, no ${i is NoStringIndex }"); +} + +f(String.begin) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/string-null-equality/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/string-null-equality/expect/run-result.json new file mode 100644 index 00000000..2073eb51 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/string-null-equality/expect/run-result.json @@ -0,0 +1 @@ +"true: Boolean" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/string-null-equality/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/string-null-equality/work/test/test.temper new file mode 100644 index 00000000..bb21b754 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/string-null-equality/work/test/test.temper @@ -0,0 +1,3 @@ +let f(s: String?): Boolean { s == null } + +!f("") && f(null) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/type-metadata/expect/generateCode-types.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/type-metadata/expect/generateCode-types.json new file mode 100644 index 00000000..2e562c73 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/type-metadata/expect/generateCode-types.json @@ -0,0 +1,39 @@ +{ + "I": { + "name": "I__0", + "abstract": true, + "supers": [ + "AnyValue__0" + ], + "metadata": { + "foo": [ + "void: Void" + ], + "reach": [ + "\\none: Symbol" + ] + } + }, + "Empty": { + "supers": [ + "AnyValue__0", + "Equatable__0" + ], + "methods": [ + { + "name": "constructor__0", + "visibility": "private", + "kind": "Constructor", + "open": false + } + ], + "metadata": { + "connected": [ + "void: Void" + ], + "imu": [ + "void: Void" + ] + } + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/type-metadata/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/type-metadata/expect/generateCode.temper new file mode 100644 index 00000000..ef5be727 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/type-metadata/expect/generateCode.temper @@ -0,0 +1,4 @@ +@typeDecl(I__0) @stay @foo @reach(\none) let I__0; +I__0 = type (I__0); +@typePlaceholder(I__0) @reach(\none) let typePlaceholder#0: Empty; +typePlaceholder#0 = {class: Empty__0} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/type-metadata/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/type-metadata/work/test/test.temper new file mode 100644 index 00000000..e2245746 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/type-metadata/work/test/test.temper @@ -0,0 +1 @@ +@foo interface I {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/type-parameter-can-extend-concrete-type/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/type-parameter-can-extend-concrete-type/expect/errors.json new file mode 100644 index 00000000..a7e9d8f7 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/type-parameter-can-extend-concrete-type/expect/errors.json @@ -0,0 +1,3 @@ +[ + "Illegal type parameter S. Overridable methods don't allow generics!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/type-parameter-can-extend-concrete-type/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/type-parameter-can-extend-concrete-type/expect/generateCode.temper new file mode 100644 index 00000000..d34c0dd9 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/type-parameter-can-extend-concrete-type/expect/generateCode.temper @@ -0,0 +1,8 @@ +@method(\f) @visibility(\public) @fn @stay @fromType(I__0) @reach(\none) let f__0; +@typeFormal(\S) @typeDecl(S__0) @reach(\none) let S__0; +S__0 = type (S__0); +f__0 = (@stay fn f(@impliedThis(I__0) this__0: I__0, s__0 /* aka s */: S__0) /* return__0 */: Void { + pureVirtual() +}); +@typeDecl(I__0) @stay @reach(\none) let I__0; +I__0 = type (I__0) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/type-parameter-can-extend-concrete-type/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/type-parameter-can-extend-concrete-type/work/test/test.temper new file mode 100644 index 00000000..20cccb75 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/type-parameter-can-extend-concrete-type/work/test/test.temper @@ -0,0 +1 @@ +interface I { public f(s: S): Void; } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/unaligned-named-args/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/unaligned-named-args/expect/errors.json new file mode 100644 index 00000000..48fe25f5 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/unaligned-named-args/expect/errors.json @@ -0,0 +1,3 @@ +[ + "nom has not been declared!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/unaligned-named-args/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/unaligned-named-args/expect/generateCode.temper new file mode 100644 index 00000000..562c25f2 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/unaligned-named-args/expect/generateCode.temper @@ -0,0 +1,8 @@ +let console#0; +console#0 = getConsole(); +@fn let hi__0; +hi__0 = (@stay fn hi(name__0 /* aka name */: String) /* return__1 */: Void { + do_call_log(console#0, name__0); + return__1 = void +}); +hi__0(\nom, "Alice") diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/unaligned-named-args/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/unaligned-named-args/work/test/test.temper new file mode 100644 index 00000000..374e827d --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/unaligned-named-args/work/test/test.temper @@ -0,0 +1,2 @@ +let hi(name: String): Void { console.log(name); } +hi(\nom, "Alice"); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/upcast-ok/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/upcast-ok/expect/errors.json new file mode 100644 index 00000000..72b02baf --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/upcast-ok/expect/errors.json @@ -0,0 +1,4 @@ +[ + "Unnecessary type check to B__0 from expression with type B__0 which is a subtype", + "Unnecessary type check to A__0 from expression with type C__2 which is a subtype" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/upcast-ok/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/upcast-ok/expect/run-result.json new file mode 100644 index 00000000..cc7a3b30 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/upcast-ok/expect/run-result.json @@ -0,0 +1 @@ +"void: Void" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/upcast-ok/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/upcast-ok/work/test/test.temper new file mode 100644 index 00000000..42646cc0 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/upcast-ok/work/test/test.temper @@ -0,0 +1,10 @@ +interface A {} +class B extends A {} +class C extends A {} +// Basic and upcast are fine. No warnings. +let bVals = new Map([new Pair("a", new B())]); +let aVals = new Map([new Pair("a", new B() as A)]); +// Samecast should still get a warning. +let bbVals = new Map([new Pair("a", new B() as B)]); +// Upcheck should also get a warning. Here we use a different subtype for clear message distinction. +let isSub = new C() is A; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/very-big-map-constructor/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/very-big-map-constructor/expect/run-result.json new file mode 100644 index 00000000..cc7a3b30 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/very-big-map-constructor/expect/run-result.json @@ -0,0 +1 @@ +"void: Void" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/very-big-map-constructor/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/very-big-map-constructor/work/test/test.temper new file mode 100644 index 00000000..4a1490d1 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/very-big-map-constructor/work/test/test.temper @@ -0,0 +1 @@ +export let numbers: Map = new Map([ new Pair("0", 0), new Pair("1", 1), new Pair("2", 2), new Pair("3", 3), new Pair("4", 4), new Pair("5", 5), new Pair("6", 6), new Pair("7", 7), new Pair("8", 8), new Pair("9", 9), new Pair("10", 10), new Pair("11", 11), new Pair("12", 12), new Pair("13", 13), new Pair("14", 14), new Pair("15", 15), new Pair("16", 16), new Pair("17", 17), new Pair("18", 18), new Pair("19", 19), new Pair("20", 20), new Pair("21", 21), new Pair("22", 22), new Pair("23", 23), new Pair("24", 24), new Pair("25", 25), new Pair("26", 26), new Pair("27", 27), new Pair("28", 28), new Pair("29", 29), new Pair("30", 30), new Pair("31", 31), new Pair("32", 32), new Pair("33", 33), new Pair("34", 34), new Pair("35", 35), new Pair("36", 36), new Pair("37", 37), new Pair("38", 38), new Pair("39", 39), new Pair("40", 40), new Pair("41", 41), new Pair("42", 42), new Pair("43", 43), new Pair("44", 44), new Pair("45", 45), new Pair("46", 46), new Pair("47", 47), new Pair("48", 48), new Pair("49", 49), new Pair("50", 50), new Pair("51", 51), new Pair("52", 52), new Pair("53", 53), new Pair("54", 54), new Pair("55", 55), new Pair("56", 56), new Pair("57", 57), new Pair("58", 58), new Pair("59", 59), new Pair("60", 60), new Pair("61", 61), new Pair("62", 62), new Pair("63", 63), new Pair("64", 64), new Pair("65", 65), new Pair("66", 66), new Pair("67", 67), new Pair("68", 68), new Pair("69", 69), new Pair("70", 70), new Pair("71", 71), new Pair("72", 72), new Pair("73", 73), new Pair("74", 74), new Pair("75", 75), new Pair("76", 76), new Pair("77", 77), new Pair("78", 78), new Pair("79", 79), new Pair("80", 80), new Pair("81", 81), new Pair("82", 82), new Pair("83", 83), new Pair("84", 84), new Pair("85", 85), new Pair("86", 86), new Pair("87", 87), new Pair("88", 88), new Pair("89", 89), new Pair("90", 90), new Pair("91", 91), new Pair("92", 92), new Pair("93", 93), new Pair("94", 94), new Pair("95", 95), new Pair("96", 96), new Pair("97", 97), new Pair("98", 98), new Pair("99", 99), new Pair("100", 100), new Pair("101", 101), new Pair("102", 102), new Pair("103", 103), new Pair("104", 104), new Pair("105", 105), new Pair("106", 106), new Pair("107", 107), new Pair("108", 108), new Pair("109", 109), new Pair("110", 110), new Pair("111", 111), new Pair("112", 112), new Pair("113", 113), new Pair("114", 114), new Pair("115", 115), new Pair("116", 116), new Pair("117", 117), new Pair("118", 118), new Pair("119", 119), new Pair("120", 120), new Pair("121", 121), new Pair("122", 122), new Pair("123", 123), new Pair("124", 124), new Pair("125", 125), new Pair("126", 126), new Pair("127", 127), new Pair("128", 128), new Pair("129", 129), new Pair("130", 130), new Pair("131", 131), new Pair("132", 132), new Pair("133", 133), new Pair("134", 134), new Pair("135", 135), new Pair("136", 136), new Pair("137", 137), new Pair("138", 138), new Pair("139", 139), new Pair("140", 140), new Pair("141", 141), new Pair("142", 142), new Pair("143", 143), new Pair("144", 144), new Pair("145", 145), new Pair("146", 146), new Pair("147", 147), new Pair("148", 148), new Pair("149", 149), new Pair("150", 150), new Pair("151", 151), new Pair("152", 152), new Pair("153", 153), new Pair("154", 154), new Pair("155", 155), new Pair("156", 156), new Pair("157", 157), new Pair("158", 158), new Pair("159", 159), new Pair("160", 160), new Pair("161", 161), new Pair("162", 162), new Pair("163", 163), new Pair("164", 164), new Pair("165", 165), new Pair("166", 166), new Pair("167", 167), new Pair("168", 168), new Pair("169", 169), new Pair("170", 170), new Pair("171", 171), new Pair("172", 172), new Pair("173", 173), new Pair("174", 174), new Pair("175", 175), new Pair("176", 176), new Pair("177", 177), new Pair("178", 178), new Pair("179", 179), new Pair("180", 180), new Pair("181", 181), new Pair("182", 182), new Pair("183", 183), new Pair("184", 184), new Pair("185", 185), new Pair("186", 186), new Pair("187", 187), new Pair("188", 188), new Pair("189", 189), new Pair("190", 190), new Pair("191", 191), new Pair("192", 192), new Pair("193", 193), new Pair("194", 194), new Pair("195", 195), new Pair("196", 196), new Pair("197", 197), new Pair("198", 198), new Pair("199", 199), new Pair("200", 200), new Pair("201", 201), new Pair("202", 202), new Pair("203", 203), new Pair("204", 204), new Pair("205", 205), new Pair("206", 206), new Pair("207", 207), new Pair("208", 208), new Pair("209", 209), new Pair("210", 210), new Pair("211", 211), new Pair("212", 212), new Pair("213", 213), new Pair("214", 214), new Pair("215", 215), new Pair("216", 216), new Pair("217", 217), new Pair("218", 218), new Pair("219", 219), new Pair("220", 220), new Pair("221", 221), new Pair("222", 222), new Pair("223", 223), new Pair("224", 224), new Pair("225", 225), new Pair("226", 226), new Pair("227", 227), new Pair("228", 228), new Pair("229", 229), new Pair("230", 230), new Pair("231", 231), new Pair("232", 232), new Pair("233", 233), new Pair("234", 234), new Pair("235", 235), new Pair("236", 236), new Pair("237", 237), new Pair("238", 238), new Pair("239", 239), new Pair("240", 240), new Pair("241", 241), new Pair("242", 242), new Pair("243", 243), new Pair("244", 244), new Pair("245", 245), new Pair("246", 246), new Pair("247", 247), new Pair("248", 248), new Pair("249", 249), new Pair("250", 250), new Pair("251", 251), new Pair("252", 252), new Pair("253", 253), new Pair("254", 254), new Pair("255", 255), new Pair("256", 256), new Pair("257", 257), new Pair("258", 258), new Pair("259", 259), new Pair("260", 260), new Pair("261", 261), new Pair("262", 262), new Pair("263", 263), new Pair("264", 264), new Pair("265", 265), new Pair("266", 266), new Pair("267", 267), new Pair("268", 268), new Pair("269", 269), new Pair("270", 270), new Pair("271", 271), new Pair("272", 272), new Pair("273", 273), new Pair("274", 274), new Pair("275", 275), new Pair("276", 276), new Pair("277", 277), new Pair("278", 278), new Pair("279", 279), new Pair("280", 280), new Pair("281", 281), new Pair("282", 282), new Pair("283", 283), new Pair("284", 284), new Pair("285", 285), new Pair("286", 286), new Pair("287", 287), new Pair("288", 288), new Pair("289", 289), new Pair("290", 290), new Pair("291", 291), new Pair("292", 292), new Pair("293", 293), new Pair("294", 294), new Pair("295", 295), new Pair("296", 296), new Pair("297", 297), new Pair("298", 298), new Pair("299", 299), new Pair("300", 300), new Pair("301", 301), new Pair("302", 302), new Pair("303", 303), new Pair("304", 304), new Pair("305", 305), new Pair("306", 306), new Pair("307", 307), new Pair("308", 308), new Pair("309", 309), new Pair("310", 310), new Pair("311", 311), new Pair("312", 312), new Pair("313", 313), new Pair("314", 314), new Pair("315", 315), new Pair("316", 316), new Pair("317", 317), new Pair("318", 318), new Pair("319", 319), new Pair("320", 320), new Pair("321", 321), new Pair("322", 322), new Pair("323", 323), new Pair("324", 324), new Pair("325", 325), new Pair("326", 326), new Pair("327", 327), new Pair("328", 328), new Pair("329", 329), new Pair("330", 330), new Pair("331", 331), new Pair("332", 332), new Pair("333", 333), new Pair("334", 334), new Pair("335", 335), new Pair("336", 336), new Pair("337", 337), new Pair("338", 338), new Pair("339", 339), new Pair("340", 340), new Pair("341", 341), new Pair("342", 342), new Pair("343", 343), new Pair("344", 344), new Pair("345", 345), new Pair("346", 346), new Pair("347", 347), new Pair("348", 348), new Pair("349", 349), new Pair("350", 350), new Pair("351", 351), new Pair("352", 352), new Pair("353", 353), new Pair("354", 354), new Pair("355", 355), new Pair("356", 356), new Pair("357", 357), new Pair("358", 358), new Pair("359", 359), new Pair("360", 360), new Pair("361", 361), new Pair("362", 362), new Pair("363", 363), new Pair("364", 364), new Pair("365", 365), new Pair("366", 366), new Pair("367", 367), new Pair("368", 368), new Pair("369", 369), new Pair("370", 370), new Pair("371", 371), new Pair("372", 372), new Pair("373", 373), new Pair("374", 374), new Pair("375", 375), new Pair("376", 376), new Pair("377", 377), new Pair("378", 378), new Pair("379", 379), new Pair("380", 380), new Pair("381", 381), new Pair("382", 382), new Pair("383", 383), new Pair("384", 384), new Pair("385", 385), new Pair("386", 386), new Pair("387", 387), new Pair("388", 388), new Pair("389", 389), new Pair("390", 390), new Pair("391", 391), new Pair("392", 392), new Pair("393", 393), new Pair("394", 394), new Pair("395", 395), new Pair("396", 396), new Pair("397", 397), new Pair("398", 398), new Pair("399", 399), new Pair("400", 400), new Pair("401", 401), new Pair("402", 402), new Pair("403", 403), new Pair("404", 404), new Pair("405", 405), new Pair("406", 406), new Pair("407", 407), new Pair("408", 408), new Pair("409", 409), new Pair("410", 410), new Pair("411", 411), new Pair("412", 412), new Pair("413", 413), new Pair("414", 414), new Pair("415", 415), new Pair("416", 416), new Pair("417", 417), new Pair("418", 418), new Pair("419", 419), new Pair("420", 420), new Pair("421", 421), new Pair("422", 422), new Pair("423", 423), new Pair("424", 424), new Pair("425", 425), new Pair("426", 426), new Pair("427", 427), new Pair("428", 428), new Pair("429", 429), new Pair("430", 430), new Pair("431", 431), new Pair("432", 432), new Pair("433", 433), new Pair("434", 434), new Pair("435", 435), new Pair("436", 436), new Pair("437", 437), new Pair("438", 438), new Pair("439", 439), new Pair("440", 440), new Pair("441", 441), new Pair("442", 442), new Pair("443", 443), new Pair("444", 444), new Pair("445", 445), new Pair("446", 446), new Pair("447", 447), new Pair("448", 448), new Pair("449", 449), new Pair("450", 450), new Pair("451", 451), new Pair("452", 452), new Pair("453", 453), new Pair("454", 454), new Pair("455", 455), new Pair("456", 456), new Pair("457", 457), new Pair("458", 458), new Pair("459", 459), new Pair("460", 460), new Pair("461", 461), new Pair("462", 462), new Pair("463", 463), new Pair("464", 464), new Pair("465", 465), new Pair("466", 466), new Pair("467", 467), new Pair("468", 468), new Pair("469", 469), new Pair("470", 470), new Pair("471", 471), new Pair("472", 472), new Pair("473", 473), new Pair("474", 474), new Pair("475", 475), new Pair("476", 476), new Pair("477", 477), new Pair("478", 478), new Pair("479", 479), new Pair("480", 480), new Pair("481", 481), new Pair("482", 482), new Pair("483", 483), new Pair("484", 484), new Pair("485", 485), new Pair("486", 486), new Pair("487", 487), new Pair("488", 488), new Pair("489", 489), new Pair("490", 490), new Pair("491", 491), new Pair("492", 492), new Pair("493", 493), new Pair("494", 494), new Pair("495", 495), new Pair("496", 496), new Pair("497", 497), new Pair("498", 498), new Pair("499", 499), new Pair("500", 500), new Pair("501", 501), new Pair("502", 502), new Pair("503", 503), new Pair("504", 504), new Pair("505", 505), new Pair("506", 506), new Pair("507", 507), new Pair("508", 508), new Pair("509", 509), new Pair("510", 510), new Pair("511", 511), new Pair("512", 512), new Pair("513", 513), new Pair("514", 514), new Pair("515", 515), new Pair("516", 516), new Pair("517", 517), new Pair("518", 518), new Pair("519", 519), new Pair("520", 520), new Pair("521", 521), new Pair("522", 522), new Pair("523", 523), new Pair("524", 524), new Pair("525", 525), new Pair("526", 526), new Pair("527", 527), new Pair("528", 528), new Pair("529", 529), new Pair("530", 530), new Pair("531", 531), new Pair("532", 532), new Pair("533", 533), new Pair("534", 534), new Pair("535", 535), new Pair("536", 536), new Pair("537", 537), new Pair("538", 538), new Pair("539", 539), new Pair("540", 540), new Pair("541", 541), new Pair("542", 542), new Pair("543", 543), new Pair("544", 544), new Pair("545", 545), new Pair("546", 546), new Pair("547", 547), new Pair("548", 548), new Pair("549", 549), new Pair("550", 550), new Pair("551", 551), new Pair("552", 552), new Pair("553", 553), new Pair("554", 554), new Pair("555", 555), new Pair("556", 556), new Pair("557", 557), new Pair("558", 558), new Pair("559", 559), new Pair("560", 560), new Pair("561", 561), new Pair("562", 562), new Pair("563", 563), new Pair("564", 564), new Pair("565", 565), new Pair("566", 566), new Pair("567", 567), new Pair("568", 568), new Pair("569", 569), new Pair("570", 570), new Pair("571", 571), new Pair("572", 572), new Pair("573", 573), new Pair("574", 574), new Pair("575", 575), new Pair("576", 576), new Pair("577", 577), new Pair("578", 578), new Pair("579", 579), new Pair("580", 580), new Pair("581", 581), new Pair("582", 582), new Pair("583", 583), new Pair("584", 584), new Pair("585", 585), new Pair("586", 586), new Pair("587", 587), new Pair("588", 588), new Pair("589", 589), new Pair("590", 590), new Pair("591", 591), new Pair("592", 592), new Pair("593", 593), new Pair("594", 594), new Pair("595", 595), new Pair("596", 596), new Pair("597", 597), new Pair("598", 598), new Pair("599", 599), new Pair("600", 600), new Pair("601", 601), new Pair("602", 602), new Pair("603", 603), new Pair("604", 604), new Pair("605", 605), new Pair("606", 606), new Pair("607", 607), new Pair("608", 608), new Pair("609", 609), new Pair("610", 610), new Pair("611", 611), new Pair("612", 612), new Pair("613", 613), new Pair("614", 614), new Pair("615", 615), new Pair("616", 616), new Pair("617", 617), new Pair("618", 618), new Pair("619", 619), new Pair("620", 620), new Pair("621", 621), new Pair("622", 622), new Pair("623", 623), new Pair("624", 624), new Pair("625", 625), new Pair("626", 626), new Pair("627", 627), new Pair("628", 628), new Pair("629", 629), new Pair("630", 630), new Pair("631", 631), new Pair("632", 632), new Pair("633", 633), new Pair("634", 634), new Pair("635", 635), new Pair("636", 636), new Pair("637", 637), new Pair("638", 638), new Pair("639", 639), new Pair("640", 640), new Pair("641", 641), new Pair("642", 642), new Pair("643", 643), new Pair("644", 644), new Pair("645", 645), new Pair("646", 646), new Pair("647", 647), new Pair("648", 648), new Pair("649", 649), new Pair("650", 650), new Pair("651", 651), new Pair("652", 652), new Pair("653", 653), new Pair("654", 654), new Pair("655", 655), new Pair("656", 656), new Pair("657", 657), new Pair("658", 658), new Pair("659", 659), new Pair("660", 660), new Pair("661", 661), new Pair("662", 662), new Pair("663", 663), new Pair("664", 664), new Pair("665", 665), new Pair("666", 666), new Pair("667", 667), new Pair("668", 668), new Pair("669", 669), new Pair("670", 670), new Pair("671", 671), new Pair("672", 672), new Pair("673", 673), new Pair("674", 674), new Pair("675", 675), new Pair("676", 676), new Pair("677", 677), new Pair("678", 678), new Pair("679", 679), new Pair("680", 680), new Pair("681", 681), new Pair("682", 682), new Pair("683", 683), new Pair("684", 684), new Pair("685", 685), new Pair("686", 686), new Pair("687", 687), new Pair("688", 688), new Pair("689", 689), new Pair("690", 690), new Pair("691", 691), new Pair("692", 692), new Pair("693", 693), new Pair("694", 694), new Pair("695", 695), new Pair("696", 696), new Pair("697", 697), new Pair("698", 698), new Pair("699", 699), new Pair("700", 700), new Pair("701", 701), new Pair("702", 702), new Pair("703", 703), new Pair("704", 704), new Pair("705", 705), new Pair("706", 706), new Pair("707", 707), new Pair("708", 708), new Pair("709", 709), new Pair("710", 710), new Pair("711", 711), new Pair("712", 712), new Pair("713", 713), new Pair("714", 714), new Pair("715", 715), new Pair("716", 716), new Pair("717", 717), new Pair("718", 718), new Pair("719", 719), new Pair("720", 720), new Pair("721", 721), new Pair("722", 722), new Pair("723", 723), new Pair("724", 724), new Pair("725", 725), new Pair("726", 726), new Pair("727", 727), new Pair("728", 728), new Pair("729", 729), new Pair("730", 730), new Pair("731", 731), new Pair("732", 732), new Pair("733", 733), new Pair("734", 734), new Pair("735", 735), new Pair("736", 736), new Pair("737", 737), new Pair("738", 738), new Pair("739", 739), new Pair("740", 740), new Pair("741", 741), new Pair("742", 742), new Pair("743", 743), new Pair("744", 744), new Pair("745", 745), new Pair("746", 746), new Pair("747", 747), new Pair("748", 748), new Pair("749", 749), new Pair("750", 750), new Pair("751", 751), new Pair("752", 752), new Pair("753", 753), new Pair("754", 754), new Pair("755", 755), new Pair("756", 756), new Pair("757", 757), new Pair("758", 758), new Pair("759", 759), new Pair("760", 760), new Pair("761", 761), new Pair("762", 762), new Pair("763", 763), new Pair("764", 764), new Pair("765", 765), new Pair("766", 766), new Pair("767", 767), new Pair("768", 768), new Pair("769", 769), new Pair("770", 770), new Pair("771", 771), new Pair("772", 772), new Pair("773", 773), new Pair("774", 774), new Pair("775", 775), new Pair("776", 776), new Pair("777", 777), new Pair("778", 778), new Pair("779", 779), new Pair("780", 780), new Pair("781", 781), new Pair("782", 782), new Pair("783", 783), new Pair("784", 784), new Pair("785", 785), new Pair("786", 786), new Pair("787", 787), new Pair("788", 788), new Pair("789", 789), new Pair("790", 790), new Pair("791", 791), new Pair("792", 792), new Pair("793", 793), new Pair("794", 794), new Pair("795", 795), new Pair("796", 796), new Pair("797", 797), new Pair("798", 798), new Pair("799", 799), new Pair("800", 800), new Pair("801", 801), new Pair("802", 802), new Pair("803", 803), new Pair("804", 804), new Pair("805", 805), new Pair("806", 806), new Pair("807", 807), new Pair("808", 808), new Pair("809", 809), new Pair("810", 810), new Pair("811", 811), new Pair("812", 812), new Pair("813", 813), new Pair("814", 814), new Pair("815", 815), new Pair("816", 816), new Pair("817", 817), new Pair("818", 818), new Pair("819", 819), new Pair("820", 820), new Pair("821", 821), new Pair("822", 822), new Pair("823", 823), new Pair("824", 824), new Pair("825", 825), new Pair("826", 826), new Pair("827", 827), new Pair("828", 828), new Pair("829", 829), new Pair("830", 830), new Pair("831", 831), new Pair("832", 832), new Pair("833", 833), new Pair("834", 834), new Pair("835", 835), new Pair("836", 836), new Pair("837", 837), new Pair("838", 838), new Pair("839", 839), new Pair("840", 840), new Pair("841", 841), new Pair("842", 842), new Pair("843", 843), new Pair("844", 844), new Pair("845", 845), new Pair("846", 846), new Pair("847", 847), new Pair("848", 848), new Pair("849", 849), new Pair("850", 850), new Pair("851", 851), new Pair("852", 852), new Pair("853", 853), new Pair("854", 854), new Pair("855", 855), new Pair("856", 856), new Pair("857", 857), new Pair("858", 858), new Pair("859", 859), new Pair("860", 860), new Pair("861", 861), new Pair("862", 862), new Pair("863", 863), new Pair("864", 864), new Pair("865", 865), new Pair("866", 866), new Pair("867", 867), new Pair("868", 868), new Pair("869", 869), new Pair("870", 870), new Pair("871", 871), new Pair("872", 872), new Pair("873", 873), new Pair("874", 874), new Pair("875", 875), new Pair("876", 876), new Pair("877", 877), new Pair("878", 878), new Pair("879", 879), new Pair("880", 880), new Pair("881", 881), new Pair("882", 882), new Pair("883", 883), new Pair("884", 884), new Pair("885", 885), new Pair("886", 886), new Pair("887", 887), new Pair("888", 888), new Pair("889", 889), new Pair("890", 890), new Pair("891", 891), new Pair("892", 892), new Pair("893", 893), new Pair("894", 894), new Pair("895", 895), new Pair("896", 896), new Pair("897", 897), new Pair("898", 898), new Pair("899", 899), new Pair("900", 900), new Pair("901", 901), new Pair("902", 902), new Pair("903", 903), new Pair("904", 904), new Pair("905", 905), new Pair("906", 906), new Pair("907", 907), new Pair("908", 908), new Pair("909", 909), new Pair("910", 910), new Pair("911", 911), new Pair("912", 912), new Pair("913", 913), new Pair("914", 914), new Pair("915", 915), new Pair("916", 916), new Pair("917", 917), new Pair("918", 918), new Pair("919", 919), new Pair("920", 920), new Pair("921", 921), new Pair("922", 922), new Pair("923", 923), new Pair("924", 924), new Pair("925", 925), new Pair("926", 926), new Pair("927", 927), new Pair("928", 928), new Pair("929", 929), new Pair("930", 930), new Pair("931", 931), new Pair("932", 932), new Pair("933", 933), new Pair("934", 934), new Pair("935", 935), new Pair("936", 936), new Pair("937", 937), new Pair("938", 938), new Pair("939", 939), new Pair("940", 940), new Pair("941", 941), new Pair("942", 942), new Pair("943", 943), new Pair("944", 944), new Pair("945", 945), new Pair("946", 946), new Pair("947", 947), new Pair("948", 948), new Pair("949", 949), new Pair("950", 950), new Pair("951", 951), new Pair("952", 952), new Pair("953", 953), new Pair("954", 954), new Pair("955", 955), new Pair("956", 956), new Pair("957", 957), new Pair("958", 958), new Pair("959", 959), new Pair("960", 960), new Pair("961", 961), new Pair("962", 962), new Pair("963", 963), new Pair("964", 964), new Pair("965", 965), new Pair("966", 966), new Pair("967", 967), new Pair("968", 968), new Pair("969", 969), new Pair("970", 970), new Pair("971", 971), new Pair("972", 972), new Pair("973", 973), new Pair("974", 974), new Pair("975", 975), new Pair("976", 976), new Pair("977", 977), new Pair("978", 978), new Pair("979", 979), new Pair("980", 980), new Pair("981", 981), new Pair("982", 982), new Pair("983", 983), new Pair("984", 984), new Pair("985", 985), new Pair("986", 986), new Pair("987", 987), new Pair("988", 988), new Pair("989", 989), new Pair("990", 990), new Pair("991", 991), new Pair("992", 992), new Pair("993", 993), new Pair("994", 994), new Pair("995", 995), new Pair("996", 996), new Pair("997", 997), new Pair("998", 998), new Pair("999", 999),]); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/void-not-a-value/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/void-not-a-value/expect/errors.json new file mode 100644 index 00000000..ff4ac639 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/void-not-a-value/expect/errors.json @@ -0,0 +1,7 @@ +[ + "Type formal \u003clistT extends AnyValue\u003e cannot bind to Void which does not fit upper bounds [AnyValue]!", + "Void expressions cannot be used as values!", + "Void expressions cannot be used as values!", + "Void expressions cannot be used as values!", + "Void expressions cannot be used as values!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/void-not-a-value/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/void-not-a-value/expect/generateCode.temper new file mode 100644 index 00000000..6de96231 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/void-not-a-value/expect/generateCode.temper @@ -0,0 +1,19 @@ +let console#0; +console#0 = getConsole(); +@fn let b__0, @fn c__0; +b__0 = (@stay fn b /* return__0 */: Void { + do_call_log(console#0, "hi"); + return__0 = void +}); +let a__0; +b__0(); +a__0 = list(void); +c__0 = (@stay fn c(d__0 /* aka d */: Void) /* return__1 */: Void { + b__0(); + return__1 = void +}); +@reach(\none) let e__0; +do_call_get(a__0, 0); +c__0(void); +e__0 = void; +c__0(void) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/void-not-a-value/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/void-not-a-value/work/test/test.temper new file mode 100644 index 00000000..d1c0e8ab --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/void-not-a-value/work/test/test.temper @@ -0,0 +1,5 @@ +let a = [b()]; +let b(): Void { console.log("hi"); } +let c(d: Void): Void { b() } +let e = c(a[0]); +c(void); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/void-vs-value/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/void-vs-value/expect/errors.json new file mode 100644 index 00000000..3f3a8638 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/void-vs-value/expect/errors.json @@ -0,0 +1,4 @@ +[ + "Cannot assign to Void from Int32!", + "Expected subtype of Void, but got Int32!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/void-vs-value/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/void-vs-value/expect/generateCode.temper new file mode 100644 index 00000000..8e01e0ca --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/void-vs-value/expect/generateCode.temper @@ -0,0 +1,10 @@ +@fn @reach(\none) let trick__0, @fn @reach(\none) treat__0, @fn @reach(\none) trail__0; +trick__0 = (@stay fn trick /* return__1 */: Void { + return__1 = 123 +}); +treat__0 = (@stay fn treat /* return__2 */: Int32 { + return__2 = 456 +}); +trail__0 = (@stay fn trail /* return__3 */: Void { + return__3 = void +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/void-vs-value/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/void-vs-value/work/test/test.temper new file mode 100644 index 00000000..497a5f96 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/void-vs-value/work/test/test.temper @@ -0,0 +1,3 @@ +let trick(): Void { 123 } +let treat(): Int { 456 } +let trail(): Void { 789; } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/when-else-bubble/expect/generateCode-exports.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/when-else-bubble/expect/generateCode-exports.json new file mode 100644 index 00000000..7e355818 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/when-else-bubble/expect/generateCode-exports.json @@ -0,0 +1,7 @@ +{ + "something": { + "stateVector": "fn something", + "typeTag": "Function", + "abbrev": "fn something: Function" + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/when-else-bubble/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/when-else-bubble/expect/generateCode.temper new file mode 100644 index 00000000..cb36c042 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/when-else-bubble/expect/generateCode.temper @@ -0,0 +1,18 @@ +@fn let `test//`.something ⦂(fn (String?): String | Bubble); +`test//`.something = (@stay fn something(x__0 /* aka x */: String?) /* return__0 */: (String | Bubble) { + var t#0 ⦂ Boolean; + if (!isNull ⋖ String ⋗(x__0)) { + t#0 = x__0 is String + } else { + t#0 = false + }; + if (t#0) { + if (isNull ⋖ String ⋗(x__0)) { + return__0 = panic ⋖ String ⋗() + } else { + return__0 = assertAs ⋖ String ⋗(x__0, String) + } + } else { + bubble ⋖ String ⋗() + } +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/when-else-bubble/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/when-else-bubble/work/test/test.temper new file mode 100644 index 00000000..84bff4c0 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/generate-code/when-else-bubble/work/test/test.temper @@ -0,0 +1,7 @@ +export let something(x: String?): String throws Bubble { + /** Silly */ + when (x) { + is String -> x; + else -> bubble(); + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/angle-bracket-confusion-error-message-is-not-super-terrible/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/angle-bracket-confusion-error-message-is-not-super-terrible/expect/errors.json new file mode 100644 index 00000000..4dede882 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/angle-bracket-confusion-error-message-is-not-super-terrible/expect/errors.json @@ -0,0 +1,4 @@ +[ + "Expected a TopLevel here!", + "Interpreter encountered error()!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/angle-bracket-confusion-error-message-is-not-super-terrible/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/angle-bracket-confusion-error-message-is-not-super-terrible/expect/run-result.json new file mode 100644 index 00000000..80f4df67 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/angle-bracket-confusion-error-message-is-not-super-terrible/expect/run-result.json @@ -0,0 +1 @@ +{ "exitKind": "Panic" } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/angle-bracket-confusion-error-message-is-not-super-terrible/expect/stage-completed.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/angle-bracket-confusion-error-message-is-not-super-terrible/expect/stage-completed.json new file mode 100644 index 00000000..b4956eb6 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/angle-bracket-confusion-error-message-is-not-super-terrible/expect/stage-completed.json @@ -0,0 +1 @@ +"GenerateCode" diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/angle-bracket-confusion-error-message-is-not-super-terrible/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/angle-bracket-confusion-error-message-is-not-super-terrible/work/test/test.temper new file mode 100644 index 00000000..3448be88 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/angle-bracket-confusion-error-message-is-not-super-terrible/work/test/test.temper @@ -0,0 +1,6 @@ +let or(a: Boolean, b: Boolean): Boolean { a || b } +let a = 1; +// The below has a use of angle-brackets, not a use +// of less-than and a use of greater-than. +or(a< 2, a > 0); +// ^---- Missing space causes a parse failure. diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/appendix/expect/parse-appendix.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/appendix/expect/parse-appendix.json new file mode 100644 index 00000000..97763136 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/appendix/expect/parse-appendix.json @@ -0,0 +1,9 @@ +{ + "foo": [ + "bar", + { + "baz": -800 + }, + false + ] +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/appendix/expect/parse.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/appendix/expect/parse.temper new file mode 100644 index 00000000..eb28ef44 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/appendix/expect/parse.temper @@ -0,0 +1 @@ +foo() diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/appendix/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/appendix/work/test/test.temper new file mode 100644 index 00000000..bed08ba0 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/appendix/work/test/test.temper @@ -0,0 +1,5 @@ +foo() +;;; +{ + "foo": ["bar", { "baz": -800 }, false] +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/bad-unicode-scalar-values/README.md b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/bad-unicode-scalar-values/README.md new file mode 100644 index 00000000..ad384787 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/bad-unicode-scalar-values/README.md @@ -0,0 +1,2 @@ +Purposely do some things that might throw off sloppy position estimation. +And include regex, even with good escapes, to make sure we handle such. diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/bad-unicode-scalar-values/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/bad-unicode-scalar-values/expect/errors.json new file mode 100644 index 00000000..e70c52f8 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/bad-unicode-scalar-values/expect/errors.json @@ -0,0 +1,3 @@ +[ + "Expected a Expression here!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/bad-unicode-scalar-values/expect/parse.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/bad-unicode-scalar-values/expect/parse.temper new file mode 100644 index 00000000..425724c5 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/bad-unicode-scalar-values/expect/parse.temper @@ -0,0 +1,23 @@ +rgx(list("."), list()); +rgx(list(raw "(^|,)\s*"), list()); +stringExpr(null, false, "wanna be pair", error (list(raw "\:")), " ", error (list(raw "\ud800")), error (list(raw "\udc00")), "\nso does that have more pos needs?"); +stringExpr(null, false, "fine", " ", "escape", " ", "here", error (list(raw "\u"))); +stringExpr(null, false, "too big: ", error (list(raw "\u{hi}")), error (list(raw "\u{110000}")), "!", error (list(raw "\u"))); +stringExpr(null, false, "space bad: ", " ", error (list(raw "\u{ }")), "!"); +stringExpr(null, false, "empty: "); +stringExpr(null, false, "fine: ", " "); +stringExpr(null, false, "also: ", " ", "!"); +error (list("`(QuotedGroup`", "\"", "`(Leaf`", "bad order: ", "`Leaf)`", "`(UnicodeRun`", raw "\u{", "`(Comma`", ",", "`(Leaf`", "20", "`Leaf)`", ",", ",", "`(Leaf`", "21", "`Leaf)`", ",", "`(Leaf`", "22", "`Leaf)`", "`Comma)`", "}", "`UnicodeRun)`", "\"", "`QuotedGroup)`")); +stringExpr(raw, true, raw "\u{", "}", raw "\u{", " ", "}"); +stringExpr(raw, true, "too big: ", raw "\u{", " ", "hi", ",", " ", "110000", " ", "}", "!", raw "\u"); +stringExpr(raw, true, "too big: ", raw "\u{", " ", "hi", \interpolate, " there", ",", " ", "110000", " ", "}", "!", raw "\u"); +stringExpr(raw, true, "hi", raw "\u{", \interpolate, " t", "}", "here"); +stringExpr(null, false, "wanna be ", pair, " in list:", " ", error (list(raw "\u{d800}")), error (list(raw "\u{dc00}"))); +stringExpr(null, false, "interpolate after list not in:", " ", "hi"); +"hi"; +\interpolate; +hi; +stringExpr(null, false, "hi"); +quasiInner(quasiLeaf(\hi)); +stringExpr(null, false, "surrogate, not scalar: ", error (list(raw "\ud834")), "!"); +stringExpr(null, false, "wanna be pair: ", error (list(raw "\ud800")), error (list(raw "\udc00"))); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/bad-unicode-scalar-values/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/bad-unicode-scalar-values/work/test/test.temper new file mode 100644 index 00000000..b74c6032 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/bad-unicode-scalar-values/work/test/test.temper @@ -0,0 +1,25 @@ +/./; +/(^|,)\s*/; +""" +"wanna${} be pair\: \ud800\udc00 +~so does that have more pos needs? +; +"fine\u0020escape${" "}here\u"; +"too big: \u{hi,110000}!\u"; +"space bad: \u{20, 21}"; +"empty: \u{}"; +"fine: \u{20}"; +"also: \u{20,21}"; +"bad order: \u{,20,,21,22}"; +raw"\u{}\u{ }"; +raw"too big: \u{ hi, 110000 }!\u"; +raw"too big: \u{ hi${" there"}, 110000 }!\u"; +raw"hi\u{${" t"}}here"; +"wanna be ${pair} in list:\u{2${}0,d800,dc00}"; +"interpolate after list not in:\u{20}${"hi"}"; +"hi"; +${hi}; +"${"hi"}"; +\{hi}; +"surrogate, not scalar: \ud834!"; +"wanna be pair: \ud800\udc00"; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/call-join-rewrite-for-docs/expect/parse.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/call-join-rewrite-for-docs/expect/parse.temper new file mode 100644 index 00000000..14d1af66 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/call-join-rewrite-for-docs/expect/parse.temper @@ -0,0 +1,7 @@ +if(a, fn { + b + }, \else_if, c, fn { + d + }, \else, fn { + e +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/call-join-rewrite-for-docs/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/call-join-rewrite-for-docs/work/test/test.temper new file mode 100644 index 00000000..05ada82b --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/call-join-rewrite-for-docs/work/test/test.temper @@ -0,0 +1 @@ +if (a) { b } else if (c) { d } else { e } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/call-join-rewrite/expect/parse.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/call-join-rewrite/expect/parse.temper new file mode 100644 index 00000000..aa99ce5f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/call-join-rewrite/expect/parse.temper @@ -0,0 +1,11 @@ +if(a, fn { + b + }, \else_if, fn (f#0) { + f#0(c, fn { + d + }, \else, fn (f#1) { + f#1(fn { + e + }) + }) +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/call-join-rewrite/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/call-join-rewrite/work/test/test.temper new file mode 100644 index 00000000..05ada82b --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/call-join-rewrite/work/test/test.temper @@ -0,0 +1 @@ +if (a) { b } else if (c) { d } else { e } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/unrepresentable-integers-warned-on/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/unrepresentable-integers-warned-on/expect/errors.json new file mode 100644 index 00000000..e23ce896 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/unrepresentable-integers-warned-on/expect/errors.json @@ -0,0 +1,8 @@ +[ + { + "template": "Int32OutOfBounds", + "values": [ + 2.147483648e+9 + ] + } +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/unrepresentable-integers-warned-on/expect/parse.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/unrepresentable-integers-warned-on/expect/parse.temper new file mode 100644 index 00000000..8dd25d42 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/unrepresentable-integers-warned-on/expect/parse.temper @@ -0,0 +1,5 @@ +let a = -2147483648, b = 2147483647; +REM("ok", null, false); +let c = 2147483648; +REM("ok", null, false); +let d = -2147483648; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/unrepresentable-integers-warned-on/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/unrepresentable-integers-warned-on/work/test/test.temper new file mode 100644 index 00000000..6d8fdc1d --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/parse/unrepresentable-integers-warned-on/work/test/test.temper @@ -0,0 +1,4 @@ +let a = 2147483648; +let b = 2147483647; // ok +let c = 2147483648i64; // ok +let d = 0x8000_0000; // ok because idioms diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/assignments-in-multi-decls-resolve-properly/expect/syntaxMacro.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/assignments-in-multi-decls-resolve-properly/expect/syntaxMacro.lispy new file mode 100644 index 00000000..26ab86bc --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/assignments-in-multi-decls-resolve-properly/expect/syntaxMacro.lispy @@ -0,0 +1,80 @@ +[ + "Block", + [ + [ + "Block", + [ + [ + "Decl", + [ + [ + "LeftName", + "x__0" + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "y__1" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "nym`=`: Function" + ], + [ + "Call", + [ + [ + "Value", + "nym`,`: Function" + ], + [ + "LeftName", + "x__0" + ], + [ + "LeftName", + "y__1" + ] + ] + ], + [ + "Call", + [ + [ + "RightName", + "f" + ] + ] + ] + ] + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "nym`do_call__+_`[PlusIntInt, PlusIntInt64, PlusFltFlt]: Function" + ], + [ + "RightName", + "x__0" + ], + [ + "RightName", + "y__1" + ] + ] + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/assignments-in-multi-decls-resolve-properly/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/assignments-in-multi-decls-resolve-properly/work/test/test.temper new file mode 100644 index 00000000..62fe7e05 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/assignments-in-multi-decls-resolve-properly/work/test/test.temper @@ -0,0 +1 @@ +let [x, y] = f(); x + y diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/back-reference-in-formal-initializer/expect/syntaxMacro.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/back-reference-in-formal-initializer/expect/syntaxMacro.lispy new file mode 100644 index 00000000..c7651e01 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/back-reference-in-formal-initializer/expect/syntaxMacro.lispy @@ -0,0 +1,188 @@ +[ + "Block", + [ + [ + "Decl", + [ + [ + "LeftName", + "f__0" + ], + [ + "Value", + "\\fn: Symbol" + ], + [ + "Value", + "void: Void" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.f()\u0022: String" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "nym`=`: Function" + ], + [ + "LeftName", + "f__0" + ], + [ + "Fun", + [ + [ + "Decl", + [ + [ + "LeftName", + "i__1" + ], + [ + "Value", + "\\default: Symbol" + ], + [ + "RightName", + "j__2" + ], + [ + "Value", + "\\word: Symbol" + ], + [ + "Value", + "\\i: Symbol" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.f().(i)\u0022: String" + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "j__2" + ], + [ + "Value", + "\\default: Symbol" + ], + [ + "Value", + "42: Int32" + ], + [ + "Value", + "\\word: Symbol" + ], + [ + "Value", + "\\j: Symbol" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.f().(j)\u0022: String" + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "k__3" + ], + [ + "Value", + "\\default: Symbol" + ], + [ + "RightName", + "f__0" + ], + [ + "Value", + "\\word: Symbol" + ], + [ + "Value", + "\\k: Symbol" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.f().(k)\u0022: String" + ] + ] + ], + [ + "Value", + "\\returnedFrom: Symbol" + ], + [ + "Value", + "true: Boolean" + ], + [ + "Value", + "\\word: Symbol" + ], + [ + "Value", + "\\f: Symbol" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.f()\u0022: String" + ], + [ + "Block", + [ + [ + "Value", + "\\label: Symbol" + ], + [ + "LeftName", + "fn__4" + ] + ] + ] + ] + ] + ] + ], + [ + "Value", + "void: Void" + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/back-reference-in-formal-initializer/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/back-reference-in-formal-initializer/work/test/test.temper new file mode 100644 index 00000000..b87ca810 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/back-reference-in-formal-initializer/work/test/test.temper @@ -0,0 +1 @@ +let f(i = j, j = 42, k = f) {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/block-lambda/expect/syntaxMacro.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/block-lambda/expect/syntaxMacro.lispy new file mode 100644 index 00000000..fdc1a514 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/block-lambda/expect/syntaxMacro.lispy @@ -0,0 +1,82 @@ +[ + "Block", + [ + [ + "Call", + [ + [ + "RightName", + "f" + ], + [ + "Fun", + [ + [ + "Decl", + [ + [ + "LeftName", + "arg__0" + ], + [ + "Value", + "\\type: Symbol" + ], + [ + "RightName", + "ArgType" + ], + [ + "Value", + "\\word: Symbol" + ], + [ + "Value", + "\\arg: Symbol" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.(arg)\u0022: String" + ] + ] + ], + [ + "Value", + "\\returnDecl: Symbol" + ], + [ + "Decl", + [ + [ + "LeftName", + "return__0" + ], + [ + "Value", + "\\type: Symbol" + ], + [ + "RightName", + "ReturnType" + ] + ] + ], + [ + "Block", + [ + [ + "RightName", + "arg__0" + ] + ] + ] + ] + ] + ] + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/block-lambda/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/block-lambda/expect/syntaxMacro.temper new file mode 100644 index 00000000..f898723b --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/block-lambda/expect/syntaxMacro.temper @@ -0,0 +1,3 @@ +f(fn (arg__0 /* aka arg */: ArgType) /* return__0 */: (ReturnType) { + arg__0 +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/block-lambda/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/block-lambda/work/test/test.temper new file mode 100644 index 00000000..4b3854b6 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/block-lambda/work/test/test.temper @@ -0,0 +1 @@ +f { (arg: ArgType): ReturnType => arg } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/block-scoping/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/block-scoping/expect/run-result.json new file mode 100644 index 00000000..5df64e4f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/block-scoping/expect/run-result.json @@ -0,0 +1 @@ +"3: Int32" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/block-scoping/expect/syntaxMacro.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/block-scoping/expect/syntaxMacro.lispy new file mode 100644 index 00000000..74e31423 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/block-scoping/expect/syntaxMacro.lispy @@ -0,0 +1,124 @@ +[ + "Block", + [ + [ + "Decl", + [ + [ + "LeftName", + "a__0" + ], + [ + "Value", + [ + "init", + "Symbol" + ] + ], + [ + "Value", + [ + 1, + "Int32" + ] + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.a\u0022: String" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "nym`do_call__+_`[PlusIntInt, PlusIntInt64, PlusFltFlt]: Function" + ], + [ + "Call", + [ + [ + "RightName", + "do" + ], + [ + "Fun", + [ + [ + "Block", + [ + [ + "Decl", + [ + [ + "LeftName", + "a__1" + ], + [ + "Value", + [ + "init", + "Symbol" + ] + ], + [ + "Value", + [ + 2, + "Int32" + ] + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.a=\u0022: String" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "REM: Function" + ], + [ + "Value", + "\u0022Why do I feel compelled to write `let ... in` here?\\nI wish I knew how to quit you, OCaml!\u0022: String" + ], + [ + "Value", + "null: Null" + ], + [ + "Value", + "false: Boolean" + ] + ] + ], + [ + "RightName", + "a__1" + ] + ] + ] + ] + ] + ] + ], + [ + "RightName", + "a__0" + ] + ] + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/block-scoping/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/block-scoping/expect/syntaxMacro.temper new file mode 100644 index 00000000..3df3e469 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/block-scoping/expect/syntaxMacro.temper @@ -0,0 +1,6 @@ +let a__0 = 1; +do (fn { + let a__1 = 2; + REM("Why do I feel compelled to write `let ... in` here?\nI wish I knew how to quit you, OCaml!", null, false); + a__1 +}) + a__0 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/block-scoping/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/block-scoping/work/test/test.temper new file mode 100644 index 00000000..8401a642 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/block-scoping/work/test/test.temper @@ -0,0 +1,7 @@ +let a = 1; +(do { + let a = 2; + // Why do I feel compelled to write `let ... in` here? + // I wish I knew how to quit you, OCaml! + a +}) + a diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/chain-null/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/chain-null/expect/syntaxMacro.temper new file mode 100644 index 00000000..1c35295f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/chain-null/expect/syntaxMacro.temper @@ -0,0 +1,40 @@ +@typeDecl(StringHolder__0) @stay let StringHolder__0 = type (StringHolder__0); +@fn let `test//`.maybeLength; +class(\word, \StringHolder, \concrete, true, @typeDefined(StringHolder__0) fn { + StringHolder__0 extends AnyValue; + @constructorProperty @maybeVar @visibility(\public) let string__0: String; + @visibility(\public) let constructor__0 = fn constructor(@impliedThis(StringHolder__0) this__0: StringHolder__0, string__1 /* aka string */: String) /* return__0 */: Void { + do { + let t#0; + do_iset_string(type (StringHolder__0), this(StringHolder__0), t#0 = string__1); + t#0 + }; + }; +}); +`test//`.maybeLength = fn maybeLength(a__0 /* aka a */: StringHolder__0?, min__0 /* aka min */: Int) /* return__1 */: (Int?) { + fn__0: do { + { + let subject#0; + subject#0 = { + let subject#1; + subject#1 = { + if (isNull(a__0)) { + null + } else { + do_get_string(notNull(a__0)) + } + }; + if (isNull(subject#1)) { + null + } else { + do_call_countBetween(notNull(subject#1), do_get_begin(String), do_get_end(do_get_string(a__0))) + } + }; + if (isNull(subject#0)) { + null + } else { + do_call_max(notNull(subject#0), min__0) + } + } + } +}; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/chain-null/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/chain-null/work/test/test.temper new file mode 100644 index 00000000..bc56ee0c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/chain-null/work/test/test.temper @@ -0,0 +1,4 @@ +class StringHolder(public string: String) {} +export let maybeLength(a: StringHolder?, min: Int): Int? { + a?.string?.countBetween(String.begin, a.string.end)?.max(min) +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/class-formal-args-do-not-cross-scopes/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/class-formal-args-do-not-cross-scopes/expect/syntaxMacro.temper new file mode 100644 index 00000000..51de6a5b --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/class-formal-args-do-not-cross-scopes/expect/syntaxMacro.temper @@ -0,0 +1,8 @@ +@typeDecl(I__0) @stay let I__0 = type (I__0); +let T__1 = "T"; +interface(\word, \I, \concrete, false, @typeDefined(I__0) fn { + @typeFormal(\T) @memberTypeFormal(\T) @typeDefined(T__0) let T__0 = type (T__0); + I__0 extends AnyValue; + @property(\t) @maybeVar let t__0: T__0; +}); +let t__1 = T__1; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/class-formal-args-do-not-cross-scopes/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/class-formal-args-do-not-cross-scopes/work/test/test.temper new file mode 100644 index 00000000..c38dcb85 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/class-formal-args-do-not-cross-scopes/work/test/test.temper @@ -0,0 +1,3 @@ +let T = "T"; +interface I { t: T } +let t = T; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/comments-on-setters-and-getters/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/comments-on-setters-and-getters/expect/disAmbiguate.temper new file mode 100644 index 00000000..724fd4e3 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/comments-on-setters-and-getters/expect/disAmbiguate.temper @@ -0,0 +1,11 @@ +@typeDecl(C__0) @hoistLeft(true) @resolution(C__0) @stay let C = type (C__0); +class(\word, C, \concrete, true, @typeDefined(C__0) fn { + C__0 extends AnyValue; + REM("Returns 1", true, false); + @method(\x) @getter @visibility(\public) let nym`get.x` = fn(\word, nym`get.x`, @impliedThis(C__0) let this__0: C__0, \outType, Int, fn { + 1 + }); + REM("You can set it but it'll still be 1.", true, false); + @method(\x) @setter @visibility(\public) let nym`set.x` = fn(\word, nym`set.x`, @impliedThis(C__0) let this__1: C__0, let newValue /* aka newValue */: Int, \outType, Void, fn {}); +}); +C diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/comments-on-setters-and-getters/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/comments-on-setters-and-getters/expect/syntaxMacro.temper new file mode 100644 index 00000000..7320d62c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/comments-on-setters-and-getters/expect/syntaxMacro.temper @@ -0,0 +1,17 @@ +@typeDecl(C__0) @stay let C__0 = type (C__0); +class(\word, \C, \concrete, true, @typeDefined(C__0) fn { + C__0 extends AnyValue; + @property(\x) @visibility(\public) let x__0; + REM("Returns 1", true, false); + @method(\x) @getter @visibility(\public) @fn let nym`get.x__1` = (@docString(...) fn nym`get.x`(@impliedThis(C__0) this__0: C__0) /* return__0 */: (Int) { + fn__0: do { + 1 + } + }); + REM("You can set it but it'll still be 1.", true, false); + @method(\x) @setter @visibility(\public) @fn let nym`set.x__2` = (@docString(...) fn nym`set.x`(@impliedThis(C__0) this__1: C__0, newValue__0 /* aka newValue */: Int) /* return__1 */: (Void) { + fn__1: do {} + }); + @method(\constructor) @visibility(\public) let constructor__0 = fn constructor(@impliedThis(C__0) this__2: C__0) /* return__2 */: Void {}; +}); +C__0 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/comments-on-setters-and-getters/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/comments-on-setters-and-getters/work/test/test.temper new file mode 100644 index 00000000..1104edb0 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/comments-on-setters-and-getters/work/test/test.temper @@ -0,0 +1,6 @@ +class C { + /** Returns 1 */ + public get x(): Int { 1 } + /** You can set it but it'll still be 1. */ + public set x(newValue: Int): Void {} +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/compound-ops-with-getter-and-setter/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/compound-ops-with-getter-and-setter/expect/disAmbiguate.temper new file mode 100644 index 00000000..ba92336a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/compound-ops-with-getter-and-setter/expect/disAmbiguate.temper @@ -0,0 +1,15 @@ +@stay @imported(\(`test//c/`.C)) let C = type (C); +do(fn { + let c = new C(); + do { + let t#0; + t#0 = c; + leftHandOf(t#0.x, (nym`do_call__+_`[PlusIntInt, PlusIntInt64, PlusFltFlt])(t#0.x, 1)) + }; + do { + let t#1; + t#1 = c; + leftHandOf(t#1.x, (nym`do_call__*_`[TimesIntInt, TimesIntInt64, TimesFltFlt])(t#1.x, 2)) + }; + console.log(c.x); +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/compound-ops-with-getter-and-setter/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/compound-ops-with-getter-and-setter/expect/syntaxMacro.temper new file mode 100644 index 00000000..0ef527b5 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/compound-ops-with-getter-and-setter/expect/syntaxMacro.temper @@ -0,0 +1,25 @@ +@stay @imported(\(`test//c/`.C)) let C__0 = type (C), console#0 = doPure(fn: Console { + getConsole() +}); +do (fn { + let c__0 = new C__0(); + do { + let t#0; + t#0 = c__0; + do { + let t#2; + do_set_x(t#0, t#2 = (nym`do_call__+_`[PlusIntInt, PlusIntInt64, PlusFltFlt])(do_get_x(t#0), 1)); + t#2 + } + }; + do { + let t#1; + t#1 = c__0; + do { + let t#3; + do_set_x(t#1, t#3 = (nym`do_call__*_`[TimesIntInt, TimesIntInt64, TimesFltFlt])(do_get_x(t#1), 2)); + t#3 + } + }; + do_call_log(console#0, do_get_x(c__0)); +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/compound-ops-with-getter-and-setter/work/test/c/c.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/compound-ops-with-getter-and-setter/work/test/c/c.temper new file mode 100644 index 00000000..c9b863ef --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/compound-ops-with-getter-and-setter/work/test/c/c.temper @@ -0,0 +1,4 @@ +export class C { + public get x(): Int32 { 1 } + public set x(newX: Int32) { /* ignoring it */ } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/compound-ops-with-getter-and-setter/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/compound-ops-with-getter-and-setter/work/test/test.temper new file mode 100644 index 00000000..53b935b1 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/compound-ops-with-getter-and-setter/work/test/test.temper @@ -0,0 +1,8 @@ +let { C } = import("./c"); +do { + let c = new C(); + c.x += 1; + c.x *= 2; + console.log(c.x); +} + diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/compound-ops-with-indexed-get-and-set/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/compound-ops-with-indexed-get-and-set/expect/disAmbiguate.temper new file mode 100644 index 00000000..3a9cb599 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/compound-ops-with-indexed-get-and-set/expect/disAmbiguate.temper @@ -0,0 +1,14 @@ +let `test//`.myList = do(fn { + let b: ListBuilder = list(1, 2).toListBuilder(); + do { + let t#0; + t#0 = b; + t#0.set(0, (nym`do_call__+_`[PlusIntInt, PlusIntInt64, PlusFltFlt])(t#0.get(0), 1)) + }; + do { + let t#1; + t#1 = b; + t#1.set(1, (nym`do_call__*_`[TimesIntInt, TimesIntInt64, TimesFltFlt])(t#1.get(1), 2)) + }; + b.toList() +}); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/compound-ops-with-indexed-get-and-set/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/compound-ops-with-indexed-get-and-set/expect/syntaxMacro.temper new file mode 100644 index 00000000..a33d65b4 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/compound-ops-with-indexed-get-and-set/expect/syntaxMacro.temper @@ -0,0 +1,14 @@ +let `test//`.myList = do (fn { + let b__0: ListBuilder = do_call_toListBuilder(list(1, 2)); + do { + let t#0; + t#0 = b__0; + do_call_set(t#0, 0, (nym`do_call__+_`[PlusIntInt, PlusIntInt64, PlusFltFlt])(do_call_get(t#0, 0), 1)) + }; + do { + let t#1; + t#1 = b__0; + do_call_set(t#1, 1, (nym`do_call__*_`[TimesIntInt, TimesIntInt64, TimesFltFlt])(do_call_get(t#1, 1), 2)) + }; + do_call_toList(b__0) +}); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/compound-ops-with-indexed-get-and-set/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/compound-ops-with-indexed-get-and-set/work/test/test.temper new file mode 100644 index 00000000..c1c3ab27 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/compound-ops-with-indexed-get-and-set/work/test/test.temper @@ -0,0 +1,6 @@ +export let myList = do { + let b: ListBuilder = [1, 2].toListBuilder(); + b[0] += 1; + b[1] *= 2; + b.toList() +}; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/console-bound/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/console-bound/expect/syntaxMacro.temper new file mode 100644 index 00000000..80ff5a26 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/console-bound/expect/syntaxMacro.temper @@ -0,0 +1,5 @@ +let console#0 = doPure(fn: Console { + getConsole() +}), console__0 = getConsole("myConsole"); +do_call_log(console__0, "Hi!"); +do_call_log(console#0, "Bye!"); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/console-bound/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/console-bound/work/test/test.temper new file mode 100644 index 00000000..1fbd7702 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/console-bound/work/test/test.temper @@ -0,0 +1,3 @@ +let console = getConsole("myConsole"); +console.log("Hi!"); +builtins.console.log("Bye!"); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/console-unbound/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/console-unbound/expect/syntaxMacro.temper new file mode 100644 index 00000000..d7b38e8a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/console-unbound/expect/syntaxMacro.temper @@ -0,0 +1,8 @@ +let console#0 = doPure(fn: Console { + getConsole() +}); +do (fn { + let console__0 = getConsole("myConsole"); +}); +do_call_log(console#0, "Hi!"); +do_call_log(console#0, "Bye!"); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/console-unbound/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/console-unbound/work/test/test.temper new file mode 100644 index 00000000..e8d718f2 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/console-unbound/work/test/test.temper @@ -0,0 +1,3 @@ +do { let console = getConsole("myConsole"); } +console.log("Hi!"); +builtins.console.log("Bye!"); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-compound-op/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-compound-op/expect/disAmbiguate.temper new file mode 100644 index 00000000..8e5c5243 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-compound-op/expect/disAmbiguate.temper @@ -0,0 +1,3 @@ +## `let` macro applied + var x = 1; + x = (nym`do_call__+_`[PlusIntInt, PlusIntInt64, PlusFltFlt])(x, 2); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-compound-op/expect/import.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-compound-op/expect/import.temper new file mode 100644 index 00000000..ead20f51 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-compound-op/expect/import.temper @@ -0,0 +1,3 @@ + nym`@`(var, let x = 1); +## That resolves early to an assignment to x with a desugar call with the builtin variants. + x = (nym`do_call__+_`[PlusIntInt, PlusIntInt64, PlusFltFlt])(x, 2); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-compound-op/expect/parse.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-compound-op/expect/parse.temper new file mode 100644 index 00000000..d2832e48 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-compound-op/expect/parse.temper @@ -0,0 +1,3 @@ + nym`@`(var, let x = 1); +## Parse produces a desugar call for `+=` + desugarOperation (nym`+=`, x, 2); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-compound-op/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-compound-op/expect/syntaxMacro.temper new file mode 100644 index 00000000..6ab0c95e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-compound-op/expect/syntaxMacro.temper @@ -0,0 +1,3 @@ +## Names resolved + var x__0 = 1; + x__0 = (nym`do_call__+_`[PlusIntInt, PlusIntInt64, PlusFltFlt])(x__0, 2); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-compound-op/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-compound-op/work/test/test.temper new file mode 100644 index 00000000..9815561a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-compound-op/work/test/test.temper @@ -0,0 +1,2 @@ +var x = 1; +x += 2; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-prefix-op-with-complex-operand/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-prefix-op-with-complex-operand/expect/syntaxMacro.temper new file mode 100644 index 00000000..0931a55e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-prefix-op-with-complex-operand/expect/syntaxMacro.temper @@ -0,0 +1,40 @@ + @fn let `test//`.f; + `test//`.f = fn f(ls__0 /* aka ls */: ListBuilder, j__0 /* aka j */: Int32) /* return__0 */: (Void) { + fn__0: do { + var i__0 = j__0; +## To do `ls[i++]--`, first we need to get the index `i++`. + do { + let t#0; +## `t#0` lets us avoid multiple evaluation of `ls`. + t#0 = ls__0; + let t#1; + t#1 = do { + let postfixReturn#0 = i__0; + i__0 = do_call_succ(postfixReturn#0); + postfixReturn#0 + }; +## Now, `t#1` has the post-incremented `i`. + do { +## Reading the array. + let postfixReturn#1 = do_call_get(t#0, t#1); +## Writing the array. Same array and element. + do_call_set(t#0, t#1, do_call_pred(postfixReturn#1)); +## The result is what was read from the array beforehand. + postfixReturn#1 + } + }; +## Not as much to do for pre-increment and pre-decreemnt. +## `--ls[ls[++i]]` is what we're handling here. +## + do { + let t#2; +## Again, we get the subject. The subject is a simple name, +## but if it were `var`, reading it's property could have the +## side-effect of setting it. + t#2 = ls__0; + let t#3; + t#3 = do_call_get(ls__0, i__0 = do_call_succ(i__0)); + do_call_set(t#2, t#3, do_call_pred(do_call_get(t#2, t#3))) + }; + } + }; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-prefix-op-with-complex-operand/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-prefix-op-with-complex-operand/work/test/test.temper new file mode 100644 index 00000000..c7210a27 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-prefix-op-with-complex-operand/work/test/test.temper @@ -0,0 +1,5 @@ +export let f(ls: ListBuilder, j: Int32): Void { + var i = j; + ls[i++]--; + --ls[ls[++i]]; +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-prefix-op/expect/import.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-prefix-op/expect/import.temper new file mode 100644 index 00000000..f885efa9 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-prefix-op/expect/import.temper @@ -0,0 +1,16 @@ + nym`@`(export, let(\word, f, do { + \_complexArg_; + x; + \type; + Int32 + }, \outType, Int32, fn { + nym`@`(var, let y = x); + do { +## Name allocated to do pre-capture + let postfixReturn#0 = y; +## Dot desugaring here in case there are extensions to do succ and pred. + y = postfixReturn#0.pred(); + postfixReturn#0 + }; + y = y.succ() + })) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-prefix-op/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-prefix-op/expect/syntaxMacro.temper new file mode 100644 index 00000000..1aab9927 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-prefix-op/expect/syntaxMacro.temper @@ -0,0 +1,12 @@ +@fn let `test//`.f; +`test//`.f = fn f(x__0 /* aka x */: Int32) /* return__0 */: (Int32) { + fn__0: do { + var y__0 = x__0; + do { + let postfixReturn#0 = y__0; + y__0 = do_call_pred(postfixReturn#0); + postfixReturn#0 + }; + y__0 = do_call_succ(y__0) + } +}; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-prefix-op/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-prefix-op/work/test/test.temper new file mode 100644 index 00000000..660d003c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/desugar-prefix-op/work/test/test.temper @@ -0,0 +1,5 @@ +export let f(x: Int32): Int32 { + var y = x; + y--; + ++y +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/doc-strings-from-markdown/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/doc-strings-from-markdown/expect/syntaxMacro.temper new file mode 100644 index 00000000..0fe1a489 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/doc-strings-from-markdown/expect/syntaxMacro.temper @@ -0,0 +1,30 @@ +## No "Geometry" for the class doc comment + @typeDecl(Point__0) @stay @docString((["Point represents a two-dimensional point.", "Point represents a two-dimensional point.", "test/test.temper.md"])) let Point__0 = type (Point__0); + REM("Point represents a two-dimensional point.", true, true); + class(\word, \Point, \concrete, true, @typeDefined(Point__0) fn { + Point__0 extends AnyValue; +## x's docs don't talk about the factory + @docString((["x is the x coordinate.", "x is the x coordinate.", "test/test.temper.md"])) @constructorProperty @maybeVar @visibility(\public) let x__0: Float64; + @docString((["y is the y coordinate.", "y is the y coordinate.", "test/test.temper.md"])) @constructorProperty @maybeVar @visibility(\public) let y__0: Float64; + REM("magnitude is the distance of this point from the origin.", true, true); + REM("It is always >= 0.", true, true); +## magnitude has its doc string + @fn let magnitude__0 = (@docString((["magnitude is the distance of this point from the origin.", "magnitude is the distance of this point from the origin.\n\nIt is always >= 0.", "test/test.temper.md"])) fn magnitude(@impliedThis(Point__0) this__0: Point__0) /* return__0 */: (Float64) { + fn__0: do { + do_call_sqrt(do_iget_x(type (Point__0), this(Point__0)) * do_iget_x(type (Point__0), this(Point__0)) + do_iget_y(type (Point__0), this(Point__0)) * do_iget_y(type (Point__0), this(Point__0))) + } + }); + @visibility(\public) let constructor__0 = fn constructor(@impliedThis(Point__0) this__1: Point__0, x__1 /* aka x */: Float64, y__1 /* aka y */: Float64) /* return__1 */: Void { + do { + let t#0; + do_iset_x(type (Point__0), this(Point__0), t#0 = x__1); + t#0 + }; + do { + let t#1; + do_iset_y(type (Point__0), this(Point__0), t#1 = y__1); + t#1 + }; + }; + }); + Point__0 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/doc-strings-from-markdown/work/test/test.temper.md b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/doc-strings-from-markdown/work/test/test.temper.md new file mode 100644 index 00000000..e179a4ce --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/doc-strings-from-markdown/work/test/test.temper.md @@ -0,0 +1,24 @@ +# Geometry + +Point represents a two-dimensional point. + + class Point( + +Point's factory takes two coordinates. TODO: another factory for polar form. + +x is the x coordinate. + + public x: Float64, + +y is the y coordinate. + + public y: Float64, + ) { + +magnitude is the distance of this point from the origin. + +It is always >= 0. + + magnitude(): Float64 { (x * x + y * y).sqrt() } + + } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/dots-to-symbols/expect/syntaxMacro.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/dots-to-symbols/expect/syntaxMacro.lispy new file mode 100644 index 00000000..457280dc --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/dots-to-symbols/expect/syntaxMacro.lispy @@ -0,0 +1,82 @@ +[ + "Block", + [ + [ + "Decl", + [ + [ + "LeftName", + "foo__0" + ], + [ + "Value", + "\\init: Symbol" + ], + [ + "Call", + [ + [ + "RightName", + "f" + ] + ] + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.foo\u0022: String" + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "bar__1" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.bar\u0022: String" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "nym`do_call__+_`[PlusIntInt, PlusIntInt64, PlusFltFlt]: Function" + ], + [ + "Call", + [ + [ + "Value", + "do_get_bar: Function" + ], + [ + "RightName", + "foo__0" + ] + ] + ], + [ + "RightName", + "bar__1" + ] + ] + ], + [ + "Value", + "void: Void" + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/dots-to-symbols/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/dots-to-symbols/expect/syntaxMacro.temper new file mode 100644 index 00000000..e92af52f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/dots-to-symbols/expect/syntaxMacro.temper @@ -0,0 +1,2 @@ +let foo__0 = f(), bar__1; +do_get_bar(foo__0) + bar__1; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/dots-to-symbols/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/dots-to-symbols/work/test/test.temper new file mode 100644 index 00000000..5792452c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/dots-to-symbols/work/test/test.temper @@ -0,0 +1,2 @@ +let foo = f(), bar; +foo.bar + bar; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/fn-formal-args-do-not-cross-scopes/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/fn-formal-args-do-not-cross-scopes/expect/syntaxMacro.temper new file mode 100644 index 00000000..df337619 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/fn-formal-args-do-not-cross-scopes/expect/syntaxMacro.temper @@ -0,0 +1,9 @@ +@fn let f__0, T__0 = "T"; +@typeFormal(\T) @typeDecl(T__1) let T__1 = type (T__1); +T__1 extends AnyValue; +f__0 = fn f(x__0 /* aka x */: T__1) /* return__0 */: (T__1) { + fn__0: do { + x__0 + } +}; +let t__0 = T__0; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/fn-formal-args-do-not-cross-scopes/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/fn-formal-args-do-not-cross-scopes/work/test/test.temper new file mode 100644 index 00000000..af57bed7 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/fn-formal-args-do-not-cross-scopes/work/test/test.temper @@ -0,0 +1,3 @@ +let T = "T"; +let f(x: T): T { x } +let t = T; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-extracts-declarations-just-init/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-extracts-declarations-just-init/expect/syntaxMacro.temper new file mode 100644 index 00000000..eba85768 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-extracts-declarations-just-init/expect/syntaxMacro.temper @@ -0,0 +1,6 @@ +do { + let i__0 = 0; + for(\__flowInit, {class: Empty__0}, fn { + body; + }) +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-extracts-declarations-just-init/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-extracts-declarations-just-init/work/test/test.temper new file mode 100644 index 00000000..3394febd --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-extracts-declarations-just-init/work/test/test.temper @@ -0,0 +1 @@ +for(let i = 0;;) { body; } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-extracts-declarations-minimal/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-extracts-declarations-minimal/expect/syntaxMacro.temper new file mode 100644 index 00000000..8fdf7e60 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-extracts-declarations-minimal/expect/syntaxMacro.temper @@ -0,0 +1,3 @@ +for(fn { + body; +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-extracts-declarations-minimal/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-extracts-declarations-minimal/work/test/test.temper new file mode 100644 index 00000000..5da58d88 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-extracts-declarations-minimal/work/test/test.temper @@ -0,0 +1 @@ +for(;;) { body; } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-extracts-declarations/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-extracts-declarations/expect/syntaxMacro.temper new file mode 100644 index 00000000..dd8dbd78 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-extracts-declarations/expect/syntaxMacro.temper @@ -0,0 +1,6 @@ +do { + var i__0 = 0; + for(\__flowInit, {class: Empty__0}, \cond, i__0 < 3, \incr, i__0 = i__0 + 1, fn { + body; + }) +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-extracts-declarations/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-extracts-declarations/work/test/test.temper new file mode 100644 index 00000000..799339fd --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-extracts-declarations/work/test/test.temper @@ -0,0 +1 @@ +for (var i = 0; i < 3; i += 1) { body; } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-extracts-multiple-declarations/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-extracts-multiple-declarations/expect/syntaxMacro.temper new file mode 100644 index 00000000..a6e6ebb5 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-extracts-multiple-declarations/expect/syntaxMacro.temper @@ -0,0 +1,6 @@ +do { + var i__0: Int = 0, x__1 = 3; + for(\__flowInit, {class: Empty__0}, \cond, i__0 < 3, \incr, i__0 = i__0 + 1, fn { + body; + }) +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-extracts-multiple-declarations/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-extracts-multiple-declarations/work/test/test.temper new file mode 100644 index 00000000..a8b34f99 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-extracts-multiple-declarations/work/test/test.temper @@ -0,0 +1 @@ +for (var i: Int = 0, x = 3; i < 3; i += 1) { body; } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-keeps-label/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-keeps-label/expect/syntaxMacro.temper new file mode 100644 index 00000000..7e278593 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-keeps-label/expect/syntaxMacro.temper @@ -0,0 +1,8 @@ +do { + var i__0 = 0; + label__0: do { + for(\__flowInit, {class: Empty__0}, \cond, i__0 < 3, \incr, i__0 = i__0 + 1, fn { + body; + }) + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-keeps-label/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-keeps-label/work/test/test.temper new file mode 100644 index 00000000..2a524212 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-keeps-label/work/test/test.temper @@ -0,0 +1 @@ +label: for (var i = 0; i < 3; i += 1) { body; } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-like-extracts-declarations/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-like-extracts-declarations/expect/syntaxMacro.temper new file mode 100644 index 00000000..b43ca294 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-like-extracts-declarations/expect/syntaxMacro.temper @@ -0,0 +1,6 @@ +do { + let i__0 = 0; + foo(\__flowInit, {class: Empty__0}, \cond, i__0 < 3, \incr, i__0 = i__0 + 1, fn { + body; + }) +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-like-extracts-declarations/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-like-extracts-declarations/work/test/test.temper new file mode 100644 index 00000000..fc51bbe9 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-loop-like-extracts-declarations/work/test/test.temper @@ -0,0 +1 @@ +foo (let i = 0; i < 3; i += 1) { body; } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-of-loop-var-available-in-body/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-of-loop-var-available-in-body/expect/syntaxMacro.temper new file mode 100644 index 00000000..4560b825 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-of-loop-var-available-in-body/expect/syntaxMacro.temper @@ -0,0 +1,5 @@ +let x__0 = f(); +do_call_forEach(x__0, fn (x__1) { + x__1 +}); +x__0 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-of-loop-var-available-in-body/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-of-loop-var-available-in-body/work/test/test.temper new file mode 100644 index 00000000..f4ad92d4 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/for-of-loop-var-available-in-body/work/test/test.temper @@ -0,0 +1,5 @@ +let x = f(); +for (let x of x) { + x +} +x diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/generic-fn/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/generic-fn/expect/define.temper new file mode 100644 index 00000000..08967711 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/generic-fn/expect/define.temper @@ -0,0 +1,10 @@ +@fn let identity__0; +@typeFormal(\T) @typeDecl(T__0) let T__0; +T__0 = type (T__0); +T__0 extends AnyValue; +identity__0 = (@stay fn identity(x__0 /* aka x */: T__0) /* return__0 */: T__0 { + fn__0: do { + x__0 + } +}); +42 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/generic-fn/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/generic-fn/expect/run-result.json new file mode 100644 index 00000000..a961b07f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/generic-fn/expect/run-result.json @@ -0,0 +1 @@ +"42: Int32" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/generic-fn/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/generic-fn/expect/syntaxMacro.temper new file mode 100644 index 00000000..07e2e342 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/generic-fn/expect/syntaxMacro.temper @@ -0,0 +1,9 @@ +@fn let identity__0; +@typeFormal(\T) @typeDecl(T__0) let T__0 = type (T__0); +T__0 extends AnyValue; +identity__0 = fn identity(x__0 /* aka x */: T__0) /* return__0 */: (T__0) { + fn__0: do { + x__0 + } +}; +identity__0(42) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/generic-fn/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/generic-fn/work/test/test.temper new file mode 100644 index 00000000..ddc92b98 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/generic-fn/work/test/test.temper @@ -0,0 +1,2 @@ +let identity(x: T): T { x } +identity(42) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/generic-function-in-docs/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/generic-function-in-docs/expect/syntaxMacro.temper new file mode 100644 index 00000000..1a9039cd --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/generic-function-in-docs/expect/syntaxMacro.temper @@ -0,0 +1,7 @@ +@fn let f__0; +@typeFormal(\T) @typeDecl(T__0) @withinDocFold let T__0 = type (T__0); +@typeFormal(\U) @typeDecl(U__0) @withinDocFold let U__0 = type (U__0); +U__0 extends T__0; +f__0 = fn f(x__0 /* aka x */: T__0) /* return__0 */: (U__0) { + x__0 +}; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/generic-function-in-docs/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/generic-function-in-docs/work/test/test.temper new file mode 100644 index 00000000..7898d3a6 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/generic-function-in-docs/work/test/test.temper @@ -0,0 +1 @@ +let f(x: T): U { x } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/getter-and-setter-inherit-visibility-from-property/expect/syntaxMacro-types.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/getter-and-setter-inherit-visibility-from-property/expect/syntaxMacro-types.json new file mode 100644 index 00000000..811f6f70 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/getter-and-setter-inherit-visibility-from-property/expect/syntaxMacro-types.json @@ -0,0 +1,49 @@ +{ + "Anon": { + "properties": [ + { + "name": "_x", + "visibility": "private", + "abstract": false + }, + { + "name": "x", + "abstract": true, + "visibility": "public", + "getter": "get.x", + "setter": "set.x" + } + ], + "methods": [ + { + "name": "get.x", + "symbol": "x", + "visibility": "public", + "open": false, + "kind": "Getter" + }, + { + "name": "set.x", + "symbol": "x", + "visibility": "public", + "open": false, + "kind": "Setter" + }, + { + "name": "constructor", + "visibility": "public", + "open": false, + "kind": "Constructor" + } + ], + "supers": [ + "AnyValue__0" + ] + }, + "AnyValue": { + "abstract": true + }, + "Void": { + "supers": [] + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/getter-and-setter-inherit-visibility-from-property/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/getter-and-setter-inherit-visibility-from-property/expect/syntaxMacro.temper new file mode 100644 index 00000000..94839925 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/getter-and-setter-inherit-visibility-from-property/expect/syntaxMacro.temper @@ -0,0 +1,28 @@ +@typeDecl(Anon__0) @stay let t#0 = type (Anon__0); +class(\concrete, true, @typeDefined(Anon__0) fn { + Anon__0 extends AnyValue; + @constructorProperty @property(\_x) @maybeVar @visibility(\private) let _x__5; + @property(\x) @visibility(\public) var x__6; + @method(\x) @getter @fn let nym`get.x__7` = fn nym`get.x`(@impliedThis(Anon__0) this__2: Anon__0) { + fn__8: do { + do_iget__x(type (Anon__0), this(Anon__0)) + } + }; + @method(\x) @setter @fn let nym`set.x__9` = fn nym`set.x`(@impliedThis(Anon__0) this__3: Anon__0, newValue__10 /* aka newValue */) /* return__0 */: Void { + fn__11: do { + do { + let t#1; + do_iset__x(type (Anon__0), this(Anon__0), t#1 = newValue__10); + t#1 + } + } + }; + @method(\constructor) @visibility(\public) let constructor__12 = fn constructor(@impliedThis(Anon__0) this__13: Anon__0, _x__14 /* aka _x */) /* return__1 */: Void { + do { + let t#2; + do_iset__x(type (Anon__0), this(Anon__0), t#2 = _x__14); + t#2 + }; + }; +}); +type (Anon__0) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/getter-and-setter-inherit-visibility-from-property/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/getter-and-setter-inherit-visibility-from-property/work/test/test.temper new file mode 100644 index 00000000..3dd3e0ff --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/getter-and-setter-inherit-visibility-from-property/work/test/test.temper @@ -0,0 +1,5 @@ +class(private _x) { + public x; + get x() { _x } + set x(newValue) { _x = newValue } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/let-function-body-required-but-checked-later/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/let-function-body-required-but-checked-later/expect/syntaxMacro.temper new file mode 100644 index 00000000..b9232747 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/let-function-body-required-but-checked-later/expect/syntaxMacro.temper @@ -0,0 +1,6 @@ +@fn let f__0; +f__0 = fn f { + fn__0: do { + abstractPanic() + } +}; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/let-function-body-required-but-checked-later/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/let-function-body-required-but-checked-later/work/test/test.temper new file mode 100644 index 00000000..599981c2 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/let-function-body-required-but-checked-later/work/test/test.temper @@ -0,0 +1 @@ +let f() diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/let-function-body-required-without-name/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/let-function-body-required-without-name/expect/syntaxMacro.temper new file mode 100644 index 00000000..eb993c5c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/let-function-body-required-without-name/expect/syntaxMacro.temper @@ -0,0 +1 @@ +error (MissingName) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/let-function-body-required-without-name/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/let-function-body-required-without-name/work/test/test.temper new file mode 100644 index 00000000..6e82d104 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/let-function-body-required-without-name/work/test/test.temper @@ -0,0 +1 @@ +let() diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/let-function-name-required/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/let-function-name-required/expect/syntaxMacro.temper new file mode 100644 index 00000000..eb993c5c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/let-function-name-required/expect/syntaxMacro.temper @@ -0,0 +1 @@ +error (MissingName) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/let-function-name-required/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/let-function-name-required/work/test/test.temper new file mode 100644 index 00000000..fb1bd521 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/let-function-name-required/work/test/test.temper @@ -0,0 +1 @@ +let() {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/let-of-fn/expect/syntaxMacro.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/let-of-fn/expect/syntaxMacro.lispy new file mode 100644 index 00000000..79ec90fa --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/let-of-fn/expect/syntaxMacro.lispy @@ -0,0 +1,281 @@ +[ + "Block", + [ + [ + "Decl", + [ + [ + "LeftName", + "f__0" + ], + [ + "Value", + "\\init: Symbol" + ], + [ + "Fun", + [ + [ + "Decl", + [ + [ + "LeftName", + "x__1" + ], + [ + "Value", + "\\word: Symbol" + ], + [ + "Value", + "\\x: Symbol" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.f().(x)\u0022: String" + ] + ] + ], + [ + "Value", + "\\returnedFrom: Symbol" + ], + [ + "Value", + "true: Boolean" + ], + [ + "Value", + "\\word: Symbol" + ], + [ + "Value", + "\\f: Symbol" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.f()\u0022: String" + ], + [ + "Block", + [ + [ + "Value", + "\\label: Symbol" + ], + [ + "LeftName", + "fn__2" + ] + ] + ] + ] + ], + [ + "Value", + "\\fn: Symbol" + ], + [ + "Value", + "void: Void" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.f()\u0022: String" + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "g__3" + ], + [ + "Value", + "\\init: Symbol" + ], + [ + "Fun", + [ + [ + "Decl", + [ + [ + "LeftName", + "y__4" + ], + [ + "Value", + "\\word: Symbol" + ], + [ + "Value", + "\\y: Symbol" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.g().(y)\u0022: String" + ] + ] + ], + [ + "Value", + "\\returnedFrom: Symbol" + ], + [ + "Value", + "true: Boolean" + ], + [ + "Value", + "\\word: Symbol" + ], + [ + "Value", + "\\g: Symbol" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.g()\u0022: String" + ], + [ + "Block", + [ + [ + "Value", + "\\label: Symbol" + ], + [ + "LeftName", + "fn__5" + ] + ] + ] + ] + ], + [ + "Value", + "\\fn: Symbol" + ], + [ + "Value", + "void: Void" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.g()\u0022: String" + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "h__0" + ], + [ + "Value", + "\\init: Symbol" + ], + [ + "Fun", + [ + [ + "Decl", + [ + [ + "LeftName", + "z__0" + ], + [ + "Value", + "\\word: Symbol" + ], + [ + "Value", + "\\z: Symbol" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.h().(z)\u0022: String" + ] + ] + ], + [ + "Value", + "\\returnedFrom: Symbol" + ], + [ + "Value", + "true: Boolean" + ], + [ + "Block", + [ + [ + "Value", + "\\label: Symbol" + ], + [ + "LeftName", + "fn__0" + ] + ] + ] + ] + ], + [ + "Value", + "\\var: Symbol" + ], + [ + "Value", + "void: Void" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.h()\u0022: String" + ] + ] + ], + [ + "Value", + "void: Void" + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/let-of-fn/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/let-of-fn/work/test/test.temper new file mode 100644 index 00000000..6e20b109 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/let-of-fn/work/test/test.temper @@ -0,0 +1,3 @@ +let f = fn (x) {}; +let g = fn g(y) {}; +var h = fn (z) {}; // *var* fn should get neither symbol nor qname diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/making-this-unambiguous/expect/syntaxMacro-types.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/making-this-unambiguous/expect/syntaxMacro-types.json new file mode 100644 index 00000000..12b4132e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/making-this-unambiguous/expect/syntaxMacro-types.json @@ -0,0 +1,59 @@ +{ + "AnyValue": { + "abstract": true + }, + "C": { + "word": "C", + "typeParameters": [ + { + "name": "T__2" + } + ], + "supers": [ + "I__0" + ], + "properties": [ + { + "name": "y", + "symbol": "y", + "abstract": false, + "visibility": "public" + } + ], + "methods": [ + { + "name": "f", + "symbol": "f", + "open": false, + "visibility": "private" + }, + { + "name": "constructor", + "open": false, + "visibility": "public", + "kind": "Constructor" + } + ] + }, + "I": { + "word": "I", + "abstract": true, + "properties": [ + { + "name": "x", + "symbol": "x", + "abstract": true, + "visibility": "public" + } + ], + "supers": [ + "AnyValue__0" + ] + }, + "T": { + "word": "T" + }, + "Void": { + "supers": [] + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/making-this-unambiguous/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/making-this-unambiguous/expect/syntaxMacro.temper new file mode 100644 index 00000000..e679bb5f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/making-this-unambiguous/expect/syntaxMacro.temper @@ -0,0 +1,25 @@ +@typeDecl(I__0) @stay let I__0 = type (I__0); +@typeDecl(C__0) @stay let C__0 = type (C__0); +interface(\word, \I, \concrete, false, @typeDefined(I__0) fn { + I__0 extends AnyValue; + @property(\x) @maybeVar let x__6; +}); +let x__7, y__8, z__9; +class(\word, \C, \concrete, true, @typeDefined(C__0) fn { + @typeFormal(\T) @memberTypeFormal(\T) @typeDefined(T__2) let T__2 = type (T__2); + C__0 extends I__0; + @constructorProperty @property(\y) @maybeVar @visibility(\public) let y__14; + @method(\f) @visibility(\private) @fn let f__12 = fn f(@impliedThis(C__0) this__2: C__0) { + fn__13: do { + do_iget_x(type (C__0), this(C__0)) + do_iget_y(type (C__0), this(C__0)) + z__9 + } + }; + @method(\constructor) @visibility(\public) let constructor__15 = fn constructor(@impliedThis(C__0) this__16: C__0, y__17 /* aka y */) /* return__0 */: Void { + do { + let t#0; + do_iset_y(type (C__0), this(C__0), t#0 = y__17); + t#0 + }; + }; +}); +C__0 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/making-this-unambiguous/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/making-this-unambiguous/work/test/test.temper new file mode 100644 index 00000000..04f7ad48 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/making-this-unambiguous/work/test/test.temper @@ -0,0 +1,11 @@ +interface I { + x; +} + +let x, y, z; + +class C(public y) extends I { + private f() { + x + y + z // x is inherited, y is locally defined, z is closed over. + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/malformed-numeric-literal-errors/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/malformed-numeric-literal-errors/expect/errors.json new file mode 100644 index 00000000..5be59152 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/malformed-numeric-literal-errors/expect/errors.json @@ -0,0 +1,3 @@ +[ + "Malformed number!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/malformed-numeric-literal-errors/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/malformed-numeric-literal-errors/expect/syntaxMacro.temper new file mode 100644 index 00000000..e29ab270 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/malformed-numeric-literal-errors/expect/syntaxMacro.temper @@ -0,0 +1 @@ +let `test//`.oneTwoThree = error (list("123i6")); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/malformed-numeric-literal-errors/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/malformed-numeric-literal-errors/work/test/test.temper new file mode 100644 index 00000000..13a47377 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/malformed-numeric-literal-errors/work/test/test.temper @@ -0,0 +1 @@ +export let oneTwoThree = 123i6; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/method-without-body/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/method-without-body/expect/syntaxMacro.temper new file mode 100644 index 00000000..e86a5520 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/method-without-body/expect/syntaxMacro.temper @@ -0,0 +1,10 @@ +@typeDecl(I__0) @stay let I__0 = type (I__0); +interface(\word, \I, \concrete, false, @typeDefined(I__0) fn { + I__0 extends AnyValue; + @method(\method) @fn let method__4 = fn method(@impliedThis(I__0) this__1: I__0) { + fn__5: do { + pureVirtual() + } + }; +}); +I__0 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/method-without-body/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/method-without-body/work/test/test.temper new file mode 100644 index 00000000..329fa80c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/method-without-body/work/test/test.temper @@ -0,0 +1,5 @@ + + interface I { + method(); + } + diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/multi-declarations/expect/syntaxMacro.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/multi-declarations/expect/syntaxMacro.lispy new file mode 100644 index 00000000..720d40e0 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/multi-declarations/expect/syntaxMacro.lispy @@ -0,0 +1,172 @@ +[ + "Block", + [ + [ + "Block", + [ + [ + "Decl", + [ + [ + "LeftName", + "t#0" + ], + [ + "Value", + "\\init: Symbol" + ], + [ + "RightName", + "S" + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "t#1" + ], + [ + "Value", + "\\init: Symbol" + ], + [ + "RightName", + "x" + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "t#2" + ], + [ + "Value", + "\\init: Symbol" + ], + [ + "RightName", + "T" + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "a__3" + ], + [ + "Value", + "\\type: Symbol" + ], + [ + "RightName", + "t#2" + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "b__4" + ], + [ + "Value", + "\\type: Symbol" + ], + [ + "Call", + [ + [ + "RightName", + "\u0026" + ], + [ + "RightName", + "t#0" + ], + [ + "RightName", + "t#2" + ] + ] + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "c__5" + ], + [ + "Value", + "\\type: Symbol" + ], + [ + "RightName", + "t#2" + ], + [ + "Value", + "\\init: Symbol" + ], + [ + "RightName", + "t#1" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "nym`=`: Function" + ], + [ + "Call", + [ + [ + "Value", + "nym`,`: Function" + ], + [ + "LeftName", + "a__3" + ], + [ + "LeftName", + "b__4" + ], + [ + "LeftName", + "c__5" + ] + ] + ], + [ + "Call", + [ + [ + "RightName", + "f" + ] + ] + ] + ] + ] + ] + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/multi-declarations/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/multi-declarations/work/test/test.temper new file mode 100644 index 00000000..554a9f40 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/multi-declarations/work/test/test.temper @@ -0,0 +1 @@ +let [a, b is S, c = x]: T = f() diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/mutually-referencing-class-types/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/mutually-referencing-class-types/expect/syntaxMacro.temper new file mode 100644 index 00000000..8526ce31 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/mutually-referencing-class-types/expect/syntaxMacro.temper @@ -0,0 +1,26 @@ +@typeDecl(C__0) @stay let C__0 = type (C__0); +@typeDecl(D__0) @stay let D__0 = type (D__0); +class(\word, \D, \concrete, true, @typeDefined(D__0) fn { + D__0 extends AnyValue; + @constructorProperty @property(\c) @maybeVar @visibility(\private) let c__0: C__0; + @method(\constructor) @visibility(\public) let constructor__0 = fn constructor(@impliedThis(D__0) this__1: D__0, c__1 /* aka c */: C__0) /* return__1 */: Void { + do { + let t#0; + do_iset_c(type (D__0), this(D__0), t#0 = c__1); + t#0 + }; + }; +}); +class(\word, \C, \concrete, true, @typeDefined(C__0) fn { + C__0 extends AnyValue; + let typeof_d#0 = D__0?; + @constructorProperty @property(\d) @maybeVar @visibility(\private) let d__0: typeof_d#0; + @method(\constructor) @visibility(\public) let constructor__1 = fn constructor(@impliedThis(C__0) this__0: C__0, d__1 /* aka d */: typeof_d#0) /* return__0 */: Void { + do { + let t#1; + do_iset_d(type (C__0), this(C__0), t#1 = d__1); + t#1 + }; + }; +}); +D__0 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/mutually-referencing-class-types/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/mutually-referencing-class-types/work/test/test.temper new file mode 100644 index 00000000..47c55424 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/mutually-referencing-class-types/work/test/test.temper @@ -0,0 +1,2 @@ +class C(private d: D?) {} +class D(private c: C) {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/mutually-referencing-function-definition/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/mutually-referencing-function-definition/expect/syntaxMacro.temper new file mode 100644 index 00000000..3048669f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/mutually-referencing-function-definition/expect/syntaxMacro.temper @@ -0,0 +1,12 @@ +@fn let f__0, @fn g__0; +REM("These do not converge since neither has a base case, but they demonstrate hoisting.", null, false); +g__0 = fn g(x__0 /* aka x */) { + fn__0: do { + f__0(x__0 - 1) + } +}; +f__0 = fn f(x__1 /* aka x */) { + fn__1: do { + g__0(x__1 / 2) + } +}; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/mutually-referencing-function-definition/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/mutually-referencing-function-definition/work/test/test.temper new file mode 100644 index 00000000..c56c39f9 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/mutually-referencing-function-definition/work/test/test.temper @@ -0,0 +1,3 @@ +// These do not converge since neither has a base case, but they demonstrate hoisting. +let f(x) { g(x / 2) } +let g(x) { f(x - 1) } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/mutually-referencing-interface-types/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/mutually-referencing-interface-types/expect/syntaxMacro.temper new file mode 100644 index 00000000..46e9fdb7 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/mutually-referencing-interface-types/expect/syntaxMacro.temper @@ -0,0 +1,11 @@ +@typeDecl(I__0) @stay let I__0 = type (I__0); +@typeDecl(J__0) @stay let J__0 = type (J__0); +interface(\word, \J, \concrete, false, @typeDefined(J__0) fn { + J__0 extends AnyValue; + @property(\i) @maybeVar let i__0: I__0; +}); +interface(\word, \I, \concrete, false, @typeDefined(I__0) fn { + I__0 extends AnyValue; + @property(\j) @maybeVar let j__0: J__0; +}); +J__0 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/mutually-referencing-interface-types/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/mutually-referencing-interface-types/work/test/test.temper new file mode 100644 index 00000000..3adc3b2e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/mutually-referencing-interface-types/work/test/test.temper @@ -0,0 +1,2 @@ +interface I { j: J } +interface J { i: I } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/names-resolve-to-exported-names/expect/syntaxMacro.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/names-resolve-to-exported-names/expect/syntaxMacro.lispy new file mode 100644 index 00000000..bfa1992c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/names-resolve-to-exported-names/expect/syntaxMacro.lispy @@ -0,0 +1,48 @@ +[ + "Block", + [ + [ + "Decl", + [ + [ + "LeftName", + { + "type": "ExportedName", + "baseName": "x" + } + ], + [ + "Value", + "\\init: Symbol" + ], + [ + "Value", + "42: Int32" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.x\u0022: String" + ] + ] + ], + [ + "RightName", + { + "type": "ExportedName", + "baseName": "x" + } + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/names-resolve-to-exported-names/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/names-resolve-to-exported-names/expect/syntaxMacro.temper new file mode 100644 index 00000000..7372733c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/names-resolve-to-exported-names/expect/syntaxMacro.temper @@ -0,0 +1,2 @@ +let `test//`.x = 42; +`test//`.x diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/names-resolve-to-exported-names/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/names-resolve-to-exported-names/work/test/test.temper new file mode 100644 index 00000000..a8d363ca --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/names-resolve-to-exported-names/work/test/test.temper @@ -0,0 +1 @@ +export let x = 42; x diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/nested-arithmetic/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/nested-arithmetic/expect/syntaxMacro.temper new file mode 100644 index 00000000..4c596de9 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/nested-arithmetic/expect/syntaxMacro.temper @@ -0,0 +1,6 @@ +@fn let `test//`.negStr; +`test//`.negStr = fn negStr(x__0 /* aka x */: Int32) /* return__0 */: (String) { + fn__0: do { + do_call_toString(-1 * x__0) + } +}; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/nested-arithmetic/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/nested-arithmetic/work/test/test.temper new file mode 100644 index 00000000..e82db619 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/nested-arithmetic/work/test/test.temper @@ -0,0 +1,3 @@ +export let negStr(x: Int32): String { + (-1 * x).toString() +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/no-property-constructor-properties-in-property-bag/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/no-property-constructor-properties-in-property-bag/expect/errors.json new file mode 100644 index 00000000..a0a20d3e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/no-property-constructor-properties-in-property-bag/expect/errors.json @@ -0,0 +1,8 @@ +[ + { + "template": "NoSignatureMatches", + "values": [], + "left": 117, + "right": 137 + } +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/no-property-constructor-properties-in-property-bag/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/no-property-constructor-properties-in-property-bag/expect/syntaxMacro.temper new file mode 100644 index 00000000..091b120f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/no-property-constructor-properties-in-property-bag/expect/syntaxMacro.temper @@ -0,0 +1,20 @@ +@typeDecl(C__0) @stay let C__0 = type (C__0); +class(\word, \C, \concrete, true, @typeDefined(C__0) fn { + C__0 extends AnyValue; + @constructorProperty @maybeVar @visibility(\private) let x__0: Int; + do {}; + @maybeVar @visibility(\private) let z__0: Int; + @visibility(\public) let constructor__0 = fn constructor(@impliedThis(C__0) this__0: C__0, x__1 /* aka x */: Int, @constructorProperty y__0 /* aka y */: Int) /* return__0 */: Void { + do { + let t#0; + do_iset_x(type (C__0), this(C__0), t#0 = x__1); + t#0 + }; + do { + let t#1; + do_iset_z(type (C__0), this(C__0), t#1 = y__0 + 1); + t#1 + }; + }; +}); +let `test//`.cs = list(new C__0(\x, 1, \y, 2), new(\x, 1, \y, 2, \z, 3)); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/no-property-constructor-properties-in-property-bag/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/no-property-constructor-properties-in-property-bag/work/test/test.temper new file mode 100644 index 00000000..14134c3a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/no-property-constructor-properties-in-property-bag/work/test/test.temper @@ -0,0 +1,8 @@ +class C(private x: Int, @noProperty let y: Int) { + private z: Int = y + 1; +} + +export let cs = [ + { x: 1, y: 2 }, + { x: 1, y: 2, z: 3 }, // ERROR: z not allowed here +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/null-chaining-desugaring/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/null-chaining-desugaring/expect/syntaxMacro.temper new file mode 100644 index 00000000..ce392430 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/null-chaining-desugaring/expect/syntaxMacro.temper @@ -0,0 +1,37 @@ +@stay @imported(\(`test//c/`.C)) let C__0 = type (C), @imported(\(`test//c/`.g)) @fn g__0 = `test//c/`.g, @imported(\(`test//c/`.complexSubject)) @fn complexSubject__0 = (fn complexSubject), @fn f__0; +f__0 = fn f(c__0 /* aka c */: C__0?) /* return__0 */: (Void) { + fn__0: do { + g__0({ + if (isNull(c__0)) { + null + } else { + do_get_prop(notNull(c__0)) + } + }); + g__0({ + let subject#0; + subject#0 = complexSubject__0(c__0); + if (isNull(subject#0)) { + null + } else { + do_get_prop(notNull(subject#0)) + } + }); + g__0({ + if (isNull(c__0)) { + null + } else { + do_call_method(notNull(c__0)) + } + }); + g__0({ + let subject#1; + subject#1 = complexSubject__0(c__0); + if (isNull(subject#1)) { + null + } else { + do_call_method(notNull(subject#1)) + } + }); + } +}; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/null-chaining-desugaring/work/test/c/c.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/null-chaining-desugaring/work/test/c/c.temper new file mode 100644 index 00000000..8ab162da --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/null-chaining-desugaring/work/test/c/c.temper @@ -0,0 +1,10 @@ +// A class to null chain to. +export class C(public prop: String) { + public method(): String; +} + +// Somewhere to send null chaining uses. +export let g(x: String?): Void { if (x != null) { console.log(x) }; } + +// Calls to complexSubject shouldn't be duplicated +export let complexSubject(c: C?): C? { c } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/null-chaining-desugaring/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/null-chaining-desugaring/work/test/test.temper new file mode 100644 index 00000000..f91b9195 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/null-chaining-desugaring/work/test/test.temper @@ -0,0 +1,10 @@ +let { C, g, complexSubject } = import("./c"); + +let f(c: C?): Void { + g(c?.prop); + g(complexSubject(c)?.prop); + + g(c?.method()); + g(complexSubject(c)?.method()); +} + diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-literal-multiple-matches-nested/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-literal-multiple-matches-nested/work/test/test.temper new file mode 100644 index 00000000..2aa1978f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-literal-multiple-matches-nested/work/test/test.temper @@ -0,0 +1,5 @@ +class Apple(private hi: Int) {} +let nest(): Void { + class Banana(private hi: Int, public ha: Int = 0) {} + { hi: 5 } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-literal-multiple-matches/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-literal-multiple-matches/work/test/test.temper new file mode 100644 index 00000000..914f61dc --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-literal-multiple-matches/work/test/test.temper @@ -0,0 +1,3 @@ +class Apple(public hi: Int) {} +class Banana(public hi: Int) {} +{ hi: 5 } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-literal-no-matches/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-literal-no-matches/expect/errors.json new file mode 100644 index 00000000..e699b95b --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-literal-no-matches/expect/errors.json @@ -0,0 +1,3 @@ +[ + "No signature matches!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-literal-no-matches/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-literal-no-matches/expect/syntaxMacro.temper new file mode 100644 index 00000000..ed83cf0e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-literal-no-matches/expect/syntaxMacro.temper @@ -0,0 +1 @@ +new(\hi, 5) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-literal-no-matches/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-literal-no-matches/work/test/test.temper new file mode 100644 index 00000000..ab989a77 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-literal-no-matches/work/test/test.temper @@ -0,0 +1 @@ +{ hi: 5 } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-literal-overloads/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-literal-overloads/work/test/test.temper new file mode 100644 index 00000000..aea17dd2 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-literal-overloads/work/test/test.temper @@ -0,0 +1,6 @@ +{ hi: 5 } +class Thing { + public constructor(hi: Int) { } + public constructor(lo: Int) { } +} +{ lo: 5 } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-punning/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-punning/expect/errors.json new file mode 100644 index 00000000..e699b95b --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-punning/expect/errors.json @@ -0,0 +1,3 @@ +[ + "No signature matches!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-punning/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-punning/expect/syntaxMacro.temper new file mode 100644 index 00000000..5cbd39ec --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-punning/expect/syntaxMacro.temper @@ -0,0 +1,2 @@ +let x__0 = 1; +new(\x, x__0) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-punning/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-punning/work/test/test.temper new file mode 100644 index 00000000..c1063f8a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/object-punning/work/test/test.temper @@ -0,0 +1,2 @@ +let x = 1; +{ x } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/quoted-names/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/quoted-names/expect/syntaxMacro.temper new file mode 100644 index 00000000..cb34f8ec --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/quoted-names/expect/syntaxMacro.temper @@ -0,0 +1,2 @@ +let x__0, y__1; +f(x__0, y__1, x__0, y__1) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/quoted-names/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/quoted-names/work/test/test.temper new file mode 100644 index 00000000..3bfb7232 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/quoted-names/work/test/test.temper @@ -0,0 +1,2 @@ +let nym`x`, y; +f(x, y, nym`x`, nym`y`) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/referenced-to-pre-resolved-property-names-recognized-as-this-references/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/referenced-to-pre-resolved-property-names-recognized-as-this-references/expect/syntaxMacro.temper new file mode 100644 index 00000000..c10b9801 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/referenced-to-pre-resolved-property-names-recognized-as-this-references/expect/syntaxMacro.temper @@ -0,0 +1,17 @@ + @typeDecl(C__0) @stay let C__0 = type (C__0); + class (\word, \C, \concrete, true, @typeDefined(C__0) fn { + C__0 extends AnyValue; + @visibility(\public) @constructorProperty @maybeVar let i__0: Int32; + @visibility(\public) let f__0 = fn (@impliedThis(C__0) this__0: C__0) /* return__0 */: Int32 { +## The resolved i reference here turned into a do_iget_i + do_iget_i(type (C__0), this(C__0)) + }; + @visibility(\public) let constructor__0 = fn constructor(@impliedThis(C__0) this__1: C__0, i__1 /* aka i */: Int32) /* return__1 */: Void { + do { + let t#0; + do_iset_i(type (C__0), this(C__0), t#0 = i__1); + t#0 + }; + }; + }); + C__0 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/reorder/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/reorder/expect/syntaxMacro.temper new file mode 100644 index 00000000..a26ba2a0 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/reorder/expect/syntaxMacro.temper @@ -0,0 +1,12 @@ +@fn let f__0, i__0 = 1, j__0 = i__0 + 1; +f__0 = fn f /* return__0 */: (Int) { + fn__0: do { + @fn let g__0, i__1 = 4; + g__0 = fn g /* return__1 */: (Int) { + fn__1: do { + i__1 + j__0 + } + }; + g__0() + } +}; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/reorder/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/reorder/work/test/test.temper new file mode 100644 index 00000000..489b50cb --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/reorder/work/test/test.temper @@ -0,0 +1,3 @@ + let f(): Int { let i = 4; let g(): Int { i + j }; g() } + let j = i + 1; + let i = 1; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/rewrite-connected-decorator/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/rewrite-connected-decorator/expect/syntaxMacro.temper new file mode 100644 index 00000000..8f40da3e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/rewrite-connected-decorator/expect/syntaxMacro.temper @@ -0,0 +1,11 @@ +@typeDecl(Hi__0) @stay let Hi__0 = type (Hi__0); +class(\word, \Hi, \concrete, true, @typeDefined(Hi__0) fn { + Hi__0 extends AnyValue; + @method(\there) @visibility(\private) @connected @fn let there__0 = (@connected fn there(@impliedThis(Hi__0) this__0: Hi__0) { + fn__0: do { + pureVirtual() + } + }); + @method(\constructor) @visibility(\public) let constructor__0 = fn constructor(@impliedThis(Hi__0) this__1: Hi__0) /* return__0 */: Void {}; +}); +Hi__0 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/rewrite-connected-decorator/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/rewrite-connected-decorator/work/test/test.temper new file mode 100644 index 00000000..99bdac29 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/rewrite-connected-decorator/work/test/test.temper @@ -0,0 +1,4 @@ +class Hi { + @connected + private there(); +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/setter-invocation-used-in-expression-context/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/setter-invocation-used-in-expression-context/expect/syntaxMacro.temper new file mode 100644 index 00000000..294b1c56 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/setter-invocation-used-in-expression-context/expect/syntaxMacro.temper @@ -0,0 +1,9 @@ + REM("A chained assignment involving a setter invocation.", null, false); + x = do { + let t#0; +## Here we capture the right operand in t#0, +## so the value assigned to x does not depend +## on any setter's return value. + do_set_p(o, t#0 = f()); + t#0 + } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/setter-invocation-used-in-expression-context/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/setter-invocation-used-in-expression-context/work/test/test.temper new file mode 100644 index 00000000..7a82e8dc --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/setter-invocation-used-in-expression-context/work/test/test.temper @@ -0,0 +1,2 @@ +// A chained assignment involving a setter invocation. +x = o.p = f() diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/static-methods/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/static-methods/expect/syntaxMacro.temper new file mode 100644 index 00000000..2f514c59 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/static-methods/expect/syntaxMacro.temper @@ -0,0 +1,11 @@ +@typeDecl(C__0) @stay let C__0 = type (C__0); +class(\word, \C, \concrete, true, @typeDefined(C__0) fn { + C__0 extends AnyValue; + @staticProperty(\f) @fn @static @visibility(\public) let f__0 = fn f(i__0 /* aka i */: Int) /* return__0 */: (Int) { + fn__0: do { + i__0 + 1 + } + }; + @method(\constructor) @visibility(\public) let constructor__0 = fn constructor(@impliedThis(C__0) this__0: C__0) /* return__1 */: Void {}; +}); +C__0 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/static-methods/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/static-methods/work/test/test.temper new file mode 100644 index 00000000..0a0f4d4d --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/static-methods/work/test/test.temper @@ -0,0 +1,3 @@ +class C { + public static f(i: Int): Int { i + 1 } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/storing-doc-string-with-exported-type/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/storing-doc-string-with-exported-type/expect/syntaxMacro.temper new file mode 100644 index 00000000..d06aacea --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/storing-doc-string-with-exported-type/expect/syntaxMacro.temper @@ -0,0 +1,6 @@ +@typeDecl(I) @stay @docString(...) let `test//`.I = type (I); +do {}; +REM("I am a pretty cool type", true, false); +interface(\word, \I, \concrete, false, @typeDefined(I) fn { + I extends AnyValue +}); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/storing-doc-string-with-exported-type/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/storing-doc-string-with-exported-type/work/test/test.temper new file mode 100644 index 00000000..c04b37be --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/storing-doc-string-with-exported-type/work/test/test.temper @@ -0,0 +1,3 @@ +/** I am a pretty cool type */ +export interface I {} +; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/storing-doc-string-with-fn/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/storing-doc-string-with-fn/expect/define.temper new file mode 100644 index 00000000..89da4537 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/storing-doc-string-with-fn/expect/define.temper @@ -0,0 +1,8 @@ + @fn let f__0; + void; +## And the comment just fades away. + f__0 = (@docString(...) @stay fn f(x__0 /* aka x */: Int32) /* return__0 */: Int32 { + fn__0: do { + x__0 + } + }); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/storing-doc-string-with-fn/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/storing-doc-string-with-fn/expect/syntaxMacro.temper new file mode 100644 index 00000000..9ef0f8bb --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/storing-doc-string-with-fn/expect/syntaxMacro.temper @@ -0,0 +1,7 @@ +@fn let f__0; +REM("tldr, f(x) = x.\n\nWhen x is an Int.\n\n ^ _\n | /|\n y = | /\n f(x) |/\n <--0--->\n /| x\n / |\n |/_ v\n\n(ASCII art is hard)", true, false); +f__0 = (@docString(...) fn f(x__0 /* aka x */: Int) /* return__0 */: (Int) { + fn__0: do { + x__0 + } +}); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/storing-doc-string-with-fn/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/storing-doc-string-with-fn/work/test/test.temper new file mode 100644 index 00000000..ddc14d87 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/storing-doc-string-with-fn/work/test/test.temper @@ -0,0 +1,17 @@ +/** + * tldr, f(x) = x. + * + * When x is an Int. + * + * ^ _ + * | /| + * y = | / + * f(x) |/ + * <--0---> + * /| x + * / | + * |/_ v + * + * (ASCII art is hard) + */ +let f(x: Int): Int { x } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/storing-doc-string-with-type/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/storing-doc-string-with-type/expect/syntaxMacro.temper new file mode 100644 index 00000000..c472c508 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/storing-doc-string-with-type/expect/syntaxMacro.temper @@ -0,0 +1,6 @@ +@typeDecl(Foo__0) @stay @docString((["Foo is a pretty cool type", "Foo is a pretty cool type", "test/test.temper"])) let Foo__0 = type (Foo__0); +REM("Foo is a pretty cool type", true, false); +class(\word, \Foo, \concrete, true, @typeDefined(Foo__0) fn { + Foo__0 extends AnyValue; + @visibility(\public) let constructor__0 = fn constructor(@impliedThis(Foo__0) this__0: Foo__0) /* return__0 */: Void {}; +}); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/storing-doc-string-with-type/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/storing-doc-string-with-type/work/test/test.temper new file mode 100644 index 00000000..be36ebe4 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/storing-doc-string-with-type/work/test/test.temper @@ -0,0 +1,3 @@ +/** Foo is a pretty cool type */ +class Foo {} +; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/this-this-is-ok-but-that-this-is-not/expect/disAmbiguate-types.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/this-this-is-ok-but-that-this-is-not/expect/disAmbiguate-types.json new file mode 100644 index 00000000..698e1e9c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/this-this-is-ok-but-that-this-is-not/expect/disAmbiguate-types.json @@ -0,0 +1,8 @@ +{ + "C": { + "word": "C" + }, + "AnyValue": { + "abstract": true + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/this-this-is-ok-but-that-this-is-not/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/this-this-is-ok-but-that-this-is-not/expect/disAmbiguate.temper new file mode 100644 index 00000000..df00d8bf --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/this-this-is-ok-but-that-this-is-not/expect/disAmbiguate.temper @@ -0,0 +1,6 @@ +@typeDecl(C__0) @hoistLeft(true) @resolution(C__0) @stay let C = type (C__0); +class(\word, C, \concrete, true, @typeDefined(C__0) fn { + C__0 extends AnyValue; + @property(\me) @maybeVar @visibility(\private) let me = this(C__0); +}); +let me = this(); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/this-this-is-ok-but-that-this-is-not/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/this-this-is-ok-but-that-this-is-not/expect/errors.json new file mode 100644 index 00000000..4d2d1ed3 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/this-this-is-ok-but-that-this-is-not/expect/errors.json @@ -0,0 +1,3 @@ +[ + "`this` may only appear inside a type definition!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/this-this-is-ok-but-that-this-is-not/expect/syntaxMacro-types.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/this-this-is-ok-but-that-this-is-not/expect/syntaxMacro-types.json new file mode 100644 index 00000000..439b27de --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/this-this-is-ok-but-that-this-is-not/expect/syntaxMacro-types.json @@ -0,0 +1,30 @@ +{ + "AnyValue": { + "abstract": true + }, + "C": { + "word": "C", + "properties": [ + { + "name": "me", + "symbol": "me", + "abstract": false, + "visibility": "private" + } + ], + "methods": [ + { + "name": "constructor", + "kind": "Constructor", + "visibility": "public", + "open": false + } + ], + "supers": [ + "AnyValue__0" + ] + }, + "Void": { + "supers": [] + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/this-this-is-ok-but-that-this-is-not/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/this-this-is-ok-but-that-this-is-not/expect/syntaxMacro.temper new file mode 100644 index 00000000..011c9932 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/this-this-is-ok-but-that-this-is-not/expect/syntaxMacro.temper @@ -0,0 +1,13 @@ +@typeDecl(C__0) @stay let C__0 = type (C__0); +class(\word, \C, \concrete, true, @typeDefined(C__0) fn { + C__0 extends AnyValue; + @property(\me) @maybeVar @visibility(\private) let me__3; + @method(\constructor) @visibility(\public) let constructor__4 = fn constructor(@impliedThis(C__0) this__5: C__0) /* return__0 */: Void { + do { + let t#0; + do_iset_me(type (C__0), this(C__0), t#0 = this(C__0)); + t#0 + }; + }; +}); +let me__7 = error (); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/this-this-is-ok-but-that-this-is-not/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/this-this-is-ok-but-that-this-is-not/work/test/test.temper new file mode 100644 index 00000000..d35eb4b8 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/this-this-is-ok-but-that-this-is-not/work/test/test.temper @@ -0,0 +1,2 @@ +class C { private me = this } +let me = this; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/untyped-fun-args/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/untyped-fun-args/expect/syntaxMacro.temper new file mode 100644 index 00000000..a0595f4e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/untyped-fun-args/expect/syntaxMacro.temper @@ -0,0 +1,3 @@ +hi(fn (x__0 /* aka x */: Int, y__0 /* aka y */) /* return__0 */: (String) { + x__0 +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/untyped-fun-args/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/untyped-fun-args/work/test/test.temper new file mode 100644 index 00000000..29bc244e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/untyped-fun-args/work/test/test.temper @@ -0,0 +1 @@ +hi { (x: Int, y): String => x } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/use-in-let-initializer/README.md b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/use-in-let-initializer/README.md new file mode 100644 index 00000000..3eb2d28d --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/use-in-let-initializer/README.md @@ -0,0 +1,37 @@ + +In Java and Rust, consider this: + + { + int i = 0; + { + int i = i; + } + } + +That's legal since, the `i` used in the initializer binds in a scope that excludes the name being +initialized. + + T n = e; + // following statements in the same block + +Java treats every initialization like that the same as: + + T temporary = e; + { + T n = temporary; + // following statements in the same block + } + +JavaScript has a temporal dead zone though. + + { + let i = 0; + { + let i = i; + } + } + +That is illegal since the `i` in the initializer binds to the uninitialized inner `let`. + +The Rust and Kotlin communities' experiences with shadowing starting lexically after +initialization show that this feature is widely appreciated. diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/use-in-let-initializer/expect/syntaxMacro.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/use-in-let-initializer/expect/syntaxMacro.lispy new file mode 100644 index 00000000..b9bd7abe --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/use-in-let-initializer/expect/syntaxMacro.lispy @@ -0,0 +1,91 @@ +[ + "Block", + [ + [ + "Decl", + [ + [ + "LeftName", + "i__0" + ], + [ + "Value", + "\\init: Symbol" + ], + [ + "Value", + "0: Int32" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.i\u0022: String" + ] + ] + ], + [ + "Call", + [ + [ + "RightName", + "do" + ], + [ + "Fun", + [ + [ + "Block", + [ + [ + "Decl", + [ + [ + "LeftName", + "i__1" + ], + [ + "Value", + "\\init: Symbol" + ], + [ + "RightName", + "i__0" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.i=\u0022: String" + ] + ] + ], + [ + "Call", + [ + [ + "RightName", + "f" + ], + [ + "RightName", + "i__1" + ] + ] + ], + [ + "Value", + "void: Void" + ] + ] + ] + ] + ] + ] + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/use-in-let-initializer/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/use-in-let-initializer/work/test/test.temper new file mode 100644 index 00000000..2eade703 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/use-in-let-initializer/work/test/test.temper @@ -0,0 +1,5 @@ +let i = 0; +do { + let i = i; + f(i); +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/who-decorates-the-decorators/expect/syntaxMacro.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/who-decorates-the-decorators/expect/syntaxMacro.lispy new file mode 100644 index 00000000..370b6739 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/who-decorates-the-decorators/expect/syntaxMacro.lispy @@ -0,0 +1,188 @@ +[ + "Block", + [ + [ + "Decl", + [ + [ + "LeftName", + "I__0" + ], + [ + "Value", + "\\init: Symbol" + ], + [ + "Value", + "I__0: Type" + ], + [ + "Value", + "\\typeDecl: Symbol" + ], + [ + "Value", + "I__0: Type" + ], + [ + "Value", + "\\stay: Symbol" + ], + [ + "Stay", + "kotlin.Unit" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.type I\u0022: String" + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "REM: Function" + ], + [ + "Value", + "\u0022Stack many decorators on a declaration and make sure they eliminate themselves.\u0022: String" + ], + [ + "Value", + "null: Null" + ], + [ + "Value", + "false: Boolean" + ] + ] + ], + [ + "Call", + [ + [ + "RightName", + "interface" + ], + [ + "Value", + "\\word: Symbol" + ], + [ + "Value", + "\\I: Symbol" + ], + [ + "Value", + "\\concrete: Symbol" + ], + [ + "Value", + "false: Boolean" + ], + [ + "Fun", + [ + [ + "Value", + "\\typeDefined: Symbol" + ], + [ + "Value", + "I__0: Type" + ], + [ + "Block", + [ + [ + "Call", + [ + [ + "Value", + "extends: Function" + ], + [ + "Value", + "I__0: Type" + ], + [ + "Value", + "AnyValue: Type" + ] + ] + ], + [ + "Decl", + [ + [ + "LeftName", + "thing__0" + ], + [ + "Value", + "\\staticProperty: Symbol" + ], + [ + "Value", + "\\thing: Symbol" + ], + [ + "Value", + "\\var: Symbol" + ], + [ + "Value", + "void: Void" + ], + [ + "Value", + "\\static: Symbol" + ], + [ + "Value", + "void: Void" + ], + [ + "Value", + "\\visibility: Symbol" + ], + [ + "Value", + "\\public: Symbol" + ], + [ + "Value", + "\\foo: Symbol" + ], + [ + "Value", + "\u0022FOO\u0022: String" + ], + [ + "Value", + "\\QName: Symbol" + ], + [ + "Value", + "\u0022test-code.type I.thing\u0022: String" + ] + ] + ] + ] + ] + ] + ] + ] + ], + [ + "RightName", + "I__0" + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/who-decorates-the-decorators/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/who-decorates-the-decorators/expect/syntaxMacro.temper new file mode 100644 index 00000000..37f30f1c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/who-decorates-the-decorators/expect/syntaxMacro.temper @@ -0,0 +1,7 @@ +@typeDecl(I__0) @stay let I__0 = type (I__0); +REM("Stack many decorators on a declaration and make sure they eliminate themselves.", null, false); +interface(\word, \I, \concrete, false, @typeDefined(I__0) fn { + I__0 extends AnyValue; + @staticProperty(\thing) @static @visibility(\public) @foo("FOO") var thing__0; +}); +I__0 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/who-decorates-the-decorators/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/who-decorates-the-decorators/work/test/test.temper new file mode 100644 index 00000000..0918d1b2 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/syntax-macro/who-decorates-the-decorators/work/test/test.temper @@ -0,0 +1,4 @@ +// Stack many decorators on a declaration and make sure they eliminate themselves. +interface I { + @foo("FOO") public static var thing; +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/amazing-evaporating-classes/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/amazing-evaporating-classes/expect/type.temper new file mode 100644 index 00000000..557dc69f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/amazing-evaporating-classes/expect/type.temper @@ -0,0 +1,24 @@ +let return__15; +@fn @stay @fromType(I__0) let method__6; +method__6 = fn method(@impliedThis(I__0) this__2: I__0) /* return__16 */{ + fn__0: do { + pureVirtual() + } +}; +@typeDecl(I__0) @stay let I__0; +I__0 = type (I__0); +@typeDecl(C__1) @stay let C__1; +C__1 = type (C__1); +@constructorProperty @visibility(\private) @stay @fromType(C__1) let property__9; +@visibility(\public) @fn @stay @fromType(C__1) let method__10; +method__10 = (@stay fn method(@impliedThis(C__1) this__3: C__1) /* return__17 */{ + fn__1: do { + return__17 = getp(property__9, this__3) + } +}); +@fn @visibility(\public) @stay @fromType(C__1) let constructor__12; +constructor__12 = (@stay fn constructor(@impliedThis(C__1) this__13: C__1, property__14 /* aka property */) /* return__18 */: Void { + setp(property__9, this__13, property__14); + return__18 = void +}); +return__15 = type (C__1) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/amazing-evaporating-classes/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/amazing-evaporating-classes/work/test/test.temper new file mode 100644 index 00000000..a13a9afa --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/amazing-evaporating-classes/work/test/test.temper @@ -0,0 +1,6 @@ +interface I { + method() +} +class C(private property) extends I { + public method { property } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/as-check-with-incomplete-type-completed/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/as-check-with-incomplete-type-completed/expect/type.temper new file mode 100644 index 00000000..8f8797a3 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/as-check-with-incomplete-type-completed/expect/type.temper @@ -0,0 +1,12 @@ + @fn let `test//`.noStrings; + `test//`.noStrings = (@stay fn noStrings /* return__0 */: (Listed) { + void; + fn__0: do { + var fail#0; +## Above, `as Listed`, here `... as Listed` + return__0 = hs(fail#0, list() as Listed); + if (fail#0) { + bubble() + }; + } + }) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/as-check-with-incomplete-type-completed/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/as-check-with-incomplete-type-completed/work/test/test.temper new file mode 100644 index 00000000..168b6a72 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/as-check-with-incomplete-type-completed/work/test/test.temper @@ -0,0 +1 @@ +export let noStrings(): Listed { [] as Listed } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/bare-reference-to-operator/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/bare-reference-to-operator/expect/errors.json new file mode 100644 index 00000000..3e6fcb08 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/bare-reference-to-operator/expect/errors.json @@ -0,0 +1,3 @@ +[ + "No declaration for nym`+`!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/bare-reference-to-operator/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/bare-reference-to-operator/expect/generateCode.temper new file mode 100644 index 00000000..a3a657cf --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/bare-reference-to-operator/expect/generateCode.temper @@ -0,0 +1,2 @@ +let return__0; +return__0 = nym`+` diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/bare-reference-to-operator/expect/syntaxMacro.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/bare-reference-to-operator/expect/syntaxMacro.lispy new file mode 100644 index 00000000..6882a2ce --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/bare-reference-to-operator/expect/syntaxMacro.lispy @@ -0,0 +1,9 @@ +[ + "Block", + [ + [ + "RightName", + "+" + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/bare-reference-to-operator/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/bare-reference-to-operator/work/test/test.temper new file mode 100644 index 00000000..d30011e9 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/bare-reference-to-operator/work/test/test.temper @@ -0,0 +1 @@ + nym`+` diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/bare-return-void/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/bare-return-void/expect/type.temper new file mode 100644 index 00000000..bb40f5cf --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/bare-return-void/expect/type.temper @@ -0,0 +1,16 @@ +let console#0; +console#0 = doPure(@stay fn /* return__0 */: Console { + return__0 = getConsole(); +}); +@fn let f__0; +f__0 = (@stay fn f(returnEarly__0 /* aka returnEarly */: Boolean) /* return__1 */: Void { + void; + fn__0: do { + if (returnEarly__0) { + return__1 = void; + break fn__0; + }; + do_call_log(console#0, "Did not return early"); + return__1 = void + } +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/bare-return-void/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/bare-return-void/work/test/test.temper new file mode 100644 index 00000000..a8b18a40 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/bare-return-void/work/test/test.temper @@ -0,0 +1,4 @@ +let f(returnEarly: Boolean): Void { + if (returnEarly) { return } + console.log("Did not return early"); +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/binding-callees-not-pulled-out/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/binding-callees-not-pulled-out/expect/type.temper new file mode 100644 index 00000000..82a5b343 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/binding-callees-not-pulled-out/expect/type.temper @@ -0,0 +1,17 @@ +let console#0; +console#0 = doPure(@stay fn /* return__0 */: Console { + return__0 = getConsole(); +}); +@fn let f__0; +f__0 = (@stay fn f(hi__0 /* aka hi */: String) /* return__1 */: Void { + var t#0; + void; + fn__0: do { + let s__0: String; + s__0 = cat("Hello, ", str(hi__0), "!"); + t#0 = s__0; + do_call_log(console#0, t#0); + do_call_log(console#0, s__0); + return__1 = void + } +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/binding-callees-not-pulled-out/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/binding-callees-not-pulled-out/work/test/test.temper new file mode 100644 index 00000000..02dac18a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/binding-callees-not-pulled-out/work/test/test.temper @@ -0,0 +1,5 @@ +let f(hi: String): Void { + let s: String; + console.log((s = "Hello, ${hi}!")); + console.log(s); +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/block-pulled-through-decl/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/block-pulled-through-decl/expect/type.temper new file mode 100644 index 00000000..7083f036 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/block-pulled-through-decl/expect/type.temper @@ -0,0 +1,6 @@ +let x__1: int; +if (a) { + x__1 = 42 +} else { + x__1 = 0 +}; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/block-pulled-through-decl/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/block-pulled-through-decl/work/test/test.temper new file mode 100644 index 00000000..3aebdf88 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/block-pulled-through-decl/work/test/test.temper @@ -0,0 +1 @@ +let x: int = (do { if (a) { 42 } else { 0 } }) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/brahmaguptas-revenge/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/brahmaguptas-revenge/expect/run-result.json new file mode 100644 index 00000000..372db8db --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/brahmaguptas-revenge/expect/run-result.json @@ -0,0 +1 @@ +"0: Int32" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/brahmaguptas-revenge/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/brahmaguptas-revenge/expect/type.temper new file mode 100644 index 00000000..aed985fb --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/brahmaguptas-revenge/expect/type.temper @@ -0,0 +1,11 @@ +let return__0; +var t#1, fail#3; +orelse#1: { + t#1 = hs(fail#3, 0 / 0); + if (fail#3) { + break orelse#1; + }; + return__0 = t#1 +} orelse { + return__0 = 0 +}; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/brahmaguptas-revenge/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/brahmaguptas-revenge/work/test/test.temper new file mode 100644 index 00000000..bcf90431 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/brahmaguptas-revenge/work/test/test.temper @@ -0,0 +1 @@ +(0 / 0) orelse 0 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/break-from-inner-loop-to-outer/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/break-from-inner-loop-to-outer/expect/type.temper new file mode 100644 index 00000000..7b97f4f7 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/break-from-inner-loop-to-outer/expect/type.temper @@ -0,0 +1,6 @@ +outer__0: do { + body#0: do {} +}; +do_call_log(doPure(@stay fn /* return__0 */: Console { + return__0 = getConsole(); + }), "yes"); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/break-from-inner-loop-to-outer/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/break-from-inner-loop-to-outer/work/test/test.temper new file mode 100644 index 00000000..d62299c4 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/break-from-inner-loop-to-outer/work/test/test.temper @@ -0,0 +1,9 @@ +do { + outer: while (true) { + while (true) { + break outer; + } + console.log("no"); + } + console.log("yes"); +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/break-in-for-of/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/break-in-for-of/expect/run-result.json new file mode 100644 index 00000000..cc7a3b30 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/break-in-for-of/expect/run-result.json @@ -0,0 +1 @@ +"void: Void" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/break-in-for-of/expect/stdout.txt b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/break-in-for-of/expect/stdout.txt new file mode 100644 index 00000000..422c2b7a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/break-in-for-of/expect/stdout.txt @@ -0,0 +1,2 @@ +a +b diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/break-in-for-of/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/break-in-for-of/expect/type.temper new file mode 100644 index 00000000..5e26cfba --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/break-in-for-of/expect/type.temper @@ -0,0 +1,28 @@ + let console#0 ⦂ Console; + console#0 = doPure ⋖ Console ⋗(@stay fn /* return__0 */: Console { + return__0 = getConsole(); + }); + let this__0: List; + this__0 = list ⋖ String ⋗("a", "b", "c", "d"); +## Here we start the inlined callee body. + let n__0 ⦂ Int32; + n__0 = do_get_length(this__0); + var i__0 ⦂ Int32; + i__0 = 0; + while (i__0 < n__0) { + let el__0: String; + el__0 = do_call_get(this__0, i__0); + i__0 = i__0 + 1; +## Here we start the inlined block lambda parameters. + let x__0 ⦂ String; + x__0 = el__0; +## Here we start the inlined block lambda body. +## Note the absence of a void-like return declaration. + if (x__0 == "c") { + break; + }; + do_call_log(console#0, x__0); +## Did not inline `return__0 = void`. Not ok for local vars. +## Here's the end of the inlined block lambda. + }; +## Here's the end of the inlined callee body. No `return__0 = void` here either. diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/break-in-for-of/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/break-in-for-of/work/test/test.temper new file mode 100644 index 00000000..c3a6c44f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/break-in-for-of/work/test/test.temper @@ -0,0 +1,4 @@ +for (let x of ["a", "b", "c", "d"]) { + if (x == "c") { break } + console.log(x) +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/continue-from-inner-loop-to-outer/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/continue-from-inner-loop-to-outer/expect/run-result.json new file mode 100644 index 00000000..ac3fa442 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/continue-from-inner-loop-to-outer/expect/run-result.json @@ -0,0 +1,4 @@ +[ + 5, + "Int32" +] \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/continue-from-inner-loop-to-outer/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/continue-from-inner-loop-to-outer/expect/type.temper new file mode 100644 index 00000000..d773c128 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/continue-from-inner-loop-to-outer/expect/type.temper @@ -0,0 +1,14 @@ +let return__0; +var i__0: Int32; +i__0 = 0; +outer__0: while (i__0 < 5) { + i__0 = i__0 + 1; + void; + while (i__0 < 10) { + if (i__0 < 6) { + continue outer__0; + }; + i__0 = i__0 + 10; + } +}; +return__0 = i__0; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/continue-from-inner-loop-to-outer/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/continue-from-inner-loop-to-outer/work/test/test.temper new file mode 100644 index 00000000..9d975323 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/continue-from-inner-loop-to-outer/work/test/test.temper @@ -0,0 +1,13 @@ +do { + var i: Int = 0; + outer: while (i < 5) { + i += 1; + while (i < 10) { + if (i < 6) { + continue outer; + } + i += 10; + } + } + i +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/deep-default-method/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/deep-default-method/expect/run-result.json new file mode 100644 index 00000000..1d3d7ac7 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/deep-default-method/expect/run-result.json @@ -0,0 +1,4 @@ +[ + "hello", + "String" +] \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/deep-default-method/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/deep-default-method/work/test/test.temper new file mode 100644 index 00000000..3fc2f014 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/deep-default-method/work/test/test.temper @@ -0,0 +1,4 @@ +interface A { public hi(): String { "hello" } } +interface B extends A {} +class C extends B {} +new C().hi() diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/deep-string-to-string/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/deep-string-to-string/expect/type.temper new file mode 100644 index 00000000..430f7b2c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/deep-string-to-string/expect/type.temper @@ -0,0 +1,6 @@ +@stay fn (i__0 /* aka i */: Int32) /* return__0 */: String { + void; + fn__0: do { + return__0 = do_call_toString(do_call_toString(do_call_toString(i__0))); + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/deep-string-to-string/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/deep-string-to-string/work/test/test.temper new file mode 100644 index 00000000..4dd0e33d --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/deep-string-to-string/work/test/test.temper @@ -0,0 +1 @@ +fn (i: Int): String { i.toString().toString().toString() } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-compound-assignments-complex-r-h-s/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-compound-assignments-complex-r-h-s/expect/run-result.json new file mode 100644 index 00000000..7a848e22 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-compound-assignments-complex-r-h-s/expect/run-result.json @@ -0,0 +1 @@ +"12: Int32" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-compound-assignments-complex-r-h-s/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-compound-assignments-complex-r-h-s/work/test/test.temper new file mode 100644 index 00000000..0633439d --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-compound-assignments-complex-r-h-s/work/test/test.temper @@ -0,0 +1 @@ +var x: Int = 10; var y: Int = 1; x += (y + 1); x diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-compound-assignments/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-compound-assignments/expect/run-result.json new file mode 100644 index 00000000..5df64e4f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-compound-assignments/expect/run-result.json @@ -0,0 +1 @@ +"3: Int32" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-compound-assignments/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-compound-assignments/expect/syntaxMacro.temper new file mode 100644 index 00000000..1a908868 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-compound-assignments/expect/syntaxMacro.temper @@ -0,0 +1,8 @@ +do (fn { + var x__0: Int = 10; + x__0 = x__0 - 9; + x__0 = x__0 + 4; + x__0 = x__0 * 3; + x__0 = x__0 / 5; + x__0 +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-compound-assignments/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-compound-assignments/expect/type.temper new file mode 100644 index 00000000..d5c1a8c6 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-compound-assignments/expect/type.temper @@ -0,0 +1,12 @@ +let return__0; +var t#0, fail#0, x__0: Int32; +x__0 = 10; +x__0 = x__0 - 9; +x__0 = x__0 + 4; +x__0 = x__0 * 3; +t#0 = hs(fail#0, x__0 / 5); +if (fail#0) { + bubble() +}; +x__0 = t#0; +return__0 = x__0; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-compound-assignments/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-compound-assignments/work/test/test.temper new file mode 100644 index 00000000..101092f5 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-compound-assignments/work/test/test.temper @@ -0,0 +1 @@ +do { var x: Int = 10; x -= 9; x += 4; x *= 3; x /= 5; x } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-postfix-operators/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-postfix-operators/expect/define.temper new file mode 100644 index 00000000..cbf3a63a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-postfix-operators/expect/define.temper @@ -0,0 +1,28 @@ +do (@stay fn { + var x__4: Int32; + x__4 = 3; + do { + let postfixReturn#0; + postfixReturn#0 = x__4; + x__4 = do_call_succ(postfixReturn#0); + postfixReturn#0 + }; + do { + let postfixReturn#1; + postfixReturn#1 = x__4; + x__4 = do_call_succ(postfixReturn#1); + postfixReturn#1 + }; + do { + let postfixReturn#2; + postfixReturn#2 = x__4; + x__4 = do_call_pred(postfixReturn#2); + postfixReturn#2 + }; + do { + let postfixReturn#3; + postfixReturn#3 = x__4; + x__4 = do_call_succ(postfixReturn#3); + postfixReturn#3 + } +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-postfix-operators/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-postfix-operators/expect/run-result.json new file mode 100644 index 00000000..151aecd2 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-postfix-operators/expect/run-result.json @@ -0,0 +1 @@ +"4: Int32" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-postfix-operators/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-postfix-operators/work/test/test.temper new file mode 100644 index 00000000..59a71644 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-postfix-operators/work/test/test.temper @@ -0,0 +1 @@ +do { var x: Int = 3; x++; x++; x--; x++ } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-prefix-operators/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-prefix-operators/expect/define.temper new file mode 100644 index 00000000..587e38d8 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-prefix-operators/expect/define.temper @@ -0,0 +1,8 @@ +do (@stay fn { + var x__0: Int32; + x__0 = 3; + x__0 = do_call_succ(x__0); + x__0 = do_call_succ(x__0); + x__0 = do_call_pred(x__0); + x__0 +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-prefix-operators/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-prefix-operators/expect/run-result.json new file mode 100644 index 00000000..151aecd2 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-prefix-operators/expect/run-result.json @@ -0,0 +1 @@ +"4: Int32" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-prefix-operators/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-prefix-operators/work/test/test.temper new file mode 100644 index 00000000..b3434316 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/desugar-prefix-operators/work/test/test.temper @@ -0,0 +1 @@ +do { var x: Int = 3; ++x; ++x; --x; x } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/do-once-transformed/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/do-once-transformed/expect/type.temper new file mode 100644 index 00000000..105bd957 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/do-once-transformed/expect/type.temper @@ -0,0 +1,2 @@ +let return__0; +return__0 = f(); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/do-once-transformed/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/do-once-transformed/work/test/test.temper new file mode 100644 index 00000000..25c6079c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/do-once-transformed/work/test/test.temper @@ -0,0 +1 @@ +(do { f() }) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/do-while-transformed/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/do-while-transformed/expect/type.temper new file mode 100644 index 00000000..7f0b0f39 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/do-while-transformed/expect/type.temper @@ -0,0 +1,4 @@ +let return__2; +do { + return__2 = f(); +} while (c); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/do-while-transformed/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/do-while-transformed/work/test/test.temper new file mode 100644 index 00000000..19d9e9c6 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/do-while-transformed/work/test/test.temper @@ -0,0 +1 @@ +do { f() } while (c) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/empty-file/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/empty-file/expect/type.temper new file mode 100644 index 00000000..e69de29b diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/empty-file/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/empty-file/work/test/test.temper new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/empty-file/work/test/test.temper @@ -0,0 +1 @@ + diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/empty-repl-chunk/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/empty-repl-chunk/expect/type.temper new file mode 100644 index 00000000..77602277 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/empty-repl-chunk/expect/type.temper @@ -0,0 +1,2 @@ +let return__0; +return__0 = void diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/empty-repl-chunk/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/empty-repl-chunk/work/test/test.temper new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/empty-repl-chunk/work/test/test.temper @@ -0,0 +1 @@ + diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/explicit-type-arguments-remain-in-tree/expect/disAmbiguate.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/explicit-type-arguments-remain-in-tree/expect/disAmbiguate.lispy new file mode 100644 index 00000000..3cdfd998 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/explicit-type-arguments-remain-in-tree/expect/disAmbiguate.lispy @@ -0,0 +1,31 @@ +[ + "Block", + [ + [ + "Call", + [ + [ + "Call", + [ + [ + "Value", + "nym`\u003c\u003e`: Function" + ], + [ + "RightName", + "echo" + ], + [ + "RightName", + "Int" + ] + ] + ], + [ + "Value", + "42: Int32" + ] + ] + ] + ] +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/explicit-type-arguments-remain-in-tree/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/explicit-type-arguments-remain-in-tree/expect/disAmbiguate.temper new file mode 100644 index 00000000..554f136a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/explicit-type-arguments-remain-in-tree/expect/disAmbiguate.temper @@ -0,0 +1 @@ +echo(42) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/explicit-type-arguments-remain-in-tree/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/explicit-type-arguments-remain-in-tree/expect/type.temper new file mode 100644 index 00000000..b0b6f5c7 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/explicit-type-arguments-remain-in-tree/expect/type.temper @@ -0,0 +1,2 @@ +let return__0; +return__0 = echo(42); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/explicit-type-arguments-remain-in-tree/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/explicit-type-arguments-remain-in-tree/work/test/test.temper new file mode 100644 index 00000000..554f136a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/explicit-type-arguments-remain-in-tree/work/test/test.temper @@ -0,0 +1 @@ +echo(42) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/extension-hints-resolved/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/extension-hints-resolved/expect/type.temper new file mode 100644 index 00000000..3f17e39d --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/extension-hints-resolved/expect/type.temper @@ -0,0 +1,23 @@ +let return__0, @fn @extension("isZero") isZero__0; +@typeDecl(Zero__0) @stay let Zero__0; +Zero__0 = type (Zero__0); +isZero__0 = (@stay fn isZero(x__0 /* aka x */: Int32) /* return__1 */: Boolean { + fn__0: do { + return__1 = x__0 == 0 + } +}); +@visibility(\public) @fn @stay @fromType(Zero__0) let isZero__1; +isZero__1 = (@stay fn isZero(@impliedThis(Zero__0) this__0: Zero__0) /* return__2 */: Boolean { + fn__1: do { + return__2 = true + } +}); +@fn @visibility(\public) @stay @fromType(Zero__0) let constructor__0; +constructor__0 = (@stay fn constructor(@impliedThis(Zero__0) this__1: Zero__0) /* return__3 */: Void { + return__3 = void +}); +if (isZero__0(0)) { + return__0 = do_call_isZero(new Zero__0()); +} else { + return__0 = false +}; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/extension-hints-resolved/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/extension-hints-resolved/work/test/test.temper new file mode 100644 index 00000000..12d4912e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/extension-hints-resolved/work/test/test.temper @@ -0,0 +1,8 @@ +@extension("isZero") +let isZero(x: Int): Boolean { x == 0 } +class Zero { + public let isZero(): Boolean { true } +} + +0.isZero() && new Zero().isZero() + diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/fn-with-mixed-return-and-implied-result-paths/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/fn-with-mixed-return-and-implied-result-paths/expect/syntaxMacro.temper new file mode 100644 index 00000000..b638c0c6 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/fn-with-mixed-return-and-implied-result-paths/expect/syntaxMacro.temper @@ -0,0 +1,11 @@ +fn (b__0 /* aka b */) /* return__1 */{ + fn__2: do { + if(b__0, fn { + do { + return__1 = 1; + break(\label, fn__2) + } + }); + 0 + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/fn-with-mixed-return-and-implied-result-paths/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/fn-with-mixed-return-and-implied-result-paths/expect/type.temper new file mode 100644 index 00000000..1d9ae212 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/fn-with-mixed-return-and-implied-result-paths/expect/type.temper @@ -0,0 +1,10 @@ +let return__3; +return__3 = (@stay fn (b__0 /* aka b */) /* return__1 */{ + fn__2: do { + if (b__0) { + return__1 = 1; + break fn__2; + }; + return__1 = 0 + } +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/fn-with-mixed-return-and-implied-result-paths/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/fn-with-mixed-return-and-implied-result-paths/work/test/test.temper new file mode 100644 index 00000000..38f8bac4 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/fn-with-mixed-return-and-implied-result-paths/work/test/test.temper @@ -0,0 +1 @@ +fn(b) { if (b) { return 1 } 0 } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/for-with-expression-parts/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/for-with-expression-parts/expect/type.temper new file mode 100644 index 00000000..dd7a0363 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/for-with-expression-parts/expect/type.temper @@ -0,0 +1,4 @@ +init; +for (; + cond; + incr) {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/for-with-expression-parts/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/for-with-expression-parts/work/test/test.temper new file mode 100644 index 00000000..39682958 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/for-with-expression-parts/work/test/test.temper @@ -0,0 +1 @@ +for (init; cond; incr) {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/for-with-ifs-and-jumps-transformed/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/for-with-ifs-and-jumps-transformed/expect/type.temper new file mode 100644 index 00000000..bd4f7437 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/for-with-ifs-and-jumps-transformed/expect/type.temper @@ -0,0 +1,10 @@ +init; +for (; + cond; + incr) { + if (a) { + f() + } else if (b) { + break; + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/for-with-ifs-and-jumps-transformed/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/for-with-ifs-and-jumps-transformed/work/test/test.temper new file mode 100644 index 00000000..7bf5ca6c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/for-with-ifs-and-jumps-transformed/work/test/test.temper @@ -0,0 +1,9 @@ +for (init; cond; incr) { + if (a) { + f(); + } else if (b) { + break; + } else { + continue + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/function-with-arguments-and-return-type/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/function-with-arguments-and-return-type/expect/syntaxMacro.temper new file mode 100644 index 00000000..52f3d1bd --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/function-with-arguments-and-return-type/expect/syntaxMacro.temper @@ -0,0 +1,12 @@ +do { + @fn let sum2i__0; + sum2i__0 = fn sum2i(x__0 /* aka x */: Int, y__0 /* aka y */: Int) /* return__0 */: (Int) { + fn__0: do { + do { + return__0 = x__0 + y__0; + break(\label, fn__0) + }; + } + }; + sum2i__0 +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/function-with-arguments-and-return-type/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/function-with-arguments-and-return-type/expect/type.temper new file mode 100644 index 00000000..74ebf4ff --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/function-with-arguments-and-return-type/expect/type.temper @@ -0,0 +1,8 @@ +let return__1, @fn sum2i__0; +sum2i__0 = (@stay fn sum2i(x__0 /* aka x */: Int32, y__0 /* aka y */: Int32) /* return__0 */: Int32 { + void; + fn__0: do { + return__0 = x__0 + y__0; + } +}); +return__1 = (fn sum2i) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/function-with-arguments-and-return-type/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/function-with-arguments-and-return-type/work/test/test.temper new file mode 100644 index 00000000..0f2bfa4c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/function-with-arguments-and-return-type/work/test/test.temper @@ -0,0 +1,5 @@ + + fn sum2i(x: Int, y: Int): Int { + return x + y; + } + diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-else-result-needed/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-else-result-needed/expect/type.temper new file mode 100644 index 00000000..57ddf0c2 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-else-result-needed/expect/type.temper @@ -0,0 +1,6 @@ +let return__0; +if (a == b) { + return__0 = c +} else { + return__0 = d +}; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-else-result-needed/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-else-result-needed/work/test/test.temper new file mode 100644 index 00000000..df08c0e8 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-else-result-needed/work/test/test.temper @@ -0,0 +1 @@ +if (a == b) { c } else { d } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-is-null-result-needed/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-is-null-result-needed/expect/type.temper new file mode 100644 index 00000000..21034f96 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-is-null-result-needed/expect/type.temper @@ -0,0 +1,12 @@ +let return__0, @fn `test//`.thing; +`test//`.thing = (@stay fn thing(x__0 /* aka x */: Int32?) /* return__1 */: Int32 { + void; + fn__0: do { + if (isNull(x__0)) { + return__1 = 0 + } else { + return__1 = notNull(x__0) + 1; + }; + } +}); +return__0 = void diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-is-null-result-needed/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-is-null-result-needed/work/test/test.temper new file mode 100644 index 00000000..bafbdd7f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-is-null-result-needed/work/test/test.temper @@ -0,0 +1 @@ +export let thing(x: Int?): Int { if (x == null) { 0 } else { x + 1 } } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-not-null-multi/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-not-null-multi/expect/type.temper new file mode 100644 index 00000000..f765393a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-not-null-multi/expect/type.temper @@ -0,0 +1,29 @@ +let return__2, @fn `test//`.multi, @fn `test//`.post; +`test//`.multi = (@stay fn multi(a__0 /* aka a */: Int32?, b__0 /* aka b */: Int32?) /* return__0 */: Int32 { + var t#0; + void; + fn__0: do { + if (!isNull(a__0)) { + t#0 = !isNull(b__0) + } else { + t#0 = false + }; + if (t#0) { + return__0 = a__0 * b__0; + void; + break fn__0; + }; + return__0 = 0 + } +}); +`test//`.post = (@stay fn post(a__1 /* aka a */: Int32?) /* return__1 */: Int32 { + void; + fn__1: do { + if (isNull(a__1)) { + return__1 = 0; + break fn__1; + }; + return__1 = 2 * a__1; + } +}); +return__2 = void diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-not-null-multi/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-not-null-multi/work/test/test.temper new file mode 100644 index 00000000..dcb27394 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-not-null-multi/work/test/test.temper @@ -0,0 +1,8 @@ +export let multi(a: Int?, b: Int?): Int { + if (a != null && b != null) { return a * b; } + 0 +} +export let post(a: Int?): Int { + if (a == null) { return 0; } + 2 * a +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-transformed/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-transformed/expect/type.temper new file mode 100644 index 00000000..f7b23550 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-transformed/expect/type.temper @@ -0,0 +1,6 @@ +let return__2; +if (c) { + return__2 = f(); +} else { + return__2 = g(); +}; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-transformed/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-transformed/work/test/test.temper new file mode 100644 index 00000000..acf6c304 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-transformed/work/test/test.temper @@ -0,0 +1 @@ +if (c) { f() } else { g() } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-vs-nested-if/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-vs-nested-if/expect/define.temper new file mode 100644 index 00000000..fd5eb5ff --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-vs-nested-if/expect/define.temper @@ -0,0 +1,41 @@ +@fn let `test//`.useIf, @fn `test//`.useIfElse; +`test//`.useIf = fn useIf(i__0 /* aka i */: Int32) { + fn__0: do { + if(i__0 < 0, @stay fn { + -1 + }, \else_if, fn (f#0) { + f#0(i__0 > 0, @stay fn { + 1 + }, \else, fn (f#1) { + f#1(@stay fn { + 0 + }) + }) + }) + } +}; +`test//`.useIfElse = fn useIfElse(i__1 /* aka i */: Int32) { + fn__1: do { + if(i__1 < 0, @stay fn { + -1 + }, \else, fn (f#2) { + f#2(fn { + if(i__1 > 0, @stay fn { + 1 + }, \else, fn (f#3) { + f#3(@stay fn { + 0 + }) + }) + }) + }) + } +}; +let `test//`.a; +`test//`.a = if(true, @stay fn { + 1 + }, \else, fn (f#4) { + f#4(@stay fn { + 0 + }) +}); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-vs-nested-if/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-vs-nested-if/expect/type.temper new file mode 100644 index 00000000..6a98398b --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-vs-nested-if/expect/type.temper @@ -0,0 +1,29 @@ +@fn let `test//`.useIf, @fn `test//`.useIfElse; +`test//`.useIf = (@stay fn useIf(i__0 /* aka i */: Int32) /* return__0 */{ + void; + fn__0: do { + if (i__0 < 0) { + return__0 = -1 + } else if (i__0 > 0) { + return__0 = 1 + } else { + return__0 = 0 + }; + } +}); +`test//`.useIfElse = (@stay fn useIfElse(i__1 /* aka i */: Int32) /* return__1 */{ + void; + fn__1: do { + if (i__1 < 0) { + return__1 = -1 + } else { + if (i__1 > 0) { + return__1 = 1 + } else { + return__1 = 0 + }; + }; + } +}); +let `test//`.a; +`test//`.a = 1 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-vs-nested-if/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-vs-nested-if/work/test/test.temper new file mode 100644 index 00000000..fa4e7fb2 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/if-vs-nested-if/work/test/test.temper @@ -0,0 +1,3 @@ +export let useIf(i: Int) { if (i < 0) { -1 } else if (i > 0) { 1 } else { 0 } } +export let useIfElse(i: Int) { if (i < 0) { -1 } else { if (i > 0) { 1 } else { 0 } } } +export let a = if (true) { 1 } else { 0 }; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/implicit-return-for-doc-genre/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/implicit-return-for-doc-genre/expect/type.temper new file mode 100644 index 00000000..fcd44877 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/implicit-return-for-doc-genre/expect/type.temper @@ -0,0 +1,9 @@ +@fn let f__0, @fn g__0; +f__0 = (@stay fn f /* return__0 */: (preserve(Void, type (Void))) {}); +g__0 = (@stay fn g(b__0 /* aka b */: preserve(Boolean, type (Boolean))) /* return__1 */: (preserve(Int, type (Int32))) { + preserve(if, ifForDocGen)(b__0, do { + returnForDocGen(42) + }, do { + returnForDocGen(0) + }) +}); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/implicit-return-for-doc-genre/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/implicit-return-for-doc-genre/work/test/test.temper new file mode 100644 index 00000000..9fa8bbbc --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/implicit-return-for-doc-genre/work/test/test.temper @@ -0,0 +1,4 @@ +let f(): Void {} +let g(b: Boolean): Int { + if (b) { 42 } else { 0 } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/imported-extensions-usable/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/imported-extensions-usable/expect/type.temper new file mode 100644 index 00000000..a6f54b48 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/imported-extensions-usable/expect/type.temper @@ -0,0 +1,6 @@ + @stay @imported(\(`half//`.intHalf)) @fn @extension("half") let intHalf__0; + intHalf__0 = (fn intHalf); + do_call_log(doPure(@stay fn /* return__0 */: Console { + return__0 = getConsole(); + }), do_call_toString(intHalf__0(84))); +## ^^^^^^^^^^ extension resolved across module boundaries diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/imported-extensions-usable/work/half/half.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/imported-extensions-usable/work/half/half.temper new file mode 100644 index 00000000..fa54214b --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/imported-extensions-usable/work/half/half.temper @@ -0,0 +1,4 @@ +@extension("half") +export let intHalf(x: Int): Int { + x / 2 +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/imported-extensions-usable/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/imported-extensions-usable/work/test/test.temper new file mode 100644 index 00000000..0906316b --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/imported-extensions-usable/work/test/test.temper @@ -0,0 +1,2 @@ +let { intHalf } = import("../half"); +console.log(84.half().toString()); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/issue1828-missing-return/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/issue1828-missing-return/expect/type.temper new file mode 100644 index 00000000..fe3a449d --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/issue1828-missing-return/expect/type.temper @@ -0,0 +1,15 @@ +@fn let a__0; +a__0 = (@stay fn a(i__0 /* aka i */: List) /* return__1 */: (List) { + void; + fn__0: do { + if (do_get_length(i__0) == 0) { + return__1 = list(); + break fn__0; + }; + let n__0; + n__0 = new ListBuilder(); + return__1 = do_call_map(n__0, @stay fn (it__0 /* aka it */) /* return__2 */: Int32 { + return__2 = 2 * it__0; + }); + } +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/issue1828-missing-return/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/issue1828-missing-return/work/test/test.temper new file mode 100644 index 00000000..7de235df --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/issue1828-missing-return/work/test/test.temper @@ -0,0 +1,5 @@ +let a(i: List): List { + if (i.length == 0) { return [] }; // One explicit return + let n = new ListBuilder(); + n.map { (it): Int => 2 * it } // One implied return +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/jump-default-label/expect/type.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/jump-default-label/expect/type.lispy new file mode 100644 index 00000000..a1df3891 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/jump-default-label/expect/type.lispy @@ -0,0 +1,27 @@ +[ + "Block", + [ + [ + "Decl", + [ + [ + "LeftName", + "return__0" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ] + ] + ], + [ + "continue", + [] + ] + ], + "StructuredFlow" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/jump-default-label/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/jump-default-label/expect/type.temper new file mode 100644 index 00000000..a41cb41a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/jump-default-label/expect/type.temper @@ -0,0 +1,2 @@ +let return__0; +continue; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/jump-default-label/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/jump-default-label/work/test/test.temper new file mode 100644 index 00000000..44c5d7d6 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/jump-default-label/work/test/test.temper @@ -0,0 +1 @@ +continue diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/jump-to-label/expect/type.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/jump-to-label/expect/type.lispy new file mode 100644 index 00000000..1c076f90 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/jump-to-label/expect/type.lispy @@ -0,0 +1,28 @@ +[ + "Block", + [ + [ + "Decl", + [ + [ + "LeftName", + "return__0" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ] + ] + ], + [ + "break", + "\\foo", + [] + ] + ], + "StructuredFlow" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/jump-to-label/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/jump-to-label/expect/type.temper new file mode 100644 index 00000000..087f5c39 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/jump-to-label/expect/type.temper @@ -0,0 +1,2 @@ +let return__0; +break foo; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/jump-to-label/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/jump-to-label/work/test/test.temper new file mode 100644 index 00000000..6982aa1c --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/jump-to-label/work/test/test.temper @@ -0,0 +1 @@ +break foo diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/make-empty-explicit-void/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/make-empty-explicit-void/expect/type.temper new file mode 100644 index 00000000..53adf84a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/make-empty-explicit-void/expect/type.temper @@ -0,0 +1,10 @@ +@fn let f__0, @fn g__0; +f__0 = (@stay fn f /* return__1 */: Void { + return__1 = void; + fn__0: do {} +}); +g__0 = (@stay fn g /* return__2 */: Void { + fn__1: do { + return__2 = void + } +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/make-empty-explicit-void/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/make-empty-explicit-void/work/test/test.temper new file mode 100644 index 00000000..0fb5e916 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/make-empty-explicit-void/work/test/test.temper @@ -0,0 +1,3 @@ +let f(): Void {} +let g(): Void { f() } +g(); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/minimal-for-of-transformed/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/minimal-for-of-transformed/expect/define.temper new file mode 100644 index 00000000..8ac73004 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/minimal-for-of-transformed/expect/define.temper @@ -0,0 +1,7 @@ +let console#0; +console#0 = doPure(@stay fn: Console { + getConsole() +}); +do_call_forEach(list("foo"), @stay fn (x__0) { + do_call_log(console#0, x__0) +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/minimal-for-of-transformed/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/minimal-for-of-transformed/expect/type.temper new file mode 100644 index 00000000..8a7df6a5 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/minimal-for-of-transformed/expect/type.temper @@ -0,0 +1,21 @@ + let console#0; + console#0 = doPure(@stay fn /* return__0 */: Console { + return__0 = getConsole(); + }); +## Start inlined forEach + let this__0: List; + this__0 = list("foo"); + let n__0; + n__0 = do_get_length(this__0); + var i__0; + i__0 = 0; + while (i__0 < n__0) { + let el__0: String; + el__0 = do_call_get(this__0, i__0); + i__0 = i__0 + 1; +## Inlined block lambda + let x__0; + x__0 = el__0; + do_call_log(console#0, x__0); +## End of inlined block lambda + }; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/minimal-for-of-transformed/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/minimal-for-of-transformed/work/test/test.temper new file mode 100644 index 00000000..4de00815 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/minimal-for-of-transformed/work/test/test.temper @@ -0,0 +1 @@ +for (let x of ["foo"]) { console.log(x) } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/minimal-for-transformed/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/minimal-for-transformed/expect/type.temper new file mode 100644 index 00000000..1fa180e5 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/minimal-for-transformed/expect/type.temper @@ -0,0 +1 @@ +while (true) {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/minimal-for-transformed/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/minimal-for-transformed/work/test/test.temper new file mode 100644 index 00000000..3199f087 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/minimal-for-transformed/work/test/test.temper @@ -0,0 +1 @@ +for (;;) {} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/nested-fn/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/nested-fn/expect/type.temper new file mode 100644 index 00000000..4f40084e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/nested-fn/expect/type.temper @@ -0,0 +1,8 @@ +let return__2, @fn g__0; +g__0 = fn g /* return__5 */{ + void; + fn__0: do { + return__5 = f(); + } +}; +return__2 = g__0(); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/nested-fn/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/nested-fn/work/test/test.temper new file mode 100644 index 00000000..98e0280f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/nested-fn/work/test/test.temper @@ -0,0 +1,2 @@ +let g() { do { f() } } +g() diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/or-else-panic/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/or-else-panic/expect/type.temper new file mode 100644 index 00000000..21b498dc --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/or-else-panic/expect/type.temper @@ -0,0 +1,19 @@ +let return__0 ⦂ String; +var t#0 ⦂ String, fail#0 ⦂ Boolean; +@fn let `test//`.f ⦂(fn (): String | Bubble); +`test//`.f = (@stay fn f /* return__1 */: (String | Bubble) { + fn__0: do { + bubble ⋖ String ⋗() + } +}); +let x__0 ⦂ String; +orelse#0: { + t#0 = hs ⋖ String ⋗(fail#0, (fn f)()); + if (fail#0) { + break orelse#0; + }; + x__0 = t#0 +} orelse { + x__0 = panic ⋖ String ⋗() +}; +return__0 = x__0 diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/or-else-panic/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/or-else-panic/work/test/test.temper new file mode 100644 index 00000000..28a7c401 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/or-else-panic/work/test/test.temper @@ -0,0 +1,7 @@ +export let f(): String throws Bubble { + bubble() +} + +let x = f() orelse panic(); + +x diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overload-on-generics/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overload-on-generics/expect/type.temper new file mode 100644 index 00000000..ff1937f3 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overload-on-generics/expect/type.temper @@ -0,0 +1,27 @@ +@typeDecl(Stringer) @stay let `test//`.Stringer ⦂ Type; +`test//`.Stringer = type (Stringer); +@fn let `test//`.stringifyLists ⦂(fn (Stringer, Int32, List, List): String); +@visibility(\public) @overload("stringify") @fn @stay @fromType(Stringer) let stringifyInt32__0 ⦂(fn (Stringer, Int32): String); +stringifyInt32__0 = fn stringifyInt32(@impliedThis(Stringer) this__0: Stringer, int__0 /* aka int */: Int32) /* return__0 */: String { + fn__0: do { + pureVirtual ⋖ String ⋗() + } +}; +@visibility(\public) @overload("stringify") @fn @stay @fromType(Stringer) let stringifyInt32List__0 ⦂(fn (Stringer, Listed): String); +stringifyInt32List__0 = fn stringifyInt32List(@impliedThis(Stringer) this__1: Stringer, ints__0 /* aka ints */: Listed) /* return__1 */: String { + fn__1: do { + pureVirtual ⋖ String ⋗() + } +}; +@visibility(\public) @overload("stringify") @fn @stay @fromType(Stringer) let stringifyStringList__0 ⦂(fn (Stringer, Listed): String); +stringifyStringList__0 = fn stringifyStringList(@impliedThis(Stringer) this__2: Stringer, string__0 /* aka string */: Listed) /* return__2 */: String { + fn__2: do { + pureVirtual ⋖ String ⋗() + } +}; +`test//`.stringifyLists = (@stay fn stringifyLists(stringer__0 /* aka stringer */: Stringer, int__1 /* aka int */: Int32, ints__1 /* aka ints */: List, strings__0 /* aka strings */: List) /* return__3 */: String { + void; + fn__3: do { + return__3 = cat(str(do_call_stringifyInt32(stringer__0, int__1)), ", ", str(do_call_stringifyInt32List(stringer__0, ints__1)), ", ", str(do_call_stringifyStringList(stringer__0, strings__0))) + } +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overload-on-generics/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overload-on-generics/work/test/test.temper new file mode 100644 index 00000000..0cd23ee7 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overload-on-generics/work/test/test.temper @@ -0,0 +1,15 @@ +export interface Stringer { + @overload("stringify") + public stringifyInt32(int: Int32): String; + + @overload("stringify") + public stringifyInt32List(ints: Listed): String; + + @overload("stringify") + public stringifyStringList(string: Listed): String; +} + +// Purposely receive List but use as Listed above. +export let stringifyLists(stringer: Stringer, int: Int, ints: List, strings: List): String { + "${stringer.stringify(int)}, ${stringer.stringify(ints)}, ${stringer.stringify(strings)}" +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overloaded-methods-wrong/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overloaded-methods-wrong/expect/type.temper new file mode 100644 index 00000000..fc37cfee --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overloaded-methods-wrong/expect/type.temper @@ -0,0 +1,52 @@ +@typeDecl(IntMaker) @stay let `test//`.IntMaker ⦂ Type; +`test//`.IntMaker = type (IntMaker); +@fn let `test//`.crazySum ⦂(fn (IntMaker, Int64, String): Int32 | Bubble); +@constructorProperty @visibility(\public) @stay @fromType(IntMaker) let radix__0: Int32; +@visibility(\public) @fn @stay @fromType(IntMaker) let toInt__0 ⦂(fn (IntMaker, Int64): Int32 | Bubble); +toInt__0 = (@stay fn toInt(@impliedThis(IntMaker) this__0: IntMaker, int__0 /* aka int */: Int64) /* return__0 */: (Int32 | Bubble) { + void; + fn__0: do { + var fail#0 ⦂ Boolean; + return__0 = hs ⋖ Int32 ⋗(fail#0, do_call_toInt32(int__0)); + if (fail#0) { + bubble ⋖ Int32 ⋗() + }; + } +}); +@visibility(\public) @fn @stay @fromType(IntMaker) let toInt__1 ⦂(fn (IntMaker, String): Int32 | Bubble); +toInt__1 = (@stay fn toInt(@impliedThis(IntMaker) this__1: IntMaker, string__0 /* aka string */: String) /* return__1 */: (Int32 | Bubble) { + void; + fn__1: do { + var fail#1 ⦂ Boolean; + return__1 = hs ⋖ Int32 ⋗(fail#1, do_call_toInt32(string__0, getp(radix__0, this__1))); + if (fail#1) { + bubble ⋖ Int32 ⋗() + }; + } +}); +@fn @visibility(\public) @stay @fromType(IntMaker) let constructor__0 ⦂(fn (IntMaker, Int32): Void); +constructor__0 = (@stay fn constructor(@impliedThis(IntMaker) this__2: IntMaker, radix__1 /* aka radix */: Int32) /* return__2 */: Void { + setp(radix__0, this__2, radix__1); + return__2 = void +}); +@fn @visibility(\public) @stay @fromType(IntMaker) let getradix__0 ⦂(fn (IntMaker): Int32); +getradix__0 = (@stay fn (@impliedThis(IntMaker) this__3: IntMaker) /* return__3 */: Int32 { + return__3 = getp(radix__0, this__3) +}); +`test//`.crazySum = (@stay fn crazySum(intMaker__0 /* aka intMaker */: IntMaker, int__1 /* aka int */: Int64, string__1 /* aka string */: String) /* return__4 */: (Int32 | Bubble) { + void; + fn__2: do { + var fail#2 ⦂ Boolean, fail#3 ⦂ Boolean; + let intInt__0 ⦂ Int32; + intInt__0 = hs ⋖ Int32 ⋗(fail#2, do_call_toInt(intMaker__0, int__1)); + if (fail#2) { + bubble ⋖ Int32 ⋗() + }; + let stringInt__0 ⦂ Int32; + stringInt__0 = hs ⋖ Int32 ⋗(fail#3, do_call_toInt(intMaker__0, string__1)); + if (fail#3) { + bubble ⋖ Int32 ⋗() + }; + return__4 = intInt__0 + stringInt__0; + } +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overloaded-methods-wrong/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overloaded-methods-wrong/work/test/test.temper new file mode 100644 index 00000000..cdb7c9cd --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overloaded-methods-wrong/work/test/test.temper @@ -0,0 +1,10 @@ +export class IntMaker(public radix: Int32) { + public toInt(int: Int64): Int32 throws Bubble { int.toInt32() } + public toInt(string: String): Int32 throws Bubble { string.toInt32(radix) } +} + +export let crazySum(intMaker: IntMaker, int: Int64, string: String): Int throws Bubble { + let intInt = intMaker.toInt(int); + let stringInt = intMaker.toInt(string); + intInt + stringInt +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overloaded-methods/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overloaded-methods/expect/type.temper new file mode 100644 index 00000000..e1fe2939 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overloaded-methods/expect/type.temper @@ -0,0 +1,60 @@ +@typeDecl(IntMaker) @stay let `test//`.IntMaker ⦂ Type; +`test//`.IntMaker = type (IntMaker); +@fn let `test//`.crazySum ⦂(fn (IntMaker, Int64, String): Int32 | Bubble); +@constructorProperty @visibility(\public) @stay @fromType(IntMaker) let radix__0: Int32; +@visibility(\public) @overload("toInt") @fn @stay @fromType(IntMaker) let int64ToInt__0 ⦂(fn (IntMaker, Int64): Int32 | Bubble); +int64ToInt__0 = (@stay fn int64ToInt(@impliedThis(IntMaker) this__0: IntMaker, int__0 /* aka int */: Int64) /* return__0 */: (Int32 | Bubble) { + void; + fn__0: do { + var fail#0 ⦂ Boolean; + return__0 = hs ⋖ Int32 ⋗(fail#0, do_call_toInt32(int__0)); + if (fail#0) { + bubble ⋖ Int32 ⋗() + }; + } +}); +@visibility(\public) @overload("toInt") @fn @stay @fromType(IntMaker) let stringToInt__0 ⦂(fn (IntMaker, String): Int32 | Bubble); +stringToInt__0 = (@stay fn stringToInt(@impliedThis(IntMaker) this__1: IntMaker, string__0 /* aka string */: String) /* return__1 */: (Int32 | Bubble) { + void; + fn__1: do { + var fail#1 ⦂ Boolean; + return__1 = hs ⋖ Int32 ⋗(fail#1, do_call_toInt32(string__0, getp(radix__0, this__1))); + if (fail#1) { + bubble ⋖ Int32 ⋗() + }; + } +}); +@visibility(\public) @overload("justMe") @fn @stay @fromType(IntMaker) let int32ToInt__0 ⦂(fn (IntMaker, Int32): Int32); +int32ToInt__0 = (@stay fn int32ToInt(@impliedThis(IntMaker) this__2: IntMaker, int__1 /* aka int */: Int32) /* return__2 */: Int32 { + fn__2: do { + return__2 = int__1 + } +}); +@fn @visibility(\public) @stay @fromType(IntMaker) let constructor__0 ⦂(fn (IntMaker, Int32): Void); +constructor__0 = (@stay fn constructor(@impliedThis(IntMaker) this__3: IntMaker, radix__1 /* aka radix */: Int32) /* return__3 */: Void { + setp(radix__0, this__3, radix__1); + return__3 = void +}); +@fn @visibility(\public) @stay @fromType(IntMaker) let getradix__0 ⦂(fn (IntMaker): Int32); +getradix__0 = (@stay fn (@impliedThis(IntMaker) this__4: IntMaker) /* return__4 */: Int32 { + return__4 = getp(radix__0, this__4) +}); +`test//`.crazySum = (@stay fn crazySum(intMaker__0 /* aka intMaker */: IntMaker, int__2 /* aka int */: Int64, string__1 /* aka string */: String) /* return__5 */: (Int32 | Bubble) { + var t#0 ⦂ Int32; + void; + fn__3: do { + var fail#2 ⦂ Boolean, fail#3 ⦂ Boolean; + let intInt__0 ⦂ Int32; + intInt__0 = hs ⋖ Int32 ⋗(fail#2, do_call_int64ToInt(intMaker__0, int__2)); + if (fail#2) { + bubble ⋖ Int32 ⋗() + }; + let stringInt__0 ⦂ Int32; + stringInt__0 = hs ⋖ Int32 ⋗(fail#3, do_call_stringToInt(intMaker__0, string__1)); + if (fail#3) { + bubble ⋖ Int32 ⋗() + }; + t#0 = intInt__0 + stringInt__0; + return__5 = do_call_int32ToInt(intMaker__0, t#0); + } +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overloaded-methods/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overloaded-methods/work/test/test.temper new file mode 100644 index 00000000..1f3b9c1e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overloaded-methods/work/test/test.temper @@ -0,0 +1,16 @@ +export class IntMaker(public radix: Int32) { + @overload("toInt") + public int64ToInt(int: Int64): Int32 throws Bubble { int.toInt32() } + + @overload("toInt") + public stringToInt(string: String): Int32 throws Bubble { string.toInt32(radix) } + + @overload("justMe") + public int32ToInt(int: Int32): Int32 { int } +} + +export let crazySum(intMaker: IntMaker, int: Int64, string: String): Int throws Bubble { + let intInt = intMaker.toInt(int); + let stringInt = intMaker.toInt(string); + intMaker.justMe(intInt + stringInt) +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overridden-and-unoverridden-overloaded-methods/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overridden-and-unoverridden-overloaded-methods/expect/type.temper new file mode 100644 index 00000000..30cd7052 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overridden-and-unoverridden-overloaded-methods/expect/type.temper @@ -0,0 +1,12 @@ +@stay @imported(\(`test//c/`.C)) let C__0 ⦂ Type; +C__0 = type (C); +@fn let `test//`.useC ⦂(fn (C): Void); +`test//`.useC = (@stay fn useC(c__0 /* aka c */: C) /* return__0 */: Void { + void; + fn__0: do { + do_call_fooInt32(c__0, 1); + do_call_foolean(c__0, true); + do_call_fooString(c__0, ""); + return__0 = void + } +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overridden-and-unoverridden-overloaded-methods/work/test/c/c.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overridden-and-unoverridden-overloaded-methods/work/test/c/c.temper new file mode 100644 index 00000000..d1c27236 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overridden-and-unoverridden-overloaded-methods/work/test/c/c.temper @@ -0,0 +1,23 @@ + +export interface I { + @overload("foo") + fooInt32(x: Int32): Void { fooString(x.toString()); } + + @overload("foo") + foolean(x: Boolean): Void { fooString(x.toString()); } + + @overload("foo") + fooString(x: String): Void; +} + +export class C extends I { + @overload("foo") + public fooInt32(x: Int32): Void { fooString("Int32 $x"); } + + // Does not overload foolean + + // Implements fooString but does not redeclare metadata + public fooString(x: String): Void { + ; + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overridden-and-unoverridden-overloaded-methods/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overridden-and-unoverridden-overloaded-methods/work/test/test.temper new file mode 100644 index 00000000..03d9875f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/overridden-and-unoverridden-overloaded-methods/work/test/test.temper @@ -0,0 +1,8 @@ +let {C} = import("./c"); + +export let useC(c: C): Void { + c.foo(1); + c.foo(true); + c.foo(""); +} + diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/return-that-violates-return-type/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/return-that-violates-return-type/expect/disAmbiguate.temper new file mode 100644 index 00000000..f1c5dcc0 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/return-that-violates-return-type/expect/disAmbiguate.temper @@ -0,0 +1,3 @@ +fn(\outType, Boolean, fn { + return 42 +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/return-that-violates-return-type/expect/errors.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/return-that-violates-return-type/expect/errors.json new file mode 100644 index 00000000..2e52cc4f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/return-that-violates-return-type/expect/errors.json @@ -0,0 +1,4 @@ +[ + "Cannot assign to Boolean from Int32!", + "Expected subtype of Boolean, but got Int32!" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/return-that-violates-return-type/expect/generateCode.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/return-that-violates-return-type/expect/generateCode.temper new file mode 100644 index 00000000..c9b4a9f9 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/return-that-violates-return-type/expect/generateCode.temper @@ -0,0 +1,4 @@ +let return__2; +return__2 = (@stay fn /* return__0 */: Boolean { + return__0 = 42 +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/return-that-violates-return-type/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/return-that-violates-return-type/expect/syntaxMacro.temper new file mode 100644 index 00000000..bb0e8d00 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/return-that-violates-return-type/expect/syntaxMacro.temper @@ -0,0 +1,8 @@ +fn /* return__0 */: (Boolean) { + fn__1: do { + do { + return__0 = 42; + break(\label, fn__1) + } + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/return-that-violates-return-type/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/return-that-violates-return-type/expect/type.temper new file mode 100644 index 00000000..cca29099 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/return-that-violates-return-type/expect/type.temper @@ -0,0 +1,6 @@ +let return__2; +return__2 = (@stay fn /* return__0 */: Boolean { + fn__1: do { + return__0 = 42 + } +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/return-that-violates-return-type/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/return-that-violates-return-type/work/test/test.temper new file mode 100644 index 00000000..b25f2dcb --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/return-that-violates-return-type/work/test/test.temper @@ -0,0 +1 @@ +fn () : Boolean { return 42 } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/returning-untyped/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/returning-untyped/expect/disAmbiguate.temper new file mode 100644 index 00000000..58c0b8e6 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/returning-untyped/expect/disAmbiguate.temper @@ -0,0 +1,3 @@ +fn(fn { + return 42 +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/returning-untyped/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/returning-untyped/expect/syntaxMacro.temper new file mode 100644 index 00000000..70fdaed7 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/returning-untyped/expect/syntaxMacro.temper @@ -0,0 +1,8 @@ +fn /* return__0 */{ + fn__1: do { + do { + return__0 = 42; + break(\label, fn__1) + } + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/returning-untyped/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/returning-untyped/expect/type.temper new file mode 100644 index 00000000..11777dfc --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/returning-untyped/expect/type.temper @@ -0,0 +1,6 @@ +let return__2; +return__2 = (@stay fn /* return__0 */{ + fn__1: do { + return__0 = 42 + } +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/returning-untyped/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/returning-untyped/work/test/test.temper new file mode 100644 index 00000000..04e9e7e7 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/returning-untyped/work/test/test.temper @@ -0,0 +1 @@ +fn { return 42 } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/returning-with-return-type-metadata/expect/disAmbiguate.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/returning-with-return-type-metadata/expect/disAmbiguate.temper new file mode 100644 index 00000000..d6b5360b --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/returning-with-return-type-metadata/expect/disAmbiguate.temper @@ -0,0 +1,3 @@ +fn(\outType, Int, fn { + return 42 +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/returning-with-return-type-metadata/expect/syntaxMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/returning-with-return-type-metadata/expect/syntaxMacro.temper new file mode 100644 index 00000000..505ac1e0 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/returning-with-return-type-metadata/expect/syntaxMacro.temper @@ -0,0 +1,8 @@ +fn /* return__0 */: (Int) { + fn__1: do { + do { + return__0 = 42; + break(\label, fn__1) + } + } +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/returning-with-return-type-metadata/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/returning-with-return-type-metadata/expect/type.temper new file mode 100644 index 00000000..ed719324 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/returning-with-return-type-metadata/expect/type.temper @@ -0,0 +1,6 @@ +let return__2; +return__2 = (@stay fn /* return__0 */: Int32 { + fn__1: do { + return__0 = 42 + } +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/returning-with-return-type-metadata/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/returning-with-return-type-metadata/work/test/test.temper new file mode 100644 index 00000000..23066835 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/returning-with-return-type-metadata/work/test/test.temper @@ -0,0 +1 @@ +fn () : Int { return 42 } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/skipped-and-swapped-args/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/skipped-and-swapped-args/expect/type.temper new file mode 100644 index 00000000..a53dd68f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/skipped-and-swapped-args/expect/type.temper @@ -0,0 +1,36 @@ +var t#0; +@constructorProperty @visibility(\private) @stay @fromType(Hi__0) let a__0: Int32; +@constructorProperty @visibility(\private) @stay @fromType(Hi__0) let b__0: Int32; +@constructorProperty @visibility(\private) @stay @fromType(Hi__0) let c__0: Int32; +@fn @visibility(\public) @stay @fromType(Hi__0) let constructor__0; +constructor__0 = (@stay fn constructor(@impliedThis(Hi__0) this__0: Hi__0, @optional(true) a__1 /* aka a */: Int32?, @optional(true) b__1 /* aka b */: Int32?, @optional(true) c__1 /* aka c */: Int32?) /* return__0 */: Void { + let a__2 /* aka a */: Int32; + if (isNull(a__1)) { + a__2 = 1 + } else { + a__2 = notNull(a__1); + }; + let b__2 /* aka b */: Int32; + if (isNull(b__1)) { + b__2 = 2 + } else { + b__2 = notNull(b__1); + }; + let c__2 /* aka c */: Int32; + if (isNull(c__1)) { + c__2 = 3 + } else { + c__2 = notNull(c__1); + }; + setp(a__0, this__0, a__2); + setp(b__0, this__0, b__2); + setp(c__0, this__0, c__2); + return__0 = void +}); +@typeDecl(Hi__0) @stay let Hi__0; +Hi__0 = type (Hi__0); +var n__0; +n__0 = 1; +n__0 = n__0 + 1; +t#0 = n__0; +new Hi__0(n__0 + 1, null, t#0); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/skipped-and-swapped-args/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/skipped-and-swapped-args/work/test/test.temper new file mode 100644 index 00000000..aac04d6d --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/skipped-and-swapped-args/work/test/test.temper @@ -0,0 +1,3 @@ +class Hi(private a: Int = 1, private b: Int = 2, private c: Int = 3) {} +var n = 1; +{ c: do { n += 1; n }, a: n + 1 }; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/static-access/expect/run-result.json b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/static-access/expect/run-result.json new file mode 100644 index 00000000..2073eb51 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/static-access/expect/run-result.json @@ -0,0 +1 @@ +"true: Boolean" \ No newline at end of file diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/static-access/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/static-access/work/test/test.temper new file mode 100644 index 00000000..9953f21e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/static-access/work/test/test.temper @@ -0,0 +1,2 @@ +class C { public static let foo = "foo"; } +C.foo == "foo" diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/static-extension-hints-resolved/expect/define.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/static-extension-hints-resolved/expect/define.temper new file mode 100644 index 00000000..76db9392 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/static-extension-hints-resolved/expect/define.temper @@ -0,0 +1,15 @@ +@fn @staticExtension({ + class: Pair__0, key: type (Int32), value: "isZero" +}) let isZero__0; +isZero__0 = (@stay fn isZero(x__0 /* aka x */: Int32) /* return__0 */: Boolean { + fn__0: do { + x__0 == 0 + } +}); +if((do_call_isZero[static isZero__0])(type (Int32), 0), @stay fn { + true + }, \else, fn (f#0) { + f#0(@stay fn { + false + }) +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/static-extension-hints-resolved/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/static-extension-hints-resolved/expect/type.temper new file mode 100644 index 00000000..21e6b302 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/static-extension-hints-resolved/expect/type.temper @@ -0,0 +1,13 @@ +let return__1, @fn @staticExtension({ + class: Pair__0, key: type (Int32), value: "isZero" +}) isZero__0; +isZero__0 = (@stay fn isZero(x__0 /* aka x */: Int32) /* return__0 */: Boolean { + fn__0: do { + return__0 = x__0 == 0 + } +}); +if (isZero__0(0)) { + return__1 = true +} else { + return__1 = false +}; diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/static-extension-hints-resolved/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/static-extension-hints-resolved/work/test/test.temper new file mode 100644 index 00000000..2855f56a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/static-extension-hints-resolved/work/test/test.temper @@ -0,0 +1,5 @@ +@staticExtension(Int, "isZero") +let isZero(x: Int): Boolean { x == 0 } + +Int.isZero(0) && isZero(0) + diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/tagged-string/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/tagged-string/expect/type.temper new file mode 100644 index 00000000..05ea0500 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/tagged-string/expect/type.temper @@ -0,0 +1,12 @@ +@fn let f__0 ⦂(fn (List, List): String), @fn `test//`.g ⦂(fn (String): String); +f__0 = (@stay fn f(literals__0 /* aka literals */: List, values__0 /* aka values */: List) /* return__0 */: String { + void; + fn__0: do { + return__0 = do_call_get(literals__0, 0); + } +}); +`test//`.g = (@stay fn g(there__0 /* aka there */: String) /* return__1 */: String { + fn__1: do { + return__1 = (fn f)(list ⋖ String ⋗("hi", ""), list ⋖ String ⋗(there__0)) + } +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/tagged-string/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/tagged-string/work/test/test.temper new file mode 100644 index 00000000..48777809 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/tagged-string/work/test/test.temper @@ -0,0 +1,7 @@ +let f(literals: List, values: List): String { + literals[0] +} + +export let g(there: String): String { + f"hi${there}" +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/type-mismatch-in-call/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/type-mismatch-in-call/expect/type.temper new file mode 100644 index 00000000..997e275e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/type-mismatch-in-call/expect/type.temper @@ -0,0 +1,19 @@ + let return__0; + var t#0; + t#0 = doPure(@stay fn /* return__1 */: Console { + return__1 = getConsole(); + }); + @fn let i__0; + i__0 = (@stay fn i(x__0 /* aka x */: Int32) /* return__2 */{ + fn__0: do { + return__2 = x__0 + } + }); + orelse#0: { +## We don't inline the below which has a type error even though its +## body's semantics would result in "0" if x could be bound. + (fn i)("0") + } orelse { + do_call_log(t#0, "bad"); + }; + return__0 = void diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/type-mismatch-in-call/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/type-mismatch-in-call/work/test/test.temper new file mode 100644 index 00000000..1c00b63e --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/type-mismatch-in-call/work/test/test.temper @@ -0,0 +1,2 @@ +let i(x: Int) { x } +i("0") orelse console.log("bad"); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/unary-plus-washes-out/expect/functionMacro.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/unary-plus-washes-out/expect/functionMacro.temper new file mode 100644 index 00000000..2161aec6 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/unary-plus-washes-out/expect/functionMacro.temper @@ -0,0 +1,21 @@ + @fn let `test//`.fi, @fn `test//`.ff, @fn `test//`.fs; + `test//`.fi = (@stay fn fi(i__0 /* aka i */: Int32) /* return__0 */: Int32 { + void; + fn__0: do { +## Now it's gone + return__0 = i__0; + } + }); + `test//`.ff = (@stay fn ff(f__0 /* aka f */: Float64) /* return__1 */: Float64 { + void; + fn__1: do { + return__1 = f__0; + } + }); + `test//`.fs = (@stay fn fs(s__0 /* aka s */: String) /* return__2 */: String { + void; + fn__2: do { +## This stays here so that TypeChecker can flag it as an error later. + return__2 = +s__0; + } + }) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/unary-plus-washes-out/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/unary-plus-washes-out/expect/type.temper new file mode 100644 index 00000000..770c1d54 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/unary-plus-washes-out/expect/type.temper @@ -0,0 +1,19 @@ +@fn let `test//`.fi, @fn `test//`.ff, @fn `test//`.fs; +`test//`.fi = (@stay fn fi(i__0 /* aka i */: Int32) /* return__0 */: Int32 { + void; + fn__0: do { + return__0 = identity(i__0); + } +}); +`test//`.ff = (@stay fn ff(f__0 /* aka f */: Float64) /* return__1 */: Float64 { + void; + fn__1: do { + return__1 = identity(f__0); + } +}); +`test//`.fs = (@stay fn fs(s__0 /* aka s */: String) /* return__2 */: String { + void; + fn__2: do { + return__2 = +s__0; + } +}) diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/unary-plus-washes-out/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/unary-plus-washes-out/work/test/test.temper new file mode 100644 index 00000000..56f0d985 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/unary-plus-washes-out/work/test/test.temper @@ -0,0 +1,6 @@ +// For these first two, the unary plus survives to the typer +// but is then removed so there's one less thing to translate. +export let fi(i: Int32): Int32 { +i } +export let ff(f: Float64): Float64 { +f } +// This use of `+` is illegal so remains in the tree. +export let fs(s: String): String { +s } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/while-transformed-in-repl-context/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/while-transformed-in-repl-context/expect/type.temper new file mode 100644 index 00000000..51497ae5 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/while-transformed-in-repl-context/expect/type.temper @@ -0,0 +1,5 @@ +let return__1; +while (c) { + f(); +}; +return__1 = void diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/while-transformed-in-repl-context/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/while-transformed-in-repl-context/work/test/test.temper new file mode 100644 index 00000000..2e8262a2 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/while-transformed-in-repl-context/work/test/test.temper @@ -0,0 +1 @@ +while (c) { f() } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/while-transformed/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/while-transformed/expect/type.temper new file mode 100644 index 00000000..67072372 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/while-transformed/expect/type.temper @@ -0,0 +1,4 @@ +void; +while (c) { + f(); +} diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/while-transformed/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/while-transformed/work/test/test.temper new file mode 100644 index 00000000..2e8262a2 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/while-transformed/work/test/test.temper @@ -0,0 +1 @@ +while (c) { f() } diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/yields-separated/expect/type.lispy b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/yields-separated/expect/type.lispy new file mode 100644 index 00000000..c06f025f --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/yields-separated/expect/type.lispy @@ -0,0 +1,217 @@ +[ + "Block", + [ + [ + "Call", + [ + [ + "RightName", + "ignore" + ], + [ + "Fun", + [ + [ + "Value", + "\\returnDecl: Symbol" + ], + [ + "Decl", + [ + [ + "LeftName", + "return__0" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ] + ] + ], + [ + "Block", + [ + [ + "Call", + [ + [ + "Value", + "nym`=`: Function" + ], + [ + "LeftName", + "return__0" + ], + [ + "Call", + [ + [ + "Value", + "adaptGeneratorFnSafe: Function" + ], + [ + "Fun", + [ + [ + "Value", + "\\returnDecl: Symbol" + ], + [ + "Decl", + [ + [ + "LeftName", + "return__1" + ], + [ + "Value", + "\\type: Symbol" + ], + [ + "Value", + "GeneratorResult\u003cEmpty\u003e: Type" + ], + [ + "Value", + "\\ssa: Symbol" + ], + [ + "Value", + "void: Void" + ] + ] + ], + [ + "Value", + "\\super: Symbol" + ], + [ + "Value", + "GeneratorFn: Type" + ], + [ + "Value", + "\\wrappedGeneratorFn: Symbol" + ], + [ + "Value", + "void: Void" + ], + [ + "Block", + [ + [ + "Call", + [ + [ + "Value", + "nym`=`: Function" + ], + [ + "LeftName", + "return__1" + ], + [ + "Call", + [ + [ + "Call", + [ + [ + "Value", + "nym`\u003c\u003e`: Function" + ], + [ + "RightName", + "core.doneResult" + ], + [ + "Value", + "Empty: Type" + ] + ] + ] + ] + ] + ] + ], + [ + "Value", + "void: Void" + ], + [ + "while", + [ + "Value", + "true: Boolean" + ], + [ + [ + "stmt-block", + [ + [ + "Call", + [ + [ + "Value", + "cat: Function" + ], + [ + "Call", + [ + [ + "Value", + "str: Function" + ], + [ + "Value", + "123: Int32" + ] + ] + ] + ] + ], + [ + "Call", + [ + [ + "Value", + "yield: Function" + ] + ] + ] + ] + ], + [ + "stmt-block", + [] + ] + ] + ] + ], + "StructuredFlow" + ] + ] + ] + ] + ] + ] + ] + ], + "StructuredFlow" + ] + ] + ] + ] + ], + [ + "Value", + "void: Void" + ] + ], + "StructuredFlow" +] diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/yields-separated/expect/type.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/yields-separated/expect/type.temper new file mode 100644 index 00000000..0d8d706a --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/yields-separated/expect/type.temper @@ -0,0 +1,10 @@ +ignore(fn /* return__0 */{ + return__0 = adaptGeneratorFnSafe(@wrappedGeneratorFn fn /* return__1 */: (GeneratorResult) implements GeneratorFn { + return__1 = core.doneResult(); + void; + while (true) { + cat(str(123)); + yield() + } + }) +}); diff --git a/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/yields-separated/work/test/test.temper b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/yields-separated/work/test/test.temper new file mode 100644 index 00000000..8e861c38 --- /dev/null +++ b/frontend/src/commonTest/resources/lang/temper/frontend/stage-tests/type/yields-separated/work/test/test.temper @@ -0,0 +1,6 @@ +ignore { (): GeneratorResult extends GeneratorFn => + while (true) { + "${ 123 }"; + yield; + } +} diff --git a/frontend/src/jvmTest/kotlin/lang/temper/frontend/AllStageTestDirsTested.kt b/frontend/src/jvmTest/kotlin/lang/temper/frontend/AllStageTestDirsTested.kt new file mode 100644 index 00000000..08522a00 --- /dev/null +++ b/frontend/src/jvmTest/kotlin/lang/temper/frontend/AllStageTestDirsTested.kt @@ -0,0 +1,74 @@ +package lang.temper.frontend + +import lang.temper.fs.temperRoot +import java.nio.file.Files +import java.nio.file.Path +import kotlin.io.path.extension +import kotlin.io.path.relativeTo +import kotlin.io.path.toPath +import kotlin.test.Test +import kotlin.test.assertEquals + +class AllStageTestDirsTested { + @Test + fun stageTestDirsUsed() { + // Merge conflicts could cause dropping of test cases. + // Scan the file system for the stage dirs and then check the Kotlin + // sources mention them. + val inFileSystem = buildSet { + val root = stageTestDirFileRoot.toPath() + + // Look for directories that have a `work` and/or `expect` sub-directories. + fun walk(p: Path) { + val ls = Files.list(p).toList() + val hasWorkOrExpectSubDir = ls.any { + when ("${it.fileName}") { + "work", "expect" -> true + else -> false + } + } + if (hasWorkOrExpectSubDir) { + add("${p.relativeTo(root)}") + } else { + for (c in ls) { + if (Files.isDirectory(c)) { + walk(c) + } + } + } + } + walk(root) + } + val used = buildSet { + /** Scan for uses of [StageTestDir]'s constructor */ + val stageTestDirCtor = Regex( + """StageTestDir\((?:\w+\s*=)?\s*"((?:[^"\\]|\\.)*)"\s*(?:,\s*)?\)""", + ) + fun walk(p: Path) { + when { + Files.isRegularFile(p) && p.fileName.extension == "kt" -> { + val content = Files.readString(p) + for (m in stageTestDirCtor.findAll(content)) { + add(m.groupValues[1]) + } + } + Files.isDirectory(p) -> { + for (c in Files.list(p)) { + walk(c) + } + } + } + } + walk(temperRoot.resolve("frontend/src/commonTest/kotlin/lang/temper")) + } + + val unused = inFileSystem.toMutableSet() + unused.removeAll(used) + + assertEquals( + inFileSystem.sorted().joinToString("\n"), + used.sorted().joinToString("\n"), + message = "unused=$unused", + ) + } +} diff --git a/frontend/src/jvmTest/kotlin/lang/temper/frontend/AssertModuleAtStage.jvm.kt b/frontend/src/jvmTest/kotlin/lang/temper/frontend/AssertModuleAtStage.jvm.kt new file mode 100644 index 00000000..5b90d596 --- /dev/null +++ b/frontend/src/jvmTest/kotlin/lang/temper/frontend/AssertModuleAtStage.jvm.kt @@ -0,0 +1,26 @@ +package lang.temper.frontend + +import lang.temper.fs.Url +import lang.temper.fs.temperRoot + +private object FrontendResourcePlaceholder + +private const val PACKAGE_PATH = "lang/temper/frontend" +private const val README_RELPATH = "stage-tests/README-stage-tests.md" + +actual val stageTestDirFileRoot: Url by lazy { + val readmeUri = FrontendResourcePlaceholder.javaClass + .getResource("/$PACKAGE_PATH/$README_RELPATH")!! + .toURI()!! + readmeUri.resolve(".") +} + +actual val stageTestDirFileSourceRoot: Url by lazy { + Url( + "file", + null, // authority + "$temperRoot/frontend/src/commonTest/resources/$PACKAGE_PATH/$README_RELPATH", + null, + null, + ).resolve(".") +} diff --git a/frontend/src/jvmTest/kotlin/lang/temper/frontend/StageTestDirTests.kt b/frontend/src/jvmTest/kotlin/lang/temper/frontend/StageTestDirTests.kt new file mode 100644 index 00000000..3c9dc02d --- /dev/null +++ b/frontend/src/jvmTest/kotlin/lang/temper/frontend/StageTestDirTests.kt @@ -0,0 +1,11 @@ +package lang.temper.frontend + +import kotlin.test.Test +import kotlin.test.assertEquals + +class StageTestDirTests { + @Test + fun stageTestDirFileRootAvailableAsFiles() { + assertEquals("file", stageTestDirFileRoot.scheme) + } +} diff --git a/lexer/src/commonMain/kotlin/lang/temper/lexer/LanguageConfig.kt b/lexer/src/commonMain/kotlin/lang/temper/lexer/LanguageConfig.kt index 63c01c20..d941b865 100644 --- a/lexer/src/commonMain/kotlin/lang/temper/lexer/LanguageConfig.kt +++ b/lexer/src/commonMain/kotlin/lang/temper/lexer/LanguageConfig.kt @@ -10,6 +10,9 @@ import lang.temper.log.FilePathSegmentOrPseudoSegment * match that starts at *pos* in *text*; or -1 if no such match. */ interface LanguageConfig { + /** The preferred file extension, with the dot, but excluding any ".temper" */ + val dotExtension: String? + /** * True if the lexer should start in a semilit comment context and look for an exit * before the first content tokens. @@ -49,6 +52,8 @@ interface LanguageConfig { } class MarkdownLanguageConfig : LanguageConfig { + override val dotExtension: String get() = ".md" + // March code ranges forward only. private var _codeRanges: List? = null private var codeRangeIndex = 0 @@ -131,6 +136,7 @@ data class TaggedRange( expect fun findMarkdownCodeBlocks(text: String): List object StandaloneLanguageConfig : LanguageConfig { + override val dotExtension: Nothing? get() = null override val isSemilit get() = false override fun matchSemilitCommentEntrance(text: CharSequence, pos: Int) = -1 override fun matchSemilitCommentExit(text: CharSequence, pos: Int) = -1 diff --git a/test-helpers/src/commonMain/kotlin/lang/temper/testdir/TestFileBundle.kt b/test-helpers/src/commonMain/kotlin/lang/temper/testdir/TestFileBundle.kt new file mode 100644 index 00000000..99f2e3dd --- /dev/null +++ b/test-helpers/src/commonMain/kotlin/lang/temper/testdir/TestFileBundle.kt @@ -0,0 +1,79 @@ +package lang.temper.testdir + +import lang.temper.common.Either +import lang.temper.log.FilePath +import lang.temper.log.FilePathSegment +import java.net.URI +import java.nio.file.Files +import java.nio.file.Path +import kotlin.io.path.isDirectory +import kotlin.io.path.isReadable +import kotlin.io.path.isRegularFile +import kotlin.io.path.relativeTo +import kotlin.io.path.toPath + +typealias Url = URI + +/** Builder for a list of files to regenerate */ +typealias RegeneratedFilesList = MutableList>> + +fun regenerateFiles(testDirRoot: Url, files: List>>) { + for ((relUrl, content) in files) { + val path = testDirRoot.resolve(relUrl).toPath() + Files.createDirectories(path.parent) + val bytes = when (content) { + is Either.Left -> content.item.encodeToByteArray() + is Either.Right -> content.item + } + Files.newOutputStream(path).use { outputStream -> + outputStream.write(bytes) + } + } +} + +val defaultSkipFilePattern = Regex("""~$|README.*[.]md$|^[.]""", RegexOption.DOT_MATCHES_ALL) + +fun readTestDir(testDirRoot: Url, skipFilePattern: Regex? = defaultSkipFilePattern): TestFileBundle { + // We assume that, when running tests, all the resources are in the + // same source root which is on the file system. + // This is not always the case Urls derived via Class.getResource on the JVM, + // but it is true when running tests via Maven or Gradle. + check(testDirRoot.scheme == "file") { "$testDirRoot" } + + val rootPath = testDirRoot.toPath() + + return TestFileBundle( + testDirRoot, + buildMap { + fun recursivelyReadRegularFilesIntoMap(path: Path) { + when { + path.isRegularFile() && path.isReadable() -> { + val name = "${path.fileName}" + if (skipFilePattern?.find(name) == null) { + val relPath = FilePath( + path.relativeTo(rootPath).map { FilePathSegment(it.fileName.toString()) }, + isDir = false, + ) + // Let race conditions with isReadable check just bubble up as IOExceptions + this[relPath] = Files.readString(path, Charsets.UTF_8) + } + } + path.isDirectory() -> { + for (child in Files.list(path)) { + recursivelyReadRegularFilesIntoMap(child) + } + } + } + } + recursivelyReadRegularFilesIntoMap(rootPath) + }, + ) +} + +data class TestFileBundle( + val testDirRoot: Url, + val files: Map, +) { + fun isEmpty() = files.isEmpty() + fun isNotEmpty() = files.isNotEmpty() +}